|
|
View previous topic :: View next topic |
Author |
Message |
corgenius
Joined: 27 May 2015 Posts: 18
|
A Clever Button |
Posted: Mon Jul 13, 2015 11:26 am |
|
|
Dear colleagues,
This days I'm trying to make a "clever" button with the help of my loyal friend, the 675 pic .
The projects sounds something like this:
If button is pressed for more then 200 ms then do nothing. If button is pressed for more then 200 ms then LED ON .
My code looks something like this :
Code: | #include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 previous, current, previous2, current2;
delay_us(100); // delay for pullups - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
previous2 = !input(LAMP_BUTTON2); // read buton2
previous = !input(LAMP_BUTTON); // read buton
//===========================================================================================
//first input
While (true) // FOREVER LOOP
{
current2 = !input(LAMP_BUTTON2);
if((current2 == SWITCH_PRESSED) && (previous2 == SWITCH_NOT_PRESSED))
{
delay_ms(200);
if((current2 == SWITCH_NOT_PRESSED) && (previous2 == SWITCH_PRESSED))
{
output_low(LAMP); // PIN_A2
}}
current2 = !input(LAMP_BUTTON2);
if((current2 == SWITCH_PRESSED) && (previous2 == SWITCH_NOT_PRESSED))
{
delay_ms(300);
if((current2 == SWITCH_NOT_PRESSED) && (previous2 == SWITCH_PRESSED))
{
output_high(LAMP); // PIN_A2
}}
}
} |
Any ideas how I can make this work?
Thank you for your time,
Warm regards,
Eugeniu |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Mon Jul 13, 2015 11:48 am |
|
|
Hi,
I'd start by updating your description of what you want the program to do, because this makes no sense:
Quote: |
If button is pressed for more then 200 ms then do nothing. If button is pressed for more then 200 ms then LED ON.
|
I suspect there should be a 'less than' in there somewhere, but you should tell us, we shouldn't have to guess!
John |
|
|
corgenius
Joined: 27 May 2015 Posts: 18
|
|
Posted: Mon Jul 13, 2015 11:51 am |
|
|
ezflyr wrote: | Hi,
I'd start by updating your description of what you want the program to do, because this makes no sense:
Quote: |
If button is pressed for more then 200 ms then do nothing. If button is pressed for more then 200 ms then LED ON.
|
I suspect there should be a 'less than' in there somewhere, but you should tell us, we shouldn't have to guess!
John |
Dear John,
You are right, sorry .
The right statement should of been Quote: | If button is pressed for LESS then 200 ms then do nothing. If button is pressed for more then 200 ms then LED ON. |
Eugeniu |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Mon Jul 13, 2015 12:10 pm |
|
|
Consider something like this (easily expanded for two buttons in the same loop, and in 'theoretical' code):
Code: |
int tick1=0;
while (TRUE)
{
if (button1_is_on)
{
if (tick1<180)
tick1++
else
what_you_want_for_button1_on;
}
else
{
tick1=0;
what_you_want_for_button1_off;
}
delay_ms(1);
}
|
The point is your loop executes at just over 1mSec (delay plus the tests), when the button is seen as having been on for 180 loops (so about 200mSec), the 'what you want for on' executes, when it is released 'what you want for off' executes.
Add a second counter and second set of tests, and a second button can be handled.
If you want the 'what you want' codes to execute only once, then you can use your 'last condition' tests if needed, however for what you describe they are not needed. |
|
|
corgenius
Joined: 27 May 2015 Posts: 18
|
|
Posted: Tue Jul 14, 2015 1:38 pm |
|
|
Dear Ttelmah,
Thank you for your code. I've tried to integrate it in my code, but with no success :(. The PIC is not executing the "output_high part" no matter what value I set for tick.
My code is :
Code: | #include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 previous, current, previous2, current2;
int tick1;
delay_us(100); // delay for pullups (daca exista) - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
previous2 = !input(LAMP_BUTTON2); // citeste stare buton
tick1=0;
//===========================================================================================
//primul input
While (true) // FOREVER LOOP
{
current2 = !input(LAMP_BUTTON2);
if((current2 == SWITCH_PRESSED) && (previous2 == SWITCH_NOT_PRESSED))
{
if (tick1<180)
tick1++;
else
output_high(LAMP); // PIN_A2
delay_ms(500);
output_low(LAMP);
previous2 = current2;
}
else
{
tick1=0;
output_low(LAMP);
}
delay_ms(1);
}
} |
Thank you for your time,
Warm regards,
Eugeniu |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Tue Jul 14, 2015 2:03 pm |
|
|
You don't want the pressed/not pressed part where you have it. The code already rejects a pressed edge unless it remains on for 180 counts.
Code: |
#include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 current2=SWITCH_NOT_PRESSED;
int8 tick1=0;
int16 lamp_count=0;
delay_us(100); // delay for pullups (daca exista) - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
//===========================================================================================
//primul input
While (true) // FOREVER LOOP
{
if(input(LAMP_BUTTON2)==SWITCH_PRESSED)
{
if (tick1<180)
tick1++;
else
{
if (current2==SWITCH_NOT_PRESSED)
{
lamp_count=460;
current2=SWITCH_PRESSED;
}
}
}
else
{
tick1=0;
lamp_count=0;
current2=SWITCH_NOT_PRESSED;
}
if (lamp_count)
{
output_high(LAMP);
lamp_count--;
}
else
output_low(LAMP);
delay_ms(1);
}
}
|
The key is that the master 'loop' wants to execute continuously. You do all your timings in terms of this (so you can add more buttons etc.). This includes the lamp timings. As soon as you add delays into part of the code you stop the keyscan. |
|
|
ezflyr
Joined: 25 Oct 2010 Posts: 1019 Location: Tewksbury, MA
|
|
Posted: Tue Jul 14, 2015 2:32 pm |
|
|
Hi,
Threads like this always make we wonder how people are troubleshooting & debugging their code. My guess is that you are compiling the code, loading it into the chip, and then attempting to run the code as it's intended? If so, you have absolutely zero feedback about what's going on internally, and you can't track the 'flow' of your code's execution. In essence, you are totally blind to what is going on! This is a really, really bad troubleshooting strategy, and will lead to long development times, and lots of frustration.
On my PIC projects, I always devote at least one pin for sending diagnostic serial messages. I know your PIC is a small one, but usually you can spare a single pin, at least temporarily, to help debug your code.
In the case of your code, I'd probably change the 'loop time' to a much longer value for troubleshooting purposes, and I'd sprinkle some diagnostic messages into the code so that I could track the program execution flow. If you'd done this, I think you would have quickly seen your own problem? I've done many projects with the '675, and it can be done!
I put a small diagnostic header on my PCB's, that connects to a small PCB containing a TTL to RS232 converter chip (MAX232), so that this extra hardware does not need to be on my PCB. _________________ John
If it's worth doing, it's worth doing in real hardware! |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Wed Jul 15, 2015 1:21 am |
|
|
Very much agreed.
I'll often 'double use' a pin. So for instance if I have a status LED in the final design, the same pin can be connected via a crude TTL->RS232 circuit, and used to give software serial out for debugging. Or the LED itself can be flashed at rates above 'human perception', which can then be read with an oscilloscope, to give basic counts, corresponding to stages in the code. I'll often have a macro 'DEBUG', and through the code at points put 'DEBUG(1)' etc., so I can just monitor that pin and see that I _have_ reached this point, and _when_ I reach this relative to other events. Trying to build code without some way of 'seeing' the flow like this, would be like a blind man trying to drive a car (without a sighted person acting as a 'guider'). |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Wed Jul 15, 2015 2:05 am |
|
|
The suggestions to use a pin for debugging messages or LED flashing is a poor man's debugger. They are useful tools for specific situations but my tools of choice are the MPLAB simulator and an In Circuit Debuggers (ICD). These tools allow to single step through my program and allow me to inspect or change any variable at will. Or just run the program up till a set breakpoint is reached. No need to add extra debugging code to my program and I've access to all the information I ever need.
The MPLAB simulator allows to test software without hardware, great for a quick test or when the hardware design isn't finished yet.
Many projects require a connection to specific hardware that can't be simulated, then an ICD comes in handy. It requires two dedicated hardware pins, but those are the same pins used for in-circuit programming already present in many designs. Example devices are:
- CCS ICD-U64 for $89
- Microchip PICkit 3 for $48
- Microchip ICD 3 for $200
The cheap PICkit device has served me well as both a programmer and debugging tool. |
|
|
corgenius
Joined: 27 May 2015 Posts: 18
|
|
Posted: Sat Jul 25, 2015 2:00 pm |
|
|
Dear colleagues,
Sorry for not posting any result in a while but I've been traveling with work and only tonight I've got the change to look at the code that Ttelmah suggested.
Thank you for the code Ttelmah, but unfortunately it doesn't work as i need it to work. :(
First I've changed the logic of the buttons in order to make the LED turn ON, because my system works for 0 V. That wasn't easily fixable, but I've encountered some other problems.
One of them was that the LED turned ON, but I don't know how to insert also a timer in the equation to make it go OFF after a period of time.Also, I don't really understand what lamp_count does....
Thank you so much for the support! I would really appreciate if I could finish this project until Monday. In rest, the program needs to stay the same : If button is pressed for LESS then 200 ms then do nothing. If button is pressed for more then 200 ms then LED ON for 1000 ms then LED OFF.
And finally, if the button is continuous pressed I need the LED to do the cycle just ONCE.
With Ttelmah's code I've noticed that for a continuous press of the button the cycle restarts itself. Some of this details I didn't posted in my first post, sorry for that.
Warm regards,
Eugeniu
Code: | #include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 current2=SWITCH_NOT_PRESSED;
int8 tick1=0;
int16 lamp_count=0;
delay_us(100); // delay for pullups (daca exista) - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
//===========================================================================================
//primul input
While (true) // FOREVER LOOP
{
if(input(LAMP_BUTTON2)==SWITCH_PRESSED)
{
if (tick1<180)
tick1++;
else
{
if (current2==SWITCH_NOT_PRESSED)
{
lamp_count=460;
current2=SWITCH_PRESSED;
}
}
}
else
{
tick1=0;
lamp_count=0;
current2=SWITCH_NOT_PRESSED;
}
if (lamp_count)
{
output_high(LAMP);
lamp_count--;
}
else
output_low(LAMP);
delay_ms(1);
}
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Jul 26, 2015 1:07 am |
|
|
I hope you mean "was", not "wasn't" easy to fix for changing the lamp logic. That is so simple, if you can't do that easily, then we might as well give up....
Draw yourself a 'task' diagram. Like a flow chart.
Now have the main loop executing 1000* per second.
Task 1: Is button on?. If so switch to task 2.
Task 2: Turn LED on. Load 'timer' with a count. Advance to task 3.
Task 3: Decrement timer/ Is it zero?. Yes. Advance to task 4.
Task 4: Switch LED off. Switch to task 1.
This doesn't do what you describe as wanting, but gives you an idea of how to lay things out. The loop executes 1000* per second, and the current task is executed. Each task just does what is needed and exits immediately. So the delay is done by counting 'timer'.
This is then very easy to code.
The tasks can be done _very_ easily as a 'switch... case' statement.
The point is you don't stop and do things, but keep looping. This then allows multiple things to be done. So (for instance), after the first flurry of tasks to handle one switch, you can just duplicate these tasks for a second switch. The current operation for switch 1, is then done, followed by the operation for switch 2. Since each operation is quick, there is no noticeable interaction between the jobs. |
|
|
corgenius
Joined: 27 May 2015 Posts: 18
|
|
Posted: Sun Jul 26, 2015 1:32 am |
|
|
Dear Ttelmah,
In my last post I've meant "was", sorry for the typo...
I've followed your advice and draw a task diagram, that looks something like this:
Question1 : Is the button pressed (0V at pin A2) for more then 200ms?
Question1NO : Go to Question1
Question1YES : Go to Task1
Task1 : Turn LED ON (5V at A5) , delay_ms (1000) , LED OFF. (here I think I need to put a variable in order to make the code run just once in case of someone continuously keeps the button pressed - tricky part). Go to Question1.
I'm not really familiar with the 'switch... case' statement and that's why I prefer to implement just "if" statements.
Thank you for your time and guidance,
Eugeniu
Edit :
I've added the delay for the LED, but when the button is continuously pressed the code start the cycle all over. For this problem I've added current2=SWITCH_PRESSED at the end of the code to make it stop there, but with no succes :(
Code: | #include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 current2=SWITCH_NOT_PRESSED;
int8 tick1=0;
int16 lamp_count=0;
delay_us(100); // delay for pullups (daca exista) - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
//===========================================================================================
//primul input
While (true) // FOREVER LOOP
{
if(input(LAMP_BUTTON2)==SWITCH_NOT_PRESSED)
{
if (tick1<200)
tick1++;
else
{
if (current2==SWITCH_PRESSED)
{
lamp_count=1;
current2=SWITCH_NOT_PRESSED;
}
}
}
else
{
tick1=0;
lamp_count=0;
current2=SWITCH_PRESSED;
}
if (lamp_count>0)
{
output_high(LAMP);
delay_ms(1000);
}
else
output_low(LAMP);
delay_ms(1);
}
[b]current2=SWITCH_PRESSED;[/b]
} |
|
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Jul 26, 2015 7:48 am |
|
|
No.
Task 1: Is button pressed. Yes: (count=200. Task=2)
Task 2: Is button still pressed?. No: back to task 1. Yes: Does --count=0? Yes goto task 3
You need to stop thinking about putting times into the tasks. The times are just counts of the loop. So if the button stays pressed for 200 calls to task 2, it says 'OK' go on to task 3. If the button is released at any time it goes back to doing task 1.
Putting times into the tasks, stops your code doing anything else. The whole point is that you want to do multiple things, so you have to change how you think, and instead of having a linear flow through one piece of code, you loop continuously doing jobs that never delay/stop. |
|
|
corgenius
Joined: 27 May 2015 Posts: 18
|
|
Posted: Sun Jul 26, 2015 9:21 am |
|
|
Ok, so the first part of the code stays the same :
Code: | #include <12F675.h>
#FUSES INTRC_IO
#use delay(clock=4MHz)
#define LAMP_BUTTON PIN_A0
#define LAMP_BUTTON2 PIN_A2
#define LAMP PIN_A5
#define LAMP2 PIN_A4
#define LAMP3 PIN_A1
#define SWITCH_PRESSED 0 // 5V
#define SWITCH_NOT_PRESSED 1 // 0V
//============================================================================================
void main()
{
int8 current2=SWITCH_NOT_PRESSED;
int8 tick1=0;
int16 lamp_count=0;
delay_us(100); // delay for pullups (daca exista) - start up delay
output_high(LAMP3); // STATUS - LED ON = MICROCONTROLER ON
//===========================================================================================
//primul input
While (true) // FOREVER LOOP
{
if(input(LAMP_BUTTON2)==SWITCH_NOT_PRESSED)
{
if (tick1<180)
tick1++;
else
{
if (current2==SWITCH_NOT_PRESSED)
{
lamp_count=460;
current2=SWITCH_PRESSED;
}
}
}
else
{
tick1=0;
current2=SWITCH_NOT_PRESSED;
}
|
The code checks 180 times if button pressed if it still is, then it makes lamp_count = 460 and leaves second "if"
Next task is :
Code: |
if (lamp_count>0)
{
output_high(LAMP);
lamp_count--;
}
else
output_low(LAMP);
delay_ms(1);
}
|
Lamp_count being 460, LAMP turns ON and stays ON until the uC counts from 460 to 0. When Lamp_count= 0 then LAMP tuns OFF and waits 1 ms.
I think this pieces of code respect Task 1 & 2.The problem that I don't know how to create Task 3, in order to fix the "continuous press" bug. (if the button is pressed for a longer period of time the code restarts it's cycle). I was thinking something like :
Task 1: Is button pressed. Yes: (count=200. Task=2)
Task 2: Is button still pressed?. No: back to task 1. Yes: Does --count=0? Yes goto task 3
Task 3: Code: | output_low(LAMP);
delay_ms(1); | and somehow prevent the code from restarting....still thinking about this part...
I've understood now that delays are the wrong way to go, thank you Ttelmah .
Any suggestions will be appreciated.
Warm regards,
Eugeniu |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19540
|
|
Posted: Sun Jul 26, 2015 9:49 am |
|
|
Hurrah.
Yes, it's a switch in 'thinking' needed to make your code effectively 'multi task'.
Now there is no reason you can't have a huge number of tasks. Though it'll then be simpler to use 'switch case', instead of 'if'.
So you can add a task to the list that basically ignores a key if it is still pressed (then when released goes back to the 'looking' job). If you call this when the lamp time finishes, then if the key is held in, it won't matter.
Now even better is to use names for the tasks.
- not actual code
So:
Code: |
//I'd #define 'button_pressed', so
#define button_pressed() (input(LAMP_BUTTON1)==SWITCH_PRESSED)
enum {LOOK_FOR_BUTTON, WAIT_200, LAMP_500, IGNORE_STILL_ON} task;
int16 ticks;
switch (task)
{
case LOOK_FOR_BUTTON:
if (button_pressed())
{
task=WAIT_200;
ticks=200;
}
break;
case WAIT_200:
if (button_pressed())
{
if (ticks)
--ticks;
else
{
//button has been pressed for 200 ticks
ticks=500;
task=LAMP_500;
}
}
else //button released
task=LOOK_FOR_BUTTON'
break;
case LAMP_500:
if (ticks)
{
lamp_on(); //again I'd define this - haven't done so
--ticks;
}
else
{
lamp_off(); //same comment
task=IGNORE_STILL_ON;
}
break;
case IGNORE_STILL_ON:
if (! button_pressed())
task=LOOK_FOR_BUTTON;
break; //wait for the button to go off
}//end of switch
|
Now, this makes it much easier to see what each 'task' does. Even better if you typedef the task, you could use the same definitions for the second button. Then if you tweak the delay for the loop, so instead of using 'delay_ms(1)', use delay_us(900) (possibly) then the loop time will be close to 1mSec, so the times can all be done in mSec counts (neater). Then if you name (either #define or declare functions), to check the button etc., the code becomes far more 'self commenting'.
I've only done some of the tasks, and an example define, but hopefully you can see where it goes. |
|
|
|
|
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
|