|
|
View previous topic :: View next topic |
Author |
Message |
muatuyet_2012
Joined: 14 Jun 2012 Posts: 8
|
Timer0 interrupt,help |
Posted: Tue Dec 04, 2012 3:47 am |
|
|
Help me,please
I have a graphs : y1=c1*z1
c1=const= y1/c1
y1=read_analog - set_high;
z1= y1/c1; (time : second)
Control:
led HIGH on z1 (second)
led HIGH off (time-z1) (second) with time : setpoint (second)
set_high,wd_high,time : set with button.
I use delay_ms but when I use delay_ms, led 7 seg not work.
I think, I can use interrupts, but I'm not understand how to use.
code: I use PIC16f877a, 20Mhz, display 7 segment led
Code: | while(1)
{
a=read_analog(0);
a= a/div ;
h=a;
SET_ENTER(); //Buttons (set value : set_high , wd_high ,time)
if(setenter==5) // setenter =5 : end set value
{
if(h > (set_high + wd_high))
{ HIGH=1; LOW=0; t=1; }
if(t==1)
{
if(h <= (set_high + wd_high))
{
if(h <= set_high)
{
t=0;
HIGH=0;LOW=0;
}
// Graphs : y1 = c1* z1
c1 = wd_high / time; //coefficient , variable time : setpoint
y1 = h - set_high; // measured value - setpoint (set_high)
z1 = y1/c1; // z1: time (change)
// I want to use interrupt:
for(k=0;k<z1;k++)
{
HIGH=1; LOW=0;
delay_ms(1000);
}
for(l=0;l<(time - z1);l++)
{
HIGH=0; LOW=0;
delay_ms(1000);
}
}
}
}
} |
Last edited by muatuyet_2012 on Thu Dec 13, 2012 4:17 am; edited 2 times in total |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Tue Dec 04, 2012 3:54 am |
|
|
A search on the forum will yield loads of answers.
I've contributed more than once on the subject.
You're trying to do two tasks, drive a 7 seg display, and create a delay.
Use interrupts to do either or both.
Mike
EDIT As it stands your code is neither complete nor compilable, so can't offer further help. |
|
|
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
|
Posted: Tue Dec 04, 2012 8:33 am |
|
|
a tip:
even ONE of these is a disaster and not a brilliant bit of code inside a timer ISR:
|
|
|
muatuyet_2012
Joined: 14 Jun 2012 Posts: 8
|
|
Posted: Thu Dec 06, 2012 2:11 am |
|
|
I learned about it. But it don't work correct . Timer is too slow.
In function interrupts:
Code: | #int_timer0
void interrupts_timer0()
{
set_timer0(0);
count++;
} |
main:
Code: |
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(1)
{
a=read_analog(0);
a= a/div ;
h=a;
SET_ENTER();
if(setenter==5)
{
if(h > (set_high + wd_high))
{ HIGH=1; LOW=0; t=1; }
if(t==1)
{
if(h <= (set_high + wd_high))
{
if(h <= set_high)
{
HIGH=0;LOW=0;
t=0;
}
c1 = wd_high / time;
y1 = h - set_high;
if(count==76) // 1s
{
if(z1<(y1/c1))
{
HIGH=1;LOW=0;
}
if(z1>=(y1/c1))
{
HIGH=0;LOW=0;
k++;
if(k==(time-(y1/c1)))
{
z1=0;k=0;
}
}
z1++;
count=0;
}
}
}
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19515
|
|
Posted: Thu Dec 06, 2012 2:33 am |
|
|
What chip, what chip, what chip......
On most of the later chips, the RTCC defaults to running as a 16bit timer. So with /256 prescaler will give (master oscillator)/(4*256*65536). There should be an 8bit option in the timer setup, but depends on the chip.
Second, the interrupt occurs when the timer resets to zero. You don't need to set the timer to zero in the handler.
Best Wishes |
|
|
muatuyet_2012
Joined: 14 Jun 2012 Posts: 8
|
|
Posted: Thu Dec 06, 2012 2:39 am |
|
|
I use PIC16f877A and crystal 20Mhz
20Mhz / (4*256*256) ~76
I will review. Thanks Mike,Ttelmah,asmboy |
|
|
muatuyet_2012
Joined: 14 Jun 2012 Posts: 8
|
|
Posted: Thu Dec 13, 2012 4:08 am |
|
|
I have just repaired it. I improved but delay still slow.
Code: | #int_timer0
void ngat_timer0()
{
CLEAR_INTERRUPT(INT_TIMER0);
DISABLE_INTERRUPTS(INT_TIMER0);
count++;
if(count>=(76*time))
{
count=0;flag1=0;flag2=0;
}
else if(count < (76*z1))
{
flag1=1;
}
else
if( (76*z1)< count < (76*time))
{
flag2=1;
}
set_timer0(0);
ENABLE_INTERRUPTS(INT_TIMER0);
} |
and Main:
Code: | setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
set_timer0(0);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(1)
{
disable_interrupts(GLOBAL);
a=read_analog(0);
a= a/div ;
h=a;
SET_ENTER();
if(setenter==5)
{
if(h > (set_high + wd_high))
{ HIGH=1; LOW=0; p=1;}
if(p==1)
{
if(h <= (set_high + wd_high))
{
if(h<= set_high)
{
p=0;
HIGH=0; LOW=0;
}
else
{
c1 = wd_high / time;
y1 = h - set_high;
z1=y1/c1;
}
}
}
}
enable_interrupts(GLOBAL);
if(flag1==1)
{
HIGH=1;LOW=0;
flag1=0;
}
else if(flag2==1)
{
HIGH=0;LOW=0;
flag2=0;
}
} |
Please let me know if I have any mistake. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Thu Dec 13, 2012 5:37 am |
|
|
Your code is neither complete nor compilable.
It helps if you post the SHORTEST complete and compilable code which shows the problem you're having.
i.e. We need to see #FUSES, copiler version, everything, so that it's a simple cut and paste job for us.
Mike |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu Dec 13, 2012 5:41 am |
|
|
Code: | if( (76*z1)< count < (76*time)) | I'm surprised this compiles as it is invalid C language, you'll have to split it into two lines: Code: | if ( ((76*z1)< count)
&& (count < (76*time)) ) |
|
|
|
muatuyet_2012
Joined: 14 Jun 2012 Posts: 8
|
|
Posted: Thu Dec 13, 2012 8:51 pm |
|
|
I use CCS 4.104. If you find any mistake,please help me.
Code: | #include <16F877A.h>
#include <def_16f877a.h>
#fuses NOWDT,HS,NOPUT,NOPROTECT,NODEBUG,NOBROWNOUT,NOLVP,NOCPD,NOWRT
#use delay(clock=20000000)
#use fast_io(d) //7 segment led
#use fast_io(a) //led alarm
#use fast_io(b) //button and control
#bit UP=PortB.0
#bit DOWN=PortB.1
#bit LEFT=PortB.2
#bit RIGHT=PortB.3
#bit SET=PortB.4
#bit ENTER=PortB.5
#bit HIGH=PortB.6 //port control
#bit LOW=PortB.7 //port control
#bit ON_LEDHIGH=PortA.0 //led alarm
#bit ON_LEDLOW=PortA.1 // led alarm
int16 temp,value,count;
long int a,data,X,h,set_high,set_low;
int8 j,nghin,tram,chuc,dvi,T,count_shift,count_set,setenter,wd_high,wd_low,time,y1,y2,z1,z2,p;
int1 b,flag1=0,flag2=0;
float div,c1,c2;
const unsigned char seg[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
#int_timer0
void ngat_timer0()
{
CLEAR_INTERRUPT(INT_TIMER0);
DISABLE_INTERRUPTS(INT_TIMER0);
count++;
if(count>=(76*time))
{
count=0;flag1=0;flag2=0;
}
else if(count < (76*z1))
{
flag1=1;
}
else
if(((76*z1)< count) && (count < (76*time)))
{
flag2=1;
}
set_timer0(0);
ENABLE_INTERRUPTS(INT_TIMER0);
}
// Read ADC LTC1298
void adc_init() {
output_high(ADC_CS);
}
void write_adc_byte(BYTE data_byte, BYTE number_of_bits) {
BYTE i;
delay_us(2);
for(i=0; i<number_of_bits; ++i) {
if((data_byte & 1)==0) output_low(ADC_DIN);
else output_high(ADC_DIN);
data_byte=data_byte>>1;
output_high(ADC_CLK);
delay_us(50);
output_low(ADC_CLK);
delay_us(50);
}
}
BYTE read_adc_byte(BYTE number_of_bits) {
BYTE i,data;
data=0;
for(i=0;i<number_of_bits;++i) {
output_high(ADC_CLK);
delay_us(50);
shift_left(&data,1,input(ADC_DOUT));
output_low(ADC_CLK);
delay_us(50);
}
return(data);
}
long int read_analog( BYTE channel ) {
int l;
long int h;
delay_us(200);
output_low(ADC_CLK);
output_high(ADC_DIN);
output_low(ADC_CS);
if(channel==0)
channel=0x1b;
else
channel=0x1f;
write_adc_byte( channel, 5);
h=read_adc_byte(8);
l=read_adc_byte(4)<<4;
output_high(ADC_CS);
return((h<<8)|l);
}
void Display()
{
nghin=data/1000;
tram=(data%1000)/100;
chuc=(data%100)/10;
dvi=data%10;
for(j=0;j<100;j++)
{
output_low(PIN_C3);output_high(PIN_C2);output_high(PIN_C1);output_high(PIN_C0);
portd=seg[dvi];
delay_us(700);
output_high(PIN_C3);output_low(PIN_C2);output_high(PIN_C1);output_high(PIN_C0);
portd=seg[chuc];
delay_us(700);
output_high(PIN_C3);output_high(PIN_C2);output_low(PIN_C1);output_high(PIN_C0);
portd=seg[tram];
delay_us(700);
output_high(PIN_C3);output_high(PIN_C2);output_high(PIN_C1);output_low(PIN_C0);
portd=seg[nghin];
delay_us(700);
}
}
void UP_DOWN()
{
b=0;
if(UP==0)
{
temp=temp+value; T++;
while(UP==0){}
}
else
if(DOWN==0)
{
temp=temp-value;
if(T==0) {b=1;} T--;
while(DOWN==0){}
}
}
void LEFT_RIGHT()
{
if(LEFT==0)
{
count_shift++;
if(count_shift==6) { count_shift=2;}
while(LEFT==0){}
}
else
if(RIGHT==0)
{
count_shift--;
if((count_shift==0)|(count_shift==1)) { count_shift=5;}
while(RIGHT==0){}
}
if(count_shift==2)
{
value=1; T=dvi; UP_DOWN(); data=X+temp;
if(T==10)
{
T=0; temp=0; data=data-10; X=data;
}
if(b==1)
{
T=9; temp=0; data=data+10; X=data;
}
if(data > 1400)
{
data=1400; temp=0; X=data;
}
nhay_dvi(); //blinking unit led
}
else if(count_shift==3)
{
value=10; T=chuc; UP_DOWN(); data=X+temp;
if(T==10)
{
T=0; temp=0; data=data-100; X=data;
}
if(b==1)
{
T=9; temp=0; data=data+100; X=data;
}
if(data > 1400)
{
data=1400; temp=0; X=data;
}
nhay_chuc(); //blinking ten led
}
else if(count_shift==4)
{
value=100; T=tram; UP_DOWN(); data=X+temp;
if(T==10)
{
T=0; temp=0; data=data-1000; X=data;
}
if(b==1)
{
T=9; temp=0; data=data+1000; X=data;
}
if(data > 1400)
{
data=1400; temp=0; X=data;
}
nhay_tram();//blinking hundred led
}
else
if(count_shift==5)
{
value=1000; T=nghin; UP_DOWN(); data=X+temp;
if(T==2)
{
T=0; temp=0; data=data-2000; X=data;
}
if(b==1)
{
T=1; temp=0; data=data+2000; X=data;
}
if(data > 1400)
{
data=1400; temp=0; X=data;
}
nhay_nghin(); //blinking thousand led
}
}
void LEFT_RIGHT_TIME()
{
if(LEFT==0)
{
count_shift++;
if(count_shift==3) { count_shift=2;}
while(LEFT==0){}
}
else
if(RIGHT==0)
{
count_shift--;
if((count_shift==0)|(count_shift==1)) { count_shift=2;}
while(RIGHT==0){}
}
if(count_shift==2)
{
value=10; T=chuc; UP_DOWN(); data=X+temp;
if(T==10)
{
T=0; temp=0; data=data-100; X=data;
}
if(b==1)
{
T=9; temp=0; data=data+100; X=data;
}
if(data > 60)
{
data=60; temp=0; X=data;
}
nhay_chuc();
}
}
void SET_ENTER()
{
if(SET==0)
{
count_set++; count_shift=1; setenter=0; p=0;
if(count_set==6) { count_set=0;}
while(SET==0){}
}
if(count_set==1)
{
ON_LEDHIGH=1; ON_LEDLOW=0;
if((count_shift==0)|(count_shift==1))
{
X=set_high; temp=0; data=X; Display();
}
LEFT_RIGHT();
if(ENTER==0)
{
count_set=2; count_shift=1; set_high=data; setenter=1;
while(ENTER==0){}
}
}
else if(count_set==2)
{
if((count_shift==0)|(count_shift==1))
{
X=wd_high; temp=0; data=X; Display();
}
LEFT_RIGHT_HYS();
if(ENTER==0)
{
count_set=3; count_shift=1; wd_high=data; setenter=2;
while(ENTER==0){}
}
}
else if(count_set==3)
{
ON_LEDHIGH=0; ON_LEDLOW=1;
if((count_shift==0)|(count_shift==1))
{
X=set_low; temp=0; data=X; Display();
}
LEFT_RIGHT();
if(ENTER==0)
{
count_set=4; count_shift=1; set_low=data; setenter=3;
while(ENTER==0){}
}
}
else if(count_set==4)
{
if((count_shift==0)|(count_shift==1))
{
X=wd_low; temp=0; data=X; Display();
}
LEFT_RIGHT();
if(ENTER==0)
{
count_set=5; count_shift=1; wd_low=data; setenter=4;
while(ENTER==0){}
}
}
else if(count_set==5)
{
if((count_shift==0)|(count_shift==1))
{
X=time; temp=0; data=X; Display();
}
LEFT_RIGHT_TIME();
if(ENTER==0)
{
count_set=6; count_shift=1; time=data; setenter=5;
while(ENTER==0){}
}
}
else
if((count_set==6)|(count_set==0))
{
ON_LEDHIGH=0; ON_LEDLOW=0;
data=h;
Display();
count_set=0;
}
}
void main()
{
disable_interrupts(INT_TIMER1);
set_tris_d(0x00);
set_tris_a(0x00);
set_tris_b(0x3F);
temp=0;
count_shift=1;
count_set=0;
setenter=0;
set_high=0; set_low=0;
ON_LEDHIGH=0; ON_LEDLOW=0;
HIGH=0; LOW=0;
wd_high=0; wd_low=0;
time=0;
adc_init(); //
div=13.104;
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256);
set_timer0(0);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(1)
{
disable_interrupts(GLOBAL);
a=read_analog(0);
a= a/div ;
h=a;
SET_ENTER();
if(setenter==5)
{
//I only worked with set_high, I will do the same with set_low.
if(h > (set_high + wd_high))
{ HIGH=1; LOW=0; p=1;}
if(p==1)
{
if(h <= (set_high + wd_high))
{
if(h<= set_high)
{
p=0;
HIGH=0; LOW=0;
}
else
{
c1 = wd_high / time;
y1 = h - set_high;
z1=y1/c1;
}
}
}
}
enable_interrupts(GLOBAL);
if(flag1==1)
{
HIGH=1;LOW=0;
flag1=0;
}
else if(flag2==1)
{
HIGH=0;LOW=0;
flag2=0;
}
}
}
|
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Fri Dec 14, 2012 9:03 am |
|
|
Mike Walne wrote: | It helps if you post the SHORTEST complete and compilable code which shows the problem you're having. | Your program as posted is NOT short.
A quick look at your program showed one error: Code: | if((count_shift==0)|(count_shift==1)) | Replace '|' by '||'
This at multiple locations in your program.
Then I stopped searching because it gave me a headache to look at your code. Some of the annoyances: Code: | count_set=3; count_shift=1; wd_high=data; setenter=2; | Good coding practice is to have only one instruction at a line as it makes reading easier.
Write only constants and #defines in capital letters, all other items in lower case (or a mix of lower/upper case).
Code: | int16 temp,value,count;
long int a,data,X,h,set_high,set_low;
int8 j,nghin,tram,chuc,dvi,T,count_shift,count_set,setenter,wd_high,wd_low,time,y1,y2,z1,z2,p;
int1 b,flag1=0,flag2=0;
float div,c1,c2; | Try to use as few global variables as possible:
- Now your code is difficult to follow as we have to constantly scroll to the program start to see the data definitions.
- The compiler can not optimize memory usage of global variables.
- Dangerous, because you are using the same name for local and global variables (data).
Try to use meaningful variable names; e, T, h, b, flag1, c1, c2 What do these do?
You mix 'int16' and 'long int'. Both are the same. Make a choice and stick to it. Preferred is int16 as it is the same in all compilers.
Code: | #int_timer0
void ngat_timer0()
{
CLEAR_INTERRUPT(INT_TIMER0);
DISABLE_INTERRUPTS(INT_TIMER0); | Add '#case' to your program. It will make the compiler case sensitive so you use the correct capitalization for each function.
You don't have to clear the timer interrupt in your code, the CCS compiler does this for you (and now is done two times).
Inside the interrupt, the PIC hardware disables the GLOBAL interrupt flag so you are already sure no other interrupt can come in between. It makes no sense to disable and enable the Timer0 interrupt. These two lines can be removed.
This line is inside the Timer0 interrupt. Why? You get inside the interrupt because the timer overflowed and started counting again at 0. When you get at this location in your code the timer will have already advanced a bit. Resetting again to 0 will cause an extra delay that makes your timer less accurate.
Code: | if(count>=(76*time))
{
count=0;flag1=0;flag2=0;
}
else if(count < (76*z1))
{
flag1=1;
}
else
if(((76*z1)< count) && (count < (76*time)))
{
flag2=1;
}
| You can only get into the 3rd if-statement when the other two have failed. Calculations are expensive for the CPU. It makes no sense to do the whole test for both conditions again. Besides, there is a small bug: when count == (76*z1) then no code is executed.
With all that, your interrupt routine can be reduced to: Code: | #int_timer0
void ngat_timer0()
{
count++;
if (count >= (76*time))
{
count=0; flag1=0; flag2=0;
}
else if (count < (76*z1))
{
flag1=1;
}
else
{
flag2=1;
}
} |
... and then I've only checked the first function of your program.
Sorry, so many things wrong with your program. Have I mentioned the use of Magic Numbers? The lack of comments?
Post a short (50 lines maximum) program that is complete and compilable that demonstrates your problem. Perhaps that we then will have another look into your problem. |
|
|
|
|
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
|