PotatoWatch-可编程手表
我需要一块手表,可自定义开发,可以编程,可以玩游戏,可以接收消息,可以规划日程,还有就是不要丢掉初心:时间日期显示是一个手表基本功能......当然了,最重要是装逼。
- Microsoft ToDo 日程规划API调用,可与手机结合规划日程。
- 动态显示天气信息。(说实话,咱界面设计还是拿的出手的)
- 尝试移植ArduBoy游戏库。
- 三级界面菜单逻辑设计。
- 拨轮编码器驱动编写。
- 屏幕驱动板设计。
- 4层PCB设计。
- 外壳设计。
STC-8G因为接口比ESP-M2多很多,所以选择STC作为外设控制以及端口引出,ESP-M2作为主控,处理消息以及获取网络信息。
项目导图如下:
主框架逻辑:
1 /********************************************* 2 * 创建一个结构体 3 * 存放界面标志位 4 */ 5 typedef struct 6 { 7 u8 Interface_Mark; //界面状态 8 u8 Task_Mark; //任务状态 9 u8 Run_Task; //开始运行任务 10 } Mark; 11 Mark Mark_Sign;//状态标志位 12 13 /********************************************* 14 * 创建一个枚举 15 * 存放界面变量 16 */ 17 enum 18 { 19 Main_Interface = 0x10, /****主界面*****/ 20 Menu_Interface = 0x20, /****菜单界面***/ 21 Task_Interface = 0x30, /****任务界面***/ 22 }; 23 24 25 switch(Mark_Sign.Interface_Mark) 26 { 27 //状态标志位 主界面 28 case Main_Interface: 29 Main_Interface_APP();//显示主界面 30 break; 31 32 //状态标志位 菜单界面 33 case Menu_Interface: 34 Menu_Interface_APP();//显示菜单界面 35 break; 36 case Task_Interface: 37 Function_Menu_APP();//显示功能界面 38 break; 39 default: 40 break; 41 } 42 43 44 // 每个篮框定义一个结构体存放:起始x,y,长和宽,图像指针 45 void Main_Interface_APP() 46 { 47 // 时间显示 48 49 // 日期显示 50 51 // 图标显示 52 53 // 气温,CO2显示 54 } 55 56 // 每个菜单选项具有独立的 1.位号,2.标题,3.图标指针 57 struct Table 58 { 59 unsigned char tab_num; 60 char *title; 61 BMP_Ptr *ptr; 62 } 63 64 // 菜单选项管理器:1.子项个数,3.当前选项指针,4.菜单项数组 65 struct Menu_argument 66 { 67 Table Tab_array[t_size]; 68 char t_size; 69 unsigned char *Tab_current; 70 } 71 72 // 屏幕初始化时,创建菜单管理器 73 // for循环加载各个菜单子项(位号,标题, 图标指针)进入菜单管理器 74 75 76 // 图像管理集:专门存放图像的文件,统一使用一个图像指针数组进行管理 77 78 void Menu_Interface_APP() //显示菜单选项界面 79 { 80 // 绘制隔断线 81 82 for(i = 0; i < 3; i++) 83 { 84 // 1.绘制第一栏 85 86 // 2.绘制第二栏(指定为当前指针栏居中,字体放大一号) 87 88 // 3.绘制第三栏 89 90 } 91 // 当前指针栏指示符号绘制 92 93 // 当前指针栏图标加载绘制 94 }
滚轮操作检测逻辑:
u8 Opera_array[OPERA_NUM];
这是一个操作队列数组,用来存储51发送过来的操作数据的
bool Busy_flag;
这是繁忙标志,当程序正在执行当前任务时,就不会读取下一个操作数。
实操代码: #pragma once #define SCAN_T_MS 10 #define OPERA_NUM 10 enum KEY_VALUE { KEY_FORWARD = 0xA0, // 滚轮前滚 KEY_BCKWARD = 0xB0, // 滚轮后滚 KEY_UP = 0xC0, // 滚轮上弹 KEY_DOWN = 0xD0, // 滚轮按下 }; // 定义操作结构体:操作数,忙标志,操作队列数组,当前操作数指针 typedef struct { // 有效操作数存在标志 bool Opera_have_flag; // 操作繁忙标志 bool Busy_flag; // 当前队列操作数个数 u8 Opera_Current_num; // 操作队列当前值 u8 Opera_Current_value; // 操作队列数组 u8 Opera_array[OPERA_NUM]; }Opera_argument; Opera_argument KeyArgument; // 按键操作数初始化 void Init_KeyScan() { // 所有值清0 KeyArgument.Opera_have_flag = 0; KeyArgument.Busy_flag = 0; // 默认不繁忙 KeyArgument.Opera_Current_num = 0; for (int i = 0; i < OPERA_NUM; i++) { KeyArgument.Opera_array[i] = 0; } } // 定时按键扫描函数: void Key_Scan() { // 有效操作数是否存在 if (KeyArgument.Opera_Current_num != 0) { // 当前是否存在操作繁忙 if (KeyArgument.Busy_flag != 1) { // 操作数赋值给主函数,繁忙标志开启 KeyArgument.Opera_Current_value = KeyArgument.Opera_array[0]; KeyArgument.Busy_flag = 1; Serial.println("in_scan"); // 当前值置零,数组整体前移,当前队列操作个数-1 // KeyArgument.Opera_array[0] = 0; for (int i = 0; i < OPERA_NUM; i++) { KeyArgument.Opera_array[i] = KeyArgument.Opera_array[i + 1]; } KeyArgument.Opera_Current_num--; } } }
三级菜单界面切换逻辑:
1 //按键滚轮一共会产生以下几种触发状态 2 /* 3 * 1.滚轮前滚 4 * 2.滚轮后滚 5 * 3.滚轮按下 6 * 4.滚轮按下前滚 7 * 5.滚轮按下后滚 8 * 6.滚轮长按 9 */ 10 11 // 中断程序操作伪代码 12 if(触发操作 == 滚轮按下) 13 { 14 if(息屏 == 当前屏幕状态) 15 { 16 当前屏幕状态 = 主界面; 17 } 18 else if(主界面 == 当前屏幕状态) 19 { 20 当前屏幕状态 = 菜单界面; 21 } 22 else if(菜单界面 == 当前屏幕状态) 23 { 24 当前屏幕状态 = 任务界面; 25 26 switch(当前带单界面任务编号) 27 { 28 case 任务编号1: 29 即将执行任务编号 = 当前带单界面任务编号;break; 30 case 任务编号2: 31 即将执行任务编号 = 当前带单界面任务编号;break; 32 case 任务编号3: 33 即将执行任务编号 = 当前带单界面任务编号;break; 34 case 任务编号4: 35 即将执行任务编号 = 当前带单界面任务编号;break; 36 default:break; 37 } 38 } 39 else if(任务界面 == 当前屏幕状态) 40 { 41 switch(即将执行任务编号) 42 { 43 case 任务编号1: 44 break; 45 case 任务编号2: 46 break; 47 case 任务编号3: 48 break; 49 case 任务编号4: 50 break; 51 52 } 53 } 54 } 55 else if(触发操作 == 滚轮滚动) 56 { 57 // 仍然判断当前屏幕状态 58 if(息屏 == 当前屏幕状态) 59 { 60 当前屏幕状态 =主菜单; 61 } 62 else if(主菜单 == 当前屏幕状态) 63 { 64 // 无操作响应 65 } 66 else if(菜单界面 == 当前屏幕状态) 67 { 68 // 定义滚动方向变量(0):上滚变量赋值-1;下滚变量赋值+1 69 70 // 菜单当前主任务指示指针+滚动方向变量 71 72 // 滚动操作变量复位0 73 } 74 else if(任务界面 == 当前屏幕状态) 75 { 76 // 定义滚动方向变量(0):上滚变量赋值-1;下滚变量赋值+1 77 switch(任务序号) 78 { 79 case 任务编号1: 80 // 1.编号1任务子选项指针,加滚动方向变量 81 break; 82 case 任务编号2: 83 // 1.编号2任务子选项指针,加滚动方向变量 84 break; 85 case 任务编号3: 86 // 1.编号3任务子选项指针,加滚动方向变量 87 break; 88 case 任务编号4: 89 // 1.编号4任务子选项指针,加滚动方向变量 90 break; 91 92 } 93 } 94 }
项目全部文件:
个人博客下方私信领取
http://potatoworld.top:5800/
- 画了三年板子了,还是把RX与TX画反了......(自抽三巴掌)
- 重要的事情说三遍,for(int i = 0; i < 3; i++){ cout << "ESP系列的模块一定要独立电源供电,否则运行不了"; } 我就是直接在板子上用了两块AMS1117,一块专门给ESP-M2
- ESP模块下载程序的时候,有个细节:
- 1.先关电源
- 2.在断电模式下,FLASH键接地(我是直接按住FLASH按钮接地)
- 3.开启电源,注意!!!FLASH此时仍然需要持续按住(接地),此时ESP-M2已经工作再FLASH下载模式了
- 4.电脑点击烧录
- 看到百分号进度条才能把手松开
- 等待程序下载完成