|
本帖最后由 jssd 于 2020-4-29 12:24 编辑
增加:19楼更新了程序,上传了整个工程
这东西坛子里做的人太多了。但对于我这小白来说,一直用不了别人的,感觉还是用自己的顺手一些,所以搞了个简单的,满足平时使用。当然,还可以扩展
底层驱动:
- //以下头文件
- #ifndef __LCD12864_ZK_H
- #define __LCD12864_ZK_H
- #include "main.h"
- //数据显示长度
- #define DISP_MASK 0x1F
- #define DISP_ALL 0x00
- //进制格式
- #define FORMAT_MASK 0x80
- #define FORMAT_D 0x00 //十进制Decimal
- #define FORMAT_H 0x80 //十六进制Hexadecimal
- //对齐方式
- #define ALIGN_MASK 0x60
- #define ALIGN_R 0x00 //右对齐
- #define ALIGN_L 0x20 //左对齐
- #define ALIGN_M 0x40 //中间对齐
- void LCD_Init(void);
- unsigned char LCD_ShowString(unsigned char x,unsigned char y,const char *pStr);
- unsigned char LCD_ShowNumber(unsigned char x,unsigned char y,long num,unsigned char param,char fill);
- void LCD_SetWhite(unsigned char x,unsigned char y,unsigned char width);
- void LCD_SetBG(unsigned char x,unsigned char y,unsigned char w,unsigned char bg);
- void LCD_Process(void);
- void LCD_ClearAll(void);
- #endif
- //以下C文件
- #include "main.h"
- #define LCD_RST_1 P20 = 1
- #define LCD_RST_0 P20 = 0
- #define LCD_CS_1 P26 = 1
- #define LCD_CS_0 P26 = 0
- #define LCD_CLK_1 P24 = 1
- #define LCD_CLK_0 P24 = 0
- #define LCD_SID_1 P25 = 1
- #define LCD_SID_0 P25 = 0
- static void write(char cmd, unsigned char dat) //写指令或数据 数据cmd=1:0xfa 命令cmd=0:0xf8
- { unsigned char i,j,Temp;
-
- LCD_CS_1;
- LCD_CLK_0;
-
- for(j=0;j<3;j++){
- if (j==0){ Temp =( cmd? 0xfa:0xf8);}
- else if (j==1){ Temp =((dat<<0) & 0xf0);}
- else if (j==2){ Temp =((dat<<4) & 0xf0);}
- for(i=0;i<8;i++){
- (Temp&0x80)?(LCD_SID_1):(LCD_SID_0); Temp<<=1; delay_us(1); //左移
- LCD_CLK_1; //delay_us(1); //_nop_();_nop_();//移入
- LCD_CLK_0; //delay_us(1); //_nop_();_nop_();_nop_(); //读出
- }
- }
- LCD_CS_0;
- }
- unsigned char SetWdat[64];//反白显示缓存
- unsigned char SetWdat_bak[64];//反白显示缓存
- //设置反白区域
- void LCD_SetBG(unsigned char x,unsigned char y,unsigned char w,unsigned char bg)
- {
- unsigned char i;
- if(x>15||y>3||w==0) return; //超出范围
- if(w+x>16) w = 16-x;
- for(i=0;i<w;i++){
- SetWdat[(y<<4)+x+i] = bg;
- }
- }
- //反白显示2字节
- void LCD_ShowBG2Byte(unsigned char n)
- {
- unsigned char Ax[] = {0x80,0x80,0x88,0x88};
- unsigned char Ay[] = {0x80,0x90,0x80,0x90};
- unsigned char j;
- unsigned char x = ((n&0x0f)>>1);
- unsigned char y = (n>>4);
-
- write(0,0x34); write(0,0x36); //打开GGRAM
- for(j=0;j<16;j++){
- write(0,Ay[y]+j); //y
- write(0,Ax[y]+x); //x
- write(1,SetWdat[n]);
- write(1,SetWdat[n+1]);
- }
- write(0,0x30); //关闭GGRAM
- }
- void LCD_BGProcess(void) //反白显示
- {
- unsigned char i;
- for(i=0;i<64;i+=2){
- if((SetWdat_bak[i]!=SetWdat[i])||(SetWdat_bak[i+1]!=SetWdat[i+1])){ SetWdat_bak[i] = SetWdat[i]; SetWdat_bak[i+1] = SetWdat[i+1];
- LCD_ShowBG2Byte(i);
- }
- }
- }
- unsigned char LCDdat[64];//显示缓存
- unsigned char LCDdat_bak[64];//显示缓存备份
- void LCD_Process(void) //模拟刷屏12864
- {
- unsigned char Addr[] = {0x80,0x90,0x88,0x98};
- unsigned char i;
-
- for(i=0;i<64;i+=2){
- if((LCDdat_bak[i]!=LCDdat[i])||(LCDdat_bak[i+1]!=LCDdat[i+1])){LCDdat_bak[i] = LCDdat[i];LCDdat_bak[i+1] = LCDdat[i+1];
- write(0,Addr[i>>4]+((i&0x0f)>>1)); //写地址 控制光标
- write(1,LCDdat[i]); //数据一次要连写两个
- write(1,LCDdat[i+1]); //数据一次要连写两个
- }
- }
- LCD_BGProcess();
- }
- //void LCD_RefreshALL(void) //模拟刷屏12864
- //{
- // unsigned char Addr[] = {0x80,0x90,0x88,0x98};
- // unsigned char i,j;
- //
- // for(i=0;i<4;i++){ //送四行汉字 //一次送一个汉字 (两个字节)
- // write(0,Addr[i]); //先送地址后送16个字符
- // for(j=0;j<16;j++){write(1,LCDdat[(i*16)+j]);}
- // }
- //}
- void LCD_ClearGM(void)
- {
- unsigned char i,j;
- write(0,0x34);
- write(0,0x36);
- for(j=0;j<32;j++)
- {
- write(0,0x80+j);
- write(0,0x80);
- for(i=0;i<16;i++)
- {
- write(1,0x00);
- }
- }
- for(j=0;j<32;j++)
- {
- write(0,0x80+j);
- write(0,0x88);
- for(i=0;i<16;i++)
- {
- write(1,0x00);
- }
- }
- write(0,0x30);
- }
- //******************** 显示字符串 ***********************//
- //** x:横坐标(0~15) y:纵坐标(0~3) 显示中文时注意从x坐标偶数写,否则乱码
- unsigned char LCD_ShowString(unsigned char x,unsigned char y,const char *pStr)
- {
- unsigned char i;
- unsigned int strLen = strlen(pStr); //字符串长度用 strlen(); 类型长度 sizeof();
- if(strLen<=0||x>15||y>3) return 0; //超出范围
-
- if(strLen+x>16) strLen = 16-x;
- for(i=0;i<strLen;i++){ //只在一行显示,超出部分丢弃
- LCDdat[16*y+x+i] = pStr[i];
- }
- return strLen;
- }
- void LCD_ClearAll(void)
- {
- memset(LCDdat,' ',sizeof(LCDdat));
- memset(SetWdat,0x00,sizeof(SetWdat));
- }
- //******************** 显示数字 ***********************//
- //** x:横坐标(0~15) y:纵坐标(0~3)
- //** param:
- //** (bit(7) 0:十进制显示 1:十六进制显示)
- //** (bit(6~5) 00:右对齐 x为右边坐标,字符向左扩展 01:左对齐 x为左点坐标,字符向右扩展 10:中间对齐 x为中点坐标,字符向两边扩展)
- //** (bit(4~0)显示的长度0~31 0:显示全部)
- //** fill: 空白处填充的字符,注意转义字符
- unsigned char LCD_ShowNumber(unsigned char x,unsigned char y,long num,unsigned char param,char fill)
- {
- unsigned char i;
- char strBuff[32]; //一行字符缓存
- char disBuff[32]; //一行字符缓存用于显示
- int strLen = 0;
- unsigned char disLen = (param&DISP_MASK);
-
- if((x>15)||(y>3)) return 0; //超出范围
-
- if(param&FORMAT_MASK){ //十六进制显示
- strLen = sprintf(strBuff,"%lX",num);
- }
- else{ //十进制显示
- strLen = sprintf(strBuff,"%ld",num);
- }
-
- if(strLen<=0) return 0; //错误
-
- if(disLen==DISP_ALL) disLen = strLen; //数据长度为0则全部显示
-
- if((param&ALIGN_MASK)==ALIGN_R){//右对齐
- if(x+1<disLen) disLen = x+1;
- for(i=0;i<disLen;i++){
- if(i<strLen) disBuff[disLen-1-i] = strBuff[strLen-1-i];
- else disBuff[disLen-1-i] = fill;
- }
- x = x+1-disLen;
- }
- else if((param&ALIGN_MASK)==ALIGN_L){//左对齐
- for(i=0;i<disLen;i++){
- if(i<strLen) disBuff[i] = strBuff[i];
- else disBuff[i] = fill;
- }
- }
- else if((param&ALIGN_MASK)==ALIGN_M){//中间对齐
- uint8_t disM = (disLen>>1); //显示窗口的中间位置
- uint8_t strM = (strLen>>1); //数据的中间位置
- for(i=0;i<disM;i++){ //前半部分 右对齐
- if(i<strM) disBuff[disM-1-i] = strBuff[strM-1-i];
- else disBuff[disM-1-i] = fill;
- }
- for(i=disM;i<disLen;i++){ //后半部分 左对齐
- if(strM+i-disM<strLen) disBuff[i] = strBuff[strM+i-disM];
- else disBuff[i] = fill;
- }
- }
- disBuff[disLen] = '\0'; //末尾加结束符
- return (LCD_ShowString(x,y,disBuff));
- }
- /**********************************
- LCD初始化
- **********************************/
- void LCD_Init(void)
- {
- memset(LCDdat,' ',sizeof(LCDdat));
- memset(LCDdat_bak,0x00,sizeof(LCDdat_bak));
- memset(SetWdat,0x00,sizeof(SetWdat));
- memset(SetWdat_bak,0x00,sizeof(SetWdat_bak));
-
- LCD_RST_0; delay_ms(100);
- LCD_RST_1; //delay_ms(100);//复位
- write(0,0x30); //8 位介面,基本指令集
- write(0,0x0c); //显示打开,光标关,反白关
- write(0,0x01); //清屏,将DDRAM的地址计数器归零
- // delay_ms(100);
- LCD_ClearGM();
-
- // LCD_SetBG(3,1,5,1);
- }
复制代码
菜单层:
- //以下为头文件
- #ifndef __HAL_MENU_H__
- #define __HAL_MENU_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "main.h"
- #ifdef __cplusplus
- }
- #endif
- #define UBOUND(__ARR) (sizeof(__ARR)/sizeof(__ARR[0]))
-
- //菜单项类型
- #define STRUCT_MASK 0x80 //结构掩码
- #define STRUCT_UD 0x80 //上下结构
- #define STRUCT_LR 0x00 //左右结构
- #define TYPE_MASK 0x70 //类型掩码
- #define label 0x00 //只显标题
- #define edit 0x10 //label + num
- #define text 0x20 //label + str
- #define editL 0x30 //label + long num 数字可一位一位改变
- #define X_MASK 0x0f //x轴坐标掩码
- typedef struct __item item_t; //菜单项(item_t)
- typedef struct __page page_t; //页面(page_t)
- typedef struct __engine engine_t; //引擎(engine_t)
- //菜单项(item_t)
- typedef int8_t item_handler_t(item_t *); //菜单项执行函数
- struct __item {
- uint8_t type; //菜单项类型 + 低4位为x轴偏移
- const char *title; //标题 null:无标题
- const void *mem; //变量指针
- page_t *child; //子页面
- item_handler_t *fnHandle; //菜单项执行函数
- };
- //页面(page_t)
- struct __page {
- char *title; //标题 null:无标题
- item_t *items; //!< page item list //菜单项数组
- uint8_t count; //!< page item count //菜单项个数
- page_t *parent; //!< parent page; //父页面
- };
- //引擎(engine_t)
- struct __engine {
- const page_t *curPage;
- uint8_t curItemIndex;
- uint8_t param;
- };
- void Menu_Process(void);
- //**********************************************************************************//
-
- #endif
- //以下为C文件
- #include "main.h"
- static engine_t engine = { pageMain,0,0 };
- //void LCD_SetBG(unsigned char x,unsigned char y,unsigned char w,unsigned char bg)
- void Menu_ShowItem(engine_t* ptEngine)
- {
- uint8_t i;
- uint8_t lineIndex = 0;
- uint8_t cursorX = 0,cursorY = 0,cursorL = 16;
- page_t *ptPage = ptEngine->curPage;
-
- LCD_ClearAll();
-
- if(ptPage->title){
- LCD_ShowString(0,lineIndex++,ptPage->title);
- cursorY = 1;
- }
-
- for(i=engine.curItemIndex;i<ptPage->count;i++){
- item_t *pItem = ptPage->items + i;
- uint8_t type = pItem->type&TYPE_MASK;
- uint8_t x = pItem->type&X_MASK;
-
- switch(type){
- case label:{
- LCD_ShowString(x,lineIndex,pItem->title);
- lineIndex++;
- break;}
- case edit:{
- uint8_t len = LCD_ShowString(x,lineIndex,pItem->title);
- len = LCD_ShowNumber(15,lineIndex,*((const uint8_t*)(pItem->mem)),0,' ');
- if((lineIndex==cursorY) && (ptEngine->param&0x80)){
- cursorL = len; cursorX = 16-cursorL;
- }
- lineIndex++;
- break;}
- case text:{
- uint8_t len = LCD_ShowString(x,lineIndex,pItem->title);
- len = LCD_ShowString(16-strlen((const char*)(pItem->mem)),lineIndex,(const char*)(pItem->mem));
- lineIndex++;
- break;}
- default:break;
- case editL:{
-
- break;}
- }
- if(lineIndex>3) break;
- }
-
- //光标
- LCD_SetBG(cursorX,cursorY,cursorL,0xff);
- }
- void Menu_Process(void)
- {
- static uint8_t state=0;
- static uint32_t tick = 0;
-
- static uint8_t keyU,keyD,keyE,keyC;
-
- static uint8_t parentIndex[100]; //几层页面
- static uint8_t dex=0;
-
- switch(state){
- enum {
- START = 0,
- KEY_PROCESS,
- RUN_ITEM_HANDLER
- };
- case START: state++;
- case KEY_PROCESS:{
- if(keyU!=SL_GetEvent(idSL_UP)){ keyU = SL_GetEvent(idSL_UP);
- if(keyU==SL_PRESS_DOWN){
- if(engine.curItemIndex>0) engine.curItemIndex--;
- else engine.curItemIndex = 7;
- }
- }else if(keyD!=SL_GetEvent(idSL_DOWN)){ keyD = SL_GetEvent(idSL_DOWN);
- if(keyD==SL_PRESS_DOWN){
- if(++engine.curItemIndex>7) engine.curItemIndex = 0;
- }
- }else if(keyE!=SL_GetEvent(idSL_ENTER)){ keyE = SL_GetEvent(idSL_ENTER);
- if(keyE==SL_PRESS_DOWN){
- item_t *pItem = &(engine.curPage->items[engine.curItemIndex]);
- if(pItem->fnHandle){
- engine.param = 0x80;
- state = RUN_ITEM_HANDLER;
- }else if(pItem->child){
- engine.curPage = pItem->child;
- parentIndex[dex++] = engine.curItemIndex;
- engine.curItemIndex = 0;
- }
- }
- }else if(keyC!=SL_GetEvent(idSL_ESC)){ keyC = SL_GetEvent(idSL_ESC);
- if(keyC==SL_PRESS_DOWN){
- page_t *ptPage = engine.curPage;
- if(ptPage->parent){
- engine.curPage = ptPage->parent;
- engine.curItemIndex = parentIndex[--dex];
- }
- }
- }
- break;}
- case RUN_ITEM_HANDLER:{
- item_t *pItem = &(engine.curPage->items[engine.curItemIndex]);
- int8_t ret = pItem->fnHandle(pItem);
- if(ret>0){
- engine.param = 0x00;
- state = START;
- }
- break;}
- }
-
- if(Sys_GetTick()-tick>=_LCD12864_CYCLE){ tick = Sys_GetTick();
- Menu_ShowItem(&engine);
- LCD_Process();
- }
- }
复制代码
app使用
- //以下为头文件
- #ifndef __APP_MENU_H__
- #define __APP_MENU_H__
- #ifdef __cplusplus
- extern "C" {
- #endif
- #include "main.h"
- #ifdef __cplusplus
- }
- #endif
- extern const page_t pageMain[];
- #endif
- //以下为C文件
- /*============================ INCLUDES ======================================*/
- #include "main.h"
- uint8_t num = 123;
- const char str[2][3] = {
- "否",
- "是",
- };
- uint8_t strSlect = 0;
- char pStr[3] = "否";
-
- int8_t cb_ChangeNum(item_t* pItem)
- {
- static uint8_t keyU=0,keyD=0,keyE=0,keyC=0;
-
- if(keyU!=SL_GetEvent(idSL_UP)){ keyU = SL_GetEvent(idSL_UP);
- if(keyU==SL_PRESS_DOWN){
- num++;
- }
- }else if(keyD!=SL_GetEvent(idSL_DOWN)){ keyD = SL_GetEvent(idSL_DOWN);
- if(keyD==SL_PRESS_DOWN){
- num--;
- }
- }else if(keyE!=SL_GetEvent(idSL_ENTER)){ keyE = SL_GetEvent(idSL_ENTER);
- if(keyE==SL_PRESS_DOWN){
- return 1;
- }
- }else if(keyC!=SL_GetEvent(idSL_ESC)){ keyC = SL_GetEvent(idSL_ESC);
- if(keyC==SL_PRESS_DOWN){
- return 1;
- }
- }
- return 0;
- }
- int8_t cb_ChangeCheck(item_t* pItem)
- {
- // static uint8_t keyU,keyD,keyE,keyC;
- if(++strSlect>=2) strSlect = 0;
- memcpy(pStr,str[strSlect],strlen(pStr));
- return 1;
- }
- //********************* 菜单 ***********************//
- const page_t page2[];
- const page_t page3[];
- //********************* 菜单项 ***********************//
- const item_t itemMain[] = {
- label,"菜单01",0,page2,0,
- label,"菜单02",0,page2,0,
- label,"菜单03",0,page2,0,
- label,"菜单04",0,page2,0,
- label,"菜单05",0,page2,0,
- label,"菜单06",0,page2,0,
- edit ,"菜单07",(uint8_t*)&num,0,cb_ChangeNum,
- text ,"菜单08",(const char*)pStr,page2,cb_ChangeCheck,
- };
- const item_t item2[] = {
- label,"子菜单01",0,page3,0,
- label,"子菜单02",0,page3,0,
- label,"子菜单03",0,page3,0,
- label,"子菜单04",0,page3,0,
- label,"子菜单05",0,page3,0,
- label,"子菜单06",0,page3,0,
- edit ,"子菜单07",(uint8_t*)&num,0,cb_ChangeNum,
- text ,"子菜单08",(const char*)pStr,0,cb_ChangeCheck,
- };
- const item_t item3[] = {
- label,"子子菜单01",0,0,0,
- label,"子子菜单02",0,0,0,
- label,"子子菜单03",0,0,0,
- label,"子子菜单04",0,0,0,
- label,"子子菜单05",0,0,0,
- label,"子子菜单06",0,0,0,
- edit ,"子子菜单07",(uint8_t*)&num,0,cb_ChangeNum,
- text ,"子子菜单08",(const char*)pStr,0,cb_ChangeCheck,
- };
- //********************* 页面 ***********************//
- const page_t pageMain[] = {
- "===== 页面1 ====",itemMain,UBOUND(itemMain),0,
- };
- const page_t page2[] = {
- "===== 页面2 ====",item2,UBOUND(item2),pageMain,
- };
- const page_t page3[] = {
- 0,item3,UBOUND(item3),page2,
- };
复制代码
几张效果图,请忽略渣渣的拍照技术。。。
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有帐号?注册
x
阿莫论坛20周年了!感谢大家的支持与爱护!!
月入3000的是反美的。收入3万是亲美的。收入30万是移民美国的。收入300万是取得绿卡后回国,教唆那些3000来反美的!
|