中南民族大学,电子信息工程学院,开设了一门课程,叫《嵌入式电路设计》,由舒老师带头,旨在引导低年级的学生入门嵌入式,其内容比较多,包括模电、数电、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 #include2 #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<<i); 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 }