蓝桥杯单片机(二) 数码管与按键
1.数码管
数码管的动态扫描使用1ms的定时器扫描,放在中断服务函数中,数码管显示很稳定
例子:数码管后五位显示12345
#include<stc15f2k60s2.h>
typedef unsigned char uchar;
typedef unsigned int uint;
uchar dsp_code[]={ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
uchar dsp_show[8]={ 0xff,0xff,0xff}; //数码管前三位熄灭,后五位显示12345
uint number=12345;
void Timer0Init(void) //中断初始化,1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //记得加上这两句
EA=1;
}
void Timer0_Service() interrupt 1 //中断入口
{
static uchar bit_com=0;
P0=0; //消影,使所有数码管熄灭
P2=0xc0;
P2=0;
P0=dsp_show[bit_com]; //段选内容,即要显示的数字
P2=0xe0; //打开锁存器控制数码管段选
P2=0; //关闭锁存器
P0=1<<bit_com; //位选左移一位
P2=0xc0; //打开锁存器控制数码管位选
P2=0;
if(++bit_com==8)
bit_com=0;
}
void main()
{
Timer0Init(); //中断初始化
dsp_show[3]=dsp_code[number/10000];
dsp_show[4]=dsp_code[number/1000%10];
dsp_show[5]=dsp_code[number/100%10];
dsp_show[6]=dsp_code[number/10%10];
dsp_show[7]=dsp_code[number%10];
while(1)
{
;
}
}
2.按键
按键部分分为独立按键与矩阵按键,跳帽J5接在BTN(button)时即原理图中23,独立按键生效。接在KBD(keyboard)时即原理图中12,矩阵按键生效。
2.1 独立按键:
跳线帽需要短接J5口的3和2引脚,按键能使用的仅有第一列(即上图中S4、S5、S6、S7)。当按键按下时,相应的P30-33口输入为低电平,由此编写独立按键扫描函数。
void KEY_1(void)
{
static u8 key_flag = 1;
if(key_flag && (P30 == 0||P31 == 0|| P32 == 0||P33 == 0))
{
key_flag = 0;
if(P30 == 0) //S7
{
}
else if(P31 == 0) //S6
{
}
else if(P32 == 0) //S5
{
}
else if(P33 == 0) //S4
{
}
}
else if(P33 && P32 && P31 && P30) key_flag = 1;
}
例子:将跳帽J5接在BTN,按下S4点亮L4,按下S5点亮L5,按下S6点亮L6,按下S7点亮L7,每次只点亮一个LED
#include<stc15f2k60s2.h>
typedef unsigned char uchar;
typedef unsigned int uint;
uchar cnt,trg;
uchar count_key; //控制按键刷新率的变量
void scan_button()
{
uchar readdat=P3^0xff;
trg=readdat&(readdat^cnt); //???
cnt=readdat;
if(trg&0x01) //检测到按下S7,即0001,用trg==0x01会使按键不灵敏
P0=~0x40; //点亮L7
else if(trg&0x02) //检测到按下S6,即0010
P0=~0x20;
else if(trg&0x04) //检测到按下S5,即0100
P0=~0x10;
else if(trg&0x08) //检测到按下S4,即1000
P0=~0x08;
P2=0x80;
P2=0;
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //记得加上这两句
EA=1;
}
void Timer0_Service() interrupt 1 //中断入口
{
++count_key;
}
void main()
{
P0=0x00;
P2=0xa0; //打开锁存器控制蜂鸣器和继电器
P2=0;
P0=0xff;
P2=0x80; //打开锁存器控制LED
P2=0;
Timer0Init();
while(1)
{
if(count_key>9) //10ms刷新一次,相当于消抖
{
count_key=0; //控制刷新率的变量清零
scan_button(); //调用独立按键处理函数
}
}
}
2.2矩阵按键
跳线帽需要短接J5口的1和2引脚,按键能使用16个(即上图中S4-S19)。矩阵按键的扫描方法可采用行列扫描法,分为两步:
- 将行的输出设为低电平(0),检测列的电平输入值。
- 将列的输出设为低电平(0),检测行的电平输入值。
将两个检测值进行叠加,计算判断哪个按键被按下
例子:按下S7使数码管显示+1.按下S11使显示的数-1,数的范围0~200,当其为奇数时打开蜂鸣器关闭继电器,为偶数时打开继电器关闭蜂鸣器。
#include<stc15f2k60s2.h>
typedef unsigned char uchar;
typedef unsigned int uint;
sbit buzzer=P0^6;
sbit relay=P0^4;
uchar dsp_code[]={ 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90}; //显示内容(0~9
uchar dsp_value[8]={ 0xff,0xff,0xff,0xff,0xff};//初始化,使前5位数码管熄灭
uchar number=10;
uchar count_key;//控制数码管刷新率
void Timer0_sevice() interrupt 1
{
static uchar dsp_com=0;
uchar P0_keeper=0,P2_keeper=0;
P0_keeper=P0;P2_keeper=P2; //现场保护
P0=0;
P2=0xc0; //消影,使所有数码管熄灭
P2=0;
P0=dsp_value[dsp_com];
P2=0xe0; //打开锁存器控制数码管段选
P2=0;
P0=1<<dsp_com;
P2=0xc0; //打开锁存器控制数码管位选
P2=0;
if(++dsp_com==8) dsp_com=0;
P0=P0_keeper;P2=P2_keeper;//返回现场
++count_key;
}
void scan_key()
{
static uchar key_stat=0;
uchar key_val=0,key_x=0,key_y=0;
P3=0x0f;P4=0x00;//行扫描
if(!P30) key_x=3;
else if(!P31) key_x=2;
else if(!P32) key_x=1;
else if(!P33) key_x=0;
P3=0xf0;P4=0xff;//列扫描
if(!P34) key_y=4;
else if(!P35) key_y=3;
else if(!P42) key_y=2;
else if(!P44) key_y=1;
key_val=key_x+key_y*4;//综合行、列扫描的结果,判断具体位置
switch(key_stat)
{
case 0:
if(key_val!=0) key_stat=1;//第一次检测到有按键按下,状态为1
break;
case 1:
if(key_val==0) key_stat=0;//第二次(10ms后)若检测到无按键按下,返回状态0,按键防抖
else
{
key_stat=2;//第二次(10ms后)再次检测到有按键按下,状态为2
switch(key_val)
{
case 7: //按下S7数字加一
if(number<200)//注意判断后再执行,防止数超出范围
{
++number;
}
break;
case 11: //按下S11数字减一
if(number>0)
{ --number;}
break;
}
}
break;
case 2: //按键防抖设计
if(key_val==0)key_stat=0;//第三次若检测到无按键按下,返回状态0
break;
}
}
void Timer0Init(void) //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1; //记得加上这两句
EA=1;
}
void main()
{
P0=0xff;P2=0x80;P2=0;
P0=0x00;P2=0xa0;P2=0;
Timer0Init();
while(1)
{
if(number%2==1)
{
buzzer=1;
relay=0;
}
else
{
relay=1;
buzzer=0;
}
P2=0xa0;P2=0;
if(number>9)
dsp_value[6]=dsp_code[number/10%10];
else
dsp_value[6]=0xff;
dsp_value[7]=dsp_code[number%10];
if(count_key>9) //10ms刷新一次,相当于消抖10ms
{
count_key=0; //控制刷新率的变量清零
scan_key(); //调用矩阵按键处理函数
}
}
}