-5

I'm working on an embedded (avr) project, and basically I want to print out a few different things based on how long a pin has been pressed down. I can't figure out what happens as the value passes through and satisfies if statements along the way (button is still pressed so counter increments).

The setup is as follows:

if overflows is between 7-48 (button pressed for 30ms-200ms), print out a '.'
if overflows is greater than 48 (button pressed for greater than 200ms), print out a '-'
if overflows is greater than 97 (button has not been pressed in over 400ms), print out a ' '

My current code is as follows:

static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
if (type == 'e') { // edge captured
    if (TCCR1B & 0x40) { // rising edge
        if (overflows < 7) {
            // do nothing
        } else if (overflows < 49) {
            buffer[idx++] = '.';
            size++;
        } else {
            buffer[idx++] = '-';
            size++;
        }
    }
    overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
    overflows++;
    if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
        buffer[idx++] = ' ';
        size++;
    }
}

I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow value is incremented, it satisfies the <49 condition.

Any thoughts?

Clifford
  • 88,407
  • 13
  • 85
  • 165
MS9T1
  • 11
  • 2
  • Are you taking one measurement, storing it somewhere, then doing logic on this value? Or are you remeasuring every time you ask `if`? – e0k Feb 19 '16 at 06:20
  • Basically, when I press down on a button it detects an edge. As long as I hold down that button, it will start counting. This is a morse-code detector, so I don't want to print out '.-' every time i'm holding down the button long enough to get a '-'. – MS9T1 Feb 19 '16 at 06:35
  • Buttons also bounce. When you press it, you get more than one of whatever edge you're detecting. The bounce is fast, but the microcontroller is faster, so it picks it up multiple times. You will probably have to debounce the button to do what you want to do. – e0k Feb 19 '16 at 06:40
  • Well my question is more related to how C executes things within if statements. Like since I'll be holding down the button for a while and want it to print out a '-' when it's been over 200ms (49 overflows), I don't want it to also print out a '.' since obviously it had to be held between 30-200ms (7-49 overflows). Ignore the "overflows" thing, that has more to do with my clock speed and timer size. – MS9T1 Feb 19 '16 at 06:45
  • Don't post pseudocode, post your actual code, and provide information about the expected and actual behaviour. – Randy the Dev Feb 19 '16 at 06:48
  • Are you running checks over and over in a loop? Or just checking once? The order of operations depends on the code that is written. – e0k Feb 19 '16 at 06:52
  • Okay just updated the question with my actual code and a (hopefully) clearer understanding of the problem. – MS9T1 Feb 19 '16 at 06:53
  • You should do as little as possible inside an interrupt service routine. For example, just set a flag then leave. You can poll the state of the flag, then respond if it's set. This AVR uses memory-mapped I/O. Every time you read TCCR1B you are making a new measurement. – e0k Feb 19 '16 at 06:55
  • How did you configure this `isr()`? Is it called for every edge? – e0k Feb 19 '16 at 07:01
  • Connecting switches to interrupt-triggered pins is problematic and somewhat involved, please read and understand [this](http://stackoverflow.com/questions/32646071/slight-delay-after-returning-from-interrupt/32647699#32647699). – Lundin Feb 19 '16 at 08:00
  • What *does* happen? What do you *want* to happen? You have made neither of this things clear. The answer to teh question in your title is "when the condition is true", but that is not the same as your body text appear to be asking. – Clifford Feb 19 '16 at 10:31
  • Given the code and your uncertainty regarding how it works, I can only assume that this is in fact not *your* code. – Clifford Feb 19 '16 at 10:37

3 Answers3

0

if you want to count no.of times switch pressed, you can use while loop. for example,

    if(sw==0) //sw is switch connected with I/O pin
    {
      while(sw==0)
      {
       led=1; //LED is output
       delay(); // use delay function
       led=0;
       delay();
       count++;
       }
     }

by using while loop, you can avoid from getting multiple times switch pressed. if you make one on and off switch, the count will be increased by one.

Arul
  • 13
  • 2
  • if(count<7) { //do something... } if((count>7)&&(count<49)) transmit('.'); if(count>=49) transmit('-'); void transmit(unsigned char b)//this function is for LCD to display the character { P1 = a;//port rs = 1; //rs=0 for command and rs=1 for data rw = 0; en = 1; delay(); en = 0; } – Arul Feb 19 '16 at 07:08
  • 1
    ....and what about [debouncing](http://whatis.techtarget.com/definition/debouncing)....? – LPs Feb 19 '16 at 07:15
  • manually you can make it. the switch is connected with pin. when you press the switch and release it, the count will be incremented by one – Arul Feb 19 '16 at 07:28
0

I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow value is incremented, it satisfies the <49 condition.

But the tests are performed only on the rising edge - when both type == 'e' and (TCCR1B & 0x40) != 0. So the overflow count is evaluated only when the button is released, so you will not see the intermediate . before -.

So to answer your question, a conditional statement or block is executed when the condition is true. Here you have nested conditionals, so all preceding conditions must be true for the inner condition to be evaluated.

Clifford
  • 88,407
  • 13
  • 85
  • 165
0

According to your description I assume you have a button on your pin, so in this case the first thing what I would recommend before doing anything is to implement a debounce for the button signal. I would solve the problem something like this:

#define BUTTON_UNKNOWN  0
#define BUTTON_DOWN     1
#define BUTTON_UP       2

#define FALSE           0
#define TRUE            1

static inline unsigned char debounce( unsigned char current_state)
{
static unsigned char ret_value;
unsigned char state_changed = FALSE;
// Counter for number of equal states
static unsigned char count = 0;
// Keeps track of current (de-bounced) state
static unsigned char button_state = 0;
// Check if button is high or low for the moment
if (current_state != button_state) 
{
    // Button state is about to be changed, increase counter
    count++;
    if (count >= 3) 
        {
        // The button have not bounced for four checks, change state
        button_state = current_state;
        // If the button was pressed (not released), tell main so
        count = 0;
        state_changed = TRUE;
        }
} 
else 
{
state_changed = FALSE;
// Reset counter
count = 0;
}

//if butten press or release detected
if (state_changed == TRUE)
{
    //check for the current state of the button
    if (current_state != 0) 
        {
        ret_value = BUTTON_DOWN;
        }
    else
        {
        ret_value = BUTTON_UP;
        }
}

return ret_value;
}

int main(void)
{
//perform proper initialization of your pin

unsigned char button = BUTTON_UNKNOWN;    
unsigned char cycle_count  = 0;
unsigned char idx = 0;
unsigned char buffer[255];
unsigned char current_state;
unsigned char no_activity;
//unsigned char current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;

while(1)
{
//read the button state
current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
// Update button_state
button = debounce(current_state);
// Check if the button is pressed.
if (button == BUTTON_DOWN)
{
    //count cycles in which the button was pressed
    //one cycle is 10 ms - see delay below
    cycle_count++;
}
else
{
    //check if the button was pressed before
    if ((button != BUTTON_UNKNOWN) && (cycle_count != 0))
    {
        //if button was pressed for 200ms
        if (cycle_count <= 20)
        {
            buffer[idx] = '.';
            idx++;            
        }
        else
        {
            //if the button was pressed between 200 and 400 ms
            if ((cycle_count > 20) && (cycle_count <= 40))
            {
               buffer[idx] = '-';
               idx++;
            }
            //the button was pressed for more than 400ms, uncomment if you need it

            /*else
            {
               buffer[idx] = ' ';
               idx++;
            }*/

        }
        //reset counting mechanism
        cycle_count = 0;
        no_activity = 0; 
    }
    else
    {
        no_activity++;
        if (no_activity >= 40)
        {
            buffer[idx] = ' ';
            idx++;
            no_activity = 0;
        }
    }
}

// Delay for a while so we don’t check to button too often
_delay_ms(10);
}
}

You can adapt this code according to your needs: change the line current_state = (~BUTTON_PIN & BUTTON_MASK) != 0; so that to read your pin state, and change the declaration of the buffer to suite your needs unsigned char buffer[255];

Please note that due to the debounce the time measured is not exactly 200ms ( it is 200ms + 2*debounce_time = 260ms (debounce time is 3 cycles, each cycle is 10ms, see delay at the end), but you may compensate these errors by reducing the contants in the cycle_count comparisons in the end.

Hope this helps!

If you really stick to your solution, then to avoid the problem what you experience is to not evaluate the overflow value continuously, do not try to determine the length of the button push on the fly, try instead to measure the length of the push and after that evaluate it and put the char in the buffer. You need to wait for the 'release button' and then evaluate how much time the button was pressed. Something like this:

static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
unsiged char button_status;

if (type == 'e') { // edge captured
    if (TCCR1B & 0x40) { // rising edge
        //perform a debounce otherwise wont be good
        button_status = 1;

    }
    overflows = 0; // restart counting overflows at each edge
} else { // overflow occured  
    overflows++;
     //if button was pressed and its now released evaluate result
    if (!(TCCR1B & 0x40) && (button_status == 1))
    {
        if (overflows < 7) {
            // do nothing
        } else if (overflows < 49) {
            buffer[idx++] = '.';
            size++;
        } else {
            buffer[idx++] = '-';
            size++;
        }
        button_status = 0;
    }
    if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
        buffer[idx++] = ' ';
        size++;
    }
}