我們進(jìn)修串口通訊次要是要完成單片機(jī)和電腦之間的信息交互,可以用電腦掌握單片機(jī)的一些信息,可以把單片機(jī)的一些信息情況發(fā)給電腦上的軟件。下面我們就做一個(gè)復(fù)雜的例程,完成單片機(jī)串口調(diào)試助手發(fā)送的數(shù)據(jù),在我們開辟板上的數(shù)碼管上顯示出來。
企業(yè)建站必須是能夠以充分展現(xiàn)企業(yè)形象為主要目的,是企業(yè)文化與產(chǎn)品對(duì)外擴(kuò)展宣傳的重要窗口,一個(gè)合格的網(wǎng)站不僅僅能為公司帶來巨大的互聯(lián)網(wǎng)上的收集和信息發(fā)布平臺(tái),成都創(chuàng)新互聯(lián)公司面向各種領(lǐng)域:成都集裝箱等成都網(wǎng)站設(shè)計(jì)、成都營銷網(wǎng)站建設(shè)解決方案、網(wǎng)站設(shè)計(jì)等建站排名服務(wù)。
#includesbit ADDR3 = P1^3; sbit ENLED = P1^4; unsigned char code LedChar[] = { //數(shù)碼管顯示字符轉(zhuǎn)換表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; unsigned char LedBuff[7] = { //數(shù)碼管+自力 LED 顯示緩沖區(qū) 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; unsigned char T0RH = 0; //T0 重載值的高字節(jié) unsigned char T0RL = 0; //T0 重載值的低字節(jié) unsigned char RxdByte = 0; //串口接納到的字節(jié) void ConfigTimer0(unsigned int ms); void ConfigUART(unsigned int baud); void main(){ EA = 1; //使能總中綴 ENLED = 0; //選擇數(shù)碼管和自力 LED ADDR3 = 1; ConfigTimer0(1); //設(shè)置裝備擺設(shè) T0 準(zhǔn)時(shí) 1ms ConfigUART(9600); //設(shè)置裝備擺設(shè)波特率為 9600 while (1){ //將接納字節(jié)在數(shù)碼管上以十六進(jìn)制方式顯示出來 LedBuff[0] = LedChar[RxdByte & 0x0F]; LedBuff[1] = LedChar[RxdByte >> 4]; } } /* 設(shè)置裝備擺設(shè)并啟動(dòng) T0,ms-T0 準(zhǔn)時(shí)工夫 */ void ConfigTimer0(unsigned int ms){ unsigned long tmp; //暫時(shí)變量 tmp = 11059200 / 12; //準(zhǔn)時(shí)器計(jì)數(shù)頻率 tmp = (tmp * ms) / 1000; //盤算所需的計(jì)數(shù)值 tmp = 65536 - tmp; //盤算準(zhǔn)時(shí)重視載值 tmp = tmp + 13; //賠償中綴呼應(yīng)延時(shí)形成的誤差 T0RH = (unsigned char)(tmp>>8); //準(zhǔn)時(shí)重視載值拆分為上下字節(jié) T0RL = (unsigned char)tmp; TMOD &= 0xF0; //清零 T0 的掌握位 TMOD |= 0x01; //設(shè)置裝備擺設(shè) T0 為形式 1 TH0 = T0RH; //加載 T0 重載值 TL0 = T0RL; ET0 = 1; //使能 T0 中綴 TR0 = 1; //啟動(dòng) T0 } /* 串口設(shè)置裝備擺設(shè)函數(shù),baud-通訊波特率 */ void ConfigUART(unsigned int baud){ SCON = 0x50; //設(shè)置裝備擺設(shè)串口為形式 1 TMOD &= 0x0F; //清零 T1 的掌握位 TMOD |= 0x20; //設(shè)置裝備擺設(shè) T1 為形式 2 TH1 = 256 - (11059200/12/32)/baud; //盤算 T1 重載值 TL1 = TH1; //初值等于重載值 ET1 = 0; //制止 T1 中綴 ES = 1; //使能串口中綴 TR1 = 1; //啟動(dòng) T1 } /* LED 靜態(tài)掃描刷新函數(shù),需在準(zhǔn)時(shí)中綴中挪用 */ void LedScan(){ static unsigned char i = 0; //靜態(tài)掃描索引 P0 = 0xFF; //封閉一切段選位,顯示消隱 P1 = (P1 & 0xF8) | i; //位選索引值賦值到 P1 口低 3 位 P0 = LedBuff[i]; //緩沖區(qū)中索引地位的數(shù)據(jù)送到 P0 口 if (i < 6){ //索引遞增輪回,遍歷全部緩沖區(qū) i++; }else{ i = 0; } } /* T0 中綴效勞函數(shù),完成 LED 掃描 */ void InterruptTimer0() interrupt 1{ TH0 = T0RH; //從新加載重載值 TL0 = T0RL; LedScan(); //LED 掃描顯示 } /* UART 中綴效勞函數(shù) */ void InterruptUART() interrupt 4{ if (RI){ //接納到字節(jié) RI = 0; //手動(dòng)清零接納中綴標(biāo)記位 RxdByte = SBUF; //接納到的數(shù)據(jù)保管到接納字節(jié)變量中 //接納到的數(shù)據(jù)又直接發(fā)還,叫作-"echo", //用以提醒用戶輸出的信息能否已準(zhǔn)確接納 SBUF = RxdByte; } if (TI){ //字節(jié)發(fā)送終了 TI = 0; //手動(dòng)清零發(fā)送中綴標(biāo)記位 } }
人人在做這個(gè)試驗(yàn)的時(shí)分,有個(gè)小成績(jī)要留意一下。由于 STC89C52 下載程序是運(yùn)用了UART 串口下載,下載完程序后,程序運(yùn)轉(zhuǎn)起來了,可是下載軟件最初還會(huì)經(jīng)過串口發(fā)送一些額定的數(shù)據(jù),所以程序剛下載出來不是顯示 00,而能夠是其他數(shù)據(jù)。人人只需把電源開關(guān)封閉,從新翻開一次就好了。
仔細(xì)的同窗能夠會(huì)發(fā)現(xiàn),在串口調(diào)試助手發(fā)送選項(xiàng)和接納選項(xiàng)處,還有個(gè)“字符格局發(fā)送”和“字符格局顯示”,這是什么意思呢?
先拋開我們運(yùn)用的漢字不談,那么我們常用的字符就包括了 0~9 的數(shù)字、A~Z/a~z 的字母、還有各類標(biāo)點(diǎn)符號(hào)等。那么在單片機(jī)零碎外面我們?cè)鯓觼肀憩F(xiàn)它們呢? ASCII 碼(American Standard Code for Information Interchange,即美國信息交換規(guī)范代碼)可以完成這個(gè)任務(wù):我們曉得,在單片機(jī)中一個(gè)字節(jié)的數(shù)據(jù)可以有 0~255 共 256 個(gè)值,我們?nèi)€(gè)中的 0~127 共 128 個(gè)值付與了它別的一層涵義,即讓它們辨別來代表一個(gè)常用字符,其詳細(xì)的對(duì)應(yīng)關(guān)系如表 11-3 所示。
表 11-3 ASCII 碼字符表
ASC | 掌握 | ASCII | 字符 | ASCII | 字符 | ASCII | 字符 |
---|---|---|---|---|---|---|---|
000 值 | NUL 字符 | 032 值 | (space) | 064 值 | @ | 096 值 | |
001 | SOH | 033 | ! | 065 | A | 097 | a |
002 | STX | 034 | " | 066 | B | 098 | b |
003 | ETX | 035 | # | 067 | C | 099 | c |
004 | EOT | 036 | $ | 068 | D | 100 | d |
005 | END | 037 | % | 069 | E | 101 | e |
006 | ACK | 038 | & | 070 | F | 102 | f |
007 | BEL | 039 | ' | 071 | G | 103 | g |
008 | BS | 040 | ( | 072 | H | 104 | h |
009 | HT | 041 | ) | 073 | I | 105 | i |
010 | LF | 042 | * | 074 | J | 106 | j |
011 | VT | 043 | + | 075 | K | 107 | k |
012 | FF | 044 | , | 076 | L | 108 | l |
013 | CR | 045 | - | 077 | M | 109 | m |
014 | SO | 046 | . | 078 | N | 110 | n |
015 | SI | 047 | / | 079 | O | 111 | o |
016 | DLE | 048 | 0 | 080 | P | 112 | p |
017 | DC1 | 049 | 1 | 081 | Q | 113 | q |
018 | DC2 | 050 | 2 | 082 | R | 114 | r |
019 | DC3 | 051 | 3 | 083 | S | 115 | s |
020 | DC4 | 052 | 4 | 084 | T | 116 | t |
021 | NAK | 053 | 5 | 085 | U | 117 | u |
022 | SYN | 054 | 6 | 086 | V | 118 | v |
023 | ETB | 055 | 7 | 087 | W | 119 | w |
024 | CAN | 056 | 8 | 088 | X | 120 | x |
025 | EM | 057 | 9 | 089 | Y | 121 | y |
026 | SUB | 058 | : | 090 | Z | 122 | z |
027 | ESC | 059 | ; | 091 | [ | 123 | { |
028 | FS | 060 | < | 092 | \ | 124 | | |
029 | GS | 061 | = | 093 | ] | 125 | } |
030 | RS | 062 | > | 094 | ^ | 126 | ~ |
031 | US | 063 | ? | 095 | _ | 127 | DEL |
如許我們就在常用字符和字節(jié)數(shù)據(jù)之間樹立了逐個(gè)對(duì)應(yīng)的關(guān)系,那么如今一個(gè)字節(jié)就既可以代表一個(gè)整數(shù)又可以代表一個(gè)字符了,但它實(shí)質(zhì)上只是一個(gè)字節(jié)的數(shù)據(jù),而我們付與了它分歧的涵義,什么時(shí)分付與它哪一種涵義就看編程者的意圖了。ASCII 碼在單片機(jī)零碎中使用十分普遍,我們后續(xù)的課程也會(huì)常常運(yùn)用到它,下面我們來對(duì)它做一個(gè)直不雅的看法,同窗們必定要深入了解其實(shí)質(zhì)。
對(duì)比上述表格,我們就可以完成字符和數(shù)字之間的轉(zhuǎn)換了,比方照樣這個(gè)程序,我們發(fā)送的時(shí)分改成字符格局發(fā)送,接納照樣用十六進(jìn)制接納,如許接納和數(shù)碼管好做一下比照。
我們用字符格局發(fā)送一個(gè)小寫的 a,前往一個(gè)十六進(jìn)制的 0x61,數(shù)碼管上顯示的也是 61,ASCII 碼內(nèi)外字符 a 對(duì)應(yīng)十進(jìn)制是 97,等于十六進(jìn)制的 0x61;我們?cè)儆米址窬职l(fā)送一個(gè)數(shù)字 1,前往一個(gè)十六進(jìn)制的 0x31,數(shù)碼管上顯示的也是 31,ASCII 內(nèi)外字符 1 對(duì)應(yīng)的十進(jìn)制是 49,等于十六進(jìn)制的 0x31。這下人人就該清晰了:所謂的十六進(jìn)制發(fā)送和十六進(jìn)制接納,多是按字節(jié)數(shù)據(jù)的真實(shí)值停止的;而字符格局發(fā)送和字符格局接納,是按 ASCII 碼表中字符方式停止的,但它實(shí)踐上最終傳輸?shù)恼諛右粋€(gè)字節(jié)數(shù)據(jù)。這個(gè)表格,當(dāng)然不需求人人去記住,了解它,用的時(shí)分過去查就行了。
通訊的進(jìn)修,不像前邊掌握局部那么直不雅了,通訊局部我們的程序只能取得一個(gè)后果,而其進(jìn)程我們卻無法直接看到,所以漸漸的能夠人人就會(huì)曉得有示波器和邏輯剖析儀這類丈量?jī)x器。假如黌舍試驗(yàn)室或許公司里有示波器或許邏輯剖析儀這類儀器,可以拿過去抓一下串口波形,直不雅的理解一下。假如臨時(shí)還沒有這些儀器,先曉得這么回事,有前提再說。由于工具類裝備有的比擬昂貴,有前提可以盡量運(yùn)用黌舍或許公司的。在這里我用一款簡(jiǎn)略單純的邏輯剖析儀把串口通訊的波形抓出來給人人看一下,人人理解一下即可,如圖 11-7 所示。
圖 11-7 邏輯剖析儀串口數(shù)據(jù)表示圖
剖析儀和示波器的感化,就是把通訊進(jìn)程的波形抓出來停止剖析。先大約說一下波形的意思。波形右邊是低位,左邊是高位,上邊這個(gè)波形是電腦發(fā)送給單片機(jī)的,下邊這個(gè)波形是單片機(jī)回發(fā)給電腦的。以上邊的波形為例,右邊第一位是肇端位 0,從低位到高位順次是10001100,次序倒一下,就是數(shù)據(jù) 0x31,也就是 ASCII 碼內(nèi)外的‘1’。人人可以留意到剖析儀在每一個(gè)數(shù)據(jù)位都給標(biāo)了一個(gè)白色的點(diǎn),表現(xiàn)是數(shù)據(jù),肇端位和有數(shù)據(jù)的時(shí)分都沒有這個(gè)白點(diǎn)。工夫標(biāo) T1 和 T2 的差值在左邊顯示出來是 0.102ms,大約是 9600 分之一,略微有點(diǎn)偏向,在允許規(guī)模內(nèi)即可。經(jīng)過圖 11-7,我們可以明晰的理解了串口通訊的收發(fā)的具體進(jìn)程。
那我們這里再來理解一下,假如我們運(yùn)用串口調(diào)試助手,用字符格局直接發(fā)送一個(gè)“12”,我們?cè)谖覀兊臄?shù)碼管上應(yīng)當(dāng)顯示什么呢?串口調(diào)試助手應(yīng)當(dāng)前往什么呢?經(jīng)由實(shí)驗(yàn)發(fā)現(xiàn),我們數(shù)碼管顯示的是 32,而串口調(diào)試助手前往十六進(jìn)制顯示的是 31、32 兩個(gè)數(shù)據(jù),如圖 11-8所示。
圖 11-8 串口調(diào)試助手?jǐn)?shù)據(jù)顯示
我們?cè)儆眠壿嬈饰鰞x把這個(gè)數(shù)據(jù)抓出來看一下,如圖 11-9 所示。
圖 11-9 邏輯剖析儀抓取數(shù)據(jù)
關(guān)于 ASCII 碼表來說,數(shù)字自身是字符而非數(shù)據(jù),所以假如發(fā)送“12”的話,實(shí)踐上是是辨別發(fā)送了“1”和“2”兩個(gè)字符,單片機(jī)呢,先收到第一個(gè)字符“1”,在數(shù)碼管上會(huì)顯示出 31 這個(gè)對(duì)應(yīng)數(shù)字,然則立時(shí)就又收到了“2”這個(gè)字符,數(shù)碼管霎時(shí)從 31 釀成了 32,而我們視覺上呢,是沒有方法發(fā)現(xiàn)這種疾速變更的,所以我們覺得數(shù)碼管直接顯示的是 32。