问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

51单片机流水灯实现与代码优化详解

创作时间:
作者:
@小白创作中心

51单片机流水灯实现与代码优化详解

引用
1
来源
1.
https://blog.dotcpp.com/course/185

本教程将详细介绍如何使用51单片机的P0口控制8个LED实现流水灯效果。通过具体的二进制和十六进制转换示例,帮助读者理解流水灯的工作原理,并提供完整的代码实现及优化方案。

本讲讲解用P0的8个IO端口控制8盏LED实现流水灯。
本教程所用开发板的硬件连接简化如下

1.数字模拟点灯

我们用八位的二进制数表示八盏灯,对应的位为0灯就亮,为1灯就灭。
流水灯的实现如下所示
11111110 //对应十六进制=0xFE,P0.0输出0,其余输出1
11111101 //对应十六进制=0xFD,P0.1输出0,其余输出1
11111011 //对应十六进制=0xFB,P0.2输出0,其余输出1
11110111 //对应十六进制=0xF7,P0.3输出0,其余输出1
11101111 //对应十六进制=0xEF,P0.4输出0,其余输出1
11011111 //对应十六进制=0xDF,P0.5输出0,其余输出1
10111111 //对应十六进制=0xBF,P0.6输出0,其余输出1
01111111 //对应十六进制=0xF7,P0.7输出0,其余输出1
11111110
11111101
......

2.流水灯代码

这里一次性控制8个IO端口就不需要sbit去定义单个IO端口了(请前去复习本章第二讲),有了之前章节的基础,代码的实现就不难了

#include <reg52.h> 
//sbit LED2 = P0^0; 本节代码中用不到这条语句了
sbit ADDR2 = P1^2;
sbit ADDR1 = P1^1;
sbit ADDR0 = P1^0;
sbit ENLED = P1^4;
sbit ADDR3 = P1^3;
void delay_ms(unsigned int x)
{
 unsigned int i,j;
 if(x==1000)
 {
 for(i=0;i<19601;i++)//延时1s
 {
 for(j=5;j>0;j--);
 }
 }
 else while(x--)for(j=115;j>0;j--);
}
void main()
{ 
 ADDR3 = 1;//使能三八译码器
 ENLED = 0;// 
 ADDR2 = 1;//**************************
 ADDR1 = 1;//让三八译码器的IO6输出低电平
 ADDR0 = 0;//**************************
 while(1)
 {
 P0 = 0xFE; 
 delay_ms(100);// 大概延时一段时间 
 P0 = 0xFD; 
 delay_ms(100);
 P0 = 0xFB; 
 delay_ms(100); 
 P0 = 0xF7; 
 delay_ms(100);
 P0 = 0xEF; 
 delay_ms(100); 
 P0 = 0xDF; 
 delay_ms(100);
 P0 = 0xBF; 
 delay_ms(100); 
 P0 = 0x7F; 
 delay_ms(100);
 }
}

3.代码优化

为了让大家第一次了解switch语句在单片机程序中的运用(《手把手教你学51单片机》文档6.3节有介绍语句用法),我们用switch语句让代码显得整齐一些,且不需要重复书写“delay_ms(100);”,实现了书写上的优化,避免占据过多版面,修改主函数如下

void main()
{ 
 unsigned char i=1;//定义新的变量用来轮流调用不同的case语句
 ADDR3 = 1;//使能三八译码器
 ENLED = 0;// 
 ADDR2 = 1;//**************************
 ADDR1 = 1;//让三八译码器的IO6输出低电平
 ADDR0 = 0;//**************************
 while(1)
 {
 switch(i)
 { 
 case 1: P0 = 0xFE; break;
 case 2: P0 = 0xFD; break;
 case 3: P0 = 0xFB; break; 
 case 4: P0 = 0xF7; break;
 case 5: P0 = 0xEF; break; 
 case 6: P0 = 0xDF; break;
 case 7: P0 = 0xBF; break; 
 case 8: P0 = 0x7F; i=0; break;//i归0使语句又从case 1执行
 } 
 i++;//i从1变到8使switch语句轮流调用“P0 = xxxx;”
 delay_ms(100);
 }
}

4.提醒

这里提及一下,在“delay_ms();”函数里有变量名i,主函数中也有同样的变量名i,但这两个相同名字的变量都是局部变量(文档7.1节有简单讲解),两个相同名字的变量各自占有独立的内存,不受各自的值变化而影响到另一个值,C语言基础知识普及。
在主函数中我们定义i为unsigned char类型是为了节约RAM内存,毕竟主函数里的i我们只需要它在1~8之间变化,不用超过255(文档4.2节有普及数据类型)。还有大家别忘了case语句结尾记得加“break;”防止程序一次性从“case 1”执行到“case 8”都没有去实现延时那部分,大家可尝试把8个“break;”都去掉,然后编译下载进开发板看会有什么现象?

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号