View previous topic :: View next topic |
Author |
Message |
Namams
Joined: 01 Feb 2019 Posts: 9
|
Help with PIC16F818 |
Posted: Fri Feb 01, 2019 3:56 pm |
|
|
I'm a newbie to this site, so please excuse me if I'm posting in the wrong forum section, or if my question is too elementary. I've just recently started using MPLab with a CCS complier to program a PIC16F819 I'm trying to write a code in which a single LED is switched on if 2 certain switches are pressed within 2 seconds of each other. I've started a basic code in which I have 4 inputs (switches) and four outputs (LED's) at the moment each switch corresponds to a single LED so if I was to press switch1 then LED1 lights up.
I want to program the PIC so that LED1 would light up if I was to press switch1 and then switch2 (within 2 seconds of each other).
I was thinking of having a timer running in the background so when the first button is pressed, it makes a copy of the current time and when the second button is pressed, it takes another copy of the current time. I could then subtract the first time from the second time to see the difference between them. If the difference is 2 seconds or less, then the LED would light up.
However, I have no idea how to program the above can someone please help me with the coding required.
Thanks in advance.
Current code:
Code: |
#include <16F819.h>
#fuses INTRC_IO,NOWDT,NOPROTECT,MCLR,NOBROWNOUT
#use delay(clock=4000000)
#define SW2 PIN_B7
#define SW2 PIN_B6
#define SW3 PIN_B5
#define SW4 PIN_B4
#define LED1 PIN_B3
#define LED2 PIN_B2
#define LED3 PIN_B1
#define LED4 PIN_B0
void main()
{
port_b_pullups(TRUE);
while(1)
{
if(!input(SW1)) output_high(LED1);
if(!input(SW2)) output_high(LED2);
if(!input(SW3)) output_high(LED3);
if(!input(SW4)) output_high(LED4);
}
}
|
|
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 5:51 am |
|
|
Hi,
the code is completely untested, but this is how I would do it. I'm sure there are easier ways :-)
Code: |
#include <main.h>
#define SW1 PIN_B7
#define SW2 PIN_B6
#define SW3 PIN_B5
#define SW4 PIN_B4
#define LED1 PIN_B3
#define LED2 PIN_B2
#define LED3 PIN_B1
#define LED4 PIN_B0
int1 GO = 0;
int1 SW1_PRESSED = 0;
int1 SW2_PRESSED = 0;
int1 SW3_PRESSED = 0;
int1 SW4_PRESSED = 0;
int8 LIGHT_LED1 = 0; // LED1 state machine
#define LED1_SW1 0 // states for LED1
#define LED1_SW2 1
#define LED1_ON 2
int8 Counter1 = 0; // counter between two switches
#INT_RB
void RB_isr(void) { // something changed
if(!input_state(SW1)){ // SW1 level = 0V. I presume that you close the switch to 0
SW1_PRESSED = 1;
}
else{
SW1_PRESSED = 0;
}
if(!input_state(SW2)){ // SW2 level = 0V. I presume that you close the switch to 0
SW2_PRESSED = 1;
}
else{
SW2_PRESSED = 0;
}
if(!input_state(SW3)){ // SW3 level = 0V. I presume that you close the switch to 0
SW3_PRESSED = 1;
}
else{
SW3_PRESSED = 0;
}
if(!input_state(SW4)){ // SW4 level = 0V. I presume that you close the switch to 0
SW4_PRESSED = 1;
}
else{
SW4_PRESSED = 0;
}
}
#INT_TIMER1 // 131ms overflow
void TIMER1_isr(void) {
}
#INT_TIMER0 // 65,5ms overflow
void TIMER0_isr(void) {
GO = 1;
}
void main() {
port_b_pullups(0xFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //65,5 ms overflow
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //131 ms overflow
setup_timer_2(T2_DIV_BY_16,77,16); //1,2 ms overflow, 19,9 ms interrupt
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(TRUE){
if(GO){
GO = 0; // execute this loop every 65,5ms
// ******************** check LED1 condition **********************************
switch (LIGHT_LED1){ // nothing is pressed, we are waiting for SW1 to be pressed
case LED1_SW1:{
if(SW1_pressed){ // we have SW1 press, go check SW2
Counter1 = 0;
LIGHT_LED1 = LED1_SW2; // proceed to SW2 wait
break;
}
}
case LED1_SW2:{
Counter1++;
if(Counter1 > 31){
LIGHT_LED1 = LED1_SW1; // go back waiting for SW1, we waited for more than 2s 65,5ms * 32
break;
}
if(SW2_pressed){
LIGHT_LED1 = LED1_ON; // proceed to turn on LED1
break;
}
}
case LED1_ON:{
output_low(LED1);
break;
}
} // switch LIGHT_LED1 brace
// ************************ END LED1 check ************************************
} // if GO brace
} // while brace
}
|
Please note, you have no debouncing and no code to turn the LED1 off.
Regards |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 5:52 am |
|
|
and main.h
Code: |
#include <16F819.h>
#device ADC=10
#use delay(internal=4000000)
|
|
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 6:03 am |
|
|
First error, the code never exits case 2. It should be:
if(SW2_pressed){
LIGHT_LED1 = LED1_ON; // proceed to turn on LED1
break;
}
else{
break;
}
And I chose the wrong pic, 819 instead of 818 |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 8:08 am |
|
|
Spotted another mistake, break in case. This is the corrected version:
Code: |
#include <main.h>
#define SW1 PIN_B7
#define SW2 PIN_B6
#define SW3 PIN_B5
#define SW4 PIN_B4
#define LED1 PIN_B3
#define LED2 PIN_B2
#define LED3 PIN_B1
#define LED4 PIN_B0
int1 GO = 0;
int1 SW1_PRESSED = 0;
int1 SW2_PRESSED = 0;
int1 SW3_PRESSED = 0;
int1 SW4_PRESSED = 0;
int8 LIGHT_LED1 = 0; // LED1 state machine
#define LED1_SW1 0 // states for LED1
#define LED1_SW2 1
#define LED1_ON 2
int8 Counter1 = 0; // counter between two switches
#INT_RB
void RB_isr(void) { // something changed
if(!input_state(SW1)){ // SW1 level = 0V. I presume that you close the switch to 0
SW1_PRESSED = 1;
}
else{
SW1_PRESSED = 0;
}
if(!input_state(SW2)){ // SW2 level = 0V. I presume that you close the switch to 0
SW2_PRESSED = 1;
}
else{
SW2_PRESSED = 0;
}
if(!input_state(SW3)){ // SW3 level = 0V. I presume that you close the switch to 0
SW3_PRESSED = 1;
}
else{
SW3_PRESSED = 0;
}
if(!input_state(SW4)){ // SW4 level = 0V. I presume that you close the switch to 0
SW4_PRESSED = 1;
}
else{
SW4_PRESSED = 0;
}
}
#INT_TIMER1 // 131ms overflow
void TIMER1_isr(void) {
}
#INT_TIMER0 // 65,5ms overflow
void TIMER0_isr(void) {
GO = 1;
}
void main() {
port_b_pullups(0xFF);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_256|RTCC_8_BIT); //65,5 ms overflow
setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //131 ms overflow
setup_timer_2(T2_DIV_BY_16,77,16); //1,2 ms overflow, 19,9 ms interrupt
enable_interrupts(INT_RB);
enable_interrupts(INT_TIMER1);
enable_interrupts(INT_TIMER0);
enable_interrupts(GLOBAL);
while(TRUE){
if(GO){
GO = 0; // execute this loop every 65,5ms
// ******************** check LED1 condition **********************************
switch (LIGHT_LED1){ // nothing is pressed, we are waiting for SW1 to be pressed
case LED1_SW1:{
if(SW1_pressed){ // we have SW1 press, go check SW2
Counter1 = 0;
LIGHT_LED1 = LED1_SW2; // proceed to SW2 wait
}
break;
}
case LED1_SW2:{
Counter1++;
if(Counter1 > 31){
LIGHT_LED1 = LED1_SW1; // go back waiting for SW1, we waited for more than 2s 65,5ms * 32
break;
}
if(SW2_pressed){
LIGHT_LED1 = LED1_ON; // proceed to turn on LED1
}
break;
}
case LED1_ON:{
output_low(LED1);
break;
}
} // switch LIGHT_LED1 brace
// ************************ END LED1 check ************************************
} // if GO brace
} // while brace
}
|
|
|
|
Namams
Joined: 01 Feb 2019 Posts: 9
|
|
Posted: Sat Feb 02, 2019 8:30 am |
|
|
Thank you that's really helpful I think I understand most of it I just wanted to ask if the code would keep the LED on after both buttons are pressed( or if it switches off after a while) . Also if I want to do the same thing multipule times using different switch combinations would I copy the same body of test but just change the switches and LED's accordingly. Thank you again for your reply |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 8:50 am |
|
|
Right now the diode stays lit, but you could easily add some code to turn it off after a while or when you press some key. Please test first if this part works as intended.
Regards,
Samo |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Sat Feb 02, 2019 9:56 am |
|
|
I just tested it, it works. I changed SW1 and SW2 to B4 and B5 so to be able to use the debugger and added some code that switches the diode off after a while.
Code: |
while(TRUE){
if(GO){
GO = 0; // execute this loop every 65,5ms
// ******************** check LED1 condition **********************************
switch (LIGHT_LED1){ // nothing is pressed, we are waiting for SW1 to be pressed
case LED1_SW1:{
output_high(LED1); // turn off the led
if(SW1_pressed){ // we have SW1 press, go check SW2
Counter1 = 0;
LIGHT_LED1 = LED1_SW2; // proceed to SW2 wait
}
break;
}
case LED1_SW2:{
Counter1++;
if(Counter1 > 31){
LIGHT_LED1 = LED1_SW1; // go back waiting for SW1, we waited for more than 2s 65,5ms * 32
break;
}
if(SW2_pressed){
LIGHT_LED1 = LED1_ON; // proceed to turn on LED1
Counter1 = 0;
}
break;
}
case LED1_ON:{
Counter1++; // Counter1 is zero when we come here
if(Counter1 < 50){
output_low(LED1); // turn on the led
}
else{
Counter1 = 0;
LIGHT_LED1 = LED1_SW1; // leave the led on for a while, then go to beggining
}
break;
}
} // switch LIGHT_LED1 brace
// ************************ END LED1 check ************************************
} // if GO brace
} // while(TRUE) brace
|
|
|
|
Namams
Joined: 01 Feb 2019 Posts: 9
|
|
Posted: Mon Feb 04, 2019 4:36 am |
|
|
Hi I've just tried the code but it doesn't see to be doing anything, the LED stays off regardless of if the switches are pressed or not.
Also can you please explain the setup_timer lines of the code.For example I understand that the DIV_BY is used to set the prescaler but why does timer 2 say DIV_BY_16,77,16 and why does it not have the _INTERNAL part like the other 2 timers.Finally can you also explain the switch case loop briefly.
If it's possible can you please upload a image of your circuit setup so I can compare it to mine to see if I have made an error setting it up.
Thank you again for taking time to help me.
Last edited by Namams on Mon Feb 04, 2019 4:53 am; edited 2 times in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19550
|
|
Posted: Mon Feb 04, 2019 4:46 am |
|
|
You do have pull up resistors on the switches?.
The code all assumes that the pins have resistors on them (perhaps 10KR)
pulling the pins 'up' to the supply. Then the switches pull the pins down.
So when the switch is 'on', the input is 0v, and when the switch is 'off' the
input goes up to the supply voltage. |
|
|
Namams
Joined: 01 Feb 2019 Posts: 9
|
|
Posted: Mon Feb 04, 2019 4:48 am |
|
|
Yep the switches are connected to pull up resistors |
|
|
temtronic
Joined: 01 Jul 2010 Posts: 9245 Location: Greensville,Ontario
|
|
Posted: Mon Feb 04, 2019 5:53 am |
|
|
also, you should have a small value cap, say .1mfd across the switch (parallel). This will help minimize or reduce contact bounce'. Without it, the switch will give several '1-0-1-0' levels for every press. This is a hardware solution. You can and should also add a software delay(10-50 ms) when reading pushbuttons.
you can use the light blue search button ,enter 'bounce' and you'' get a lot of hits.
Jay |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Mon Feb 04, 2019 7:19 am |
|
|
Hi,
the code was tested on 18f252. The setup is very simple, PIC, two push button switches and 4 wires. I didn't even use external resistors. Can you confirm that your PIC is working? Maybe by turning a LED on at the start? And if it is, then turn a LED on when the PIC enters the interrupt routine, to see if it ever comes there at all. Please check if the push of the button actually changes the voltage from 5V to 0V on those two pins.
As for the timers, the built-in wizard in CCS created the code :-). I did an excel spreadsheet once to see how it works and what the numbers mean, but I must admit that I'm too lazy to do it by hand. Anyway, the code doesn't use Timer2. |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19550
|
|
Posted: Mon Feb 04, 2019 8:02 am |
|
|
and, of 'why it doesn't have INTERNAL', this is a read the data sheet and look
at the header question.
Basically Timer2 on most of the standard PIC's, has 'no choice' about where
it is fed from. No external input pin, only capable of being fed from the
internal oscillator, so no selection has to be made.
If you look at the block diagram in the data sheet, the only clock input
to timer2, is Fosc/4. Nothing else. |
|
|
PrinceNai
Joined: 31 Oct 2016 Posts: 480 Location: Montenegro
|
|
Posted: Mon Feb 04, 2019 8:19 am |
|
|
Please also check how the LED is oriented. It should go from 5V to the PIC pin. 0V on that pin turns the diode on. |
|
|
|