unsigned short num;
unsigned i;
void main() {
CMCON = 0x07;
TRISB = 0x00;
TRISA = 0xFF;
num = 1;
while (1){
switch (num){
case 1: PORTB = 0x01;
delay_ms(300);
PORTB = 0x00;
delay_ms(300);
break;
case 2: PORTB = 0x02;
delay_ms(300);
PORTB = 0x00;
delay_ms(300);
break;
case 3: PORTB = 0x03;
delay_ms(300);
PORTB = 0x00;
delay_ms(300);
break;
}
if (PORTA.F0 == 1) {
delay_ms(50);
if (PORTA.F0 == 1) {
i++;
num = i;
}
}
}
}
You should not necessarily create a temporary variable "num". The variable "i" could be used as the switch argument. Anyway, the code as wrote will not work as expected, because you did not provided any limit to the counting. You could replace the "i++" statement by: "if (i++ > 3) i=0"
You do not say which PIC you are using, but if it has analogue function available on PORTA, then you will need to disable analogue as described in the datasheet for your PIC
You have the entire PORTA set to inputs. Do you have pullup resistors on all of those pins? If not, they're floating, which is not good. Unused pins should either be set to output and driven low, or set to input and tied high or low. Most peope opt for setting them to outputs.
What does your circuit look like at the button? Most people would tie the pin high via a 10K resistor and have the button pull the pin low.
i need to pressed the switch for 2 seconds in order to change the status. Still trying to solve this
With the code as wrote, you are running a sequential LED blink routine, spending 600ms at each one of the 3 outputs, so just after 1,8 seconds will will be able to read the button. You need to avoid using Delay() functions. Take a look on examples of delays using Timer interruption, so that you can do other stuffs meanwhile.
As andre_teprom said the delays are causing the problem. When delay is executing the button press will not be detected. You have to use Timer Interrupt for making the delay of 300 ms and toggle the required bit of the port in while(1) loop.
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 sbit SW at RA0_bit; unsigned char pattern_counter = 0; //Timer1 //Prescaler 1:8; TMR1 Preload = 28036; Actual Interrupt Time : 300 ms //Place/Copy this part in declaration section void InitTimer1() { T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; TMR1IE_bit = 1; INTCON = 0xC0; } void Interrupt() { if(TMR1IF_bit) { //Enter your code here switch(pattern_counter) { case 0: break; case 1: RB0_bit = ~RB0_bit; break; case 2: RB1_bit = ~RB1_bit; break; case 3: RB2_bit = ~RB2_bit; break; }; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; } } void main() { CMCON = 0x07; TRISA = 0b11100001; TRISB = 0x00; PORTA = 0x01; PORTB = 0x00; InitTimer1(); while(1) { if(SW == 1) { Delay_ms(50); while(SW == 1); if(++pattern_counter > 3)pattern_counter = 0; PORTB = 0x00; } } }
I modified the code a little. Here is the new code. I replaced the signed char counter variable with a unsigned char type and eliminated the use of a negative value for the counter.
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 sbit SW at RA0_bit; unsigned char pattern_counter = 0; //Timer1 //Prescaler 1:8; TMR1 Preload = 28036; Actual Interrupt Time : 300 ms //Place/Copy this part in declaration section void InitTimer1() { T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; TMR1IE_bit = 1; INTCON = 0xC0; } void Interrupt() { if(TMR1IF_bit) { //Enter your code here switch(pattern_counter) { case 0: break; case 1: RB0_bit = ~RB0_bit; break; case 2: RB1_bit = ~RB1_bit; break; case 3: RB2_bit = ~RB2_bit; break; }; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; } } void main() { CMCON = 0x07; TRISA = 0b11100001; TRISB = 0x00; PORTA = 0x01; PORTB = 0x00; InitTimer1(); while(1) { if(SW == 1) { Delay_ms(50); while(SW == 1); if(++pattern_counter > 3)pattern_counter = 0; PORTB = 0x00; } } }
I modified the code a little. Here is the new code. I replaced the signed char counter variable with a unsigned char type and eliminated the use of a negative value for the counter.
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 unsigned short num; unsigned i; void InitTimer1() { T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; TMR1IE_bit = 1; INTCON = 0xC0; } void Interrupt() { if(TMR1IF_bit) { switch (num) { case 1:PORTB = 0x01; delay_ms(300); PORTB = 0x00; delay_ms(300); break; case 2:PORTB = 0x02; delay_ms(300); PORTB = 0x00; delay_ms(300); break; case 3:PORTB = 0x03; delay_ms(300); PORTB = 0x00; delay_ms(300); break; } // case end TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; } } void main() { CMCON = 0x07; TRISB = 0x00; TRISA = 0xFF; InitTimer1(); num = 1; // initialize status while (1){ if (PORTA.F0 == 1) { if (i++ > 3) i=1; num = i; } } }
An interrupt is a condition that causes the microprocessor to temporarily work on a different task
PORTA = 0x01;
PORTA = 0x00;
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 unsigned char num = 0; //Timer1 //Prescaler 1:8; TMR1 Preload = 28036; Actual Interrupt Time : 300 ms //Place/Copy this part in declaration section void InitTimer1() { T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; TMR1IE_bit = 1; INTCON = 0xC0; } void Interrupt() { if(TMR1IF_bit) { //Enter your code here switch(num) { case 0: break; case 1: RB0_bit = ~RB0_bit; break; case 2: RB1_bit = ~RB1_bit; break; case 3: RB2_bit = ~RB2_bit; break; }; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; } } void main() { CMCON = 0x07; TRISA = 0b11100001; TRISB = 0x00; PORTA = 0x00; PORTB = 0x00; InitTimer1(); while(1) { if(PORTA.F0 == 1) { Delay_ms(50); while(PORTA.F0 == 1); if(++num > 3)num = 0; PORTB = 0x00; } } }
If you are not yet confortable building delays based on Timer interrupt, another option that you could consider on the original closed loop Delay() approach, is using pin-change interrupt. You did not mention for which PIC familly you made this code, but at least on the 16F core, the PORTB has this funtionality. On this case, the button read is done by sensing changes on a specific pin of this port.
Hi
As andre_tepro suggested please don't use delays in interrupt service routine (isr). The timer interrupt is used to generate 300 ms delay. You have to just toggle the required PORTB pin based on the counter value. Also in your code value of variable num is 1 before entering while(1) loop nd this will make RB0 LED to blink as soon as the device is turned on because InitTimer1() is called before while(1) loop and the timer is ON all the time ( same in my code but I use counter value 0 to keep all pins turned off).
There was one bug in my code. Please change
Code:PORTA = 0x01;
to
Code:PORTA = 0x00;
And where did the debounce delay go in the button press detect code ?
This is a tested code which I made from your code and it is working.
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 unsigned char num = 0; //Timer1 //Prescaler 1:8; TMR1 Preload = 28036; Actual Interrupt Time : 300 ms //Place/Copy this part in declaration section void InitTimer1() { T1CON = 0x31; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; TMR1IE_bit = 1; INTCON = 0xC0; } void Interrupt() { if(TMR1IF_bit) { //Enter your code here switch(num) { case 0: break; case 1: RB0_bit = ~RB0_bit; break; case 2: RB1_bit = ~RB1_bit; break; case 3: RB2_bit = ~RB2_bit; break; }; TMR1IF_bit = 0; TMR1H = 0x6D; TMR1L = 0x84; } } void main() { CMCON = 0x07; TRISA = 0b11100001; TRISB = 0x00; PORTA = 0x00; PORTB = 0x00; InitTimer1(); while(1) { if(PORTA.F0 == 1) { Delay_ms(50); while(PORTA.F0 == 1); if(++num > 3)num = 0; PORTB = 0x00; } } }
TRISA = 0b11100001;
So is it means that i dont use delay now, and to replace the delay, i need to use timer. am i right?
Code C - [expand] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 sbit LED1 at RB1_bit; sbit LED2 at RB2_bit; sbit LED3 at RB3_bit; unsigned char num = 0; void Interrupt() { if(INTF_bit) { if(++num > 3) { num = 0; } PORTB = 0x00; INTF_bit = 0; } } void main() { CMCON = 0x07; TRISA = 0b11100000; TRISB = 0x01; PORTA = 0x00; PORTB = 0x00; INTEDG_bit = 1; INTE_bit = 1; PEIE_bit = 1; GIE_bit = 1; while(1) { switch(num) { case 1: RB1_bit = ~RB1_bit; Delay_ms(300); break; case 2: RB2_bit = ~RB2_bit; Delay_ms(300); break; case 3: RB3_bit = ~RB3_bit; Delay_ms(300); break; } } }
Hi
Yes. The comment of the InitTimer1() shows that it is configured for 300 ms and so the ISR (Interrupt Service Routine) is called once every 300 ms.
RA6 and RA7 are for Oscillator and RA5 is for MCLR and hence configured as inputs in TRISA. RA0 is for Button and also configured as input pin.
See attached Circuit.
What andre_teprom suggestes is to retain the delay_ms() based code in the while(1) loop and use INTIE for the button and increment the pattern_counter (num) inside the INTIF interrupt.
- - - Updated - - -
Here is the project which uses INTE (External Interrupt) for button press detection as mentioned by andre_teprom and here is its mikroC PRO code. See attached video for working of the project.
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?
We use cookies and similar technologies for the following purposes:
Do you accept cookies and these technologies?