如何用51单片机数码管实现跑马灯功能?

51单片机数码管显示跑马灯程序源代码讲解
基于51单片机学习板。用s1键作为控制跑马灯的方向按键,s5键作为控制跑马灯方向的加速度按键,s9键作为控制跑马灯方向的减速度按键,s13键作为控制跑马灯方向的启动或者暂停按键。记得把输出线p0.4一直输出低电平,模拟独立按键的触发地gnd。
(2)实现功能:
跑马灯运行:第1个至第8个led灯一直不亮。在第9个至第16个led灯,依次逐个亮灯并且每次只能亮一个灯。每按一次独立按键s13键,原来运行的跑马灯会暂停,原来暂停的跑马灯会运行。用s1来改变方向。用s5和s9来改变速度,每按一次按键的递增或者递减以10为单位。
数码管显示:本程序只有1个窗口,这个窗口分成3个局部显示。8,7,6位数码管显示运行状态,启动时显示“on”,停止时显示“off”。5位数码管显示数码管方向,正向显示“n”,反向显示“u”。4,3,2,1位数码管显示速度。数值越大速度越慢,最慢的速度是550,最快的速度是50。
(3)源代码讲解如下:
#include reg52.h
#define const_voice_short 40 //蜂鸣器短叫的持续时间
#define const_key_time1 20 //按键去抖动延时的时间
#define const_key_time2 20 //按键去抖动延时的时间
#define const_key_time3 20 //按键去抖动延时的时间
#define const_key_time4 20 //按键去抖动延时的时间
void initial_myself();
void initial_peripheral();
void delay_short(unsigned int uidelayshort);
void delay_long(unsigned int uidelaylong);
//驱动数码管的74hc595
void dig_hc595_drive(unsigned char ucdigstatustemp16_09,unsigned char ucdigstatustemp08_01);
void display_drive(); //显示数码管字模的驱动函数
void display_service(); //显示的窗口菜单服务程序
//驱动led的74hc595
void hc595_drive(unsigned char ucledstatustemp16_09,unsigned char ucledstatustemp08_01);
void led_flicker_09_16(); //第9个至第16个led的跑马灯程序,逐个亮并且每次只能亮一个.
void led_update(); //led更新函数
void t0_time(); //定时中断函数
void key_service(); //按键服务的应用程序
void key_scan();//按键扫描函数 放在定时中断里
sbit beep_dr=p2^7; //蜂鸣器的驱动io口
sbit key_sr1=p0^0; //对应学习板的s1键
sbit key_sr2=p0^1; //对应学习板的s5键
sbit key_sr3=p0^2; //对应学习板的s9键
sbit key_sr4=p0^3; //对应学习板的s13键
sbit key_gnd_dr=p0^4; //模拟独立按键的地gnd,因此必须一直输出低电平
sbit led_dr=p3^5;
sbit dig_hc595_sh_dr=p2^0; //数码管的74hc595程序
sbit dig_hc595_st_dr=p2^1;
sbit dig_hc595_ds_dr=p2^2;
sbit hc595_sh_dr=p2^3; //led灯的74hc595程序
sbit hc595_st_dr=p2^4;
sbit hc595_ds_dr=p2^5;
unsigned char uckeysec=0; //被触发的按键编号
unsigned int uikeytimecnt1=0; //按键去抖动延时计数器
unsigned char uckeylock1=0; //按键触发后自锁的变量标志
unsigned int uikeytimecnt2=0; //按键去抖动延时计数器
unsigned char uckeylock2=0; //按键触发后自锁的变量标志
unsigned int uikeytimecnt3=0; //按键去抖动延时计数器
unsigned char uckeylock3=0; //按键触发后自锁的变量标志
unsigned int uikeytimecnt4=0; //按键去抖动延时计数器
unsigned char uckeylock4=0; //按键触发后自锁的变量标志
unsigned int uivoicecnt=0; //蜂鸣器鸣叫的持续时间计数器
unsigned char ucled_dr1=0; //代表16个灯的亮灭状态,0代表灭,1代表亮
unsigned char ucled_dr2=0;
unsigned char ucled_dr3=0;
unsigned char ucled_dr4=0;
unsigned char ucled_dr5=0;
unsigned char ucled_dr6=0;
unsigned char ucled_dr7=0;
unsigned char ucled_dr8=0;
unsigned char ucled_dr9=0;
unsigned char ucled_dr10=0;
unsigned char ucled_dr11=0;
unsigned char ucled_dr12=0;
unsigned char ucled_dr13=0;
unsigned char ucled_dr14=0;
unsigned char ucled_dr15=0;
unsigned char ucled_dr16=0;
unsigned char ucled_update=0; //刷新变量。每次更改led灯的状态都要更新一次。
unsigned char ucledstep_09_16=0; //第9个至第16个led跑马灯的步骤变量
unsigned int uitimecnt_09_16=0; //第9个至第16个led跑马灯的统计定时中断次数的延时计数器
unsigned char ucledstatus16_09=0; //代表底层74hc595输出状态的中间变量
unsigned char ucledstatus08_01=0; //代表底层74hc595输出状态的中间变量
unsigned char ucleddirflag=0; //方向变量,把按键与跑马灯关联起来的核心变量,0代表正方向,1代表反方向
unsigned int uisettimelevel_09_16=300; //速度变量,此数值越大速度越慢,此数值越小速度越快。
unsigned char ucledstartflag=1; //启动和暂停的变量,0代表暂停,1代表启动
unsigned char ucdigshow8; //第8位数码管要显示的内容
unsigned char ucdigshow7; //第7位数码管要显示的内容
unsigned char ucdigshow6; //第6位数码管要显示的内容
unsigned char ucdigshow5; //第5位数码管要显示的内容
unsigned char ucdigshow4; //第4位数码管要显示的内容
unsigned char ucdigshow3; //第3位数码管要显示的内容
unsigned char ucdigshow2; //第2位数码管要显示的内容
unsigned char ucdigshow1; //第1位数码管要显示的内容
unsigned char ucdigdot8; //数码管8的小数点是否显示的标志
unsigned char ucdigdot7; //数码管7的小数点是否显示的标志
unsigned char ucdigdot6; //数码管6的小数点是否显示的标志
unsigned char ucdigdot5; //数码管5的小数点是否显示的标志
unsigned char ucdigdot4; //数码管4的小数点是否显示的标志
unsigned char ucdigdot3; //数码管3的小数点是否显示的标志
unsigned char ucdigdot2; //数码管2的小数点是否显示的标志
unsigned char ucdigdot1; //数码管1的小数点是否显示的标志
unsigned char ucdigshowtemp=0; //临时中间变量
unsigned char ucdisplaydrivestep=1; //动态扫描数码管的步骤变量
unsigned char ucwd1part1update=1; //窗口1的局部1更新显示变量
unsigned char ucwd1part2update=1; //窗口1的局部2更新显示变量
unsigned char ucwd1part3update=1; //窗口1的局部3更新显示变量
//根据原理图得出的共阴数码管字模表
code unsigned char dig_table[]=
{
0x3f, //0 序号0
0x06, //1 序号1
0x5b, //2 序号2
0x4f, //3 序号3
0x66, //4 序号4
0x6d, //5 序号5
0x7d, //6 序号6
0x07, //7 序号7
0x7f, //8 序号8
0x6f, //9 序号9
0x00, //无 序号10
0x40, //- 序号11
0x73, //p 序号12
0x5c, //o 序号13
0x71, //f 序号14
0x3e, //u 序号15
0x37, //n 序号16
};
void main()
{
initial_myself();
delay_long(100);
initial_peripheral();
while(1)
{
key_service(); //按键服务的应用程序
display_service(); //显示的窗口菜单服务程序
led_flicker_09_16(); //第9个至第16个led的跑马灯程序,逐个亮并且每次只能亮一个.
led_update(); //led更新函数
}
}
/* 注释一:
* 由于本程序只有1个窗口,而这个窗口又分成3个局部,因此可以省略去窗口变量uwd,
* 只用三个局部变量ucwdxpartyupdate就可以了。
*/
void display_service() //显示的窗口菜单服务程序
{
if(ucwd1part1update==1) //更新显示当前系统是处于运行还是暂停的状态
{
ucwd1part1update=0; //及时把更新变量清零,防止一直进来更新
if(ucledstartflag==1) //启动,显示on
{
ucdigshow8=13; //显示o
ucdigshow7=16; //显示n
ucdigshow6=10; //显示空
}
else //暂停,显示off
{
ucdigshow8=13; //显示o
ucdigshow7=14; //显示f
ucdigshow6=14; //显示f
}
}
if(ucwd1part2update==1) //更新显示当前系统是处于正方向还是反方向
{
ucwd1part2update=0; //及时把更新变量清零,防止一直进来更新
if(ucleddirflag==0) //正方向,向上,显示n
{
ucdigshow5=16; //显示n
}
else //反方向,向下,显示u
{
ucdigshow5=15; //显示u
}
}
if(ucwd1part3update==1) //更新显示当前系统的速度,此数值越大速度越慢,此数值越小速度越快。
{
ucwd1part3update=0; //及时把更新变量清零,防止一直进来更新
ucdigshow4=10; //显示空 这一位不用,作为空格
if(uisettimelevel_09_16>=100)
{
ucdigshow3=uisettimelevel_09_16/100; //显示速度的百位
}
else
{
ucdigshow3=10; //显示空
}
if(uisettimelevel_09_16>=10)
{
ucdigshow2=uisettimelevel_09_16%100/10; //显示速度的十位
}
else
{
ucdigshow2=10; //显示空
}
ucdigshow1=uisettimelevel_09_16%10; //显示速度的个位
}
}
void key_scan()//按键扫描函数 放在定时中断里
{
if(key_sr1==1)//io是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
uckeylock1=0; //按键自锁标志清零
uikeytimecnt1=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
else if(uckeylock1==0)//有按键按下,且是第一次被按下
{
uikeytimecnt1++; //累加定时中断次数
if(uikeytimecnt1>const_key_time1)
{
uikeytimecnt1=0;
uckeylock1=1; //自锁按键置位,避免一直触发
uckeysec=1; //触发1号键
}
}
if(key_sr2==1)//io是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
uckeylock2=0; //按键自锁标志清零
uikeytimecnt2=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
else if(uckeylock2==0)//有按键按下,且是第一次被按下
{
uikeytimecnt2++; //累加定时中断次数
if(uikeytimecnt2>const_key_time2)
{
uikeytimecnt2=0;
uckeylock2=1; //自锁按键置位,避免一直触发
uckeysec=2; //触发2号键
}
}
if(key_sr3==1)//io是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
uckeylock3=0; //按键自锁标志清零
uikeytimecnt3=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
else if(uckeylock3==0)//有按键按下,且是第一次被按下
{
uikeytimecnt3++; //累加定时中断次数
if(uikeytimecnt3>const_key_time3)
{
uikeytimecnt3=0;
uckeylock3=1; //自锁按键置位,避免一直触发
uckeysec=3; //触发3号键
}
}
if(key_sr4==1)//io是高电平,说明按键没有被按下,这时要及时清零一些标志位
{
uckeylock4=0; //按键自锁标志清零
uikeytimecnt4=0;//按键去抖动延时计数器清零,此行非常巧妙,是我实战中摸索出来的。
}
else if(uckeylock4==0)//有按键按下,且是第一次被按下
{
uikeytimecnt4++; //累加定时中断次数
if(uikeytimecnt4>const_key_time4)
{
uikeytimecnt4=0;
uckeylock4=1; //自锁按键置位,避免一直触发
uckeysec=4; //触发4号键
}
}
}
void key_service() //按键服务的应用程序
{
switch(uckeysec) //按键服务状态切换
{
case 1:// 改变跑马灯方向的按键 对应学习板的s1键
if(ucleddirflag==0) //通过中间变量改变跑马灯的方向
{
ucleddirflag=1;
}
else
{
ucleddirflag=0;
}
ucwd1part2update=1; //及时更新显示方向
uivoicecnt=const_voice_short; //按键声音触发,滴一声就停。
uckeysec=0; //响应按键服务处理程序后,按键编号清零,避免一致触发
break;
case 2:// 加速按键 对应学习板的s5键 uisettimelevel_09_16越小速度越快
uisettimelevel_09_16=uisettimelevel_09_16-10;
if(uisettimelevel_09_16550) //最慢限定在550
{
uisettimelevel_09_16=550;
}
ucwd1part3update=1; //及时更新显示速度
uivoicecnt=const_voice_short; //按键声音触发,滴一声就停。
uckeysec=0; //响应按键服务处理程序后,按键编号清零,避免一致触发
break;
case 4:// 启动和暂停按键 对应学习板的s13键 ucledstartflag为0时代表暂停,为1时代表启动
if(ucledstartflag==1) //启动和暂停两种状态循环切换
{
ucledstartflag=0;
}
else //启动和暂停两种状态循环切换
{
ucledstartflag=1;
}
ucwd1part1update=1; //及时更新显示系统的运行状态,是运行还是暂停.
uivoicecnt=const_voice_short; //按键声音触发,滴一声就停。
uckeysec=0; //响应按键服务处理程序后,按键编号清零,避免一致触发
break;
}
}
void led_update() //led更新函数
{
if(ucled_update==1)
{
ucled_update=0; //及时清零,让它产生只更新一次的效果,避免一直更新。
if(ucled_dr1==1)
{
ucledstatus08_01=ucledstatus08_01|0x01;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xfe;
}
if(ucled_dr2==1)
{
ucledstatus08_01=ucledstatus08_01|0x02;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xfd;
}
if(ucled_dr3==1)
{
ucledstatus08_01=ucledstatus08_01|0x04;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xfb;
}
if(ucled_dr4==1)
{
ucledstatus08_01=ucledstatus08_01|0x08;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xf7;
}
if(ucled_dr5==1)
{
ucledstatus08_01=ucledstatus08_01|0x10;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xef;
}
if(ucled_dr6==1)
{
ucledstatus08_01=ucledstatus08_01|0x20;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xdf;
}
if(ucled_dr7==1)
{
ucledstatus08_01=ucledstatus08_01|0x40;
}
else
{
ucledstatus08_01=ucledstatus08_01&0xbf;
}
if(ucled_dr8==1)
{
ucledstatus08_01=ucledstatus08_01|0x80;
}
else
{
ucledstatus08_01=ucledstatus08_01&0x7f;
}
if(ucled_dr9==1)
{
ucledstatus16_09=ucledstatus16_09|0x01;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xfe;
}
if(ucled_dr10==1)
{
ucledstatus16_09=ucledstatus16_09|0x02;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xfd;
}
if(ucled_dr11==1)
{
ucledstatus16_09=ucledstatus16_09|0x04;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xfb;
}
if(ucled_dr12==1)
{
ucledstatus16_09=ucledstatus16_09|0x08;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xf7;
}
if(ucled_dr13==1)
{
ucledstatus16_09=ucledstatus16_09|0x10;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xef;
}
if(ucled_dr14==1)
{
ucledstatus16_09=ucledstatus16_09|0x20;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xdf;
}
if(ucled_dr15==1)
{
ucledstatus16_09=ucledstatus16_09|0x40;
}
else
{
ucledstatus16_09=ucledstatus16_09&0xbf;
}
if(ucled_dr16==1)
{
ucledstatus16_09=ucledstatus16_09|0x80;
}
else
{
ucledstatus16_09=ucledstatus16_09&0x7f;
}
hc595_drive(ucledstatus16_09,ucledstatus08_01); //74hc595底层驱动函数
}
}
void display_drive()
{
//以下程序,如果加一些数组和移位的元素,还可以压缩容量。但是鸿哥追求的不是容量,而是清晰的讲解思路
switch(ucdisplaydrivestep)
{
case 1: //显示第1位
ucdigshowtemp=dig_table[ucdigshow1];
if(ucdigdot1==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xfe);
break;
case 2: //显示第2位
ucdigshowtemp=dig_table[ucdigshow2];
if(ucdigdot2==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xfd);
break;
case 3: //显示第3位
ucdigshowtemp=dig_table[ucdigshow3];
if(ucdigdot3==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xfb);
break;
case 4: //显示第4位
ucdigshowtemp=dig_table[ucdigshow4];
if(ucdigdot4==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xf7);
break;
case 5: //显示第5位
ucdigshowtemp=dig_table[ucdigshow5];
if(ucdigdot5==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xef);
break;
case 6: //显示第6位
ucdigshowtemp=dig_table[ucdigshow6];
if(ucdigdot6==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xdf);
break;
case 7: //显示第7位
ucdigshowtemp=dig_table[ucdigshow7];
if(ucdigdot7==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0xbf);
break;
case 8: //显示第8位
ucdigshowtemp=dig_table[ucdigshow8];
if(ucdigdot8==1)
{
ucdigshowtemp=ucdigshowtemp|0x80; //显示小数点
}
dig_hc595_drive(ucdigshowtemp,0x7f);
break;
}
ucdisplaydrivestep++;
if(ucdisplaydrivestep>8) //扫描完8个数码管后,重新从第一个开始扫描
{
ucdisplaydrivestep=1;
}
}
//数码管的74hc595驱动函数
void dig_hc595_drive(unsigned char ucdigstatustemp16_09,unsigned char ucdigstatustemp08_01)
{
unsigned char i;
unsigned char uctempdata;
dig_hc595_sh_dr=0;
dig_hc595_st_dr=0;
uctempdata=ucdigstatustemp16_09; //先送高8位
for(i=0;i=0x80)dig_hc595_ds_dr=1;
else dig_hc595_ds_dr=0;
dig_hc595_sh_dr=0; //sh引脚的上升沿把数据送入寄存器
delay_short(1);
dig_hc595_sh_dr=1;
delay_short(1);
uctempdata=uctempdata<<1;
}
uctempdata=ucdigstatustemp08_01; //再先送低8位
for(i=0;i=0x80)dig_hc595_ds_dr=1;
else dig_hc595_ds_dr=0;
dig_hc595_sh_dr=0; //sh引脚的上升沿把数据送入寄存器
delay_short(1);
dig_hc595_sh_dr=1;
delay_short(1);
uctempdata=uctempdata<<1;
}
dig_hc595_st_dr=0; //st引脚把两个寄存器的数据更新输出到74hc595的输出引脚上并且锁存起来
delay_short(1);
dig_hc595_st_dr=1;
delay_short(1);
dig_hc595_sh_dr=0; //拉低,抗干扰就增强
dig_hc595_st_dr=0;
dig_hc595_ds_dr=0;
}
//led灯的74hc595驱动函数
void hc595_drive(unsigned char ucledstatustemp16_09,unsigned char ucledstatustemp08_01)
{
unsigned char i;
unsigned char uctempdata;
hc595_sh_dr=0;
hc595_st_dr=0;
uctempdata=ucledstatustemp16_09; //先送高8位
for(i=0;i=0x80)hc595_ds_dr=1;
else hc595_ds_dr=0;
hc595_sh_dr=0; //sh引脚的上升沿把数据送入寄存器
delay_short(1);
hc595_sh_dr=1;
delay_short(1);
uctempdata=uctempdata<<1;
}
uctempdata=ucledstatustemp08_01; //再先送低8位
for(i=0;i=0x80)hc595_ds_dr=1;
else hc595_ds_dr=0;
hc595_sh_dr=0; //sh引脚的上升沿把数据送入寄存器
delay_short(1);
hc595_sh_dr=1;
delay_short(1);
uctempdata=uctempdata<=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr16=0; //第16个灭
ucled_dr9=1; //第9个亮
ucled_update=1; //更新显示
ucledstep_09_16=1; //切换到下一个步骤
}
else //反方向
{
ucled_dr15=1; //第15个亮
ucled_dr16=0; //第16个灭
ucled_update=1; //更新显示
ucledstep_09_16=7; //返回上一个步骤
}
}
break;
case 1:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr9=0; //第9个灭
ucled_dr10=1; //第10个亮
ucled_update=1; //更新显示
ucledstep_09_16=2; //切换到下一个步骤
}
else //反方向
{
ucled_dr16=1; //第16个亮
ucled_dr9=0; //第9个灭
ucled_update=1; //更新显示
ucledstep_09_16=0; //返回上一个步骤
}
}
break;
case 2:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr10=0; //第10个灭
ucled_dr11=1; //第11个亮
ucled_update=1; //更新显示
ucledstep_09_16=3; //切换到下一个步骤
}
else //反方向
{
ucled_dr9=1; //第9个亮
ucled_dr10=0; //第10个灭
ucled_update=1; //更新显示
ucledstep_09_16=1; //返回上一个步骤
}
}
break;
case 3:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr11=0; //第11个灭
ucled_dr12=1; //第12个亮
ucled_update=1; //更新显示
ucledstep_09_16=4; //切换到下一个步骤
}
else //反方向
{
ucled_dr10=1; //第10个亮
ucled_dr11=0; //第11个灭
ucled_update=1; //更新显示
ucledstep_09_16=2; //返回上一个步骤
}
}
break;
case 4:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr12=0; //第12个灭
ucled_dr13=1; //第13个亮
ucled_update=1; //更新显示
ucledstep_09_16=5; //切换到下一个步骤
}
else //反方向
{
ucled_dr11=1; //第11个亮
ucled_dr12=0; //第12个灭
ucled_update=1; //更新显示
ucledstep_09_16=3; //返回上一个步骤
}
}
break;
case 5:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr13=0; //第13个灭
ucled_dr14=1; //第14个亮
ucled_update=1; //更新显示
ucledstep_09_16=6; //切换到下一个步骤
}
else //反方向
{
ucled_dr12=1; //第12个亮
ucled_dr13=0; //第13个灭
ucled_update=1; //更新显示
ucledstep_09_16=4; //返回上一个步骤
}
}
break;
case 6:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr14=0; //第14个灭
ucled_dr15=1; //第15个亮
ucled_update=1; //更新显示
ucledstep_09_16=7; //切换到下一个步骤
}
else //反方向
{
ucled_dr13=1; //第13个亮
ucled_dr14=0; //第14个灭
ucled_update=1; //更新显示
ucledstep_09_16=5; //返回上一个步骤
}
}
break;
case 7:
if(uitimecnt_09_16>=uisettimelevel_09_16) //时间到
{
uitimecnt_09_16=0; //时间计数器清零
if(ucleddirflag==0) //正方向
{
ucled_dr15=0; //第15个灭
ucled_dr16=1; //第16个亮
ucled_update=1; //更新显示
ucledstep_09_16=0; //返回到开始处,重新开始新的一次循环
}
else //反方向
{
ucled_dr14=1; //第14个亮
ucled_dr15=0; //第15个灭
ucled_update=1; //更新显示
ucledstep_09_16=6; //返回上一个步骤
}
}
break;
}
}
}
void t0_time() interrupt 1
{
tf0=0; //清除中断标志
tr0=0; //关中断
if(uitimecnt_09_16<0xffff) //设定这个条件,防止uitimecnt超范围。
{
if(ucledstartflag==1) //此变量为1时代表启动
{
uitimecnt_09_16++; //累加定时中断的次数,
}
}
key_scan(); //按键扫描函数
if(uivoicecnt!=0)
{
uivoicecnt--; //每次进入定时中断都自减1,直到等于零为止。才停止鸣叫
beep_dr=0; //蜂鸣器是pnp三极管控制,低电平就开始鸣叫。
// beep_dr=1; //蜂鸣器是pnp三极管控制,低电平就开始鸣叫。
}
else
{
; //此处多加一个空指令,想维持跟if括号语句的数量对称,都是两条指令。不加也可以。
beep_dr=1; //蜂鸣器是pnp三极管控制,高电平就停止鸣叫。
// beep_dr=0; //蜂鸣器是pnp三极管控制,高电平就停止鸣叫。
}
display_drive(); //数码管字模的驱动函数
th0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
tl0=0x0b;
tr0=1; //开中断
}
void delay_short(unsigned int uidelayshort)
{
unsigned int i;
for(i=0;i {
; //一个分号相当于执行一条空语句
}
}
void delay_long(unsigned int uidelaylong)
{
unsigned int i;
unsigned int j;
for(i=0;i {
for(j=0;j<500;j++) //内嵌循环的空指令数量
{
; //一个分号相当于执行一条空语句
}
}
}
void initial_myself() //第一区 初始化单片机
{
/* 注释二:
* 矩阵键盘也可以做独立按键,前提是把某一根公共输出线输出低电平,
* 模拟独立按键的触发地,本程序中,把key_gnd_dr输出低电平。
* 51学习板的s1就是本程序中用到的一个独立按键。
*/
key_gnd_dr=0; //模拟独立按键的地gnd,因此必须一直输出低电平
led_dr=0; //关闭独立led灯
beep_dr=1; //用pnp三极管控制蜂鸣器,输出高电平时不叫。
tmod=0x01; //设置定时器0为工作方式1
th0=0xfe; //重装初始值(65535-500)=65035=0xfe0b
tl0=0x0b;
}
void initial_peripheral() //第二区 初始化外围
{
ucdigdot8=0; //小数点全部不显示
ucdigdot7=0;
ucdigdot6=0;
ucdigdot5=0;
ucdigdot4=0;
ucdigdot3=0;
ucdigdot2=0;
ucdigdot1=0;
ea=1; //开总中断
et0=1; //允许定时中断
tr0=1; //启动定时中断

一起来看看9月份车用照明大事件
特斯拉来华背后大有“玄机”,新一轮外企更集中于高新技术领域
三星S8已经确认本月18号上市,想要换新机的朋友可以稍微等一下
升压式高亮度LED背光驱动电路技术设计
iOS10.3.1系统发布了,死亡率远超90%!苹果iOS10.3新增哪些功能?
如何用51单片机数码管实现跑马灯功能?
htc被收购!手机市场被蚕食殆尽被谷歌收购,会不会成为下一个诺基亚?
莱迪思宣布支持松下1080P图像传感器
聚合物锂电池常识
X1Y1安规电容的特点及应用
不得不关注的六个LED照明技术细节
全国首条智慧地下电缆线路的监控信息正式接入
助力低碳,深耕低温锡膏技术引领行业工艺发展
有哪些平价的蓝牙耳机?四款适合学生的平价蓝牙耳机推荐
冠层分析仪的作用是什么,它有哪些应用
传感器前级信号处理
UWB室内定位高精度定位应用的宠儿
ADI新数字隔离器封装确保医疗和工业应用安全
基于A2DP框架的近距离无线音频通信研究
联发科公布第三季财报 营收达670亿元并表示对AI的投入已有相当的成果