This commit is contained in:
Олег Бородин
2025-01-11 21:41:13 +02:00
commit 4b289d1c46
21 changed files with 28117 additions and 0 deletions

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
*.o
*.hex
*.bin
*.elf
*.d

68
Makefile Normal file
View File

@@ -0,0 +1,68 @@
CC = avr-gcc
OBJCOPY = avr-objcopy
SIZE = avr-size
F_CPU = 16000000UL
MCU = atmega328p
CFLAGS += -DF_CPU=$(F_CPU) -mmcu=$(MCU)
CFLAGS += -I. -Os --std=c11
CFLAGS += -ffunction-sections -fdata-sections
CFLAGS += -save-temps
CFLAGS += -Wall
LDFLAGS += -s -mmcu=$(MCU)
LDFLAGS += -Wl,--gc-sections
LDFLAGS += -Wl,-u,vfprintf -lprintf_flt -lm
MAIN_OBJS += main.o
MAIN_OBJS += adc.o
MAIN_OBJS += button.o
MAIN_OBJS += contr.o
MAIN_OBJS += disp.o
MAIN_OBJS += eeprom.o
MAIN_OBJS += i2c.o
MAIN_OBJS += timer.o
MAIN_OBJS += tool.o
MAIN_ELF = main.elf
MAIN_HEX = main.hex
all: $(MAIN_HEX)
$(MAIN_ELF): $(MAIN_OBJS)
$(CC) $(LDFLAGS) -o $(MAIN_ELF) $(MAIN_OBJS)
$(SIZE) --format=berkeley $@
DEPENDS_DIR = .dep
%.o: %.c
@mkdir -p $(DEPENDS_DIR)
$(CC) $(CFLAGS) -c $*.c -o $*.o
@$(CC) -MM $(CFLAGS) $*.c > $(DEPENDS_DIR)/$*.d
$(MAIN_HEX): $(MAIN_ELF)
$(OBJCOPY) -O ihex -R .eeprom $< $@
AVRDUDE = sudo avrdude
TTY_PORT = /dev/ttyUSB0
TTY_SPEED = 115200
BACKUP = $(MAIN_HEX).bak
upload: $(MAIN_HEX)
$(AVRDUDE) -qq -c arduino -p m328p -P $(TTY_PORT) -b $(TTY_SPEED) -U flash:w:$<
download:
$(AVRDUDE) -F -V -c arduino -p m328p -P $(TTY_PORT) -b $(TTY_SPEED) -U flash:r:$(BACKUP):i
clean:
rm -f *.i *.o *.s
rm -f *.hex *.elf *.bin
rm -f *~ *.d
rm -rf $(DEPENDS_DIR)
-include $(DEPENDS_DIR)/$(MAIN_OBJS:.o=.d)
#EOF

43
adc.c Normal file
View File

@@ -0,0 +1,43 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#include <avr/interrupt.h>
#include <util/delay.h>
#include <tool.h>
void adc_init() {
/* Disable ADC */
REG_SETDOWN_BIT(ADCSRA, ADEN);
/* Set reference*/
REG_SETUP_BIT(ADMUX, REFS0);
REG_SETDOWN_BIT(ADMUX, REFS1);
/* Set result type */
REG_SETUP_BIT(ADMUX, ADLAR);
/* Set freq prescale */
REG_SETUP_BIT(ADCSRA, ADPS2);
REG_SETUP_BIT(ADCSRA, ADPS1);
REG_SETUP_BIT(ADCSRA, ADPS0);
/* Disable autoconversion */
REG_SETDOWN_BIT(ADCSRA, ADATE);
/* Disable interrupt */
REG_SETDOWN_BIT(ADCSRA, ADIE);
/* Enable ADC */
REG_SETUP_BIT(ADCSRA, ADEN);
}
uint16_t adc_read(uint8_t channel) {
uint8_t reg = ADMUX;
ADMUX = (reg & 0xF0) | channel;
REG_SETUP_BIT(ADCSRA, ADSC);
while (ADCSRA & BIT(ADSC));
uint16_t lval = (uint16_t)ADCL;
uint16_t hval = (uint16_t)ADCH;
hval = (hval << 8) & 0xFF00;
lval = lval & 0x00FF;
return (hval | lval);
}

16
adc.h Normal file
View File

@@ -0,0 +1,16 @@
#ifndef ADC_H_QWERTY
#define ADC_H_QWERTY
#define ACD_CHANELL0 0x00
#define ACD_CHANELL1 0x01
#define ACD_CHANELL2 0x02
#define ACD_CHANELL3 0x03
#define ACD_CHANELL4 0x04
#define ACD_CHANELL5 0x05
#define ACD_CHANELL6 0x06
#define ACD_CHANELL7 0x07
void adc_init(void);
uint16_t adc_read(uint8_t channel);
#endif

57
button.c Normal file
View File

@@ -0,0 +1,57 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#include <stdint.h>
#include <stdbool.h>
#include <avr/io.h>
#include <button.h>
#include <tool.h>
static bool button_is_pressed(button_t *button);
void button_init(button_t *button, uintptr_t ddraddr, uintptr_t portaddr, uintptr_t pinaddr, uint8_t outnum) {
button->ddraddr = ddraddr;
button->portaddr = portaddr;
button->pinaddr = pinaddr;
button->outnum = outnum;
}
void button_setup(button_t *button) {
REG_SETDOWN_BIT(_MMIO_BYTE(button->ddraddr), button->outnum);
REG_SETUP_BIT(_MMIO_BYTE(button->portaddr), button->outnum);
}
static bool button_is_pressed(button_t *button) {
if (REG_BIT_VALUE(_MMIO_BYTE(button->pinaddr), button->outnum)) {
return true;
}
return false;
}
bool button_was_pressed(button_t *button) {
bool was_pressed = button->was_pressed;
if (was_pressed) {
button->was_pressed = false;
button->push_time = 0;
}
return was_pressed;
}
void button_reset(button_t *button) {
button->was_pressed = false;
button->push_time = 0;
}
#define BUTTON_PRESS_TIME 30
void button_handle(button_t *button) {
if (button_is_pressed(button)) {
button->push_time++;
}
if (button->push_time > BUTTON_PRESS_TIME) {
button->was_pressed = true;
}
}

26
button.h Normal file
View File

