View previous topic :: View next topic |
Author |
Message |
oxxyfx
Joined: 24 May 2007 Posts: 97
|
Question about creating delays inside of a while loop |
Posted: Thu May 15, 2008 8:57 am |
|
|
Hello,
I have written the code below. The purpose of this is to use is as a video source switcher between 2 video sources. The program will verify the position of the RC Transmitter stick or switch and it will switch a pin high or low in function of the stick position - by counting the lenght of the pulses.
There is also a failsafe which should prevent switching on it's own - it will switch only after 10 valid pulses in the required range are received.
The other failsafe I need to build in, is that in case of a complete signal loss after 2 or 4 seconds (value to be determined) it will switch back to the 1st video source. Now this is the part which is not working, and I do not understand why. At the moment once I switch the RC receiver off, it switches right away without any delay. I need a 2 to 4 seconds delay there, because the signal loss might be temporary and may come back in less then 2-4 seconds.
So here is the code:
Code: |
#include "Vidsplit.h"
#define Signal PIN_A4 //define pin for incoming signal
#define vidsig PIN_A0 //define pin for outgoing signal
#define High 1
#define Low 0
#define Middle 2
#define Status char
int flag;
int16 count;
int8 sfty;
int16 time;
unsigned char oldpos;
unsigned char position;
Status Checksignal(unsigned char pos);
void main()
{
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_comparator(NC_NC_NC_NC);
Output_low(vidsig); //clear the output port
oldpos = Low; //set starting position
sfty = 0; //initialize safety counter
time = 0; //initialize timer counter
While(true){
position = Checksignal(position); //go and check the stick position
if (Flag == 1) {
Flag = 0;
Output_low(vidsig); //if the timer is at 4000 - we lost the tx signal
} //for more than 4 seconds, it is time to make sure
//the channel 1 is active
Else { //if the counter is less then 4000, then we are still safe
if ( position || oldpos) //check if the position has changed compared to the previous state
{
oldpos = position; //if it did, make the oldposition equal to the newposition
Switch (position) { //switch based on the position
Case Low:
Output_low(vidsig);
Delay_ms(50);
sfty = 0;
Break;
Case High:
Output_High(vidsig);
Delay_ms(50);
sfty = 0;
Break;
Case Middle:
Delay_ms(50);
Break;
}
}
}
}
}
Status CheckSignal(unsigned char pos) {
count = 0; // initialize the pulse counter
time = 0;
While (!input(Signal)) { // Wait for pin to come on
time++;
If (time > 2000) {
flag = 1;
Break;
}
}
While (input(Signal)) {count++;} // Once the signal is high, count
If (count > 80 && count < 220) { // Make sure you are dealing with a valid pulse
sfty++; // Increase safety counter
If (sfty = 10) { // we need 5 valid signals to switch - it will eliminate accidental switching
sfty = 0; // if it is 5, then clear the counter
if (count <= 120) return(Low); // If the count is under 120 then we are on the low end
else if (count >= 180) return(High); // If the count is over 180 then we are on the high end
else return(Middle); // In case we are on the rudder stick the middle gets you nowhere.
}
}
}
|
and the h file:
Code: |
#include <12F629.h>
#FUSES NOWDT //No Watch Dog Timer
#FUSES INTRC_IO //Internal RC Osc, no CLKOUT
#FUSES NOCPD //No EE protection
#FUSES NOPROTECT //Code not protected from reading
#FUSES NOMCLR //Master Clear pin used for I/O
#FUSES NOPUT //No Power Up Timer
#FUSES NOBROWNOUT //No brownout reset
#FUSES BANDGAP_HIGH
#use delay(clock=4000000)
//#use rs232(baud=9600,parity=N,xmit=PIN_A3,rcv=PIN_A2,bits=8) |
|
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu May 15, 2008 9:35 am |
|
|
I didn't study your code very well but I did notice a few things.
Code: | position = Checksignal(position); | The variable 'position' is not initialised at startup, but...
Code: | Status CheckSignal(unsigned char pos) { | ...you never use 'pos' anyway so it is best to get rid of this parameter.
Change to '=='
Code: | if ( position || oldpos) //check if the position has changed compared to the previous state | Change the '||' to '!='. |
|
|
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Thu May 15, 2008 9:47 am |
|
|
Thank you, these are great, I will correct these, however the problem is in the following portion which never gets executed:
Code: |
While (!input(Signal)) { // Wait for pin to come on
time++;
If (time > 2000) {
flag = 1;
Break;
}
}
|
here, instead of counting to 2000 it will break the loop right away. |
|
|
mindstorm88
Joined: 06 Dec 2006 Posts: 102 Location: Montreal , Canada
|
|
Posted: Thu May 15, 2008 9:58 am |
|
|
Do you realise that at 4 mHz clock your 2000 count should last about 2000 uSec or 2 mS !!!! |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu May 15, 2008 10:03 am |
|
|
Quote: | here, instead of counting to 2000 it will break the loop right away. | Which means your A4 input pin is always high when you enter this function. What does the electronic schematic connected to this pin look like?
Add code for disabling the pull-up resistor on PIN A4. These should be disabled by default but it doesn't hurt to make this explicit. Code: | port_a_pullups(0x00); // Disable all weak pull up resistors |
What is your compiler version number? (see top of the *.lst file)
Last edited by ckielstra on Thu May 15, 2008 10:34 am; edited 1 time in total |
|
|
ckielstra
Joined: 18 Mar 2004 Posts: 3680 Location: The Netherlands
|
|
Posted: Thu May 15, 2008 10:27 am |
|
|
Some more remarks:
- Variable Flag is not initialized at startup.
Code: | #define High 1
#define Low 0
#define Middle 2
#define Status char | This code is correct, but if you want to do it realy nice than you code it with an enumeration which was designed for this purpose. A good compiler will then do type checking for you. Code: | enum Status {Low, Middle, High}; |
Code: | While (input(Signal)) {count++;} | This is a very rough mechanism for time measurement. A new compiler version or change in clock frequency will break this code. Try something like: Code: | While (input(Signal))
{
count++;
delay_us(200);
} | Make sure the delay routine is relatively long compared to the loop overhead (about 8us at 4Mhz).
There is a possible program flow where the function CheckSignal() does not return a value. This is a bug and too bad the compiler does not warn you for this.
Last edited by ckielstra on Thu May 15, 2008 10:34 am; edited 1 time in total |
|
|
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Thu May 15, 2008 10:32 am |
|
|
mindstorm88 wrote: | Do you realise that at 4 mHz clock your 2000 count should last about 2000 uSec or 2 mS !!!! |
Thanks, I had it at 20000 and it did not make any difference. However furher down while the "signal is on" it counts properly. It brings me back the correct values, and it switches pretty nicely. |
|
|
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Thu May 15, 2008 10:35 am |
|
|
ckielstra wrote: | Quote: | here, instead of counting to 2000 it will break the loop right away. | Which means your A4 input pin is always high when you enter this function. What does the electronic schematic connected to this pin look like?
Add code for disabling the pull-up resistor on PIN A4.
What is your compiler version number? (see top of the *.lst file) |
That might be the case, I have to verify that tonight. However the RC receivers signal is directly connected to this pin an I tested the signal coming out from the receiver with a scope - it goes low the moment the signal is lost - so it should bring the pin low as well, however I have to verify this.
I am not certain what the compiler version is, I have to check once i get home. |
|
|
oxxyfx
Joined: 24 May 2007 Posts: 97
|
|
Posted: Thu May 15, 2008 10:45 am |
|
|
ckielstra wrote: | Some more remarks:
- Variable Flag is not initialized at startup.
|
that is the most likely problem of my code. I think this will solve it.
ckielstra wrote: |
Code: | #define High 1
#define Low 0
#define Middle 2
#define Status char | This code is correct, but if you want to do it realy nice than you code it with an enumeration which was designed for this purpose. A good compiler will then do type checking for you. Code: | enum Status {Low, Middle, High}; |
|
Well, I am not really a programmer, thanks for pointing that out, I will defintely look into changing that.
ckielstra wrote: |
Code: | While (input(Signal)) {count++;} | This is a very rough mechanism for time measurement. A new compiler version or change in clock frequency will break this code. Try something like: Code: | While (input(Signal))
{
count++;
delay_us(200);
} | Make sure the delay routine is relatively long compared to the loop overhead (about 8us at 4Mhz).
|
Well, thank you again, but I timed this such that it works for me. The pulses coming from the rc receiver should be between 1ms to 2ms. To get an accurate measurement and also keep the code simple enough I changed the clock settings in the h file, so for 1.5ms middle position to count 150, lower position 1ms to be a 100 count and the high position - 2ms to be a 200 count.
This is precise enough for my application. It is very unlikely I will port this to a different compiler version of a different clock setting.
Quote: |
There is a possible program flow where the function CheckSignal() does not return a value. This is a bug and too bad the compiler does not warn you for this. |
thank you. |
|
|
|