
struct Button_Data
{
enum Object id; //идентификатор объекта
char *button_text; //текст кнопки
uint8_t y; //координаты верхнего левого угла кнопки
uint8_t x; //координаты верхнего левого угла кнопки
uint8_t height; //высота кнопки
uint8_t width; //ширина кнопки
uint8_t to_redraw; //флаг "отрисовать"
Button_State current_state; //текущее состояние кнопки
Button_State previous_state; //предыдущее состояние кнопки
uint32_t pushed_counter; //счетчик тиков сколько кнопка нажата
void (*Draw_Button)(Button_Data *btn_struct, uint8_t clear);
void (*HasPushed)(Button_Data *btn_struct);
void (*HasUnPushed)(Button_Data *btn_struct);
void (*StillPushed)(Button_Data *btn_struct);
};

//состояние кнопки
typedef enum
{
NO_PRESS = 0,
PRESS
}
Button_State;
//идентификаторы объектов
enum Object
{
Button1 = 1,
};
//описание кнопки

#define NUM_OBJECTS_BTN 1
//массив объектов
struct Button_Data Object[NUM_OBJECTS_BTN]=
{
{
.id = Button1,
.button_text = "OK",
.y = 30,
.x = 10,
.height = 24,
.width = 32,
.to_redraw = 1,
.current_state = NO_PRESS,
.previous_state = NO_PRESS,
.pushed_counter = 0,
.Draw_Button = &draw_btn,
.HasPushed = &draw_haspushed,
.HasUnPushed = &draw_hasunpushed,
.StillPushed = &draw_stillpushed
}
}; 
//отрисовка кнопок примитивами
//clear: 0 - рисуем нормально, 1 - рисуем цветом фона (BLACK)
void draw_btn(Button_Data *btn_struct, uint8_t clear)
{
uint16_t Color;
if(btn_struct->current_state == NO_PRESS)
Color = WHITE;
else
Color = RED;
if(clear!=0)
Color= BLACK; //очистка примитивами
} 
//отрисовка кнопок примитивами
//clear: 0 - рисуем нормально, 1 - рисуем цветом фона (BLACK)
void draw_btn(Button_Data *btn_struct, uint8_t clear)
{
uint16_t Color;
if(btn_struct->current_state == NO_PRESS)
Color = WHITE;
else
Color = RED;
if(clear!=0)
Color= BLACK; //очистка примитивами
//вывод прямых участков границ кнопки
ssd1331_draw_line(btn_struct->x+10, btn_struct->y,btn_struct->x + btn_struct->width-10, btn_struct->y, Color); //верхний горизонт
ssd1331_draw_line(btn_struct->x+10, btn_struct->y+btn_struct->height,btn_struct->x + btn_struct->width-10, btn_struct->y+btn_struct->height, Color); //нижний горизонт
ssd1331_draw_line(btn_struct->x, btn_struct->y+10, btn_struct->x, btn_struct->y+btn_struct->height-10, Color); //левая граница
ssd1331_draw_line(btn_struct->x+btn_struct->width, btn_struct->y+10, btn_struct->x+btn_struct->width, btn_struct->y+btn_struct->height-10, Color); //правая граница
//вывод скругления углов кнопки
ssd1331_draw_circle_seg4(btn_struct->x+10, btn_struct->y+10, 10, Color);//левый верхний
ssd1331_draw_circle_seg3(btn_struct->x+10, btn_struct->y+btn_struct->height-10, 10, Color); //левый нижний
ssd1331_draw_circle_seg2(btn_struct->x+btn_struct->width-10, btn_struct->y+btn_struct->height-10, 10, Color);//правый нижний
ssd1331_draw_circle_seg1(btn_struct->x+btn_struct->width-10, btn_struct->y+10, 10, Color);//правый верхний

//центр кнопки
uint8_t x_c = btn_struct->x + btn_struct->width/2;
uint8_t y_c = btn_struct->y + btn_struct->height/2;
uint8_t size_txt = strlen(btn_struct->button_text); //размер текста
//координаты текста - центрирование внутри кнопки
uint8_t y_t = y_c - FONT_1206/2;
uint8_t x_t = x_c - ( (FONT_1206/2) * size_txt)/2;
//вывод текста кнопки
ssd1331_display_string(x_t, y_t, btn_struct->button_text, FONT_1206, Color);
} 
//метод-событие "кнопка только что нажата"
void draw_haspushed(Button_Data *btn_struct)
{
print2LCD(" ", 0, 0);
print2LCD("pushed", 0, 3);
btn_struct->pushed_counter = 0; //сброс счетчика все еще нажатой кнопки
print2LCD(" ", 1, 0);
char str_sec[6];
sprintf(str_sec, "%04d", btn_struct->pushed_counter);
print2LCD(str_sec, 1, 1);
}
//метод-событие "кнопка только что отжата"
void draw_hasunpushed(Button_Data *btn_struct)
{
print2LCD(" ", 0, 0);
print2LCD("unpushed", 0, 3);
}
//метод-событие "кнопка все еще нажата"
void draw_stillpushed(Button_Data *btn_struct)
{
static uint8_t tick=5;
tick--;
if(tick==0)
{//прошло 0.5 секунд
tick=5;
btn_struct->pushed_counter++; //считаем автоповторы пока все еще нажата кнопка
char str_sec[6];
sprintf(str_sec, "%04d", btn_struct->pushed_counter);
print2LCD(str_sec, 1, 1);
}
} 10. Генерируем два новых события:

