单片机编程:【经验分享】一个简单却实用的菜单程序
- 格式:doc
- 大小:22.50 KB
- 文档页数:2
单片机多级菜单编程实现单片机多级菜单编程实现(ZT)建立一个树状的菜单结构,用链表实现链表中包含:1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针;2、进入该菜单时需要执行的初始化函数指针3、退出该菜单时需要执行的结束函数指针4、该菜单内的按键处理函数指针数组的指针操作菜单模块需要的按键操作有:左、右、确认、退出。
采用这种办法,可以方便的添加或删减菜单。
并且只需要在其头文件中修改初始变量就可以实现,完全无须修改C文件中的任何函数。
具体结构定义我的定义,做个参考:#define MENU_HLP_EN //菜单帮助信息使能typedef struct{void (*pMenuTaskInit)(void); //指向菜单任务初始化函数的指针void (*pMenuTaskEnd)(void); //指向菜单任务结束函数的指针}MENU_TASK_TYP;typedef struct MenuTyp{INT8U *MenuName; //菜单名称字符串WORK_MOD WorkMod; //工作状态编号MENU_TASK_TYP *pMenuTask; //指向菜单任务的指针void (**pTaskKeyDeal)(void); //指向菜单任务按键处理函数数组的指针#ifdef MENU_HLP_ENINT8U *MenuHlp; //菜单帮助字符串#endifstruct MenuTyp *pParent; //指向上层菜单的指针struct MenuTyp *pChild; //指向子菜单的指针struct MenuTyp *pRight; //指向右菜单的指针struct MenuTyp *pLeft; //指向左菜单的指针}MENU_TYP;我根据网上的资料做的一个菜单:/****************菜单数据结构**********************/struct KeyTabStruct{uint8 MenuIndex; //当前状态索引号uint8 MaxItems; //本级菜单最大条目数uint8 ShowLevel; //菜单显示内容uint8 PressOk; //按下"回车"键时转向的状态索引号uint8 PressEsc; //按下"返回"键时转向的状态索引号uint8 PressDown; //按下"向下"键时转向的状态索引号uint8 PressUp; //按下"向上"键时转向的状态索引号void (*CurrentOperate)(); //当前状态应该执行的功能操作};uint8 MenuID; //菜单ID号uint8 MenuNextID; //下级菜单ID号//CurMenuID=本菜单ID//MaxMenuItem=同级菜单最大项数//OkMenuID=子菜单层所对应的菜单ID,ID=999为菜单已经到底了//EscMenuID=父菜单层所对应的菜单ID,ID=999为菜单已经到顶了//DownMenuID=弟菜单层所对应的菜单ID,ID=999为菜单是独生子//UpMenuID=兄菜单层所对应的菜单ID,ID=999为菜单是独生子//CurFunction=本菜单所对应的菜单函数指针const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={//CurMenuID, axMenuItem, MenuShowLevel, OkMenuID, EscMenuID, DownMenuID, UpMenuID, CurFunction{MENU_EDIT, 0, 0, MENU_DATA_VIEW, MENU_NO, MENU_NO, MENU_NO, *MenuEdit},{MENU_DATA_VIEW, 3, 1, MENU_DATA_VIEW_FIRE, MENU_EDIT, MENU_ SYS_EDIT, MENU_PRINT_DATA,*MenuEdit},{MENU_DATA_VIEW_FIRE, 5, MENU_NO, MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_TROUBLE, MENU_STEP_FOLLOW, *MenuDataViewIn}, {MENU_DATA_VIEW_TROUBLE, 5, MENU_NO, MENU_NO, MENU_DATA_VI EW, MENU_DATA_VIEW_REPEAT, MENU_DATA_VIEW_FIRE, *MenuDataVie wIn},{MENU_DATA_VIEW_REPEAT, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_FACE_CHECK,MENU_DATA_VIEW_TROUBLE, *MenuDataViewIn},{MENU_FACE_CHECK, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_STEP_FOLLOW,MENU_DATA_VIEW_REPEAT, *MenuFaceCheck},{MENU_STEP_FOLLOW, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_FIRE, MENU_FACE_CH ECK,*MenuStepFollow},{MENU_SYS_EDIT, 3,2, MENU_SUM_SET, MENU_EDIT,MENU_PRINT_DATA, MENU_DATA_VIEW, *MenuEdit},{MENU_SUM_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_INSULATE,MENU_TIME_SET, *MenuSumSet},{MENU_EDIT_INSULATE, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_HZ, MENU_SUM_SET,*MenuEditInsulate},{MENU_EDIT_HZ, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_LD_CONTROL,MENU_EDIT_INSULATE, *MenuEditHZ},{MENU_LD_CONTROL, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_LD_DELAY,MENU_EDIT_HZ, *MenuLDControl},{MENU_LD_DELAY, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_TIME_SET,MENU_LD_CONTROL, *MenuLDDelay},{MENU_TIME_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_SUM_SET, MENU_LD_DELAY,*MenuTimeSet},{MENU_PRINT_DATA, 3, 3,MENU_PRINT_DATA_FIRE, MENU_EDIT, MENU_DATA_VIEW,MENU_SYS_EDIT, *MenuEdit},{MENU_PRINT_DATA_FIRE, 4,MENU_NO, MENU_NO, MENU_PRINT_DATA,MENU_PRINT_DATA_TROUBLE, MENU_PRINT_SET, *MenuPrintDataIn}, {MENU_PRINT_DATA_TROUBLE, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINTER_CHECK,MENU_PRINT_DATA_FIRE, *MenuPrintDataIn},{MENU_PRINTER_CHECK, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINT_SET,MENU_PRINT_DATA_TROUBLE, *MenuPrintDataIn},{MENU_PRINT_SET, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINT_DATA_FIRE,MENU_PRINTER_CHECK, *MenuPrintSet},};/**************************************编程菜单显示数据******************************/const struct MenuDispData MenuEditShow[][MENU_MAX] = {{{MENU_NO , 0, 0, "选择: 消音→退出"}, //主菜单{MENU_DATA_VIEW , 1, 6, "⒈数据查看"},{MENU_SYS_EDIT , 2, 6, "⒉系统编程"},{MENU_PRINT_DATA , 3, 6, "⒊数据打印"}},{{MENU_NO , 0, 0, "数据查看: 消音→退出"}, //数据查看{MENU_DATA_VIEW_FIRE , 1, 4, "⒈火警"},{MENU_DATA_VIEW_TROUBLE, 2, 4, "⒉故障"},{MENU_DATA_VIEW_REPEAT , 3, 4, "⒊重码"},{MENU_FACE_CHECK , 1,12, "⒋面板检测"},{MENU_STEP_FOLLOW , 2,12, "⒌单步跟踪"}},{{MENU_NO , 0, 0, "系统编程: 消音→退出"}, //系统编程{MENU_SUM_SET , 1, 0, "⒈容量设置"},{MENU_EDIT_INSULATE , 2, 0, "⒉隔离点"},{MENU_EDIT_HZ , 3, 0, "⒊汉字描述"},{MENU_LD_CONTROL , 1,12, "⒋联动控制"},{MENU_LD_DELAY , 2,12, "⒌模块延时"},{MENU_TIME_SET , 3,12, "⒍时钟调整"}},{{MENU_NO , 0, 0, "数据打印: 消音→退出"}, //数据打印{MENU_PRINT_DATA_FIRE , 1, 0, "⒈火警数据"},{MENU_PRINT_DATA_TROUBLE,2, 0, "⒉故障数据"},{MENU_PRINTER_CHECK , 3, 0, "⒊打印机自检"},{MENU_PRINT_SET , 1,12, "⒋打印设置"}},};/***********************************等待按键******************** **************/void WaitKey(void){uint32 time;time = RTCFlag;WhichKey = KEY_NONE;while(!EscFlag){if(RTCFlag - time >= EDIT_TIME)EscFlag = TRUE;if(WhichKey != KEY_NONE){KeySound(300); //按键音return;}}}/*********************************显示多级菜单**********************************/void MenuEdit(){uint32 i,j=0;uint32 oldid;j = KeyTab[MenuID].ShowLevel;if(WhichKey == KEY_ESC || WhichKey == KEY_OK){ClearScreen();for(i=0;i<KeyTab[MenuNextID].MaxItems+1;i++) ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j] [i].Column,MenuEditShow[j][i].Pdata,0); //初始化显示oldid =0;//没有原先选择的项}else{if(WhichKey == KEY_UP)oldid = KeyTab[MenuNextID].PressDown;elseoldid = KeyTab[MenuNextID].PressUp;//指示原先的项}for(i=1;i<KeyTab[MenuNextID].MaxItems+1;i++){if(MenuEditShow[j][i].Id == oldid)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j][i].Column,MenuEditShow[j][i].Pdata,0); //正常显示原先的项else{if(MenuEditShow[j][i].Id == MenuNextID)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j][i].Column,MenuEditShow[j][i].Pdata,1); //反显当前选择的项}}WhichKey = KEY_NONE;}/******************************系统编程************************* ******/uint32 Edit(void){struct KeyTabStruct NowKeyTab; //指示当前的菜单值uint32 escflag = FALSE;ResetFlag = FALSE;ChangeFlag = FALSE;EscFlag = FALSE;MenuID = MENU_EDIT;NowKeyTab = KeyTab[MenuID];MenuNextID = NowKeyTab.PressOk;(*NowKeyTab.CurrentOperate)(); //显示主菜单do{if(WhichKey == KEY_NONE)WaitKey(); //等待按键switch(WhichKey){case KEY_ESC : if(NowKeyTab.PressEsc != MENU_NO) {MenuID =NowKeyTab.PressEsc;MenuNextID =NowKeyTab.MenuIndex;NowKeyTab = KeyTab[MenuID];NowKeyTab.PressOk =MenuNextID;(*NowKeyTab.CurrentOperate)(); //显示当前菜单}elseescflag =TRUE; //退出编程状态break;case KEY_OK : if(NowKeyTab.PressOk != MENU_NO) {MenuID =NowKeyTab.PressOk;NowKeyTab = KeyTab[MenuID];MenuNextID =NowKeyTab.PressOk;}(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作break;case KEY_UP : if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressUp != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressUp;MenuNextID = KeyTab[MenuNextID].PressUp;(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作}break;case KEY_DOWN: if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressDown != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressDown;MenuNextID = KeyTab[MenuNextID].PressDown;(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作}break;case KEY_RESET: ResetFlag = TRUE;break;default : break;}}while(!ResetFlag && !EscFlag && !escflag);if(ChangeFlag && !EscFlag && !ResetFlag) EditDataChange();if(ResetFlag)return SYS_RESET;else{return 0;}}关于这个菜单的说明:1.我用的是ARM处理器,所以51的时候把const改成code,uint32改成unsign ed char。
单片机C语言下LCD多级菜单的一种实现方法(转)2012-1-10 00:45阅读(1)单片机菜单程序#include#include#define SIZE_OF_KEYBD_MENU 20 //菜单长度uchar KeyFuncIndex=0;//uchar KeyFuncIndexNew=0;void (*KeyFuncPtr)(); //按键功能指针typedef struct{uchar KeyStateIndex; //当前状态索引号uchar KeyDnState; //按下"向下"键时转向的状态索引号uchar KeyUpState; //按下"向上"键时转向的状态索引号uchar KeyCrState; //按下"回车"键时转向的状态索引号void (*CurrentOperate)(); //当前状态应该执行的功能操作} KbdTabStruct;KbdTabStruct code KeyTab[SIZE_OF_KEYBD_MENU]={{ 0, 0, 0, 1,(*DummyJob)},//顶层{ 1, 2, 0, 3,(*DspUserInfo)},//第二层{ 2, 1, 1, 9,(*DspServiceInfo)}, //第二层{ 3, 0, 0, 1,(*DspVoltInfo)},//第三层>>DspUserInfo的展开{ 4, 0, 0, 1,(*DspCurrInfo)},//第三层>>DspUserInfo的展开{ 5, 0, 0, 1,(*DspFreqInfo)},//第三层>>DspUserInfo的展开{ 6, 0, 0, 1,(*DspCableInfo)},//第三层>>DspUserInfo的展开...........{ 9, 0, 0, 1,(*DspSetVoltLevel)}//第三层>>DspServiceInfo的展开..........};void GetKeyInput(void){uchar KeyValue;KeyValue=P1&0x07; //去掉高5bitdelay(50000);switch(KeyValue){case 1: //回车键,找出新的菜单状态编号{KeyFuncIndex=KeyTab[KeyFuncIndex].KeyCrState;break;}case 2: //向上键,找出新的菜单状态编号{KeyFuncIndex=KeyTab[KeyFuncIndex].KeyUpState; break;}case 4: //向下键,找出新的菜单状态编号{KeyFuncIndex=KeyTab[KeyFuncIndex].KeyDnState; break;}default: //按键错误的处理......break;}KeyFuncPtr=KeyTab[KeyFuncIndex].CurrentOperate; (*KeyFuncPtr)();//执行当前按键的操作}//其中KeyTab的设计颇费尽心机。
#include<reg51.h>#define uchar unsigned char#define uint unsigned int#define port P0 //DB0~DB7数据口sbit e=P2^0;//使能sbit rw=P2^1;//读写sbit rs=P2^2;//数据/命令sbit cs2=P2^3;//片选sbit cs1=P2^4;sbit busy=P0^7;//检测忙uchar code hz[][32]={{/*-- 文字: 信--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x40,0x20,0xF8,0x06,0x10,0x10,0x50,0x50,0x4A,0xAC,0xA8,0x08,0x08,0x08,0x00, 0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x1D,0x15,0x15,0x12,0x1E,0x00,0x00,0x00,0x00, },{/*-- 文字: 息--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0x00,0xF8,0x54,0x56,0x55,0x04,0xFC,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x10,0x0C,0x00,0x0D,0x11,0x21,0x25,0x29,0x21,0x28,0x30,0x22,0x02,0x04,0x00,}, {/*-- 文字: 通--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x40,0x44,0xC8,0x00,0xE0,0x24,0x54,0xFA,0x5A,0x16,0xF2,0x00,0x00,0x00,0x00, 0x08,0x08,0x0B,0x0C,0x08,0x17,0x10,0x11,0x37,0x21,0x24,0x2F,0x20,0x20,0x20,0x00,}, {/*-- 文字: 讯--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x80,0x42,0xC4,0x0C,0x80,0x90,0xF0,0x48,0x48,0xE8,0x18,0x00,0x00,0x00,0x00, 0x00,0x00,0x10,0x0F,0x04,0x02,0x00,0x1F,0x00,0x00,0x03,0x04,0x08,0x10,0x1C,0x00,}, {/*-- 文字: 时--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0xF8,0x48,0x44,0xFC,0x00,0xA0,0x20,0x20,0x20,0xFE,0x10,0x10,0x10,0x00,0x00, 0x00,0x0F,0x04,0x04,0x0F,0x00,0x00,0x01,0x10,0x20,0x3F,0x00,0x00,0x00,0x00,0x00,}, {/*-- 文字: 钟--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x40,0x30,0x4C,0xEB,0xA8,0x88,0x70,0x90,0x90,0xFF,0x88,0x88,0x78,0x00,0x00, 0x00,0x00,0x01,0x01,0x1F,0x08,0x04,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, },{/*-- 文字: 已--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0x0F,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x10,0x1E,0x00,0x00,}, {/*-- 文字: 发--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x20,0x38,0x20,0xE0,0xB8,0x96,0x90,0x90,0x14,0x08,0x00,0x00,0x00,0x00, 0x10,0x10,0x08,0x24,0x23,0x12,0x14,0x08,0x0C,0x13,0x30,0x20,0x20,0x20,0x20,0x00, },{/*-- 文字: 已--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xF0,0x44,0x44,0x44,0x44,0x32,0x0E,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x0F,0x10,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x10,0x1E,0x00,0x00,}, {/*-- 文字: 收--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0xE0,0x00,0x00,0xFE,0x00,0x40,0xA0,0x38,0x26,0xE0,0x10,0x10,0x00,0x00,0x00, 0x00,0x07,0x02,0x01,0x3F,0x10,0x10,0x08,0x05,0x02,0x05,0x08,0x18,0x10,0x10,0x00,}, {/*-- 文字: 草--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x04,0x04,0x04,0xE5,0x5E,0x54,0x54,0x9E,0x93,0x72,0x02,0x02,0x00,0x00,0x00, 0x04,0x04,0x04,0x04,0x04,0x05,0x05,0x7F,0x02,0x02,0x02,0x02,0x02,0x02,0x00,0x00,}, {/*-- 文字: 稿--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x40,0x48,0x48,0xFC,0xA4,0x26,0x00,0x08,0x68,0xD5,0xD6,0xB4,0x84,0x80,0x00,0x00, 0x04,0x02,0x01,0x1F,0x00,0x01,0x1E,0x01,0x0D,0x0A,0x0E,0x10,0x20,0x1F,0x00,0x00, },{/*-- 文字: 拨--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x20,0x20,0xFF,0x90,0x00,0x38,0x20,0xE0,0x9E,0x90,0x92,0x14,0x10,0x00,0x00, 0x02,0x02,0x11,0x3F,0x00,0x08,0x14,0x13,0x0A,0x04,0x0A,0x09,0x10,0x10,0x10,0x00,}, {/*-- 文字: 出--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0xF0,0x80,0x80,0x80,0xFE,0x40,0x40,0x40,0xF0,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x1C,0x10,0x10,0x10,0x1F,0x08,0x08,0x08,0x3C,0x00,0x00,0x00,0x00, },{/*-- 文字: 接--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x20,0x20,0xFF,0x90,0x50,0x80,0x88,0xA9,0x4A,0x74,0x44,0x44,0x00,0x00,0x00, 0x02,0x02,0x11,0x3F,0x00,0x22,0x22,0x16,0x0B,0x0A,0x17,0x11,0x21,0x01,0x01,0x00,}, {/*-- 文字: 听--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0xF0,0x88,0x88,0x78,0x00,0x00,0xFC,0x44,0x44,0xC2,0x22,0x20,0x20,0x00,0x00, 0x00,0x00,0x00,0x00,0x10,0x08,0x06,0x01,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00, },{/*-- 文字: 未--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x80,0x80,0x90,0x90,0xFF,0xC8,0x48,0x48,0x40,0x40,0x00,0x00,0x00,0x00, 0x10,0x10,0x08,0x04,0x02,0x01,0x7F,0x00,0x01,0x02,0x04,0x08,0x18,0x10,0x10,0x00, },{/*-- 文字: 接--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x02,0x02,0x11,0x3F,0x00,0x22,0x22,0x16,0x0B,0x0A,0x17,0x11,0x21,0x01,0x01,0x00, },{/*-- 文字: 日--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0x00,0xF8,0x88,0x88,0x44,0x44,0x04,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x08,0x04,0x04,0x04,0x08,0x0F,0x00,0x00,0x00,0x00,0x00,}, {/*-- 文字: 期--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x08,0x08,0xFE,0xA8,0x04,0xFF,0x04,0x00,0xF8,0x24,0x04,0xFC,0x00,0x00,0x02,0x22,0x12,0x0A,0x07,0x02,0x06,0x49,0x21,0x18,0x07,0x01,0x10,0x3F,0x00,0x00, },{/*-- 文字: 闹--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0xF8,0x01,0xA2,0xA0,0xA8,0xF2,0x52,0xD2,0x02,0x02,0xFE,0x00,0x00,0x00, 0x00,0x00,0x1F,0x00,0x07,0x00,0x00,0x1F,0x02,0x07,0x00,0x10,0x3F,0x00,0x00,0x00,}, {/*-- 文字: 钟--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x80,0x40,0x30,0x4C,0xEB,0xA8,0x88,0x70,0x90,0x90,0xFF,0x88,0x88,0x78,0x00,0x00,0x00,0x00,0x01,0x01,0x1F,0x08,0x04,0x00,0x00,0x00,0x7F,0x00,0x00,0x00,0x00,0x00,}, {/*-- 文字: 设--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x40,0x20,0xE2,0x04,0x00,0x40,0x20,0x9C,0x82,0x82,0xBE,0x20,0x20,0x00,0x00,0x00,0x00,0x00,0x1F,0x08,0x24,0x20,0x11,0x0A,0x04,0x0A,0x11,0x30,0x20,0x20,0x20,0x00,}, {/*-- 文字: 置--*//*-- 楷体_GB231212; 此字体下对应的点阵为:宽x高=16x16 --*/0x00,0x00,0x00,0x4C,0x54,0x54,0xFA,0xAA,0xAE,0xAA,0x2A,0x26,0x00,0x00,0x00,0x00, 0x00,0x20,0x20,0x20,0x20,0x3F,0x2A,0x2A,0x20,0x1F,0x10,0x10,0x10,0x10,0x00,0x00,}, };uchar code num[][16]={{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00}, //"0",0{0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00}, //"1",1{0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00}, //"2",2{0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00}, //"3",3{0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00}, //"4",4{0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00},//"5",5{0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00}, //"6",6{0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00}, //"7",7{0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00}, //"8",8{0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00} //"9",9};uchar code sign[][16]={{0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00}, //"!",0{0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00}, //":",1{0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00} //"Q",2};//延时void delay(uint n){uint i;for(;n>0;n--)for(i=200;i>0;i--);}//判断是否忙void check(){rs=0;rw=1; //读e=1;port=0x00;e=1;while(busy);e=0;}//写指令void sendcommand(uchar command){check();rs=0; //指令rw=0; //写e=0;port=command;e=1;e=0; //写入指令}//写数据void writedata(uchar dat){check();rs=1; //数据rw=0;port=dat;e=1;e=0;}//选屏幕0--全屏,1--左屏,2--右屏;void select(uint n){switch(n){case 0:cs1=0;cs2=0;break; //低电平选中case 1:cs1=0;cs2=1;break; //cs1左屏case 2:cs1=1;cs2=0;break; //cs2右屏}}//页void setpage(uchar page){page=page&0x07;page=page|0xb8;sendcommand(page);}//列void setcolumn(uchar column){column=column&0x3f;column=column|0x40;sendcommand(column);}//起始行void setline(uchar line){line=line&0x3f;line=line|0xc0;sendcommand(line);}//屏幕开关显示0--关,1--开;void seton(uint n){n=n|0x3f;sendcommand(n);}//清屏0--全屏,1--左屏,2--右屏;void clear(uint n){uchar i,j;select(n);for(i=0;i<8;i++){setpage(i);setcolumn(0);for(j=0;j<64;j++)writedata(0); //置0清空}}//初始化void init(){check();seton(1);clear(0);setline(0);}void show16(uchar page,uchar column,uchar screen,uchar method,uchar *str)//页,列,屏,反白,第几个字{uchar i,j;select(screen);j=0;setpage(page);setcolumn(column);for(i=0;i<16;i++){ if(method==1) writedata(~str[j++]); //method为显示方式。
stc单片机编程实例单片机(Single Chip Microcontroller)是一种集成了中央处理器、存储器和各种外设功能的微型计算机系统。
它具有体积小、功能强大、成本低廉等特点,广泛应用于各个领域。
在使用STC单片机进行编程时,我们可以通过实例来学习和理解其编程原理和应用方法。
本文将介绍几个STC单片机编程实例,以帮助读者深入了解和掌握该技术。
实例一:LED闪烁首先,我们来实现一个简单的LED闪烁程序。
通过控制IO口输出高低电平,从而控制LED的亮灭。
下面是代码示例:```#include <reg52.h>sbit LED = P1^0; // 将P1.0引脚定义为LED控制引脚void main(){while(1){LED = 0; // LED亮delay(); // 延时LED = 1; // LED灭delay(); // 延时}}void delay(){int i, j;for(i = 0; i < 100; i++)for(j = 0; j < 1000; j++);}```在上述代码中,我们首先通过`#include<reg52.h>`导入STC单片机的寄存器定义文件。
然后,我们使用`sbit`关键字将P1.0引脚定义为LED控制引脚。
在`main()`函数中,我们循环执行LED亮灭的操作,并通过`delay()`函数进行延时控制。
实例二:数码管显示接下来,我们将实现一个数码管显示程序。
通过控制IO口输出不同的数码管段选信号和位选信号,从而使数码管显示出指定的数字。
下面是代码示例:```#include <reg52.h>unsigned char code smgduan[] = {0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90}; // 数码管显示字符对应的编码sbit smg_duan = P1^0; // 数码管段选信号sbit smg_wei = P1^1; // 数码管位选信号void main(){unsigned char i;while(1){for(i = 0; i < 10; i++){smg_duan = smgduan[i]; // 设置段选信号smg_wei = 0; // 显示位选信号有效delay(); // 延时smg_wei = 1; // 显示位选信号无效}}}void delay(){int i, j;for(i = 0; i < 100; i++)for(j = 0; j < 1000; j++);}```在上述代码中,我们使用了一个长数组`smgduan`来存储数码管显示字符的编码。
单片机多级菜单编程实现单片机多级菜单编程实现(ZT)建立一个树状的菜单结构,用链表实现链表中包含:1、指向同级左右菜单和指向父菜单、子菜单的四个菜单结构体指针;2、进入该菜单时需要执行的初始化函数指针3、退出该菜单时需要执行的结束函数指针4、该菜单内的按键处理函数指针数组的指针操作菜单模块需要的按键操作有:左、右、确认、退出。
采用这种办法,可以方便的添加或删减菜单。
并且只需要在其头文件中修改初始变量就可以实现,完全无须修改C文件中的任何函数。
具体结构定义我的定义,做个参考:#define MENU_HLP_EN //菜单帮助信息使能typedef struct{void (*pMenuTaskInit)(void); //指向菜单任务初始化函数的指针void (*pMenuTaskEnd)(void); //指向菜单任务结束函数的指针}MENU_TASK_TYP;typedef struct MenuTyp{INT8U *MenuName; //菜单名称字符串WORK_MOD WorkMod; //工作状态编号MENU_TASK_TYP *pMenuTask; //指向菜单任务的指针void (**pTaskKeyDeal)(void); //指向菜单任务按键处理函数数组的指针#ifdef MENU_HLP_ENINT8U *MenuHlp; //菜单帮助字符串#endifstruct MenuTyp *pParent; //指向上层菜单的指针struct MenuTyp *pChild; //指向子菜单的指针struct MenuTyp *pRight; //指向右菜单的指针struct MenuTyp *pLeft; //指向左菜单的指针}MENU_TYP;我根据网上的资料做的一个菜单:/****************菜单数据结构**********************/struct KeyTabStruct{uint8 MenuIndex; //当前状态索引号uint8 MaxItems; //本级菜单最大条目数uint8 ShowLevel; //菜单显示内容uint8 PressOk; //按下"回车"键时转向的状态索引号uint8 PressEsc; //按下"返回"键时转向的状态索引号uint8 PressDown; //按下"向下"键时转向的状态索引号uint8 PressUp; //按下"向上"键时转向的状态索引号void (*CurrentOperate)(); //当前状态应该执行的功能操作};uint8 MenuID; //菜单ID号uint8 MenuNextID; //下级菜单ID号//CurMenuID=本菜单ID//MaxMenuItem=同级菜单最大项数//OkMenuID=子菜单层所对应的菜单ID,ID=999为菜单已经到底了//EscMenuID=父菜单层所对应的菜单ID,ID=999为菜单已经到顶了//DownMenuID=弟菜单层所对应的菜单ID,ID=999为菜单是独生子//UpMenuID=兄菜单层所对应的菜单ID,ID=999为菜单是独生子//CurFunction=本菜单所对应的菜单函数指针const struct KeyTabStruct KeyTab[MAX_KEYTABSTRUCT_NUM]={//CurMenuID, axMenuItem, MenuShowLevel, OkMenuID, EscMenuID, DownMenuID, UpMenuID, CurFunction{MENU_EDIT, 0, 0, MENU_DATA_VIEW, MENU_NO, MENU_NO, MENU_NO, *MenuEdit},{MENU_DATA_VIEW, 3, 1, MENU_DATA_VIEW_FIRE, MENU_EDIT, MENU_ SYS_EDIT, MENU_PRINT_DATA,*MenuEdit},{MENU_DATA_VIEW_FIRE, 5, MENU_NO, MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_TROUBLE, MENU_STEP_FOLLOW, *MenuDataViewIn}, {MENU_DATA_VIEW_TROUBLE, 5, MENU_NO, MENU_NO, MENU_DATA_VI EW, MENU_DATA_VIEW_REPEAT, MENU_DATA_VIEW_FIRE, *MenuDataVie wIn},{MENU_DATA_VIEW_REPEAT, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_FACE_CHECK,MENU_DATA_VIEW_TROUBLE, *MenuDataViewIn},{MENU_FACE_CHECK, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_STEP_FOLLOW,MENU_DATA_VIEW_REPEAT, *MenuFaceCheck},{MENU_STEP_FOLLOW, 5, MENU_NO,MENU_NO, MENU_DATA_VIEW, MENU_DATA_VIEW_FIRE, MENU_FACE_CH ECK,*MenuStepFollow},{MENU_SYS_EDIT, 3,2, MENU_SUM_SET, MENU_EDIT,MENU_PRINT_DATA, MENU_DATA_VIEW, *MenuEdit},{MENU_SUM_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_INSULATE,MENU_TIME_SET, *MenuSumSet},{MENU_EDIT_INSULATE, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_EDIT_HZ, MENU_SUM_SET,*MenuEditInsulate},{MENU_EDIT_HZ, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_LD_CONTROL,MENU_EDIT_INSULATE, *MenuEditHZ},{MENU_LD_CONTROL, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_LD_DELAY,MENU_EDIT_HZ, *MenuLDControl},{MENU_LD_DELAY, 6,MENU_NO, MENU_NO, MENU_SYS_EDIT, MENU_TIME_SET,MENU_LD_CONTROL, *MenuLDDelay},{MENU_TIME_SET, 6, MENU_NO,MENU_NO, MENU_SYS_EDIT, MENU_SUM_SET, MENU_LD_DELAY,*MenuTimeSet},{MENU_PRINT_DATA, 3, 3,MENU_PRINT_DATA_FIRE, MENU_EDIT, MENU_DATA_VIEW,MENU_SYS_EDIT, *MenuEdit},{MENU_PRINT_DATA_FIRE, 4,MENU_NO, MENU_NO, MENU_PRINT_DATA,MENU_PRINT_DATA_TROUBLE, MENU_PRINT_SET, *MenuPrintDataIn}, {MENU_PRINT_DATA_TROUBLE, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINTER_CHECK,MENU_PRINT_DATA_FIRE, *MenuPrintDataIn},{MENU_PRINTER_CHECK, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINT_SET,MENU_PRINT_DATA_TROUBLE, *MenuPrintDataIn},{MENU_PRINT_SET, 4, MENU_NO,MENU_NO, MENU_PRINT_DATA, MENU_PRINT_DATA_FIRE,MENU_PRINTER_CHECK, *MenuPrintSet},};/**************************************编程菜单显示数据******************************/const struct MenuDispData MenuEditShow[][MENU_MAX] = {{{MENU_NO , 0, 0, "选择: 消音→退出"}, //主菜单{MENU_DATA_VIEW , 1, 6, "⒈数据查看"},{MENU_SYS_EDIT , 2, 6, "⒉系统编程"},{MENU_PRINT_DATA , 3, 6, "⒊数据打印"}},{{MENU_NO , 0, 0, "数据查看: 消音→退出"}, //数据查看{MENU_DATA_VIEW_FIRE , 1, 4, "⒈火警"},{MENU_DATA_VIEW_TROUBLE, 2, 4, "⒉故障"},{MENU_DATA_VIEW_REPEAT , 3, 4, "⒊重码"},{MENU_FACE_CHECK , 1,12, "⒋面板检测"},{MENU_STEP_FOLLOW , 2,12, "⒌单步跟踪"}},{{MENU_NO , 0, 0, "系统编程: 消音→退出"}, //系统编程{MENU_SUM_SET , 1, 0, "⒈容量设置"},{MENU_EDIT_INSULATE , 2, 0, "⒉隔离点"},{MENU_EDIT_HZ , 3, 0, "⒊汉字描述"},{MENU_LD_CONTROL , 1,12, "⒋联动控制"},{MENU_LD_DELAY , 2,12, "⒌模块延时"},{MENU_TIME_SET , 3,12, "⒍时钟调整"}},{{MENU_NO , 0, 0, "数据打印: 消音→退出"}, //数据打印{MENU_PRINT_DATA_FIRE , 1, 0, "⒈火警数据"},{MENU_PRINT_DATA_TROUBLE,2, 0, "⒉故障数据"},{MENU_PRINTER_CHECK , 3, 0, "⒊打印机自检"},{MENU_PRINT_SET , 1,12, "⒋打印设置"}},};/***********************************等待按键******************** **************/void WaitKey(void){uint32 time;time = RTCFlag;WhichKey = KEY_NONE;while(!EscFlag){if(RTCFlag - time >= EDIT_TIME)EscFlag = TRUE;if(WhichKey != KEY_NONE){KeySound(300); //按键音return;}}}/*********************************显示多级菜单**********************************/void MenuEdit(){uint32 i,j=0;uint32 oldid;j = KeyTab[MenuID].ShowLevel;if(WhichKey == KEY_ESC || WhichKey == KEY_OK){ClearScreen();for(i=0;i<KeyTab[MenuNextID].MaxItems+1;i++) ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j] [i].Column,MenuEditShow[j][i].Pdata,0); //初始化显示oldid =0;//没有原先选择的项}else{if(WhichKey == KEY_UP)oldid = KeyTab[MenuNextID].PressDown;elseoldid = KeyTab[MenuNextID].PressUp;//指示原先的项}for(i=1;i<KeyTab[MenuNextID].MaxItems+1;i++){if(MenuEditShow[j][i].Id == oldid)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j][i].Column,MenuEditShow[j][i].Pdata,0); //正常显示原先的项else{if(MenuEditShow[j][i].Id == MenuNextID)ShowString(MenuEditShow[j][i].Lin,MenuEditShow[j][i].Column,MenuEditShow[j][i].Pdata,1); //反显当前选择的项}}WhichKey = KEY_NONE;}/******************************系统编程************************* ******/uint32 Edit(void){struct KeyTabStruct NowKeyTab; //指示当前的菜单值uint32 escflag = FALSE;ResetFlag = FALSE;ChangeFlag = FALSE;EscFlag = FALSE;MenuID = MENU_EDIT;NowKeyTab = KeyTab[MenuID];MenuNextID = NowKeyTab.PressOk;(*NowKeyTab.CurrentOperate)(); //显示主菜单do{if(WhichKey == KEY_NONE)WaitKey(); //等待按键switch(WhichKey){case KEY_ESC : if(NowKeyTab.PressEsc != MENU_NO) {MenuID =NowKeyTab.PressEsc;MenuNextID =NowKeyTab.MenuIndex;NowKeyTab = KeyTab[MenuID];NowKeyTab.PressOk =MenuNextID;(*NowKeyTab.CurrentOperate)(); //显示当前菜单}elseescflag =TRUE; //退出编程状态break;case KEY_OK : if(NowKeyTab.PressOk != MENU_NO) {MenuID =NowKeyTab.PressOk;NowKeyTab = KeyTab[MenuID];MenuNextID =NowKeyTab.PressOk;}(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作break;case KEY_UP : if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressUp != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressUp;MenuNextID = KeyTab[MenuNextID].PressUp;(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作}break;case KEY_DOWN: if((MenuNextID != MENU_NO) && (KeyTab[MenuNextID].PressDown != MENU_NO)){NowKeyTab.PressOk =KeyTab[MenuNextID].PressDown;MenuNextID = KeyTab[MenuNextID].PressDown;(*NowKeyTab.CurrentOperate)(); //执行当前按键的操作}break;case KEY_RESET: ResetFlag = TRUE;break;default : break;}}while(!ResetFlag && !EscFlag && !escflag);if(ChangeFlag && !EscFlag && !ResetFlag) EditDataChange();if(ResetFlag)return SYS_RESET;else{return 0;}}关于这个菜单的说明:1.我用的是ARM处理器,所以51的时候把const改成code,uint32改成unsign ed char。
该菜单程序需要建立两个C文件main.c,lcd.c,和一个用户自定义头文件Icd.h,以函数调用为算法,写成的理解难度稍大,但一旦理解便可应用自如。
#include<reg52.h>#include"Icd.h"#define uchar unsigned char#define uint unsigned intsbit keyup=P1^5; //上移sbit keydown=P1^1; //下移sbit keyenter=P1^0; //确认sbit keyback=P1^2; //返回;uchar code a[16]={"1 励志歌曲"};uchar code b[16]={"2 流行歌曲"};uchar code c[16]={"3 军旅歌曲"};uchar code lz1[16]={"1 精忠报国"};uchar code lz2[16]={"2 男儿当自强"};uchar code lz3[16]={"3 藏龙卧虎"};uchar code lx1[16]={"1 男人海洋"};uchar code lx2[16]={"2 痴心绝对"};uchar code lx3[16]={"3 痛彻心扉"};uchar code jl1[16]={"1 军中绿花"};uchar code jl2[16]={"2 咱当兵的人"};uchar code jl3[16]={"3 我是一个兵"};void display();void photodisplay(uchar x,uchar y,uchar width);void xianshi1() //显示主菜单{uchar i;delay(5);Icd_init();Icd_pos(1,0); //设置a【】的显示位置for(i=0;i<16;i++){Icd_wdat(a[i]); //把a【】的数据显示在液晶屏delay(10);}Icd_pos(2,0); //设置b【】的显示位置for(i=0;i<16;i++){Icd_wdat(b[i]); //把b【】的数据显示在液晶屏上delay(10);}Icd_pos(3,0); //设置c【】的显示位置for(i=0;i<16;i++){Icd_wdat(c[i]); //把c【】的数据显示在液晶屏上delay(10);}}void xianshi2() // 显示子菜单一{uchar i;delay(5);Icd_init();Icd_pos(1,0); //设置lz1【】的显示位置for(i=0;i<16;i++){Icd_wdat(lz1[i]); //把lz1【】的数据显示在液晶屏上delay(10);}Icd_pos(2,0); //设置lz2【】的显示位置for(i=0;i<16;i++){Icd_wdat(lz2[i]); //把lz2【】的数据显示在液晶屏上delay(10);}Icd_pos(3,0); //设置lz3【】的显示位置for(i=0;i<16;i++){Icd_wdat(lz3[i]); //把lz3【】的数据显示在液晶屏上delay(10);}}void xianshi3() //显示子菜单二{uchar i;delay(5);Icd_init();Icd_pos(1,0); //设置lx1【】的显示位置for(i=0;i<16;i++){Icd_wdat(lx1[i]); //把lx1【】的数据显示在液晶屏上delay(10);}Icd_pos(2,0); //设置lx2【】的显示位置for(i=0;i<16;i++){Icd_wdat(lx2[i]); //把lx2【】的数据显示在液晶屏上delay(10);}Icd_pos(3,0); //设置lx3【】的显示位置for(i=0;i<16;i++){Icd_wdat(lx3[i]); //把lx3【】的数据显示在液晶屏上delay(10);}}void xianshi4() //显示子菜单三{uchar i;delay(5);Icd_init();Icd_pos(1,0); //设置jl1【】的显示位置for(i=0;i<16;i++){Icd_wdat(jl1[i]); //把jl1【】的数据显示在液晶屏上delay(10);}Icd_pos(2,0); //设置jl2【】的显示位置for(i=0;i<16;i++){Icd_wdat(jl2[i]); //把jl2【】的数据显示在液晶屏上delay(10);}Icd_pos(3,0); //设置jl3【】的显示位置for(i=0;i<16;i++){Icd_wdat(jl3[i]); //把jl3【】的数据显示在液晶屏上delay(10);}}void enter(uchar n) //确认函数{while(1){if(n==0&&keyenter==0) //反白区在主菜单第一行按下确认键{delay(500);if(n==0&&keyenter==0){xianshi2(); //显示子菜单一delay(30);}}if(n==1&&keyenter==0) //反白区在主菜单第二行按下确认键{delay(500);if(n==1&&keyenter==0){xianshi3(); //显示子菜单二delay(30);}}if(n==2&&keyenter==0) //反白区在主菜单第三行按下确认键{delay(500);if(n==2&&keyenter==0){xianshi4(); //显示子菜单三delay(30);}}if(keyback==0||keyup==0||keydown==0) //按下返回,上移,下移时跳出循环体{delay(500);if(keyback==0||keyup==0||keydown==0)break;}}}void back() //返回函数{while(1){if(keyback==0) //按下返回键返回主菜单{delay(500);if(keyback==0){xianshi1(); //显示主菜单delay(30);}}if(keyenter==0||keyup==0||keydown==0) //跳出返回函数的循环体向下执行{delay(500);if(keyenter==0||keyup==0||keydown==0)break;}}}uchar keyscan(){uchar m=0; //设置显示反白位置的标志变量while(1){if(keydown==0&&m==0) //反白位置在第一行,按下下移键移到第二行{delay(400);if(keydown==0&&m==0){photodisplay(2,1,6); //第二行后12个字节反白delay(10);m=1;}}if(keyup==0&&m==0) //反白位置在第一行,按下上移键移到第三行{delay(500);if(keyup==0&&m==0){photodisplay(2,2,6); //第三行后12个字节反白delay(10);m=2;}}if(keydown==0&&m==1) //反白位置在第二行,按下下移键移到第三行{delay(400);if(keydown==0&&m==1){photodisplay(2,2,6); //第三行后12个字节反白delay(10);m=2;}}if(keyup==0&&m==2) //反白位置在第三行,按下上移键移到第二行{delay(500);if(keyup==0&&m==2){photodisplay(2,1,6); //第二行后12个字节反白delay(10);m=1;}if(keydown==0&&m==2) //反白位置在第三行,按下下移键移到第一行{delay(400);if(keydown==0&&m==2){photodisplay(2,0,6); //第一行后12个字节反白delay(10);m=0;}}if(keyup==0&&m==1) //反白位置在第二行,按下上移键移到第一行{delay(500);if(keyup==0&&m==1)photodisplay(2,0,6); //第一行后12个字节反白delay(10);m=0;}}if(keyback==0||keyenter==0) // 按下返回,确认跳出上下移动的循环体向下执行{delay(500);if(keyback==0||keyenter==0)break;}}return (m); //返回的标志变量的值做为确认函数进入相应子菜单的判断依据}void main() //主函数{uchar n;xianshi1();photodisplay(2,0,6); //显示主菜单时反白的初始位置在第一行delay(10);n=keyscan(); //调用上下移动函数enter(n); //调用确认函数photodisplay(2,0,6);delay(10);keyscan();back(); //调用返回函数photodisplay(2,0,6);delay(10);}void display() //为反白做准备,目地是在图形显示时防止有噪点uchar i,j;Icd_wcmd(0x34); //写数据时,关闭图形显示for(i=0;i<32;i++) //先写入上半屏{Icd_wcmd(0x80+i); //先写入水平坐标值Icd_wcmd(0x80); //写入垂直坐标值for(j=0;j<16;j++) //再写入两个8位元的数据Icd_wdat(0x00);delay(1);}for(i=0;i<32;i++) //在写入下半屏{Icd_wcmd(0x80+i);Icd_wcmd(0x88);for(j=0;j<16;j++)Icd_wdat(0x00);delay(1);}Icd_wcmd(0x36); //写完数据,开图形显示void photodisplay(uchar x,uchar y,uchar width) //反白,X值为0-7,Y值为0-3,width为行反白格数{uchar i,j,flag=0x00;display();if(y>1){flag=0x08;y=y-2;}Icd_wcmd(0x34); //写数据时,关闭图形显示,且打开扩展指令集for(i=0;i<16;i++){Icd_wcmd(0x80+(y<<4)+i);Icd_wcmd(0x80+flag+x);for(j=0;j<width;j++){Icd_wdat(0xff);Icd_wdat(0xff);}delay(1);}Icd_wcmd(0x36); //写完数据,开图形显示// Icd_wcmd(0x30); //从扩展指令到基本指令}定义液晶的底层函数的C文件#include<reg52.h>#include<intrins.h>#include"Icd.h"#define uint unsigned int#define uchar unsigned charsbit RS=P2^6;sbit RW=P2^5;sbit EN=P2^7;sbit PSB=P3^2;sbit RST=P3^7;#define nop(); {_nop_();_nop_();_nop_();_nop_();};void delay(uint xms) //定义延时函数{uchar m;for(xms;xms>0;xms--)for(m=110;m>0;m--);}bit Icd_busy() //定义检查忙碌函数{bit result;RS=0;RW=1;EN=1;nop();result=(bit)(P0&0x80);EN=0;return (result);}void Icd_wcmd(uchar cmd) //定义传输控制指令函数{while(Icd_busy());RS=0;RW=0;EN=0;_nop_();_nop_();P0=cmd;nop();EN=1;nop();EN=0;}void Icd_wdat(uchar dat) //定义传输数据函数{while(Icd_busy());RS=1;RW=0;EN=0;P0=dat;nop();EN=1;nop();EN=0;}void Icd_pos(uchar x,uchar y) //定义显示位置设定函数{uchar pos;if (x==1){x=0x80;}else if (x==2){x=0x90;}else if (x==3){x=0x88;}else if (x==4){x=0x98;}pos = x+y ;Icd_wcmd(pos);}void Icd_init() //定义初始化函数{PSB=1;RST=0;delay(3);RST=1;delay(3);Icd_wcmd(0x34);delay(5);Icd_wcmd(0x30);delay(5);Icd_wcmd(0x0c);delay(5);Icd_wcmd(0x01);delay(5);}用户自定的头文件”Icd.h”: 液晶显示底层函数配置#define uint unsigned int#define uchar unsigned charextern void delay(uint xms); //扩展延时函数的作用域extern bit Icd_busy(); //扩展查忙函数的作用域extern void Icd_wcmd(uchar cmd); //扩展传输控制指令函数的作用域extern void Icd_wdat(uchar dat); //扩展传输数据函数的作用域extern void Icd_init(); //扩展初始化函数的作用域extern void Icd_pos(uchar x,uchar y); //扩展设定位置函数的作用。
stc单片机范例程序STC单片机范例程序STC单片机是一种常用的嵌入式系统开发工具,它具有体积小、功耗低、功能强大等特点,被广泛应用于各种电子设备中。
在使用STC单片机开发项目时,范例程序是非常重要的参考资料。
本文将介绍一些常见的STC单片机范例程序,以帮助读者更好地理解和应用STC单片机。
一、LED闪烁程序以下是一个简单的LED闪烁程序范例:```c#include <reg52.h>sbit LED = P1^0;void main(){while(1){LED = 0; // LED亮delay(500); // 延时500msLED = 1; // LED灭delay(500); // 延时500ms}}void delay(unsigned int count){unsigned int i, j;for(i = 0; i < count; i++)for(j = 0; j < 120; j++);}```该程序使用了P1口的第0位作为控制LED的引脚,通过不断改变LED的状态来实现LED的闪烁效果。
其中的delay函数用于延时一定的时间,以控制LED的亮灭频率。
二、按键检测程序以下是一个简单的按键检测程序范例:```c#include <reg52.h>sbit KEY = P2^0;sbit LED = P1^0;void main(){while(1){if(KEY == 0) // 检测按键是否按下{LED = 0; // LED亮}else{LED = 1; // LED灭}}}```该程序使用了P2口的第0位作为检测按键的引脚,当按键被按下时,LED亮起;当按键松开时,LED熄灭。
三、数码管显示程序以下是一个简单的数码管显示程序范例:```c#include <reg52.h>unsigned char code ledChar[] = {0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};sbit digit1 = P2^0;sbit digit2 = P2^1;sbit digit3 = P2^2;sbit digit4 = P2^3;void main(){unsigned char i = 0;while(1){P0 = ledChar[i]; // 在数码管上显示数字digit1 = 1; // 第1位数码管亮digit2 = 0; // 第2位数码管灭digit3 = 0; // 第3位数码管灭digit4 = 0; // 第4位数码管灭delay(10);P0 = ledChar[i]; // 在数码管上显示数字digit1 = 0; // 第1位数码管灭digit2 = 1; // 第2位数码管亮digit3 = 0; // 第3位数码管灭digit4 = 0; // 第4位数码管灭delay(10);P0 = ledChar[i]; // 在数码管上显示数字 digit1 = 0; // 第1位数码管灭digit2 = 0; // 第2位数码管灭digit3 = 1; // 第3位数码管亮digit4 = 0; // 第4位数码管灭delay(10);P0 = ledChar[i]; // 在数码管上显示数字 digit1 = 0; // 第1位数码管灭digit2 = 0; // 第2位数码管灭digit3 = 0; // 第3位数码管灭digit4 = 1; // 第4位数码管亮delay(10);i++;if(i == 10){i = 0;}}}void delay(unsigned int count){unsigned int i, j;for(i = 0; i < count; i++)for(j = 0; j < 120; j++);}```该程序使用了P0口作为数码管的控制引脚,通过改变P0口的输出来控制数码管显示不同的数字。
C51菜单设计struct menu{struct menu flash *parent;struct menu flash *child;uchar hide;uchar pos;uchar MenuLenght;uchar MenuId;uchar str_len;uchar menu_str[16];};注意:在这里定义一个结构体,可以根据自己的需要进行修改。
struct menu flash menu_datetime[];struct menu flash menu_mod[];struct menu flash menu_serialnum[];struct menu flash menu_transmit[];struct menu flash menu_data[];struct menu flash menu_inter[];在实际的应用中可以结合实际的需求来设置菜单,进行初始化。
下面可以加入菜单链表如:datatime.child=menu_mod.parent;就完成了两个菜单的连接。
uchar menu_exe(){struct menu flash *mp;uchar flash *str;uchar menu_len,position;mp = main_menu;position = 0;while(1){menu_len = mp->MenuLenght;str = mp->menu_str;DISTY=1;clr_all();NUM = mp->str_len;FIR_COL =61-NUM*16/2;dis_str(str);while(!(keyb()))注意这里需要判断按键:switch(key_val){case UP_KEY:if(position == (menu_len-1)){position = 0;mp -= menu_len-1;}else{mp++;position++;}break;case DOWN_KEY:if(position == 0){position = menu_len-1;mp += menu_len-1;}else{mp--;position--;}break;case ENTER_KEY:if(mp->child == NULL)return mp->MenuId;mp = mp->child;position = 0;break;case ESC_KEY:if(mp->parent == NULL) return 0xff;mp = mp->parent;position = mp->pos;break;default:break;}}}在进行OSD处理时只要把指针*mp的值送入OSD芯片即可。
【回到大虾单片机电子网首页】 【回到精华帖子首页】标题标题::一种在单片机便于修改的多级菜单及程序思路关键关键字字:编号:606 大大虾论坛虾论坛文章文章文章编编号:210132 发发表时间时间::2004-2-18 1:12:07 访问访问访问次次数:826 文章文章类类型:经验交流 作者作者::zzwj5120/id:18030跟帖作者跟帖作者::清风徐徐,倾云之恋,gegegegeda ,jye ,Oldkey ,本页地址地址::/bibis/lookgood.asp?lookid=606一种在单片机便于修改的多片机便于修改的多级级菜单及程序思路及程序思路((17561756字字)zzwj51202004zzwj51202004--2-18 1:12:07[15918 1:12:07[159次次]完全用数据结构的方法建立多级菜单,网上有现成的例子,但不便于修改和维护。
这里给出另一个思路,不但完全可行,而且嵌入其它代码及修改控制都十分方便。
//三级菜单定义extern char menu_stay[3]; //menu_stay[0]: 存放第1级菜单所选菜单项 extern char menu_number[3]; //menu_number[0]: 第1级菜单菜单项总数 extern char menu_grade; //menu_grade:当前所处菜单级//code 常量定义//第1级菜单菜单项数目为3code char list_0x1[] = {0x02,0x03, 0x03}; //第1级菜单菜单项X-〉下级菜单数目 code char list_1x2[] = {0x05, 0x03}; //第1级菜单菜单项1-〉下级菜单数目code char list_2x2[] = {0x02, 0x04, 0x03}; //第1级菜单菜单项2-〉下级菜单数目 code char list_3x2[] = {0x02, 0x04, 0x03}; //第1级菜单菜单项3-〉下级菜单数目 code char list_4x2[] = {0x02, 0x04, 0x03}; //第1级菜单菜单项4-〉下级菜单数目code char Menu_new[] = {"NEW"};code char Menu_open[] = {"OPEN"};code char Menu_save[] = {"SAVE"};处于当前菜单级时需要读取当前选项对应下级菜单菜单项总数,可设定菜单项总数为0 表示下一级已经没有菜单了。
如果编写简单的程序的话这个菜单函数就可以不用看了,但是当你编写到复杂的程序的时候就可能就会为人机界面和各个函数直接的连接而烦恼了,这个菜单函数就是用来解决这个问题,虽然没有UCGUI厉害,但是我觉得代码在2000行一下的话用起来还是不错的选择的.虽说简单但是用到了结构体大部分的知识了,希望c语言不太好的朋友自己补习一下好了.
主要程序:
#define Null 0
/***********************
* 函数声明*
***********************/
void ShowMenu(void);
void Menu_Change(unsigned char KeyNum);
/***********************
* 按键功能键宏定义*
***********************/
#define UP '3'
#define Down '7'
#define Esc 'B'
#define Enter 'F'
#define Reset '0'
/**********************
* 目录结构体定义*
**********************/
struct MenuItem
{
unsigned char MenuCount; //当前层节点数
unsigned char *DisplayString; //菜单标题
void (*Subs)(); //节点函数
struct MenuItem *ChildrenMenus; //子节点
struct MenuItem *ParentMenus; //父节点
};
/***********************
* 调用子函数区*
***********************/
void NullSubs(void)
{
}
//----------------------以下为例子,请根据实际情况修改---------------------------
void TimeSet(void)
{
put_s("TimeSet");
}
void DateSet(void)
{
put_s("DateSet");
}
void AlertSet (void)
{
put_s("AlertSet");
}
//------------------------------------------------------------------------------。