![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
oxxyfx
Joined: 24 May 2007 Posts: 97
|
External Interrupt problem |
Posted: Sun May 17, 2009 9:29 am |
|
|
Hello,
my nephew asked me nicely to build him an intelligent traffic light. How can you say no to him?
So I decided to use a 16F88 (little overkill I know) but hey, it is a one time deal.
I started testing the below program and I see some issues around the external interrupt.
First let me give you a brief description of the project:
There are 3 LED lights these are large(20mm) 12 LED arrays driven by a transistor from the pin of the PIC. There are also 4 buttons beside the obvious On/Off power button. The function of each button is the following:
- MRED - once pushed it will turn all lights off and turn on the red
- MYELLOW - same as above for the Yellow
- MGREEN - same as above for the Green
- MAUTO - multifunction button:
--- When pressed once it will start an automatic routine - Green, Yellow Red as on real traffic lights.
--- When pressed twice it will do the same routine but with longer wait times
--- When pressed 3 times it should flash all 3 lights together as a defective traffic light
--- When pressed the fourth time it should turn all lights on - again as a defective traffic light.
Additional functionalities not implemented yet - For the first 3 buttons when pressed twice it will flash the respective color only.
So with all the above I have the following problem:
The first 3 buttons work great, the moment it is pressed it will go turn the respective color on.
The Auto button does not work as expected. When pressed it will continue the routine and at the beginning of the next cycle will perhaps change the sequence. This is not good, because a child as it does not see the reaction right away will keep punching the button again and again and that is already a different functionality.
Can you please tell me what is wrong with this code? I thought it is simple enough but it seems nothing is that simple any more...
Code: |
#include "...\Semaphore\semaphore.h"
#define Green Pin_A0
#define Yellow Pin_A1
#define Red Pin_A2
#define MAuto Pin_B4
#define MGreen Pin_B7
#define MYellow Pin_B6
#define MRed Pin_B5
int16 mtimer, seconds, dtime;
int Mode, APcount, Color;
Void Runauto(int i){
dtime = 1000;
Output_High(Green);
If (i == 1)Delay_ms(dtime);
If (i == 2){
Delay_ms(dtime);
Delay_ms(dtime);
Delay_ms(dtime);
}
Output_low(Green);
Output_High(Yellow);
If (i == 1) Delay_ms(dtime);
If (i == 2) {
Delay_ms(dtime);
Delay_ms(dtime);
}
Output_low(Yellow);
Output_High(Red);
If (i == 1)Delay_ms(dtime);
If (i == 2){
Delay_ms(dtime);
Delay_ms(dtime);
Delay_ms(dtime);
}
Output_Low(Red);
}
Void Allon(){
Output_high(Red);
Output_high(Yellow);
Output_high(Green);
}
Void Flashall(){
Output_Low(Red);
Output_low(Yellow);
Output_low(Green);
Delay_ms(dtime);
Output_High(Green);
Output_High(Yellow);
Output_High(Red);
Delay_ms(dtime);
}
Void Flashgreen(){
Output_Low(Green);
Output_Low(Yellow);
Output_Low(Red);
Delay_ms(dtime);
Output_high(Green);
Delay_ms(1000);
}
Void Flashyellow(){
Output_Low(Green);
Output_Low(Yellow);
Output_Low(Red);
Delay_ms(dtime);
Output_high(Yellow);
Delay_ms(dtime);
}
Void Flashred(){
Output_Low(Green);
Output_Low(Yellow);
Output_Low(Red);
Delay_ms(dtime);
Output_high(Red);
Delay_ms(dtime);
}
#int_RB
Void int_RB_isr(){
int8 prt;
prt = Input_b();
If (prt == 16){
APCount++;
Mode = 1;
If (APCount == 5) APCount = 1;
If (APCount == 1){
Output_Low(Green);
Output_low(Yellow);
Output_Low(Red);
Output_High(Green);
Delay_ms(dtime);
Output_low(Green);
Output_High(Yellow);
Delay_ms(dtime);
Output_low(Yellow);
Output_High(Red);
Delay_ms(dtime);
Output_Low(Red);
}
If (APCount == 2){
Output_Low(Green);
Output_low(Yellow);
Output_low(Red);
dtime = 1000;
Output_High(Green);
Delay_ms(dtime);
Delay_ms(dtime);
Delay_ms(dtime);
Output_low(Green);
Output_High(Yellow);
Delay_ms(dtime);
Delay_ms(dtime);
Output_low(Yellow);
Output_High(Red);
Delay_ms(dtime);
Delay_ms(dtime);
Delay_ms(dtime);
Output_Low(Red);
}
If (APCount == 3) {
Output_Low(Green);
Output_low(Yellow);
Output_Low(Red);
Output_Low(Red);
Output_low(Yellow);
Output_low(Green);
Delay_ms(dtime);
Output_High(Green);
Output_High(Yellow);
Output_High(Red);
Delay_ms(dtime);
}
If (APCount == 4) {
Output_Low(Green);
Output_low(Yellow);
Output_Low(Red);
Output_high(Red);
Output_high(Yellow);
Output_high(Green);
}
}
If (prt == 128){
Mode = 2;
Color = 1;
}
If (prt == 64){
Mode = 2;
Color = 2;
}
If (prt == 32){
Mode = 2;
Color = 3;
}
}
void main()
{
setup_adc_ports(NO_ANALOGS|VSS_VDD);
setup_adc(ADC_OFF);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
setup_oscillator(OSC_8MHZ|OSC_INTRC);
enable_interrupts(GLOBAL);
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
APCount = 1;
Mode = 1;
dtime = 75;
While(true){
Switch(Mode){
Case 1:
If (APCount == 5) APCount = 1;
If (APCount == 1) Runauto(1);
If (APCount == 2) Runauto(2);
If (APCount == 3) Flashall();
If (APCount == 4) Allon();
Break;
Case 2:
If (Color == 1){
Output_Low(Red);
Output_low(Yellow);
Output_high(Green);
}
If (Color == 2){
Output_Low(Red);
Output_High(Yellow);
Output_Low(Green);
}
If (Color == 3){
Output_High(Red);
Output_Low(Yellow);
Output_Low(Green);
}
Break;
Case 5:
Delay_ms(100);
Break;
}
}
}
|
There might be unnecessary routines in this code, I have not touched it in weeks, please excuse me for that.
Thanks,
Oxy |
|
![](templates/subSilver/images/spacer.gif) |
bungee-
Joined: 27 Jun 2007 Posts: 206
|
|
Posted: Sun May 17, 2009 3:56 pm |
|
|
Just a quick observation. Don't use delay's in the interrupt routine. That can lead to unpredictive states. ![Wink](images/smiles/icon_wink.gif) |
|
![](templates/subSilver/images/spacer.gif) |
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Mon May 18, 2009 1:43 am |
|
|
Switch bouncing might be another issue. Search this forum for 'debounce' for several solutions to this problem.
Code: | enable_interrupts(GLOBAL);
clear_interrupt(INT_RB);
enable_interrupts(INT_RB);
APCount = 1;
Mode = 1;
dtime = 75; | Here the interrupt is enabled before the variables it uses are initialized. Revert the sequence. |
|
![](templates/subSilver/images/spacer.gif) |
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Wed May 27, 2009 9:27 am |
|
|
Thanks folks,
I completely forgot I posted this question.
bungee: Originally the delays were in a subroutine and the subroutine got called by the interrupt routine. That didn't work either since it was called by the interrupt routine...
How can I avoid using delays here when I have to time the flashing of the lights?
ckielstra: I will try this however I doubt it will make any difference. I will search for "debounce" after I posted this
Thanks. If you folks have any other ideas please let me know. |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Wed May 27, 2009 9:38 am |
|
|
Approach things completely differentlty.
Have a timer interrupt, at some fastish interval. Perhaps 10msec. Have this check the keys, and if it 'sees' a key pressed, set a flag to say this has been seen. Then on the next call, if the flag is seen, check again, and if the key is still 'true', set an external global variable, to say the particular key has been recorded. Otherwise turn off the flag. This gives the debounce needed for any mechanical key. Also have a 'tick' decremented in the routine, if it is non zero.
Then the main code, sits in a 'state machine', looping as fast as you can. First, check if a key has been recorded. If so, change the 'light state' to reflect this, and set the 'tick', to correspond to the new time required. Then, check the 'tick', and if it reaches zero, change to the next required light state, and set the new tick time for this state. Then loop.
Basically, the main code, sits, timed by the 'tick', changing lights whenever this reaches zero. It is overriden, if a button is pushed, jumping immediately to the new required state. All light changes are done in the 'main', but are timed by the hardware timer interrupt, or triggered by the buttons if required.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Wed May 27, 2009 9:47 am |
|
|
Thank you, that is really nice way of doing this. I will try to rewrite the code to reflect this.
Thanks again. |
|
![](templates/subSilver/images/spacer.gif) |
asmboy
Joined: 20 Nov 2007 Posts: 2128 Location: albany ny
|
using timer0 |
Posted: Wed May 27, 2009 4:28 pm |
|
|
I discovered and have done exactly what Ttelmah suggests - for multiple push button blocks - where I want only the highest PRIORITY button press by reading a 74HC148 3 bit output into 3 bits of PORTB and handling 7 buttons with the LOWEST priority button ( #7 ) always asserted in hardware by tying the input pin.
THEN
on an 18f886 using int 8 mhz clock and
setup timer 0 for RTC/int clockas DIV_64
(prescalar=256 )
this gives an appx 8.192 mSec 'tick' -
define T0IF ( timer zero interupt flag )
simply test for:
If (T0IF) {
T0IF=0; // clear it
see if the masked bit of portb has a change
if so record it
and if THE SAME state on NEXT TICK
it is valid
}
use of the external priority encoder makes the job of sort out multiple
button press 's very easy - if that is your desire as only the highest priority one is reported
} |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|