您好,登錄后才能下訂單哦!
我們進修串口通訊次要是要完成單片機和電腦之間的信息交互,可以用電腦掌握單片機的一些信息,可以把單片機的一些信息情況發給電腦上的軟件。下面我們就做一個復雜的例程,完成單片機串口調試助手發送的數據,在我們開辟板上的數碼管上顯示出來。
#include <reg52.h> sbit ADDR3 = P1^3; sbit ENLED = P1^4; unsigned char code LedChar[] = { //數碼管顯示字符轉換表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; unsigned char LedBuff[7] = { //數碼管+自力 LED 顯示緩沖區 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF }; unsigned char T0RH = 0; //T0 重載值的高字節 unsigned char T0RL = 0; //T0 重載值的低字節 unsigned char RxdByte = 0; //串口接納到的字節 void ConfigTimer0(unsigned int ms); void ConfigUART(unsigned int baud); void main(){ EA = 1; //使能總中綴 ENLED = 0; //選擇數碼管和自力 LED ADDR3 = 1; ConfigTimer0(1); //設置裝備擺設 T0 準時 1ms ConfigUART(9600); //設置裝備擺設波特率為 9600 while (1){ //將接納字節在數碼管上以十六進制方式顯示出來 LedBuff[0] = LedChar[RxdByte & 0x0F]; LedBuff[1] = LedChar[RxdByte >> 4]; } } /* 設置裝備擺設并啟動 T0,ms-T0 準時工夫 */ void ConfigTimer0(unsigned int ms){ unsigned long tmp; //暫時變量 tmp = 11059200 / 12; //準時器計數頻率 tmp = (tmp * ms) / 1000; //盤算所需的計數值 tmp = 65536 - tmp; //盤算準時重視載值 tmp = tmp + 13; //賠償中綴呼應延時形成的誤差 T0RH = (unsigned char)(tmp>>8); //準時重視載值拆分為上下字節 T0RL = (unsigned char)tmp; TMOD &= 0xF0; //清零 T0 的掌握位 TMOD |= 0x01; //設置裝備擺設 T0 為形式 1 TH0 = T0RH; //加載 T0 重載值 TL0 = T0RL; ET0 = 1; //使能 T0 中綴 TR0 = 1; //啟動 T0 } /* 串口設置裝備擺設函數,baud-通訊波特率 */ void ConfigUART(unsigned int baud){ SCON = 0x50; //設置裝備擺設串口為形式 1 TMOD &= 0x0F; //清零 T1 的掌握位 TMOD |= 0x20; //設置裝備擺設 T1 為形式 2 TH1 = 256 - (11059200/12/32)/baud; //盤算 T1 重載值 TL1 = TH1; //初值等于重載值 ET1 = 0; //制止 T1 中綴 ES = 1; //使能串口中綴 TR1 = 1; //啟動 T1 } /* LED 靜態掃描刷新函數,需在準時中綴中挪用 */ void LedScan(){ static unsigned char i = 0; //靜態掃描索引 P0 = 0xFF; //封閉一切段選位,顯示消隱 P1 = (P1 & 0xF8) | i; //位選索引值賦值到 P1 口低 3 位 P0 = LedBuff[i]; //緩沖區中索引地位的數據送到 P0 口 if (i < 6){ //索引遞增輪回,遍歷全部緩沖區 i++; }else{ i = 0; } } /* T0 中綴效勞函數,完成 LED 掃描 */ void InterruptTimer0() interrupt 1{ TH0 = T0RH; //從新加載重載值 TL0 = T0RL; LedScan(); //LED 掃描顯示 } /* UART 中綴效勞函數 */ void InterruptUART() interrupt 4{ if (RI){ //接納到字節 RI = 0; //手動清零接納中綴標記位 RxdByte = SBUF; //接納到的數據保管到接納字節變量中 //接納到的數據又直接發還,叫作-"echo", //用以提醒用戶輸出的信息能否已準確接納 SBUF = RxdByte; } if (TI){ //字節發送終了 TI = 0; //手動清零發送中綴標記位 } }
人人在做這個試驗的時分,有個小成績要留意一下。由于 STC89C52 下載程序是運用了UART 串口下載,下載完程序后,程序運轉起來了,可是下載軟件最初還會經過串口發送一些額定的數據,所以程序剛下載出來不是顯示 00,而能夠是其他數據。人人只需把電源開關封閉,從新翻開一次就好了。
仔細的同窗能夠會發現,在串口調試助手發送選項和接納選項處,還有個“字符格局發送”和“字符格局顯示”,這是什么意思呢?
先拋開我們運用的漢字不談,那么我們常用的字符就包括了 0~9 的數字、A~Z/a~z 的字母、還有各類標點符號等。那么在單片機零碎外面我們怎樣來表現它們呢? ASCII 碼(American Standard Code for Information Interchange,即美國信息交換規范代碼)可以完成這個任務:我們曉得,在單片機中一個字節的數據可以有 0~255 共 256 個值,我們取個中的 0~127 共 128 個值付與了它別的一層涵義,即讓它們辨別來代表一個常用字符,其詳細的對應關系如表 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 |
如許我們就在常用字符和字節數據之間樹立了逐個對應的關系,那么如今一個字節就既可以代表一個整數又可以代表一個字符了,但它實質上只是一個字節的數據,而我們付與了它分歧的涵義,什么時分付與它哪一種涵義就看編程者的意圖了。ASCII 碼在單片機零碎中使用十分普遍,我們后續的課程也會常常運用到它,下面我們來對它做一個直不雅的看法,同窗們必定要深入了解其實質。
對比上述表格,我們就可以完成字符和數字之間的轉換了,比方照樣這個程序,我們發送的時分改成字符格局發送,接納照樣用十六進制接納,如許接納和數碼管好做一下比照。
我們用字符格局發送一個小寫的 a,前往一個十六進制的 0x61,數碼管上顯示的也是 61,ASCII 碼內外字符 a 對應十進制是 97,等于十六進制的 0x61;我們再用字符格局發送一個數字 1,前往一個十六進制的 0x31,數碼管上顯示的也是 31,ASCII 內外字符 1 對應的十進制是 49,等于十六進制的 0x31。這下人人就該清晰了:所謂的十六進制發送和十六進制接納,多是按字節數據的真實值停止的;而字符格局發送和字符格局接納,是按 ASCII 碼表中字符方式停止的,但它實踐上最終傳輸的照樣一個字節數據。這個表格,當然不需求人人去記住,了解它,用的時分過去查就行了。
通訊的進修,不像前邊掌握局部那么直不雅了,通訊局部我們的程序只能取得一個后果,而其進程我們卻無法直接看到,所以漸漸的能夠人人就會曉得有示波器和邏輯剖析儀這類丈量儀器。假如黌舍試驗室或許公司里有示波器或許邏輯剖析儀這類儀器,可以拿過去抓一下串口波形,直不雅的理解一下。假如臨時還沒有這些儀器,先曉得這么回事,有前提再說。由于工具類裝備有的比擬昂貴,有前提可以盡量運用黌舍或許公司的。在這里我用一款簡略單純的邏輯剖析儀把串口通訊的波形抓出來給人人看一下,人人理解一下即可,如圖 11-7 所示。
圖 11-7 邏輯剖析儀串口數據表示圖
剖析儀和示波器的感化,就是把通訊進程的波形抓出來停止剖析。先大約說一下波形的意思。波形右邊是低位,左邊是高位,上邊這個波形是電腦發送給單片機的,下邊這個波形是單片機回發給電腦的。以上邊的波形為例,右邊第一位是肇端位 0,從低位到高位順次是10001100,次序倒一下,就是數據 0x31,也就是 ASCII 碼內外的‘1’。人人可以留意到剖析儀在每一個數據位都給標了一個白色的點,表現是數據,肇端位和有數據的時分都沒有這個白點。工夫標 T1 和 T2 的差值在左邊顯示出來是 0.102ms,大約是 9600 分之一,略微有點偏向,在允許規模內即可。經過圖 11-7,我們可以明晰的理解了串口通訊的收發的具體進程。
那我們這里再來理解一下,假如我們運用串口調試助手,用字符格局直接發送一個“12”,我們在我們的數碼管上應當顯示什么呢?串口調試助手應當前往什么呢?經由實驗發現,我們數碼管顯示的是 32,而串口調試助手前往十六進制顯示的是 31、32 兩個數據,如圖 11-8所示。
圖 11-8 串口調試助手數據顯示
我們再用邏輯剖析儀把這個數據抓出來看一下,如圖 11-9 所示。
圖 11-9 邏輯剖析儀抓取數據
關于 ASCII 碼表來說,數字自身是字符而非數據,所以假如發送“12”的話,實踐上是是辨別發送了“1”和“2”兩個字符,單片機呢,先收到第一個字符“1”,在數碼管上會顯示出 31 這個對應數字,然則立時就又收到了“2”這個字符,數碼管霎時從 31 釀成了 32,而我們視覺上呢,是沒有方法發現這種疾速變更的,所以我們覺得數碼管直接顯示的是 32。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。