51单片机流水灯电路模型设计和编程

[复制链接]
查看66563 | 回复0 | 2024-7-17 09:24:06 | 显示全部楼层 |阅读模式

前面一课掌握了嵌入式程序源代码级调试,为复杂单片机实验程序的调试做好了准备工作。本次实验完成流水灯电路模型设计和编程,在实验过程中,学习流水灯电路设计、编写延迟函数、循环移位宏定义。



video: https://mp.weixin.qq.com/mp/readtemplate?t=pages/video_player_tmpl&action=mpvideo&auto=0&vid=wxv_2734396923331444737
流水灯电路设计

本次实验设计要求通过单片机P0口实现流水灯控制电路,P0口8个端口外接8个LED,每个LED串联一个200欧姆的限流电阻,8个限流电阻的公共端接5V直流电源。电路设计如下图所示:



8个LED正极端通过串联电阻接5V直流电源,负极端接P0端口,只要给P0端口一个低电平,就可以点亮LED,若需要熄灭LED,需要给P0端口一个高电平,要实现LED流水灯功能,只要将8个LED依次点亮、熄灭即可。
编写时间延迟函数

流水灯电路要求LED依次点亮,每个LED要持续亮一段时间后熄灭。用程序来控制LED的点亮和熄灭,只需要将与LED连接的端口写入低电平或高电平即可,代码如下:
#includevoid main(){       P0 = 0xFF;    P0 = 0xFD;}

上述代码第1条语句将P0第0位写入低电平,与第0位连接的lED被点亮,第2条语句将第0位写入高电平,与第0位连接的lED熄灭。两条语句连续执行,每条语句的执行时间非常短,也就十几微秒,LED点亮后很快被熄灭,人们通过眼睛感觉不到LED被点亮。因此需要在第1条语句和第2条语句之间进行时间延迟,延迟一段时间后再执行第2条语句。

如何用软件来模拟延时时间呢?在设计的电路模型中,51单片机的时钟频率是12MHZ,一个时钟周期约0.08微秒,一个机器周期由12个时钟周期构成,一个机器周期约1微秒,51单片机执行一个指令的时间是机器周期的倍数,若使用for循环语句来实现时间延迟,一条基本的for循环语句执行时间大约为8微秒,若延迟500毫秒,大约需要执行500*120次循环。
// 时间延迟函数void delay(unsigned int millisecond){       unsigned int i,j;       for(i=millisecond;i>0;i--)              for(j=120;j>0;j--);}

delay()函数延迟millisecond毫秒,函数使用for嵌套循环,外层for循环用于控制延迟的毫秒数,内层for循环用于控制1毫秒执行的语句次数。
循环移位

流水灯需要在每个时间间隔内只有一个LED点亮,其余LED均为熄灭状态,流水灯可以通过循环左移实现。循环左移是将操作数的二进制位按1位进行循环左移,移出的位并不会丢失,而是被后续移动的位填充。



P0默认值为0xFE,P0第0位的LED被点亮,其它位熄灭;延迟一段时间后,P0循环左移1位,其值为0xFD,P0第1位LED被点亮,其它位熄灭;延迟一段时间后,P0循环左移1位,其值为0xFB,P0第2位LED被点亮,其它位熄灭;以此类推,P0不断循环左移1位,从而实现了流水灯控制。

C语言并没有提供循环左移或循环右移的运算功能,需要开发者自己编程实现。



循环左移位的具体算法如上图所示:value为操作数,其值为0xFE,先将value左移1位,赋值给变量a,其值为0xFC,然后将value右移7位,赋值给变量b,其值为0X1,最后计算a|b,计算结果为value循环左移1位,并将计算结果赋值为value。

流水灯算法实现代码如下:
void main(){    unsigned char value=0xfe,a,b;       unsigned char count = 0;       while(1)       {                           P0 = value;              delay(5000);              a = value << 1;              b = value >> 7;              value = a | b;   count+= 1;              if( count >= 8 )              {     value = 0xfe;   count= 0;              }       }      }

算法通过while循环实现流水灯控制,在循环内部,变量value赋值给P0,点亮第0位的LED,其它位的LED为熄灭状态,然后调用delay()函数延迟5000毫秒,value循环左移1位,在下轮循环中,点亮第1位的LED,其它位的LED为熄灭状态,以此类推……。

count为计数变量,当流水灯循环点亮一次后,将value重新赋值为0xFE,并将conunt清零。

考虑到循环移位是经常使用的操作,可以将循环左移位操作定义为宏,在代码中直接调用宏就可以了。

循环左移位的宏定义:

#define ROTATE_LEFT(x) ((x) << 1) | ((x) >> 7 )

完整C程序代码如下:
#include#define ROTATE_LEFT(x) ((x) << 1) | ((x) >> 7 )void delay(unsigned int millisecond){       unsigned int i,j;       for(i=millisecond;i>0;i--)              for(j=120;j>0;j--);}void main(){    unsigned char value=0xfe,count=0;       while(1)       {              P0 = value;              delay(5000);              value = ROTATE_LEFT(value);   count+= 1;              if( count >= 8 )              {     value = 0xfe;   count= 0;              }       }      }
实验小结

通过这次实验,掌握了流水灯的电路模型设计和编程,流水灯电路模型比较简单,单片机通过I/O口的8个端口来控制8个LED的点亮和熄灭。流水灯的控制通过编程实现,编程主要涉及到时间延迟函数和循环左移位宏定义,时间延迟函数用于控制间LED点亮和熄灭的隔时间,循环左移位用于控制I/O口循环输出高电平和低电平。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册哦

x
您需要登录后才可以回帖 登录 | 注册哦

本版积分规则