51单片机之大杂烩

来源:互联网 发布:finale2016打谱软件 编辑:程序博客网 时间:2024/06/04 18:04
/************************************************************    程序实现的功能:        用矩阵按键控制 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]);  //配置并启动PWMfor (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;    }}


0 0
原创粉丝点击