欧美极品高清xxxxhd,国产日产欧美最新,无码AV国产东京热AV无码,国产精品人与动性XXX,国产传媒亚洲综合一区二区,四库影院永久国产精品,毛片免费免费高清视频,福利所导航夜趣136
標題:
單片機入門心得(連載)
[打印本頁]
作者:
liangzaizhou
時間:
2014-11-27 19:14
標題:
單片機入門心得(連載)
(一)匯編入門
最近看到幾個尋求單片機入門的帖子,一時心血來潮,把自己的一些入門心得寫了下來,希望能對初學者有所幫助吧。
可能很多人學習單片機的開始都是一章一章的的去閱讀教程,我也這樣做過,結果就是沒多久就昏昏欲睡了。對于初學者來說,什么隨機存儲器啊,只讀存儲器啊,寄存器啊,尋址方式啊,周期啊,指令啊。。。等等等等,簡直就跟看天書一樣。其實,我認為對于初學者來說,沒必要了解這么多,學習總是一個循序漸進的過程,不要妄想著能一下子就把單片機的理解透了,然后再去動手做實驗,做項目,這是很不現實的。
學習單片機的時候,要想著單片機能做什么我就學什么,我想要做什么就學什么,不懂,就翻書,再不行,就上網找。那么首先單片機能做些什么呢?單片機能做的事情很多很多,恐怕說個幾天幾夜都說不完。可能很多人會這么說,這么多的功能,這么多的例子,究竟從何學起啊!但是在我看來,單片機能做的只有兩件事而你要做的也只有這兩件事情:第一,輸出高低電平;第二,接收高低電平的輸入。假如單片機沒有輸入輸出功能,那么程序編得在怎么超凡脫俗,也沒有任何意義。因為,沒有了跟外圍器件的通信,單片機還有什么用呢!那么跟外圍器件的通信靠的是什么呢?高電平(+3.3V或+5V)和低電平(0V)。那么我們的目的就很明確了,學習單片機的目的就是讓單片機的各個管腳輸入或輸出高或低電平。在程序上代表高低電平的就是數字量1和0。也就是說,程序的最終目的就是在各個管腳上輸入或輸出1或0。所有的程序都是為了達成這個目的而設計的。換句話來說,只要能在你想要的管腳輸入或輸出你想要實現的高或低電平,那么你的目的就已經達到了,不要去管你的程序有多么的臃腫或是不堪入目,這個會隨著你學習的深入和經驗的積累而逐漸改善,不需要著急。
舉個最簡單的例子,在單片機的P1.0的管腳上接一個LED燈,要讓LED燈點亮,就是在P1.0管腳上輸出高電平,要讓LED燈熄滅,就是在P1.0腳上輸出低電平。那么怎么樣才能在P1.0腳上輸出高或低電平呢?不知道,那就去翻書一條一條的去找指令。哦,找到一條SETB置位指令,置位P1.0那不就是把1賦給P1.0嗎,P1.0置1,不就是輸出高電平了嗎?至于是不是,誰試誰知道。不過,先不要著急,既然找到了輸出高電平的指令,那么順便找找輸出低電平的指令。好了,沒錯,就是你了CLR。那么現在就可以編程序了:
ORG 0000H
JMP MAIN
OGR 0030H ;如果不能理解這幾條指令的意思,那就直接套用就可以了
MAIN:
SETB P1.0 ;輸出高電平,點亮LED燈
CLR P1.0 ;輸出低電平,熄滅LED燈
END
好了,程序完成,很簡單吧。可是,這個只是一亮一滅,我要它不停的閃爍怎么辦?簡單!多加一句跳轉指令就行了,跳轉指令上面就有JMP,那好吧,再改一下程序
ORG 0000H
JMP MAIN
OGR 0030H
MAIN:
SETB P1.0
CLR P1.0
JMP MAIN
END
大功告成
可是,程序運行之后,看不到LED燈一亮一滅啊!怎么回事?這是當然了,單片機CUP的運行速度是以微秒來計的,人的眼睛是反應不過來的。那要怎么辦呢?讓CPU停一下等個一兩秒再執行下一條指令?那顯然不行,地球人都知道。那就找點事情給CPU去忙吧,不管它干什么都行,只要再這段時間內不要去碰P1.0管腳就行了。那么讓它去做什么呢,國際上-_-!!!通常讓它去數數,因為CPU每數一個數的時間都是一樣的,比如說1微秒,那么數1 000個數,就是1毫秒,數1 000 000個數就是一秒。那么怎么樣讓CPU去數數呢?繼續找指令表,我找。。。找到一個INC,每執行一次,操作數加1,那我要數到1 000 000的時候停止呢,怎么辦?不知道。不知道!那要你干什么,一邊去吧你,順便把你兄弟DEC也帶走,我不想再見到你們!我再找。。。這個好像有點用JZ,累加器A中為0就跳轉,好像可以啊,我先讓CPU跳一邊去然后給A一個數1 000 000,讓A從1 000 000減到0,A為0時再跳轉回來不就行了?不過累加器A是什么?不知道?那就再翻書。。。哦,好像A最大只能到255,到不了1 000 000,怎么辦?255就255吧,先試試再說,看能不能看出變化。那么怎么給A送數呢?MOV唄!好了,那誰誰誰,你給我回來,DEC別看了,說的就是你!嗯,再改一下程序
ORG 0000H
JMP MAIN
OGR 0030H
MAIN:
SETB P1.0
MOV A,#255 ;給A一個數,讓CPU去數
JMP WAIT ;CPU給我一邊數數去
LED_OFF:
CLR P1.0
MOV A,#255 ;
JMP WAIT1 ;再來一個
LED_ON:
JMP MAIN
WAIT:
DEC A ;A-1
JZ LED_OFF ;等于0就跳回去
JMP WAIT ;不等于0就繼續減
WAIT1:
DEC A ;A-1
JZ LED_ON ;等于0就跳回去
JMP WAIT1 ;不等于0就繼續減
END
編譯,,排錯,運行,大功告成
好了,程序編完了,也能運行了,不過現在高興是不是太早了,你在JMP來JMP去的,JMP的我頭都暈了,那我要是要再延長一點時間,你豈不是要JMP個沒完沒了了?!難道就沒有別的方法了嗎?那好吧,我在翻翻書。真是書到用時方恨少啊。。。咦,這個看起來有點意思,CALL,是不是跟打電話一樣,不管你在哪里,一個CALL,就能找到你啊。不過這個ACALL和LCALL又有神馬不同呢,難道還有國內長途和國際長途之分?不管了,就用你了LCALL,反正不用花錢。
ORG 0000H
JMP MAIN
OGR 0030H
MAIN:
SETB P1.0
MOV A,#255
LCALL WAIT ;我CALL
LCALL WAIT ;我再CALL
LCALL WAIT ;
LCALL WAIT ;
LCALL WAIT ;我CALL,CALL,CALL。。。
CLR P1.0
LCALL WAIT
LCALL WAIT
LCALL WAIT
LCALL WAIT ;哈哈哈。。。CALL個夠,爽
JMP MAIN
WAIT:
DEC A ;A-1
JNZ WAIT ;沒數完,繼續。。。
RET ;數完了,那我掛電話了,有時間再CALL你啊
END
好了,這回看起來舒服多了。不過累加器A,看起來你有點意見?A:“廢話!你不知道老子很忙的嗎!分分鐘幾十萬上下,你叫我給你數數?你確定,你的腦袋沒被驢給踢過?老子縱橫機湖幾十年,閱人無數,就沒見過你這么白的程序員!”好吧,大哥,你牛,我惹不起你我躲的起。我再翻書,幸好這不是在考試,我想怎么翻就怎么翻。。。有了!就是你了DJNZ,減1不為0就跳轉。咦,怎么沒有減1為0跳轉的呢?也不知道創造匯編的那位大神是怎么想的。好吧,這不是我們這些小菜鳥該管的,還是改我的程序比較靠譜一點
ORG 0000H
JMP MAIN
OGR 0030H
MAIN:
SETB P1.0
MOV R0,#255 ;那就換一個唄
LCALL WAIT ;我CALL
LCALL WAIT ;我再CALL
LCALL WAIT ;
LCALL WAIT ;
LCALL WAIT ;我CALL,CALL,CALL。。。
CLR P1.0
LCALL WAIT
LCALL WAIT
LCALL WAIT
LCALL WAIT ;哈哈哈。。。
JMP MAIN
WAIT:
DJNZ R0,WAIT ;沒數完,繼續
RET ;數完了,那我掛電話了,有時間再CALL你啊
END
好了,終于終于終于編完了,其實單片機也不怎么難嘛,呵呵。
最后,再介紹一句,其實
DJNZ R0,WAIT
這句,還可以換成
DJNZ R0,$
這樣,減1不為0就等待,其實我想介紹的是這一句
JMP $
這是個死循環,原地跳步,用來調試程序是非常好用的。不知道創造這句的大神是不是要告訴全世界的程序員,美元的魅力連CPU也擋不住,看到它,誰也跑不動。好了,言歸正傳,這一句其實用來調試程序是非常好用的,不知道怎么用,就先記住吧,或許以后有用,或許永遠也沒用,一家之言,每個人有每個人的方法。
作者:
liangzaizhou
時間:
2014-11-27 19:15
(二)IC協議
如果CCAV要舉辦“菊花郎杯我最喜愛的單片機通信協議”的話,我以菊花郎集團首席執行官名譽擔保,I2C一定會摘得
桂冠。什么?你說SPI應用更廣泛?但是,對于初學者來說SPI在很多時候往往數據發送過去之后,就如石沉大海,完
全不知所以。當年,小菜鳥我操控SPI協議的時候,簡直就像是中了七傷拳的至尊寶:“二當家的,老子踩了你那么久
,就算不痛也隨便應付兩聲嘛!”相比之下I2C就乖巧多了,至少你踩他8腳,他會回應一聲。現在,大家知道我為什
么要選I2C了吧!
好了,我們言歸正傳,I2C的ACK確實是非常的好用,I2C有沒有寫對,請看ACK!一目了然,真的是太方便了!I2C真的
這么簡單嗎?是不是參照著協議圖寫完就OK了呢?未必!以我自己的經歷來看,曾經無數次的,拿著仿真器,對著I2C
協議時序圖,一個時鐘一個時鐘的校驗,或是在客戶那里對著示波器一個脈沖一個脈沖的讀I2C數據。那時候,總是擔
心著是不是多了或是少了一個脈沖啊,究竟是在上升沿還是下降沿讀寫數據啊。。。等等,總之,就是心里沒底。哎
,小菜鳥真是傷不起,傷不起啊傷不起。。。
咦,又跑題了。對于I2C,我總結了3點原則。自從有了這3點(怎么聽起來這么別扭呢),再也不用為I2C協議
擔心啦!請看:
(1)、在I2C起始信號之前,和結束信號之后,確保SCL和SDA腳為高電平;
(2)、在每個函數(結束信號函數除外)之后,確保SCL為低電平;
(3)、請參考以上兩條(哈哈,其實只有兩點啦,但是我要是說只有兩點那豈不是很沒面子)
是不是不明覺厲呢。別著急,我們慢慢來分析。
我們先從起始和結束信號函數開始分析,
void I2c_Start(void)
{
SCL_HIGH;
SDA_HIGH;
nop();
SDA_LOW;
nop();
SCL_LOW;
}
void I2c_Stop(void)
{
SDA_LOW;
nop();
SCL_HIGH;
nop();
SDA_HIGH;
}
對照這兩個函數請看第一點,對于I2c_Stop()的SCL_HIGH和SDA_HIGH,這兩個沒什么可說的,這是協議的結束信號,
只要沒寫反了就行,連這個也寫反了的童鞋,自己面壁思過去。這里要說明一下的是I2c_Start()開始的兩個SCL_HIGH
和SDA_HIGH,有沒有童鞋覺得每次結束信號都把SCL和SDA拉高了,還有沒有必要每次都在I2c_Start()里面再寫一遍啊
,太浪費了,勤儉節約是中華民族的光榮傳統,可是我要說的是,可能在某個不為人知
的陰暗角落,或許I2C的某根線就被偷偷的改變了狀態。這怎么可能!我自己編的程序難度有沒有用到I2C還不知道嗎
?可是,在工作中可能你接手的程序已經不知道經過了多少人的縫縫補補,特別是在一些大型企業中尤為如此。So,
安全第一,安全第一!還有就是你編寫的I2C程序可能會有他人調用,與人方便自己方便吧!對了,還有第2點,這點
跟I2c_Stop()沒就關系,你可以涼涼去了。當然對于I2c_Start()也沒什么可說的,協議寫了嘛,SCL為低,必須的!
好了,你們兩個可以去領盒飯了,下一個I2c_Write(u8 uByte)輪到你了,還看,說的就是你了!上來躺好,放心不用
解剖,我們只看兩點,好吧,就看一點
void I2c_write(u8 uByte) //unsigned char 定義為u8,以后不在說明
{
u8 i;
for(i=0; i<8; i++)
{
if(uByte & 0x80)
{
SDA_HIGH;
}
else
{
SDA_LOW;
}
SCL_HIGH; //我高,劃破長空,前面的一切不管
nop();
SCL_LOW; //我低,一場春夢,生與死一切成空
uByte <<= 1;
}
}
寫數據其實就是8個時鐘脈沖,這個做個循環就行了,依次把一個字節的數據寫到SDA腳。關鍵是SCL的時鐘脈沖怎么寫
,根據第二點準則,所有I2C通信函數都以SCL低電平結束(結束信號除外),所以,寫脈沖首先就是把SCL拉高,然后
再拉低,這就是一個bit的寫時序了,循環8次,結束寫字節操作。你看,最后還是以SCL低為結束,完美收官!耶!真是太有默契了,贊一個先!
當當當當,下面有請我們今天的男豬腳I2c_WriteAck()隆重登場!咦,你腳下踩的是什么?
u8 I2c_WriteAck(void)
{
u8 ack;
SDA_IN; //對于51單片機來說,設置為輸入其實就是把管腳置1,所以這句等同于SDA_HIGH,
//這句很重要,因為你可能在寫數據的時候把SDA拉低了,所以比不可少
SCL_HIGH;
nop();
if(READ_SDA) //Only you 能保護我,讓螃蟹和蚌精無法吃我
ack;= 1;
else
ack;= 0;
SCL_LOW;
SDA_OUT; //對于51來說,這句為空
return ack;
}
根據第二準則,寫操作必定是以SCL低為結束,那么,SCL也是以拉高為開始。現在大家知道我為什么要強調必須以SCL
低為函數的結束了吧!這樣一來對于每一個函數,都可以獨立去分析,不必去理會在這之前的時鐘是什么狀態。別看
ACK這么簡單,I2C協議是生是死就看他的臉色了!對于用I2C通信的所有產品,不管別人對我說的是什么問題,我首先
聞到第一句就是ACK有沒有響應?嗯,調試等一下再說,先看讀操作。“O~O~Only you!”O你個頭。。。
好了,輪到你們了,I2c_Read()、I2c_ReadAck()和I2c_ReadNAck(),都以前上來吧
u8 I2c_Read(void)
{
u8 i;
u8 uByte;
SDA_IN; //親,別忘了倫家哦
for(i=0; i<8; i++)
{
uByte <<= 1;
SCL_HIGH;
if(READ_SDIO)
uByte |= 0x01;
SCL_LOW;
nop();
}
SDA_OUT; //“我呢,我呢!”你啊,看情況吧
return uByte;
}
void I2c_ReadAck(void)
{
SDA_LOW;
nop();
SCL_HIGH;
nop();
SCL_LOW;
}
void I2c_ReadNack(void)
{
SDA_HIGH;
nop();
SCL_HIGH;
nop();
SCL_LOW;
}
這三個函數就不一一分析了,大家以此類推吧。
呼,I2C協議至此大功告成了,照此分析,童鞋們再也不用擔心出錯了!大家想怎么玩就怎么玩,即使是量大的日子也
不用擔心側漏了(咦,這句好像在哪里聽過)!
好了,高興三分鐘就夠了。是不是I2C協議寫好就完事OK了呢?我可以很負責任的告訴你:NO!
嗯,今天就先講到這里吧。欲知后事,請聽下回分解。。。
作者:
aabbcc
時間:
2014-11-27 22:37
樓主太給力了,我剛看了兩次,非常精辟。對我很有用,既學到了技術又提高了信心感謝
作者:
hujia
時間:
2014-11-27 23:49
一口氣看完了,意猶未盡,等待樓主的第3篇連載
作者:
admin
時間:
2014-11-28 16:09
寫的不錯,對初學者很有幫助。看來此貼可以加入精華了。等待樓主的下一篇文章
歡迎光臨 (http://www.raoushi.com/bbs/)
Powered by Discuz! X3.1