|
|
View previous topic :: View next topic |
Author |
Message |
tienchuan
Joined: 25 Aug 2009 Posts: 175
|
Problem when using both external interrupt with low voltage |
Posted: Fri Aug 29, 2014 2:25 am |
|
|
Hi everybody.
I'm have problems when using both external interrupt with high-low voltage interrupts.
In my project, I used: int_ext0, int_ext1, int_rb and int_lowvolt of PIC18F4680, CCSC complier ver 5.021.
The trouble occurs when the circuit has an interrupt on int_ext1 pin, my program go to int_ext1 and int_lowvolt, the right is only run to int_ext1.
I referenced some topic in site but it not help me to solve this problem.
Because the code is long, so that i cutout some body of my program.
- config fuse and lib:
Code: | #include "18F4680.h"
#fuses H4,PUT,PROTECT,NODEBUG,NOLVP,NOWDT,NOPBADEN,MCLR,BROWNOUT,BORV21
#use delay(clock=40000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, errors) |
- int_ext0 program:
Code: |
#int_ext
void ngat_counter(void)
{
output_toggle(PIN_E0);
delay_ms(50);
clear_interrupt(int_ext);
update_lcd=1;
if(en_count_ac==1) { count_ac++;}
else
{
output_high(PIN_C5);
leds_on;
}
if(detect_eepr==1)
{
detect_eepr=0;
save_tag_eepr=1;
}
}
|
- int_ext1 program:
Code: |
#int_ext1
void ngat_sw(void)
{
while(input(PIN_B1)==0);
delay_ms(50);
count_knife++;
output_toggle(PIN_E0);
update_lcd=1;
}
|
-int_lowvolt program:
Code: |
#int_lowvolt
void ngat_hlvd(void)
{
leds_on;
if(save_tag_eepr==1)
{
write_ext_eeprom( 500, make8(count_knife,3) );
write_ext_eeprom( 501, make8(count_knife,2) );
write_ext_eeprom( 502, make8(count_knife,1) );
write_ext_eeprom( 503, make8(count_knife,0) );
pt_eepr_hi= read_ext_eeprom(0);
pt_eepr_lo= read_ext_eeprom(1);
pt_eepr = make16(pt_eepr_hi, pt_eepr_lo);
if(pt_eepr==0) { pt_eepr=20;}
pt_eepr++;
if(chk_offset_pc==1) write_ext_eeprom(pt_eepr, 0X40);
else write_ext_eeprom(pt_eepr, 0X00);
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(count_ac,2));
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(count_ac,1));
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(count_ac,0));
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(app_code,2));
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(app_code,1));
pt_eepr++;
write_ext_eeprom(pt_eepr, make8(app_code,0));
write_ext_eeprom(0, make8(pt_eepr,1));
write_ext_eeprom(1, make8(pt_eepr,0));
}
save_tag_eepr=0;
}
|
- int_rb program:
Code: |
#int_rb
void ngat_rb()
{
temp_read =input(PIN_B5);
clear_interrupt (int_rb);
delay_ms(100);
check_so_sa=1;
}
|
- config interrupt in main program:
Code: |
#use delay(clock=40000000)
void main(void)
{
set_tris_a (0x3F); //0x20
set_tris_b (0x23); //0x21
set_tris_c (0x87);
set_tris_d (0x00); // lcd_data
set_tris_e (0x00); // led_disp_stt
delay_ms (500);
buzz_off;
lcd_bl_off;
set_timer0(62); // setup timer0: 5ms
setup_timer_0 (RTCC_INTERNAL | RTCC_8_BIT | RTCC_DIV_256);
set_timer1(62); // setup timer1: 50ms
setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);
set_timer2(0); // setup timer2_limit_PIN_TX_485 : 5ms F_cystal=40MHZ
setup_timer_2 (T2_DIV_BY_16,195,16 );
temp_read =input(PIN_B5);
clear_interrupt (int_rb);
setup_low_volt_detect( LVD_TRIGGER_BELOW | LVD_40 );
delay_ms(1000);
clear_interrupt ( int_lowvolt);
enable_interrupts (int_lowvolt);
ext_int_edge (0, H_TO_L) ;
clear_interrupt (int_ext);
ext_int_edge (1, H_TO_L) ;
clear_interrupt (int_ext1);
enable_interrupts (int_rb);
enable_interrupts (int_ext1);
enable_interrupts (int_rda);
enable_interrupts (global);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
lcd_init();
init_ext_eeprom(); // Init Ext EEPROM 24C128
delay_ms(100);
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
pt_eepr_hi= read_ext_eeprom(0);
pt_eepr_lo= read_ext_eeprom(1);
if(pt_eepr_hi !=0xff && pt_eepr_lo !=0xff)
{
pt_eepr = make16(pt_eepr_hi, pt_eepr_lo);
}
lcd_gotoxy(1,1);
printf(lcd_putc,"%lu",pt_eepr);
delay_ms(500);
if(pt_eepr >=27 )
{
count_knife3= read_ext_eeprom(500);
delay_ms(10);
count_knife2= read_ext_eeprom(501);
delay_ms(10);
count_knife1= read_ext_eeprom(502);
delay_ms(10);
count_knife0= read_ext_eeprom(503);
delay_ms(10);
count_knife = make32(count_knife3, count_knife2, count_knife1, count_knife0);
count_ac2 = read_ext_eeprom( pt_eepr -5);
count_ac1 = read_ext_eeprom( pt_eepr -4);
count_ac0 = read_ext_eeprom( pt_eepr -3);
app_code2 = read_ext_eeprom( pt_eepr -2);
app_code1 = read_ext_eeprom( pt_eepr -1);
app_code0 = read_ext_eeprom( pt_eepr);
count_ac_eepr = make32(0, count_ac2, count_ac1, count_ac0);
app_code_eepr = make32(0, app_code2, app_code1, app_code0);
if (count_ac_eepr != 0 && count_ac_eepr <200000 ) { count_ac = count_ac_eepr;} //
if (app_code_eepr != 0 && app_code_eepr <99999 ) { app_code = app_code_eepr;} //
detect_eepr=1;
status_disp=1;
en_count_ac=1;
}
else
{
status_disp=3;
en_count_ac=0;
pt_eepr=0;
count_ac=0;
app_code=0;
detect_eepr=0;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
can_init();
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
for(i_count=0; i_count<5; i_count++) { str_id_4key[i_count] = 0;}
for(i_count=0; i_count<11; i_count++)
{
str_id_10key[i_count] = 0;
str_rs232[i_count] =0;
}
xoa_str_name1();
xoa_str_name2();
read_id();
lcd_bl_on;
lcd_gotoxy(1,1);
printf(lcd_putc,"NODE %03lu",id_addr);
lcd_gotoxy(1,2);
printf(lcd_putc,"%lu",app_code_eepr);
lcd_gotoxy(9,2);
printf(lcd_putc,"%lu",count_ac_eepr);
lcd_gotoxy(12,1);
printf(lcd_putc,"%lu", count_knife);
delay_ms(1500);
disp_lcd();
lcd_bl_off;
leds_off;
enable_interrupts (int_ext);
for(;;)
{
-
-
}
|
I think my program have a conflict between int_ext1 vs int_lowvolt, but i still find a errors in my code.
Do you have a way to solve this problem?
Pls help me.
Thanks. _________________ Begin Begin Begin !!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Fri Aug 29, 2014 3:35 am |
|
|
The core reason is the simple one. Using a delay in the ISR. Treat this as if it carries a risk of ebola....
The key point is that ISR handlers should be _quick_. If you want a delay, then set a flag, and use a timer to give the delay.
A search here will find this repeated again and again. In fact if you search for the keyword 'mantra', I know you will find several posts.
You may get an answer then saying 'use high priority interrupts', but this won't work in this case, since INT_EXT, is always high priority if this is done.
Have a nice little 'tick' interrupt at something like 50mSec, and use this to provide your delays.
As it stands, if pin B1 is low, it'll stay in this ISR for ever.
_All_ your interrupts display similar versions of bad programming.
Consider a completely different approach. Have a tick interrupt as already mentioned, and have this check all the pins, and move through a state machine to give all the functions required. Advance the counter for delays, and the state for different pin patterns, and immediately exit. |
|
|
tienchuan
Joined: 25 Aug 2009 Posts: 175
|
|
Posted: Tue Sep 02, 2014 10:07 pm |
|
|
Thanks u.
I've modified all interrupt program by remove delay_ms() function and replace by loop delay.
I don't think i make a errors between int_ext1 with int_lowvolt.
I afraid CCS have a errors when compiling? _________________ Begin Begin Begin !!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Sep 03, 2014 12:40 am |
|
|
a 'loop delay', is just as bad if it is inside the interrupt.
The point is you _must_ get out of the interrupt handler ASAP.
As I said, use a single tick interrupt, and sample your pins in this. Whhen you want delays set a counter, and immediately exit. Next time the timer ticks, decrement the counter and exit. |
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Wed Sep 03, 2014 10:02 am |
|
|
If you are convinced it's a CCS problem, write a short, complete, compilable program which proves the point.
I took one look at the length of your code and decided to ignore it.
Mike |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9225 Location: Greensville,Ontario
|
|
Posted: Wed Sep 03, 2014 10:35 am |
|
|
also
you CANNOT write to the eeprom inside any ISR !! That too is very.very bad coding.NO delays( and writing to the eeprom is a HUGE delay...) are acceptable inside any ISR.
Simply set a 'flag' and get out ASAP.
within 'main()' do code based on the 'flags' set within the ISRs.
hth
jay |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Wed Sep 03, 2014 10:43 am |
|
|
Disagree just fractionally.
Power failure, is the _one_ interrupt where you can/do write to EEPROM. However you also need to work out how you are going to recover if the power goes back on, and the 'hold up' time of your supply relative to the write time.
The big problem before doing this though, is that it's never going to get to the power fail interrupt, since it is often sitting for ages in other (unnecessary) interrupts..... |
|
|
tienchuan
Joined: 25 Aug 2009 Posts: 175
|
|
Posted: Wed Sep 03, 2014 7:53 pm |
|
|
Thanks you so much.
I think I will edit my program as all our's advices, can be as follows:
- write a delay function using "for" loop.
- change delay function of CCSC by my delay function in ISR program.
- move ISR program to main loop program by check flag interrupts.
- repair ISR ext interrupts.
The first, I write a delay function using for loop to create a delay 10ms, but real it's seem longer. I can't calculate exact time delay creat in MPLAB, so I used help in CCSC and saw it take 0.4us with plus operation, with loop 25000 times, it makes 10ms.
Code: |
void delay_10_milisec(unsigned int8 ms_delay)
{
unsigned int16 count_delay=0x61A8;
unsigned int8 count_loop=0;
for(count_loop=0; count_loop<ms_delay; count_loop++)
{
while (count_delay--);
count_delay= 0x61A8;
}
}
|
Random while editing my program, I detection bug of me in setup low high voltage interrupt:
Code: |
setup_low_volt_detect( LVD_TRIGGER_BELOW | LVD_36 );
IRVST_BIT = 0;
delay_ms(1000);
clear_interrupt ( int_lowvolt);
enable_interrupts (int_lowvolt);
|
In above code, if i setup LVD_40, when ext1 interrupts occur, it also make high-low voltage occur. And, If I set LVD < 4 volt, i work finally. Normal, the power supply for PIC18F4680 is nearly 4.5->4.6V.
I checked again my circuit and not saw bugs in this.
I uploaded this circuit to my post to clearly, I hope ur help me fix it.
Thanks so much.
_________________ Begin Begin Begin !!! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19504
|
|
Posted: Thu Sep 04, 2014 11:40 am |
|
|
You are just ignoring the key point:
"The point is you _must_ get out of the interrupt handler ASAP. "
Using your delay, instead of the CCS delay, makes no difference. You are still delaying in the ISR.
This is equivalent to hitting yourself on the head with a sledgehammer. Not likely to lead to working code.
If you want something to happen an time 'after' an edge is seen, program a timer with the required timeout, and leave the interrupt handler immediately. Then when this timer triggers and interrupts, do the other half of your job.
However the whole thing is much simpler if you just have a 'tick' interrupt, and do the jobs needing timing in this. The approach is over complicated, and is causing your problems. |
|
|
|
|
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
|