#include <avr/interrupt.h>
#include <avr/io.h>
#include <stdbool.h>
#define MASK_PIND 0b11110000
#define KEYS_AMOUNT 16
#define DEBOUNCE_MS_THRESHOLD 20
struct key {
unsigned long time;
bool physical;
bool logical;
};
struct key keys[KEYS_AMOUNT];
volatile unsigned long ms = 0;
#define FOSC 1843200 // Clock Speed
#define BAUD 9600
#define UDREn (5)
#define MYUBRR FOSC/16/BAUD-1
void USART_Transmit(unsigned char data);
void USART_Init(unsigned int ubrr);
void USART_Init(unsigned int ubrr) {
/*Set baud rate */
UBRR0H = (unsigned char)(ubrr>>8);
UBRR0L = (unsigned char)ubrr;
UBRR0H = 0;
UBRR0L = 8;
/* Enable receiver and transmitter */
UCSR0B = (1<<RXEN0)|(1<<TXEN0);
/* Set frame format: 8data, 2stop bit */
UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
void USART_Transmit(unsigned char data) {
/* Wait for empty transmit buffer */
while (!(UCSR0A & (1<<UDREn)))
;
/* Put data into buffer, sends the data */
UDR0 = data;
}
void setupTimer() {
TCCR1B |= (1 << WGM12); // настраиваем режим CTC (Clear Timer on Compare Match)
OCR1A = 250; // задаем значение, при котором будет срабатывать прерывание (в данном случае 15999, так как Atmega328p работает на частоте 16 МГц и нужно получить прерывание раз в 1 мс)
TIMSK1 |= (1 << OCIE1A); // включаем прерывание по совпадению со значением регистра OCR1A
sei(); // разрешаем глобальные прерывания
TCCR1B |= (1 << CS11) | (1 << CS10); // запускаем таймер с предделителем 64 (16000000/64=250000)
}
void setup() {
USART_Init(MYUBRR);
DDRD = 0b00001111;
PORTD = 0b11110000;
DDRC = 0b111111;
PORTC = 0b001111;
setupTimer();
Serial.begin(9600);
Serial.println("Program start");
}
ISR(TIMER1_COMPA_vect) {
++ms;
}
unsigned long get_millis() {
return ms;
}
void get_physical_keys(struct key *keys) {
uint8_t row;
for (int i = 0; i < KEYS_AMOUNT / 4; i++) {
PORTC &= ~(1 << i);
row = PIND & MASK_PIND;
if (row & (1 << 4)) keys[i * 4].physical = false; else keys[i * 4].physical = true;
if (row & (1 << 5)) keys[i * 4 + 1].physical = false; else keys[i * 4 + 1].physical = true;
if (row & (1 << 6)) keys[i * 4 + 2].physical = false; else keys[i * 4 + 2].physical = true;
if (row & (1 << 7)) keys[i * 4 + 3].physical = false; else keys[i * 4 + 3].physical = true;
PORTC |= (1 << i);
}
}
void get_logical_keys(struct key *undc_keys) {
unsigned long timestamp = get_millis();
if (undc_keys[0].physical != undc_keys[0].logical) { // .physical_prev -> logical
if (timestamp - undc_keys[0].time >= DEBOUNCE_MS_THRESHOLD) {
undc_keys[0].logical = undc_keys[0].physical;
}
} else {
undc_keys[0].time = timestamp;
}
}
void loop() {
get_physical_keys(keys);
get_logical_keys(keys);
// for (int i = 0; i < KEYS_AMOUNT; i++) {
//Serial.print(keys[0].logical);
// Serial.print(":");
// Serial.print(keys[i].time);
// Serial.print(" ");
// }
// Serial.println();
printf("%d", keys[0].logical);
}
int printf( const char * format, ... )
{
char buffer[16];
va_list args;
va_start (args, format);
size_t s = vsprintf (buffer,format, args);
for(size_t i = 0; i < s; i++){
USART_Transmit(buffer[i]);
}
va_end (args);
return s;
}