51單片機(jī)編程開發(fā)(四)之完轉(zhuǎn)LED

點(diǎn)燈是不是太簡(jiǎn)單了
上一篇的編程內(nèi)容中我們點(diǎn)亮了LED,肯定有朋友會(huì)說點(diǎn)燈是不是太簡(jiǎn)單了,文章后方留言還有朋友催我更新呢,哈哈哈,我當(dāng)然也想快點(diǎn)更新,只是各位朋友都是來自祖國(guó)大地的五湖四海,基礎(chǔ)肯定不一樣,所以為了照顧一些基礎(chǔ)稍微差一點(diǎn)的朋友必須要把問題點(diǎn)講得明白一些,把基礎(chǔ)原理解釋清楚,這有助于他們?cè)诔鯇W(xué)階段能夠形成良好的編程思維,所以前期更新速度會(huì)慢一些。到后期我倒是希望大家都能夠跟得上哈。但是大家如果有需求照樣可以大膽在后臺(tái)留言的,我會(huì)在教程計(jì)劃內(nèi)盡力滿足各位需求,如果不好意思留言,也可以選擇后臺(tái)私信。但是話說回來遲早要出社會(huì)混的,還在乎啥面子?你現(xiàn)在在乎的那點(diǎn)面子遲早會(huì)被社會(huì)“收拾干凈”哈,所以有啥不好意思的呢?
因?yàn)楸救俗詭У囊稽c(diǎn)“逗比”氣質(zhì),有時(shí)寫文章可能會(huì)戳到你的心窩子,到時(shí)千萬別較真,一定要記得我肯定是在開玩笑,提醒我再戳狠一點(diǎn),我真的會(huì)戳更狠喲。
另外,我今天也想了一個(gè)方案,希望在這里能夠讓不同基礎(chǔ)的朋友快速提高編程能力。在今后的推送消息中我會(huì)添加一篇文章,文章內(nèi)容可能涉及編程題目,經(jīng)典程序分享,或者一些編程經(jīng)驗(yàn),并且難度也會(huì)由低到高循序漸進(jìn),這樣以后新來的朋友也可以快速入門。當(dāng)然內(nèi)容中所涉及到的編程語言暫時(shí)限定為C語言。后面再視情況添加其他語言,例如C++,JAVA,Python,JS甚至dos,Shell腳本等等,還希望大家可以一起來玩轉(zhuǎn)。
現(xiàn)在先回到最初的LED話題,你是不是想說,就這?這點(diǎn)知識(shí)內(nèi)容還不夠下飯吃呢?那接下來我們?cè)偻纥c(diǎn)不一樣的。
延時(shí)的概念
前面的程序中我們只是點(diǎn)一下燈,熄一下燈,或者點(diǎn)亮另幾個(gè)燈,再熄滅,有這編程的功夫還不如裝個(gè)開關(guān)吧。你還想咋地?“寶寶想看那種五顏六色還能一閃一閃亮晶晶的”。如果你的女朋友(或男朋友)看到你學(xué)單片機(jī)只會(huì)點(diǎn)燈時(shí)這么對(duì)你說,你該咋辦?毫無疑問,咱無論如何也要滿足她(他)呀,還不止只給她看一閃一閃亮晶晶呢,你應(yīng)該要給她看星星,看月亮,看整個(gè)宇宙的。畢竟現(xiàn)在這社會(huì)競(jìng)爭(zhēng)這么大,你不給她,另一個(gè)朋友能給她,到時(shí)你該怎么辦?都到談戀愛這份上了,為了這點(diǎn)小事難道你要“善罷甘休”,真不想以后交換戒指的是你和她?
想清楚了吧,為了未來的那一大幕,我們現(xiàn)在是不是要先來研究研究LED怎么一閃一閃這一小步呢?
我們要讓單片機(jī)控制的LED一閃一閃要怎么做呢,是不是讓它亮一會(huì)再滅一會(huì)?那要怎么讓它亮了再滅呢?難道寫一個(gè)點(diǎn)亮程序,再寫一個(gè)熄滅程序不停交替下載這兩程序?要是這樣,你女朋友早跟樓下小王跑了。
前面的內(nèi)容中我們說了數(shù)字芯片大多都是需要時(shí)序來控制的吧,單片機(jī)是數(shù)字芯片的集合體,它的時(shí)鐘源就是我們上節(jié)課說的晶振電路,晶振電路產(chǎn)生的時(shí)鐘信號(hào)輸入到其內(nèi)部,然后其內(nèi)部電路就根據(jù)這個(gè)信號(hào)按照一定的規(guī)律進(jìn)行運(yùn)行,如果給到的程序有什么功能它內(nèi)部就隨著這個(gè)時(shí)鐘一步一步實(shí)現(xiàn)我們的功能,如果我們給了一個(gè)"空白"程序(空白不是什么都沒有,用無意義來形容可能更貼切,就是不處理正經(jīng)事單純消耗系統(tǒng)時(shí)鐘的命令,實(shí)現(xiàn)這一點(diǎn)的原理是因?yàn)閱纹瑱C(jī)中任何命令執(zhí)行都會(huì)消耗時(shí)間,類比人休息但時(shí)間也在流失道理一樣),那它內(nèi)部在這一段時(shí)鐘信號(hào)內(nèi)就保持原樣什么都不變動(dòng)。就像我們?nèi)艘粯?,?dāng)我們?cè)谧呗窌r(shí),大腦控制我們的神經(jīng),帶動(dòng)肌肉往復(fù)運(yùn)動(dòng),我們休息時(shí)就讓肌肉放松下來。那我們要怎么控制芯片讓它暫停一下呢,看完上面內(nèi)容是不是就有答案了?給它一段“空白"命令,不行就2段,或者N段。
那在程序中要怎么實(shí)現(xiàn)讓單片機(jī)執(zhí)行一段空白命令呢?
前面接收C語言基礎(chǔ)時(shí)我們是不是講到了循環(huán)語句?我們?cè)谘h(huán)語句中不執(zhí)行任何功能,這樣就可以解決這個(gè)問題了吧。一個(gè)“暫?!惫δ艿某绦蛟谀X海中應(yīng)該有了吧。這種情況我們一般稱為延時(shí),和暫停是一個(gè)意思,但不這不是意味著單片機(jī)就真的是停下來的吧,就像我們休息的時(shí)候心跳也要照樣跳動(dòng)一樣,“暫?!倍际羌傧蟆?/p>
下面來看一下我們平時(shí)常用的延時(shí)代碼:
while(n<100)
{
????n--;
}
我們也可以改寫成for循環(huán)的方式吧。
for(n=0;n<100;n++)
{
????;
}
當(dāng)然,以上程序還可以進(jìn)行嵌套,如果你需要設(shè)置的延時(shí)時(shí)間很久的話。另外,熟練編程之后我們也可以把大括號(hào)對(duì){}省略不寫,至于為什么?自己思考一下。
這里我們?cè)凇皶和!睍r(shí)用一個(gè)變量n來控制“空白”命令的次數(shù),如果短了就把n加大,如果長(zhǎng)了就減小。但到底多少合適呢,也就是我們要怎樣實(shí)現(xiàn)可控的延時(shí)時(shí)間呢,這里我們需要來了解幾個(gè)關(guān)于51單片機(jī)的新概念,即時(shí)鐘周期,機(jī)器周期,指令周期。
時(shí)鐘周期就是指晶振振蕩的周期,它是晶振頻率的倒數(shù),我們仿真電路中使用的是12MHz的晶振那它就是(1/12M)秒。
機(jī)器周期在51單片機(jī)中機(jī)器周期就是12個(gè)時(shí)鐘周期,即(1/1M)秒,也就是1微秒(us)。
指令周期就是單片機(jī)執(zhí)行一條指令的時(shí)間,它由若干個(gè)機(jī)器周期組成,在單片機(jī)中一些簡(jiǎn)單指令是1個(gè)機(jī)器周期,一部分復(fù)雜指令需要2個(gè)或多個(gè)機(jī)器周期。
當(dāng)然我們項(xiàng)目開發(fā)時(shí)這些內(nèi)容需要參考芯片數(shù)據(jù)手冊(cè),因?yàn)檫@不是固定的定義,現(xiàn)在很多增強(qiáng)型51單片機(jī)的時(shí)鐘都不是這樣的了,其他更高級(jí)的芯片就不用說了。
那我們到底要怎么確定我們延時(shí)程序中的n,能延時(shí)多久呢?我們可以通過程序的調(diào)試功能進(jìn)行仿真確定(畢竟是仿真與實(shí)際會(huì)有一些出入)。最死板的辦法是我們可以把程序下載到單片機(jī)中進(jìn)行測(cè)試分析呀,用示波器測(cè)量單片機(jī)引腳電平變化周期就不出來了,然后大概記住一些典型時(shí)間,如0.1s,0.5s,1s等延時(shí)n的值,以后直接使用也可以。但我們肯定還有更簡(jiǎn)單又準(zhǔn)確的延時(shí)辦法,因?yàn)樵O(shè)計(jì)到定時(shí)器的使用,所以今天就先不講解,后面學(xué)習(xí)定時(shí)器是在做具體介紹。
寫了這么多內(nèi)容,終于把基礎(chǔ)寫完了,老司機(jī)們是不是早就迫不及待的發(fā)車了?那我們先上車開起來吧
閃燈程序
看了以上原理,現(xiàn)在我們想來實(shí)現(xiàn)讓一個(gè)燈閃起來吧。我們來看看程序內(nèi)容,跟著注釋看一遍是不是就很明了了。
#include <reg52.h> //這是52單片機(jī)的頭文件
#include <intrins.h> //這也是編譯器的一個(gè)頭文件后面會(huì)用到
typedef unsigned char u8; //typedef 是別名關(guān)鍵字
typedef unsigned int ?u16;
void main()
{
? ? ? u8 i,j; //定義變量
???? ?P1 = 0xfe;//點(diǎn)亮第一個(gè)燈
for(i=0;i<200;i++) //第一段延時(shí)
{
for(j=0;j<200;j++)
{
;
}
}
P1 = 0xff;//熄滅第一個(gè)燈
for(i=0;i<200;i++)//第二段延時(shí)
{
for(j=0;j<200;j++)
{
;
????????????}
}
}
這個(gè)代碼里我新引入一個(gè)頭文件#include <intrins.h>,它也是編譯軟件自帶的一個(gè)頭文件,里面包含對(duì)寄存器的循環(huán)操作接下來的程序中我們會(huì)使用到。
typedef這個(gè)關(guān)鍵字就是取別名的意思,就是把一長(zhǎng)串名稱給一個(gè)簡(jiǎn)短的名字,編程時(shí)可以巧用它來簡(jiǎn)化某些程序。
使用上一節(jié)內(nèi)容中對(duì)P1端口整體賦值的方式進(jìn)行點(diǎn)燈。
點(diǎn)完燈后延時(shí)一會(huì),接下來講燈熄滅,熄滅后再進(jìn)行一個(gè)延時(shí),這樣就實(shí)現(xiàn)了我們的閃燈效果。
創(chuàng)建函數(shù),制作配件
如果我們把延時(shí)程序打包成一個(gè)函數(shù)以后就可以重復(fù)使用了,這是不是爽歪歪?
再來看看修改好的代碼:
#include <reg52.h> //這是52單片機(jī)的頭文件
#include <intrins.h> //這也是編譯器的一個(gè)頭文件
typedef unsigned char u8;
typedef unsigned int ?u16;
//void delay();//聲明函數(shù)
void delay(u8 ms);
void main()
{
P1 = 0xfe;//將LED1點(diǎn)亮
delay(50);//調(diào)用函數(shù)
P1 = 0xff; //將LED1關(guān)閉
delay(50);
}
void delay(u8 ms) ? //定義函數(shù)
{
u8 i,j;//定義這個(gè)延時(shí)函數(shù)中的i,j變量
for(i=0;i<ms;i++)
{
for(j=0;j<200;j++)
{
;
}
}
}
還是同樣的意思,這么一對(duì)比是不是可以看出程序有層次感就出來了,代碼瞬間就好看了很多吧。當(dāng)然把延時(shí)函數(shù)打包成void delay()還是void delay(u8 ms)就看個(gè)人了,要想使用更靈活那當(dāng)然是后者咯。
循環(huán)流水燈
只是知道閃燈未免太單調(diào),也打動(dòng)不了人心吧,接下來我們?cè)僬c(diǎn)復(fù)雜的,使用循環(huán)位移操作實(shí)現(xiàn)流水燈變化,現(xiàn)在先來看看程序。
#include <reg52.h>
#include <intrins.h>?
typedef unsigned char u8;
typedef unsigned int ?u16;
void delay(u8 ms);
void main()
{
u8 rol = 0xfe;
u8 i;
for(i=0;i<8;i++)
{
//先將P1端口初始化,先設(shè)定P1.0點(diǎn)亮
P1 = rol;
//延時(shí)一會(huì)
delay(100);
????????????//將變量移位
rol = _cror_(rol,1);?
? ? ? ? ? ?//移位完成在下一個(gè)循環(huán),rol的值將重新賦值給P1寄存器
}
}
void delay(u8 ms) ? //定義函數(shù)
{
u8 i,j;//定義這個(gè)延時(shí)函數(shù)中的i,j變量
for(i=0;i<ms;i++)
{
for(j=0;j<200;j++)
{
;
}
}
}
這個(gè)程序?qū)χ曨l仿真效果一起看是不是還好理解呢?
_cror_函數(shù)相當(dāng)于一個(gè)環(huán)形位移 11111110 向右移動(dòng)一位就變成 01111111,其高位是將末位補(bǔ)充過來。
如果換成_iror_結(jié)果就不一樣了。
_iror_是單向位移,11111110 向右移動(dòng)一位變成01111111,其高位是補(bǔ)0。
當(dāng)然左移就和右移剛好相反了。
_crol_函數(shù)是環(huán)形移動(dòng),11111110 移動(dòng)一位就變成 11111101,其末尾是將最高位補(bǔ)充過來。
_irol_中11111110 向左移動(dòng)一位變成11111100,其末尾是補(bǔ)0。
這兩種循環(huán)反方式在編程時(shí)各有用途,所以要區(qū)分得開來,如果覺得不好掌握就多編程嘗試一下。
視頻中程序注釋部分寫錯(cuò)了,_cror_和_iror_的功能寫成_crol_和_irol_的功能了,大家留意一下!
小結(jié)
相信看完這幾個(gè)例子有朋友應(yīng)該知道可以嘗試做些什么東西出來了吧,比如DIY一個(gè)電子愛心,或者光立方方,廣州塔,不妨自己動(dòng)手試試,如果有遇到問題也可以在這里交流。
當(dāng)然要打動(dòng)心儀對(duì)象的芳心,只有上面這點(diǎn)技能肯定是還不夠,樓下小王都會(huì)做跳動(dòng)的旋律了,你這都沒競(jìng)爭(zhēng)力,要多加強(qiáng)練級(jí)呀,爭(zhēng)取有朝一日超過小王,摘得星星月亮回,也抱得美人歸。后面的內(nèi)容我們?cè)俳又榻B更深層的一些知識(shí),敬請(qǐng)期待,下期再見。