@@ -0,0 +1,26 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#ifndef BUTTON_H_QWERTY
#define BUTTON_H_QWERTY
#include <stdint.h>
typedef struct button_t {
uintptr_t ddraddr;
uintptr_t portaddr;
uintptr_t pinaddr;
uint8_t outnum;
bool was_pressed;
uint8_t push_time;
} button_t;
void button_init(button_t *button, uintptr_t ddraddr, uintptr_t portaddr, uintptr_t pinaddr, uint8_t outnum);
void button_setup(button_t *button);
void button_reset(button_t *button);
bool button_was_pressed(button_t *button);
void button_handle(button_t *button);
#endif

85
contr.c Normal file
View File

@@ -0,0 +1,85 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <tool.h>
#include <eeprom.h>
#include <disp.h>
#include <timer.h>
#include <adc.h>
#include <button.h>
#include <contr.h>
button_t volume_button;
typedef struct {
uint8_t volume;
bool volume_updated;
} contr_t;
contr_t contr;
void contr_init(void) {
contr.volume = 0;
contr.volume_updated = false;
}
void contr_setup(void) {
}
ISR(TIMER0_OVF_vect) {
button_handle(&volume_button);
}
void contr_show_logo(void) {
disp_clear();
char* dispstr = "Made by R2FDX";
disp_string(1, 1, dispstr);
_delay_ms(100);
disp_clear();
}
#define CONTR_DISPSTR_SIZE 16
void contr_show_volume(void) {
char dispstr[CONTR_DISPSTR_SIZE];
sprintf(dispstr, "%4d", contr.volume);
disp_string(1, 1, dispstr);
}
#define MAX_VOLUME 64
void contr_calc_volume(void) {
if (button_was_pressed(&volume_button) == true) {
contr.volume++;
contr.volume_updated = true;
}
if (contr.volume > MAX_VOLUME) {
contr.volume = 0;
contr.volume_updated = true;
}
}
void contr_main(void) {
contr_show_logo();
uint16_t counter = 0;
while (true) {
counter++;
_delay_ms(10);
contr_calc_volume();
contr_show_volume();
}
}

12
contr.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef CONTR_H_QWERTY
#define CONTR_H_QWERTY
#include <stdint.h>
button_t volume_button;
void contr_init(void);
void contr_setup(void);
void contr_main(void);
#endif

428
disp.c Normal file
View File

