历史上的今天
今天是:2025年03月09日(星期日)
2020年03月09日 | 51单片机入门教程(2)——实现流水灯
2020-03-09 来源:eefocus
一、搭建流水灯电路
在Proteus中搭建流水灯电路如图

二、流水灯程序
我们可以把流水灯看作依次点亮若干个灯。
程序如下:
#include sbit led1 = P2^0; sbit led2 = P2^1; sbit led3 = P2^2; sbit led4 = P2^3; sbit led5 = P2^4; sbit led6 = P2^5; sbit led7 = P2^6; sbit led8 = P2^7; void main() { //点亮第一个灯 led1 = 1; led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //点亮第二个灯 led1 = 0; led2 = 1; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //点亮剩余的灯 //省略…… while(1); } 编译并下载程序到仿真中,观察现象发现只有第二个灯是亮的??? 什么鬼??? 2.1 延时程序 单片机的执行指令速度非常快,一个晶振是12MHz的单片机执行一条指令的速度是微秒级的,所以点亮第一个灯的时间太短了,以至于我们根本没有察觉。 因此我们需要一个延时的语句。 实现延时的方法就是循环执行很多次空指令。程序如下: //延时一秒的程序 int i,j; for(i = 0;i < 110; ++i) { for(j = 0; j < 1000; ++j) { ;//什么也不做 } } 然后我们就可以把流水灯的程序改成这样的: #include sbit led1 = P2^0; sbit led2 = P2^1; sbit led3 = P2^2; sbit led4 = P2^3; sbit led5 = P2^4; sbit led6 = P2^5; sbit led7 = P2^6; sbit led8 = P2^7; void main() { int i,j; //点亮第一个灯 led1 = 1; led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //延时1秒 for(i = 0;i < 110; ++i) { for(j = 0; j < 1000; ++j) { ;//什么也不做 } } //点亮第二个灯 led1 = 0; led2 = 1; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //点亮剩余的灯 //省略…… while(1); } 编译并下载程序到仿真中,观察现象发现首先第一个灯亮,过了一会儿第二个灯亮。 2.2 延时函数 我们剩下的任务就是依次点亮每个灯,但是每次点亮一个灯就需要写一段延时程序,很麻烦! 为了程序的可读性(toulan),可以把延时程序写成一个子函数,随时供我们使用。 C语言中子函数的定义方式如下 返回值类型 函数名 (参数1,参数2,……) { 函数体; } 这样我们就可以把延时函数写成这样: void delay1s() { int i,j; for(i = 0; i<110;++i) { for(j = 0; j<1000;++j) { //什么也不做 } } } 几点说明: void:因为该延时函数不需要返回值,所以写为void delay1s:该函数的函数名,命名需要符合C语言的标识符命名规则。 (): 不需要传入参数,所以括号中为空 至此我们可以把流水灯程序写为以下形式: #include sbit led1 = P2^0; sbit led2 = P2^1; sbit led3 = P2^2; sbit led4 = P2^3; sbit led5 = P2^4; sbit led6 = P2^5; sbit led7 = P2^6; sbit led8 = P2^7; //延时1s void delay1s() { int i ,j; for(i = 0;i<110; ++i){ for(j = 0;j<1000;++j){ ; } } } void main() { //点亮第一个灯 led1 = 1; led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //延时1s delay1s(); //点亮第二个灯 led1 = 0; led2 = 1; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; //点亮剩余的灯 //省略…… while(1); } 2.3 按字节寻址 我们可以看到,上面的代码十分冗长,每次点亮一个灯需要8条语句,那么如何简化? 比如把 led1 = 1;led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; 这8条语句替代为P2 = 0000 0001??? 答案是可以的。代码如下 unsigned char a = 0x01; //0x01是0000 0001的16进制形式 P2 = a;//相当于led1 = 1;led2 = 0; led3 = 0; led4 = 0; led5 = 0; led6 = 0; led7 = 0; led8 = 0; 至此,我们可以把流水的代码优化为如下形式: #include //延时1s void delay1s() { int i ,j; for(i = 0;i<110; ++i){ for(j = 0;j<1000;++j){ ; } } } void main() { unsigned char a1 = 0x01 ; // 0000 0001 unsigned char a2 = 0x02; // 0000 0010 //点亮第一个灯 P2 = a1; //延时1s delay1s(); //点亮第二个灯 P2 = a2; //点亮剩余的灯 //省略…… while(1); } 2.4 逻辑移位 依次点亮8个灯,每点亮一个灯都需要一句赋值语句还是很麻烦 。 所以可以使用逻辑移位语句,每次赋值后,将数值左移一位。 C语言逻辑左移代码如下: unsigned char a = 0x01; //a = 0000 0001 unsigned char b = a<<1; // b = 0000 0010 usingned char c = a<<3; //c = 0000 1000 至此,我们可以把流水灯的代码优化如下: #include //延时1s void delay1s() { int i ,j; for(i = 0;i<110; ++i){ for(j = 0;j<1000;++j){ ; } } } void main() { //初始化 unsigned char a = 0x01; while(1) { //循环点亮流水灯 P2 = a; a = a<<1; delay1s(); } } 编译并下载程序到仿真中,观察现象发现8个灯依次亮过之后不再亮了。 2.5 条件判断 因为在移位操作中,当变量a的值为1000 0000时,再次执行左移操作,a 中的1就溢出了,因此a的值变为0000 0000,此时我们需要加一个判断,使a再次恢复为0000 0001 C语言中,if条件判断使用方式如下 if(判断条件) { //语句 } 当判断条件为真时,执行{ }中的语句。 至此,流水灯代码可改成如下形式: #include //延时1s void delay1s() { int i ,j; for(i = 0;i<110; ++i){ for(j = 0;j<1000;++j){ ; } } } void main() { unsigned char a = 0x01; while(1) { if(a == 0x00) //如果高位溢出 { a = 0x01; //则恢复 } //循环点亮led灯 P2 = a; a = a<<1; delay1s(); } }
下一篇:1课:单片机简叙
史海拾趣
|
随着应用的不断扩展,今天和未来的单片机普及和车辆网络正在继续。单片机是车辆内各种电子控制模块的“大脑”,而网络则是“系统互连”。本地互连网络(LIN)是业界第一个提出车内Class A开放多路复用协议标准。它定义了一个支持车辆内 ...… 查看全部问答> |
|
程序中有两个任务,分别是收和发,收的优先级高。在接收到特写的数据后,用msgQSend()转向发任务进行相关处理。但是在发任务中又需要收任务提供一些支持,比如发了一定的数据包后需要对方回应,而这个回应是收任务处理的,收到回应后发任务才能 ...… 查看全部问答> |
|
呵呵,如果哪位见识过DSP Builder高级库的朋友想必会它的功能折服!大概提供了几十个demos涵盖很多领域,几乎每个例子都可以自动生成一个用户IP下面是利用DSP Builder自动生成NCO设计的IP… 查看全部问答> |
|
【连载】【ALIENTEK 战舰STM32开发板】STM32开发指南--第三十八章 PS2鼠标实验 第三十八章 PS2鼠标实验 PS/2作为电脑的标准输入接口,用于鼠标键盘等设备。PS/2只需要一个简单的接口(2个IO口),就可以外扩鼠标、键盘等,是单片机理想的输入外扩方式。ALIENTEK战舰STM32开发板也自带了一个PS/2接口,可以用来驱动标 ...… 查看全部问答> |
|
手里有一块28335的板子和一个前辈留下的仿真器,各个地方都找遍了就是找不到驱动程序,求各位大侠出手相助。 我的系统是WIN7 32位,已装好CCS3.3。用过的大侠能把驱动发我邮箱么..mashaokang1111@163.com。谢谢啊! [ 本帖最后由 mashaokang 于 20 ...… 查看全部问答> |




