51单片机计分器

前言:因为学校期末51单片机考核,我就在书上的基础代码上改了改,改的比较简单,实现的功能也很单一(当时时间紧,应付老师),希望能给正在学习的学弟学妹一个小小参考吧。

题目要求:

用数码管设计一个计分设备。

项目展示:

代码展示:

#include 
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit KEY_IN_1 = P2^4;
sbit KEY_IN_2 = P2^5;
sbit KEY_IN_3 = P2^6;
sbit KEY_IN_4 = P2^7;
sbit KEY_OUT_1 = P2^3;
sbit KEY_OUT_2 = P2^2;
sbit KEY_OUT_3 = P2^1;
sbit KEY_OUT_4 = P2^0;
unsigned char code LedChar[] = { //数码管显示字符转换表0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86,0x8E, 0xBF
};
unsigned char LedBuff[6] = { //数码管显示缓冲区0xFF, 0xFF, 0xBF, 0xBF, 0xFF, 0xFF
};
unsigned char 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 键、 回车键、 向右键
};
unsigned char KeySta[4][4] = { //全部矩阵按键的当前状态{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}
};unsigned long pdata KeyDownTime[4][4] = { //每个按键按下的持续时间,单位 ms{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}
};void KeyDriver();void main()
{EA = 1; //使能总中断ENLED = 0; //选择数码管进行显示ADDR3 = 1;TMOD = 0x01; //设置 T0 为模式 1TH0 = 0xFC; //为 T0 赋初值 0xFC67,定时 1msTL0 = 0x67;ET0 = 1; //使能 T0 中断TR0 = 1; //启动 T0while (1){KeyDriver(); //调用按键驱动函数}
}/* 按键动作函数,根据键码执行相应的操作,keycode-按键键码 */
void KeyAction(unsigned char keycode)
{static unsigned char sec1 = 0; //用于保存输入的加数static unsigned long sec2 = 0; //用于保存输入的加数if (keycode == 0x31) //K1键控制左边计分{sec2++;LedBuff[0] = LedChar[sec1%10];LedBuff[1] = LedChar[sec1/10];LedBuff[2] = LedChar[16];LedBuff[3] = LedChar[16];LedBuff[4] = LedChar[sec2%10];LedBuff[5] = LedChar[sec2/10];if(sec2 >= 99){sec2 = 0;}} if (keycode == 0x26) //K4键控制右边计分{sec1++;LedBuff[0] = LedChar[sec1%10];LedBuff[1] = LedChar[sec1/10];LedBuff[2] = LedChar[16];LedBuff[3] = LedChar[16];LedBuff[4] = LedChar[sec2%10];LedBuff[5] = LedChar[sec2/10];if(sec1 >= 99){sec1 = 0;}} else if (keycode == 0x1B) //Esc 键,清零结果{LedBuff[0] = 0xC0; LedBuff[1] = 0XC0;LedBuff[2] = 0XBF; LedBuff[3] = 0XBF; LedBuff[4] = 0XC0; LedBuff[5] = 0XC0; sec1 = 0;sec2 = 0;}
}
/* 按键驱动函数,检测按键动作,调度相应动作函数,需在主循环中调用 */
void KeyDriver()
{unsigned char i, j;static unsigned char backup[4][4] = { //按键值备份,保存前一次的值{1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}, {1, 1, 1, 1}};
static unsigned long pdata TimeThr[4][4] = { //快速输入执行的时间阈值{1000, 1000, 1000, 1000}, {1000, 1000, 1000, 1000},{1000, 1000, 1000, 1000}, {1000, 1000, 1000, 1000}};for (i=0; i<4; i++) //循环检测 4*4 的矩阵按键{for (j=0; j<4; j++){if (backup[i][j] != KeySta[i][j]) //检测按键动作{if(backup[i][j] != 0) //按键按下时执行动作{KeyAction(KeyCodeMap[i][j]); //调用按键动作函数}backup[i][j] = KeySta[i][j]; //刷新前一次的备份值}if (KeyDownTime[i][j] > 0) //检测执行快速输入{if (KeyDownTime[i][j] >= TimeThr[i][j]){ //达到阈值时执行一次动作KeyAction(KeyCodeMap[i][j]); //调用按键动作函数TimeThr[i][j] += 200; //时间阈值增加 200ms,以准备下次执行}}else //按键弹起时复位阈值时间{TimeThr[i][j] = 1000; //恢复 1s 的初始阈值时间}}}
}
/* 按键扫描函数,需在定时中断中调用,推荐调用间隔 1ms */
void KeyScan()
{unsigned char i;static unsigned char keyout = 0; //矩阵按键扫描输出索引static unsigned char keybuf[4][4] = { //矩阵按键扫描缓冲区{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF},{0xFF, 0xFF, 0xFF, 0xFF}, {0xFF, 0xFF, 0xFF, 0xFF}};//将一行的 4 个按键值移入缓冲区keybuf[keyout][0] = (keybuf[keyout][0] << 1) | KEY_IN_1;keybuf[keyout][1] = (keybuf[keyout][1] << 1) | KEY_IN_2;keybuf[keyout][2] = (keybuf[keyout][2] << 1) | KEY_IN_3;keybuf[keyout][3] = (keybuf[keyout][3] << 1) | KEY_IN_4;//消抖后更新按键状态for (i=0; i<4; i++) //每行 4 个按键,所以循环 4 次{if ((keybuf[keyout][i] & 0x0F) == 0x00){ //连续 4 次扫描值为 0,即 4*4ms 内都是按下状态时,可认为按键已稳定的按下KeySta[keyout][i] = 0;KeyDownTime[keyout][i] +=4;}else if ((keybuf[keyout][i] & 0x0F) == 0x0F){ //连续 4 次扫描值为 1,即 4*4ms 内都是弹起状态时,可认为按键已稳定的弹起KeySta[keyout][i] = 1;KeyDownTime[keyout][i] = 0;}}//执行下一次的扫描输出keyout++; //输出索引递增keyout = keyout & 0x03; //索引值加到 4 即归零switch (keyout) //根据索引,释放当前输出引脚,拉低下次的输出引脚{case 0: KEY_OUT_4 = 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_4 = 0; break;default: break;}
}
/* 数码管动态扫描刷新函数,需在定时中断中调用 */
void LedScan()
{static unsigned char i = 0; //动态扫描的索引P0 = 0xFF; //显示消隐switch (i){case 0: ADDR2=0; ADDR1=0; ADDR0=0; i++; P0=LedBuff[0]; break;case 1: ADDR2=0; ADDR1=0; ADDR0=1; i++; P0=LedBuff[1]; break;case 2: ADDR2=0; ADDR1=1; ADDR0=0; i++; P0=LedBuff[2]; break;case 3: ADDR2=0; ADDR1=1; ADDR0=1; i++; P0=LedBuff[3]; break;case 4: ADDR2=1; ADDR1=0; ADDR0=0; i++; P0=LedBuff[4]; break;case 5: ADDR2=1; ADDR1=0; ADDR0=1; i=0; P0=LedBuff[5]; break;default: break;}
}
/* T0 中断服务函数,用于数码管显示扫描与按键扫描 */
void InterruptTimer0() interrupt 1
{TH0 = 0xFC; //重新加载初值TL0 = 0x67;LedScan(); //调用数码管显示扫描函数KeyScan(); //调用按键扫描函数
}

以上就是我的全部代码了,功能很单一,只能实现数字递增清除,不能减法等其他功能。刚刚接触单片机的学弟学妹们,可以试着往里面再加代码,以达到实现真正的快捷的计分器设计。比如初级的就是加入减法函数,高级点就是直接按键修改两边的得分数字等等。我的代码仅供你们参考,毕竟真的简单。


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部