C語(yǔ)言,沒(méi)接觸過(guò)計(jì)算機(jī)編程語(yǔ)言的人會(huì)把它看的很神秘,感覺(jué)非常的難,而在我看來(lái),C語(yǔ)言的邏輯和運(yùn)算,就是小學(xué)水平,所以大家不要怕它,我盡可能的從小學(xué)數(shù)學(xué)邏輯方式帶著大家學(xué)習(xí)C語(yǔ)言。
看似很簡(jiǎn)單的東西,但是從同學(xué)們學(xué)習(xí)視頻的情況來(lái)看,很多同學(xué)不能徹底明白。這里先簡(jiǎn)單介紹一些注意事項(xiàng),然后還是從實(shí)驗(yàn)中講解會(huì)比較深刻。
1、十進(jìn)制就不多說(shuō)了,逢十進(jìn)位,一個(gè)位有十個(gè)值:0~9,我們的生活中到處都是它的身影。二進(jìn)制就是逢二進(jìn)位,它的一個(gè)位只有兩個(gè)值:0和1,但它卻是實(shí)現(xiàn)計(jì)算機(jī)系統(tǒng)的最基本的理論基礎(chǔ),計(jì)算機(jī)(包括單片機(jī))芯片是基于成萬(wàn)上億個(gè)的開(kāi)關(guān)管組合而成的,他們每一個(gè)都只能有開(kāi)和關(guān)兩種狀態(tài),再難找出第三個(gè)狀態(tài)了(不要辯解半開(kāi)半關(guān)這個(gè)狀態(tài),它是不穩(wěn)定態(tài),是極力避免的),所以他們只能對(duì)應(yīng)于二進(jìn)制的1和0兩個(gè)值,而沒(méi)有2、3、4……,理解二進(jìn)制對(duì)于理解計(jì)算機(jī)的本質(zhì)很有幫助。書(shū)寫(xiě)二進(jìn)制數(shù)據(jù)時(shí)需加前綴0b,每一位的值只能是0或1。十六進(jìn)制就是把4個(gè)二進(jìn)制位組合為一位來(lái)表示,于是它的每一位有0b0000~0b1111共16個(gè)值,用0~9再加上A~F(或a~f)表示,那么它自然就是逢十六進(jìn)位了,它本質(zhì)上同二進(jìn)制是一樣的,是二進(jìn)制的一種縮寫(xiě)形式,也是我們程序編寫(xiě)中常用的形式。書(shū)寫(xiě)十六進(jìn)制數(shù)據(jù)時(shí)需加前綴0x,下表是三種進(jìn)制之間的對(duì)應(yīng)關(guān)系。
十進(jìn)制 |
二進(jìn)制 |
十六進(jìn)制 |
0 |
0b0 |
0x00 |
1 |
0b1 |
0x01 |
2 |
0b10 |
0x02 |
3 |
0b11 |
0x03 |
4 |
0b100 |
0x04 |
5 |
0b101 |
0x05 |
6 |
0b110 |
0x06 |
7 |
0b111 |
0x07 |
8 |
0b1000 |
0x08 |
9 |
0b1001 |
0x09 |
10 |
0b1010 |
0x0A |
11 |
0b1011 |
0x0B |
12 |
0b1100 |
0x0C |
13 |
0b1101 |
0x0D |
14 |
0b1110 |
0x0E |
15 |
0b1111 |
0x0F |
16 |
0b10000 |
0x10 |
17 |
0b10001 |
0x11 |
18 |
0b10010 |
0x12 |
…… |
…… |
…… |
表4-1 進(jìn)制轉(zhuǎn)換
2、對(duì)于二進(jìn)制來(lái)說(shuō),8位二進(jìn)制我們稱(chēng)之為一個(gè)字節(jié),二進(jìn)制的表達(dá)范圍值是從0b00000000~0b11111111,而我們程序中用十六進(jìn)制表示的時(shí)候就是從0x00到0xFF,這里教大家一個(gè)二進(jìn)制轉(zhuǎn)換十進(jìn)制和十六進(jìn)制的方法,二進(jìn)制4位一組,遵循8,4,2,1的規(guī)律比如 1010,那么從最高位開(kāi)始算,數(shù)字大小是8*1+4*0+2*1+1*0 = 10,那么十進(jìn)制就是10,十六進(jìn)制就是0xA。尤其二進(jìn)制轉(zhuǎn)十六進(jìn)制的時(shí)候,十六進(jìn)制一位剛好是和二進(jìn)制的4位相互對(duì)應(yīng)的,這些大家不需要強(qiáng)行記憶,用幾次就熟練了。
3、對(duì)于進(jìn)制來(lái)說(shuō),只是數(shù)據(jù)的表現(xiàn)形式,而數(shù)據(jù)的大小不會(huì)因?yàn)檫M(jìn)制表現(xiàn)形式不同而不同,比如二進(jìn)制的0b1、十進(jìn)制的1、十六進(jìn)制的0x01,他們本質(zhì)上數(shù)值大小相等的同一個(gè)數(shù)據(jù)。我們?cè)谶M(jìn)行C語(yǔ)言編程的時(shí)候,我們只寫(xiě)十進(jìn)制和十六進(jìn)制,那么不帶0x的就是十進(jìn)制,帶了0x符號(hào)的就是十六進(jìn)制。
什么是變量?變量自然和常量是相對(duì)的。常量比如是1、2、3......等固定的數(shù)字,而變量,和我們小學(xué)學(xué)的x是一個(gè)概念,我們可以讓它是1,也可以讓它是2,我們想讓它是幾是我們程序說(shuō)了算的。
那么我們小學(xué)學(xué)的數(shù)學(xué)里邊,有這么幾類(lèi),正數(shù)、負(fù)數(shù)、整數(shù)和小數(shù)。在C語(yǔ)言里,名字和我們數(shù)學(xué)里學(xué)的不一樣外,還對(duì)數(shù)據(jù)大小進(jìn)行了限制。這個(gè)地方有一點(diǎn)復(fù)雜的是,在C51里邊的數(shù)據(jù)范圍和其他編程環(huán)境還不完全一樣,因此我們下邊的這個(gè)圖,僅僅代表的是C51,其他編程環(huán)境可能不一樣,大家知道有這回事就可以了。C語(yǔ)言的關(guān)鍵字較多語(yǔ)法有些嚴(yán)謹(jǐn)我們不必死記硬背只需理解了,用的時(shí)候再打開(kāi)http://www.torrancerestoration.com/mcuteach/150.html 查閱即可.
C語(yǔ)言的數(shù)據(jù)基本類(lèi)型分為整型、字符型以及浮點(diǎn)型,如圖4-1
圖4-1 C語(yǔ)言數(shù)據(jù)類(lèi)型
圖4-1中,三種基本類(lèi)型,每個(gè)基本類(lèi)型又包含了兩個(gè)類(lèi)型。其中字符型和整型,除了有一定的數(shù)據(jù)大小范圍之外,只能表達(dá)整數(shù)。而unsigned型的又只能表達(dá)正數(shù),要表達(dá)負(fù)數(shù)必須用signed型,編寫(xiě)程序的時(shí)候,signed可以省略。表達(dá)小數(shù),必須用浮點(diǎn)型。
比如上節(jié)課最后給的閃爍小燈的程序,我們用的是unsigned int i = 0;這個(gè)地方i的范圍就是0~65535,我們for語(yǔ)句的寫(xiě)法,如果那個(gè)30000改成70000的話(huà),for(i=0;i<70000;i++);大家會(huì)發(fā)現(xiàn)小燈會(huì)一直亮,而不是閃爍了,那理解這個(gè)問(wèn)題,當(dāng)然我們要來(lái)了解for語(yǔ)句的用法了。這里有一個(gè)編程宗旨,就是能用小不用大。就是說(shuō)定義能用1個(gè)字題的,就不定義成int,一方面節(jié)省RAM空間可以讓其他變量或者中間運(yùn)算過(guò)程使用,另外一方面,占空間小程序運(yùn)算速度也快一些。
for語(yǔ)句是我們今后編程的一個(gè)常用的語(yǔ)句,這個(gè)語(yǔ)句必須得學(xué)會(huì)其用法,他不僅僅可以用來(lái)做延時(shí),還可以用來(lái)做一些循環(huán)運(yùn)算。for語(yǔ)句的一般形式如下:
for(表達(dá)式1; 表達(dá)式2; 表達(dá)式3)
(需要執(zhí)行的語(yǔ)句);
其執(zhí)行過(guò)程是:表達(dá)式1首先執(zhí)行且只執(zhí)行一次;然后執(zhí)行表達(dá)式2,通常都是一個(gè)用于判定條件的表達(dá)式,如果表達(dá)式2條件成立,就執(zhí)行(需要執(zhí)行的語(yǔ)句);然后再執(zhí)行表達(dá)式3;再判斷表達(dá)式2,再執(zhí)行表達(dá)式3.....一直到表達(dá)式2不成立時(shí),跳出循環(huán)往下執(zhí)行。舉個(gè)例子:
for(i = 0; i<2; i++)
j++;
這里有一個(gè)符號(hào)++,這個(gè)符號(hào)表示加1的意思。假如j最開(kāi)始初值是0,首先執(zhí)行表達(dá)式1的i=0,然后判斷i小于2這個(gè)條件成立,就執(zhí)行一次j++,j的值就是1了,然后經(jīng)過(guò)表達(dá)式3后,i的值也變成1了,再判斷條件2,還是符合,j再加一次,j變成2了,表達(dá)式3后i也變成2了,再判斷條件2,發(fā)現(xiàn)2<2這個(gè)條件不成立了,所以就不會(huì)再執(zhí)行j++這個(gè)語(yǔ)句了。所以執(zhí)行完畢后,j的值就是2。
for語(yǔ)句除了這種標(biāo)準(zhǔn)用法,還有幾種特殊用法,我們上節(jié)課的閃爍小燈對(duì)for語(yǔ)句的用法for(i=0; i<30000; i++) ;我們沒(méi)有加(需要執(zhí)行的語(yǔ)句),沒(méi)有加的話(huà),就是什么都不操作。但是什么都不操作的話(huà),我們這個(gè)for語(yǔ)句循環(huán)判斷了30000次,程序執(zhí)行是會(huì)用掉時(shí)間的,所以就起到了延時(shí)的作用。比如我們把30000改成20000,會(huì)發(fā)現(xiàn)燈的閃爍速度加快了,因?yàn)槲覀冄訒r(shí)時(shí)間短了,當(dāng)然,我們?cè)摮?/font>40000后會(huì)發(fā)現(xiàn),閃爍慢了。但是有一點(diǎn)特別注意,C語(yǔ)言的延時(shí)時(shí)間是不能通過(guò)程序看出來(lái)的,也不會(huì)成比例,比如假如我們這個(gè)for循環(huán)里邊的表達(dá)式2使用30000的時(shí)候延時(shí)3秒的話(huà),那么延時(shí)40000的時(shí)候,可能不會(huì)是4秒,那如何看實(shí)際延時(shí)時(shí)間呢,一會(huì)我再教大家。
還有一種寫(xiě)法for( ; ; ),這樣寫(xiě)后,這個(gè)for循環(huán)就變成了死循環(huán)了,就不停的執(zhí)行(需要執(zhí)行的語(yǔ)句),和我們前邊講的while(1)的意思是一樣的。那while這個(gè)語(yǔ)法是如何用的呢?
在我們單片機(jī)C語(yǔ)言編程的時(shí)候,每個(gè)程序我們都會(huì)固定的加一句while(1),這條語(yǔ)句就可以起到死循環(huán)的作用。對(duì)于while語(yǔ)句來(lái)說(shuō),他的一般形式是:
While (表達(dá)式)
{
循環(huán)體語(yǔ)句;
}
在C語(yǔ)言里,通常表達(dá)式符合條件,我們叫做真,不符合條件,叫做假。比如前邊i<30000,當(dāng)i等于0的時(shí)候,那這個(gè)條件成立,就是真,如果i大于30000的時(shí)候,條件不成立,叫做假。
while(表達(dá)式)這個(gè)括號(hào)里的表達(dá)式,為真的時(shí)候,就會(huì)執(zhí)行循環(huán)體語(yǔ)句,當(dāng)為假的時(shí)候,就不執(zhí)行。在這里先不舉例,后邊遇到時(shí)再詳細(xì)說(shuō)明。
還有另外一種情況,就是我們C語(yǔ)言里邊,除了表達(dá)式外,還有常數(shù),習(xí)慣上,我們非0的常數(shù)都認(rèn)為是真,只有0認(rèn)為是假,所以我們程序中加了while(1),這個(gè)數(shù)字1,可以改成2,3,4......等等都可以,都是一個(gè)死循環(huán),不停的執(zhí)行循環(huán)體的語(yǔ)句,但是如果把這個(gè)數(shù)字改成0,那么就不會(huì)執(zhí)行循環(huán)體的語(yǔ)句了。
函數(shù)定義的一般形式如下:
函數(shù)值類(lèi)型 函數(shù)名 (形式參數(shù)列表)
{
函數(shù)體
}
1、函數(shù)值類(lèi)型,就是函數(shù)返回值的類(lèi)型。在我們后邊程序使用中,會(huì)有很多函數(shù)中有return x這個(gè)東西,這個(gè)返回值也就是函數(shù)本身的類(lèi)型。還有一種情況,就是這個(gè)函數(shù)只執(zhí)行操作,不需要返回任何值,那么這個(gè)時(shí)候它的類(lèi)型就是空類(lèi)型void,這個(gè)void按道理來(lái)說(shuō)是可以省略的,但是一旦省略,Keil軟件會(huì)報(bào)一個(gè)警告,所以我們通常也不省。
2、函數(shù)名?梢允侨魏魏戏ǖ臉(biāo)示符,但是不能與其他函數(shù)或者變量重名,也不能是關(guān)鍵字。什么是關(guān)鍵字,后邊我們慢慢接觸,比如char這類(lèi),都是關(guān)鍵字,是我們程序中具備特殊功能的標(biāo)志符,這種東西不可以命名函數(shù)。
3、形式參數(shù)列表,我們也叫做形參,這個(gè)是函數(shù)調(diào)用的時(shí)候,相互傳遞數(shù)據(jù)用的。有的函數(shù),我們不需要傳遞參數(shù),那么可以用void來(lái)替代,void同樣可以省略,但是那個(gè)括號(hào)是不能省略的。
4、函數(shù)體。函數(shù)體包含了聲明語(yǔ)句部分和執(zhí)行語(yǔ)句部分。聲明語(yǔ)句部分主要用于聲明函數(shù)內(nèi)部所使用的變量,執(zhí)行語(yǔ)句部分主要是一些函數(shù)需要執(zhí)行的語(yǔ)句。特別注意,所有的聲明語(yǔ)句部分必須放在執(zhí)行語(yǔ)句之前,否則編譯的時(shí)候會(huì)報(bào)錯(cuò)。
5、一個(gè)工程文件必須有且僅能有一個(gè)main函數(shù),程序執(zhí)行的時(shí)候,都是從main函數(shù)開(kāi)始的。
6、關(guān)于形參和實(shí)參的概念,我們后邊再總結(jié),如果遇到程序里有,大家再跟著抄一段時(shí)間。先用,后講解,這樣更有利于理解。
我們?cè)賮?lái)回顧一下我們上節(jié)課閃爍LED程序部分
void main() //void即函數(shù)類(lèi)型
{
unsigned int i = 0; //定義一個(gè)無(wú)符號(hào)整數(shù)i,變量范圍是0~65535
//并且賦一個(gè)初值0
ENLED = 0; //先定義變量i,后寫(xiě)執(zhí)行部分
ADDR0 = 0;
ADDR1 = 1;
ADDR2 = 1;
ADDR3 = 1; //74HC138開(kāi)啟三極管
while(1) //程序死循環(huán)
{
LED = 0; //點(diǎn)亮小燈
for(i=0;i<30000;i++); //for延時(shí)操作
LED = 1; //熄滅小燈
for(i=0;i<30000;i++); //for延時(shí)操作
}
}
C語(yǔ)言常用的延時(shí)辦法,有以下4種
圖4-2 C語(yǔ)言延時(shí)
圖4-2是我們編程語(yǔ)言常用的4種延時(shí)方法,其中兩種非精確延時(shí),兩種精確一些的延時(shí)。for語(yǔ)句和while語(yǔ)句都可以通過(guò)改變i的范圍值來(lái)改變延時(shí)時(shí)間,但是C語(yǔ)言的時(shí)間都是不能通過(guò)程序看出來(lái)的。
精確延時(shí)有兩個(gè)方法,一個(gè)方法是用定時(shí)器來(lái)延時(shí),這個(gè)方法我們后邊課程要詳細(xì)介紹,定時(shí)器是單片機(jī)的一個(gè)重點(diǎn)。另外一個(gè)就是用庫(kù)函數(shù)_nop_();,一個(gè)NOP的時(shí)間是一個(gè)機(jī)器周期的時(shí)間,這個(gè)后邊也要介紹。
非精確延時(shí),只是在我們做一些簡(jiǎn)單的比如小燈閃爍,流水燈等簡(jiǎn)單實(shí)驗(yàn)中使用,而實(shí)際做實(shí)際開(kāi)發(fā)程序中其實(shí)這種非精確延時(shí)用的極少,這里我們只是做演示功能使用。
好了,介紹完了,我們就要實(shí)戰(zhàn)了。上節(jié)課的LED小燈閃爍的程序,我們用的延時(shí)方式是for(i=0;i<30000;i++);大家如果把這里的i改成100,下載進(jìn)入單片機(jī),會(huì)發(fā)現(xiàn)小燈一直亮,而不是閃爍狀態(tài),現(xiàn)在大家都把這個(gè)程序改一下,都改成100,然后下載觀(guān)察一下現(xiàn)象再繼續(xù)。
觀(guān)察完了,毫無(wú)疑問(wèn),實(shí)際現(xiàn)象和我提到的理論是相符合的,這是為什么呢?這里介紹一個(gè)常識(shí)。我們?nèi)说娜庋?/span>對(duì)閃爍的光線(xiàn)有一個(gè)最低分辨能力,通常情況下當(dāng)閃爍的頻率高于50Hz時(shí),我們看到的信號(hào)就是常亮的。即,延時(shí)的時(shí)間低于20ms的時(shí)候,我們的肉眼是分辨不出來(lái)小燈是在閃爍的,可能最多看到的是小燈亮暗稍微變化了一下。要想清楚的看到小燈閃爍,延時(shí)的值必須大一點(diǎn),大到什么程度呢,不同的亮度的燈不完全一樣,大家可以自己做實(shí)驗(yàn)。
那么如何觀(guān)察延時(shí)有多長(zhǎng)時(shí)間呢?大家鼠標(biāo)點(diǎn)Keil的Project-->Options for Target ‘Target1’,或點(diǎn)Target1右側(cè)圖標(biāo),進(jìn)入設(shè)置選項(xiàng),如圖4-3所示
圖4-3 Options for Target
首先我們打開(kāi)Target這個(gè)選項(xiàng)卡,找到里邊的Xtal(MHz)這個(gè)位置,這是填寫(xiě)我們進(jìn)行模擬時(shí)間的晶振選項(xiàng),從我們?cè)韴D以及板子上都可以看到,我們單片機(jī)所配的晶振是11.0592MHz,所以這個(gè)地方我們要填上11.0592。然后找到Debug這個(gè)選項(xiàng),選擇左側(cè)的Use Simulator,然后點(diǎn)擊最下邊的OK就可以了,如圖4-4所示。
圖4-4 Debug配置信息
點(diǎn)擊Debug菜單里的Start/Stop Debug Session,或者鼠標(biāo)點(diǎn)做左側(cè)的這個(gè)Debug圖標(biāo),會(huì)進(jìn)入一個(gè)新的頁(yè)面,如圖4-5所示。
圖4-5 Debug窗口顯示
最左側(cè)那一欄是單片機(jī)的一些寄存器和系統(tǒng)信息,最上邊那一欄是Keil將C語(yǔ)言轉(zhuǎn)換成匯編的代碼,下邊就是我們C語(yǔ)言的程序,還有各種窗口都可以打開(kāi),在view菜單可以打開(kāi)或者關(guān)閉我們的各種窗口。這節(jié)課我們只關(guān)心我們需要的窗口,其他窗口用到再說(shuō)。那么有時(shí)候我們覺(jué)得這種分布不是特別的好,所以我們想改變一下窗口分布怎么辦呢?比如Disassembly(匯編)窗口,我們先用鼠標(biāo)拖動(dòng)它,然后中間會(huì)出現(xiàn)一個(gè)方向符號(hào),再用鼠標(biāo)點(diǎn)那個(gè)方向符號(hào),他就給我們分布了,如圖4-6所示。
圖4-6 Keil窗口移動(dòng)(一)
我們點(diǎn)擊最右邊的那個(gè)箭頭,然后窗口變化成如4-7圖所示;蛘呶覀?nèi)绻貌坏絽R編的程序,也可以直接關(guān)掉。
圖4-7所示 Keil窗口移動(dòng)(二)
細(xì)心的同學(xué)會(huì)看到在C語(yǔ)言的程序里有個(gè)黃色的箭頭,這個(gè)箭頭代表的就是這個(gè)程序當(dāng)前運(yùn)行的位置,在這個(gè)Debug里邊,我們可以看到我們的程序運(yùn)行的過(guò)程。在左上角有這三個(gè)圖標(biāo),第一個(gè)是復(fù)位,點(diǎn)擊一下之后,程序就會(huì)跑到最開(kāi)始的位置運(yùn)行,第二個(gè)圖標(biāo)是全速運(yùn)行圖標(biāo),點(diǎn)擊一下程序就會(huì)全速運(yùn)行跑起來(lái),第三個(gè)圖標(biāo)是停止圖標(biāo),當(dāng)程序全速運(yùn)行跑起來(lái)后,我們可以通過(guò)點(diǎn)擊第三個(gè)圖標(biāo)來(lái)讓程序停止,觀(guān)察程序運(yùn)行到哪里了。點(diǎn)擊一下復(fù)位后,我們會(huì)發(fā)現(xiàn)C語(yǔ)言程序左側(cè)有的灰色或者綠色,有的地方還是保持原來(lái)的白色,我們可以在我們灰色的位置雙擊鼠標(biāo)設(shè)置斷點(diǎn),就是比如程序一共20行,在第十行設(shè)置斷點(diǎn)后,點(diǎn)全速運(yùn)行,程序就會(huì)運(yùn)行到第十行停止,方便我們觀(guān)察運(yùn)行到這個(gè)地方的情況。
同學(xué)們會(huì)發(fā)現(xiàn),有的位置可以設(shè)置斷點(diǎn),有的地方不可以設(shè)置斷點(diǎn),這是為什么呢?Keil軟件本身具備優(yōu)化我們程序的功能,如果大家想在所有的位置設(shè)置斷點(diǎn),可以把優(yōu)化選項(xiàng)設(shè)置到0位置,就是程序不進(jìn)行優(yōu)化。如圖4-8所示。
圖4-8 優(yōu)化選項(xiàng)設(shè)置
這節(jié)課我們重點(diǎn)是看看C語(yǔ)言代碼的運(yùn)行時(shí)間,在最左側(cè)的register那個(gè)框內(nèi),有一個(gè)sec選項(xiàng),這個(gè)選項(xiàng)就是單片機(jī)運(yùn)行時(shí)間的統(tǒng)計(jì)選項(xiàng),大家點(diǎn)一下復(fù)位按鈕,會(huì)發(fā)現(xiàn)這個(gè)sec變成了0,然后我們?cè)?/font>LED = 0; 這一句加一個(gè)斷點(diǎn),在LED = 1;這個(gè)位置加一個(gè)斷點(diǎn),我們點(diǎn)擊全速運(yùn)行按鈕,會(huì)直接停留在LED = 0;我們會(huì)看到我們的時(shí)間變化成0.000197秒,如圖4-9所示。
圖4-9 斷點(diǎn)設(shè)置
我們?cè)冱c(diǎn)一下全速運(yùn)行,會(huì)發(fā)現(xiàn)sec變成了0.07530650秒,那么這樣一個(gè)for循環(huán)的時(shí)間大概有75ms左右,我們也可以通過(guò)改變30000這個(gè)數(shù)字來(lái)改變這個(gè)間隔時(shí)間。當(dāng)然了,大家要注意i的變量范圍,你如果寫(xiě)成了大于65535的值以后,程序就會(huì)一直運(yùn)行不下去了,因?yàn)?font face="Times New Roman">i無(wú)論如何變化,都不會(huì)大于這個(gè)值,如果要大于這個(gè)值正常運(yùn)行,必須改變i定義的類(lèi)型了。后邊如果我們要求看一段程序運(yùn)行多長(zhǎng)時(shí)間,都可以通過(guò)這種方式來(lái)看。
我們前邊學(xué)了點(diǎn)亮LED小燈,然后又學(xué)了LED小燈閃爍,下邊我們要進(jìn)一步了解一下如何讓8個(gè)小燈依次一個(gè)一個(gè)點(diǎn)亮,流動(dòng)起來(lái)。
圖4-10 LED小燈電路圖
通過(guò)前面的課程,我們可以了解到控制引腳P0.0通過(guò)了74HC245控制DB0,P0.1控制DB1......P0.7控制DB7。我們還學(xué)到一個(gè)字節(jié)是8位,我們?nèi)绻麑?xiě)一個(gè)P0,就代表了P0.0到P0.7的共8個(gè)位。比如我們寫(xiě)P0 = 0xFE;轉(zhuǎn)換成二進(jìn)制就是0b11111110,所以點(diǎn)亮LED小燈的程序,實(shí)際上我們可以改成另外一種寫(xiě)法,如下所示。
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
ENLED = 0;
ADDR0 = 0;
ADDR1 = 1;
ADDR2 = 1;
ADDR3 = 1; //74HC138開(kāi)啟三極管
P0 = 0xFE;
while(1); //程序停止在這里
}
通過(guò)上邊這個(gè)程序我們可以看出來(lái),可以通過(guò)P0來(lái)控制所有的8個(gè)LED小燈的亮和滅。我們下邊要進(jìn)行依次亮和滅,怎么辦呢?從這里就可以得到方法了,如果想讓單片機(jī)流水燈流動(dòng)起來(lái),依次要實(shí)現(xiàn)的結(jié)果是:0xFE,0xFD,0xFB,0xF7,0xEF,0xDF,0xBF,0x7F。
在我們的C語(yǔ)言當(dāng)中,有一個(gè)移位操作,其中<<代表的是左移,>>代表的是右移。比如a = 0x01 << 1就是a 的結(jié)果等于0x01左移一位。大家注意,移位都是指二進(jìn)制移位,那么移位完了,本來(lái)在第0位的1移動(dòng)到了第一位上,移動(dòng)完了低位是補(bǔ)0的。所以a的值最終是等于0x02。
還要學(xué)習(xí)另外一個(gè)運(yùn)算符~,這個(gè)符號(hào)是按位取反的意思,同樣,按位取反也是針對(duì)二進(jìn)制而言。比如a = ~(0x01),0x01的二進(jìn)制是0b00000001,按位取反是0b11111110,那么a的值就是0xFE了。
學(xué)會(huì)了這兩個(gè)符號(hào)后,那么我們就可以把流水燈的程序?qū)懗鰜?lái),先把程序貼上。
#include <reg52.h>
sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
void main()
{
unsigned char j = 0;
unsigned int i = 0;
ENLED = 0;
ADDR0 = 0;
ADDR1 = 1;
ADDR2 = 1;
ADDR3 = 1; //74HC138開(kāi)啟三極管Q16
while(1) //程序死循環(huán)
{
P0 = ~(0x01 << j++); //P0等于1左移j位,并且j++
for(i=0; i<20000; i++); //延時(shí)
if(j == 8) //如果j等于8,重新給j賦值0
{
j = 0;
}
}
}
這里我只講兩種情況,當(dāng)j等于0的時(shí)候,1左移0位還是1,那么寫(xiě)成二進(jìn)制后就是0b00000001,對(duì)這個(gè)數(shù)字按位取反就是0b11111110,亮的是最右邊的小燈。當(dāng)j等于7的時(shí)候,1左移7位就是0b10000000,按位取反0b01111111,亮的是最左邊的小燈。中間過(guò)程大家自己分析一下。
流水燈結(jié)束后,關(guān)于小燈的講解,我們暫時(shí)告一段落,后邊還有小燈的高級(jí)用法,我們到時(shí)候再詳細(xì)講解。
1、熟練掌握二進(jìn)制、十進(jìn)制和十六進(jìn)制的轉(zhuǎn)換方法。
2、掌握C語(yǔ)言變量類(lèi)型和范圍,for、while等基本語(yǔ)句的用法。
3、了解函數(shù)的基本結(jié)構(gòu),能夠獨(dú)立進(jìn)入程序Debug,多多動(dòng)手操作,熟練Keil軟件環(huán)境的一些基本操作。
4、將流水燈左移理解透徹后,獨(dú)立完成流水燈右移操作以及流水燈先左移后右移等簡(jiǎn)單的花樣操作。
curry 發(fā)表于 2015-8-28 17:29
**** 作者被禁止或刪除 內(nèi)容自動(dòng)屏蔽 ****
heron 發(fā)表于 2018-8-13 12:46
/***直接從keil里復(fù)制過(guò)來(lái)的漢字全是亂碼,估計(jì)從這里復(fù)制回去也是***/
/**剛寫(xiě)了一個(gè)流水,延時(shí)時(shí)間大概在 ...
heron 發(fā)表于 2018-8-13 12:46
/***直接從keil里復(fù)制過(guò)來(lái)的漢字全是亂碼,估計(jì)從這里復(fù)制回去也是***/
/**剛寫(xiě)了一個(gè)流水,延時(shí)時(shí)間大概在 ...
歡迎光臨 (http://www.torrancerestoration.com/bbs/) | Powered by Discuz! X3.1 |