if(event_100ms_flag_obj==1)
{//наступило событие "раз в 100 мс проверка объектов"
//проверка всех объектов
check_objects(Object, NUM_OBJECTS_BTN);
//перерисовка всех объектов при необходимости
redraw_objects(Object, NUM_OBJECTS_BTN);
event_100ms_flag_obj=0; //сбросим флаг - обработали событие
}
if(event_3s_flag_pushbtn==1)
{//наступило событие "раз в 3 сек нажимаем кнопку"
static uint8_t pushed_unpushed=0;
if(pushed_unpushed==0)
{
//нажимаем все кнопки
to_push_btns(Object, NUM_OBJECTS_BTN);
pushed_unpushed=1;
}
else
{
//отжимаем все кнопки
to_unpush_btns(Object, NUM_OBJECTS_BTN);
pushed_unpushed=0;
}
event_3s_flag_pushbtn=0; //сбросим флаг - обработали событие
} 
// нажатие всех кнопок
void to_push_btns(struct Button_Data Object[], uint32_t num_objs)
{
for(uint32_t i=0; i< num_objs; i++)
Object[i].current_state = PRESS;
}
// отжатие всех кнопок
void to_unpush_btns(struct Button_Data Object[], uint32_t num_objs)
{
for(uint32_t i=0; i< num_objs; i++)
Object[i].current_state = NO_PRESS;
}
//проверка всех объектов
void check_objects(struct Button_Data Object[], uint32_t num_objs)
{
for(uint32_t i=0; i< num_objs; i++) //перебор всех объектов
{
if(Object[i].current_state == PRESS && Object[i].previous_state == NO_PRESS)
{//только что нажали
Object[i].HasPushed(&Object[i]); //вызов обработчика "только что нажали"
Object[i].Draw_Button(&Object[i],1);//очистка примитивами объекта- рисуем примитивы фоном
Object[i].to_redraw = 1; //надо потом нарисовать объект с новым состоянием
Object[i].previous_state = Object[i].current_state; //меняем предыдущее состояние
}
if(Object[i].current_state == PRESS && Object[i].previous_state == PRESS)
{//все еще нажата
Object[i].StillPushed(&Object[i]); //вызов обработчика "все еще нажата"
}
if(Object[i].current_state == NO_PRESS && Object[i].previous_state == PRESS)
{//только что отжали
Object[i].HasUnPushed(&Object[i]); //вызов обработчика "только что отжали"
Object[i].Draw_Button(&Object[i],1);//очистка примитивами объекта- рисуем примитивы фоном
Object[i].to_redraw = 1; //надо потом нарисовать объект с новым состоянием
Object[i].previous_state = Object[i].current_state; //меняем предыдущее состояние
}
}
} 
//перерисовка всех объектов
void redraw_objects(struct Button_Data Object[], uint32_t num_objs)
{
for(uint32_t i=0; i< num_objs; i++) //перебор всех объектов
{
if(Object[i].to_redraw!=0)
{
Object[i].Draw_Button(&Object[i], 0); //рисуем с новым состоянием
Object[i].to_redraw=0;//сброс флага отрисовки объекта
}
}
}
//все объекты на перерисовку
void to_redraw_all_objects(struct Button_Data Object[], uint32_t num_objs)
{
for(uint32_t i=0; i< num_objs; i++) //перебор всех объектов
{
Object[i].to_redraw=1;//устанвока флага отрисовки объекта
}
} 


| Стартуем! |
| Дальше |
| Проверить |
| Узнать результат |
| Дальше |
| Проверить |
| Узнать результат |
| Дальше |
| Проверить |
| Узнать результат |
| Дальше |
| Проверить |
| Узнать результат |
| Пройти еще раз |
| Пройти еще раз |
| Пройти еще раз |