本帖最后由 zouzhichao 于 2017-3-9 21:06 编辑
缘由:近来在做一个手持设备(12864+四个操作按键),在确定程序架构后,修修改改甚是烦躁,于是乎在架构稳定之后写了这么一个菜单程序生成器。
1)先上菜单描述文件范例menu_test.xml,伪造的xml文件,实际解析自己lex&yacc做的。
描述内容无非就是菜单结构(子菜单关系),还有每项菜单的描述,比如菜单类型(普通菜单,单选菜单,多选菜单),菜单名字,是否勾选,响应函数名等
2)怎么使用神器,以一个bat文件内容为例自动生成C代码.bat
- menu_creator.exe menu_test.xml 16 4 >main.c
- pause
复制代码
16 4表示12864的缓存区大小:每行16个字符,一共4行
3)生成的C代码main.c
- /************************************************************************************************************************
- 使用说明:
- 01.本文件用于四按键文本菜单架构!
- 02.本文件可以直接在PC上编译成控制台模拟程序,软件作者使用CFree测试!
- 03.控制台模拟程序使用上下左右方向键控制菜单!
- 04.上下方向键对应菜单上下翻,左方向键对应菜单回退,右方向键对应点击菜单,ESC键表示结束程序!
- 05.本程序可以很方便地移植到单片机系统!
- 06.嵌入式移植需重写void update_screen(const int8_t* buffer)函数!
- 07.void update_screen(const int8_t* buffer)函数表示把buffer里面的内容放到屏幕中,比如12864屏的buffer大小为4R16C = 64!
- 08.本文件提供函数void menu_update(void)用于在屏幕上刷新菜单!
- 09.本文件提供函数void menu_init(void)用于初始化菜单!
- 10.本文件提供函数ITEM* get_item_index_now(void)用于获取当前选定的菜单项!
- 11.本文件提供函数void menu_item_enable(int32_t index)用于使能菜单项!
- 12.本文件提供函数void menu_item_disable(int32_t index)用于禁止菜单项!
- 13.本文件提供函数void menu_item_rename(int32_t index, const int8_t* name)用于修改菜单项的名字!
- 14.本文件提供函数void key_func(int8_t key)用于处理按键消息!
- ************************************************************************************************************************/
- #include <stdio.h>
- #include <stdint.h>
- #define SCREEN_X_SIZE (16)
- #define SCREEN_Y_SIZE (4)
- #define MENU_DEPTH (4)
- #define ITEM_AMOUNT (93)
- #define PAGE_AMOUNT (14)
- #define PUSH_BUTTON (1)
- #define RADIO_BUTTON (2)
- #define CHECK_BUTTON (3)
- #define KEY_ENTER (1)
- #define KEY_ESC (2)
- #define KEY_UP (3)
- #define KEY_DOWN (4)
- typedef struct tagITEM {
- int8_t type;
- int8_t is_enable;
- int8_t child;
- int8_t is_checked;
- int8_t* name;
- int8_t (*func_on_click)(int8_t index_in_page);
- }ITEM;
- ITEM item_pool[ITEM_AMOUNT] = {
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit0输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit1输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit2输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit3输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit4输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit5输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit6输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit7输出低 ", NULL}, /* page_index = 0, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit0输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit1输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit2输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit3输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit4输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit5输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit6输出低 ", NULL}, /* page_index = 1, depth = 3 */
- {CHECK_BUTTON, -1, -1, 0, (int8_t*)"Bit7输出低 ", NULL}, /* page_index = 1, depth = 3 */
- { PUSH_BUTTON, -1, 0, 0, (int8_t*)"端口A设置 ", NULL}, /* page_index = 2, depth = 2 */
- { PUSH_BUTTON, -1, 1, 0, (int8_t*)"端口B设置 ", NULL}, /* page_index = 2, depth = 2 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0:PT100电阻 ", NULL}, /* page_index = 3, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1:K型热电偶 ", NULL}, /* page_index = 3, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"2:MBUS变量A ", NULL}, /* page_index = 3, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"3:MBUS变量B ", NULL}, /* page_index = 3, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0:PT100电阻 ", NULL}, /* page_index = 4, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1:K型热电偶 ", NULL}, /* page_index = 4, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"2:MBUS变量A ", NULL}, /* page_index = 4, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"3:MBUS变量B ", NULL}, /* page_index = 4, depth = 3 */
- { PUSH_BUTTON, -1, 3, 0, (int8_t*)"4-20mA源选择", NULL}, /* page_index = 5, depth = 2 */
- { PUSH_BUTTON, -1, 4, 0, (int8_t*)"0-5V源选择 ", NULL}, /* page_index = 5, depth = 2 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"-100 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"100 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"200 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"300 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"400 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"500 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"600 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"700 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"800 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"900 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1000 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1100 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1200 ", NULL}, /* page_index = 6, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"-100 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"100 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"200 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"300 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"400 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"500 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"600 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"700 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"800 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"900 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1000 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1100 ", NULL}, /* page_index = 7, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1200 ", NULL}, /* page_index = 7, depth = 4 */
- { PUSH_BUTTON, -1, 6, 0, (int8_t*)"4mA-温度 ", NULL}, /* page_index = 8, depth = 3 */
- { PUSH_BUTTON, -1, 7, 0, (int8_t*)"20mA-温度 ", NULL}, /* page_index = 8, depth = 3 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"-100 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"100 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"200 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"300 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"400 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"500 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"600 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"700 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"800 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"900 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1000 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1100 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1200 ", NULL}, /* page_index = 9, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"-100 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"0 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"100 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"200 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"300 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"400 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"500 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"600 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"700 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"800 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"900 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1000 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1100 ", NULL}, /* page_index = 10, depth = 4 */
- {RADIO_BUTTON, -1, -1, 0, (int8_t*)"1200 ", NULL}, /* page_index = 10, depth = 4 */
- { PUSH_BUTTON, -1, 9, 0, (int8_t*)"0V-温度 ", NULL}, /* page_index = 11, depth = 3 */
- { PUSH_BUTTON, -1, 10, 0, (int8_t*)"5V-温度 ", NULL}, /* page_index = 11, depth = 3 */
- { PUSH_BUTTON, -1, 8, 0, (int8_t*)"4-20mA线性化", NULL}, /* page_index = 12, depth = 2 */
- { PUSH_BUTTON, -1, 11, 0, (int8_t*)"0-5V线性化 ", NULL}, /* page_index = 12, depth = 2 */
- { PUSH_BUTTON, -1, 2, 0, (int8_t*)"数字输出端口", NULL}, /* page_index = 13, depth = 1 */
- { PUSH_BUTTON, -1, 5, 0, (int8_t*)"输出源选择 ", NULL}, /* page_index = 13, depth = 1 */
- { PUSH_BUTTON, -1, 12, 0, (int8_t*)"线性化设置 ", NULL}, /* page_index = 13, depth = 1 */
- };
- typedef struct tagPAGE {
- ITEM* item_p;
- int8_t item_amount;
- int8_t index_focused;
- int8_t index_displayed;
- }PAGE;
- PAGE page_pool[PAGE_AMOUNT] = {
- {(ITEM*)item_pool + 0, 8, 0, 0},
- {(ITEM*)item_pool + 8, 8, 0, 0},
- {(ITEM*)item_pool + 16, 2, 0, 0},
- {(ITEM*)item_pool + 18, 4, 0, 0},
- {(ITEM*)item_pool + 22, 4, 0, 0},
- {(ITEM*)item_pool + 26, 2, 0, 0},
- {(ITEM*)item_pool + 28, 14, 0, 0},
- {(ITEM*)item_pool + 42, 14, 0, 0},
- {(ITEM*)item_pool + 56, 2, 0, 0},
- {(ITEM*)item_pool + 58, 14, 0, 0},
- {(ITEM*)item_pool + 72, 14, 0, 0},
- {(ITEM*)item_pool + 86, 2, 0, 0},
- {(ITEM*)item_pool + 88, 2, 0, 0},
- {(ITEM*)item_pool + 90, 3, 0, 0},
- };
- static PAGE* page_stack[MENU_DEPTH] = {(PAGE*)page_pool + (PAGE_AMOUNT - 1)};
- static int8_t page_stack_now = 0;
- static int8_t screen_buffer[SCREEN_Y_SIZE * SCREEN_X_SIZE] = {'0'};
- void update_screen(const int8_t* buffer);
- static void screen_buffer_clr(void) {
- int32_t i;
- int8_t* p = (int8_t*)screen_buffer;
- for (i = SCREEN_Y_SIZE * SCREEN_X_SIZE; i != 0; i--) {
- *p++ = '\0';
- }
- }
- static void item_display(const ITEM* item, int8_t row, int8_t is_focused) {
- int8_t i;
- int8_t* p_src;
- int8_t* p_dst;
- if (row > SCREEN_Y_SIZE - 1) {
- return;
- }
- p_src = (int8_t*)item->name;
- p_dst = (int8_t*)screen_buffer + row * SCREEN_X_SIZE;
- *p_dst++ = is_focused;
- for (i = SCREEN_X_SIZE - 4; i != 0; i--) {
- *p_dst++ = (*p_src)? (*p_src++) : ' ';
- }
- if (0 == item->is_enable) {
- *p_dst++ = ' ';
- *p_dst++ = 'X';
- *p_dst = ' ';
- return;
- }
- if (-1 != item->child) {
- *p_dst++ = ' ';
- *p_dst++ = '>';
- *p_dst = '>';
- return;
- }
- if (CHECK_BUTTON == item->type) {
- *p_dst++ = '[';
- *p_dst++ = item->is_checked? '@' : ' ';
- *p_dst = ']';
- return;
- }
- if (RADIO_BUTTON == item->type) {
- *p_dst++ = '(';
- *p_dst++ = item->is_checked? ' : ' ';
- *p_dst = ')';
- return;
- }
- }
- void menu_update(void);
- static void key_enter_func(void) {
- int8_t i;
- PAGE* page_this = page_stack[page_stack_now];
- ITEM* item_this = (page_this->item_p) + (page_this->index_focused);
- if (0 == item_this->is_enable) {
- return;
- }
- if (NULL != item_this->func_on_click) {
- if (0 == item_this->func_on_click(page_this->index_focused)) {
- return;
- }
- }
- if ((item_this->child > -1) && (item_this->child < PAGE_AMOUNT)) {
- page_stack_now++;
- page_stack[page_stack_now] = (PAGE*)page_pool + item_this->child;
- }
- if (CHECK_BUTTON == item_this->type) {
- page_this->item_p[page_this->index_focused].is_checked ^= -1;
- return;
- }
- if (RADIO_BUTTON == item_this->type) {
- for (i = 0; i < page_this->item_amount; i++) {
- if (RADIO_BUTTON == page_this->item_p[i].type) {
- page_this->item_p[i].is_checked = 0;
- }
- }
- item_this->is_checked = -1;
- return;
- }
- }
- static void key_esc_func(void) {
- PAGE* page_this = page_stack[page_stack_now];
- if (page_stack_now > 0) {
- page_stack_now--;
- }
- }
- static void key_up_func(void) {
- PAGE* page_this = page_stack[page_stack_now];
- if (page_this->index_focused > 0) {
- page_this->index_focused--;
- }
- if (page_this->index_displayed > page_this->index_focused) {
- page_this->index_displayed = page_this->index_focused;
- }
- }
- static void key_down_func(void) {
- PAGE* page_this = page_stack[page_stack_now];
- if (page_this->index_focused < page_this->item_amount - 1) {
- page_this->index_focused++;
- }
- if (page_this->index_displayed < page_this->index_focused - (SCREEN_Y_SIZE - 1)) {
- page_this->index_displayed = page_this->index_focused - (SCREEN_Y_SIZE - 1);
- }
- }
- void menu_update(void)
- {
- int8_t i = 0, j;
- PAGE* page = page_stack[page_stack_now];
- screen_buffer_clr();
- for (j = page->index_displayed; (i < SCREEN_Y_SIZE) && (j < page->item_amount); i++, j++) {
- item_display((const ITEM*)page->item_p + j, i, j == page->index_focused? '>' : ' ');
- }
- update_screen((const int8_t*)screen_buffer);
- }
- void menu_init(void) {
- page_stack_now = 0;
- page_stack[0] = (PAGE*)page_pool + (PAGE_AMOUNT - 1);
- menu_update();
- }
- ITEM* get_item_index_now(void) {
- PAGE* page_this = page_stack[page_stack_now];
- return page_this->item_p + page_this->index_focused;
- }
- void menu_item_enable(int32_t index) {
- if ((index < 0) || (index > ITEM_AMOUNT - 1)) {
- return;
- }
- ITEM* p = (ITEM*)item_pool + index;
- p->is_enable = -1;
- menu_update();
- }
- void menu_item_disable(int32_t index) {
- if ((index < 0) || (index > ITEM_AMOUNT - 1)) {
- return;
- }
- ITEM* p = (ITEM*)item_pool + index;
- p->is_enable = 0;
- p->is_checked = 0;
- menu_update();
- }
- void menu_item_rename(int32_t index, const int8_t* name) {
- int8_t cnt;
- int8_t* p;
- if ((index < 0) || (index > ITEM_AMOUNT - 1)) {
- return;
- }
- p = (int8_t*)((ITEM*)item_pool + index)->name;
- for (cnt = SCREEN_X_SIZE - 4; cnt != 0; cnt--) {
- *p++ = (*name)? (*name++) : ' ';
- }
- menu_update();
- }
- void key_func(int8_t key) {
- switch (key) {
- case KEY_ENTER:
- key_enter_func();
- break;
- case KEY_ESC:
- key_esc_func();
- break;
- case KEY_UP:
- key_up_func();
- break;
- case KEY_DOWN:
- key_down_func();
- break;
- default:
- break;
- }
- menu_update();
- }
- #include <conio.h>
- #include <process.h>
- #include <windows.h>
- int main(int argc, char *argv[]) {
- char ch;
- menu_init();
- for ( ; ; ) {
- ch = getch();
- if (77 == ch) { // right
- Beep(1000, 100);
- key_func(KEY_ENTER);
- continue;
- }
- if (75 == ch) { // left
- Beep(1000, 100);
- key_func(KEY_ESC);
- continue;
- }
- if (72 == ch) { // up
- Beep(1000, 100);
- key_func(KEY_UP);
- continue;
- }
- if (80 == ch) { // down
- Beep(1000, 100);
- key_func(KEY_DOWN);
- continue;
- }
- if (27 == ch) {
- break;
- }
- }
- return 0;
- }
- void update_screen(const int8_t* buffer) {
- int8_t i, j;
- system("cls");
- for (i = SCREEN_Y_SIZE; i != 0; i--)
- {
- for (j = SCREEN_X_SIZE; j != 0; j--) {
- printf((const char*)"%c", *buffer++);
- }
- printf((const char*)"\n");
- }
- }
复制代码
4)编译main.c得到exe文件,运行效果如下图:
5)当然,最后要上附件咯
6)最后上传一个小巧c/c++开发环境,范例exe文件就是它编译的
编辑补充:V1.0发现一些不足,更新V1.1版:
|