|
|
View previous topic :: View next topic |
Author |
Message |
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
help please it is urgent |
Posted: Fri Aug 12, 2016 1:21 am |
|
|
hello dear friends
I am amateur friend of you about pic programming.
I am making a pic circuit about temperature measuring and writing to LCD screen using pic 16f877a.
Compiler reporting no error but my interrupt not working correctly.
Here is proteus scheme of my circuit:
http://i.hizliresim.com/7Am5LN.jpg
and my code is below.
I hope you experts give an advise to this amateur.
love u all thanks
Code: |
#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(d)
#define use_portb_lcd TRUE
#include <lcd.c>
#int_timer0
unsigned long int bilgi;
float voltaj,sicaklik;
timer0_kesmesi()
{
if (sicaklik>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
void main ( )
{
setup_psp(PSP_DISABLED); // PSP birimi devre dışı
setup_timer_2(T2_DISABLED,0,1); // T2 zamanlayıcısı devre dışı
setup_CCP1(CCP_OFF); // CCP1 birimi devre dışı
setup_CCP2(CCP_OFF); // CCP2 birimi devre dışı
set_tris_a(0x01); // RA0 Giriş olarak yönlendiriliyor
set_tris_d(0x00);
output_d(0x00);
setup_timer_0(RTCC_INTERNAL |RTCC_DIV_4);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_adc(adc_clock_div_32); // ADC clock frekansı fosc/32
setup_adc_ports(AN0); //RA0/AN0 girişi analog
lcd_init(); // LCD hazır hale getiriliyor
set_adc_channel(0); // RA0/AN0 ucundaki sinyal A/D işlemine tabi tutulacak
delay_us(20); // Kanal seçiminde sonra bu bekleme süresi verilmelidir
printf(lcd_putc,"\fSicaklik="); // LCD'ye yazı yazdırılıyor
while(1) // sonsuz döngü
{
bilgi=read_adc(); // ADC sonucu okunuyor ve bilgi değişkenine aktarılıyor
voltaj=(0.0048828125*bilgi)*1000; // Dijitale çevirme işlemine uğrayan sinyalin mV olarak gerilimi hesaplanıyor
sicaklik=(voltaj/10)+2; // Her 10mV'ta 1 derece artma
lcd_gotoxy(10,1); // İmleç 1. satır 10.sütunda
printf(lcd_putc,"%5.1f'C",sicaklik); // LCD'ye sıcaklık değeri yazdırılıyor
delay_ms(100); // 100 msn gecikme
}
} |
|
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Fri Aug 12, 2016 3:23 am |
|
|
First, please read:
https://www.ccsinfo.com/forum/viewtopic.php?t=47549
Better you build the circuit on a prototyping board and make first a led to blink from a pin via a 560 ohm resistor at 1 second as the first stage of the program.
A few remarks regarding the hardware, regarding the software have people with much better knowledge than me to answer except why you need sophisticated calculations for the analog reading as 10 mV is 1 degree Celsius?
* You are stating that you want to measure temperature and display it on the LCD
* What the transistor supposed to do? Why driving it with a 200 ohm resistor and not let's say 4.7K ?
* How you are intending to program the PIC?
If ICSP, better drive the LCD from other ports and not B6 (PGC) and B7 (PGD).
* You will need MCLR pin also for programming with ICSP
* You have a power connection named VDD and one +VS. What is the supply to the PIC? 5V will be the best for the 16F877A
Best wishes
Joe |
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Fri Aug 12, 2016 4:34 am |
|
|
I love you man
I read your link before I posted my problem
but my problem not about proteus
problem is my interrupt not working neither in proteus nor in real circuit
I am wondering is it because of my codes or am I asking too much current from ports?
I will make changes you ask me to do
gjs_rsdi wrote: | First, please read:
https://www.ccsinfo.com/forum/viewtopic.php?t=47549
Better you build the circuit on a prototyping board and make first a led to blink from a pin via a 560 ohm resistor at 1 second as the first stage of the program.
A few remarks regarding the hardware, regarding the software have people with much better knowledge than me to answer except why you need sophisticated calculations for the analog reading as 10 mV is 1 degree Celsius?
* You are stating that you want to measure temperature and display it on the LCD
* What the transistor supposed to do? Why driving it with a 200 ohm resistor and not let's say 4.7K ?
* How you are intending to program the PIC?
If ICSP, better drive the LCD from other ports and not B6 (PGC) and B7 (PGD).
* You will need MCLR pin also for programming with ICSP
* You have a power connection named VDD and one +VS. What is the supply to the PIC? 5V will be the best for the 16F877A
Best wishes
Joe |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Fri Aug 12, 2016 8:21 am |
|
|
if (sicaklik>30)
Now sicaklik is declared as a 'float' value (ugh).
This comparison will take about 565uSec to do (actually more, since the '30', will first have to be converted to a float). Now your interrupt triggers every 1024 instructions (Fosc/(4*256*4)), so every 1024uSec. So straight away over half your processor time is being used by the interrupt. Think again. This should be done using an integer....
Float is _slow_. Until you realise just how slow, you will have problems.
Then the comparison is unlikely to work. The sicaklik value is being calculated and changed outside the interrupt. The interrupt may well receive it when it is half way through being calculated....
Then the interrupt declaration wants to be the line before the function. So:
Code: |
#INT_TIMER0
void timer0_kesmesi(void)
{
if (sicaklik>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
|
Now forget 'volts', and floating point numbers. The silly think is that you are almost doing the maths 'right' to work in mV, then throwing it all away.
Now your test for '30', starts from a voltage value that scaled as 5000 for 5v. /10 +2.
So '30' would occur for 0.28v, Is this what you want?.
Code: |
//leaving out the initialisation
#define DEG_TO_MV(x) (x)*10
//This way the calculation can be done by the compiler, not the PIC
//for constants
//Got rid of the 2 offset. This is _not correct_ for the LM35
int16 bilgi, voltaj, sicaklik;
#INT_TIMER0
timer0_kesmesi()
{
if (sicaklik>DEG_TO_MV(30))
output_high(pin_d1);
else
output_low(pin_d1);
}
//again omitting the stuff between
while(TRUE) // sonsuz döngü
{
bilgi=read_adc(); // ADC sonucu okunuyor ve bilgi değişkenine aktarılıyor
voltaj=(bilgi*39)/8; //This gives integer 0 to 5000 for 0 to 5v.
//_efficiently_.
disable_interrupts(GLOBAL);
sicaklik=voltaj; //copy with interrupts disabled
enable_interrupts(GLOBAL);
lcd_gotoxy(10,1); // İmleç 1. satır 10.sütunda
printf(lcd_putc,"%5.1LW'C",(voltaj+20)); // LCD'ye sıcaklık değeri yazdırılıyor
delay_ms(100); // 100 msn gecikme
}
|
This is doing it with integer maths.
Then tell us the sensor. Are you sure about the '2' offset?. Sure it is not 20?. I can't think of any sensor on the market that is offset by just 2 degrees. Some are offset by 273. Some by 20C.
Looking at the circuit, you are using an LM35. This is not offset by 2C, it just can't output a voltage below 2C, unless you use a -ve bias. |
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Fri Aug 12, 2016 5:17 pm |
|
|
LM35
http://www.ti.com/lit/ds/symlink/lm35.pdf
From the data sheet, the LM35 range is -55 to +150 degree Celsius
Starts at 0V (-55 degree), every degree is 10mV, 2050mV at +150
If the analog Vref+ is 5V (the VDD) at ADC=10 you will have 4.89mV/bit,
at ADC=8 will be 19.61mV/bit
Fastest is to make a table for bit/degree, but some work to do
You can make also the +Vref to a value that will give you mV/bit without fractions.
Best wishes
Joe |
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Sat Aug 13, 2016 6:37 am |
|
|
thank you big chief for your help
yes it is LM35
I used float type because heat is analog wave
but now I see that it slows my cpu after I add interrupt to my code
I hope it works fine this time
I will add my thanks to you and gjs_rsdi
Ttelmah wrote: | if (sicaklik>30)
Now sicaklik is declared as a 'float' value (ugh).
This comparison will take about 565uSec to do (actually more, since the '30', will first have to be converted to a float). Now your interrupt triggers every 1024 instructions (Fosc/(4*256*4)), so every 1024uSec. So straight away over half your processor time is being used by the interrupt. Think again. This should be done using an integer....
Float is _slow_. Until you realise just how slow, you will have problems.
Then the comparison is unlikely to work. The sicaklik value is being calculated and changed outside the interrupt. The interrupt may well receive it when it is half way through being calculated....
Then the interrupt declaration wants to be the line before the function. So:
Code: |
#INT_TIMER0
void timer0_kesmesi(void)
{
if (sicaklik>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
|
Now forget 'volts', and floating point numbers. The silly think is that you are almost doing the maths 'right' to work in mV, then throwing it all away.
Now your test for '30', starts from a voltage value that scaled as 5000 for 5v. /10 +2.
So '30' would occur for 0.28v, Is this what you want?.
Code: |
//leaving out the initialisation
#define DEG_TO_MV(x) (x)*10
//This way the calculation can be done by the compiler, not the PIC
//for constants
//Got rid of the 2 offset. This is _not correct_ for the LM35
int16 bilgi, voltaj, sicaklik;
#INT_TIMER0
timer0_kesmesi()
{
if (sicaklik>DEG_TO_MV(30))
output_high(pin_d1);
else
output_low(pin_d1);
}
//again omitting the stuff between
while(TRUE) // sonsuz döngü
{
bilgi=read_adc(); // ADC sonucu okunuyor ve bilgi değişkenine aktarılıyor
voltaj=(bilgi*39)/8; //This gives integer 0 to 5000 for 0 to 5v.
//_efficiently_.
disable_interrupts(GLOBAL);
sicaklik=voltaj; //copy with interrupts disabled
enable_interrupts(GLOBAL);
lcd_gotoxy(10,1); // İmleç 1. satır 10.sütunda
printf(lcd_putc,"%5.1LW'C",(voltaj+20)); // LCD'ye sıcaklık değeri yazdırılıyor
delay_ms(100); // 100 msn gecikme
}
|
This is doing it with integer maths.
Then tell us the sensor. Are you sure about the '2' offset?. Sure it is not 20?. I can't think of any sensor on the market that is offset by just 2 degrees. Some are offset by 273. Some by 20C.
Looking at the circuit, you are using an LM35. This is not offset by 2C, it just can't output a voltage below 2C, unless you use a -ve bias. |
|
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Sat Aug 13, 2016 7:30 am |
|
|
Hello guys,
It is me again and still not working.
My pin_d1 shouldn't give output while condition not satisfied
but don't know why I always getting output from that pin.
Here is my code below:
Code: |
#include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(d)
#define use_portb_lcd TRUE
#define DEG_TO_MV(x) (x)*10
#include <lcd.c>
#int_timer0
int16 sensor, voltaj, temp;
timer0_interrupt()
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
void main ( )
{
setup_psp(PSP_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
set_tris_a(0x01);
set_tris_d(0x00);
output_d(0x00);
setup_timer_0(RTCC_INTERNAL |RTCC_DIV_4);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);
lcd_init();
set_adc_channel(0);
delay_us(20);
printf(lcd_putc,"\ftemp=");
while(TRUE)
{
sensor=read_adc(); // ADC sonucu okunuyor ve bilgi değişkenine aktarılıyor
voltaj=(sensor*39)/8; //This gives integer 0 to 5000 for 0 to 5v.
//_efficiently_.
disable_interrupts(GLOBAL);
temp=voltaj; //copy with interrupts disabled
enable_interrupts(GLOBAL);
lcd_gotoxy(10,1);
printf(lcd_putc,"%5.1LW'C",(voltaj+20));
delay_ms(100);
}
} |
|
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Sat Aug 13, 2016 10:42 am |
|
|
I don't have the 877 so can't test it in the real life but I copy your program and run it with MPLAB v8.92
This part:
Code: | timer0_interrupt()
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
} |
Gives when I compile it:
Quote: | Function not void and does not return a value timer0_interrupt |
Also if I put break points the MPLAB can't resolve them.
Your code above is not an interrupt routine.
Replace it with:
Code: | #INT_TIMER0
void TIMER0_isr(void)
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
} |
And the interrupt works in the simulator.
Iyi geceler
Best wishes
Joe |
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Sat Aug 13, 2016 11:05 am |
|
|
Dear Joe,
can you copy paste of your full code pls?
I dont know why not happening
can it be reason we disabling interrupt in while loop?
and we not using TIMER_0 interrupt in while loop either
gjs_rsdi wrote: | I don't have the 877 so can't test it in the real life but I copy your program and run it with MPLAB v8.92
This part:
Code: | timer0_interrupt()
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
} |
Gives when I compile it:
Quote: | Function not void and does not return a value timer0_interrupt |
Also if I put break points the MPLAB can't resolve them.
Your code above is not an interrupt routine.
Replace it with:
Code: | #INT_TIMER0
void TIMER0_isr(void)
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
} |
And the interrupt works in the simulator.
Iyi geceler
Best wishes
Joe |
|
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Sat Aug 13, 2016 11:31 am |
|
|
good news good news good news
guys it is working
but it interrupts at 5 celcius
my condition is
if(temp>30)
I dont understand why
any comments? |
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Sat Aug 13, 2016 12:02 pm |
|
|
Code: | #include <16f877.h>
#device ADC=10
#fuses XT,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
#use delay (clock=4000000)
#use fast_io(a)
#use fast_io(b)
#use fast_io(d)
#define use_portb_lcd TRUE
#define DEG_TO_MV(x) (x)*10
#include <lcd.c>
//#int_timer0
int16 sensor, voltaj, temp;
/*
//whwn compiled gives: Function not void and does not return a value timer0_interrupt
timer0_interrupt()
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
*/
#INT_TIMER0
void TIMER0_isr(void)
{
if (temp>30)
output_high(pin_d1);
else
output_low(pin_d1);
}
void main ( )
{
setup_psp(PSP_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_CCP1(CCP_OFF);
setup_CCP2(CCP_OFF);
set_tris_a(0x01);
set_tris_d(0x00);
output_d(0x00);
setup_timer_0(RTCC_INTERNAL |RTCC_DIV_4);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
setup_adc(adc_clock_div_32);
setup_adc_ports(AN0);
lcd_init();
set_adc_channel(0);
delay_us(20);
printf(lcd_putc,"\ftemp=");
while(TRUE)
{
sensor=read_adc(); // ADC sonucu okunuyor ve bilgi degiskenine aktariliyor
voltaj=(sensor*39)/8; //This gives integer 0 to 5000 for 0 to 5v.
//_efficiently_.
disable_interrupts(GLOBAL);
temp=voltaj; //copy with interrupts disabled
enable_interrupts(GLOBAL);
lcd_gotoxy(10,1);
printf(lcd_putc,"%5.1LW'C",(voltaj+20));
delay_ms(100);
}
} |
Regarding:
Quote: | but it interrupts at 5 celcius
my condition is
if(temp>30) |
Something wrong in your calculations or the ADC reading
By the way, why the enable/disable Global?
Best wishes
Joe |
|
|
gjs_rsdi
Joined: 06 Feb 2006 Posts: 468 Location: Bali
|
|
Posted: Sat Aug 13, 2016 1:20 pm |
|
|
My calculations:
If your +Vref is VDD and the LM35 gets also VDD (5V) the ADC reading will be 0 to 2050mV for - 55 to 150 degree
At 150 degree 10*205=2050mV, ADC reading 419 (from 1023)
voltaj=(sensor*39)/8; 419*39/8=2042
At 30 degree 10*85=850mV, ADC reading 173 (from 1023)
voltaj=(sensor*39)/8; 173*39/8=843
At – 51 degree 10*4=40mV, ADC reading 8 (from 1023)
voltaj=(sensor*39)/8; 8*39/8=39; already above the 30 in your program
By the way, I don't think you need sensor to voltaj and the voltaj to temp.
Make directly sensor to temp
The best in my opinion is to make a table, otherwise you will need complex mathematics
Best wishes
Joe |
|
|
erendogan83
Joined: 12 Aug 2016 Posts: 13
|
|
Posted: Sun Aug 14, 2016 1:06 am |
|
|
bro I am having some difficulties about understanding your calculations (my brain mostly works slow)
we have -55 to +150 temp range total makes 205
and 10 bit A/D converter so 2^10 = 1024
so 1 degree change in weather equals 1023/205 = 5 bit
now I see why my circuit interrupts at 6 degree
because I typed if(temp>30)
30/5 = 6 degree
am I right? |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19568
|
|
Posted: Sun Aug 14, 2016 4:38 am |
|
|
The sensor does not have a -55 degree range, unless you use a -ve bias resistor so it can give outputs below 0v. The ADC cannot read below 0v anyway.
The sensor output is simple. +10mV/C. That is all.
At +20C, it gives 200mV out.
Without an external bias it can't actually output below 20mV, so gives 2C minimum.
With a 5v supply on the PIC ADC (honestly, using this you are not going to get better than perhaps a 1C repeatable resolution anyway, because of noise and inaccuracy in this voltage.... - so displaying to 0.1C, is actually pointless). |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9255 Location: Greensville,Ontario
|
|
Posted: Sun Aug 14, 2016 5:26 am |
|
|
Mr. T is 100% right about the LM35, as I've used the *F version (LM34) for decades in my remote energy control systems. The LM34 is a bit better(no pun intended) but these days the World 'thinks' *C. 21*C = 210mv for LM35 but 698mv for the LM34. The larger sensor voltage is less susceptable to noise. It's easy for the PIC to convert *F to *C for display purposes. However for 'control' use, just use the ADC 8 bit data in integer format NEVER use Floating Points !
To get better than +-1*, I used an opamp unity buffer with 3 pole R-C filters in the PSU for it, as well as the LM34 output to the buffer. That allowed for solid, stable readings over 100' of CAT5 ( twisted pair cable). 8 bit data is more than sufficent for any 'human' related temperature control projects.
Jay |
|
|
|
|
You cannot post new topics in this forum You cannot reply to topics in this forum You cannot edit your posts in this forum You cannot delete your posts in this forum You cannot vote in polls in this forum
|
Powered by phpBB © 2001, 2005 phpBB Group
|