您的位置 首页 IC

第77节:窗口里经过移动光标设置参数的液晶屏菜单程序

开场白:这一节要教会大家两个知识点:第一个知识点:我在前面讲数码管显示的时候就提出了一个一二级菜单显示理论:凡是人机界面显示

开场白:
这一节要教会我们两个知识点:
榜首个知识点:我在前面讲数码管显现的时分就提出了一个 “一二级菜单显现理论”:但凡人机界面显现,不管是数码管仍是液晶屏,都能够把显现的内容分红不同的窗口来显现,每个显现的窗口中又能够分红不同的部分显现。其间窗口便是一级菜单,用ucWd变量表明。部分便是二级菜单,用ucPart来表明。不同的窗口,会有不同的更新显现变量ucWdXUpdate来对应,表明整屏悉数更新显现。不同的部分,也会有不同的更新显现变量ucWdXPartYUpdate来对应,表明部分更新显现。把每一个窗口的内容分为两种类型,一种类型是那些不必常常改写显现的内容,只需在切换窗口的时分才需求更新的,这种内容放在整屏更新显现的括号里,比方清屏操作等内容。别的一种是那些常常需求改写显现的内容,这种内容放在部分更新显现的括号里。
第二个知识点:按键怎么跟液晶屏显现有机的结合起来?只需遵从鸿哥总结出来的一个规则“在不同的窗口下,依据不同的部分变量来操作不同的参数”,这样再杂乱的人机交互程序都会显得很简单明晰。

具体内容,请看源代码解说。

(1)硬件渠道:依据朱兆祺51单片机学习板。加按键对应S1键,减按键对应S5键,切换“光标”移动按键对应S9键,设置参数按键对应S13键。

(2)完成功用:
经过按键设置4个不同的参数。
有1个窗口。每个窗口显现4个参数。每个参数的规模是从0到99。
有4个按键:
(a) 一个是设置参数S13按键,按下此按键,液晶屏的榜首行会呈现反显的光标,表明进入设置参数模式,再次按下此按键,反显光标会消失,表明退出设置参数形式。
(b) 一个是移动光标S9按键,在进入设置参数的形式下,顺次按下此按键,液晶屏上的光标会从上往下移动,表明选中不同的参数。
(c) 一个是减数S5按键,在设置参数形式下,顺次按下此按键,被选中的参数会逐步减小。
(d) 一个是加数S1按键,在设置参数形式下,顺次按下此按键,被选中的参数会逐步加大。