@@ -0,0 +1,428 @@
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <i2c.h>
#include <disp.h>
#define DISP_FONT basefont
#define DISP_I2CADDR (0x78 >> 1)
#define DISP_WIDTH 128
#define DISP_HEIGHT 64
#define DISP_MIN_CHARCODE 32
#define DISP_MAX_CHARCODE 127
#define DISP_CHAR_ARRLEN 16
#define DISP_PAGE_HEIGHT 8
#define DISP_FONT_WIDTH 8
#define DISP_FONT_HEIGHT 2
#define DISP_SEND_CMD 0x00
#define DISP_SEND_DATA 0x40
const uint8_t basefont[DISP_MAX_CHARCODE - DISP_MIN_CHARCODE][DISP_CHAR_ARRLEN] PROGMEM;
typedef struct {
uint8_t max_posx;
uint8_t max_posy;
} disp_t;
disp_t disp;
#define SSD1306_SETLOWCOLUMN 0x00 /* Set Lower Column Start Address for Page Addressing Mode. */
#define SSD1306_SETHIGHCOLUMN 0x10 /* Set Higher Column Start Address for Page Addressing Mode. */
#define SSD1306_MEMORYMODE 0x20 /* Set Memory Addressing Mode. */
#define SSD1306_SETCOLNADDR 0x21
#define SSD1306_SETPAGEADDR 0x22
#define SSD1306_SETSTARTLINE 0x40 /* Set display RAM display start line register from 0 - 63. */
#define SSD1306_SETCONTRAST 0x81 /* Set Display Contrast to one of 256 steps. */
#define SSD1306_CHARGEPUMP 0x8D /* Enable or disable charge pump. Follow with 0X14 enable, 0X10 disable. */
#define SSD1306_SEGREMAP_MIRROR 0xA0 /* Set Segment Re-map between data column and the segment driver. */
#define SSD1306_SEGREMAP 0xA1
#define SSD1306_DISPLAYALLON_RESUME 0xA4 /* Resume display from GRAM content. */
#define SSD1306_DISPLAYALLON 0xA5 /* Force display on regardless of GRAM content. */
#define SSD1306_NORMALDISPLAY 0xA6 /* Set Normal Display. */
#define SSD1306_INVERTDISPLAY 0xA7 /* Set Inverse Display. */
#define SSD1306_SETMULTIPLEX 0xA8 /* Set Multiplex Ratio from 16 to 63. */
#define SSD1306_DISPLAYOFF 0xAE /* Set Display off. */
#define SSD1306_DISPLAYON 0xAF /* Set Display on. */
#define SSD1306_SETSTARTPAGE 0XB0 /* Set GDDRAM Page Start Address. */
#define SSD1306_COMSCANINC 0xC0 /* Set COM output scan direction normal. */
#define SSD1306_COMSCANDEC 0xC8 /* Set COM output scan direction reversed. */
#define SSD1306_SETDISPLAYOFFSET 0xD3 /* Set Display Offset. */
#define SSD1306_SETCOMPINS 0xDA /* Sets COM signals pin configuration to match the OLED panel layout. */
#define SSD1306_SETVCOMDETECT 0xDB /* This command adjusts the VCOMH regulator output. */
#define SSD1306_SETDISPLAYCLOCKDIV 0xD5 /* Set Display Clock Divide Ratio/ Oscillator Frequency. */
#define SSD1306_SETPRECHARGE 0xD9 /* Set Pre-charge Period */
#define SSD1306_DEACTIVATE_SCROLL 0x2E /* Deactivate scroll */
#define SSD1306_NOP 0XE3 /* No Operation Command. */
const uint8_t init_sequence[] PROGMEM = {
SSD1306_DISPLAYOFF,
SSD1306_MEMORYMODE, 0x00,
SSD1306_SETSTARTPAGE,
SSD1306_COMSCANDEC,
SSD1306_SETLOWCOLUMN,
SSD1306_SETHIGHCOLUMN,
SSD1306_SETSTARTLINE,
SSD1306_SETCONTRAST, 0xFF,
SSD1306_SEGREMAP,
SSD1306_NORMALDISPLAY,
SSD1306_SETMULTIPLEX, DISP_HEIGHT - 1,
SSD1306_DISPLAYALLON_RESUME,
SSD1306_SETDISPLAYOFFSET, 0x00,
SSD1306_SETDISPLAYCLOCKDIV, 0xF0,
SSD1306_SETPRECHARGE, 0x22,
SSD1306_SETCOMPINS, 0x12,
SSD1306_SETVCOMDETECT, 0x20,
SSD1306_CHARGEPUMP, 0x14,
SSD1306_DISPLAYON
};
void disp_send_cmd(uint8_t cmd[], uint8_t size) {
i2c_send_addr((DISP_I2CADDR << 1) | 0);
i2c_send_data(DISP_SEND_CMD);
for (uint8_t i = 0; i < size; i++) {
i2c_send_data(cmd[i]);
}
i2c_stop();
}
void disp_send_data(uint8_t data[], uint16_t size) {
i2c_send_addr((DISP_I2CADDR << 1) | 0);
i2c_send_data(DISP_SEND_DATA);
for (uint16_t i = 0; i < size; i++) {
i2c_send_data(data[i]);
}
i2c_stop();
}
void disp_init(void) {
disp.max_posx = 15; //(DISP_WIDTH / DISP_FONT_WIDTH) + 0;
disp.max_posy = DISP_HEIGHT / DISP_FONT_HEIGHT;
uint8_t commands[sizeof(init_sequence)];
for (uint8_t i = 0; i < sizeof(init_sequence); i++) {
commands[i] = (pgm_read_byte(&init_sequence[i]));
}
disp_send_cmd(commands, sizeof(commands));
}
void disp_string(uint8_t posy, uint8_t posx, const char* str) {
size_t idx = 0;
while (str[idx] != '\0') {
char xchar = str[idx];
if ((posx > disp.max_posx) || (posy > disp.max_posy)) {
return;
}
if ((xchar < DISP_MIN_CHARCODE) || (xchar > DISP_MAX_CHARCODE)) {
xchar = '?';
}
uint8_t char_start_col = posx * DISP_FONT_WIDTH;
uint8_t char_end_col = char_start_col + (DISP_FONT_WIDTH - 1);
uint8_t char_start_page = posy * DISP_FONT_HEIGHT;
uint8_t char_end_page = char_start_page + (DISP_FONT_HEIGHT - 1);
uint8_t commands[] = {
SSD1306_SETCOLNADDR, char_start_col, char_end_col,
SSD1306_SETPAGEADDR, char_start_page, char_end_page
};
disp_send_cmd(commands, sizeof(commands));
uint8_t indx = ((uint8_t) xchar) - DISP_MIN_CHARCODE;
uint8_t data[DISP_CHAR_ARRLEN];
for (uint8_t i = 0; i < DISP_CHAR_ARRLEN; i++) {
data[i] = (pgm_read_byte(&(DISP_FONT[indx][i])));
}
disp_send_data(data, DISP_CHAR_ARRLEN);
posx++;
idx++;
}
}
#define DISP_CLEAR_BSIZE 8
#define DISP_PAGE_COUNT 8
void disp_clear(void) {
for (uint8_t p = 0; p < DISP_PAGE_COUNT; p++) {
for (uint8_t x = 0; x < (DISP_WIDTH / DISP_CLEAR_BSIZE); x++) {
uint8_t start_col = x * DISP_PAGE_HEIGHT;
uint8_t end_col = start_col + DISP_CLEAR_BSIZE - 1;
uint8_t commands[] = {
SSD1306_SETCOLNADDR, start_col, end_col,
SSD1306_SETPAGEADDR, p, p
};
disp_send_cmd(commands, sizeof(commands));
uint8_t data[DISP_CLEAR_BSIZE * DISP_PAGE_HEIGHT];
memset(data, 0x00, sizeof(data));
disp_send_data(data, sizeof(data));
}
}
}
void disp_set_invert(bool invert) {
uint8_t commands[1];
if (invert == true) {
commands[0] = SSD1306_INVERTDISPLAY;
} else {
commands[0] = SSD1306_NORMALDISPLAY;
}
disp_send_cmd(commands, sizeof(commands));
}
void disp_set_sleep(bool sleep) {
uint8_t commands[1];
if (sleep == true) {
commands[0] = SSD1306_DISPLAYOFF;
} else {
commands[0] = SSD1306_DISPLAYON;
}
disp_send_cmd(commands, sizeof(commands));
}
void disp_set_contrast(uint8_t contrast) {
uint8_t commands[2] = { SSD1306_SETCONTRAST, contrast };
disp_send_cmd(commands, sizeof(commands));
}
void disp_flip(uint8_t flipping) {
uint8_t commands[2] = {
SSD1306_COMSCANDEC,
SSD1306_SEGREMAP
};
switch (flipping) {
case DISP_FLIP_NORM:
commands[0] = SSD1306_COMSCANDEC;
commands[1] = SSD1306_SEGREMAP;
disp_send_cmd(commands, sizeof(commands));
break;
case DISP_FLIP_HORVER:
commands[0] = SSD1306_COMSCANINC;
commands[1] = SSD1306_SEGREMAP_MIRROR;
disp_send_cmd(commands, sizeof(commands));
break;
case DISP_FLIP_VERT:
commands[0] = SSD1306_COMSCANINC;
commands[1] = SSD1306_SEGREMAP;
disp_send_cmd(commands, sizeof(commands));
break;
case DISP_FLIS_HOR:
commands[0] = SSD1306_COMSCANDEC;
commands[1] = SSD1306_SEGREMAP_MIRROR;
disp_send_cmd(commands, sizeof(commands));
default:
break;
}
}
const uint8_t xxbasefont[][16] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 32 '
{ 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00, 0x00 }, // 33 '!'
{ 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 34 '"'
{ 0x20, 0xFC, 0xFC, 0x20, 0xFC, 0xFC, 0x20, 0x00, 0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x01, 0x00 }, // 35 '#'
{ 0x70, 0xF8, 0x88, 0xFE, 0x88, 0x98, 0x10, 0x00, 0x04, 0x0C, 0x08, 0x3F, 0x08, 0x0F, 0x07, 0x00 }, // 36 '$'
{ 0x08, 0x1C, 0x14, 0xC8, 0xF0, 0x3C, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0x03, 0x04, 0x0A, 0x0E, 0x04 }, // 37 '%'
{ 0x80, 0xD8, 0x7C, 0xE4, 0xBC, 0xD8, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x0C, 0x07, 0x0F, 0x08, 0x00 }, // 38 '&'
{ 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 39 '''
{ 0x00, 0x00, 0xF0, 0xF8, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x08, 0x00, 0x00 }, // 40 '('
{ 0x00, 0x00, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0C, 0x07, 0x03, 0x00, 0x00 }, // 41 ')'
{ 0x80, 0xA0, 0xE0, 0xC0, 0xE0, 0xA0, 0x80, 0x00, 0x00, 0x02, 0x03, 0x01, 0x03, 0x02, 0x00, 0x00 }, // 42 '*'
{ 0x00, 0x80, 0x80, 0xE0, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00 }, // 43 '+'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x0C, 0x00, 0x00, 0x00 }, // 44 ','
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 45 '-'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00 }, // 46 '.'
{ 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00 }, // 47 '/'
{ 0xF8, 0xFC, 0x84, 0xC4, 0x64, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x09, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 48 '0'
{ 0x00, 0x10, 0x18, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x08, 0x08, 0x00 }, // 49 '1'
{ 0x18, 0x1C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08, 0x00 }, // 50 '2'
{ 0x18, 0x1C, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 51 '3'
{ 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0xFC, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x0F, 0x00 }, // 52 '4'
{ 0x7C, 0x7C, 0x44, 0x44, 0x44, 0xC4, 0x84, 0x00, 0x04, 0x0C, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 53 '5'
{ 0xF0, 0xF8, 0x4C, 0x44, 0x44, 0xC4, 0x80, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 54 '6'
{ 0x04, 0x04, 0x04, 0x84, 0xE4, 0x7C, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x0F, 0x01, 0x00, 0x00, 0x00 }, // 55 '7'
{ 0xB8, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 56 '8'
{ 0x78, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x00, 0x08, 0x08, 0x08, 0x0C, 0x07, 0x03, 0x00 }, // 57 '9'
{ 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00 }, // 58 ':'
{ 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x0C, 0x00, 0x00, 0x00 }, // 59 ';'
{ 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 60 '<'
{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 }, // 61 '='
{ 0x00, 0x08, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x08, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00 }, // 62 '>'
{ 0x38, 0x3C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00, 0x00 }, // 63 '?'
{ 0xF8, 0xFC, 0x04, 0xE4, 0x14, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x00 }, // 64 '@'
{ 0xF8, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 65 'A'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 66 'B'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0x1C, 0x18, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0E, 0x06, 0x00 }, // 67 'C'
{ 0xFC, 0xFC, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x0C, 0x07, 0x03, 0x00 }, // 68 'D'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 69 'E'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 70 'F'
{ 0xF8, 0xFC, 0x04, 0x84, 0x84, 0x9C, 0x98, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 71 'G'
{ 0xFC, 0xFC, 0x40, 0x40, 0x40, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 72 'H'
{ 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 73 'I'
{ 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00 }, // 74 'J'
{ 0xFC, 0xFC, 0xC0, 0xE0, 0x30, 0x1C, 0x0C, 0x00, 0x0F, 0x0F, 0x00, 0x01, 0x03, 0x0E, 0x0C, 0x00 }, // 75 'K'
{ 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 76 'L'
{ 0xFC, 0xF8, 0x30, 0x60, 0x30, 0xF8, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 77 'M'
{ 0xFC, 0xFC, 0x60, 0xC0, 0x80, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0F, 0x00 }, // 78 'N'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 79 'O'
{ 0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 80 'P'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x0C, 0x0C, 0x1F, 0x17, 0x00 }, // 81 'Q'
{ 0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 82 'R'
{ 0x38, 0x7C, 0x44, 0x44, 0x44, 0xCC, 0x88, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 83 'S'
{ 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 84 'T'
{ 0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 85 'U'
{ 0x7C, 0xFC, 0x80, 0x00, 0x80, 0xFC, 0x7C, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00, 0x00 }, // 86 'V'
{ 0xFC, 0xFC, 0x00, 0x80, 0x00, 0xFC, 0xFC, 0x00, 0x0F, 0x07, 0x03, 0x01, 0x03, 0x07, 0x0F, 0x00 }, // 87 'W'
{ 0x0C, 0x3C, 0xF0, 0xC0, 0xF0, 0x3C, 0x0C, 0x00, 0x0C, 0x0F, 0x03, 0x00, 0x03, 0x0F, 0x0C, 0x00 }, // 88 'X'
{ 0x0C, 0x3C, 0x70, 0xC0, 0xC0, 0x70, 0x3C, 0x0C, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 89 'Y'
{ 0x04, 0x04, 0x84, 0xC4, 0x64, 0x3C, 0x1C, 0x00, 0x0E, 0x0F, 0x09, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 90 'Z'
{ 0x00, 0x00, 0xFC, 0xFC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x00, 0x00 }, // 91 '['
{ 0x00, 0x0C, 0x3C, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x00 }, // 92 '\'
{ 0x00, 0x00, 0x04, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x00, 0x00 }, // 93 ']'
{ 0x00, 0x08, 0x0C, 0x06, 0x06, 0x0C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 94 '^'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00 }, // 95 '_'
{ 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 96 '`'
{ 0x00, 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 97 'a'
{ 0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 98 'b'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0x60, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0C, 0x04, 0x00 }, // 99 'c'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 100 'd'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x09, 0x09, 0x09, 0x09, 0x01, 0x00 }, // 101 'e'
{ 0x20, 0x20, 0xF8, 0xFC, 0x24, 0x24, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00 }, // 102 'f'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F, 0x00 }, // 103 'g'
{ 0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 104 'h'
{ 0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 105 'i'
{ 0x00, 0x00, 0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x30, 0x70, 0x40, 0x40, 0x7F, 0x3F, 0x00 }, // 106 'j'
{ 0xFC, 0xFC, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 107 'k'
{ 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 108 'l'
{ 0xE0, 0xE0, 0x20, 0xE0, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00 }, // 109 'm'
{ 0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 110 'n'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 111 'o'
{ 0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x7F, 0x7F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 112 'p'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x7F, 0x7F, 0x00 }, // 113 'q'
{ 0xE0, 0xE0, 0xC0, 0x60, 0x20, 0x20, 0x20, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 114 'r'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0F, 0x06, 0x00 }, // 115 's'
{ 0x20, 0x20, 0xFC, 0xFC, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x00 }, // 116 't'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 117 'u'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00, 0x00 }, // 118 'v'
{ 0xE0, 0xE0, 0x00, 0x80, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x0F, 0x08, 0x0F, 0x07, 0x00 }, // 119 'w'
{ 0x60, 0xE0, 0x80, 0x00, 0x80, 0xE0, 0x60, 0x00, 0x0C, 0x0E, 0x03, 0x01, 0x03, 0x0E, 0x0C, 0x00 }, // 120 'x'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F, 0x00 }, // 121 'y'
{ 0x20, 0x20, 0x20, 0xA0, 0xE0, 0x60, 0x20, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08, 0x00 }, // 122 'z'
{ 0x00, 0x40, 0xF8, 0xBC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x00, 0x00 }, // 123 '{'
{ 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 124 '|'
{ 0x00, 0x04, 0x04, 0xBC, 0xF8, 0x40, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00, 0x00 }, // 125 '}'
{ 0x0C, 0x0E, 0x02, 0x06, 0x0C, 0x08, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // 126 '~'
};
const uint8_t basefont[][16] PROGMEM = {
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 32 '
{ 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00, 0x00 }, // 33 '!'
{ 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 34 '"'
{ 0x20, 0xFC, 0xFC, 0x20, 0xFC, 0xFC, 0x20, 0x00, 0x01, 0x0F, 0x0F, 0x01, 0x0F, 0x0F, 0x01, 0x00 }, // 35 '#'
{ 0x70, 0xF8, 0x88, 0xFE, 0x88, 0x98, 0x10, 0x00, 0x04, 0x0C, 0x08, 0x3F, 0x08, 0x0F, 0x07, 0x00 }, // 36 '$'
{ 0x08, 0x1C, 0x14, 0xC8, 0xF0, 0x3C, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0x03, 0x04, 0x0A, 0x0E, 0x04 }, // 37 '%'
{ 0x80, 0xD8, 0x7C, 0xE4, 0xBC, 0xD8, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x0C, 0x07, 0x0F, 0x08, 0x00 }, // 38 '&'
{ 0x00, 0x00, 0x00, 0x0E, 0x0E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 39 '''
{ 0x00, 0x00, 0xF0, 0xF8, 0x0C, 0x04, 0x00, 0x00, 0x00, 0x00, 0x03, 0x07, 0x0C, 0x08, 0x00, 0x00 }, // 40 '('
{ 0x00, 0x00, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0C, 0x07, 0x03, 0x00, 0x00 }, // 41 ')'
{ 0x80, 0xA0, 0xE0, 0xC0, 0xE0, 0xA0, 0x80, 0x00, 0x00, 0x02, 0x03, 0x01, 0x03, 0x02, 0x00, 0x00 }, // 42 '*'
{ 0x00, 0x80, 0x80, 0xE0, 0xE0, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x00, 0x00, 0x00 }, // 43 '+'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x0C, 0x00, 0x00, 0x00 }, // 44 ','
{ 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 45 '-'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00 }, // 46 '.'
{ 0x00, 0x00, 0x00, 0xC0, 0xF0, 0x3C, 0x0C, 0x00, 0x00, 0x0C, 0x0F, 0x03, 0x00, 0x00, 0x00, 0x00 }, // 47 '/'
{ 0xF8, 0xFC, 0x84, 0xC4, 0x64, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x09, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 48 '0'
{ 0x00, 0x10, 0x18, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x08, 0x08, 0x00 }, // 49 '1'
{ 0x18, 0x1C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08, 0x00 }, // 50 '2'
{ 0x18, 0x1C, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 51 '3'
{ 0x80, 0xC0, 0x60, 0x30, 0x18, 0xFC, 0xFC, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x0F, 0x0F, 0x00 }, // 52 '4'
{ 0x7C, 0x7C, 0x44, 0x44, 0x44, 0xC4, 0x84, 0x00, 0x04, 0x0C, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 53 '5'
{ 0xF0, 0xF8, 0x4C, 0x44, 0x44, 0xC4, 0x80, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 54 '6'
{ 0x04, 0x04, 0x04, 0x84, 0xE4, 0x7C, 0x1C, 0x00, 0x00, 0x00, 0x0E, 0x0F, 0x01, 0x00, 0x00, 0x00 }, // 55 '7'
{ 0xB8, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 56 '8'
{ 0x78, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x00, 0x08, 0x08, 0x08, 0x0C, 0x07, 0x03, 0x00 }, // 57 '9'
{ 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x00, 0x00 }, // 58 ':'
{ 0x00, 0x00, 0x00, 0x60, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x1C, 0x0C, 0x00, 0x00, 0x00 }, // 59 ';'
{ 0x00, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x08, 0x00, 0x00, 0x00, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 60 '<'
{ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x00 }, // 61 '='
{ 0x00, 0x08, 0x18, 0x30, 0x60, 0xC0, 0x80, 0x00, 0x00, 0x08, 0x0C, 0x06, 0x03, 0x01, 0x00, 0x00 }, // 62 '>'
{ 0x38, 0x3C, 0x04, 0x84, 0xC4, 0x7C, 0x38, 0x00, 0x00, 0x00, 0x00, 0x0D, 0x0D, 0x00, 0x00, 0x00 }, // 63 '?'
{ 0xF8, 0xFC, 0x04, 0xE4, 0x14, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x09, 0x0A, 0x0B, 0x0B, 0x00 }, // 64 '@'
{ 0xF8, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0xF8, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 65 'A'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0xFC, 0xB8, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 66 'B'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0x1C, 0x18, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0E, 0x06, 0x00 }, // 67 'C'
{ 0xFC, 0xFC, 0x04, 0x04, 0x0C, 0xF8, 0xF0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x0C, 0x07, 0x03, 0x00 }, // 68 'D'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 69 'E'
{ 0xFC, 0xFC, 0x44, 0x44, 0x44, 0x04, 0x04, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 70 'F'
{ 0xF8, 0xFC, 0x04, 0x84, 0x84, 0x9C, 0x98, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 71 'G'
{ 0xFC, 0xFC, 0x40, 0x40, 0x40, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 72 'H'
{ 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 73 'I'
{ 0x00, 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x04, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00 }, // 74 'J'
{ 0xFC, 0xFC, 0xC0, 0xE0, 0x30, 0x1C, 0x0C, 0x00, 0x0F, 0x0F, 0x00, 0x01, 0x03, 0x0E, 0x0C, 0x00 }, // 75 'K'
{ 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 76 'L'
{ 0xFC, 0xF8, 0x30, 0x60, 0x30, 0xF8, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 77 'M'
{ 0xFC, 0xFC, 0x60, 0xC0, 0x80, 0xFC, 0xFC, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x01, 0x0F, 0x0F, 0x00 }, // 78 'N'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 79 'O'
{ 0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 80 'P'
{ 0xF8, 0xFC, 0x04, 0x04, 0x04, 0xFC, 0xF8, 0x00, 0x07, 0x0F, 0x08, 0x0C, 0x0C, 0x1F, 0x17, 0x00 }, // 81 'Q'
{ 0xFC, 0xFC, 0x84, 0x84, 0x84, 0xFC, 0x78, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 82 'R'
{ 0x38, 0x7C, 0x44, 0x44, 0x44, 0xCC, 0x88, 0x00, 0x06, 0x0E, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 83 'S'
{ 0x04, 0x04, 0x04, 0xFC, 0xFC, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 84 'T'
{ 0xFC, 0xFC, 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 85 'U'
{ 0x7C, 0xFC, 0x80, 0x00, 0x80, 0xFC, 0x7C, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00, 0x00 }, // 86 'V'
{ 0xFC, 0xFC, 0x00, 0x80, 0x00, 0xFC, 0xFC, 0x00, 0x0F, 0x07, 0x03, 0x01, 0x03, 0x07, 0x0F, 0x00 }, // 87 'W'
{ 0x0C, 0x3C, 0xF0, 0xC0, 0xF0, 0x3C, 0x0C, 0x00, 0x0C, 0x0F, 0x03, 0x00, 0x03, 0x0F, 0x0C, 0x00 }, // 88 'X'
{ 0x0C, 0x3C, 0x70, 0xC0, 0xC0, 0x70, 0x3C, 0x0C, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 89 'Y'
{ 0x04, 0x04, 0x84, 0xC4, 0x64, 0x3C, 0x1C, 0x00, 0x0E, 0x0F, 0x09, 0x08, 0x08, 0x08, 0x08, 0x00 }, // 90 'Z'
{ 0x00, 0x00, 0xFC, 0xFC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x00, 0x00 }, // 91 '['
{ 0x00, 0x0C, 0x3C, 0xF0, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x00 }, // 92 '\'
{ 0x00, 0x00, 0x04, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x0F, 0x00, 0x00 }, // 93 ']'
{ 0x00, 0x08, 0x0C, 0x06, 0x06, 0x0C, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 94 '^'
{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00 }, // 95 '_'
{ 0x00, 0x00, 0x01, 0x03, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 96 '`'
{ 0x00, 0xA0, 0xA0, 0xA0, 0xA0, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 97 'a'
{ 0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 98 'b'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0x60, 0x40, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0C, 0x04, 0x00 }, // 99 'c'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xFC, 0xFC, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 100 'd'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x09, 0x09, 0x09, 0x09, 0x01, 0x00 }, // 101 'e'
{ 0x20, 0x20, 0xF8, 0xFC, 0x24, 0x24, 0x04, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00 }, // 102 'f'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F, 0x00 }, // 103 'g'
{ 0xFC, 0xFC, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 104 'h'
{ 0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 105 'i'
{ 0x00, 0x00, 0x00, 0x00, 0x20, 0xEC, 0xEC, 0x00, 0x00, 0x30, 0x70, 0x40, 0x40, 0x7F, 0x3F, 0x00 }, // 106 'j'
{ 0xFC, 0xFC, 0x00, 0x80, 0xC0, 0x60, 0x20, 0x00, 0x0F, 0x0F, 0x01, 0x03, 0x06, 0x0C, 0x08, 0x00 }, // 107 'k'
{ 0x00, 0x00, 0x04, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x0F, 0x0F, 0x08, 0x00, 0x00 }, // 108 'l'
{ 0xE0, 0xE0, 0x20, 0xE0, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x0F, 0x00, 0x0F, 0x0F, 0x00 }, // 109 'm'
{ 0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00 }, // 110 'n'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 111 'o'
{ 0xE0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xC0, 0x00, 0x7F, 0x7F, 0x08, 0x08, 0x08, 0x0F, 0x07, 0x00 }, // 112 'p'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x7F, 0x7F, 0x00 }, // 113 'q'
{ 0xE0, 0xE0, 0xC0, 0x60, 0x20, 0x20, 0x20, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, // 114 'r'
{ 0xC0, 0xE0, 0x20, 0x20, 0x20, 0x20, 0x20, 0x00, 0x08, 0x09, 0x09, 0x09, 0x09, 0x0F, 0x06, 0x00 }, // 115 's'
{ 0x20, 0x20, 0xFC, 0xFC, 0x20, 0x20, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x00 }, // 116 't'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x08, 0x0F, 0x0F, 0x00 }, // 117 'u'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x00, 0x03, 0x0F, 0x0C, 0x0F, 0x03, 0x00, 0x00 }, // 118 'v'
{ 0xE0, 0xE0, 0x00, 0x80, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x0F, 0x08, 0x0F, 0x08, 0x0F, 0x07, 0x00 }, // 119 'w'
{ 0x60, 0xE0, 0x80, 0x00, 0x80, 0xE0, 0x60, 0x00, 0x0C, 0x0E, 0x03, 0x01, 0x03, 0x0E, 0x0C, 0x00 }, // 120 'x'
{ 0xE0, 0xE0, 0x00, 0x00, 0x00, 0xE0, 0xE0, 0x00, 0x07, 0x4F, 0x48, 0x48, 0x48, 0x7F, 0x3F, 0x00 }, // 121 'y'
{ 0x20, 0x20, 0x20, 0xA0, 0xE0, 0x60, 0x20, 0x00, 0x0C, 0x0E, 0x0B, 0x09, 0x08, 0x08, 0x08, 0x00 }, // 122 'z'
{ 0x00, 0x40, 0xF8, 0xBC, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x07, 0x0F, 0x08, 0x08, 0x00, 0x00 }, // 123 '{'
{ 0x00, 0x00, 0x00, 0xFC, 0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x0F, 0x00, 0x00, 0x00 }, // 124 '|'
{ 0x00, 0x04, 0x04, 0xBC, 0xF8, 0x40, 0x00, 0x00, 0x00, 0x08, 0x08, 0x0F, 0x07, 0x00, 0x00, 0x00 }, // 125 '}'
{ 0x0C, 0x0E, 0x02, 0x06, 0x0C, 0x08, 0x0E, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } // 126 '~'
};

26
disp.h Normal file
View File

@@ -0,0 +1,26 @@
#ifndef LCD_H_QWERTY
#define LCD_H_QWERTY
#include <inttypes.h>
#include <avr/pgmspace.h>
#define DISP_FLIP_NORM 0
#define DISP_FLIP_HORVER 1
#define DISP_FLIP_VERT 2
#define DISP_FLIS_HOR 3
void disp_init(void);
void disp_string(uint8_t posy, uint8_t posx, const char* str);
void disp_send_cmd(uint8_t cmd[], uint8_t size);
void disp_send_data(uint8_t data[], uint16_t size);
void disp_set_invert(bool invert);
void disp_set_sleep(bool sleep);
void disp_set_contrast(uint8_t contrast);
void disp_clear(void);
void disp_flip(uint8_t flipping);
#endif

BIN
docs/atmega328p.pdf Normal file

Binary file not shown.

27005
docs/micro-pa50.pdf Normal file

File diff suppressed because it is too large Load Diff

34
eeprom.c Normal file
View File

@@ -0,0 +1,34 @@
#include <stdint.h>
#include <avr/io.h>
#include <eeprom.h>
#include <tool.h>
void eeprom_write_byte(uint16_t address, uint8_t byte) {
while (EECR & BIT(EEPE));
EEAR = address;
EEDR = byte;
REG_SETUP_BIT(EECR, EEMPE);
REG_SETUP_BIT(EECR, EEPE);
}
uint8_t eeprom_read_byte(uint16_t address) {
while (EECR & BIT(EEPE));
EEAR = address;
REG_SETUP_BIT(EECR, EERE);
return EEDR;
}
void eeprom_write_bytes(uint16_t address, uint8_t* data, uint16_t size) {
for (uint16_t i = 0; i < size; i++) {
eeprom_write_byte(address + i, data[i]);
}
}
void eeprom_read_bytes(uint16_t address, uint8_t* data, uint16_t size) {
for (uint16_t i = 0; i < size; i++) {
data[i] = eeprom_read_byte(address + i);
}
}

12
eeprom.h Normal file
View File

@@ -0,0 +1,12 @@
#ifndef _EEPROM_H_QWERTY
#define _EEPROM_H 1
#include <stdint.h>
void eeprom_write_byte(uint16_t address, uint8_t byte);
uint8_t eeprom_read_bite(uint16_t address);
void eeprom_write_bytes(uint16_t address, uint8_t* data, uint16_t size);
void eeprom_read_bytes(uint16_t address, uint8_t* data, uint16_t size);
#endif

93
i2c.c Normal file
View File

@@ -0,0 +1,93 @@
#include <i2c.h>
uint8_t i2c_error;
void i2c_init(void) {
switch (PSC_I2C) {
case 4:
TWSR = 0x1;
break;
case 16:
TWSR = 0x2;
break;
case 64:
TWSR = 0x3;
break;
default:
TWSR = 0x00;
break;
}
TWBR = (uint8_t) SET_TWBR;
TWCR = (1 << TWEN);
}
void i2c_send_addr(uint8_t i2c_addr) {
TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
uint16_t timeout = F_CPU / F_I2C * 2.0;
while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
timeout--;
if (timeout == 0) {
i2c_error |= (1 << I2C_ERR_START);
return;
}
};
TWDR = i2c_addr;
TWCR = (1 << TWINT) | (1 << TWEN);
timeout = F_CPU / F_I2C * 2.0;
while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
timeout--;
if (timeout == 0) {
i2c_error |= (1 << I2C_ERR_SENDADRESS);
return;
}
};
}
void i2c_stop(void) {
TWCR = (1 << TWINT) | (1 << TWSTO) | (1 << TWEN);
}
void i2c_send_data(uint8_t byte) {
TWDR = byte;
TWCR = (1 << TWINT) | (1 << TWEN);
uint16_t timeout = F_CPU / F_I2C * 2.0;
while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
timeout--;
if (timeout == 0) {
i2c_error |= (1 << I2C_ERR_BYTE);
return;
}
};
}
uint8_t i2c_read_ack(void) {
TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWEA);
uint16_t timeout = F_CPU / F_I2C * 2.0;
while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
timeout--;
if (timeout == 0) {
i2c_error |= (1 << I2C_ERR_READACK);
return 0;
}
};
return TWDR;
}
uint8_t i2c_read_nack(void) {
TWCR = (1 << TWINT) | (1 << TWEN);
uint16_t timeout = F_CPU / F_I2C * 2.0;
while ((TWCR & (1 << TWINT)) == 0 && timeout != 0) {
timeout--;
if (timeout == 0) {
i2c_error |= (1 << I2C_ERR_READNACK);
return 0;
}
};
return TWDR;
}

30
i2c.h Normal file
View File

@@ -0,0 +1,30 @@
#ifndef I2C_H_QWERTY
#define I2C_H_QWERTY
#define PSC_I2C 1 // I2C prescaler
#define F_I2C 400000UL // I2C Clock
#define SET_TWBR (F_CPU/F_I2C-16UL)/(PSC_I2C*2UL)
#include <stdio.h>
#include <avr/io.h>
extern uint8_t i2c_error;
#define I2C_ERR_START 0 // Timeout start-condition
#define I2C_ERR_SENDADRESS 1 // Timeout device-adress
#define I2C_ERR_BYTE 2 // Timeout byte-transmission
#define I2C_ERR_READACK 3 // Timeout read acknowledge
#define I2C_ERR_READNACK 4 // Timeout read nacknowledge
void i2c_init(void);
void i2c_send_addr(uint8_t addr);
void i2c_send_data(uint8_t byte);
uint8_t i2c_read_ack(void);
uint8_t i2c_read_nack(void);
void i2c_stop(void);
#endif

60
main.c Normal file
View File

@@ -0,0 +1,60 @@
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
#include <button.h>
#include <i2c.h>
#include <adc.h>
#include <disp.h>
#include <timer.h>
#include <contr.h>
#define PINBADDR ((0x03) + 0x20)
#define DDRBADDR ((0x04) + 0x20)
#define PORTBADDR ((0x05) + 0x20)
#define PINCADDR ((0x06) + 0x20)
#define DDRCADDR ((0x07) + 0x20)
#define PORTCADDR ((0x08) + 0x20)
#define PINDADDR ((0x09) + 0x20)
#define DDRDADDR ((0x0A) + 0x20)
#define PORTDADDR ((0x0B) + 0x20)
//#define VOLBUT_DDRADDR DDRDADDR
//#define VOLBUT_PORTADDR PORTDADDR
//#define VOLBUT_PINDADDR PINDADDR
//#define VOLBUT_OUTNUM PD2
#define VOLBUT_DDRADDR DDRCADDR
#define VOLBUT_PORTADDR PORTCADDR
#define VOLBUT_PINDADDR PINCADDR
#define VOLBUT_OUTNUM PC0
int main(void) {
i2c_init();
disp_init();
adc_init();
timer0_init();
button_init(&volume_button, VOLBUT_DDRADDR,
VOLBUT_PORTADDR, VOLBUT_PINDADDR, VOLBUT_OUTNUM);
button_setup(&volume_button);
button_reset(&volume_button);
contr_init();
contr_setup();
sei();
contr_main();
return 0;
}

66
timer.c Normal file
View File

@@ -0,0 +1,66 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#include <avr/interrupt.h>
#include <util/delay.h>
#include <tool.h>
#include <timer.h>
void timer0_init(void) {
/* TCCR0A */
/* Disable comparators */
REG_SETDOWN_BIT(TCCR0A, COM0A1);
REG_SETDOWN_BIT(TCCR0A, COM0A0);
REG_SETDOWN_BIT(TCCR0A, COM0B1);
REG_SETDOWN_BIT(TCCR0A, COM0B0);
/* Set normal mode */
REG_SETDOWN_BIT(TCCR0A, WGM01);
REG_SETDOWN_BIT(TCCR0A, WGM00);
/* TCCR0B */
/* Set prescaler */
REG_SETUP_BIT(TCCR0B, CS02);
REG_SETDOWN_BIT(TCCR0B, CS01);
REG_SETDOWN_BIT(TCCR0B, CS00);
//REG_SETUP(TCNT0, TIMER0_PRESIZE);
/* TIMSK0 */
/* Enable timer interrupt */
REG_SETUP_BIT(TIMSK0, TOIE0);
}
void timer1_init(void) {
/* TCCR1A */
REG_SETDOWN_BIT(TCCR1A, COM1A1);
REG_SETDOWN_BIT(TCCR1A, COM1A0);
REG_SETDOWN_BIT(TCCR1A, COM1B1);
REG_SETDOWN_BIT(TCCR1A, COM1B0);
REG_SETDOWN_BIT(TCCR1A, WGM11);
REG_SETDOWN_BIT(TCCR1A, WGM10);
/* TCCR1B */
/* Disable capture noise canceler */
REG_SETDOWN_BIT(TCCR1B, ICNC1);
/* Set Capture Edge */
REG_SETUP_BIT(TCCR1B, ICES1);
/* Disable waveform generation */
REG_SETDOWN_BIT(TCCR1B, WGM13);
REG_SETDOWN_BIT(TCCR1B, WGM12);
/* Set prescaler */
REG_SETDOWN_BIT(TCCR1B, CS10);
REG_SETUP_BIT(TCCR1B, CS11);
REG_SETUP_BIT(TCCR1B, CS12);
/* TIMSK1 */
/* Disable capture interrupt */
REG_SETDOWN_BIT(TIMSK1, ICIE1);
/* Disable compare interrupt */
REG_SETDOWN_BIT(TIMSK1, OCIE1B);
REG_SETDOWN_BIT(TIMSK1, OCIE1A);
/* ENABLE overflow interrupt */
REG_SETUP(TCNT1, TIMER1_PRESIZE);
REG_SETUP_BIT(TIMSK1, TOIE1);
}

9
timer.h Normal file
View File

@@ -0,0 +1,9 @@
#ifndef CONTR_INIT_H_QWERTY
#define CONTR_INIT_H_QWERTY
#define TIMER1_PRESIZE 65528 // 65536
void timer0_init(void);
void timer1_init(void);
#endif

19
tool.c Normal file
View File

@@ -0,0 +1,19 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*/
#include <stdlib.h>
#include <stdint.h>
#include <stdbool.h>
#include <tool.h>
uint16_t str_len(uint8_t * str) {
uint16_t i = 0;
while (str[i] != 0)
i++;
return i;
}
int get_rand(int min, int max) {
return (rand() % (max - min)) + min;
}

23
tool.h Normal file
View File

@@ -0,0 +1,23 @@
/*
* Copyright 2017-2024 Oleg Borodin <onborodin@gmail.com>
*
*/
#ifndef TOOLS_H_QWERTY
#define TOOLS_H_QWERTY
#define MAX_LINE_LEN 1024
#define REG_SETUP_BIT(reg, bit) (reg) |= (1 << (bit))
#define REG_SETDOWN_BIT(reg, bit) (reg) &= ~(1 << (bit))
#define REG_BIT_ISUP(reg, bit) ((reg) & (1 << (bit)))
#define REG_SETVAL(reg, value) ((reg) = (value))
#define REG_SETUP(reg, value) ((reg) |= (value))
#define REG_SETDOWN(reg, value) ((reg) &= ~(value))
#define REG_BIT_VALUE(reg, value) ((reg) & (1 << (value)))
#define BIT(bit) (1 << (bit))
uint16_t str_len(uint8_t * str);
#endif