• 山东大学单片机原理与应用实验 3.7LCD 1602显示实验


    目录

    一、实验题目

    二、实验要求

    三、实验过程及结果分析

    四、实验流程图

    五、实验源代码


    一、实验题目

    3.7 LCD 1602显示实验

    二、实验要求

    1、画出实验的流程图

    2、编写源程序并进行注释

    3、记录实验过程

    4、记录程序运行结果截图

    三、实验过程及结果分析

    要求利用LCD1602和16个按键实现简单的十进制数的加减乘除四则运算。其中按键KEY0-KEY9代表数字0-9,按键KEY10-KEY13分别代表运算符+、-、*、/,按键KEY15代表=,按键KEY14代表清除命令。不管什么时候按下清除按键,计算过程均将停止,两个输入变量清零,屏幕将清屏。

    LCD1602第一行用于显示所输入的两个计算数以及计算符,第二行用于显示计算结果,结果允许为附属,但输入的两个输入数都必须是双字节正整数范围内的数,即0-32767.除数必须保证不为0,否则将报错。在有余数除法中,必须能同时显示商与余数。

    1. 在Proteus 环境下建立图1所示原理图,并将其保存为LCD1602_self.DSN 文件:

    图1:实验原理图

    2. 编写源程序,将其保存为LCD1602_self.c。运行Keil开发环境,建立工程LCD1602_self.uV2,CPU 为AT89C51,包含启动文件STARTUP.A51。将C 语言源程序LCD1602_self.c 加入工程LCD1602_self.uV2,并设置工程LCD1602_self.uV2 属性,将其晶振频率设置为12MHz,选择输出可执行文件,仿真方式为选择硬仿真,并选择其中的“PROTEUS VSM

    MONITOR 51 DRIVER”仿真器。

    3. 构造(Build)工程LCD1602_self.uV2。如果输入有误进行修改,直至构造正确,生成可执行程序LCD1602_self.hex 为止,为AT89C51 设置可执行程序LCD1602_self.hex。

    4. 运行程序,点击按键输入数据与运算符,计算,观察计算结果,并验证其是否正确,输入过程中,按“清除按键”观察结果,重新输入数据计算并验证。

       1)加法:1+2=3,如图2:

    图2:加法测试

    2)减法:5-3=2,如图3:

    图3:减法测试

    3)特殊情况:6-9=-3,如图4:

    图4:负数减法测试

    4)乘法:4*5=20,如图5:

    图5:乘法测试

      5) 除法:20/5=4,如图6:

    图6:除法测试

    6) 带余数的除法,如图7:

    图7:带余数的除法测试

    7) 除法为0报错,如图8:

    图8:除法为0报错

    8) 清零,如图9:

    图9:清零

    四、实验流程图

    图10:实验流程图

    编程时要有一个状态变量,该变量用于记录当前是输入的哪个变量。输入第一个变量,遇到输入运算符时结束第一个变量的输入。输入第二个变量,遇到“=”号时结束第二个变量的输入,并且开始计算结果。

    计算结果由于是16 进制的,要将其转换成十进制,并将该十进制的数转换成字符串后逐位显示出来。减法时要注意结果是否为负,除法时要注意除数是否为0,结果是否带有余数。另外,按键要注意去抖动处理。

    采用的是逐行扫描,扫描的时候将要扫描的行置0,其余的行置1;扫描过程中,所有的列全部置1,当某一行的其中一个按键被按下,且正好扫描到这一样,那么所在的列将会被置0. 这时只需要;将行与1111相与即可判断那一列为0,即按下了哪一列。也是实验3.6中键盘扫描的基本思路。

    五、实验源代码

    1. #include<reg51.h> //预处理伪指令
    2. #define uint unsigned int
    3. #define uchar unsigned char
    4. sbit lcden=P1^5; //定义引脚E使能端,高到低液晶模块执行任务
    5. sbit rs=P1^7;
    6. sbit rw=P1^6; // 控制读写
    7. sbit busy=P0^7;
    8. char i,j,temp,num;
    9. long a=0,b=0,c=0,d=0; //初始化a参与运算的第一个数,b参与运算的第二个数,c得数,d余数
    10. float a_c,b_c;
    11. uchar flag,signal; //flag表示运算符是否按下
    12. //signal表示按下运算符的名称
    13. uchar code table[]={
    14. 0,1,2,3,
    15. 4,5,6,7,
    16. 8,9,0x2b-0x30,0x2d-0x30,
    17. 0x2a-0x30,0x2f-0x30,0x01-0x30,0x3d-0x30}; //定义table数组
    18. uchar code error[]="Error!"; //定义error数组,用于显示除数为0的情况
    19. void delay(uchar z) // 设置延迟函数
    20. {
    21. uchar y;
    22. for(z;z>0;z--)
    23. for(y=0;y<110;y++);
    24. }
    25. void check() // 判断系统状态
    26. {
    27. do
    28. {
    29. P2=0xFF;
    30. rs=0;
    31. rw=1;
    32. lcden=0;
    33. delay(1);
    34. lcden=1;
    35. }
    36. while(busy==1); //判断是否为空闲,1为忙,0为空闲
    37. }
    38. void lcd_wcmd(uchar com) // 写指令
    39. {
    40. P2=com;
    41. rs=0;
    42. rw=0;
    43. lcden=0;
    44. check();
    45. lcden=1;
    46. }
    47. void lcd_wdat(uchar date) // 写数据
    48. {
    49. P2=date;
    50. rs=1;
    51. rw=0;
    52. lcden=0;
    53. check();
    54. lcden=1;
    55. }
    56. void init() //初始化
    57. {
    58. num=-1;
    59. lcden=1; // 使能信号为高电平
    60. lcd_wcmd(0x38); // 8位,2行,5X7点阵
    61. lcd_wcmd(0x0c); //显示开,光标关,不闪烁
    62. lcd_wcmd(0x06); //增量方式不移位,地址自动增加
    63. lcd_wcmd(0x80); //检测忙信号
    64. lcd_wcmd(0x01); //清屏
    65. i=0;
    66. j=0;
    67. flag=0;
    68. signal=0;
    69. }
    70. void keyscan() // 键盘扫描
    71. {
    72. P3=0xfe; //扫描第一行,后四位是行
    73. if(P3!=0xfe)
    74. {
    75. delay(20); //延时去抖动
    76. if(P3!=0xfe) //第一行有键按下
    77. {
    78. temp=P3&0xf0; // 将列与1111进行与操作取列号
    79. switch(temp) // 根据与出来的列号进行选择
    80. {
    81. case 0xe0:num=0;
    82. break;
    83. case 0xd0:num=1;
    84. break;
    85. case 0xb0:num=2;
    86. break;
    87. case 0x70:num=3;
    88. break;
    89. }
    90. }
    91. while(P3!=0xfe);
    92. if(flag==0) // 没有按过符号键时输入继续赋给第一个数
    93. {
    94. a=a*10+table[num];
    95. }
    96. else // 如果按过符号键,则赋给第二个数
    97. {
    98. b=b*10+table[num];
    99. }
    100. i=table[num];
    101. lcd_wdat(0x30+i); // 显示屏写入数字
    102. }
    103. P3=0xfd; //扫描第二行
    104. if(P3!=0xfd)
    105. {
    106. delay(5);
    107. if(P3!=0xfd) // 不等于初值,即代表该行有按键按下
    108. { // 第二行有数被按下
    109. temp=P3&0xf0; // 列与1111相与,判断按下的列
    110. switch(temp)
    111. {
    112. case 0xe0:num=4;
    113. break;
    114. case 0xd0:num=5;
    115. break;
    116. case 0xb0:num=6;
    117. break;
    118. case 0x70:num=7;
    119. break;
    120. }
    121. }
    122. while(P3!=0xfd);
    123. if(flag==0) //没有按过符号键
    124. {
    125. a=a*10+table[num];
    126. }
    127. else //按过符号键
    128. {
    129. b=b*10+table[num];
    130. }
    131. i=table[num];
    132. lcd_wdat(0x30+i); //写入显示屏
    133. }
    134. P3=0xfb; //扫描第三行
    135. if(P3!=0xfb)
    136. {
    137. delay(5);
    138. if(P3!=0xfb)
    139. {
    140. temp=P3&0xf0;
    141. switch(temp)
    142. {
    143. case 0xe0:num=8;
    144. break;
    145. case 0xd0:num=9;
    146. break;
    147. case 0xb0:num=10;
    148. break;
    149. case 0x70:num=11;
    150. break;
    151. }
    152. }
    153. while(P3!=0xfb); // 第三行的话不全是数字
    154. if(num==8||num==9) //按下的是'8','9'
    155. {
    156. if(flag==0) //没有按过符号键
    157. {
    158. a=a*10+table[num];
    159. }
    160. else //按过符号键
    161. {
    162. b=b*10+table[num];
    163. }
    164. }//0-9用table
    165. else if(num==10) // 如果按下的是'+'
    166. {
    167. flag=1;
    168. signal=1; // signal为1表示按下的是加号
    169. }
    170. else if(num==11) //如果按下的是'-'
    171. {
    172. flag=1;
    173. signal=2; //2表示按下的是减号
    174. }
    175. i=table[num];
    176. lcd_wdat(0x30+i);
    177. }
    178. P3=0xf7; // 第四行都是符号
    179. if(P3!=0xf7)
    180. {
    181. delay(5);
    182. if(P3!=0xf7)
    183. {
    184. temp=P3&0xf0; // 列和1111相与取列号
    185. switch(temp)
    186. {
    187. case 0xe0:num=12;
    188. break;
    189. case 0xd0:num=13;
    190. break;
    191. case 0xb0:num=14;
    192. break;
    193. case 0x70:num=15;
    194. break;
    195. }
    196. }
    197. while(P3!=0xf7);
    198. switch(num)
    199. {
    200. case 12:{lcd_wdat(0x30+table[num]); flag=1;signal=3;}
    201. break;
    202. case 13:{lcd_wdat(0x30+table[num]); flag=1;signal=4;} //运算符号用table
    203. break;
    204. case 14:{lcd_wcmd(0x01);i=0;j=0;a=0;b=0;c=0;d=0;flag=0;signal=0;} //按下的是"清零" ,0x01指令
    205. break;
    206. case 15:{j=1;
    207. if(signal==1) //+号
    208. {
    209. lcd_wcmd(0x80+0x40); //第二行
    210. c=a+b;
    211. lcd_wdat(0x3d);
    212. while(c!=0)
    213. {
    214. if(c/10000!=0)
    215. {
    216. lcd_wdat(0x30+c/10000);
    217. c=c%10000;
    218. lcd_wdat(0x30+c/1000);
    219. c=c%1000;
    220. lcd_wdat(0x30+c/100);
    221. c=c%100;
    222. lcd_wdat(0x30+c/10);
    223. c=c%10;
    224. lcd_wdat(0x30+c);
    225. }
    226. else if(c/1000!=0)
    227. {
    228. lcd_wdat(0x30+c/1000);
    229. c=c%1000;
    230. lcd_wdat(0x30+c/100);
    231. c=c%100;
    232. lcd_wdat(0x30+c/10);
    233. c=c%10;
    234. lcd_wdat(0x30+c);
    235. }
    236. else if(c/100!=0)
    237. {
    238. lcd_wdat(0x30+c/100);
    239. c=c%100;
    240. lcd_wdat(0x30+c/10);
    241. c=c%10;
    242. lcd_wdat(0x30+c);
    243. }
    244. else if(c/10!=0)
    245. {
    246. lcd_wdat(0x30+c/10);
    247. c=c%10;
    248. lcd_wdat(0x30+c);
    249. }
    250. else if(c/10==0)
    251. {
    252. lcd_wdat(0x30+c);
    253. }
    254. a=0;b=0;c=0;flag=0;signal=0;
    255. }
    256. }
    257. else if(signal==2)
    258. {
    259. lcd_wcmd(0x80+0x40); //第二行
    260. if(a-b>0)
    261. c=a-b;
    262. else
    263. c=b-a; //c为绝对值
    264. lcd_wdat(0x3d); //写"="
    265. if(a-b<0)
    266. lcd_wdat(0x2d); //小于0时为负号
    267. while(c!=0) //若c不为0
    268. {
    269. if(c/10000!=0) //则先从最高位写起
    270. {
    271. lcd_wdat(0x30+c/10000);
    272. c=c%10000;
    273. lcd_wdat(0x30+c/1000);
    274. c=c%1000;
    275. lcd_wdat(0x30+c/100);
    276. c=c%100;
    277. lcd_wdat(0x30+c/10);
    278. c=c%10;
    279. lcd_wdat(0x30+c);
    280. }
    281. else if(c/1000!=0)
    282. {
    283. lcd_wdat(0x30+c/1000);
    284. c=c%1000;
    285. lcd_wdat(0x30+c/100);
    286. c=c%100;
    287. lcd_wdat(0x30+c/10);
    288. c=c%10;
    289. lcd_wdat(0x30+c);
    290. }
    291. else if(c/100!=0)
    292. {
    293. lcd_wdat(0x30+c/100);
    294. c=c%100;
    295. lcd_wdat(0x30+c/10);
    296. c=c%10;
    297. lcd_wdat(0x30+c);
    298. }
    299. else if(c/10!=0)
    300. {
    301. lcd_wdat(0x30+c/10);
    302. c=c%10;
    303. lcd_wdat(0x30+c);
    304. }
    305. else if(c/10==0)
    306. {
    307. lcd_wdat(0x30+c);
    308. }
    309. a=0;b=0;c=0;flag=0;signal=0;
    310. }
    311. }
    312. else if(signal==3) //乘号的情况
    313. {
    314. lcd_wcmd(0x80+0x40);
    315. c=a*b;
    316. lcd_wdat(0x3d);
    317. while(c!=0)
    318. {
    319. if(c/10000!=0)
    320. {
    321. lcd_wdat(0x30+c/10000);
    322. c=c%10000;
    323. lcd_wdat(0x30+c/1000);
    324. c=c%1000;
    325. lcd_wdat(0x30+c/100);
    326. c=c%100;
    327. lcd_wdat(0x30+c/10);
    328. c=c%10;
    329. lcd_wdat(0x30+c);
    330. }
    331. else if(c/1000!=0)
    332. {
    333. lcd_wdat(0x30+c/1000);
    334. c=c%1000;
    335. lcd_wdat(0x30+c/100);
    336. c=c%100;
    337. lcd_wdat(0x30+c/10);
    338. c=c%10;
    339. lcd_wdat(0x30+c);
    340. }
    341. else if(c/100!=0)
    342. {
    343. lcd_wdat(0x30+c/100);
    344. c=c%100;
    345. lcd_wdat(0x30+c/10);
    346. c=c%10;
    347. lcd_wdat(0x30+c);
    348. }
    349. else if(c/10!=0)
    350. {
    351. lcd_wdat(0x30+c/10);
    352. c=c%10;
    353. lcd_wdat(0x30+c);
    354. }
    355. else if(c/10==0)
    356. {
    357. lcd_wdat(0x30+c);
    358. }
    359. a=0;b=0;c=0;flag=0;signal=0;
    360. }
    361. }
    362. else if(signal==4) //除号的情况
    363. {
    364. lcd_wcmd(0x80+0x40);
    365. lcd_wcmd(0x06);
    366. if(b==0)
    367. {
    368. i=0;
    369. while(error[i]!='\0')
    370. {
    371. lcd_wdat(error[i]);
    372. i++;
    373. }
    374. a=0;b=0;c=0;flag=0;signal=0;
    375. } //被除数为0显示error
    376. else if((a%b==0)&&(b!=0)) // 整除时输出c
    377. {
    378. lcd_wdat(0x3d);
    379. c=a/b;
    380. if(a/b<=0)
    381. {
    382. lcd_wdat(0x30);
    383. }
    384. while(c!=0)
    385. {
    386. if(c/10000!=0)
    387. {
    388. lcd_wdat(0x30+c/10000);
    389. c=c%10000;
    390. lcd_wdat(0x30+c/1000);
    391. c=c%1000;
    392. lcd_wdat(0x30+c/100);
    393. c=c%100;
    394. lcd_wdat(0x30+c/10);
    395. c=c%10;
    396. lcd_wdat(0x30+c);
    397. }
    398. else if(c/1000!=0)
    399. {
    400. lcd_wdat(0x30+c/1000);
    401. c=c%1000;
    402. lcd_wdat(0x30+c/100);
    403. c=c%100;
    404. lcd_wdat(0x30+c/10);
    405. c=c%10;
    406. lcd_wdat(0x30+c);
    407. }
    408. else if(c/100!=0)
    409. {
    410. lcd_wdat(0x30+c/100);
    411. c=c%100;
    412. lcd_wdat(0x30+c/10);
    413. c=c%10;
    414. lcd_wdat(0x30+c);
    415. }
    416. else if(c/10!=0)
    417. {
    418. lcd_wdat(0x30+c/10);
    419. c=c%10;
    420. lcd_wdat(0x30+c);
    421. }
    422. else if(c/10==0)
    423. {
    424. lcd_wdat(0x30+c);
    425. }
    426. a=0;b=0;c=0;flag=0;signal=0;
    427. }
    428. }
    429. else if((a%b!=0)&&(b!=0)) //若不整除输出c```d
    430. {
    431. c=a/b;
    432. d=a%b;
    433. lcd_wdat(0x3d);
    434. if(a/b<=0)
    435. {
    436. lcd_wdat(0x30);
    437. }
    438. while(c!=0)
    439. {
    440. if(c/10000!=0)
    441. {
    442. lcd_wdat(0x30+c/10000);
    443. c=c%10000;
    444. lcd_wdat(0x30+c/1000);
    445. c=c%1000;
    446. lcd_wdat(0x30+c/100);
    447. c=c%100;
    448. lcd_wdat(0x30+c/10);
    449. c=c%10;
    450. lcd_wdat(0x30+c);
    451. }
    452. else if(c/1000!=0)
    453. {
    454. lcd_wdat(0x30+c/1000);
    455. c=c%1000;
    456. lcd_wdat(0x30+c/100);
    457. c=c%100;
    458. lcd_wdat(0x30+c/10);
    459. c=c%10;
    460. lcd_wdat(0x30+c);
    461. }
    462. else if(c/100!=0)
    463. {
    464. lcd_wdat(0x30+c/100);
    465. c=c%100;
    466. lcd_wdat(0x30+c/10);
    467. c=c%10;
    468. lcd_wdat(0x30+c);
    469. }
    470. else if(c/10!=0)
    471. {
    472. lcd_wdat(0x30+c/10);
    473. c=c%10;
    474. lcd_wdat(0x30+c);
    475. }
    476. else if(c/10==0)
    477. {
    478. lcd_wdat(0x30+c);
    479. }
    480. a=0;b=0;c=0;flag=0;signal=0;
    481. }
    482. lcd_wdat(0x2e);
    483. lcd_wdat(0x2e);
    484. lcd_wdat(0x2e);
    485. if(d/10000!=0)
    486. {
    487. lcd_wdat(0x30+d/10000);
    488. d=d%10000;
    489. lcd_wdat(0x30+d/1000);
    490. d=d%1000;
    491. lcd_wdat(0x30+d/100);
    492. d=d%100;
    493. lcd_wdat(0x30+d/10);
    494. d=d%10;
    495. lcd_wdat(0x30+d);
    496. }
    497. else if(d/1000!=0)
    498. {
    499. lcd_wdat(0x30+d/1000);
    500. d=d%1000;
    501. lcd_wdat(0x30+d/100);
    502. d=d%100;
    503. lcd_wdat(0x30+d/10);
    504. d=d%10;
    505. lcd_wdat(0x30+d);
    506. }
    507. else if(d/100!=0)
    508. {
    509. lcd_wdat(0x30+d/100);
    510. d=d%100;
    511. lcd_wdat(0x30+d/10);
    512. d=d%10;
    513. lcd_wdat(0x30+d);
    514. }
    515. else if(d/10!=0)
    516. {
    517. lcd_wdat(0x30+d/10);
    518. d=d%10;
    519. lcd_wdat(0x30+d);
    520. }
    521. else if(d/10==0)
    522. {
    523. lcd_wdat(0x30+d);
    524. }
    525. }
    526. }
    527. break;
    528. }
    529. }
    530. }
    531. }
    532. main() // 定义主程序
    533. {
    534. init(); //初始化子程序
    535. while(1) //一直循环
    536. {
    537. keyscan(); // 键盘扫描函数扫描输入
    538. }
    539. }

    初学单片机,可能存在错误之处,还请各位不吝赐教。

    受于文本原因,本文相关实验工程无法展示出来,现已将资源上传,可自行下载。

     山东大学单片机原理与应用实验工程文件3.7LCD1602显示实验-单片机文档类资源-CSDN下载山东大学单片机原理与应用实验工程文件3.7LCD1602显示实验详解博客地址:https:/更多下载资源、学习资料请访问CSDN下载频道.https://download.csdn.net/download/m0_52316372/85924094

  • 相关阅读:
    js-函数式编程-monad-chain-mcompose-自动解嵌套
    【100个 Unity实用技能】| 关于触发器互相检测的必要前提条件配置
    vue实现调用手机拍照、录像功能
    基于Cortex-M的RTOS上下文切换详解及FreeRTOS实例
    2023-2024 年最佳 6 款数据恢复软件免费在线下载
    微信小程序使用Animate.css动画库
    地图轨迹跟踪系统设计与实现(Android+Eclipse+APP)
    4800坐标反算
    一体式水利视频监控站 遥测终端视频图像水位水质水量流速监测
    NFNet:NF-ResNet的延伸,不用BN的4096超大batch size训练 | 21年论文
  • 原文地址:https://blog.csdn.net/m0_52316372/article/details/125631876