上次課布置的流水燈實驗,硬件上我們用8根導(dǎo)線分別將P1口的第0腳接到第0個燈,第1腳接到第1個燈,以此類推,直到將第7腳接到第7個燈上。軟件上相信大家能想到的最簡單的辦法是先將第0個燈點亮,延時,再將1個燈點亮,再延時,依次類推直到將第7個燈點亮,延時,再將上面的步驟無限的循環(huán)執(zhí)行,代碼如下:
#include <reg51.h>
void main()
{
unsigned int i;
while(1)
{
P1=0xFE;
//11111110B 第0個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xFD;
//11111101B 第1個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xFB;
//11111011B 第2個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xF7;
//11110111B 第3個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xEF;
//11101111B 第4個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xDF;
//11011111B 第5個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0xBF;
//10111111B 第6個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
P1=0x7E;
//01111111B 第7個燈亮,其他的燈滅
for(i=0;i<=10000;i++); //延時
}
}
將上面的程序我們編譯下載到單片機中運行,我們看到了LED燈依次點亮的流水燈效果。我們來分析一下上面的程序的還能不能優(yōu)化。
我們發(fā)現(xiàn)點亮每個燈的語句都差不多,都是給P1賦值,然后延時,我們能不能用循環(huán)來做呢?能否用循環(huán)來做,取決于點亮每個燈的語句中不同部分是否有規(guī)律,若有規(guī)律我們就能用循環(huán)來寫。我們發(fā)現(xiàn)從第0個燈到第7個燈點亮賦的值不同,這些值程序中使用的是16進制形式,看不出規(guī)律,但我們分析這些值的二進制(見上面程序的注釋部分),發(fā)現(xiàn)每次賦的值是將上次賦的值循環(huán)左移了一下,初始值為0xFE,那我們有沒有循環(huán)左移操作符呢?匯編語言中有循環(huán)左移指令,這里我們不做介紹,那C51中有循環(huán)移位運算符嗎?答案是否定的。我們直接能想到的是C語言中有“<<”(左移)和“>>”(右移)運算符。下面我們詳細復(fù)習(xí)一下這個運算符的使用。
1、“<<”(左移)
“<<”表達式的形式是:操作數(shù)<<n,意思是將操作數(shù)按二進制的形式,每位向左移n位,最右邊空出來的n位統(tǒng)一全補0。例如0xFE<<1結(jié)果是多少呢?我們先把0xFE寫成二進制形式111111110B,左移一位后得到11111100B,最后的結(jié)果是0xFA。
2、“>>”(右移)
“>>”表達式的形式是:操作數(shù)<<n,意思是將操作數(shù)按二進制的形式,每位向右移n>>位,這里要注意最左邊空出來的n位,若操作數(shù)是無符號數(shù)則補0,若操作數(shù)是有符號數(shù)則>>補符號位。例如:
unsignedchar x=0xFE;
x=x>>1;
上面的語句x定義的是無符號字符型,x的初始值寫成二進制是111111110B,x>>1后x的值為01111111B,空出的最高位補的是0。但若是下面的語句結(jié)果就不一樣了。
char x=0xFE;
x=x>>1;
上面的語句x定義的是有符號字符型,x的初始值寫成二進制是111111110B,注意了符號位是1,x>>1后x的值為11111111B,空出的最高位補的是符號位1。再看下面的語句。
char x=0x7E;
x=x>>1;
上面的語句x定義的是有符號字符型,x的初始值寫成二進制是011111110B,注意了符號位是0,x>>1后x的值為00111111B,空出的最高位補的是符號位0。
綜上分析,C51沒有直接的循環(huán)移位運算符,但在intrins.h頭文件中已經(jīng)定義了這些功能的函數(shù),可以直接調(diào)用,移位函數(shù)有:
(1)unsigned char cror (unsigned char, unsignedchar);無符號字符型變量循環(huán)右移位
函數(shù)。
(2)unsigned int iror (unsigned int, unsigned char);無符號整型變量循環(huán)右移位函
數(shù)。
(3)unsigned long lror (unsigned long, unsigned char);無符號長整型變量循環(huán)右移位
函數(shù)
(4)unsigned char crol (unsigned char, unsigned char);無符號字符型變量循環(huán)左移位
函數(shù)。
(5)unsigned int irol (unsigned int, unsigned char);無符號字符型變量循環(huán)左移位
函數(shù)。
(6)unsigned long lrol (unsigned long, unsigned char);無符號字符型變量循環(huán)左移位
函數(shù)。
以上6個函數(shù)第一形參是循環(huán)移位的數(shù)據(jù),第二形參是循環(huán)移位的次數(shù),例如要將P0寄存器循環(huán)左移一位,函數(shù)的調(diào)用形式為:P0=_crol_ (P0, 1);
所以上面的流水燈代碼可以改寫為循環(huán)結(jié)構(gòu):
#include <reg51.h>
#include <intrins.h>
void main()
{
unsigned int i;
P1=0xFE;
while(1)
{
for(i=0;i<=10000;i++); //延時
P1=_crol_(P1, 1);//循環(huán)左移1位
}
}
大家思考一下,如果沒有這樣的庫函數(shù),我們怎么自己寫出循環(huán)左移1的功能代碼呢?
我們分析發(fā)現(xiàn),循環(huán)左移1位就是左移一位后,最右邊空出來位補最左邊移出去的那個位,我們可以先讓操作數(shù)的值“左移”一位,最右邊的位補的0,得到一個值1,再將操作數(shù)里的值右移7位,也就是,將被左移出去的最高位移到最低位上,得到值2,再將值1和值2或一下,就能實現(xiàn)循環(huán)左移功能了。例如,將P0循環(huán)左移一位我們可以寫成如下代碼:P0=(P0<<1) | ( P0>>7);
上面的流水燈還可以用下面的代碼實現(xiàn):文章來源:http://www.zghlxwxcb.cn/news/detail-718122.html
#include <reg51.h>
#include <intrins.h>
void main()
{
unsigned int i;
P1=0xFE;
while(1)
{
for(i=0;i<=10000;i++); //延時
P1=(P1<<1) | ( P1>>7);//循環(huán)左移1位
}
}
1111 1110
1111 1100 | 0000 0001 = 1111 1101
1111 1010 | 0000 0001 = 1111 1011
… = 0111 1111
1111 1110 | 0000 0000 = 1111 1110
1111 1100 | 0000 0001 = 1111 1101
1111 1010 | 0000 0001 = 1111 1011
…文章來源地址http://www.zghlxwxcb.cn/news/detail-718122.html
到了這里,關(guān)于【單片機】06流水燈的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!