51单片机学习记录(3)
实现流水灯的几种方式
方式1: 利用左移(<<)和右移(>>)
首先简单介绍左移和右移的基本知识(不考虑特殊况)
- 左移:对传来的数据翻译成二进制后,将数据的每一位的值向左移动指定位数,丢失的位数用0补充
- 右移:对传来的数据翻译成二进制后,将数据的每一位的值向右移动指定位数,丢失的位数用0补充
下面简单的通过例子来说明
数据 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
---|---|---|---|---|---|---|---|---|
左移2位 | 0 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
右移2位 | 1 | 1 | 1 | 1 | 1 | 0 | 0 | 0 |
那么如何利用左移和右移来实现流水效果呢?
我们知道可以对整个P2引脚赋值来点亮LED,而加上左移和右移的操作,引起每一个灯电平的变化,流水效果就是基于此来实现的
LED | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
---|---|---|---|---|---|---|---|---|
P2口 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
赋值 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
左移1位 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
可以看到第八个led 灯的引脚变成了低电平被点亮而其他灯的引脚都为高电平都熄灭,依次下去就能实现流水的效果。当然你需要利用一下延时函数,否则现象不明显,因为代码运行的速度非常的快。
#include <reg51.h>
typedef unsigned char u8;
typedef unsigned int u16;
#define P2 led //宏定义P2口
void delay(u16 i)
{
while(i--);
}
void main()
{
led = 0xfe; //先点亮第一个灯,然后再进入循环
while(1)
{
led = led >> 1; //每次左移一位
delay(1000); //延时1s
}
}
当然你也可以进行右移的操作,方法和上面是差不多的
但是上述的程序并不能一直让灯循环的流水,当左移的效果完成后所有灯状态都被点亮也不会在改变所以可以在此程序的基础上加上一条控制语句就能让led循环亮灭。
#include <reg51.h>
typedef unsigned char u8;
typedef unsigned int u16;
#define led P2 //宏定义P2口
void delay(u16 i)
{
while(i--);
}
void main()
{
led = 0xfe; //先点亮第一个灯,然后再进入循环
while(1)
{
led = led << 1; //每次左移一位
delay(1000); //延时1s
if(led == 0)
{
led = 0xff;
delay(1000);
}
/*如果灯处于全亮的状态(0相当于0x00也就是灯的每个引脚都是低电平)
让灯全部熄灭,然后在不断的进行移位的操作,达成循环亮
*/
}
}
方式2:利用<intrins.h>里的左移函数和右移函数
- 左移函数: _cror_(a,b )
- 右移函数: _crol_(a,b )
其中a表示 需要操作的对象, b表示 每次需要移动的次数 举个例子
LED | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
---|---|---|---|---|---|---|---|---|
P2口 | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
赋值 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 0 |
第一次_cror_(P2,1)后 | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
第二次_cror_(P2,1)后 | 1 | 0 | 1 | 1 | 1 | 1 | 1 | 1 |
第三次_cror_(P2,1)后 | 1 | 1 | 0 | 1 | 1 | 1 | 1 | 1 |
依次类推,右移函数也是同样的道理,可见使用位移函数同样也是依次点亮但不同于普通的位移,位移函数依次点亮led灯的同时也会让先前亮的灯熄灭
#include <reg51.h>
#include <intrins.h>
#define led P2
typedef unsigned char u8;
typedef unsigned int u16;
void delay(u16 i )
{
while(i--);
}
void main()
{
u8 i; // 定义一个临时变量,用来控制for循环的次数
led = 0xfe; //先让一盏灯亮起
delay(1000) //延时一会在进入for循环,让现象明显点
/*进入for循环后灯先从左向右依次点亮,接着再从右向左依次点亮不断循环*/
for(i=0;i<7;++i)
{
led = _cror_(led,1);
delay(1000);
}
for(i=0;i<7;++i)
{
led = _crol_(led,1);
delay(1000);
}
}
最后,我们也可以通过改变延时的时间以及位移的位数来实现许多不一样的效果