整体规划(1课时)
1、用protues进行原理图绘制
2、用keil软件进行代码编写与调试
3、Keil + protues进行仿真实验
4、处理器采用Atmel公司的AT89C51,晶振频率12MHz,源代码用C语言编写
5、此项目可以分为3个模块:LCD1602显示部分、按键扫描部分、核心计算部分
LCD1602模块(3课时)
1、阅读LCD1602手册,明白每一个引脚的用途,按照手册连接原理图
![](/attachment/201406/16/29270124_14029061648GgZ.jpg)
2、仔细阅读1602控制指令,编写LCD1602控制程序
指令1:清显示,指令码01H,光标复位到地址00H位置
指令2:光标复位,光标返回到地址00H
指令3:光标和显示模式设置 I/D:光标移动方向,高电平右移,低电平左移 S:屏幕上所有文字是否左移或者右移。高电平表示有效,低电平则无效
指令4:显示开关控制。 D:控制整体显示的开与关,高电平表示开显示,低电平表示关显示 C:控制光标的开与关,高电平表示有光标,低电平表示无光标 B:控制光标是否闪烁,高电平闪烁,低电平不闪烁
指令5:光标或显示移位 S/C:高电平时移动显示的文字,低电平时移动光标
指令6:功能设置命令 DL:高电平时为4位总线,低电平时为8位总线 N:低电平时为单行显示,高电平时双行显示 F: 低电平时显示5x7的点阵字符,高电平时显示5x10的点阵字符
指令7:字符发生器RAM地址设置
指令8:DDRAM地址设置
指令9:读忙信号和光标地址 BF:为忙标志位,高电平表示忙,此时模块不能接收命令或者数据,如果为低电平表示不忙。
指令10:写数据
指令11:读数据
-
#include <reg52.h>
-
-
2. #include <lcd_1602.h>
-
-
3. #define uchar unsigned char
-
-
4.
-
-
5. float power(int num, int p);
-
-
6.int powerr(int num, int p);
-
-
7.
-
-
8.//RS 高电平选择数据 低电平选择命令/地址
-
-
9.//R/W 高电平读 低电平写
-
-
10.
-
-
11.uchar code cmd[] = {
-
-
12. 0x01, //清屏
-
-
13. 0x02, //光标返回00h
-
-
14. 0x06, //开显示,无光标,不闪烁
-
-
15. 0x38 //8位总线,双行显示,5*7阵列
-
-
16. };
-
-
17.
-
-
18.void delay_1ms();
-
-
19. void delay_10us();
-
-
20.
-
-
21.int lcd_1602_busy() //读忙信号
-
-
22.{
-
-
23. uchar tmp;
-
-
24. P0 = 0xff; //将P0口设置为输出
-
-
25. LCD_1602_RW = 1;
-
-
26. LCD_1602_RS = 0;
-
-
27.
-
-
28. LCD_1602_EN = 1;
-
-
29. delay_10us();
-
-
30. tmp = P0;
-
-
31. LCD_1602_EN = 0;
-
-
32.
-
-
33. return (bit)(0x80 & tmp);
-
-
34.
-
-
35.}
-
-
36.
-
-
37. void lcd_1602_write_cmd(uchar cmd) //发送命令\地址
-
-
38.{
-
-
39. while(lcd_1602_busy());
-
-
40.
-
-
41. LCD_1602_RW = 0;
-
-
42. LCD_1602_RS = 0;
-
-
43. P0 = cmd;
-
-
44.
-
-
45. LCD_1602_EN = 1;
-
-
46.// P0 = cmd;
-
-
47. delay_10us();
-
-
48. LCD_1602_EN = 0;
-
-
49.}
-
-
50.
-
-
51. void lcd_1602_write_data(uchar dat) //发送数据
-
-
52.{
-
-
53. while(lcd_1602_busy());
-
-
54.
-
-
55. LCD_1602_RW = 0;
-
-
56. LCD_1602_RS = 1;
-
-
57. P0 = dat;
-
-
58.
-
-
59. LCD_1602_EN = 1;
-
-
60.// P0 = dat;
-
-
61. delay_10us();
-
-
62. LCD_1602_EN = 0;
-
-
63.}
-
-
64.
-
-
65. void lcd_1602_init() //lcd初始化
-
-
66.{
-
-
67. lcd_1602_write_cmd(0x01);
-
-
68. lcd_1602_write_cmd(0x0c);
-
-
69. lcd_1602_write_cmd(0x38);
-
-
70. lcd_1602_write_cmd(0x01);
-
-
71. delay_1ms();
-
-
72.}
-
-
73.
-
-
74. void lcd_1602_write_char(uchar x, uchar y, uchar dat)//写字符
-
-
75.{
-
-
76. if(x == 0)
-
-
77. {
-
-
78. lcd_1602_write_cmd(0x80 + y%16);
-
-
79. lcd_1602_write_data(dat);
-
-
80. }
-
-
81. else
-
-
82. {
-
-
83. lcd_1602_write_cmd(0xc0 + y%16);
-
-
84. lcd_1602_write_data(dat);
-
-
85. }
-
-
86.}
-
-
87.
-
-
88. void lcd_1602_write_string(uchar x, uchar y, uchar *string)//写字符串
-
-
89.{
-
-
90. while(*string != '\0')
-
-
91. {
-
-
92. lcd_1602_write_char(x, y++, *(string++));
-
-
93. }
-
-
94.}
-
-
95.
-
-
96. void lcd_1602_write_num(uchar x, uchar y, float num)//写数字
-
-
97.{
-
-
98. int i;
-
-
99. int nu = (int)num;
-
-
100.
-
-
101. char string[5];
-
-
102. for(i=0; i<4; i++)
-
-
103. {
-
-
104. string[i] = nu/powerr(10, 3-i) + '0';
-
-
105. nu = nu % powerr(10, 3-i);
-
-
106. if(nu < 10)
-
-
107. string[i+1] = nu + '0';
-
-
108. }
-
-
109. string[4] = '\0';
-
-
110. lcd_1602_write_string(x, y, string);
-
-
111.}
-
-
112.
-
-
113.int powerr(int num, int p) //求num的p次方
-
-
114.{
-
-
115. int sum = 1;
-
-
116.
-
-
117. while(p)
-
-
118. {
-
-
119. sum = sum*num;
-
-
120. p--;
-
-
121. }
-
-
122.
-
-
123. return sum;
-
-
124.}
-
-
-
-
-
-
按键模块
-
-
1、阅读课本第10章按键扫描方法
-
-
2、绘制按键原理图
-
-
3、编写按键扫描程序
-
-
-
-
-
-
点击(此处)折叠或打开
-
-
1./**************************************************
-
-
2.函数功能:按键扫描
-
-
3. 实现4*4键盘扫描,记录下每一个按键
-
-
4.*****************************************************/
-
-
5.int keyscan()
-
-
6.{
-
-
7.
-
-
8. P3=0xfe;
-
-
9. temp=P3;
-
-
10. temp = temp & 0xf0;
-
-
11. if(temp!=0xf0)
-
-
12. {
-
-
13. delay(10);
-
-
14. if(temp!=0xf0)
-
-
15. {
-
-
16. temp=P3;
-
-
17. switch(temp)
-
-
18. {
-
-
19. case 0xee:
-
-
20. key = '1';
-
-
21. break;
-
-
22.
-
-
23. case 0xde:
-
-
24. key = '2';
-
-
25. break;
-
-
26.
-
-
27. case 0xbe:
-
-
28. key = '3';
-
-
29. break;
-
-
30.
-
-
31. case 0x7e:
-
-
32. key = '+';
-
-
33. break;
-
-
34. }
-
-
35. while(temp!=0xf0)
-
-
36. {
-
-
37. temp=P3;
-
-
38. temp=temp&0xf0;
-
-
39. beep=0;
-
-
40. }
-
-
41. beep=1;
-
-
42. return 1;
-
-
43. }
-
-
44. }
-
-
45. P3=0xfd;
-
-
46. temp=P3;
-
-
47. temp=temp&0xf0;
-
-
48. if(temp!=0xf0)
-
-
49. {
-
-
50. delay(10);
-
-
51. if(temp!=0xf0)
-
-
52. {
-
-
53. temp=P3;
-
-
54. switch(temp)
-
-
55. {
-
-
56. case 0xed:
-
-
57. key='4';
-
-
58. break;
-
-
59.
-
-
60. case 0xdd:
-
-
61. key='5';
-
-
62. break;
-
-
63.
-
-
64. case 0xbd:
-
-
65. key='6';
-
-
66. break;
-
-
67.
-
-
68. case 0x7d:
-
-
69. key='-';
-
-
70. break;
-
-
71. }
-
-
72. while(temp!=0xf0)
-
-
73. {
-
-
74. temp=P3;
-
-
75. temp=temp&0xf0;
-
-
76. beep=0;
-
-
77. }
-
-
78. beep=1;
-
-
79. return 1;
-
-
80. }
-
-
81. }
-
-
82. P3=0xfb;
-
-
83. temp=P3;
-
-
84. temp=temp&0xf0;
-
-
85. if(temp!=0xf0)
-
-
86. {
-
-
87. delay(10);
-
-
88. if(temp!=0xf0)
-
-
89. {
-
-
90. temp=P3;
-
-
91. switch(temp)
-
-
92. {
-
-
93. case 0xeb:
-
-
94. key='7';
-
-
95. break;
-
-
96.
-
-
97. case 0xdb:
-
-
98. key='8';
-
-
99. break;
-
-
100.
-
-
101. case 0xbb:
-
-
102. key='9';
-
-
103. break;
-
-
104.
-
-
105. case 0x7b:
-
-
106. key='*';
-
-
107. break;
-
-
108. }
-
-
109. while(temp!=0xf0)
-
-
110. {
-
-
111. temp=P3;
-
-
112. temp=temp&0xf0;
-
-
113. beep=0;
-
-
114. }
-
-
115. beep=1;
-
-
116. return 1;
-
-
117. }
-
-
118. }
-
-
119. P3=0xf7;
-
-
120. temp=P3;
-
-
121. temp=temp&0xf0;
-
-
122. if(temp!=0xf0)
-
-
123. {
-
-
124. delay(10);
-
-
125. if(temp!=0xf0)
-
-
126. {
-
-
127. temp=P3;
-
-
128. switch(temp)
-
-
129. {
-
-
130. case 0xe7:
-
-
131. key = '0';
-
-
132. lcd_1602_write_data(key);
-
-
133. break;
-
-
134.
-
-
135. case 0xd7:
-
-
136. key='.';
-
-
137. lcd_1602_write_data(key);
-
-
138. break;
-
-
139.
-
-
140. case 0xb7:
-
-
141. key='=';
-
-
142. break;
-
-
143.
-
-
144. case 0x77:
-
-
145. key='/';
-
-
146. break;
-
-
147. }
-
-
148. while(temp!=0xf0)
-
-
149. {
-
-
150. temp=P3;
-
-
151. temp=temp&0xf0;
-
-
152. beep=0;
-
-
153. }
-
-
154. beep=1;
-
-
155. return 1;
-
-
156. }
-
-
157. }
-
-
158. return 0;
-
-
159.}
核心计算模块
1、测试LCD1602显示程序是否正确
2、测试按键扫描程序是否正确
3、在Linux环境下调试计算程序。
首先将扫描到的按键存储在数组中,然后从数组提取操作数和操作码,调用计算子程序进行计算,最后输入计算结果。
以上过程需要先在Linux环境下模拟,因此需要少许Linux知识。
-
#include <reg51.h>
-
-
2. #include <stdio.h>
-
-
3. #include <calculate.h>
-
-
4.
-
-
5. extern uchar key;
-
-
6.
-
-
7.int f = 0;
-
-
8.int str_len = 0;
-
-
9.int operand_num = 0;
-
-
10.int operator_num = 0;
-
-
11. float end = 0.0;
-
-
12.int a = 0, b = 0;
-
-
13.
-
-
14. char xdata input[100];
-
-
15. float xdata operand[10]={0};
-
-
16. char xdata operator[10];
-
-
17.
-
-
18. void get_operand(char *string);
-
-
19. void str_int(char *str, float num[]);
-
-
20.
-
-
21. float power(int num, int p);
-
-
22. float powe(int p);
-
-
23. float operat();
-
-
24.
-
-
25. void cmg88()//关数码管,点阵函数
-
-
26.{
-
-
27. DU=1;
-
-
28. P0=0X00;
-
-
29. DU=0;
-
-
30.}
-
-
31.
-
-
32. #if 0
-
-
33. void main()
-
-
34.{
-
-
35. cmg88();
-
-
36. lcd_1602_init();
-
-
37. delay_1ms();
-
-
38. lcd_1602_write_char(0, 13, '0');
-
-
39.
-
-
40. while(1)
-
-
41. {
-
-
42. while(!keyscan());
-
-
43.
-
-
44. if((key >= '0' && key <= '9') || key == '.') //显示扫描到的数字,不显示运算符号
-
-
45. lcd_1602_write_char(0, str_len, key);
-
-
46.
-
-
47. input[str_len] = key;
-
-
48. str_len ++;
-
-
49. if((key > '9' || key < '0') && key != '.') //扫描到+-/*
-
-
50. {
-
-
51. get_operand(input); //获取操作数
-
-
52. operator[operator_num] = key; //操作码保存在数组中
-
-
53. operator_num ++;
-
-
54. f++;
-
-
55.
-
-
56. if(f>1)
-
-
57. {
-
-
58. operat(); //扫描到2个以上操作码,进行运算
-
-
59. lcd_1602_write_num(1, 0, end); //显示得到的结果
-
-
60. }
-
-
61. }
-
-
62. }
-
-
63.}
-
-
64.
-
-
65./*****************************************************************
-
-
66.函数功能:获取操作数,并将小数点过滤
-
-
67.******************************************************************/
-
-
68.void get_operand(char *string)
-
-
69.{
-
-
70. int i;
-
-
71. char str[20] = {' '};
-
-
72. for(i=0; i<str_len; i++)
-
-
73. {
-
-
74. if((string[i] > '9' || string[i] < '0') && string[i] != '.')
-
-
75. {
-
-
76. str[i] = '\0';
-
-
77. lcd_1602_write_cmd(0x01);
-
-
78. break;
-
-
79. }
-
-
80. str[i] = string[i];
-
-
81. }
-
-
82. str_int(str, operand);
-
-
83. str_len = 0;
-
-
84. operand_num ++;
-
-
85.}
-
-
86./*****************************************************************
-
-
87.函数功能:字符串转浮点数
-
-
88. LCD1602只能显示字符,按键扫描到的也是字符
-
-
89. 所有的字符都必须转换为数字彩能参加运算
-
-
90.******************************************************************/
-
-
91.void str_int(char *str, float num[])
-
-
92.{
-
-
93. int i = 0, len_i = 0, len_f= 1, j = 0;
-
-
94. while(1)
-
-
95. {
-
-
96. if(str[i] == '.')
-
-
97. break;
-
-
98. if(str[i] == '\0')
-
-
99. break;
-
-
100. i++;
-
-
101. }
-
-
102. len_i = i;
-
-
103. while(len_i)
-
-
104. {
-
-
105. num[operand_num] += (str[len_i-1]-'0')*power(10, j);
-
-
106. j++;
-
-
107. len_i--;
-
-
108. }
-
-
109. j = 1;
-
-
110. while(str[i] == '.')
-
-
111. i++;
-
-
112.
-
-
113. while(str[i] != '\0')
-
-
114. {
-
-
115. num[operand_num] += (str[i]-'0')*powe(j);
-
-
116. j++;
-
-
117. i++;
-
-
118. }
-
-
119.}
-
-
120./*****************************************************************
-
-
121.函数功能:求一个数的n次方
-
-
122.******************************************************************/
-
-
123.float power(int num, int p)
-
-
124.{
-
-
125. float sum = 1;
-
-
126.
-
-
127. while(p)
-
-
128. {
-
-
129. sum = sum*num;
-
-
130. p--;
-
-
131. }
-
-
132.
-
-
133. return sum;
-
-
134.}
-
-
135./*****************************************************************
-
-
136.函数功能:求10 的-n次方
-
-
137.******************************************************************/
-
-
138.float powe(int p)
-
-
139.{
-
-
140. float sum = 1;
-
-
141. while(p)
-
-
142. {
-
-
143. sum = sum/10;
-
-
144. p--;
-
-
145. }
-
-
146.
-
-
147. return sum;
-
-
148.}
-
-
149.
-
-
150./*****************************************************************
-
-
151.函数功能:计算过程
-
-
152.******************************************************************/
-
-
153.float operat()
-
-
154.{
-
-
155. if(b == 0)
-
-
156. {
-
-
157. switch (operator[a])
-
-
158. {
-
-
159. case '+':
-
-
160. end = operand[b] + operand[b+1];
-
-
161. break;
-
-
162. case '-':
-
-
163. end = operand[b] - operand[b+1];
-
-
164. break;
-
-
165. case '*':
-
-
166. end = operand[b] * operand[b+1];
-
-
167. break;
-
-
168. case '/':
-
-
169. end = operand[b] / operand[b+1];
-
-
170. break;
-
-
171. default:
-
-
172. break;
-
-
173. }
-
-
174. b = 2;
-
-
175. a++;
-
-
176.
-
-
177. return end;
-
-
178. }
-
-
179. if(b != 0 )
-
-
180. {
-
-
181. switch (operator[a])
-
-
182. {
-
-
183. case '+':
-
-
184. end = end + operand[b];
-
-
185. break;
-
-
186. case '-':
-
-
187. end = end - operand[b];
-
-
188. break;
-
-
189. case '*':
-
-
190. end = end * operand[b];
-
-
191. break;
-
-
192. case '/':
-
-
193. end = end / operand[b];
-
-
194. break;
-
-
195. default:
-
-
196. break;
-
-
197. }
-
-
198. a++;
-
-
199. b++;
-
-
200.
-
-
201. return end;
-
-
202. }
-
-
203.}
-
-
204. #endif
阅读(1904) | 评论(1) | 转发(0) |