您的位置 首页 传感器

第83节:矩阵键盘输入恣意数字或小数点的液晶屏显现程序

开场白:本来这节打算讲调用液晶屏内部字库时让某行内容反显的,但是在昨天调试过程中,发现一个很奇怪的问题,当调用内部字库时,按照数据

开场白:

原本这节计划讲调用液晶屏内部字库时让某行内容反显的,可是在昨日调试过程中,发现一个很古怪的问题,当调用内部字库时,依照数据手册,我履行一条反显指令时,应该是只是某一行反显,可是却一起呈现两行反显。比方,当我履行
WriteCommand(0x34); //扩大指令集
WriteCommand(0x04); //第1行反显
指令时,发现榜首行和第三行反显,后来想想,我猜想这种12864的屏应该是25632折成左右半屏,左半屏在上面,右半屏在下面。通过这次经历,我觉得咱们今后尽量不要用液晶屏的内部字库形式,应该用自构字库的形式(图形形式)。由于我觉得用内部字库形式的时分,这个集成的反显扩展指令不好用。而用自构字库的形式(图形形式),却能够顺心所欲的灵活运用,适合做菜单程序。
已然发现内部字库不好用,所以不再讲内部字库形式,这节只是接着前面第79节内容,持续讲在自构字库的形式(图形形式)下,怎么通过矩阵键盘直接输入数字和小数点,就像一般的计算器相同键盘输入。这个功用外表简略,其实有以下四个当地值得留意:
榜首:怎么用数组接纳按键输入的BCD码数据。
第二:怎么约束输入参数的小数点个数和数组的有用个数。
第三:假如第0个方位是0,那么持续输入的数据直接掩盖0,不然就移位再输入。
第四:假如第0个方位是0,那么持续输入的小数点要移位输入。
要细心了解以上说到的要害点,有必要好好研讨本程序中的void set_data(…)函数。一起也要温习一下之前讲的自构字库形式的液晶屏显现内容,尤其是刺进画布显现的内容。
详细内容,请看源代码解说。
(1) 硬件渠道:
依据朱兆祺51单片机学习板。数字1键对应S1键,数字2键对应S2键,数字3键对应S3键…. 数字9键对应S9键, 数字0键对应S10键。小数键对应S11,清零键对应S16,其它按键不必。
(2) 完成功用:
用矩阵键盘输入恣意数字或小数点。小数点不能超越2位,一旦超越2位,再按其它按键则输入无效。有用数字也不能超越6位(包含小数点),一旦超越6位,再按其它按键则输入无效。
想从头输入,有必要按S16清零按键才干从头输入。

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

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

为您推荐

联系我们

联系我们

在线咨询: QQ交谈

邮箱: kf@86ic.com

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

微信扫一扫关注我们

返回顶部