/************************************************************
程序实现的功能:
用矩阵按键控制 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)];
ledbuff[1] = ledchar[(num)/10];
ledbuff[2] = ledchar[(num)/100];
}
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;
}
}
『本文转载自网络,九游会j9的版权归原作者所有,如有侵权请联系删除』