#ifndef _AAIO_H #define _AAIO_H /* AVR All-in-one: a single-header library in pure C (tailored to avr-gcc) for some typical AVR ATmega series usecases Tested on: Arduino Mega 2560 (ATmega2560), Arduino Nano (ATmega328P) Individually selectable features: * controlling internal LED (overridable to any other pin); * controlling Nokia 5110 displays; * reading the state of typical 16-key keypads; * USB-based serial input/output. All functions and macros are prefixed in order to avoid collision with other C libraries. Created by Luxferre in 2024, released into public domain */ /* basic includes */ #include #include /* Predefined profiles for Arduino Mega 2560 and Arduino Nano */ /* All parameters can be overridden before the include */ /* Definitions for Arduino Nano */ #ifdef AAIO_NANO #ifndef AAIO_LED_PIN #define AAIO_LED_PIN PB5 #endif #ifndef AAIO_LED_DDR #define AAIO_LED_DDR DDRB #endif #ifndef AAIO_LED_PORT #define AAIO_LED_PORT PORTB #endif #ifndef AAIO_KEYPAD_DDR #define AAIO_KEYPAD_DDR DDRD #endif #ifndef AAIO_KEYPAD_PORT #define AAIO_KEYPAD_PORT PORTD #endif #ifndef AAIO_KEYPAD_PIN #define AAIO_KEYPAD_PIN PIND #endif #ifndef AAIO_LCD_PORT #define AAIO_LCD_PORT PORTC #endif #ifndef AAIO_LCD_DDR #define AAIO_LCD_DDR DDRC #endif #ifndef AAIO_LCD_SCE #define AAIO_LCD_SCE PC4 #endif #ifndef AAIO_LCD_RST #define AAIO_LCD_RST PC3 #endif #ifndef AAIO_LCD_DC #define AAIO_LCD_DC PC2 #endif #ifndef AAIO_LCD_DIN #define AAIO_LCD_DIN PC1 #endif #ifndef AAIO_LCD_CLK #define AAIO_LCD_CLK PC0 #endif #endif /* Definitions for Arduino Mega 2560 */ #ifdef AAIO_MEGA2560 #ifndef AAIO_LED_PIN #define AAIO_LED_PIN PB7 #endif #ifndef AAIO_LED_DDR #define AAIO_LED_DDR DDRB #endif #ifndef AAIO_LED_PORT #define AAIO_LED_PORT PORTB #endif #ifndef AAIO_KEYPAD_DDR #define AAIO_KEYPAD_DDR DDRA #endif #ifndef AAIO_KEYPAD_PORT #define AAIO_KEYPAD_PORT PORTA #endif #ifndef AAIO_KEYPAD_PIN #define AAIO_KEYPAD_PIN PINA #endif #ifndef AAIO_LCD_PORT #define AAIO_LCD_PORT PORTL #endif #ifndef AAIO_LCD_DDR #define AAIO_LCD_DDR DDRL #endif #ifndef AAIO_LCD_SCE #define AAIO_LCD_SCE PL4 #endif #ifndef AAIO_LCD_RST #define AAIO_LCD_RST PL3 #endif #ifndef AAIO_LCD_DC #define AAIO_LCD_DC PL2 #endif #ifndef AAIO_LCD_DIN #define AAIO_LCD_DIN PL1 #endif #ifndef AAIO_LCD_CLK #define AAIO_LCD_CLK PL0 #endif #endif /* AAIO_FEATURE_LED: internal LED manipulation */ #ifdef AAIO_FEATURE_LED /* init the internal LED I/O */ void aaio_led_init() { AAIO_LED_DDR |= (1 << AAIO_LED_PIN); } /* toggle the internal LED */ void aaio_led_toggle() { AAIO_LED_PORT ^= (1 << AAIO_LED_PIN); } /* set the internal LED */ void aaio_led_set(uint8_t v) { if(v == 0) { AAIO_LED_PORT &= ~(1 << AAIO_LED_PIN); } else { AAIO_LED_PORT |= (1 << AAIO_LED_PIN); } } #endif /* AAIO_FEATURE_USBUART: USB UART I/O */ /* you should define BAUD before this but it will default to 9600 */ #ifdef AAIO_FEATURE_USBUART #ifndef BAUD #define BAUD 9600 #endif #include #include /* init UART I/O */ void aaio_uart_init(void) { UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; UCSR0C = (1< /* scan the keyboard and return the associated value */ /* the definition must be stored in PROGMEM */ uint8_t aaio_scankey(const uint8_t keypad_def[4][4]) { uint8_t row, col, dirmask; for(col = 0; col < 4; col++) { AAIO_KEYPAD_DDR = dirmask = 1 << (col + 4); AAIO_KEYPAD_PORT = 0xf & ~dirmask; for(row = 0; row < 4; row++) { _delay_ms(5); if((AAIO_KEYPAD_PIN & (1<> (7-i)) & 1) AAIO_LCD_PORT |= (1 << AAIO_LCD_DIN); else AAIO_LCD_PORT &= ~(1 << AAIO_LCD_DIN); /* blink the clock */ AAIO_LCD_PORT |= (1 << AAIO_LCD_CLK); AAIO_LCD_PORT &= ~(1 << AAIO_LCD_CLK); } AAIO_LCD_PORT |= (1 << AAIO_LCD_SCE); /* disable the controller */ } static void _aaio_lcd_write_cmd(uint8_t cmd) { _aaio_lcd_write(cmd, 0); } static void _aaio_lcd_write_data(uint8_t data) { _aaio_lcd_write(data, 1); } /* init the LCD (must be called before any other function) */ void aaio_lcd_init(void) { register unsigned i; /* set pins as output */ AAIO_LCD_DDR |= (1 << AAIO_LCD_SCE); AAIO_LCD_DDR |= (1 << AAIO_LCD_RST); AAIO_LCD_DDR |= (1 << AAIO_LCD_DC); AAIO_LCD_DDR |= (1 << AAIO_LCD_DIN); AAIO_LCD_DDR |= (1 << AAIO_LCD_CLK); /* reset the display */ AAIO_LCD_PORT |= (1 << AAIO_LCD_RST); AAIO_LCD_PORT |= (1 << AAIO_LCD_SCE); _delay_ms(10); AAIO_LCD_PORT &= ~(1 << AAIO_LCD_RST); _delay_ms(70); AAIO_LCD_PORT |= (1 << AAIO_LCD_RST); AAIO_LCD_PORT &= ~(1 << AAIO_LCD_SCE); /* enable the controller */ _aaio_lcd_write_cmd(0x21); /* LCD extended commands mode */ _aaio_lcd_write_cmd(0xB0); /* default VOP */ _aaio_lcd_write_cmd(0x04); /* set temperature coefficient */ _aaio_lcd_write_cmd(0x14); /* LCD bias mode 1:48 */ _aaio_lcd_write_cmd(0x20); /* standard commands mode, powered down */ _aaio_lcd_write_cmd(0x09); /* LCD in normal mode */ /* clear LCD RAM */ _aaio_lcd_write_cmd(0x80); _aaio_lcd_write_cmd(AAIO_LCD_CONTRAST); for(i = 0; i < 504; i++) _aaio_lcd_write_data(0); /* activate the LCD */ _aaio_lcd_write_cmd(0x08); _aaio_lcd_write_cmd(0x0C); } /* clear the LCD */ void aaio_lcd_clear(void) { register unsigned i; /* set column and row to 0 */ _aaio_lcd_write_cmd(0x80); _aaio_lcd_write_cmd(0x40); /* reset the cursor */ _aaio_lcd.cursor_x = 0; _aaio_lcd.cursor_y = 0; /* clear everything */ for(i = 0; i < 504; i++) _aaio_lcd.screen[i] = 0; } /* power the LCD on/off */ void aaio_lcd_power(uint8_t on) { _aaio_lcd_write_cmd(on ? 0x20 : 0x24); } /* set a pixel */ void aaio_lcd_set_pixel(uint8_t x, uint8_t y, uint8_t value) { uint8_t *byte = &_aaio_lcd.screen[(y >> 3) * 84 + x]; if(value) *byte |= (1 << (y & 7)); else *byte &= ~(1 << (y & 7)); } /* write an ASCII character */ void aaio_lcd_write_char(char code, uint8_t scale) { register uint8_t x, y; for(x = 0; x < 5*scale; x++) for(y = 0; y < 7*scale; y++) if(pgm_read_byte(&CHARSET[code-32][x/scale]) & (1 << y/scale)) aaio_lcd_set_pixel(_aaio_lcd.cursor_x + x, _aaio_lcd.cursor_y + y, 1); else aaio_lcd_set_pixel(_aaio_lcd.cursor_x + x, _aaio_lcd.cursor_y + y, 0); _aaio_lcd.cursor_x += 5*scale + 1; if(_aaio_lcd.cursor_x >= 84) { _aaio_lcd.cursor_x = 0; _aaio_lcd.cursor_y += 7*scale + 1; } if(_aaio_lcd.cursor_y >= 48) { _aaio_lcd.cursor_x = 0; _aaio_lcd.cursor_y = 0; } } void aaio_lcd_write_string(const char *str, uint8_t scale) { while(*str) aaio_lcd_write_char(*str++, scale); } void aaio_lcd_set_cursor(uint8_t x, uint8_t y) { _aaio_lcd.cursor_x = x; _aaio_lcd.cursor_y = y; } void aaio_lcd_render(void) { register unsigned i; /* set column and row to 0 */ _aaio_lcd_write_cmd(0x80); _aaio_lcd_write_cmd(0x40); /* write screen data to the display */ for(i = 0; i < 504; i++) _aaio_lcd_write_data(_aaio_lcd.screen[i]); } #endif #endif