I have an LED (PORTD5) that's flashing with a 200ms delay. When I press a button (PINB1) I want it to flash faster with a 50ms delay. The button doesn't seem to do anything when I press it. I'm using an atmega328p with the Arduino Uno R3 shield.
#include <avr/io.h>
#include <avr/delay.h>
#include <stdint.h>
#define F_CPU 16000000
int main(void) {
DDRB &= ~(1 << PINB1); // Button to input
DDRD |= (1 << DDD5); // LED to output
PORTB |= (1 << PINB1); // Turn Button on
while(1) {
PORTD ^= 1 << PORTD5; // Toggle light on/off every cycle
if ((PINB1 & (1 << PINB1)) != 0) { // Check if PINB1 is on
_delay_ms(50);
} else {
_delay_ms(200);
}
}
}
If I switch this code to check if equal to 0, it flashes with a 50ms delay, yet the button still does nothing:
if you don't know how the pairs are setup then you have 50% chances of having picked the two pins that are interconnected. One way to be 100% sure is to wire in diagonal across the button, this way you can't get it wrong.
As it's wired seems to be fine if the blue wire goes to an INPUT_PULLUP pin.
here is a wokwi simulation with either PORTs or arduino's helper functions
details
void setup() {
// Set the LED pin (D5) as an output Using DDRD register
DDRD |= (1 << DDD5);
// Set the button pin (D9) as an input with internal pull-up resistor Using DDRB register
DDRB &= ~(1 << DDB1); // Clear the 1st bit to configure it as input
PORTB |= (1 << PORTB1); // Set the 1st bit to enable the pull-up resistor
}
void loop() {
// Flip the state of the LED pin Using PIN register to toggle the state
PIND |= (1 << PIND5);
// Delay based on the button state
delay((PINB & (1 << PINB1)) ? 300 : 100);
}
/*
const byte ledPin = 5;
const byte buttonPin = 9;
void setup() {
pinMode(ledPin, OUTPUT);
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
digitalWrite(ledPin, digitalRead(ledPin) == LOW ? HIGH : LOW); // flip pin state
delay(digitalRead(buttonPin) == LOW ? 100 : 300); // if button is pressed wait less (but keep it visible)
}
*/
I want to learn the registers/hardware first before I start using the higher-level functions. I'd rather learn exactly what those functions are doing at a low level.
This was helpful! I definitely should have looked into exactly how the buttons works before I tried to do this
I moved the blue wire to the opposite side, as well as changed my if condition:
if ((PINB1 & (1 << PINB1)) != 0) // FROM THIS
if ((PINB & (1 << PINB1)) == 0) // TO THIS
I'm not exactly sure why, but when looking at other examples (someone in the replies also wrote it this way) they used "PINB" instead of "PINB1" when comparing the state of PINB1. I assume I have to compare it with the 8-bits of the register and not only the individual pin?
Once I made those changes, it worked!
Also, I used bit_is_clear() for the condition and it worked. I assume what I changed it to is what that function is doing.
When dealing with human interaction for buttons you rarely need the efficiency of using PORT registers. Using the higher level functions from Arduino will make your code more readable and portable - I would suggest to go for that version (which is also in the wokwi as comment).
As Jackson pointed out, you save some cycles using port manipulation but what mystifies me is the part where then you use delay().
delay(1) completely wastes 16000 cpu cycles.
When delay is in effect the sketch can't read a pin without using an interrupt and can't use interrupt info outside of the IRQ which if too long will likely cause a very hard to nail down Bug.
When I add a single delay(1) to loop() in a non-blocking sketch that counts the number of times that loop() did run every second...
the loop count drops from 50KHz or more to less than 1000.
When you ditch the delays, your code will run incredibly faster and a 100 button matrix in a box can be read in about 1 ms.
That tutorial was written by Nick Gammon for beginners with some experience and IMO newer coders may be more open to learning new ideas.