/************************************************************ 程序实现的功能: 用矩阵按键控制 8*8 LED 点阵和数码管, 实现按下1到9的数字键数码管从100或200。。。或900的 倒计时,一秒钟减1,直到减到0为止。 同时LED点阵以呼吸灯的方式渐明渐暗,显示“王”字, 当按下数字键0时,LED点阵关闭,同时数码管停止计数 并显示结果。 作者:宁静致远 ************************************************************/ #include <reg52.h> typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned long ulong; sbit ADDR0 = P1^0; sbit ADDR1 = P1^1; sbit ADDR2 = P1^2; sbit ADDR3 = P1^3; sbit ENLED = P1^4; sbit KEY_OUT_3 = P2^0; sbit KEY_OUT_2 = P2^1; sbit KEY_OUT_1 = P2^2; sbit KEY_OUT_0 = P2^3; sbit KEY_IN_0 = P2^4; sbit KEY_IN_1 = P2^5; sbit KEY_IN_2 = P2^6; sbit KEY_IN_3 = P2^7; ulong periodCnt = 0; //PWM周期计数值 uchar highRH = 0; //高电平重载值的高字节 uchar highRL = 0; //高电平重载值的低字节 uchar lowRH = 0; //低电平重载值的高字节 uchar lowRL = 0; //低电平重载值的低字节 uchar sumRH = 0; uchar sumRL = 0; uchar T1RH = 0; //T1重载值的高字节 uchar T1RL = 0; //T1重载值的低字节 bit enChange = 1; bit enLED1 = 1; uint rate, rate2Cnt; uint numberShow = 100; uchar code dutyCycle[13] = { //占空比调整表 5, 18, 30, 41, 51, 60, 68, 75, 81, 86, 90, 93, 95 }; uchar pdata hRHi[13], pdata hRLi[13], pdata lRHi[13], pdata lRLi[13]; uchar code image[8] = { 0x81,0x81,0xE7,0xC3,0xC3,0xE7,0x81,0x81 }; uchar code LEDChar[] = { //数码管显示字符转换表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; uchar LEDBuff[6] = { //数码管显示缓冲区 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; uchar code keyCodeMap[4][4] = { //矩阵按键编号到标准键盘键码的映射表 {0x31, 0x32, 0x33, 0x26}, //数字键1、数字键2、数字键3、向上键 {0x34, 0x35, 0x36, 0x25}, //数字键4、数字键5、数字键6、向左键 {0x37, 0x38, 0x39, 0x28}, //数字键7、数字键8、数字键9、向下键 {0x30, 0x1B, 0x0D, 0x27} //数字键0、ESC键、 回车键、 向右键 }; uchar keyState[4][4] = { //全部矩阵按键的当前状态 {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; void configTmr0(uint fr, uchar dc); void configTmr1(uint ms1, uchar ms2); void calcRldVal(uchar idx); void keyScan(); void keyAction(uchar keyCode); void keyDriver(); void main() { uchar i; EA = 1; //开总中断 PT0 = 1; //设置T0抢占优先 ADDR3 = 0; //选中LED点阵 ENLED = 0; configTmr0(1000, dutyCycle[0]); //配置并启动PWM for (i = 0; i < 13; i++) calcRldVal(i); configTmr1(50, 1); while (1) { keyDriver(); } } //配置并启动T1,ms1:呼吸灯的变化间隔,ms2:矩阵按键的扫描间隔(T1溢出时间) void configTmr1(uint ms1, uchar ms2) { ulong tmp; //临时变量 rate = ms1 / ms2; tmp = 11059200 / 12; //定时器计数频率 tmp = (tmp * ms2) / 1000; //计算所需的计数值 tmp = 65536 - tmp; //计算定时器重载值 tmp = tmp + 12; //补偿中断响应延时造成的误差 T1RH = tmp >> 8; //定时器重载值拆分为高低字节 T1RL = tmp; TMOD &= 0x0F; //清零T1的控制位 TMOD |= 0x10; //配置T1为模式1 TH1 = T1RH; //加载T1重载值 TL1 = T1RL; ET1 = 1; //使能T1中断 TR1 = 1; //启动T1 } /* 配置并启动PWM,fr-频率,dc-占空比 */ void configTmr0(uint fr, uchar dc) { uint high, low, sum; rate2Cnt = fr - 1; //到达1秒所需的计数值 periodCnt = 11059200 / 12 / fr; //计算一个周期所需的计数值 high = periodCnt * dc / 100; //计算高电平所需的计数值 low = periodCnt - high; //计算低电平所需的计数值 high = 65536L - high + 12; //计算高电平的定时器重载值并补偿中断延时 low = 65536L - low + 12; //计算低电平的定时器重载值并补偿中断延时 sum = 65536L - periodCnt + 12; highRH = high >> 8; //高电平重载值拆分为高低字节 highRL = high; lowRH = low >> 8; //低电平重载值拆分为高低字节 lowRL = low; sumRH = sum >> 8; sumRL = sum; TMOD &= 0xF0; //清零T0的控制位 TMOD |= 0x01; //配置T0为模式1 TH0 = highRH; //加载T0重载值 TL0 = highRL; ET0 = 1; //使能T0中断 TR0 = 1; //启动T0 } void calcRldVal(uchar idx) { uint high, low; high = periodCnt * dutyCycle[idx] / 100; //计算高电平所需的计数值 low = periodCnt - high; //计算低电平所需的计数值 high = 65536L - high + 12; //计算高电平的定时器重载值并补偿中断延时 low = 65536L - low + 12; //计算低电平的定时器重载值并补偿中断延时 hRHi[idx] = high >> 8; //高电平重载值拆分为高低字节 hRLi[idx] = high; lRHi[idx] = low >> 8; //低电平重载值拆分为高低字节 lRLi[idx] = low; } /* #define LED1_Scan(); { \ static uchar i = 0; \ P0 = 0xFF; \ P1 = (P1 & 0xF8) | i; \ P0 = image[i]; \ i = ++i & 0x07; \ } #define LED2_Scan(); { \ static uchar i = 0; \ P0 = 0xFF; \ P1 = (P1 & 0xF8) | i; \ P0 = LEDBuff[i]; \ if (i < 5) \ i++; \ else \ i = 0; \ } */ void keyScan() { static uchar i = 0; static uchar keyBuf[4][4] = { {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF} }; uchar j; keyBuf[i][0] = (keyBuf[i][0] << 1) | KEY_IN_0; keyBuf[i][1] = (keyBuf[i][1] << 1) | KEY_IN_1; keyBuf[i][2] = (keyBuf[i][2] << 1) | KEY_IN_2; keyBuf[i][3] = (keyBuf[i][3] << 1) | KEY_IN_3; for (j=0; j<4; j++) { if (keyBuf[i][j] == 0x00) keyState[i][j] = 0; else if (keyBuf[i][j] == 0xFF) keyState[i][j] = 1; } switch (i) { case 0: KEY_OUT_0 = 1; KEY_OUT_1 = 0; break; case 1: KEY_OUT_1 = 1; KEY_OUT_2 = 0; break; case 2: KEY_OUT_2 = 1; KEY_OUT_3 = 0; break; case 3: KEY_OUT_3 = 1; KEY_OUT_0 = 0; break; default : break; } i = ++i & 0x03; } #define resetLEDBuff(num); { \ LEDBuff[0] = LEDChar[(num)%10]; \ LEDBuff[1] = LEDChar[(num)/10%10]; \ LEDBuff[2] = LEDChar[(num)/100%10]; \ } void keyAction(uchar keyCode) { if (keyCode == 0x30) { enChange = 0; //TR0 = 0; enLED1 = 0; } else if (keyCode >= 0x31 && keyCode <= 0x39) { enChange = 1; //TR0 = 1; enLED1 = 1; numberShow = (keyCode - 0x30) * 100; resetLEDBuff(numberShow); } } void keyDriver() { uchar i, j; static uchar backup[4][4] = { {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1} }; for (i=0; i<4; i++) for (j=0; j<4; j++) if (keyState[i][j] != backup[i][j]) { if (keyState[i][j] == 0) keyAction(keyCodeMap[i][j]); backup[i][j] = keyState[i][j]; } } //定时器T0的中断服务函数,完成LED点阵的扫描,数码管的扫描,数码管显示的动态调整 //和产生PWM输出 void interruptTmr0() interrupt 1 { static bit flg = 1; static uchar idx = 0; static uint cnt2 = 0; if (ADDR3) { TH0 = sumRH; TL0 = sumRL; P0 = 0xFF; P1 = (P1 & 0xF8) | idx; P0 = LEDBuff[idx]; if (cnt2 == rate2Cnt) { if (enChange) { if (numberShow > 0) { numberShow--; resetLEDBuff(numberShow); } } cnt2 = 0; } else cnt2++; if (idx < 5) idx++; else { idx = 0; ADDR3 = 0; } } else { if (flg) { TH0 = lowRH; TL0 = lowRL; if (enLED1) { P0 = 0xFF; P1 = (P1 & 0xF8) | idx; P0 = image[idx]; } flg = 0; } else { TH0 = highRH; TL0 = highRL; P0 = 0xFF; flg = 1; if (idx < 7) idx++; else { idx = 0; ADDR3 = 1; } } } } //定时器T1的中断服务函数,完成矩阵按键的扫描,定时动态调整占空比 void interruptTimer1() interrupt 3 { static bit dir = 0; static uchar index = 0; static uint cnt = 0; TH1 = T1RH; //重新加载T1重载值 TL1 = T1RL; keyScan(); if (cnt == rate) { highRH = hRHi[index]; highRL = hRLi[index]; lowRH = lRHi[index]; lowRL = lRLi[index]; cnt = 0; } else cnt++; if (dir == 0) { index++; if (index == 12) dir = 1; } else { index--; if (index == 0) dir = 0; } }