(3)源代码解说如下:

  1. #include “REG52.H”
  2. #define const_voice_short40 //蜂鸣器短叫的持续时刻
  3. #define const_key_time120 //按键去颤动延时的时刻
  4. #define const_key_time220 //按键去颤动延时的时刻
  5. #define const_key_time320 //按键去颤动延时的时刻
  6. #define const_key_time420 //按键去颤动延时的时刻
  7. sbit key_sr1=P0^0; //对应朱兆祺学习板的S1键
  8. sbit key_sr2=P0^1; //对应朱兆祺学习板的S5键
  9. sbit key_sr3=P0^2; //对应朱兆祺学习板的S9键
  10. sbit key_sr4=P0^3; //对应朱兆祺学习板的S13键
  11. sbit key_gnd_dr=P0^4; //模仿独立按键的地GND,因而有必要一向输出低电平
  12. sbit beep_dr=P2^7; //蜂鸣器的驱动IO口
  13. sbitLCDCS_dr= P1^6;//片选线
  14. sbitLCDSID_dr = P1^7;//串行数据线
  15. sbitLCDCLK_dr = P3^2;//串行时钟线
  16. sbitLCDRST_dr = P3^4;//复位线
  17. void SendByteToLcd(unsigned char ucData);//发送一个字节数据到液晶模块
  18. void SPIWrite(unsigned char ucWData, unsigned char ucWRS); //模仿SPI发送一个字节的指令或许数据给液晶模块的底层驱动
  19. void WriteCommand(unsigned char ucCommand); //发送一个字节的指令给液晶模块
  20. void LCDWriteData(unsigned char ucData); //发送一个字节的数据给液晶模块
  21. void LCDInit(void);//初始化函数内部包含液晶模块的复位
  22. void display_clear(unsigned char ucFillDate); // 清屏 悉数显现空填充0x00 悉数显现点阵用0xff
  23. void insert_buffer_to_canvas(unsigned int x,unsigned int y,const unsigned char*ucArray,unsigned char ucFbFlag,unsigned int x_amount,unsigned int y_amount);//把字模刺进画布.
  24. void display_lattice(unsigned int x,unsigned int y,const unsigned char*ucArray,unsigned char ucFbFlag,unsigned int x_amount,unsigned int y_amount,unsigned int uiOffSetAddr); //显现恣意点阵函数
  25. unsigned char *number_to_matrix(unsigned charucBitNumber); //把一位数字转化成字模首地址的函数
  26. void delay_short(unsigned int uiDelayshort); //延时
  27. void delay_long(unsigned int uiDelayLong);
  28. void T0_time(); //守时中止函数
  29. void key_service(void); //按键服务的应用程序
  30. void key_scan(void);//按键扫描函数 放在守时中止里
  31. void initial_myself();
  32. void initial_peripheral();
  33. void lcd_display_service(void); //应用层面的液晶屏显现程序
  34. void clear_all_canvas(void);//把画布悉数清零
  35. code unsigned char Zf816_0[]=
  36. {
  37. /*–文字:0–*/
  38. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  39. 0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x42,0x42,0x42,0x42,0x24,0x18,0x00,0x00,
  40. };
  41. code unsigned char Zf816_1[]=
  42. {
  43. /*–文字:1–*/
  44. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  45. 0x00,0x00,0x00,0x10,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x7C,0x00,0x00,
  46. };
  47. code unsigned char Zf816_2[]=
  48. {
  49. /*–文字:2–*/
  50. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  51. 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x04,0x04,0x08,0x10,0x20,0x42,0x7E,0x00,0x00,
  52. };
  53. code unsigned char Zf816_3[]=
  54. {
  55. /*–文字:3–*/
  56. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  57. 0x00,0x00,0x00,0x3C,0x42,0x42,0x04,0x18,0x04,0x02,0x02,0x42,0x44,0x38,0x00,0x00,
  58. };
  59. code unsigned char Zf816_4[]=
  60. {
  61. /*–文字:4–*/
  62. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  63. 0x00,0x00,0x00,0x04,0x0C,0x14,0x24,0x24,0x44,0x44,0x7E,0x04,0x04,0x1E,0x00,0x00,
  64. };
  65. code unsigned char Zf816_5[]=
  66. {
  67. /*–文字:5–*/
  68. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  69. 0x00,0x00,0x00,0x7E,0x40,0x40,0x40,0x58,0x64,0x02,0x02,0x42,0x44,0x38,0x00,0x00,
  70. };
  71. code unsigned char Zf816_6[]=
  72. {
  73. /*–文字:6–*/
  74. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  75. 0x00,0x00,0x00,0x1C,0x24,0x40,0x40,0x58,0x64,0x42,0x42,0x42,0x24,0x18,0x00,0x00,
  76. };
  77. code unsigned char Zf816_7[]=
  78. {
  79. /*–文字:7–*/
  80. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  81. 0x00,0x00,0x00,0x7E,0x44,0x44,0x08,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x00,0x00,
  82. };
  83. code unsigned char Zf816_8[]=
  84. {
  85. /*–文字:8–*/
  86. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  87. 0x00,0x00,0x00,0x3C,0x42,0x42,0x42,0x24,0x18,0x24,0x42,0x42,0x42,0x3C,0x00,0x00,
  88. };
  89. code unsigned char Zf816_9[]=
  90. {
  91. /*–文字:9–*/
  92. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  93. 0x00,0x00,0x00,0x18,0x24,0x42,0x42,0x42,0x26,0x1A,0x02,0x02,0x24,0x38,0x00,0x00,
  94. };
  95. code unsigned char Zf816_nc[]=//空字模
  96. {
  97. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  98. };
  99. code unsigned char Zf816_mao_hao[]=//冒号
  100. {
  101. /*–文字::–*/
  102. /*–宋体12;此字体下对应的点阵为:宽x高=8×16 –*/
  103. 0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,0x00,0x18,0x18,0x00,0x00,
  104. };
  105. code unsigned char Hz1616_yi[]=
  106. {
  107. /*–文字:一–*/
  108. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  109. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x7F,0xFE,
  110. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  111. };
  112. code unsigned char Hz1616_er[]=
  113. {
  114. /*–文字:二–*/
  115. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  116. 0x00,0x00,0x00,0x10,0x3F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
  117. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,0x7F,0xFE,0x00,0x00,0x00,0x00,0x00,0x00,
  118. };
  119. code unsigned char Hz1616_san[]=
  120. {
  121. /*–文字:三–*/
  122. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  123. 0x00,0x00,0x00,0x00,0x7F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0xF8,
  124. 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x7F,0xFE,0x00,0x00,0x00,0x00,
  125. };
  126. code unsigned char Hz1616_si[]=
  127. {
  128. /*–文字:四–*/
  129. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  130. 0x00,0x00,0x7F,0xFC,0x44,0x84,0x44,0x84,0x44,0x84,0x44,0x84,0x44,0x84,0x44,0x84,
  131. 0x48,0x84,0x48,0x7C,0x50,0x04,0x60,0x04,0x40,0x04,0x7F,0xFC,0x40,0x04,0x00,0x00,
  132. };
  133. code unsigned char Hz1616_chuang[]=
  134. {
  135. /*–文字:窗–*/
  136. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  137. 0x01,0x00,0x00,0x80,0x7F,0xFE,0x40,0x22,0x09,0x18,0x12,0x06,0x7F,0xF8,0x11,0x08,
  138. 0x13,0xE8,0x14,0x48,0x1A,0x88,0x11,0x08,0x12,0x88,0x14,0x08,0x1F,0xF8,0x10,0x08,
  139. };
  140. code unsigned char Hz1616_kou[]=
  141. {
  142. /*–文字:口–*/
  143. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  144. 0x00,0x00,0x00,0x00,0x3F,0xF8,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,0x20,0x08,
  145. 0x20,0x08,0x20,0x08,0x20,0x08,0x3F,0xF8,0x20,0x08,0x20,0x08,0x00,0x00,0x00,0x00,
  146. };
  147. code unsigned char Hz1616_hang[]=
  148. {
  149. /*–文字:行–*/
  150. /*–宋体12;此字体下对应的点阵为:宽x高=16×16 –*/
  151. 0x08,0x00,0x1C,0x00,0x31,0xFC,0x40,0x00,0x88,0x00,0x0C,0x00,0x1B,0xFE,0x30,0x20,
  152. 0x50,0x20,0x90,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0x20,0x10,0xA0,0x10,0x40,
  153. };
  154. unsigned char ucCanvasBuffer[]= //画布显现数组。留意,这儿没有code关键字,是全局变量。初始化悉数填充0x00
  155. {
  156. 0x00,0x00,0x00,0x00,//上半屏
  157. 0x00,0x00,0x00,0x00,
  158. 0x00,0x00,0x00,0x00,
  159. 0x00,0x00,0x00,0x00,
  160. 0x00,0x00,0x00,0x00,
  161. 0x00,0x00,0x00,0x00,
  162. 0x00,0x00,0x00,0x00,
  163. 0x00,0x00,0x00,0x00,
  164. //————上半屏和下半屏的分割线———–
  165. 0x00,0x00,0x00,0x00,//下半屏
  166. 0x00,0x00,0x00,0x00,
  167. 0x00,0x00,0x00,0x00,
  168. 0x00,0x00,0x00,0x00,
  169. 0x00,0x00,0x00,0x00,
  170. 0x00,0x00,0x00,0x00,
  171. 0x00,0x00,0x00,0x00,
  172. 0x00,0x00,0x00,0x00,
  173. };
  174. unsigned char ucKeySec=0; //被触发的按键编号
  175. unsigned intuiVoiceCnt=0;//蜂鸣器鸣叫的持续时刻计数器
  176. unsigned char ucWd=1; //窗口变量
  177. unsigned char ucPart=0; //部分变量 0代表没有选中任何一行,其它数值1到4代表选中某一行
  178. unsigned char ucWd1Update=1; //窗口1的整屏更新显现变量 1代表更新显现,呼应函数内部会清零
  179. unsigned char ucWd1Part1Update=0; //窗口1的第1行部分更新显现变量1代表更新显现,呼应函数内部会清零
  180. unsigned char ucWd1Part2Update=0; //窗口1的第2行部分更新显现变量1代表更新显现,呼应函数内部会清零
  181. unsigned char ucWd1Part3Update=0; //窗口1的第3行部分更新显现变量1代表更新显现,呼应函数内部会清零
  182. unsigned char ucWd1Part4Update=0; //窗口1的第4行部分更新显现变量1代表更新显现,呼应函数内部会清零
  183. unsigned char ucData_1_1=8;//第1个窗口第1行的被设置数据
  184. unsigned char ucData_1_2=9;//第1个窗口第2行的被设置数据
  185. unsigned char ucData_1_3=10;//第1个窗口第3行的被设置数据
  186. unsigned char ucData_1_4=11;//第1个窗口第4行的被设置数据
  187. void main()
  188. {
  189. initial_myself(); //榜首区,上电后立刻初始化
  190. delay_long(100); //一线,延时线。延时一段时刻
  191. initial_peripheral();//第二区,上电后延时一段时刻再初始化
  192. while(1) //第三区
  193. {
  194. key_service(); //按键服务的应用程序
  195. lcd_display_service(); //应用层面的液晶屏显现程序
  196. }
  197. }
  198. void initial_myself()//榜首区 上电后立刻初始化
  199. {
  200. /* 注释一:
  201. * 矩阵键盘也能够做独立按键,条件是把某一根公共输出线输出低电平,
  202. * 模仿独立按键的触发地,本程序中,把key_gnd_dr输出低电平。
  203. * 朱兆祺51学习板的S1和S5两个按键便是本程序中用到的两个独立按键。
  204. */
  205. key_gnd_dr=0; //模仿独立按键的地GND,因而有必要一向输出低电平
  206. beep_dr=1; //用PNP三极管操控蜂鸣器,输出高电平时不叫。
  207. TMOD=0x01;//设置守时器0为工作方式1
  208. TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
  209. TL0=0x2f;
  210. }
  211. void initial_peripheral() //第二区 上电后延时一段时刻再初始化
  212. {
  213. LCDInit(); //初始化12864 内部包含液晶模块的复位
  214. EA=1; //开总中止
  215. ET0=1; //答应守时中止
  216. TR0=1; //发动守时中止
  217. }
  218. void T0_time() interrupt 1
  219. {
  220. TF0=0;//铲除中止标志
  221. TR0=0; //关中止
  222. key_scan(); //按键扫描函数
  223. if(uiVoiceCnt!=0)
  224. {
  225. uiVoiceCnt–; //每次进入守时中止都自减1,直到等于零中止。才中止鸣叫
  226. beep_dr=0;//蜂鸣器是PNP三极管操控,低电平就开端鸣叫。
  227. }
  228. else
  229. {
  230. ; //此处多加一个空指令,想保持跟if括号句子的数量对称,都是两条指令。不加也能够。
  231. beep_dr=1;//蜂鸣器是PNP三极管操控,高电平就中止鸣叫。
  232. }
  233. TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f
  234. TL0=0x2f;
  235. TR0=1;//开中止
  236. }
  237. void key_scan(void)//按键扫描函数 放在守时中止里
  238. {
  239. static unsigned intuiKeyTimeCnt1=0; //按键去颤动延时计数器
  240. static unsigned char ucKeyLock1=0; //按键触发后自锁的变量标志
  241. static unsigned intuiKeyTimeCnt2=0; //按键去颤动延时计数器
  242. static unsigned char ucKeyLock2=0; //按键触发后自锁的变量标志
  243. static unsigned intuiKeyTimeCnt3=0; //按键去颤动延时计数器
  244. static unsigned char ucKeyLock3=0; //按键触发后自锁的变量标志
  245. static unsigned intuiKeyTimeCnt4=0; //按键去颤动延时计数器
  246. static unsigned char ucKeyLock4=0; //按键触发后自锁的变量标志
  247. if(key_sr1==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  248. {
  249. ucKeyLock1=0; //按键自锁标志清零
  250. uiKeyTimeCnt1=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  251. }
  252. else if(ucKeyLock1==0)//有按键按下,且是榜首次被按下
  253. {
  254. uiKeyTimeCnt1++; //累加守时中止次数
  255. if(uiKeyTimeCnt1>const_key_time1)
  256. {
  257. uiKeyTimeCnt1=0;
  258. ucKeyLock1=1;//自锁按键置位,防止一向触发
  259. ucKeySec=1; //触发1号键
  260. }
  261. }
  262. if(key_sr2==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  263. {
  264. ucKeyLock2=0; //按键自锁标志清零
  265. uiKeyTimeCnt2=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  266. }
  267. else if(ucKeyLock2==0)//有按键按下,且是榜首次被按下
  268. {
  269. uiKeyTimeCnt2++; //累加守时中止次数
  270. if(uiKeyTimeCnt2>const_key_time2)
  271. {
  272. uiKeyTimeCnt2=0;
  273. ucKeyLock2=1;//自锁按键置位,防止一向触发
  274. ucKeySec=2; //触发2号键
  275. }
  276. }
  277. if(key_sr3==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  278. {
  279. ucKeyLock3=0; //按键自锁标志清零
  280. uiKeyTimeCnt3=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  281. }
  282. else if(ucKeyLock3==0)//有按键按下,且是榜首次被按下
  283. {
  284. uiKeyTimeCnt3++; //累加守时中止次数
  285. if(uiKeyTimeCnt3>const_key_time3)
  286. {
  287. uiKeyTimeCnt3=0;
  288. ucKeyLock3=1;//自锁按键置位,防止一向触发
  289. ucKeySec=3; //触发3号键
  290. }
  291. }
  292. if(key_sr4==1)//IO是高电平,阐明按键没有被按下,这时要及时清零一些标志位
  293. {
  294. ucKeyLock4=0; //按键自锁标志清零
  295. uiKeyTimeCnt4=0;//按键去颤动延时计数器清零,此行十分奇妙,是我实战中探索出来的。
  296. }
  297. else if(ucKeyLock4==0)//有按键按下,且是榜首次被按下
  298. {
  299. uiKeyTimeCnt4++; //累加守时中止次数
  300. if(uiKeyTimeCnt4>const_key_time4)
  301. {
  302. uiKeyTimeCnt4=0;
  303. ucKeyLock4=1;//自锁按键置位,防止一向触发
  304. ucKeySec=4; //触发4号键
  305. }
  306. }
  307. }
  308. void key_service(void) //按键服务的应用程序
  309. {
  310. switch(ucKeySec) //按键服务状况切换
  311. {
  312. case 1:// 加按键 对应朱兆祺学习板的S1键
  313. switch(ucWd)//在不同的窗口下,设置不同的参数
  314. {
  315. case 1:
  316. switch(ucPart)//在窗口1下,依据不同的部分变量来设置不同的参数
  317. {
  318. case 0: //无光标显现的状况 此处的case 0能够省掉
  319. break;
  320. case 1: //设置第1行参数
  321. ucData_1_1++;
  322. if(ucData_1_1>99)
  323. {
  324. ucData_1_1=99;
  325. }
  326. ucWd1Part1Update=1; //1代表更新显现,呼应函数内部会清零
  327. break;
  328. case 2: //设置第2行参数
  329. ucData_1_2++;
  330. if(ucData_1_2>99)
  331. {
  332. ucData_1_2=99;
  333. }
  334. ucWd1Part2Update=1; //1代表更新显现,呼应函数内部会清零
  335. break;
  336. case 3: //设置第3行参数
  337. ucData_1_3++;
  338. if(ucData_1_3>99)
  339. {
  340. ucData_1_3=99;
  341. }
  342. ucWd1Part3Update=1; //1代表更新显现,呼应函数内部会清零
  343. break;
  344. case 4: //设置第4行参数
  345. ucData_1_4++;
  346. if(ucData_1_4>99)
  347. {
  348. ucData_1_4=99;
  349. }
  350. ucWd1Part4Update=1; //1代表更新显现,呼应函数内部会清零
  351. break;
  352. }
  353. break;
  354. }
  355. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  356. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  357. break;
  358. case 2:// 减按键 对应朱兆祺学习板的S5键
  359. switch(ucWd)//在不同的窗口下,设置不同的参数
  360. {
  361. case 1:
  362. switch(ucPart)//在窗口1下,依据不同的部分变量来设置不同的参数
  363. {
  364. case 0: //无光标显现的状况 此处的case 0能够省掉
  365. break;
  366. case 1: //设置第1行参数
  367. ucData_1_1–;
  368. if(ucData_1_1>99) //一向减到最终,单片机C言语编译器有一个特征,0减去1会溢出变成255(0xff)
  369. {
  370. ucData_1_1=0;
  371. }
  372. ucWd1Part1Update=1; //1代表更新显现,呼应函数内部会清零
  373. break;
  374. case 2: //设置第2行参数
  375. ucData_1_2–;
  376. if(ucData_1_2>99) //一向减到最终,单片机C言语编译器有一个特征,0减去1会溢出变成255(0xff)
  377. {
  378. ucData_1_2=0;
  379. }
  380. ucWd1Part2Update=1; //1代表更新显现,呼应函数内部会清零
  381. break;
  382. case 3: //设置第3行参数
  383. ucData_1_3–;
  384. if(ucData_1_3>99) //一向减到最终,单片机C言语编译器有一个特征,0减去1会溢出变成255(0xff)
  385. {
  386. ucData_1_3=0;
  387. }
  388. ucWd1Part3Update=1; //1代表更新显现,呼应函数内部会清零
  389. break;
  390. case 4: //设置第4行参数
  391. ucData_1_4–;
  392. if(ucData_1_4>99) //一向减到最终,单片机C言语编译器有一个特征,0减去1会溢出变成255(0xff)
  393. {
  394. ucData_1_4=0;
  395. }
  396. ucWd1Part4Update=1; //1代表更新显现,呼应函数内部会清零
  397. break;
  398. }
  399. break;
  400. }
  401. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  402. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  403. break;
  404. case 3:// 切换”光标”移动按键 对应朱兆祺学习板的S9键
  405. switch(ucWd)//在不同的窗口下,设置不同的参数
  406. {
  407. case 1:
  408. switch(ucPart)//在窗口1下,依据不同的部分变量来设置不同的参数
  409. {
  410. case 0: //无光标显现的状况 此处的case 0能够省掉
  411. break;
  412. case 1: //设置第1行参数
  413. ucPart=2; //光标切换到下一行
  414. ucWd1Part1Update=1; //更新显现本来那一行,意图是更新反显光标的状况
  415. ucWd1Part2Update=1; //更新显现下一行, 意图是更新反显光标的状况
  416. break;
  417. case 2: //设置第2行参数
  418. ucPart=3; //光标切换到下一行
  419. ucWd1Part2Update=1; //更新显现本来那一行,意图是更新反显光标的状况
  420. ucWd1Part3Update=1; //更新显现下一行, 意图是更新反显光标的状况
  421. break;
  422. case 3: //设置第3行参数
  423. ucPart=4; //光标切换到下一行
  424. ucWd1Part3Update=1; //更新显现本来那一行,意图是更新反显光标的状况
  425. ucWd1Part4Update=1; //更新显现下一行, 意图是更新反显光标的状况
  426. break;
  427. case 4: //设置第4行参数
  428. ucPart=1; //光标回来到最上面榜首行
  429. ucWd1Part4Update=1; //更新显现本来那一行,意图是更新反显光标的状况
  430. ucWd1Part1Update=1; //更新显现最上面榜首行, 意图是更新反显光标的状况
  431. break;
  432. }
  433. break;
  434. }
  435. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  436. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  437. break;
  438. case 4: // 设置按键对应朱兆祺学习板的S13键,按一次进入设置状况,呈现反显光标。再按一次推出设置状况,消除反显光标
  439. switch(ucWd)//在不同的窗口下,设置不同的参数
  440. {
  441. case 1:
  442. switch(ucPart)//在窗口1下,依据不同的部分变量来设置不同的参数
  443. {
  444. case 0: //无光标显现的状况
  445. ucPart=1; //光标显现榜首行,进入设置形式
  446. ucWd1Part1Update=1; //更新显现
  447. break;
  448. case 1: //设置第1行参数
  449. ucPart=0; //无光标显现,退出设置形式
  450. ucWd1Part1Update=1; //更新显现
  451. break;
  452. case 2: //设置第2行参数
  453. ucPart=0; //无光标显现,退出设置形式
  454. ucWd1Part2Update=1; //更新显现
  455. break;
  456. case 3: //设置第3行参数
  457. ucPart=0; //无光标显现,退出设置形式
  458. ucWd1Part3Update=1; //更新显现
  459. break;
  460. case 4: //设置第4行参数
  461. ucPart=0; //无光标显现,退出设置形式
  462. ucWd1Part4Update=1; //更新显现
  463. break;
  464. }
  465. break;
  466. }
  467. uiVoiceCnt=const_voice_short; //按键声响触发,滴一声就停。
  468. ucKeySec=0;//呼应按键服务处理程序后,按键编号清零,防止共同触发
  469. break;
  470. }
  471. }
  472. unsigned char *number_to_matrix(unsigned charucBitNumber)
  473. {
  474. unsigned char *p_ucAnyNumber;//此指针依据ucBitNumber数值的巨细,别离调用不同的字库。
  475. switch(ucBitNumber)//依据ucBitNumber数值的巨细,别离调用不同的字库。
  476. {
  477. case 0:
  478. p_ucAnyNumber=Zf816_0;
  479. break;
  480. case 1:
  481. p_ucAnyNumber=Zf816_1;
  482. break;
  483. case 2:
  484. p_ucAnyNumber=Zf816_2;
  485. break;
  486. case 3:
  487. p_ucAnyNumber=Zf816_3;
  488. break;
  489. case 4:
  490. p_ucAnyNumber=Zf816_4;
  491. break;
  492. case 5:
  493. p_ucAnyNumber=Zf816_5;
  494. break;
  495. case 6:
  496. p_ucAnyNumber=Zf816_6;
  497. break;
  498. case 7:
  499. p_ucAnyNumber=Zf816_7;
  500. break;
  501. case 8:
  502. p_ucAnyNumber=Zf816_8;
  503. break;
  504. case 9:
  505. p_ucAnyNumber=Zf816_9;
  506. break;
  507. case 10:
  508. p_ucAnyNumber=Zf816_nc;
  509. break;
  510. default: //假如上面的条件都不契合,那么默许指向空字模
  511. p_ucAnyNumber=Zf816_nc;
  512. break;
  513. }
  514. return p_ucAnyNumber;//回来转化完毕后的指针
  515. }
  516. void lcd_display_service(void) //应用层面的液晶屏显现程序
  517. {
  518. unsigned char ucAnyNumber_1; //分化变量的个位
  519. unsigned char ucAnyNumber_10; //分化变量的十位
  520. unsigned char *p_ucAnyNumber_1; //经过数字转化成字模后,分化变量的个位字模首地址
  521. unsigned char *p_ucAnyNumber_10; //经过数字转化成字模后,分化变量的十位字模首地址
  522. unsigned char ucCursorFlag;//光标标志,也便是反显的标志,它是依据部分变量ucPart来定的
  523. switch(ucWd)//本程序的中心变量,窗口显现变量。类似于一级菜单的变量。代表显现不同的窗口。
  524. {
  525. case 1: //显现窗口1的数据
  526. /* 注释二:
  527. * 把每一个窗口的内容分为两种类型,一种类型是那些不必常常改写显现的内容,只需在切换窗口的时分
  528. * 才需求更新,这种内容放在整屏更新显现的括号里,比方清屏操作等内容。别的一种是那些常常需求
  529. * 改写显现的内容,这种内容放在部分更新显现的括号里。
  530. */
  531. if(ucWd1Update==1)//窗口1整屏更新,里边只放那些不必常常改写显现的内容
  532. {
  533. ucWd1Update=0;//及时清零,防止一向更新
  534. ucWd1Part1Update=1; //激活窗口1的第1行部分更新显现变量,这儿在前面数码管显现结构上有所改进
  535. ucWd1Part2Update=1; //激活窗口1的第2行部分更新显现变量,这儿在前面数码管显现结构上有所改进
  536. ucWd1Part3Update=1; //激活窗口1的第3行部分更新显现变量,这儿在前面数码管显现结构上有所改进
  537. ucWd1Part4Update=1; //激活窗口1的第4行部分更新显现变量,这儿在前面数码管显现结构上有所改进
  538. display_clear(0x00); // 清屏操作, 悉数显现空填充0x00,悉数显现点阵用0xff。
  539. clear_all_canvas();//把画布悉数清零
  540. insert_buffer_to_canvas(0,0,Zf816_mao_hao,0,1,16);//把冒号的字模刺进画布
  541. display_lattice(0,0,Hz1616_yi,0,2,16,0); //一窗口一行,这些内容不必常常更新,只需在切换窗口的时分才更新显现
  542. display_lattice(1,0,Hz1616_chuang,0,2,16,0);
  543. display_lattice(2,0,Hz1616_kou,0,2,16,0);
  544. display_lattice(3,0,Hz1616_yi,0,2,16,0);
  545. display_lattice(4,0,Hz1616_hang,0,2,16,0);
  546. display_lattice(0,16,Hz1616_yi,0,2,16,0); //一窗口二行
  547. display_lattice(1,16,Hz1616_chuang,0,2,16,0);
  548. display_lattice(2,16,Hz1616_kou,0,2,16,0);
  549. display_lattice(3,16,Hz1616_er,0,2,16,0);
  550. display_lattice(4,16,Hz1616_hang,0,2,16,0);
  551. display_lattice(8,0,Hz1616_yi,0,2,16,0); //一窗口三行
  552. display_lattice(9,0,Hz1616_chuang,0,2,16,0);
  553. display_lattice(10,0,Hz1616_kou,0,2,16,0);
  554. display_lattice(11,0,Hz1616_san,0,2,16,0);
  555. display_lattice(12,0,Hz1616_hang,0,2,16,0);
  556. display_lattice(8,16,Hz1616_yi,0,2,16,0); //一窗口四行
  557. display_lattice(9,16,Hz1616_chuang,0,2,16,0);
  558. display_lattice(10,16,Hz1616_kou,0,2,16,0);
  559. display_lattice(11,16,Hz1616_si,0,2,16,0);
  560. display_lattice(12,16,Hz1616_hang,0,2,16,0);
  561. }
  562. /* 注释三:
  563. * 留意!我前面讲数码管显现的时分有一句话讲错了,我那时说<部分更新应该写在整屏更新之前>,这是不对的。
  564. * 依照现在的显现程序结构<即整屏显现更新括号里包含了一切部分变量的激活>,应该是<整屏更新应该写在部分更新之前>
  565. * 这样才对。
  566. */
  567. if(ucWd1Part1Update==1) //窗口1的第1行部分更新显现变量,里边放一些常常需求改写显现的内容
  568. {
  569. ucWd1Part1Update=0; //及时清零,防止一向更新
  570. if(ucPart==1) //被选中
  571. {
  572. ucCursorFlag=1; //反显 显现
  573. }
  574. else //没被选中
  575. {
  576. ucCursorFlag=0; //正常 显现
  577. }
  578. if(ucData_1_1>=10) //有2位数以上
  579. {
  580. ucAnyNumber_10=ucData_1_1/10;//十位
  581. }
  582. else //不然显现空
  583. {
  584. ucAnyNumber_10=10;//鄙人面的转化函数中,代码10表明空字模
  585. }
  586. ucAnyNumber_1=ucData_1_1%10/1;//个位
  587. p_ucAnyNumber_10=number_to_matrix(ucAnyNumber_10); //把数字转化成字模首地址
  588. p_ucAnyNumber_1=number_to_matrix(ucAnyNumber_1); //把数字转化成字模首地址
  589. insert_buffer_to_canvas(2,0,p_ucAnyNumber_10,ucCursorFlag,1,16);//把十的字模刺进画布
  590. insert_buffer_to_canvas(3,0,p_ucAnyNumber_1,ucCursorFlag,1,16);//把个的字模刺进画布
  591. display_lattice(5,0,ucCanvasBuffer,0,4,16,0); //显现整屏的画布,最终的参数0是偏移量
  592. }
  593. if(ucWd1Part2Update==1) //窗口1的第2行部分更新显现变量,里边放一些常常需求改写显现的内容
  594. {
  595. ucWd1Part2Update=0; //及时清零,防止一向更新
  596. if(ucPart==2) //被选中
  597. {
  598. ucCursorFlag=1; //反显 显现
  599. }
  600. else //没被选中
  601. {
  602. ucCursorFlag=0; //正常 显现
  603. }
  604. if(ucData_1_2>=10) //有2位数以上
  605. {
  606. ucAnyNumber_10=ucData_1_2/10;//十位
  607. }
  608. else //不然显现空
  609. {
  610. ucAnyNumber_10=10;//鄙人面的转化函数中,代码10表明空字模
  611. }
  612. ucAnyNumber_1=ucData_1_2%10/1;//个位
  613. p_ucAnyNumber_10=number_to_matrix(ucAnyNumber_10); //把数字转化成字模首地址
  614. p_ucAnyNumber_1=number_to_matrix(ucAnyNumber_1); //把数字转化成字模首地址
  615. insert_buffer_to_canvas(2,0,p_ucAnyNumber_10,ucCursorFlag,1,16);//把十的字模刺进画布
  616. insert_buffer_to_canvas(3,0,p_ucAnyNumber_1,ucCursorFlag,1,16);//把个的字模刺进画布
  617. display_lattice(5,16,ucCanvasBuffer,0,4,16,0); //显现整屏的画布,最终的参数0是偏移量
  618. }
  619. if(ucWd1Part3Update==1) //窗口1的第3行部分更新显现变量,里边放一些常常需求改写显现的内容
  620. {
  621. ucWd1Part3Update=0; //及时清零,防止一向更新
  622. if(ucPart==3) //被选中
  623. {
  624. ucCursorFlag=1; //反显 显现
  625. }
  626. else //没被选中
  627. {
  628. ucCursorFlag=0; //正常 显现
  629. }
  630. if(ucData_1_3>=10) //有2位数以上
  631. {
  632. ucAnyNumber_10=ucData_1_3/10;//十位
  633. }
  634. else //不然显现空
  635. {
  636. ucAnyNumber_10=10;//鄙人面的转化函数中,代码10表明空字模
  637. }
  638. ucAnyNumber_1=ucData_1_3%10/1;//个位
  639. p_ucAnyNumber_10=number_to_matrix(ucAnyNumber_10); //把数字转化成字模首地址
  640. p_ucAnyNumber_1=number_to_matrix(ucAnyNumber_1); //把数字转化成字模首地址
  641. insert_buffer_to_canvas(2,0,p_ucAnyNumber_10,ucCursorFlag,1,16);//把十的字模刺进画布
  642. insert_buffer_to_canvas(3,0,p_ucAnyNumber_1,ucCursorFlag,1,16);//把个的字模刺进画布
  643. display_lattice(13,0,ucCanvasBuffer,0,4,16,0); //显现整屏的画布,最终的参数0是偏移量
  644. }
  645. if(ucWd1Part4Update==1) //窗口1的第4行部分更新显现变量,里边放一些常常需求改写显现的内容
  646. {
  647. ucWd1Part4Update=0; //及时清零,防止一向更新
  648. if(ucPart==4) //被选中
  649. {
  650. ucCursorFlag=1; //反显 显现
  651. }
  652. else //没被选中
  653. {
  654. ucCursorFlag=0; //正常 显现
  655. }
  656. if(ucData_1_4>=10) //有2位数以上
  657. {
  658. ucAnyNumber_10=ucData_1_4/10;//十位
  659. }
  660. else //不然显现空
  661. {
  662. ucAnyNumber_10=10;//鄙人面的转化函数中,代码10表明空字模
  663. }
  664. ucAnyNumber_1=ucData_1_4%10/1;//个位
  665. p_ucAnyNumber_10=number_to_matrix(ucAnyNumber_10); //把数字转化成字模首地址
  666. p_ucAnyNumber_1=number_to_matrix(ucAnyNumber_1); //把数字转化成字模首地址
  667. insert_buffer_to_canvas(2,0,p_ucAnyNumber_10,ucCursorFlag,1,16);//把十的字模刺进画布
  668. insert_buffer_to_canvas(3,0,p_ucAnyNumber_1,ucCursorFlag,1,16);//把个的字模刺进画布
  669. display_lattice(13,16,ucCanvasBuffer,0,4,16,0); //显现整屏的画布,最终的参数0是偏移量
  670. }
  671. break;
  672. //本程序只需1个窗口,所以只需一个case 1,假如要添加窗口,就直接添加 case 2, case 3…
  673. }
  674. }
  675. void clear_all_canvas(void)//把画布悉数清零
  676. {
  677. unsigned int j=0;
  678. unsigned int i=0;
  679. for(j=0;j<16;j++)//这儿的16表明画布有16行
  680. {
  681. for(i=0;i<4;i++) //这儿的4表明画布每行有4个字节
  682. {
  683. ucCanvasBuffer[j*4+i]=0x00;
  684. }
  685. }
  686. }
  687. void display_clear(unsigned char ucFillDate) // 清屏悉数显现空填充0x00 悉数显现点阵用0xff
  688. {
  689. unsigned char x,y;
  690. WriteCommand(0x34);//关显现缓冲指令
  691. WriteCommand(0x34);//关显现缓冲指令成心写2次,怕1次关不了 这个是由于我参考到某厂家的驱动程序也是这样写的
  692. y=0;
  693. while(y<32)//y轴的规模0至31
  694. {
  695. WriteCommand(y+0x80); //笔直地址
  696. WriteCommand(0x80); //水平地址
  697. for(x=0;x<32;x++)//256个横向点,有32个字节
  698. {
  699. LCDWriteData(ucFillDate);
  700. }
  701. y++;
  702. }
  703. WriteCommand(0x36); //开显现缓冲指令
  704. }
  705. /* 注释四:
  706. * 把字模刺进画布的函数.
  707. * 这是本节的中心函数,读者尤其要搞懂x_amount和y_amount对应的显现联系。
  708. * 第1,2个参数x,y是在画布中的坐标系统。
  709. * x的规模是0至3,由于画布的横向只需4个字节。y的规模是0至15,由于画布的纵向只需16行。
  710. * 第3个参数*ucArray是字模的数组。
  711. * 第4个参数ucFbFlag是反白显现标志。0代表正常显现,1代表反白显现。
  712. * 第5,6个参数x_amount,y_amount别离代表字模数组的横向有多少个字节,纵向有几横。
  713. */
  714. void insert_buffer_to_canvas(unsigned int x,unsigned int y,const unsigned char*ucArray,unsigned char ucFbFlag,unsigned int x_amount,unsigned int y_amount)
  715. {
  716. unsigned int j=0;
  717. unsigned int i=0;
  718. unsigned char ucTemp;
  719. for(j=0;j
  720. {
  721. for(i=0;i
  722. {
  723. ucTemp=ucArray[j*x_amount+i];
  724. if(ucFbFlag==0)
  725. {
  726. ucCanvasBuffer[(y+j)*4+x+i]=ucTemp; //这儿的4代表画布每一行只需4个字节
  727. }
  728. else
  729. {
  730. ucCanvasBuffer[(y+j)*4+x+i]=~ucTemp; //这儿的4代表画布每一行只需4个字节
  731. }
  732. }
  733. }
  734. }
  735. /* 注释五:
  736. * 显现恣意点阵函数.
  737. * 留意,本函数在前几节的基础上多添加了第7个参数uiOffSetAddr,它是偏移地址。
  738. * 关于这个函数,读者尤其要搞懂x_amount和y_amount对应的显现联系。
  739. * 第1,2个参数x,y是坐标系统。x的规模是0至15,y的规模是0至31.
  740. * 第3个参数*ucArray是字模的数组。
  741. * 第4个参数ucFbFlag是反白显现标志。0代表正常显现,1代表反白显现。
  742. * 第5,6个参数x_amount,y_amount别离代表字模数组的横向有多少个字节,纵向有几横。
  743. * 第7个参数uiOffSetAddr是偏移地址,代表字模数组的从第几个数据开端显现。
  744. */
  745. void display_lattice(unsigned int x,unsigned int y,const unsigned char*ucArray,unsigned char ucFbFlag,unsigned int x_amount,unsigned int y_amount,unsigned int uiOffSetAddr)
  746. {
  747. unsigned int j=0;
  748. unsigned int i=0;
  749. unsigned char ucTemp;
  750. //留意,要把以下两行指令屏蔽,不然屏幕在更新显现时会整屏闪烁
  751. //WriteCommand(0x34);//关显现缓冲指令
  752. //WriteCommand(0x34);//关显现缓冲指令成心写2次,怕1次关不了 这个是由于我参考到某厂家的驱动程序也是这样写的
  753. for(j=0;j
  754. {
  755. WriteCommand(y+j+0x80); //笔直地址
  756. WriteCommand(x+0x80); //水平地址
  757. for(i=0;i
  758. {
  759. ucTemp=ucArray[j*x_amount+i+uiOffSetAddr]; //uiOffSetAddr是字模数组的偏移地址
  760. if(ucFbFlag==1)//反白显现
  761. {
  762. ucTemp=~ucTemp;
  763. }
  764. LCDWriteData(ucTemp);
  765. // delay_short(30000);//把上一节这个延时函数去掉,加速刷屏速度
  766. }
  767. }
  768. WriteCommand(0x36); //开显现缓冲指令
  769. }
  770. void SendByteToLcd(unsigned char ucData)//发送一个字节数据到液晶模块
  771. {
  772. unsigned char i;
  773. for ( i = 0; i < 8; i++ )
  774. {
  775. if ( (ucData << i) & 0x80 )
  776. {
  777. LCDSID_dr = 1;
  778. }
  779. else
  780. {
  781. LCDSID_dr = 0;
  782. }
  783. LCDCLK_dr = 0;
  784. LCDCLK_dr = 1;
  785. }
  786. }
  787. void SPIWrite(unsigned char ucWData, unsigned char ucWRS) //模仿SPI发送一个字节的指令或许数据给液晶模块的底层驱动
  788. {
  789. SendByteToLcd( 0xf8 + (ucWRS << 1) );
  790. SendByteToLcd( ucWData & 0xf0 );
  791. SendByteToLcd( (ucWData << 4) & 0xf0);
  792. }
  793. void WriteCommand(unsigned char ucCommand) //发送一个字节的指令给液晶模块
  794. {
  795. LCDCS_dr = 0;
  796. LCDCS_dr = 1;
  797. SPIWrite(ucCommand, 0);
  798. delay_short(90);
  799. }
  800. void LCDWriteData(unsigned char ucData)//发送一个字节的数据给液晶模块
  801. {
  802. LCDCS_dr = 0;
  803. LCDCS_dr = 1;
  804. SPIWrite(ucData, 1);
  805. }
  806. void LCDInit(void) //初始化函数内部包含液晶模块的复位
  807. {
  808. LCDRST_dr = 1;//复位
  809. LCDRST_dr = 0;
  810. LCDRST_dr = 1;
  811. }
  812. void delay_short(unsigned int uiDelayShort) //延时函数
  813. {
  814. unsigned int i;
  815. for(i=0;i
  816. {
  817. ;
  818. }
  819. }
  820. void delay_long(unsigned int uiDelayLong)
  821. {
  822. unsigned int i;
  823. unsigned int j;
  824. for(i=0;i
  825. {
  826. for(j=0;j<500;j++)//内嵌循环的空指令数量
  827. {
  828. ; //一个分号相当于履行一条空句子
  829. }
  830. }
  831. }

总结陈词:
这一节讲了在一个窗口里设置不同的参数,假如有几个窗口的情况下,该怎么编程?欲知概况,请听下回分化—–在多个窗口里经过移动光标来设置不同参数的液晶屏菜单程序

声明:本文内容来自网络转载或用户投稿,文章版权归原作者和原出处所有。文中观点,不代表本站立场。若有侵权请联系本站删除(kf@86ic.com)https://www.86ic.net/bandaoti/262027.html

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

返回顶部