Beginners first program, port addressing and button input

It's 2:30AM and I've had entirely too much coffee. :astonished:

I got an Uno and I'm having a blast with it. It works on Linux... with Emacs + make. Hallalujah!

I have a (guitar pedal related) project I'd like to implement, but I have to learn how microcontrollers work first. It's loosely described here: Programmable fx looper design

My project will require 16 push buttons. So I've been reading all I can find on the topic (shift registers, debouncing, etc.).

Here is some code I came up with. A 7 segment display is incremented once, when -- and only when -- the button transitions from released to pressed. I don't really have a specific question. I'd just like know if I'm headed in the right direction.

/*                                                                              
  Increment a 7 segment display once per button press.                          
                                                                                
  Written for Arduino Uno Rev 3.                                                
                                                                                
  Uno pins 0-6 are segments a-g respectively.                                   
  Pin 8 is the button input.                                                    
                                                                                
  7 segment display is common cathode.                                          
  Button down is 0v, up is 5v;                                                  
 */

/******************************************                                     
  NOTE: Unhook pin 0 and 1 before uploading                                     
*********************************************/

const int but = 8;

const byte segMap[] = {
    0x3F,       /* 0 */
    0x06,       /* 1 */
    0x5B,       /* 2 */
    0x4F,       /* 3 */
    0x66,       /* 4 */
    0x6D,       /* 5 */
    0x7D,       /* 6 */
    0x07,       /* 7 */
    0x7F,       /* 8 */
    0x6F,       /* 9 */
    0x77,       /* A */
    0x7C,       /* B */
    0x39,       /* C */
    0x5E,       /* D */
    0x79,       /* E */
    0x71,       /* F */
};

int butPressed();
void increment();

void setup() {
    DDRD = 0x7f;                /* set pin 0-6 output */
    pinMode(but, INPUT);
    PORTD = segMap[0];          /* initialize display to 0 */
}

void loop() {
    if (butPressed())
        increment();
}

/*                                                                              
  Increment the display once per call.                                          
  Start at 0 (initialized in setup()). After F is displayed, start over.        
*/
void increment() {
    static int n = 1;
    PORTD = segMap[n];
    n = ++n % 16;
}

/*                                                                              
  Return 1 only if the button has transitioned from released to pressed.        
  Return 0 otherwise.                                                           
 */
int butPressed() {
    static int oldVal = 1;
    int val = 0, ret = 0;
    for (int i=0; i!=3; ++i) {
        val = digitalRead(but);
        delay(10);
    }
    ret = (oldVal && !val);
    oldVal = val;
    return ret;
}
    for (int i=0; i!=3; ++i) {

The middle part of a for statement is a while clause. Using == and != works, but <, <=, >, and >= are more intuitive and obvious, in my opinion.

The final part is the increment clause. While ++i or i++ work there, i++ is far more common.

However, the far more important issue is why are you reading digital switches more than once? Only the last reading matters, so you might as well simply have a delay() 30 before you read the switch once, and a delay(10) afterwards.

Anding and notting are typically done with boolean values.

That code does not debounce the switch, and is a rather complicated method of detecting the state change.

However, the far more important issue is why are you reading digital switches more than once?

Yeah, that was pretty convoluted. I have no idea what I was thinking there.

I found this article on debouncing: Debouncing Contacts and Switches

In the software debouncing section (part 2) I like the way the samples are shifted into a value then masked to test for the edge of the transition. That's really what I'm after. The edge transition.

I adapted the code using an 8 bit sample instead of 12.

int butPressed() {
    static unsigned int state = 0;
    state = (state << 1) | digitalRead(but) | 0xfe00;
    delay(4);
    return (state == 0xff00);
}

/*
          +-------- eight 'button down' samples in a row
          v       v
1111 1111 0000 0000
        ^
        +------- and the previous sample was 'button up'
*/

I actually understand how this works. What is giving me fits is the delay. How much, and do I delay in butPressed() or loop(). Ultimately the program will be doing much more than checking a single button.

The reason I'm using a 7 seg is so I can actually see if there are multiple state changes per button press. (Instead of trying to say, catch the flicker of a single LED). That's why I assumed the first version was working okay: one button press == exactly one state change in the display.

What kind of switches are you reading? How long do they typically bounce? Typically, switches bounce for less than 10 milliseconds.

A delay(10) in the butPressed() function is probably the best value/place for it.

I adapted the code using an 8 bit sample instead of 12.

A digital switch is either pressed or not. That's one bit. Food for thought.

stirfoo:
How much, and do I delay in butPressed() or loop()

Answers - none and don't
Have a look at the debounce example in the IDE to see how to do non blocking debouncing.

What kind of switches are you reading?

Using a tactile momentary switch.

Have a look at the debounce example in the IDE to see how to do non blocking debouncing.

I'll take a look. I haven't been using the IDE at all. For good or bad, I'm thoroughly dependent on emacs keystrokes. :blush:

stirfoo:
For good or bad, I'm thoroughly dependent on emacs keystrokes. :blush:

(alone
(forthat
(+ karma 1)))