知识点回顾
<<:左移符号
.>>:右移符号
~:取反符号
思路:
a = 0x01<<1;就是a的结果等于0x01左移一位。需要注意的是,左移是指二进制移位,移位后低位(或高位)是要补0的。举个左移流水灯的例子,要使流水灯向左依次流动,则有代码:
下面展示一些
内联代码片
。
// 左移时流水灯P0口设置,cnt为从0开始逐渐递增的左移的位数,
//等下会贴一整段代码
P0 = ~(0x01 << cnt);
我们来解析一下这个代码的意思,先从括号里面看,0x01是十六位进制的数,化成二进制为:0000 0001,。当cnt = 1时,即左移一位后,变为000 0 0010,然后取反符号后其变为111 1 1101。根据低电平有效,等于0那个小灯亮了,及第二个小灯亮了。同理可得第三个小灯为:11 11 1011,后面以此类推。
左移代码:
//左移
while(1){
P0 = ~(0x01 << cnt); //0000 0001 左移后:000 0 0010 取反:111 1 1101 低电平亮
for(i= 0; i<30000; i++);
cnt++;
if(cnt >=8){
cnt = 0;
}
}
右移代码:
//右移
while(1){
P0 = ~(0x80 >> cnt); // 1000 0000 右移后: 01000 000 取反: 10111 111
for(i=0; i<30000; i++);
cnt++;
if(cnt >=8){
cnt = 0;
}
}
不精确时间的先左移后右移代码:
注:首先要先在前面定义flag: unsigned int flag = 0;
用除余的方法来先左后右。第一遍时flag = 0,除以2余等于0则进入左移的条件。第二遍时flag自加后等于1,除以2余不等于0,则进入右移条件。
while(1){
if(flag %2 == 0){
P0 = ~(0x01 << cnt); //流水灯左移
}
else{
P0 = ~(0x80 >> cnt); //流水灯右移
}
for(i=0; i<30000;i++); //闪烁
cnt++; //灯进行左(右)移
if(cnt >= 8){
cnt = 0;
flag++; //第二遍后flag+1, 取余不是零,则变成右移方向;
}
}
用定时器精确时间的先左移后右移代码:
首先要先在前面打开定时器:
TMOD = 0;
TH0 = 0xB8;
TL0 = 0x00;
TR0 = 1;
运行的程序代码为:
//用定时器来实现左右流水灯循环
while(1){
if(TF0 == 1){ //判断T0是否溢出,溢出一次换算得0.02秒
TF0 = 0; //定时器控制0.02秒
TH0 = 0xB8;
TL0 = 0x00;
count++; //溢出次数
if(count >= 50){ //0.02乘以50等于1秒,每隔一秒点亮一个流水灯
count = 0;
if(flag %2 == 0){
P0 = ~(0x01 << cnt); //进行左移
}else{
P0 = ~(0x80 >> cnt); //进行右移
}
cnt++; //左(右)移几个单位数
if(cnt >= 8){
cnt = 0;
flag++; //第二遍后flag+1, 取余不是零,则变成右移方向;
}
}
}
}
}
全部代码:
注:因上面只能看到某部分代码,某些定义没有给出,故放出整体代码,方便易于理解:
#include<reg52.h>
sbit ENLED = P1^4; //使能74HC138
sbit ADDR3 = P1^3;
sbit ADDR2 = P1^2;
sbit ADDR1 = P1^1;
sbit ADDR0 = P1^0;
void main(){
unsigned int i = 0;
unsigned int cnt = 0;
unsigned int flag = 0;
unsigned int count = 0;
ENLED = 0; //使能
ADDR3 = 1;
ADDR2 = 1; //110 ,打开控制流水灯的三极管LEDS6,使其导通
ADDR1 = 1;
ADDR0 = 0;
TMOD = 0;
TH0 = 0xB8;
TL0 = 0x00;
TR0 = 1;
//左移流水灯
while(1){
P0 = ~(0x01 << cnt); //0000 0001 左移后:000 0 0010 取反:111 1 1101 低电平亮
for(i= 0; i<30000; i++);
cnt++;
if(cnt >=8){
cnt = 0;
}
}
//右移流水灯
while(1){
P0 = ~(0x80 >> cnt); // 1000 0000 右移后: 01000 000 取反: 10111 111
for(i=0; i<30000; i++);
cnt++;
if(cnt >=8){
cnt = 0;
}
}
//先左移,后右移。左移时第一遍为0,除余后为0,则执行左移,第二遍时为1,除余后不是零则执行右移。同理可以继续下去
while(1){
if(flag %2 == 0){
P0 = ~(0x01 << cnt); //流水灯左移
}
else{
P0 = ~(0x80 >> cnt); //流水灯右移
}
for(i=0; i<30000;i++); //闪烁
cnt++; //左(右)移
if(cnt >= 8){
cnt = 0;
flag++; //第二遍后flag+1, 取余不是零,则变成右移方向;
}
}
//用定时器来实现左右流水灯循环
while(1){
if(TF0 == 1){
TF0 = 0; //定时器控制0.02秒
TH0 = 0xB8;
TL0 = 0x00;
count++;
if(count >= 50){ //0.02乘以50等于1秒
count = 0;
if(flag %2 == 0){
P0 = ~(0x01 << cnt);
}else{
P0 = ~(0x80 >> cnt);
}
cnt++;
if(cnt >= 8){
cnt = 0;
flag++; //第二遍后flag+1, 取余不是零,则变成右移方向;
}
}
}
}
}