關(guān)于編程語言之間異同的詳細(xì)分析——(廈門html培訓(xùn)總結(jié))
靜態(tài)語言 vs.動(dòng)態(tài)語言
當(dāng)我們說到動(dòng)態(tài)語言時(shí),這個(gè)“動(dòng)態(tài)”實(shí)際上說的是變量類型。使用動(dòng)態(tài)語言編寫程序的時(shí)候,可以聲明一個(gè)變量,在程序運(yùn)行的過程中又可以改變這個(gè)變量的類型。與動(dòng)態(tài)語言相對(duì)的是靜態(tài)語言,或者叫強(qiáng)類型語言。比如C++和Java就是強(qiáng)類型的語言,而JavaScript,PHP和Perl是動(dòng)態(tài)類型的語言。
在C++中,聲明變量的時(shí)候必須同時(shí)指定變量的類型。廈門博看文思指出,在程序運(yùn)行的過程中,如果試圖去改變這個(gè)變量的類型,編譯器就會(huì)報(bào)錯(cuò)。這在Java中也是一樣。
但是JavaScript不一樣,在JavaScript程序運(yùn)行過程中可以改變變量的類型。事實(shí)上,在聲明變量的時(shí)候就不需要指定這個(gè)變量的類型,在使用變量的時(shí)候,可以先把一個(gè)整數(shù)賦值給這個(gè)變量,然后又用一個(gè)字符串覆蓋這個(gè)整數(shù),這在動(dòng)態(tài)類型的語言中都是允許的。
盡管動(dòng)態(tài)語言在最近才大行其道,可實(shí)際上這個(gè)概念在50年前就已經(jīng)提出來了。
函數(shù)式語言
隨著動(dòng)態(tài)語言的發(fā)展,人們對(duì)函數(shù)式語言的興趣也越來越大。在函數(shù)式語言中,函數(shù)本身可以被存儲(chǔ)在變量中,存儲(chǔ)在變量中的函數(shù)又可以作為參數(shù)傳遞給另外的函數(shù)?,F(xiàn)在的大多數(shù)語言都在一定程度上支持函數(shù)式編程。比如說C++,C++允許程序員將指針傳遞給函數(shù)。JavaScript等一些語言使函數(shù)的傳遞變得更加容易。所以,一般認(rèn)為C++不是一個(gè)真正意義上的函數(shù)式語言,而認(rèn)為JavaScript是函數(shù)式語言,而Haskell一般被認(rèn)為是函數(shù)式語言的絕佳示例。
垃圾**機(jī)制
理論上來說,只要你正確書寫代碼,你就不會(huì)有任何bugs。這聽起來很美好??蓪?shí)際上,當(dāng)你和許多其他程序員合作完成一個(gè)大項(xiàng)目時(shí),有一個(gè)bug會(huì)經(jīng)常出現(xiàn),這就是內(nèi)存泄露。你定義了一個(gè)變量,使用完這個(gè)變量之后卻沒有及時(shí)**這部分內(nèi)存,這時(shí)我們就說發(fā)生了內(nèi)存泄露。如果發(fā)生了內(nèi)存泄露又沒有及時(shí)發(fā)現(xiàn),隨著程序運(yùn)行時(shí)間的增加,程序越來越大,直到消耗完系統(tǒng)的所有內(nèi)存,然后系統(tǒng)崩潰。sounds terrible!
你可能會(huì)說,每次使用變量之后及時(shí)釋放內(nèi)存,內(nèi)存泄露不就不會(huì)發(fā)生了?想法是好的,可實(shí)際情況可能比這要復(fù)雜的多。比如說,你申請(qǐng)了一個(gè)鏈表來存儲(chǔ)數(shù)據(jù),這個(gè)鏈表被傳遞到另外一個(gè)函數(shù),這個(gè)函數(shù)是別人編寫的,在別人編寫的這個(gè)函數(shù)中,將這個(gè)鏈表復(fù)制了一份,但是你并不知道,你說是應(yīng)該刪除這個(gè)鏈表還是繼續(xù)保留?基于這種情況,程序員們想到了一個(gè)變通的辦法:將內(nèi)存**的工作交給系統(tǒng)來做。當(dāng)你不再使用某個(gè)變量,系統(tǒng)通過掃描內(nèi)存找到這個(gè)不再使用的內(nèi)存,然后主動(dòng)**,這就叫做垃圾**機(jī)制。對(duì)新開發(fā)出來的語言來說,這是一個(gè)非常重要的特征。垃圾**背后的思想是使編程更加容易,從而讓程序員將精力放在創(chuàng)造偉大的軟件之上。
需要說明的是,確實(shí)存在幾種不同的垃圾**機(jī)制:一種是系統(tǒng)定期掃描內(nèi)存,發(fā)現(xiàn)那些不再使用的內(nèi)存;另外一種是系統(tǒng)為每一個(gè)變量保留一個(gè)tab,一旦發(fā)現(xiàn)變量不再使用,馬上刪除之。從技術(shù)上來說,后者并不是一種垃圾**機(jī)制,而是“引用計(jì)數(shù)”,但是達(dá)到的效果是一致的。
虛擬機(jī)
當(dāng)Java在20世紀(jì)90年代中期橫空出世的時(shí)候,人們對(duì)它不是直接將代碼編譯成匯編語言這一點(diǎn)十分在意。廈門博看文思指出,和C++相反,Java在編譯的時(shí)候先把程序編譯成一個(gè)叫字節(jié)碼的中間代碼。在運(yùn)行的時(shí)候,系統(tǒng)調(diào)用虛擬機(jī)執(zhí)行字節(jié)碼,有時(shí)候甚至只是將字節(jié)碼編譯成匯編代碼。這種編譯方式剛剛出來的時(shí)候,程序員們抱
怨其速度慢,當(dāng)然現(xiàn)在已經(jīng)不成問題。許多語言采用虛擬機(jī)的方式運(yùn)行,比如說前面提到的Java、C#等?,F(xiàn)在這種類型的語言在速度上得到了長(zhǎng)足的發(fā)展。
1.編譯器選擇8級(jí)優(yōu)化時(shí),可能會(huì)出現(xiàn)錯(cuò)誤。剛寫好的程序,建議先用0級(jí)優(yōu)化看能否正常運(yùn)行,再用更高的優(yōu)化等級(jí)進(jìn)行優(yōu)化。
2.a、寫中斷程序一定要用using語句指定寄存器組。第1、2、3組都可以,不能是0,否則可能會(huì)main()函數(shù)沖突。從一個(gè)中斷程序中調(diào)用函數(shù)必須和中斷使用相同的寄存器組(摘自《Keil Cx51 編譯器用戶手冊(cè)中文版》P129)。建議把原本中斷函數(shù)需要調(diào)用的函數(shù)直接寫在中斷函數(shù)里,無須調(diào)用。
b、51單片機(jī)的中斷有兩個(gè)優(yōu)先級(jí)。一個(gè)中斷不會(huì)打斷另一個(gè)相同優(yōu)先級(jí)的中斷。這樣相同級(jí)別中斷可以使用同一個(gè)組。比如:低優(yōu)先級(jí)的中斷函數(shù)都用 using 1,高優(yōu)先級(jí)的中斷都用 using 2。這樣不會(huì)沖突。
3.C語言無符號(hào)數(shù)容易犯的錯(cuò)誤。若定義成有符號(hào)數(shù)char,則不會(huì)陷入死循環(huán)。
main(){ unsigned char i;for(i = 2;i>=0;i--){ printf(“%d”,i);} }
4.C51忌諱使用絕對(duì)定位_at_,因?yàn)橹灰x變量和變量的作用域,編譯器就會(huì)把一個(gè)固定地址給這個(gè)變量,無須人工將其絕對(duì)定位,這樣可能引發(fā)其他問題。
5.bit與sbit的區(qū)別:bit定義的位標(biāo)量的地址是隨機(jī)的,而sbit定義的位標(biāo)量的地址是確定的。bit只能訪問芯片內(nèi)部RAM中的可尋址位20H-2FH,而sbit可以訪問芯片內(nèi)部RAM中的可尋址位和特殊功能寄存器中的可尋址位。注意不能直接在程序里用P1^0等位變量,需要經(jīng)過sbit定義才可以使用。例如:
bit
tem;sbit led=P1^0;tem的地址是隨機(jī)分配的,而led的地址則固定為0x90.0。sbit變量后面需要跟等號(hào)=。6.為了避免由于使用參數(shù)宏而帶來意外的錯(cuò)誤,需要注意以下幾點(diǎn):
6.1 宏的參數(shù)必須帶括號(hào),例如 #define CIRCLE_SQUARE(R)3.141*(R)*(R)6.2 對(duì)所使用的參數(shù)宏進(jìn)行簡(jiǎn)單地展開檢查;
6.3 使用簡(jiǎn)單表達(dá)式、對(duì)參數(shù)加括號(hào)、避免節(jié)外生枝的使用方式(例如“++”、“--”一類都屬于不必要的附件運(yùn)算);
6.4 在參數(shù)宏定義時(shí),對(duì)于運(yùn)算順序通過括號(hào)進(jìn)行明確的限定,只要遵循以上幾點(diǎn),就可以避免大多數(shù)應(yīng)用場(chǎng)合的意外錯(cuò)誤。
手把手教你寫程序
內(nèi)容:從最簡(jiǎn)單的程序入手,手把手教你寫程序,讓同學(xué)們拿到一個(gè)復(fù)雜的程序或者任務(wù),能快速找到切入點(diǎn),寫出程序,再在此基礎(chǔ)上優(yōu)化程序。當(dāng)拿到一個(gè)單片機(jī)任務(wù)時(shí),不要急于動(dòng)手寫程序,先仔細(xì)分析它的以下幾個(gè)點(diǎn):
1、它要單片機(jī)整體實(shí)現(xiàn)什么功能
2、功能細(xì)分(模塊化),先干什么,再干什么,最后干什么
3、畫初步流程圖,(把幾個(gè)模塊畫出即可)
4、模塊之間的分析:一個(gè)模塊到另一個(gè)模塊之間,怎么變換,怎么連接(優(yōu)化流程圖)
5、單個(gè)模塊分析:每個(gè)模塊要做什么(流程圖細(xì)化)
6、所有模塊結(jié)合連接,細(xì)化所有流程圖
7、分析單個(gè)模塊每步要用到的方法或者指令
8、總流程圖定型
9、紙上寫程序,對(duì)照流程圖分析其可行性,若不可行則返回
10、上機(jī)調(diào)試,加注釋
11、從小到大,一個(gè)功能一個(gè)功能地調(diào)試;
以上十一步,缺一不可(小程序例外)切記:流程圖的確定很重要,需反復(fù)修改
大忌:拿到任務(wù),不仔細(xì)分析就寫程序。即使是小程序,我們也要養(yǎng)成良好的編程習(xí)慣,不要一味的追求結(jié)果。寫小程序可能比別人快,若是大程序,一旦出現(xiàn)思維混亂,或者出現(xiàn)程序調(diào)試不出結(jié)果,那么你花在調(diào)試上的時(shí)間,要比別人的多。?。?!磨刀不誤砍柴工!??!程序的優(yōu)化:屬于后期工作,只有調(diào)試出來后,才去優(yōu)化,如果一開始優(yōu)化和寫程序同時(shí)進(jìn)行,一是加重你的思考量,二是出現(xiàn)問題無從下手。無疑增加了寫程序的難度。對(duì)于一個(gè)初學(xué)者,寫一個(gè)程序,本身頭腦就處于緊張的狀態(tài),思考的問題就很多,如果此時(shí)把優(yōu)化程序也考慮進(jìn)去,你腦袋的負(fù)荷無疑加重,若你頭腦精明,你可以把優(yōu)化的地方,先在紙上記下來,等到調(diào)試結(jié)果正常,再把你想到的,優(yōu)化的地方加進(jìn)去。
7、如果在中斷程序中改變了多字節(jié)類型的變量,那么中斷程序以外的程序中(主程序,子函數(shù))要使用該多字節(jié)類型變量的話,讀寫前要關(guān)中斷,讀寫后再開中斷。否則會(huì)導(dǎo)致偶爾讀寫錯(cuò)誤。(實(shí)質(zhì)為資源沖突)舉一反三:
其他的數(shù)據(jù)類型也可能有這種影響。例如:長(zhǎng)整型、浮點(diǎn)型。例如:
unsigned int ms_counter;void T0(){ //定時(shí)器程序每100毫秒中斷一次,程序略 if(ms_counter<1000)ms_counter++;} void main(void){ //初始化定時(shí)器程序每100毫秒中斷一次,程序略 unsigned char tt;ms_counter=0;tt=0;//用tt控制只響一次 while(1){ if(ms_counter<400){ if(tt==0){ tt=1;Sound_on();
} } else { Sound_off();} //其他程序 } }
8、sbit變量不能使用extern關(guān)鍵字,使其在不同的文件中被使用,如要在led.c和main.c文件中使用同一個(gè)變量led0,有以下下兩種辦法:
1.在各種文件中重復(fù)定義變量,如在led.c中定義sbit led0=P1^0;同樣在main.c中定義sbit led0=P1^0;這樣,led0就變成了全局變量,可以在兩個(gè)文件中使用。
2.將sbit led0=P1^0定義到led.h頭文件中,均在led.c和main.c中包含led.h這個(gè)頭文件。
9、在多文件的程序中聲明外部變量(extern和)
如果一個(gè)程序包含兩個(gè)文件,在兩個(gè)文件中都要用到同一個(gè)外部變量Num,不能分別在兩個(gè)文件中各自定義一個(gè)外部變量Num,否則在進(jìn)行程序的連接時(shí)會(huì)出現(xiàn)“重復(fù)定義”的 錯(cuò)誤。正確的做法是:在任一個(gè)文件中定義外部變量Num,而在另一個(gè)文件中用extern對(duì)Num作“外部變量聲明”。即extern Num;注意若Num為uchar類型,應(yīng)當(dāng)寫為“extern uchar Num”,否則會(huì)當(dāng)為int,而導(dǎo)致出錯(cuò)。
當(dāng)使用static聲明變量和函數(shù)時(shí),需要在定義變量和函數(shù)的基礎(chǔ)上加上此關(guān)鍵字,而不能單獨(dú)使用。例如:
static int a;//定義性聲明,需要時(shí),直接使用變量a即可 a = 0x01;
static int funA(int a, int b);//聲明,且static不起作用 int funA(int a ,int b)//定義,即使funA有static關(guān)鍵字修飾,但由于static不能單獨(dú)使用,//故funA仍為外部函數(shù)。
{ …… } extern對(duì)變量進(jìn)行聲明時(shí),如沒有初始化,則為引用性聲明,不含定義,如需使用此變量,需要進(jìn)行定義。例如:
extern int a;//引用性聲明,不含定義
extern int a = 0x01;//定義性聲明,需要時(shí),直接使用變量a即可 int a;//定義
extern對(duì)函數(shù)進(jìn)行聲明時(shí),如沒有函數(shù)體,則為引用性聲明,不含定義。
extern int funB(int a ,int b);//引用性聲明,不含定義,且extern聲明可以省略
extern int funC(int a, int b)//定義性聲明 { …… }
10、一般的,要盡量減少中斷服務(wù)程序的內(nèi)容和長(zhǎng)度。因?yàn)樵谥鞒绦蛑锌梢赃€需要隨時(shí)響應(yīng)其他的中斷或事件。如果一個(gè)中斷服務(wù)程序過程,很可能會(huì)影響到主程序?qū)ν獠啃盘?hào)的檢測(cè)和響應(yīng)。通常,在中斷程序中只是改變一些變量或標(biāo)志位,在主程序中再根據(jù)變量或標(biāo)志位的值進(jìn)行判斷,處理相應(yīng)的事件。
11、在A/D和D/A轉(zhuǎn)換電路中,電源電壓和基準(zhǔn)電壓的穩(wěn)定性,對(duì)轉(zhuǎn)換的精度影響很大。另外,A/D和D/A轉(zhuǎn)換電路中要特別注意地線的正確連接,否則轉(zhuǎn)換結(jié)果將是不正確的,干擾影響將很嚴(yán)重。
12、根據(jù)C語言標(biāo)準(zhǔn),左移“<<”和右移“>>”運(yùn)算要求操作數(shù)至少是int,如果不滿int,自動(dòng)轉(zhuǎn)換成int(C語言整型提升)。因此 uchar a=0x01;a<<8;實(shí)際運(yùn)算,并不是8位數(shù)左移8位,而是int型左移8位。
13、在中斷里調(diào)用其他函數(shù),且要進(jìn)行參數(shù)傳遞時(shí),必須保證被調(diào)用函數(shù)所使用的寄存器組與中斷函數(shù)一樣,否則會(huì)產(chǎn)生不正確的結(jié)果。為了保證被調(diào)用的函數(shù)與中斷函數(shù)使用的寄存器一致,可對(duì)被調(diào)用函數(shù)使用using,不過此函數(shù)只能被中斷函數(shù)調(diào)用。
14、函數(shù)不使用using 時(shí),所使用寄存器組保持與此函數(shù)被調(diào)用前相同,不對(duì)RS0和RS1的值進(jìn)行修改;當(dāng)使用了using 關(guān)鍵字后,此函數(shù)所使用的寄存器組與using所定義的一樣。
15、當(dāng)指定中斷程序的工作寄存器組時(shí),保護(hù)工作寄存器的工作就可以被省略。使用關(guān)鍵 字using 后跟一個(gè)0 到3 的數(shù)對(duì)應(yīng)著4 組工作寄存器當(dāng)指定工作寄存器組的時(shí)候默 認(rèn)的工作寄存器組就不會(huì)被推入堆棧這將節(jié)省32 個(gè)處理周期,因?yàn)槿霔:统鰲6夹枰? 個(gè)處理周期。為中斷程序指定工作寄存器組的缺點(diǎn)是所有被中斷調(diào)用的過程都必須使用 同一個(gè)寄存器組否則參數(shù)傳遞會(huì)發(fā)生錯(cuò)誤。
16、如何使用pdata 類型的變量?當(dāng)要使用到pdata 類型的變量,如下: void main(void){ uchar pdata a;a=0x01;}
則需要進(jìn)行如下設(shè)置,否則pdata 的變量a則會(huì)無效。
a、修改STARTUP.A51的內(nèi)容。默認(rèn)時(shí),PPAGEENALBE為0,表示不允許pdata類型的變量,須將其值改為1;PPAGE表示pdata類型的變量存儲(chǔ)在哪一頁,01H表示存放在外部存儲(chǔ)器的第1頁,地址范圍100H至1FFH,此時(shí)P2經(jīng)STARTUP.A51處理后的值為0x01;此項(xiàng)設(shè)置需和BL51連接器的設(shè)置一致。
b、修改BL51連接器。根據(jù)STARTUP.A51中PPAGE所設(shè)置的值來填寫Pdata的值,如下圖。圖中Pdata的值可以填寫100H至1FFH中任意一個(gè),表示pdata類型的變量從所填
寫的值開始存儲(chǔ)。例如,當(dāng)Pdata填寫的值為108H時(shí),表示pdata類型的變量從108H開始存儲(chǔ),因此,存儲(chǔ)范圍變?yōu)榱?08H至1FFH。
另外,存儲(chǔ)模式Compact的作用是將沒有指定存儲(chǔ)類型的變量定義為pdata類型,對(duì)uchar pdata a;變量的定義沒有影響,但對(duì)uchar a;則有影響。
17、XBYTE的用法。XBYTE存在于#include 頭文件中。
XBYTE[0x000F]=data; // 此語句表示將data寫到外部RAM中的0x000F data=XBYTE[0x000F] // 此語句表示讀取外部RAM中0x000F的數(shù)據(jù) 以下語句與上面的語句等效:
#define EX_RAM XBYTE[0x000F] //將EX_RAM定義為外部RAM的地址0x000F EX_RAM=data;// 此語句表示將data寫到外部RAM中的0x000F data=EX_RAM // 此語句表示讀取外部RAM中0x000F的數(shù)據(jù)
18、如何在keil中用匯編實(shí)現(xiàn)51中沒有的指令
部分MCU與8051兼容,但會(huì)增加8051中沒有的指令,如華邦的W77E58和N79E352等芯片,具有8051中沒有的指令DEC DPTR。如何才Keil中實(shí)現(xiàn)此指令呢? 方法1:
在需要執(zhí)行該指令的地方放置相應(yīng)的機(jī)器碼 MAIN:
MOV DPTR,#02H DB 0A5H;由于從數(shù)據(jù)手冊(cè)上得知,DEC DPTR的機(jī)器碼為0A5H,故此處相當(dāng)于執(zhí)行了DEC DPTR指令。
AJMP $ END
方法2:
使用宏定義的方法
/*宏定義,表示用DEC_DPTR代替MACRO與ENDM之間的內(nèi)容*/ DEC_DPTR MACRO
DB 0A5H;此處不能與MACRO同一行 ENDM
MAIN: MOV DPTR,#02H DEC_DPTR;放置機(jī)器碼0A5H,相當(dāng)于執(zhí)行DEC DPTR AJMP $ END
通過將以上兩種方法生成的hex文件調(diào)入到編程器中,發(fā)現(xiàn)代碼一樣。經(jīng)測(cè)試,同樣可以用以上兩種方法代替8051中已有的指令。
例如,從數(shù)據(jù)手冊(cè)可知,MOV A,#0FH的長(zhǎng)度為2字節(jié),機(jī)器碼的值為74H,0FH。因此,經(jīng)驗(yàn)證,以下三個(gè)程序等效,產(chǎn)生的HEX文件一樣 MAIN: MOV A,#55H DB 74H DB 0FH MOV P1,A AJMP $ END
MAIN: MOV A,#55H MOV A,#0FH MOV P1,A AJMP $ END
TEST MACRO DB 74H DB 0FH ENDM MAIN: MOV A,#55H TEST MOV P1,A AJMP $ END
18、匯編中包含頭步驟:
例如,T2CON為定時(shí)器2的特殊功能寄存器,地址為0C8H,要對(duì)此寄存器賦值01H,除了
MOV 0C8H,#01H 和
T2CON EQU 0C8H MOV T2CON,#01H 外,還有用包含頭文件的方法 #include MOV T2CON,#01H 此時(shí),需要將A51中的“Defines 8051 SFR Names”的勾去掉。
19、指針
C51 提供一個(gè)3 字節(jié)的通用存儲(chǔ)器指針。通用指針的頭一個(gè)字節(jié)表明指針?biāo)傅拇鎯?chǔ) 區(qū)空間,另外兩個(gè)字節(jié)存儲(chǔ)16 位偏移量。對(duì)于DATA IDATA 和PDATA 段只需要8 位偏移量。Keil 允許使用者規(guī)定指針指向的存儲(chǔ)段,這種指針叫具體指針。使用具體指針的好處是節(jié)省了存儲(chǔ)空間編譯器不用為存儲(chǔ)器選擇和決定正確的存儲(chǔ)器操作指令產(chǎn)生代碼這樣就使代碼更加簡(jiǎn)短但你必須保證指針不指向你所聲明的存儲(chǔ)區(qū)以外的地方否則會(huì)產(chǎn)生錯(cuò)誤而且很難調(diào)試。
由于使用具體指針能夠節(jié)省不少時(shí)間所以我們一般都不使用通用指針。
20、EEPROM存放開關(guān)機(jī)(復(fù)位)次數(shù)方法:每次開機(jī)(復(fù)位)讀取EEPROM存放開關(guān)機(jī)的數(shù)據(jù),并加1后重新寫入EEPROM。
21、C51中,將printf函數(shù)與串口輸出結(jié)合注意事項(xiàng):
a、關(guān)串口中斷;
b、初始化串口,并使TI=1;
c、KEIL里擴(kuò)展出了b(8位),h(16位),l(32位)來對(duì)輸入字節(jié)寬的設(shè)置
在Keil C51中用printf輸出一個(gè)單字節(jié)變量時(shí)要使用%bd,若使用%d,則默認(rèn)為雙字節(jié)寬度,輸出可能會(huì)出錯(cuò)。如
unsigned char counter;printf(“Current count: %bdn”, counter);而在標(biāo)準(zhǔn)C語言中都是使用%d: printf(“Current count: %dn”, counter);d、輸出數(shù)據(jù)類型的長(zhǎng)度應(yīng)與定義的數(shù)據(jù)類型長(zhǎng)度一致,如:
uint tem2=97;
printf(“%c,%bdn”,tem2,tem2);第一個(gè)輸出會(huì)出錯(cuò)。
22、我一般不刻意的注意這個(gè),都是從軟件自身找問題的。
我寫程序時(shí)對(duì)于軟件抗干擾都是在程序狀態(tài)上考慮意外情況的,例如:
if(a == 1){...} else if(a == 2){....} else{//這個(gè)else 一定得加的,即使自己認(rèn)為不可能出現(xiàn)的情況也要加上
..//經(jīng)過好多程序走飛的情況發(fā)現(xiàn):大多情況都是缺少這個(gè)語句條件的,這 //語句可以寫成重新初始化a } 還有程序出現(xiàn)堆棧比較深的運(yùn)算(例如浮點(diǎn)乘除法后)或中斷比較深,我加2個(gè)_nop_();
23、STC12C5410AD外部RAM使用方法:
a.在Keil中設(shè)置外部RAM的起始地址和大小,如下圖
b.將變量定義為xdata即可。
24、中斷嵌套
當(dāng)有外部中斷0時(shí),中斷標(biāo)志位IE0由硬件自動(dòng)置1,進(jìn)入中斷服務(wù)程序后,IE0被自動(dòng)清0。若外部中斷0觸發(fā)信號(hào)在執(zhí)行完中斷服務(wù)程序后仍沒有撤除,就會(huì)再次使已經(jīng)變0的中斷標(biāo)志位IE0置1,再次進(jìn)入中斷服務(wù)程序;若在響應(yīng)中斷服務(wù)程序期間,再次產(chǎn)生外部中斷0觸發(fā)信號(hào)時(shí),此中斷不能被識(shí)別,因?yàn)镃PU在響應(yīng)中斷時(shí)會(huì)自動(dòng)關(guān)閉同一中斷。
如果外部中斷0比外部中斷1的優(yōu)先級(jí)高,當(dāng)在響應(yīng)外部中斷0期間產(chǎn)生外部中斷1時(shí),如果執(zhí)行完外部中斷0后,外部中斷1的中斷請(qǐng)求標(biāo)志位IE1仍沒有清除的話,將會(huì)響應(yīng)外部中斷1的請(qǐng)求;但是如果在響應(yīng)外部中斷0期間,外部中斷1的觸發(fā)信號(hào)產(chǎn)生后又撤除的話,IE1也會(huì)自動(dòng)清除,也就是說,執(zhí)行完外部中斷0后,不會(huì)去響應(yīng)外部中斷1。
當(dāng)多個(gè)中斷源同時(shí)向CPU請(qǐng)求中斷時(shí),CPU就可以通過中斷優(yōu)先權(quán)電路率先響應(yīng)中斷優(yōu)先權(quán)高的中斷請(qǐng)求,而把中斷優(yōu)先權(quán)低的中斷請(qǐng)求暫時(shí)擱置起來,等到處理完優(yōu)先權(quán)高的中斷請(qǐng)求后再來響應(yīng)優(yōu)先權(quán)低的中斷。
如果某一中斷源提出中斷請(qǐng)求后,CPU不能立即響應(yīng),只要該中斷請(qǐng)求標(biāo)志位不被軟件人為清除,中斷請(qǐng)求的狀態(tài)就將一直保持,直到CPU響應(yīng)中斷為止。但是對(duì)于串行口中斷,即使CPU響應(yīng)了中斷,其中斷標(biāo)志位RI/TI也不會(huì)自動(dòng)清零,而必須在中斷服務(wù)程序中設(shè)置
清除RI/TI的指令后,才會(huì)再一次地提出中斷請(qǐng)求。
25、在滿足應(yīng)用要求的前提下,選擇配較低的單片機(jī),較小的RAM/ROM、較低的ADC分辨率、較低的ADC速率,較少的IO管腳都可以降低單片機(jī)的整體功耗。當(dāng)然了,這個(gè)得能滿足你產(chǎn)品需求的前提下。
26、對(duì)于一個(gè)數(shù)字系統(tǒng)而言,其功耗大致滿足公式:P=CV2f。其中C為系統(tǒng)的負(fù)載電容,V為電源電壓,f為系統(tǒng)工作頻率[2]。功耗與電源電壓的平方成正比,因此電源電壓對(duì)系統(tǒng)的功耗影響最大,其次是工作頻率,再次就是負(fù)載電容。負(fù)載電容對(duì)設(shè)計(jì)人員而言,一般是不可控的,因此設(shè)計(jì)一個(gè)低功耗系統(tǒng),在不影響系統(tǒng)性能的前提下,盡可能地降低電源的電壓和工作頻率。對(duì)于大多數(shù)低功耗單片機(jī)來說,工作頻率越低,意味著消耗的電流也越小,但是不能認(rèn)為頻率越低,系統(tǒng)整體功耗越小,因?yàn)楣ぷ黝l率降低,意味著需要更長(zhǎng)的處理時(shí)間,其他外圍電路消耗的電能就越多。目前有很多單片機(jī)都允許有兩個(gè)或者兩個(gè)以上的時(shí)鐘源,低頻時(shí)鐘作為如UART、定時(shí)器等外圍功能器件的時(shí)鐘源,高頻時(shí)鐘作為系統(tǒng)的主時(shí)鐘。在不需要高速運(yùn)行的場(chǎng)合下,低頻時(shí)鐘也可以作為系統(tǒng)主時(shí)鐘使用。對(duì)于需要在工作狀態(tài)與空閑狀態(tài)之間頻繁切換的應(yīng)用,在考慮單片機(jī)本身低功耗的同時(shí),應(yīng)該考慮切換時(shí)間和切換電流??紤]到有些場(chǎng)合單片機(jī)的工作特點(diǎn),選擇單片機(jī)不光要關(guān)注工作電流,更應(yīng)該關(guān)注單片機(jī)休眠時(shí)的靜態(tài)電流。單片機(jī)豐富的低功耗模式和極低的靜態(tài)電流,在滿足特定應(yīng)用功能的同時(shí),有效降低系統(tǒng)的功耗。盡量關(guān)閉MCU內(nèi)部不用的資源,比如ATmega8內(nèi)部的模擬比較器,默認(rèn)是開著的,還有ATmega88內(nèi)部的大多數(shù)資源都可以在不用的時(shí)候用軟件關(guān)閉。
27、定時(shí)/ 計(jì)數(shù)器的實(shí)時(shí)性
定時(shí)/ 計(jì)數(shù)器啟動(dòng)計(jì)數(shù)后,當(dāng)計(jì)滿回0 溢出向主機(jī)請(qǐng)求中斷處理,由內(nèi)部硬件自動(dòng)進(jìn)行。但從回0 溢出請(qǐng)求中斷到主機(jī)響應(yīng)中斷并作出處理存在時(shí)間延遲,且這種延時(shí)隨中斷請(qǐng)求時(shí)的現(xiàn)場(chǎng)環(huán)境的不同而不同,一般需延時(shí)3 個(gè)機(jī)器周期以上,這就給實(shí)時(shí)處理帶來誤差差。大多數(shù)應(yīng)用場(chǎng)合可忽略不計(jì),但對(duì)某些要求實(shí)時(shí)性苛刻的場(chǎng)合,可采用動(dòng)態(tài)補(bǔ)償措施。
所謂動(dòng)態(tài)補(bǔ)償,即在中斷服務(wù)程序中對(duì)THx、TLx 重新置計(jì)數(shù)初值時(shí),應(yīng)將THx、TLx 從回0 溢出又重新從0 開始繼續(xù)計(jì)數(shù)的值讀出,并補(bǔ)償?shù)皆?jì)數(shù)初值中去進(jìn)行重新設(shè)置??煽紤]如下補(bǔ)償方法: CLR EA ;禁止中斷
MOV A,T L x ;讀TLx 中已計(jì)數(shù)值 ADD A,#LOW ;LOW 為原低字節(jié)計(jì)數(shù)初值 MOV T L x,A ;設(shè)置低字節(jié)計(jì)數(shù)初值 MOV A,#HIGH ;原高字節(jié)計(jì)數(shù)初值送A ADDC A,T H x ;高字節(jié)計(jì)數(shù)初值補(bǔ)償 MOV T H x,A ;置高字節(jié)計(jì)數(shù)初值 SETB EA ;開中斷
28、動(dòng)態(tài)讀取運(yùn)行中的定時(shí)器/計(jì)數(shù)值
在動(dòng)態(tài)讀取運(yùn)行中的定時(shí)/ 計(jì)數(shù)器的計(jì)數(shù)值時(shí),如果不加注意,就可能出錯(cuò)。這是因?yàn)椴豢赡茉谕粫r(shí)刻同時(shí)讀取THx 和TLx 中的計(jì)數(shù)值。比如,先讀TLx 后讀THx,因?yàn)槎〞r(shí)/ 計(jì)數(shù)器處于運(yùn)行狀態(tài),在讀TLx 時(shí)尚未產(chǎn)生向THx 進(jìn)位,而在讀THx 前已產(chǎn)生進(jìn)位,這時(shí)讀得的THx 就不對(duì)了;同樣,先讀THx 后讀TLx 也可能出錯(cuò)。
一種可避免讀錯(cuò)的方法是:先讀THx,后讀TLx,將兩次讀得的THx 進(jìn)行比較;若兩次讀得的值相等,則可確定讀的值是正確的,否則重復(fù)上述過程,重復(fù)讀得的值一般不會(huì)再錯(cuò)。此法的軟件編程如下:
RDTM: MOV A,THx ;讀取THx 存A 中 MOV R0,TLx ; 讀取TLx 存R0 中
CJNE A,THx,RDTM ;比較兩次THx 值,若相等,則讀得的值正確,否則重讀 MOV R1,A ;將THx 存于R1 中
29、掉電及空閑模式
掉電方式
當(dāng)PCON中的第二位PD為1時(shí),進(jìn)入掉電模式,不會(huì)執(zhí)行任何指令,外部時(shí)鐘停振,片內(nèi)所有功能部件停止工作,如定時(shí)器,串行口,外部中斷(部分增強(qiáng)型8051的外部中斷可以工作),但片內(nèi)RAM和SFR的內(nèi)容保持不變。標(biāo)準(zhǔn)8051從掉電狀態(tài)退出的惟一方法是硬件復(fù)位(部分增強(qiáng)型8051還可以通過外部中斷來退出掉電狀態(tài)),復(fù)位后,SFR被重新初始化,但RAM的內(nèi)容不變。因此,若要使得8051在供電恢復(fù)正常后繼續(xù)執(zhí)行掉電前的程序,那就必須在掉電前預(yù)先把SFR中的內(nèi)容保護(hù)到片內(nèi)RAM,并在供電恢復(fù)正常后為SFR恢復(fù)到掉電前的狀態(tài)。
當(dāng)PCON的第一位IDEL為1時(shí),進(jìn)入空閑模式,CPU停止工作,不會(huì)執(zhí)行任何指令,但中斷、串行口和定時(shí)器可以繼續(xù)工作。此時(shí),CPU現(xiàn)場(chǎng)(即SP、PC、PSW和ACC等)、片內(nèi)RAM和SFR中其他寄存器內(nèi)容均維持不變。退出空閑模式有兩種方法:
一、被允許中斷的中斷源發(fā)出中斷請(qǐng)求;
二、硬件復(fù)位。30、看門狗應(yīng)用
將喂狗操作(取反指令,如 CPL P1.0)分成兩步,放在主程序和中斷里執(zhí)行。如將SETB P1.0放在主程序中,將CLR P1.0放在中斷里,這樣可以避免主程序跑飛,中斷功能正?;蛘咧鞒绦蛘?,而中斷跑飛的情況導(dǎo)致看門狗失效。
31、volatile作用
如果將將變量加上volatile修飾,則編譯器保證對(duì)此變量的讀寫操作都不會(huì)被優(yōu)化(肯定執(zhí)行)。此例中i也應(yīng)該如此說明。
一般說來,volatile用在如下的幾個(gè)地方:
1、中斷服務(wù)程序中修改的供其它程序檢測(cè)的變量需要加volatile;
2、多任務(wù)環(huán)境下各任務(wù)間共享的標(biāo)志應(yīng)該加volatile;
3、存儲(chǔ)器映射的硬件寄存器通常也要加volatile說明,因?yàn)槊看螌?duì)它的讀寫都可能由不同意義;
另外,以上這幾種情況經(jīng)常還要同時(shí)考慮數(shù)據(jù)的完整性(相互關(guān)聯(lián)的幾個(gè)標(biāo)志讀了一半被打斷了重寫),在1中可以通過關(guān)中斷來實(shí)現(xiàn),2中可以禁止任務(wù)調(diào)度,3中則只能依靠硬件的良好設(shè)計(jì)了。32、51準(zhǔn)雙向口讀?。?/p>
只有1條指令:
MOV A,P1為讀端口寄存器 有兩條指令: MOV A,#0FFH MOV A,P1為讀引腳
33、采用C語言和匯編語言混合編程是最佳的選擇;
34、系統(tǒng)投入運(yùn)行的最初時(shí)刻,應(yīng)對(duì)系統(tǒng)進(jìn)行自檢和初始化。開機(jī)自檢在初始化前執(zhí)行,如果自檢無誤,則對(duì)系統(tǒng)進(jìn)行正常初始化,通常包括硬件初始化和軟件初始化兩個(gè)部分。硬件初始化是指對(duì)系統(tǒng)中的各種硬件資源設(shè)定明確的初始狀態(tài),如對(duì)各種可編程芯片進(jìn)行編程、對(duì)各I/O端口設(shè)定初始狀態(tài)和為單片機(jī)的硬件資源分配任務(wù)等。軟件初始化包括,對(duì)中斷的安排、對(duì)堆棧的安排、狀態(tài)變量的初始化、各種軟件標(biāo)志的初始化、系統(tǒng)時(shí)鐘的初始化和各
種變量?jī)?chǔ)存單元的初始化等。
35、按鍵連擊速度一般為3-4次/s。
36、復(fù)合鍵利用兩個(gè)以上按鍵同時(shí)按下時(shí)產(chǎn)生的按鍵效果,但實(shí)際情況下,不可能做到真正的“同時(shí)按下”,它們的時(shí)間差可以長(zhǎng)達(dá)50ms左右,故當(dāng)檢測(cè)到有KEY1按鍵按下時(shí),還要等待超過50ms,再判斷是否還有其他按鍵按下,再解析按鍵。
37、數(shù)碼管顯示閃爍效果時(shí),一般閃爍速度為1-4次/s。
38、大電流和高電壓設(shè)備的啟動(dòng)和關(guān)閉都是由軟件指令來完成,這些指令執(zhí)行后,必然引起強(qiáng)烈的干擾,這些干擾不能算隨機(jī)干擾,它們與軟件完全相關(guān);可以在最后才執(zhí)行這些可能引起強(qiáng)烈干擾的I/O操作,之后立即進(jìn)入睡眠狀態(tài),這樣就不會(huì)干擾到CPU,等CPU醒來后,干擾的高峰也基本過去。
39、用積分時(shí)間為20ms整數(shù)倍的雙積分型A/D轉(zhuǎn)換方式,能有效地抑制50Hz工頻干擾。40、掉電檢測(cè)電路必須在電壓下降到CPU最低工作電壓之前就提出中斷申請(qǐng),提前時(shí)間為幾百us到數(shù)ms,以便掉電中斷程序進(jìn)行掉電保護(hù)。
41、用定時(shí)器作看門狗:當(dāng)為專職看門狗時(shí),在主程序中周期性清0定時(shí)器計(jì)數(shù)值,以使定時(shí)器中斷不能產(chǎn)生,當(dāng)產(chǎn)生定時(shí)器中斷時(shí),表明看門狗溢出,此時(shí)應(yīng)執(zhí)行出錯(cuò)處理程序或者進(jìn)行復(fù)位。當(dāng)為兼職看門狗時(shí),可以在定時(shí)器中斷程序?qū)τ?jì)數(shù)值進(jìn)行加1,若計(jì)數(shù)值大于某值時(shí),表明看門狗溢出,而主程序中應(yīng)周期性地對(duì)計(jì)數(shù)值進(jìn)行清0。
42、中斷中,沖突發(fā)生的條件:
1)某一資源為中斷程序和主程序所使用;該資源可以為1個(gè)變量,也可以為1個(gè)數(shù)組或者1個(gè)緩沖區(qū)。
2)中斷程序或主程序?qū)υ撡Y源進(jìn)行了寫操作;
3)主程序不能用一條指令對(duì)資源完成讀或者寫操作。(這條不對(duì),參考深入淺出AVR單片機(jī)P100的例子)
當(dāng)這三個(gè)條件均滿足時(shí),即有可能發(fā)生資源沖突,導(dǎo)致程序偶然運(yùn)行不正常。為了避免發(fā)生沖突,可以在主程序中先關(guān)中斷,再對(duì)資源進(jìn)行讀或?qū)?,結(jié)束后再開中斷。
當(dāng)主程序?qū)Y源的訪問比較費(fèi)時(shí),長(zhǎng)期關(guān)中斷可能影響系統(tǒng)的實(shí)時(shí)性;解決的辦法是盡可能縮短關(guān)中斷的時(shí)間,將一邊訪問,一邊處理的工作方式改為集中訪問,分批處理。如果是讀該資源,則關(guān)中斷迅速將該資源的內(nèi)容轉(zhuǎn)移到緩沖區(qū),再開中斷,然后再對(duì)緩沖區(qū)中的信息進(jìn)行處理;如果是寫該資源,則先邊運(yùn)算邊寫緩沖區(qū),全部寫好后再關(guān)中斷,然后迅速將緩沖區(qū)中的內(nèi)容復(fù)制到該資源中,邊可以開中斷了。
43、A/B*C的運(yùn)算方案不如(A*C)/B的運(yùn)算方案精度高。因此,應(yīng)盡可能將出現(xiàn)偏差的運(yùn)算往后排,先進(jìn)行無偏差或偏差小的運(yùn)算。在定點(diǎn)運(yùn)算系統(tǒng)中,加減法只要不超限,是沒有偏差的,乘法運(yùn)算的結(jié)果會(huì)使字長(zhǎng)增加,如雙字節(jié)乘雙字節(jié),積為四字節(jié),如果保留全部結(jié)果,則沒有偏差的。乘法運(yùn)算的結(jié)果會(huì)使字長(zhǎng)增加,如雙字節(jié)乘雙字節(jié),積為四字節(jié),如果保留全部結(jié)果,則沒有偏差;如果受字長(zhǎng)限制,則要舍去低位字節(jié),從而產(chǎn)生舍入偏差。除法幾乎都是有偏差的能夠剛好整除的情況是很少的。在浮點(diǎn)運(yùn)算系統(tǒng)中,加減法由于要進(jìn)行對(duì)階操作,當(dāng)兩操作數(shù)的階碼相差較大時(shí),絕對(duì)值大的數(shù)有可能將絕對(duì)值小的數(shù)淹沒,使運(yùn)算的結(jié)果仍為絕對(duì)值大的數(shù),一點(diǎn)兒也看不出絕對(duì)值小的數(shù)對(duì)結(jié)果的影響。相比之下,浮點(diǎn)乘法和浮點(diǎn)除法引起的偏差就比較小,它們能夠保持一個(gè)比較穩(wěn)定的運(yùn)算精度。另外,不管在定點(diǎn)系統(tǒng)中還是在浮點(diǎn)系統(tǒng)中,都要盡可能避免兩個(gè)數(shù)值相近的數(shù)過早相減,因?yàn)樗麄兌伎赡苁墙浦担鄿p以后,差的有效數(shù)值大大減少,必然帶來更大的相對(duì)誤差。經(jīng)過后續(xù)運(yùn)算之后,結(jié)果可能離真實(shí)值相差甚遠(yuǎn)。再有,盡可能不要用絕對(duì)值小的數(shù)作分母,否則引起的誤差也是很大的。
44、要對(duì)軟件標(biāo)志位的使用進(jìn)行說明;對(duì)于全局定義的軟件標(biāo)志,它有惟一的定義;對(duì)于局
部定義的軟件標(biāo)志,必須注明其有效范圍。
45、軟件理論已經(jīng)證明:任何一個(gè)程序(除某些短小的子程序外)都存在錯(cuò)誤(缺陷),人們可以通過合理的測(cè)試來證明它仍然存在錯(cuò)誤,卻無法證明它已經(jīng)沒有錯(cuò)誤。軟件測(cè)試應(yīng)該把發(fā)現(xiàn)錯(cuò)誤作為目的,而不能把“程序調(diào)通”作為目的。
1.P0口能驅(qū)動(dòng)8個(gè)TTL電路意思: 8051單片機(jī)P0口驅(qū)動(dòng)8個(gè)TTL電路的意思,TTL電路輸入懸浮時(shí)相當(dāng)于輸入高電平,因此P0口輸出高電平驅(qū)動(dòng)TTL電路幾乎不需輸出電流。TTL電路輸入為低電平時(shí)最少要釋放1mA電流,因此P0口輸出低電平時(shí)吸收的電流大于8mA。TTL輸出高電平最大1.6mA,輸出低電平時(shí)吸收的最大電流 16mA。51輸出最好用低電平有效,推動(dòng)PNP管,因?yàn)?1復(fù)位后IO為高電平,如果用高電平有效推N管的話上電復(fù)位后會(huì)先讓外部電路動(dòng)做。
2.在51里,有一條指令沒有寫進(jìn)書本,機(jī)器碼為A5,執(zhí)行操作:將下一個(gè)字節(jié)跳過而不管它是單字節(jié)指令還是雙字節(jié)或三字節(jié)指令的一部分.如果反匯編工具不識(shí)別A5指令的話,你在A5以后的程序反匯編后就錯(cuò)亂無章.當(dāng)成個(gè)數(shù)據(jù),用db a5 即可
3.有些51系統(tǒng)容易復(fù)位,一般是電路設(shè)計(jì)上的問題。很多電路介紹的復(fù)位電路都是10u和8.2k,但是在實(shí)踐過程中我們發(fā)現(xiàn)該電路在電源不穩(wěn)時(shí)很容易復(fù)位,特別是附近有大干擾時(shí),如繼電器動(dòng)作等。我建議使用22u和1k的復(fù)位電路,有許多電路改為該數(shù)值后就工作穩(wěn)定了。當(dāng)然,最好的辦法還是使用專用復(fù)位電路或三極管電路,但是那樣要增加成本和體積。
4.電路中的濾波電容一定要注意加上,最好每個(gè)芯片都再加一個(gè)約0.1uf的電容,這樣對(duì)電路的穩(wěn)定性很有好處。如果使用了看門狗電路,就有可能是軟件問題,程序工作到某些環(huán)節(jié)時(shí)忘記了復(fù)位看門狗,結(jié)果計(jì)數(shù)滿了就復(fù)位了。
5.如果在中斷程序中改變了多字節(jié)類型的變量,那么中斷程序以外的程序中(主程序,子函數(shù)),讀寫前要關(guān)中斷,讀寫后再開中斷。舉一反三:
其他的數(shù)據(jù)類型也可能有這種影響。例如:長(zhǎng)整型、浮點(diǎn)型。
上面的例子是中斷里寫,主程序中讀。相反主程序?qū)?,中斷里讀也可能出錯(cuò)。
6.教你一招,別說我損。。
寫一個(gè)測(cè)試代碼,反復(fù)向EEPROM中的某幾個(gè)不用的空位字節(jié)寫入0x55,直到把它干到壽命終結(jié)不能寫為止,如果按照10MS寫一個(gè)字節(jié)計(jì)算的話,大約只需要20分鐘就能干掉它。然后向這個(gè)芯片中燒入你的正常代碼,當(dāng)然了,這個(gè)代碼中應(yīng)該有一段上電檢測(cè)EEPROM這幾個(gè)字節(jié)的代碼,先嘗試向它寫入0Xaa,然后再讀出來看看是否寫入成功,如果沒寫入則再來兩次,如果始終不能寫入,這當(dāng)作檢查通過,如果就判斷為檢查失敗,這個(gè)時(shí)候代碼要裝著‘不知情’繼續(xù)執(zhí)行正確代碼,下面的‘破壞’行為應(yīng)該如何做就不要我講了把? 破壞行為要裝的掩蔽一點(diǎn),例如調(diào)一段代碼檫除FLASH的代碼,嘿嘿,那對(duì)方肯定以為CHIP質(zhì)量不好容易出現(xiàn)FLASH數(shù)據(jù)丟失,如果對(duì)方使用了AD什么的,可以偶爾人為讓它波動(dòng)大一點(diǎn),這樣對(duì)方一般只會(huì)懷疑PCB和硬件電路弄的不好,而不會(huì)想到是代碼動(dòng)手腳了,長(zhǎng)久以后他的用戶肯定也會(huì)認(rèn)為他們的產(chǎn)品質(zhì)量不好,你這個(gè)時(shí)候就可以向他的客戶推廣你的產(chǎn)品了。。
上電寫EEPROM的次數(shù)要在你自己的產(chǎn)品質(zhì)量承諾的壽命時(shí)間之內(nèi),否則你自己的產(chǎn)品也
可能增加維修。。
這個(gè)方法特別適合在外接單掙錢的工程師,你可能給了對(duì)方幾個(gè)CHIP做測(cè)試,對(duì)方測(cè)試通過偏說不行,就是不給你余款,然后把CHIP拿去CRACK,妄想省掉這個(gè)錢,NND,讓他們見鬼去把,俺這招已經(jīng)對(duì)付了不少不良分子。。
7.AD鍵盤
8.防解密高招
高招, 解密
使用一些帶內(nèi)部晶振和內(nèi)部EEPROM的單片機(jī),如PIC16F913和ATMEGA8等,帶內(nèi)部晶振的單片機(jī)有一個(gè)寄存器OSCTUNE(或OSCCAL),這個(gè)是芯片廠家用來校準(zhǔn)內(nèi)部晶振的,范圍從0-31,出廠時(shí)同型號(hào)的單片機(jī)這個(gè)寄存器的值是不一樣.我們可以利用一些隱藏功能,將OSCTUNE寄存器的值存入內(nèi)部的EEPROM中,開機(jī)時(shí)讀取EEPROM的值,再與OSCTUNE的值相比較, 若二者相同系統(tǒng)正常工作,若不
相同則不正常工作.解密者將解密的程序燒寫進(jìn)單片機(jī)中后,會(huì)發(fā)大部分的芯片不能正常工作,因?yàn)樗麄儾恢肋@個(gè)隱藏的功能.舉例說明: 芯片為PIC16F913,這個(gè)廠品有4個(gè)按鍵(KEY0、KEY1、KEY2、KEY3),內(nèi)部我們可以設(shè)定這樣子一個(gè)隱藏的功能,如果KEY0與KEY1同時(shí)按下3秒鐘以上,會(huì)將OSCTUNE寄存器存入單片機(jī)的EEPROM中。
開機(jī)復(fù)位后,讀取EEPROM中的數(shù)據(jù),與OSCTUNE寄存器相比較,若二者相同系統(tǒng)正常工作,若不相同則不正常工作。以上有三個(gè)重點(diǎn):
1、對(duì)于OSCTUNE寄存器不要進(jìn)行寫的操作,只進(jìn)行讀的操作,因?yàn)閷懥艘淮我院?,就一直是你寫的這個(gè)數(shù)據(jù)的。
2、剛才介紹的KEY0、KEY1同時(shí)按下3秒鐘這個(gè)功能,可不能讓解密者(包括產(chǎn)品的用戶)知道,當(dāng)然大家可以用別的隱藏的功能。
3、單片機(jī)中的OSCTUNE寄存器(或OSCCAL)的值,同一種型號(hào)的單片機(jī)不是每一個(gè)都是一樣的,有32個(gè)數(shù)據(jù),也就是說32個(gè)芯片中有一個(gè)是與解密的單片機(jī)是一樣的。這樣子造成的后果是:解密者解密了你的程序以后,卻發(fā)現(xiàn)有些單片機(jī)可以正常工作,可有些單片機(jī)不能正常工作,可以說是大部分的單片機(jī)不能正常工作。
不過需要注意一下:要是遇到強(qiáng)干擾把EEPROM中的數(shù)據(jù)改變了看客戶怎么收拾你!
9.PIC16F887A中,要求SLEEP指令后的下一條指令為NOP;不知51和AVR的芯片是否需要注意這一點(diǎn)。經(jīng)查,AVR的datasheet無此要求,可能是其喚醒時(shí),存在啟動(dòng)延時(shí)。
10.中斷隨時(shí)隨刻都有可能產(chǎn)生,故編寫程序時(shí),需要時(shí)刻注意中斷的影響。
11.注意以下語句在某些編譯器下,結(jié)果可能出錯(cuò):
unsigned char a,b;
unsigned int sum;
a=0x80;
b=0x80;
sum=a+b;
12.編程序最重要是好維護(hù)。幾個(gè)執(zhí)行時(shí)間和程序的可讀性比,和開發(fā)時(shí)間比,我認(rèn)為是不用考慮的。為了幾個(gè)機(jī)器周期而把程序搞得很復(fù)雜,是非常愚蠢的行為??墒呛芏嗳硕鄻反瞬黄0???傮w系統(tǒng)的算法是要考慮優(yōu)化的問題的,這點(diǎn)我是贊同的。天天在技術(shù)上對(duì)著幾行程序去優(yōu)化,而導(dǎo)致開發(fā)速度減慢,是非常愚蠢的行為。
13.串口通信協(xié)議:引導(dǎo)碼/識(shí)別碼+長(zhǎng)度+命令字+data+校驗(yàn)
通過引導(dǎo)碼/識(shí)別碼、長(zhǎng)度、校驗(yàn)三步檢測(cè) 每當(dāng)出錯(cuò)則丟棄當(dāng)前數(shù)據(jù)并還原接收狀態(tài)和空間…………
14.當(dāng)準(zhǔn)備調(diào)試一塊板的時(shí)候,一定要先認(rèn)真的做好目視檢查,檢查在焊接的過程中是否有可見的短路和管腳搭錫等故障,檢查是否有元器件型號(hào)放置錯(cuò)誤,第
一腳放置錯(cuò)誤,漏裝配等問題,然后用萬用表測(cè)量各個(gè)電源到地的電阻,以檢查是否有短路,這個(gè)好習(xí)慣可以避免貿(mào)然上電后損壞單板。調(diào)試的過程中要有平和的心態(tài),遇見問題是非常正常的,要做的就是多做比較和分析,逐步的排除可能的原因,要堅(jiān)信“凡事都是有辦法解決的”和“問題出現(xiàn)一定有它的原因”,這樣最后一定能調(diào)試成功。
做一個(gè)硬件設(shè)計(jì)人員要鍛煉出良好的溝通能力,面對(duì)壓力的調(diào)節(jié)能力,同一時(shí)間處理多個(gè)事務(wù)的協(xié)調(diào)和決斷能力和良好平和的心態(tài),還有細(xì)心和認(rèn)真等等。
對(duì)初學(xué)者來說,在新的領(lǐng)域面前一窮二白,要學(xué)的東西太多太多,一味機(jī)械地試圖學(xué)習(xí)這些“高深的語法”和“看不懂的技巧”,胡亂模仿些別人的“優(yōu)秀風(fēng)格”,不能說完全無所得,只能說會(huì)學(xué)得很累,而且往往事倍功半---久而久之,信心喪失殆盡,半途而廢。學(xué)習(xí)編程,做自己便好。學(xué)習(xí)眼前能夠看懂的內(nèi)容,多寫自己會(huì)寫的程序。對(duì)于已經(jīng)學(xué)到的東西,仔細(xì)地體會(huì)、思考,發(fā)掘其中的發(fā)展;學(xué)會(huì)用一種研究的心態(tài)去考察你的每一個(gè)疑問;不可以輕易地人云亦云,在網(wǎng)上看了別人無責(zé)任的經(jīng)驗(yàn),甚至是寫錯(cuò)了,丟在一邊,懶得改的東西之后,就放棄了自己的探索;要學(xué)會(huì)堅(jiān)持自我,遇到別人先進(jìn)的做法,在自己還沒有體會(huì)到自己當(dāng)前這種做法的劣勢(shì)之前,不要輕易盲從;同樣,使用了先進(jìn)的方法,在沒有同時(shí)理解這種做法的優(yōu)點(diǎn)和缺點(diǎn)之前,請(qǐng)不要輕易地感嘆“這種方法好,跟帖頂一下!”“大師高手寧有種乎?”堅(jiān)持“體會(huì)到了才是學(xué)到了”的態(tài)度,最終形成自己的風(fēng)格,形成自己的技巧。
第一章初識(shí)Java 1.程序是為了讓計(jì)算機(jī)執(zhí)行某些操作或解決某個(gè)問題而編寫的一系列有序指令的集合。
2.Java包括編程語言和相關(guān)的技術(shù)。
3.Java主要用于開發(fā),桌面應(yīng)用程序和Internet應(yīng)用程序。4.開發(fā)一個(gè)Java應(yīng)用程序的基本步驟:編寫源程序,編譯程序和運(yùn)行程序。源程序以.java為擴(kuò)展名,編譯后生成的文件以.class為擴(kuò)展名。使用javac命令可以編譯.java文件,使用java命令可以運(yùn)行編譯后生成的.class文件。
5.編寫Java程序要符合Java編碼規(guī)范,為程序編寫注釋可大大增加程序的閱讀性。
6.MyEcplise是一個(gè)功能強(qiáng)大的集成開發(fā)環(huán)境(IDE)。它的各種窗口便于Java程序的開發(fā),調(diào)試和管理。
第二章變量、數(shù)據(jù)類型和運(yùn)算符
1.變量是一個(gè)數(shù)據(jù)存儲(chǔ)空間的表示,它是存儲(chǔ)數(shù)據(jù)的基本單元。變量的命名規(guī)則:
(1)必須以字母,“_”,“$”開頭。(2)可以包括數(shù)字,但不能以數(shù)字開頭(3)不能包括除“_”,“$”以外的特殊符號(hào)(4)不能使用Java語言關(guān)鍵字或者保留字(goto)
2.Java中數(shù)據(jù)類型分為基本數(shù)據(jù)類型和引用數(shù)據(jù)類型,基本數(shù)據(jù)類型有整型(int),雙精度浮點(diǎn)型(double),字符型(char)和字符串(String)。3.變量要先聲明并賦值,才能使用。4.Java提供各種類型的運(yùn)算符,具體如下。
(1)賦值運(yùn)算(=)(2)算術(shù)運(yùn)算符(+,-,*,/,%)(3)關(guān)系運(yùn)算符(>,>=,<,<=,==,!=)(4)條件運(yùn)算符(條件?表達(dá)式1:表達(dá)式2)(5)邏輯運(yùn)算符(&& , || ,!, & , |)&&(短路與)與&的區(qū)別:&&進(jìn)行判斷時(shí),當(dāng)?shù)谝粋€(gè)條件為假,則不需要判斷第二個(gè)條件,結(jié)果為假。&進(jìn)行判斷時(shí),即使第一個(gè)條件為假時(shí),也需要判斷完第二個(gè)條件才能給出結(jié)果為假。||(短路或)與|的區(qū)別:與上同理(5)位運(yùn)算符(&, | , << , >> , >>>)5.數(shù)據(jù)類型轉(zhuǎn)換是為了方便不同類型的數(shù)據(jù)之間進(jìn)行運(yùn)算
6.數(shù)據(jù)類型轉(zhuǎn)換包括了自動(dòng)類型轉(zhuǎn)換和強(qiáng)制類型轉(zhuǎn)換,自動(dòng)類型轉(zhuǎn)換需要滿足類型兼容且目標(biāo)類型大于源類型的條件
7.Java中使用boolean類型表示真假,boolean類型的兩個(gè)值為true和false。
8.Java中的關(guān)系運(yùn)算符可以用于來比較大小,高低,多少等,比較厚的結(jié)果是boolean類型。
9.Java提供Scanner類,可以實(shí)現(xiàn)從控制臺(tái)獲取鍵盤上輸入的信息
第三章選擇結(jié)構(gòu)(一)Java中的if選擇結(jié)構(gòu),包括以下形式
(1)基本的if選擇結(jié)構(gòu):可以處理單一或組合條件的情況(2)if-else選擇結(jié)構(gòu):可以處理簡(jiǎn)單的條件分支情況(3)多重if選擇結(jié)構(gòu):可以處理連續(xù)區(qū)間的條件分支情況(4)嵌套if選擇結(jié)構(gòu):可以處理復(fù)雜的條件分支情況
第四章選擇結(jié)構(gòu)(二)1.switch選擇結(jié)構(gòu)適用于進(jìn)行等值判斷
2.switch關(guān)鍵字后面小括號(hào)里表達(dá)式的值可以是int , short , byte , char , 枚舉 , String(JDK1.7開始支持)
第五章循環(huán)結(jié)構(gòu)(一)1.循環(huán)結(jié)構(gòu)由循環(huán)結(jié)構(gòu)和循環(huán)操作構(gòu)成,只要滿足循環(huán)條件,循環(huán)操作就會(huì)反復(fù)執(zhí)行
2.使用循環(huán)結(jié)構(gòu)解決問題問題的步驟:分析循環(huán)條件和循環(huán)操作,套用循環(huán)結(jié)構(gòu)的語法寫出代碼,檢查循環(huán)能否退出
3.while循環(huán)結(jié)構(gòu)是先判斷后執(zhí)行,do-while是先執(zhí)行,后判斷。Do-while至少執(zhí)行一次。
4.debug調(diào)試:設(shè)置斷點(diǎn),單步運(yùn)行,觀察變量
第六章循環(huán)結(jié)構(gòu)(二)1.for循環(huán)結(jié)構(gòu)的語法結(jié)構(gòu)如下
for(表達(dá)式1:表達(dá)式2:表達(dá)式3){
} //循環(huán)體
表達(dá)式1:循環(huán)結(jié)構(gòu)的初始部分,為循環(huán)變量賦初值 表達(dá)式2:循環(huán)結(jié)構(gòu)的循環(huán)條件
表達(dá)式3:循環(huán)條件的迭代部分,通常用來修改循環(huán)變量的值 2.用break和continue語句控制流程
(1)break語句用于終止某個(gè)循環(huán),程序跳轉(zhuǎn)到循環(huán)體外的下一條語句。Break也可以在switch語句中使用
(2)continue語句用于跳出本次循環(huán),進(jìn)入下一次循環(huán)
(3)return可以結(jié)束當(dāng)前方法的執(zhí)行并退出,返回調(diào)用該方法的語句處
第七章數(shù)組
1.數(shù)組是可以在內(nèi)存中連續(xù)存儲(chǔ)多個(gè)元素的結(jié)構(gòu),數(shù)組中的所有元素必須屬于相同的數(shù)據(jù)類型
2.數(shù)組中的元素通過數(shù)組的下標(biāo)進(jìn)行訪問,數(shù)組的下標(biāo)從0開始 3數(shù)組可用一個(gè)循環(huán)為元素賦值,或用一個(gè)循環(huán)輸出數(shù)組中的元素信息
4.通過數(shù)組名.length可獲得數(shù)組長(zhǎng)度
5.利用Arrays.提供的sort()方法可以方便的對(duì)數(shù)組中的元素進(jìn)行排序 6.二維數(shù)組實(shí)際上就是一個(gè)一維數(shù)組,他的每個(gè)元素又是一個(gè)一維數(shù)組。
第八章循環(huán)結(jié)構(gòu)進(jìn)階
1.數(shù)組的輸入排序,選擇排序,冒泡排序
2.在二重循環(huán)中可以使用break、continue語句控制程序的執(zhí)行 選擇排序:
思路:每次循環(huán)得到最小值的下標(biāo),然后交換數(shù)據(jù)。如果交換的位置等于原來的位置,則不交換。插入排序:
思路:將數(shù)據(jù)插入到已排序的數(shù)組中。
HTML(即超文本標(biāo)記語言)的學(xué)習(xí)總結(jié):
一:(html基本標(biāo)記):
head,頭部標(biāo)記 里面常用的標(biāo)記(
)title 標(biāo)題標(biāo)記
二:(文字與段落)
標(biāo)題文字的對(duì)齊方式:align屬性值(leftcenterright)設(shè)置文字常用屬性:(face字體;size字號(hào);color顏色)
設(shè)置文字常用標(biāo)記:=文本 粗體;斜體;下劃線;段落標(biāo)記
換行標(biāo)記
三 :(超鏈接)
超鏈接語法:新浪
建立書簽:連接文字
四 :(插入圖像及圖像連接)
圖像的格式:jpg格式; png格式;gif格式;bmp;
插入圖像語法:
注:圖片標(biāo)記
不成對(duì)出現(xiàn)圖像的超鏈接:
五 :(多媒體)
滾動(dòng)文字的標(biāo)記與語法:
....滾動(dòng)文字
設(shè)置滾動(dòng)文字常用屬性:
滾動(dòng)方向:direction=(up;down;left;right)
背景音樂的設(shè)置:注:圖片標(biāo)記不成對(duì)出現(xiàn)
六(表格的插入)
標(biāo)格的插入:
設(shè)置表格的常用屬性:width寬;height高;align對(duì)齊方式;標(biāo)格的邊框:border
標(biāo)格的邊框顏色:bordercolor
行文字以及表格標(biāo)題的對(duì)其方式:valign
水平跨度:colspan
垂直跨度:rowspan
單元格的亮,暗邊框:bordercolorlightbordercolordark
七(框架)
框架的基本結(jié)構(gòu)語法: