/************************************************************
程序实现的功能:
用矩阵按键控制 8*8 LED 点阵和数码管,
实现按下1到9的数字键数码管从100或200。。。或900的
倒计时,一秒钟减1,直到减到0为止。
同时LED点阵以呼吸灯的方式渐明渐暗,显示“王”字,
当按下数字键0时,LED点阵关闭,同时数码管停止计数
并显示结果。
作者:宁静致远
************************************************************/
#include
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
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
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] <
keyBuf[i][1] = (keyBuf[i][1] <
keyBuf[i][2] = (keyBuf[i][2] <
keyBuf[i][3] = (keyBuf[i][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 *** = 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
idx++;
else {
idx = 0;
ADDR3 = 0;
}
}
else {
if (***) {
TH0 = lowRH;
TL0 = lowRL;
if (enLED1) {
P0 = 0xFF;
P1 = (P1 & 0xF8) | idx;
P0 = image[idx];
}
*** = 0;
}
else {
TH0 = highRH;
TL0 = highRL;
P0 = 0xFF;
*** = 1;
if (idx
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;
}
}
『本文转载自网络,版权归原作者所有,如有侵权请联系删除』