中南民族大学,电子信息工程学院,开设了一门课程,叫《嵌入式电路设计》,由舒老师带头,旨在引导低年级的学生入门嵌入式,其内容比较多,包括模电、数电、C语言、单片机、EDA技术等。最近有位师弟找到我,希望我能帮他指导一下,利用AT89C52单片机设计一个最小系统,其中包括矩阵键盘、数码管显示、中断、2位数加减法、定时计数与暂停等功能。我也粗略的设计了一个,在此分享出来,希望能对初学者有所帮助,使更多的人加入到嵌入式的行业来。
开发工具:keil
仿真工具:proteus
代码如下:
头文件:inc_all.h
1 #ifndef INC_ALL_H_
2 #define INC_ALL_H_
3
4 volatile unsigned char keyValue;
5 volatile unsigned char sign;
6 volatile long int opr1;
7 volatile long int opr2;
8 volatile long int SysValue=0;
9 volatile int keyCounter;
10 volatile int cnt50ms=0;
11 volatile bit StartFlag;
12
13 void Init_Timer0();
14 void Init_Timer1();
15 void delayms(int t);
16 unsigned char KeyScan(void);
17 void showNumber(long int num);
18 void keyAnalyzing(unsigned char keyval);
19
20 #endif
源文件如下:main.c
1 #include
2 #include "inc_all.h"
3 //=======================================================
4 // 数码管显示译码,共阴极
5 // 0,1,2,3,4,5,6,7,8,9,灭,‘E’,'-'
6 //=======================================================
7 unsigned char code table[]={0x3F,0x06,0x5b,0x4F,0x66,
8 0x6d,0x7d,0x07,0x7F,0x6F,
9 0x00/* trun off */,
10 0x79/* Error */,
11 0x40/* - */};
12 //========================================================
13 // 定时器0初始化函数,定时50毫秒
14 // 用键盘上的“START”键启动计数
15 // 用键盘上的“SUS”键暂停计数
16 //========================================================
17 void Init_Timer0()
18 {
19 TMOD |= 0x01;
20 TH0 = 0x3C;
21 TL0 = 0xB0;
22 TR0 = 0;
23 ET0 = 1;
24 }
25 //=========================================================
26 // 定时器1初始化函数
27 // 定时23毫秒,用于显示
28 // 初始化后计时启动
29 //=========================================================
30 void Init_Timer1()
31 {
32 TMOD |= 0x10;
33 TH1 = 0xA6;
34 TL1 = 0x28;
35 TR1 = 1;
36 ET1 = 1;
37 }
38 //=========================================================
39 // 延时函数
40 //=========================================================
41 void delayms(int t)
42 {
43 int i,j;
44 for(i=t;i>0;i--)
45 for(j=25;j>0;j--)
46 ;
47 }
48 //=========================================================
49 // 四位数码管显示函数
50 // 能自动灭零,自动识别正负号
51 // 数值超出显示范围时显示错误"E---"
52 //=========================================================
53 void showNumber(long int num)
54 {
55 unsigned char q,s,b,g;
56 if(num>=0)
57 {
58 q = num/1000;
59 b = num/100%10;
60 s = num/10%10;
61 g = num%10;
62 if(num<10)
63 {
64 q = 10;
65 b = 10;
66 s = 10;
67 }
68 else if(num<100)
69 {
70 q = 10;
71 b = 10;
72 }
73 else if(num<1000)
74 q = 10;
75 else if(num>9999)
76 {
77 q = 11; //show error
78 b = 12;
79 s = 12;
80 g = 12;
81 }
82 }
83 else
84 {
85 if(num>-1000)
86 {
87 q = 12;
88 b = (0-num)/100;
89 s = (0-num)/10%10;
90 g = (0-num)%10;
91 }
92 else
93 {
94 q = 11; //show error
95 b = 12;
96 s = 12;
97 g = 12;
98 }
99 }
100 P0 = 0x00;
101 P0 = table[q];
102 P2 = 0xFE;
103 delayms(10);
104 P0 = 0x00;
105 P0 = table[b];
106 P2 = 0xFD;
107 delayms(10);
108 P0 = 0x00;
109 P0 = table[s];
110 P2 = 0xFB;
111 delayms(10);
112 P0 = 0x00;
113 P0 = table[g];
114 P2 = 0xF7;
115 delayms(10);
116 }
117 //=========================================================
118 // 键盘扫描函数
119 // 返回按键情况,扫描结果
120 //=========================================================
121 unsigned char KeyScan(void)
122 {
123 unsigned char temp=0xF0;
124 P1 = temp;
125 temp = P1;
126 if(temp!=0xF0)
127 {
128 delayms(5); //去抖动
129 temp = P1;
130 if(temp!=0xF0)
131 {
132 int t=0x01,i;
133 for(i=0;i<4;i++)
134 {
135 P1 = ~(t<
136 temp = P1;
137 switch(temp) //按行扫描
138 {
139 case 0xee: return '1';
140 case 0xde: return '2';
141 case 0xbe: return '3';
142 case 0x7e: return '+'; //加号
143
144 case 0xed: return '4';
145 case 0xdd: return '5';
146 case 0xbd: return '6';
147 case 0x7d: return '-'; //减号
148
149 case 0xeb: return '7';
150 case 0xdb: return '8';
151 case 0xbb: return '9';
152 case 0x7b: return 'r'; //复位
153
154 case 0xe7: return '0';
155 case 0xd7: return 's'; //启动
156 case 0xb7: return 't'; //暂停
157 case 0x77: return '='; //等于
158 default: ;
159 }
160 }
161 }
162 }
163 return '0';
164 }
165 //=========================================================
166 // 键盘解析函数
167 // 对扫描得到的键值进行解析
168 //=========================================================
169 void keyAnalyzing(unsigned char keyval)
170 {
171 if(keyval>='0' && keyval<='9')
172 {
173 switch(keyCounter)
174 {
175 case 0: SysValue = (int)keyval-0x30;
176 keyCounter++;
177 break;
178 case 1: ;
179 case 2: ;
180 case 3: SysValue =SysValue*10+(int)keyval-0x30;
181 keyCounter++;
182 break;
183 case 4: SysValue =SysValue*10+(int)keyval-0x30;
184 keyCounter=0;
185 break;
186 }
187 }
188 else
189 {
190 switch(keyval)
191 {
192 case '+': sign = '+';
193 opr1 = SysValue;
194 SysValue = 0;
195 keyCounter = 0;
196 break;
197 case '-': opr1 = SysValue;
198 SysValue = 0;
199 keyCounter = 0;
200 sign = '-';
201 break;
202 case 's': sign = 's';
203 TR0 = 1; //启动计数
204 StartFlag = 1;
205 break;
206 case 't': sign = 't';
207 if(StartFlag)
208 TR0 ^= 1;//暂停/启动计数
209 break;
210 case 'r': sign = 'r';
211 opr1 = 0;
212 opr2 = 0;
213 SysValue = 0;
214 keyCounter = 0;
215 TR0 = 0; //停止计数器
216 StartFlag = 0;
217 break;
218 case '=': opr2 = SysValue;
219 if(sign=='+')
220 SysValue = opr1+opr2;
221 else if(sign=='-')
222 SysValue = opr1 - opr2;
223 opr1 = 0;
224 opr2 = 0;
225 keyCounter = 0;
226 sign = '=';
227 break;
228 }
229 }
230 }
231 //=========================================================
232 // 主函数main
233 // 全局采用中断方式,有利于降低功耗
234 //=========================================================
235 void main()
236 {
237 EX0 = 1; //允许外部0中断
238 IT0 = 1; //外部0中断方式为 “下降沿”
239 Init_Timer0(); /*初始化定时器0,在键盘上点击“START”后
240 开始计数,定时时间为1秒*/
241 Init_Timer1(); /*初始化定时器1,用于定时显示,定时时间
242 为23毫秒,即每隔23毫秒调用一次显示函数*/
243 EA = 1; //总中断开
244 P1 = 0xF0; //初始键盘接口
245 while(1) ;
246 }
247 //=========================================================
248 // 按键中断服务函数,采用外部中断0
249 // 按键中断,在中断里面检测按键并解析按键
250 //=========================================================
251 void key_isr(void) interrupt 0
252 {
253 EA = 0;
254 keyValue = KeyScan();
255 keyAnalyzing(keyValue);
256 P1 = 0xF0;
257 EA = 1;
258 }
259 //=========================================================
260 // 定时器0中断服务函数
261 // 用于,定时1秒计数,计数到8888后返回重新新计数
262 //=========================================================
263 void timer0_isr(void) interrupt 1
264 {
265 TR0 = 0;
266 TH0 = 0x3C;
267 TL0 = 0xB0;
268 TR0 = 1;
269 cnt50ms++;
270 if(cnt50ms==19) //计数20次 20*50 = 1000毫秒,即1秒
271 {
272 cnt50ms = 0;
273 SysValue=(SysValue>8887)?0:SysValue+1;
274 }
275 }
276 //=========================================================
277 // 定时器1中断服务函数
278 // 方式1,定时时间为23毫秒
279 // 用于数码管显示
280 //=========================================================
281 void timer1_isr(void) interrupt 3
282 {
283 TR1 = 0;
284 TH1 = 0xA6;
285 TL1 = 0x28;
286 showNumber(SysValue);
287 TR1 = 1;
288 }