51单片机之大杂烩

/************************************************************
    程序实现的功能:
        用矩阵按键控制 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;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值