学习了,感谢楼主!
程序架构清晰,注释很详细,很好的资料!
(3)源代码讲解如下:
#include "REG52.H" #define const_time_level 200 void initial_myself(); void initial_peripheral(); void delay_short(unsigned int uiDelayShort); void delay_long(unsigned int uiDelaylong); void led_flicker(); void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01); void T0_time(); //定时中断函数 /* 注释一: * 朱兆祺的学习板是用74HC595控制LED,因此可以直接把595的OE引脚接地。如果在工控中,用来控制继电器, * 那么此芯片的片选脚OE不要为了省一个IO口而直接接地,否则会引起上电瞬间继电器莫名其妙地动作。 * 为了解决这个问题,OE脚应该用一个IO口单独驱动,并且千万要记住,此IO必须接一个15K左右的 * 上拉电阻,然后在程序刚上电运行时,先把OE置高,并且尽快把所有的74HC595输出口置低,然后再把OE置低. * 当然还有另外一种解决办法,就是用一个10uF的电解电容跟一个100K的下拉电阻,组成跟51单片机外围复位电路原理 * 一样的电路,连接到OE口,这样确保上电瞬间OE口有一小段时间是处于高电平状态,在此 期间, * 尽快通过软件把74hc595的所有输出口置低。 */ sbit hc595_sh_dr=P2^3; sbit hc595_st_dr=P2^4; sbit hc595_ds_dr=P2^5; unsigned char ucLedStep=0; //步骤变量 unsigned int uiTimeCnt=0; //统计定时中断次数的延时计数器 void main() { initial_myself(); delay_long(100); initial_peripheral(); while(1) { led_flicker(); } } /* 注释二: * 两个联级74HC595的工作过程: * 每个74HC595内部都有一个8位的寄存器,两个联级起来就有两个寄存器。ST引脚就相当于一个刷新 * 信号引脚,当ST引脚产生一个上升沿信号时,就会把寄存器的数值输出到74HC595的输出引脚并且锁存起来, * DS是数据引脚,SH是把新数据送入寄存器的时钟信号。也就是说,SH引脚负责把数据送入到寄存器里,ST引脚 * 负责把寄存器的数据更新输出到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<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } ucTempData=ucLedStatusTemp08_01; //再先送低8位 for(i=0;i<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来 delay_short(15); hc595_st_dr=1; delay_short(15); hc595_sh_dr=0; //拉低,抗干扰就增强 hc595_st_dr=0; hc595_ds_dr=0; } void led_flicker() ////第三区 LED闪烁应用程序 { switch(ucLedStep) { case 0: if(uiTimeCnt>=const_time_level) //时间到 { uiTimeCnt=0; //时间计数器清零 hc595_drive(0x55,0x55); ucLedStep=1; //切换到下一个步骤 } break; case 1: if(uiTimeCnt>=const_time_level) //时间到 { uiTimeCnt=0; //时间计数器清零 hc595_drive(0xaa,0xaa); ucLedStep=0; //返回到上一个步骤 } break; } } void T0_time() interrupt 1 { TF0=0; //清除中断标志 TR0=0; //关中断 if(uiTimeCnt<0xffff) //设定这个条件,防止uiTimeCnt超范围。 { uiTimeCnt++; //累加定时中断的次数, } TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; TR0=1; //开中断 } void delay_short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i<uiDelayShort;i++) { ; //一个分号相当于执行一条空语句 } } void delay_long(unsigned int uiDelayLong) { unsigned int i; unsigned int j; for(i=0;i<uiDelayLong;i++) { for(j=0;j<500;j++) //内嵌循环的空指令数量 { ; //一个分号相当于执行一条空语句 } } } void initial_myself() //第一区 初始化单片机 { TMOD=0x01; //设置定时器0为工作方式1 TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; } void initial_peripheral() //第二区 初始化外围 { EA=1; //开总中断 ET0=1; //允许定时中断 TR0=1; //启动定时中断 }
这节讲了74HC595的驱动程序,它是一次控制16个LED同时亮灭的,在实际中应用不太方便,如果我们想要像单片机IO口直接控制LED那样方便,我们该怎么编写程序呢?欲知详情,请听下回分解-----把74HC595驱动程序翻译成类似单片机IO口直接驱动的方式。
(3)源代码讲解如下:
#include "REG52.H" #define const_time_level 200 void initial_myself(); void initial_peripheral(); void delay_short(unsigned int uiDelayShort); void delay_long(unsigned int uiDelaylong); void led_flicker(); void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01); void led_update(); //LED更新函数 void T0_time(); //定时中断函数 sbit hc595_sh_dr=P2^3; sbit hc595_st_dr=P2^4; sbit hc595_ds_dr=P2^5; 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=0; //步骤变量 unsigned int uiTimeCnt=0; //统计定时中断次数的延时计数器 unsigned char ucLedStatus16_09=0; //代表底层74HC595输出状态的中间变量 unsigned char ucLedStatus08_01=0; //代表底层74HC595输出状态的中间变量 void main() { initial_myself(); delay_long(100); initial_peripheral(); while(1) { led_flicker(); led_update(); //LED更新函数 } } /* 注释一: * 把74HC595驱动程序翻译成类似单片机IO口直接驱动方式的过程。 * 每次更新LED输出,记得都要把ucLed_update置1表示更新。 */ 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 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<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } ucTempData=ucLedStatusTemp08_01; //再先送低8位 for(i=0;i<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来 delay_short(15); hc595_st_dr=1; delay_short(15); hc595_sh_dr=0; //拉低,抗干扰就增强 hc595_st_dr=0; hc595_ds_dr=0; } void led_flicker() ////第三区 LED闪烁应用程序 { switch(ucLedStep) { case 0: if(uiTimeCnt>=const_time_level) //时间到 { uiTimeCnt=0; //时间计数器清零 ucLed_dr1=1; //每个变量都代表一个LED灯的状态 ucLed_dr2=0; ucLed_dr3=1; ucLed_dr4=0; ucLed_dr5=1; ucLed_dr6=0; ucLed_dr7=1; ucLed_dr8=0; ucLed_dr9=1; ucLed_dr10=0; ucLed_dr11=1; ucLed_dr12=0; ucLed_dr13=1; ucLed_dr14=0; ucLed_dr15=1; ucLed_dr16=0; ucLed_update=1; //更新显示 ucLedStep=1; //切换到下一个步骤 } break; case 1: if(uiTimeCnt>=const_time_level) //时间到 { uiTimeCnt=0; //时间计数器清零 ucLed_dr1=0; //每个变量都代表一个LED灯的状态 ucLed_dr2=1; ucLed_dr3=0; ucLed_dr4=1; ucLed_dr5=0; ucLed_dr6=1; ucLed_dr7=0; ucLed_dr8=1; ucLed_dr9=0; ucLed_dr10=1; ucLed_dr11=0; ucLed_dr12=1; ucLed_dr13=0; ucLed_dr14=1; ucLed_dr15=0; ucLed_dr16=1; ucLed_update=1; //更新显示 ucLedStep=0; //返回到上一个步骤 } break; } } void T0_time() interrupt 1 { TF0=0; //清除中断标志 TR0=0; //关中断 if(uiTimeCnt<0xffff) //设定这个条件,防止uiTimeCnt超范围。 { uiTimeCnt++; //累加定时中断的次数, } TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; TR0=1; //开中断 } void delay_short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i<uiDelayShort;i++) { ; //一个分号相当于执行一条空语句 } } void delay_long(unsigned int uiDelayLong) { unsigned int i; unsigned int j; for(i=0;i<uiDelayLong;i++) { for(j=0;j<500;j++) //内嵌循环的空指令数量 { ; //一个分号相当于执行一条空语句 } } } void initial_myself() //第一区 初始化单片机 { TMOD=0x01; //设置定时器0为工作方式1 TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; } void initial_peripheral() //第二区 初始化外围 { EA=1; //开总中断 ET0=1; //允许定时中断 TR0=1; //启动定时中断 }
总结陈词:
(3)源代码讲解如下:
#include "REG52.H" #define const_time_level_01_08 200 //第1个至第8个LED跑马灯的速度延时时间 void initial_myself(); void initial_peripheral(); void delay_short(unsigned int uiDelayShort); void delay_long(unsigned int uiDelaylong); void led_flicker_01_08(); // 第1个至第8个LED的跑马灯程序,逐个亮,逐个灭. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01); void led_update(); //LED更新函数 void T0_time(); //定时中断函数 sbit hc595_sh_dr=P2^3; sbit hc595_st_dr=P2^4; sbit hc595_ds_dr=P2^5; 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_01_08=0; //第1个至第8个LED跑马灯的步骤变量 unsigned int uiTimeCnt_01_08=0; //第1个至第8个LED跑马灯的统计定时中断次数的延时计数器 unsigned char ucLedStatus16_09=0; //代表底层74HC595输出状态的中间变量 unsigned char ucLedStatus08_01=0; //代表底层74HC595输出状态的中间变量 void main() { initial_myself(); delay_long(100); initial_peripheral(); while(1) { led_flicker_01_08(); // 第1个至第8个LED的跑马灯程序,逐个亮,逐个灭. led_update(); //LED更新函数 } } 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 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<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } ucTempData=ucLedStatusTemp08_01; //再先送低8位 for(i=0;i<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来 delay_short(15); hc595_st_dr=1; delay_short(15); hc595_sh_dr=0; //拉低,抗干扰就增强 hc595_st_dr=0; hc595_ds_dr=0; } /* 注释一: * 以下程序,看似简单而且重复,其实蕴含着鸿哥的大智慧。 * 它是基于鸿哥的switch状态机思想,领略到了它的简单和精髓, * 以后任何所谓复杂的工程项目,都不再复杂。 */ void led_flicker_01_08() //第1个至第8个LED的跑马灯程序,逐个亮,逐个灭. { switch(ucLedStep_01_08) { case 0: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr1=1; //第1个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=1; //切换到下一个步骤 } break; case 1: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr2=1; //第2个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=2; //切换到下一个步骤 } break; case 2: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr3=1; //第3个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=3; //切换到下一个步骤 } break; case 3: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr4=1; //第4个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=4; //切换到下一个步骤 } break; case 4: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr5=1; //第5个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=5; //切换到下一个步骤 } break; case 5: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr6=1; //第6个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=6; //切换到下一个步骤 } break; case 6: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr7=1; //第7个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=7; //切换到下一个步骤 } break; case 7: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr8=1; //第8个亮 ucLed_update=1; //更新显示 ucLedStep_01_08=8; //切换到下一个步骤 } break; case 8: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr8=0; //第8个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=9; //切换到下一个步骤 } break; case 9: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr7=0; //第7个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=10; //切换到下一个步骤 } break; case 10: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr6=0; //第6个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=11; //切换到下一个步骤 } break; case 11: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr5=0; //第5个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=12; //切换到下一个步骤 } break; case 12: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr4=0; //第4个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=13; //切换到下一个步骤 } break; case 13: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr3=0; //第3个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=14; //切换到下一个步骤 } break; case 14: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr2=0; //第2个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=15; //切换到下一个步骤 } break; case 15: if(uiTimeCnt_01_08>=const_time_level_01_08) //时间到 { uiTimeCnt_01_08=0; //时间计数器清零 ucLed_dr1=0; //第1个灭 ucLed_update=1; //更新显示 ucLedStep_01_08=0; //返回到最开始处,重新开始新的一次循环。 } break; } } void T0_time() interrupt 1 { TF0=0; //清除中断标志 TR0=0; //关中断 if(uiTimeCnt_01_08<0xffff) //设定这个条件,防止uiTimeCnt超范围。 { uiTimeCnt_01_08++; //累加定时中断的次数, } TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; TR0=1; //开中断 } void delay_short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i<uiDelayShort;i++) { ; //一个分号相当于执行一条空语句 } } void delay_long(unsigned int uiDelayLong) { unsigned int i; unsigned int j; for(i=0;i<uiDelayLong;i++) { for(j=0;j<500;j++) //内嵌循环的空指令数量 { ; //一个分号相当于执行一条空语句 } } } void initial_myself() //第一区 初始化单片机 { TMOD=0x01; //设置定时器0为工作方式1 TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; } void initial_peripheral() //第二区 初始化外围 { EA=1; //开总中断 ET0=1; //允许定时中断 TR0=1; //启动定时中断 }
总结陈词:
(3)源代码讲解如下:
#include "REG52.H" #define const_time_level_09_16 300 //第9个至第16个LED跑马灯的速度延时时间 void initial_myself(); void initial_peripheral(); void delay_short(unsigned int uiDelayShort); void delay_long(unsigned int uiDelaylong); void led_flicker_09_16(); // 第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个. void hc595_drive(unsigned char ucLedStatusTemp16_09,unsigned char ucLedStatusTemp08_01); void led_update(); //LED更新函数 void T0_time(); //定时中断函数 sbit hc595_sh_dr=P2^3; sbit hc595_st_dr=P2^4; sbit hc595_ds_dr=P2^5; 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输出状态的中间变量 void main() { initial_myself(); delay_long(100); initial_peripheral(); while(1) { led_flicker_09_16(); // 第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个. led_update(); //LED更新函数 } } 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 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<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } ucTempData=ucLedStatusTemp08_01; //再先送低8位 for(i=0;i<8;i++) { if(ucTempData>=0x80)hc595_ds_dr=1; else hc595_ds_dr=0; hc595_sh_dr=0; //SH引脚的上升沿把数据送入寄存器 delay_short(15); hc595_sh_dr=1; delay_short(15); ucTempData=ucTempData<<1; } hc595_st_dr=0; //ST引脚把两个寄存器的数据更新输出到74HC595的输出引脚上并且锁存起来 delay_short(15); hc595_st_dr=1; delay_short(15); hc595_sh_dr=0; //拉低,抗干扰就增强 hc595_st_dr=0; hc595_ds_dr=0; } /* 注释一: * 以下程序,看似简单而且重复,其实蕴含着鸿哥的大智慧。 * 它是基于鸿哥的switch状态机思想,领略到了它的简单和精髓, * 以后任何所谓复杂的工程项目,都不再复杂。 */ void led_flicker_09_16() //第9个至第16个LED的跑马灯程序,逐个亮并且每次只能亮一个. { switch(ucLedStep_09_16) { case 0: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr16=0; //第16个灭 ucLed_dr9=1; //第9个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=1; //切换到下一个步骤 } break; case 1: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr9=0; //第9个灭 ucLed_dr10=1; //第10个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=2; //切换到下一个步骤 } break; case 2: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr10=0; //第10个灭 ucLed_dr11=1; //第11个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=3; //切换到下一个步骤 } break; case 3: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr11=0; //第11个灭 ucLed_dr12=1; //第12个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=4; //切换到下一个步骤 } break; case 4: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr12=0; //第12个灭 ucLed_dr13=1; //第13个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=5; //切换到下一个步骤 } break; case 5: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr13=0; //第13个灭 ucLed_dr14=1; //第14个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=6; //切换到下一个步骤 } break; case 6: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr14=0; //第14个灭 ucLed_dr15=1; //第15个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=7; //切换到下一个步骤 } break; case 7: if(uiTimeCnt_09_16>=const_time_level_09_16) //时间到 { uiTimeCnt_09_16=0; //时间计数器清零 ucLed_dr15=0; //第15个灭 ucLed_dr16=1; //第16个亮 ucLed_update=1; //更新显示 ucLedStep_09_16=0; //返回到开始处,重新开始新的一次循环 } break; } } void T0_time() interrupt 1 { TF0=0; //清除中断标志 TR0=0; //关中断 if(uiTimeCnt_09_16<0xffff) //设定这个条件,防止uiTimeCnt超范围。 { uiTimeCnt_09_16++; //累加定时中断的次数, } TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; TR0=1; //开中断 } void delay_short(unsigned int uiDelayShort) { unsigned int i; for(i=0;i<uiDelayShort;i++) { ; //一个分号相当于执行一条空语句 } } void delay_long(unsigned int uiDelayLong) { unsigned int i; unsigned int j; for(i=0;i<uiDelayLong;i++) { for(j=0;j<500;j++) //内嵌循环的空指令数量 { ; //一个分号相当于执行一条空语句 } } } void initial_myself() //第一区 初始化单片机 { TMOD=0x01; //设置定时器0为工作方式1 TH0=0xf8; //重装初始值(65535-2000)=63535=0xf82f TL0=0x2f; } void initial_peripheral() //第二区 初始化外围 { EA=1; //开总中断 ET0=1; //允许定时中断 TR0=1; //启动定时中断 }
总结陈词:
有奖活动 | |
---|---|
【有奖活动】分享技术经验,兑换京东卡 | |
话不多说,快进群! | |
请大声喊出:我要开发板! | |
【有奖活动】EEPW网站征稿正在进行时,欢迎踊跃投稿啦 | |
奖!发布技术笔记,技术评测贴换取您心仪的礼品 | |
打赏了!打赏了!打赏了! |