?
?????? 單片機被廣泛應用于工業控制,家電,消費電子,醫療電子,儀表測量等領域,為應廣大初級電子工程師/單片機愛好者之需,電子發燒友網隆重策劃整合推出《單片機關鍵技術基礎詳解》系列技術文章,以后會陸續推出其他章節,敬請廣大工程師朋友繼續關注和留意。應廣大工程師網友對前三個章節熱烈反響,電子發燒友網會再接再厲為各位工程師網友推出更多技術精品系列文章,以饗讀者。
閱讀相關系列章節
單片機關鍵技術基礎詳解(一)
單片機關鍵技術基礎詳解(二)
單片機關鍵技術基礎詳解(三)
一、電子電路設計之C51單片機常見問題
筆者在工作中實際使用過AT89C2051、AT89C51、AT89C52等51單片機,后來應用***新茂、華邦等廠家的51單片機。實踐中遇到許多問題,都是書本上沒有的。我印象中,書本上的知識只有一頁插圖了,就是cpu的時序圖。最初直接用匯編寫程序,然后是C51嵌套匯編。編譯器曾用偉福系列編譯器,后來使用keil等,感覺這些編譯器大同小異。需要熟練的C語言基礎,加上單片機應用的特殊性。
本文就51單片機應用中一些常見問題作個總結,這都是我實際碰到過的,因為文章篇幅所限,這些問題遠遠不足以表達單片機的常見問題。希望對初學者有所幫助,文中不完善的地方務請指點。謝謝!
1:C51編譯器如何區分位地址和字節地址
是靠預定義實現的,比如:sfr P0 = 0x80; sbit P0_0 = 0x80;前者聲明了P0端口地址位于0x80,后者說明了P0端口的bit0,即P0.0位于位地址空間0x80處。這2個0x80具有完全不同的含義,靠關鍵字sfr和sbit來區別。這樣當程序被編譯時,編譯器會依此編譯成相應的匯編語言。例如:
C51語句: P0 = 1;
P0聲明為sfr,因此編譯成:mov 80h,01h,將把0x01數據送入0x80單元,由于0x80單元物理上對應P0端口,因此,P0.0腳將輸出高電平(其實是呈現高阻態,P0口獨有的),其他.1-.7腳輸出低電平。
C51語句: P0_0 = 1;
P0_0聲明為sbit,因此編譯成:setb 80h,這將把位地址空間的0x80地址的bit的值置1。這個位正是P0口的bit0,執行后,P0.0將輸出高阻態。而P0.1-.7不會變化。
2:C51為什么要嵌套匯編
51單片機一個顯著優點就是指令執行時間固定,因此可以適應時序要求嚴格的場合。例如符合ISO7816協議的cpu卡的讀寫,對時序要求比較嚴格。其實就是用io腳做出來的同步半雙工串口。支持cpu卡的程序一般比較龐大,需要用c51來組織,但是由于c編譯的不確定性,必須把底層程序封裝成匯編語言模塊嵌入到工程中。這就帶來幾個問題:如何聲明函數、參數如何傳遞等。限于篇幅,不能說得很細。下面舉例:
匯編程序單獨保存一個文件,加入到工程中,函數如下:
_proc_a:
mov a, r7
inc a
mov r7, a
ret
用c語言在.h文件中聲明: extern unsigned char proc_a(unsigned char val);
調用時形如: retvalue = proc_a(0x11);
說明:
a:匯編程序如果帶參數,則需要在匯編程序前多加一個下劃線。而聲明它的地方不用加(偉福編譯器這么要求的)。
b:函數的形參中第一參數用R7傳遞,函數返回值用R7返回,這是C51的通用規范。其他參數都有相應規定。函數可以返回一個位,用psw的c位返回。
c:上面的語句,執行順序是把0x11給R7,然后跳轉子程序,子程序將它加1后送回。
d:函數跳轉到匯編程序時,本區的R0-R7,A,B,PSW,DPTR等寄存器可以供子程序使用,不必考慮調用后是否要恢復這些常規資源。上例中,A的值被函數使用了,編程者不必恢復調用前的值。
3:51單片機的P0口特殊之處
許多新手都碰到這個問題,其實很簡單,這涉及到芯片的io腳是怎么做出來的。這對硬件工程師來說十分重要。TTL的io腳模型:
P1,P2,P3口都可以理解成左圖,注意vcc下面有個電阻,因此可以理解成:引腳輸出1的能力弱。地那邊沒有電阻,可以理解成引腳吸入電流能力強。而P0口,可以理解成右圖。這就是集電極開路輸出,也叫OC輸出。可以看出,當CTR=1時,三極管導通,引腳被接地;當ctr=0時,三極管截止,引腳浮空,也叫三態。這個端口這么做的目的是考慮P0口肩負讀寫數據和地址復用,這個關系要仔細看懂cpu時序圖。因此,P0口要加合適的上拉電阻,絕不要加下拉電阻。上拉電阻的選擇要看外部負載情況。
4:P1-3口如何輸入輸出
從上節的左圖可以看出。做輸出時,ctr=1則輸出強信號0,ctr=0則輸出弱信號1。當io腳做輸入時,應使ctr=0,這樣三極管截止。外部信號如果是1,則上拉電阻加強了這個1,單片機就會讀到1。當外部信號為0時,注意,必須將上拉電阻的上拉作用全部抵消,才能在引腳上得到0。
因此,對于程序來說,把io腳置1就處于接收狀態,當然也是輸出1狀態。程序置io口為1,讀取的信號是不是1就依靠外部電路了,如果外部電路沒有“吃掉”上拉電阻的電流,則讀取得到1,反之,雖然程序置io腳為1,但是讀取得到的就是0。
因此,如果用io腳的高電平驅動外部電路時,要小心外部電路把這個1“吃掉”從而輸出不了1。而作為輸入時,為0電平的外設必須足夠有能力將io腳拉低。所以,用io腳直接點亮led的時候,最好用反邏輯,就是輸出0,讓led亮。這樣能保證驅動能力。就是io腳接led的負端,led的正端過電阻接vcc。
因此,io腳輸出1時,外部電路將它強行接地是沒有關系的,而io腳輸出0的時候,外部電路強行接電源就會把io腳損壞。所以,程序加電之后,一般把所有io口都寫成1:MOV P0,0FFH。
P3口引腳復用,必須引腳都處于輸出1狀態。例如,把RXD腳輸出0,則它什么數據都讀不進來了,筆者早期曾調試一整天才發現串口收不到數據是沒有把RXD置1的原因,把時間都浪費在外圍了,當時很是汗顏。
5:有關晶振
單片機的晶振在內部可以簡化成一個反向器。當晶振輸入腳XI剛過坎壓、被認為是1的一瞬間,輸出腳XO就輸出0,這個0會帶動晶振使XI電壓下降,當降低到坎壓被認為是0的一瞬間,輸出腳XO就輸出1。這樣周而復始。
因此,用示波器觀察正常工作的晶振輸入腳XI時,得到的是一個不高不低的近似水平線。而XO則是幅值很大的正弦波。測量晶振輸入腳XI時,示波器表筆要打在X10檔上,否則,表筆就能把晶振弄停。
因此布線時,晶振輸入腳XI要盡量靠近晶振,而XO腳可稍遠。同時XO具有一定的驅動能力,某些芯片可以用它驅動其它時序電路(不推薦這么做,因為系統可靠性下降)。
寫到這里,才發覺51單片機的問題太多了,這篇文字簡直就是滄海一粟。以后再補充吧,另行成文。
二、實驗用單片機開發板介紹
該開發板集成了單片機系統最常用,最關鍵的功能單元,包括字符液晶顯示,圖片/漢字顯示,數碼管顯示,實時時鐘,步進電機控制,繼電器控制,ADC轉換,E2PROM操作,串口通信等等,提供C51例程大全。
基本配置
1、STC89C51單片機,支持串口在線下載程序,也就是你不用買單片機燒寫器也能夠隨時燒寫程序到你的單片機里,隨時觀察你修改的程序運行狀況。
2、4位8段數碼管顯示(可做計數器,定時器,頻率計,流水燈,電子鐘等各種顯示實驗)
3、MAX232芯片RS232通訊接口(可以做為與計算機通迅的接口同時也可做為STC單片機下載程序的接口)
4、獨立的+5V直流電源供電(避免了因用USB口供電容易燒壞電腦主板的隱患)
5、蜂鳴器(可以讓單片機發聲,唱歌,讓單片機變成電子琴)。
6、模數轉換芯片ADC0832(兩路可調AD輸入,串行接口控制,轉換效率高,是我們常用的模數轉換器件)。
7、ULN2003步進電機驅動控制,可控制繼電器和驅動步進電機(這是邁進工控自動化的第一步,對步進電機的操作是在單片機學習中所必須要面對的,也是必須要掌握的內容,機械精確定位,必須使用步進電機,數碼相機調焦,掃描儀等設備都大量使用步進電機)
8、SPI串行實時時鐘電路(DS1302)以及備用電源(熟悉SPI總線,用DS1302可以做一個萬年歷電子時鐘,待機電流非常小,扣式電池的備用電源能保證時鐘芯片工作幾年時間,掉電時間照走,相比用定時器做的時鐘,它的時間準,且不用計算,閏年自動生成,重新上電,數據不亂),對于類似像時鐘芯片的操作也是我們必須要掌握的。
9、繼電器控制,學習如何使用弱電控制強電,這在電器安全控制,遠程控制方面非常有用。
10、AT24C02外部EEPROM芯片(IIC總線元件實驗),該芯片的FLASH保存的數據可以保證10年不丟失。
11、字符液晶1602LCD接口。(采用接插件方式方便插拔,可顯示兩行 每行16個 共計32.任意ASCII碼字符 它的功能應用比數碼管豐富很多 顯示的信息量也很大,可設計為儀器設備的控制面板人機交互模塊)。
12、圖形點陣液晶12864LCD接口(采用接插件方式方便插拔,可顯示任意漢字和圖形是目前單片機圖文顯示最常用的顯示器件,我們的實驗板支持帶字庫的12846液晶,開發程序更方便。12846液晶不隨板贈送)。
13、4*4矩陣鍵盤(熟悉矩陣鍵盤編碼,解碼掃描原理,可做為人機交互信息輸入接口)。
14、單片機32個IO口全部引出,方便用戶進行自由擴展,增加新功能。
15、可安裝鎖緊裝置,方便主芯片的安裝及卸取
16、大部分元件采用貼片封裝,有效的節省了系統空間。功能模塊電源切換采用軟件控制,無需跳線跳接,具有極強的系統綜合控制功能。
17、光盤中含本實驗板所有例程。贈送破解版KEIL編譯,調試,仿真軟件,STC單片機程序下載軟件,電路板設計軟件PROTEL 99SE,PROTEL 2004DXP等及所有電路圖、實驗板詳細使用教程等。
標配組件
單片機開發板標準配置
1、主機開發板一套(配齊板上所有元件)
2、串口通訊電纜一條(兼程序下載線)
3、1602字符液晶一塊
4、光盤一張DVD(開發板全套資料)
可以單獨銷售電路板及電子元件,用戶可自己焊接調試。
三、IC解密之單片機算術運算指令
單片機算術運算指令匯總,不帶進位位的單片機加法指令
ADD A,#DATA ;例:ADD A,#10H
ADD A,direct ;例:ADD A,10H
ADD A,Rn ;例:ADD A,R7
ADD A,@Ri ;例:ADD A,@R0
用途:將A中的值與其后面的值相加,最終結果否是回到A中。
例:MOV A,#30H
ADD A,#10H
則執行完本條指令后,A中的值為40H。
下面的題目自行練習
MOV 34H,#10H
MOV R0,#13H
MOV A,34H
ADD A,R0
MOV R1,#34H
ADD A,@R1
帶進位位的加法指令
ADDC A,Rn
ADDC A,direct
ADDC A,@Ri
ADDC A,#data
用途:將A中的值和其后面的值相加,并且加上進位位C中的值。
說明:由于51單片機是一種8位機,所以只能做8位的數**算,但8位運算的范圍只有0-255,這在實際工作中是不夠的,因此就要進行擴展,一般是將2個8位的數**算合起來,成為一個16位的運算,這樣,能表達的數的范圍就能達到0-65535。如何合并呢?其實很簡單,讓我們看一個10進制數的例程:
66+78。
這兩個數相加,我們根本不在意這的過程,但事實上我們是這樣做的:先做6+8(低位),然后再做6+7,這是高位。做了兩次加法,只是我們做的時候并沒有刻意分成兩次加法來做罷了,或者說我們并沒有意識到我們做了兩次加法。之所以要分成兩次來做,是因為這兩個數超過了一位數所能表達的范置(0-9)。
在做低位時產生了進位,我們做的時候是在適當的位置點一下,然后在做高位加法是將這一點加進去。那么計算機中做16位加法時同樣如此,先做低8位的,如果兩數相加產生了進位,也要“點一下”做個標記,這個標記就是進位位C,在PSW中。在進行高位加法是將這個C加進去。例:1067H+10A0H,先做67H+A0H=107H,而107H顯然超過了0FFH,因此最終保存在A中的是7,而1則到了PSW中的CY位了,換言之,CY就相當于是100H。然后再做10H+10H+CY,結果是21H,所以最終的結果是2107H。
帶借位的單片機減法指令
SUBB A,Rn
SUBB A,direct
SUBB A,@Ri
SUBB A,#data
設(每個H,(R2)=55H,CY=1,執行指令SUBB A,R2之后,A中的值為73H。
說明:沒有不帶借位的單片機減法指令,如果需要做不帶位的減法指令(在做第一次相減時),只要將CY清零即可。
乘法指令
MUL AB
此單片機指令的功能是將A和B中的兩個8位無符號數相乘,兩數相乘結果一般比較大,因此最終結果用1個16位數來表達,其中高8位放在B中,低8位放在A中。在乘積大于FFFFFH(65535)時,0V置1(溢出),不然OV為0,而CY總是0。
例:(A)=4EH,(B)=5DH,執行指令
MUL AB后,乘積是1C56H,所以在B中放的是1CH,而A中放的則是56H。
除法指令
DIV AB
此單片機指令的功能是將A中的8位無符號數除了B中的8位無符號數(A/B)。除法一般會出現小數,但計算機中可沒法直接表達小數,它用的是我們小學生還沒接觸到小數時用的商和余數的概念,如13/5,其商是2,余數是3。除了以后,商放在A中,余數放在B中。CY和OV都是0。如果在做除法前B中的值是00H,也就是除數為0,那么0V=1。
加1指令
INC A
INC Rn
INC direct
INC @Ri
INC DPTR
用途很簡單,就是將后面目標中的值加1。例:(A)=12H,(R0)=33H,(21H)=32H,(34H)=22H,DPTR=1234H。執行下面的指令:
INC A (A)=13H
INC R2 (R0)=34H
INC 21H (21H)=33H
INC @R0 (34H)=23H
INC DPTR ( DPTR)=1235H
說明:從結果上看INC A和ADD A,#1差不多,但INC A是單字節,單周期指令,而ADD #1則是雙字節,雙周期指令,而且INC A不會影響PSW位,如(A)=0FFH,INC A后(A)=00H,而CY依然保持不變。如果是ADD A ,#1,則(A)=00H,而CY一定是1。因此加1指令并不適合做加法,事實上它主要是用來做計數、地址增加等用途。另外,加法類指令都是以A為核心的
四、單片機中晶振的作用
單片機工作時,是一條一條地從RoM中取指令,然后一步一步地執行。單片機訪問一次存儲器的時間,稱之為一個機器周期,這是一個時間基準。—個機器周期包括12個時鐘周期。如果一個單片機選擇了12MHz晶振,它的時鐘周期是1/12us,它的一個機器周期是12×(1/12)us,也就是1us。
MCS—51單片機的所有指令中,有一些完成得比較快,只要一個機器周期就行了,有一些完成得比較饅,得要2個機器周期,還有兩條指令要4個機器周期才行。為了衡量指令執行時間的長短,又引入一個新的概念:指令周期。所謂指令周期就是指執行一條指令的時間。例如,當需要計算DJNZ指令完成所需要的時間時,首先必須要知道晶振的頻率,設所用晶振為12MHz,則一個機器周期就是1us。而DJNZ指令是雙周期指令,所以執行一次要2us。如果該指令需要執行500次,正好1000us,也就是1ms。
機器周期不僅對于指令執打有著重要的意義,而且機器周期也是單片機定時器和計數器的時間基準。例如一個單片機選擇了12MHz晶振,那么當定時器的數值加1時,實際經過的時間就是1us,這就是單片機的定時原理。
簡單地說,沒有晶振,就沒有時鐘周期,沒有時鐘周期,就無法執行程序代碼,單片機就無法工作。
五、格雷碼轉二進制方法
二進位碼第n位 = 二進位碼第(n+1)位+格雷碼第n位。因為二進位碼和格雷碼皆有相同位數,所以二進位碼可從最高位的左邊位元取0,以進行計算。(注:遇到1+1時結果視為0)
例如: 格雷碼0111,為4位數,所以其所轉為之二進位碼也必為4位數,因此可取轉成之二進位碼第五位為0,即0 b3 b2 b1 b0。
0+0=0,所以b3=0
0+1=1,所以b2=1
1+1取0,所以b1=0
0+1取1,所以b0=1
因此所轉換為之二進位碼為0101
格雷碼轉換快速方法
(假設以二進制為0的值做為格雷碼的0)
G:格雷碼 B:二進位碼
G(N) = B(n+1) XOR B(n)
六、程序源代碼里的秘密
許多公司程序的一開始總會有這樣一段源代碼:
const unsigned char version_num[]={。..。..};
大括號中為產品編號和程序版本號,產品編號和程序版本號都是公司指定的,除了少數時候可以通過外部通訊讀取這個號碼外,大多數時候只是放在這里,程序并沒有對其做任何處理 。
大多數人的理解是這里的產品編號和程序版本號應該是為了方便公司對產品進行管理,比如現在有同一個型號不同版本的產品混在一起,就可以利用其進行區分。實際上這段代碼的作用不是這樣簡單,更重要的是對外起到身份標示的作用,當出現知識產權糾紛的時候,這段代碼的威力就顯現了出來。
現在讓我來給你一個假設,這個假設是針對單片機產品:你花了很長時間終于開發出一款受市場歡迎的產品,經過產品開發、市場前期推廣,儼然就是花開結果,馬上就是享受回報的時候。可此時殺出一家知名公司推出同樣的產品,一下就把你逼到無利可圖的地步。你經過仔細對比,可以確認此知名公司推出的產品用的代碼就是你開發的,因為產品是你開發的,沒有源代碼外泄的可能。
難道真的這么巧是知名公司開發出了和你一模一樣的產品?這種說法只能是哄小孩,一個產品,多少都有一些只有開發者自己知道的細節,只有開發者自己才知道這些細節的存在,而且這些細節是不會再產品規格書上有體現的,就好比是雙胞胎,別人看就是一個模子出來的,可父母一眼就能看出許多不同。
現在答案是顯而易見的,是知名公司通過某種非正常手段得到了你燒到芯片里面的代碼。既然這樣那可以去告知名公司啊,現在一個問題就出現在你面前,你如何證明這個程序是你寫的?也許你會說要證明這個還不簡單?我有源代碼啊,知名廠家沒有。可如果知名廠家說他們的源代碼被當時的項目工程師離職時刪除了,現在在你這里出現了,好哇,告你非法竊取公司商業機密。
當然,知名公司告你是告不贏的,只不過他們是大公司,不缺小錢,他們可以花一筆錢請一個律師把你拖到漫長的司法訴訟過程中,知名公司并不希望打贏官司,目的只有一個:“拖垮你,讓你覺得耗不起只好自動退出。”
如果你在代碼里面有這樣的一段代碼,恐怕知名公司別再妄想通過司法過程的漫長來拖垮你,你很容易就能用這段代碼通過司法鑒定證明程序就是你編寫的,一旦證明這個程序是你的,知名公司就不會再使用拖字訣,到那個時候就只有一條路可供他們選擇,找你和解。
這是我通常在程序中留的個人簽名,很簡單,就是我常用的一個郵箱,哈!當然不會一直都是這個郵箱啦,會變來變去的,但有一個基本原則,很容易證明這個簽名信息就是我。
const unsigned char author_msg=[‘s’,‘j’,‘_’,‘d’,‘a’,‘i’,‘@’,‘h’,‘o’,‘t’,‘m’,‘a’,‘i’,‘l’,‘。’,‘c’,‘o’,‘m’);
如果你覺得這個簽名還不夠安全,看下面的:
name_sum=0;
for(i=0;i
{
name_sum=name_sum+author_msg[i];
}
if(name_sum!=0xXX)
{
while(1)
{
//死循環
}
評論
查看更多