Skip to content

Instantly share code, notes, and snippets.

@SammysHP
Last active August 29, 2015 14:16
Show Gist options
  • Save SammysHP/ec490c0d1aa3509753f4 to your computer and use it in GitHub Desktop.
Save SammysHP/ec490c0d1aa3509753f4 to your computer and use it in GitHub Desktop.
#include <stdbool.h>
#include <stdint.h>
#include <avr/interrupt.h>
#include <avr/io.h>
#include <util/atomic.h>
#include <util/delay.h>
#define LED_PIN PB4
#define SWITCH_PIN PB3
bool ledEnabled = false;
bool shouldBlink = false;
#define DEBOUNCE_MAX_CHECKS 3
volatile uint8_t pinState = 0xff;
uint8_t prevPinState = 0xff;
uint8_t pinFilter[DEBOUNCE_MAX_CHECKS];
uint8_t filterIndex = 0;
/**
* Debounce PINB and detect falling edge.
*
* Lowpass filter with last DEBOUNCE_MAX_CHECKS measurements, measurement every
* timer overflow (see main(), here 64/F_CPU*265 ms, e.g. 64/1.2e6*256 = 13.7 ms,
* so with filter size of 3 = 40 ms).
*
* Edge detection via comparison with previous state.
*/
ISR(TIM0_OVF_vect) {
ATOMIC_BLOCK(ATOMIC_FORCEON) {
// Add current state to filter array
pinFilter[filterIndex] = PINB;
++filterIndex;
if (filterIndex >= DEBOUNCE_MAX_CHECKS) filterIndex = 0;
// filter
uint8_t filteredState = 0x00;
for (uint8_t i = 0; i < DEBOUNCE_MAX_CHECKS; i++) {
filteredState |= pinFilter[i];
}
// falling edge detection
pinState &= filteredState | ~prevPinState;
prevPinState = filteredState;
}
}
/**
* Get and reset pin state.
*
* mask: operate on these pins
*
* returns: active low state for requested pins
*/
uint8_t popKeyState(uint8_t mask) {
uint8_t result;
ATOMIC_BLOCK(ATOMIC_FORCEON) {
result = pinState & mask;
pinState |= mask;
}
return result;
}
int main(void) {
// LED_PIN as output and set to LOW
DDRB |= (1 << LED_PIN);
PORTB &= ~(1 << LED_PIN);
// SWITCH_PIN as input and enable pull-up
DDRB &= ~(1 << SWITCH_PIN);
PORTB |= (1 << SWITCH_PIN);
// Timer 0 konfigurieren
TCCR0B = (1<<CS01) | (1<<CS00); // prescaler
TIMSK0 |= (1<<TOIE0); // enable overflow interrupt
for (uint8_t i = 0; i < DEBOUNCE_MAX_CHECKS; i++) {
pinFilter[i] = 0xff;
}
sei();
while (true) {
if (!popKeyState(1 << SWITCH_PIN)) {
shouldBlink = !shouldBlink;
}
if (shouldBlink && !ledEnabled) {
PORTB |= (1 << LED_PIN); // on
_delay_ms(100);
} else {
PORTB &= ~(1 << LED_PIN); // off
_delay_ms(400);
}
ledEnabled = !ledEnabled;
}
return 0;
}
#==== Main Options =============================================================
MCU = attiny13
F_CPU = 1200000
TARGET = main
#==== Compile Options ==========================================================
CFLAGS = -mmcu=$(MCU) -I.
CFLAGS += -DF_CPU=$(F_CPU)UL
CFLAGS += -Os
#CFLAGS += -mint8
#CFLAGS += -mshort-calls
CFLAGS += -funsigned-char
CFLAGS += -funsigned-bitfields
CFLAGS += -fpack-struct
CFLAGS += -fshort-enums
#CFLAGS += -fno-unit-at-a-time
CFLAGS += -Wall
CFLAGS += -Wstrict-prototypes
CFLAGS += -Wundef
#CFLAGS += -Wunreachable-code
#CFLAGS += -Wsign-compare
CFLAGS += -std=gnu99
#==== Programming Options (avrdude) ============================================
AVRDUDE_PROGRAMMER = stk500v1
AVRDUDE_PORT = /dev/ttyUSB0
AVRDUDE_BAUD = 9600
AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -b $(AVRDUDE_BAUD) -c $(AVRDUDE_PROGRAMMER)
#===============================================================================
#==== Targets ==================================================================
CC = avr-gcc
OBJCOPY = avr-objcopy
AVRDUDE = avrdude
REMOVE = rm -f
all: build
build:
$(CC) -c $(CFLAGS) $(TARGET).c -o $(TARGET).o
$(CC) $(CFLAGS) $(TARGET).o --output $(TARGET).elf
$(OBJCOPY) -O ihex -j .text -j .data $(TARGET).elf $(TARGET).hex
program: build
$(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) -U flash:w:$(TARGET).hex
clean:
$(REMOVE) "$(TARGET).hex"
$(REMOVE) "$(TARGET).elf"
$(REMOVE) "$(TARGET).o"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment