1.串口通信的基礎(chǔ)知識(shí)
百度百科:串口通信的概念
什么是通信?
例如U盤和電腦,我們電腦需要往U盤存東西,而U盤上只有四個(gè)觸點(diǎn),除去一個(gè)電源一個(gè)地,只剩下兩個(gè)引腳了。此時(shí)我們坑定不能像點(diǎn)亮LED那樣單純的給他兩個(gè)引腳上輸出個(gè)高低電平就能寫數(shù)據(jù)了對(duì)吧??偛恢劣谳敵鲆粋€(gè)高電平就能在U盤里寫入“STC32位8051單片機(jī)就是牛!”這么一句話了吧。
通信指設(shè)備之間通過一定的協(xié)議進(jìn)行的信息交換。
每次發(fā)送一位數(shù)據(jù)的稱為串行通信,多位(嚴(yán)格來說是2位以上)一起傳輸?shù)姆Q為并行通信。
今天要講的串口通信是串行通信的其中的一種!也是1位1位的往外發(fā)數(shù)據(jù),不是像這個(gè)圖一樣8位一起發(fā)。
stc共有4個(gè)串口!串口1/2和3/4的主要區(qū)別在這里,這節(jié)課主要講異步串口。
串口通信(Serial Communication)
是指外設(shè)和計(jì)算機(jī)間,通過數(shù)據(jù)信號(hào)線 、地線、控制線等,按位進(jìn)行傳輸數(shù)據(jù)的一種通訊方式。這種通信方式使用的數(shù)據(jù)線少,在遠(yuǎn)距離通信中可以節(jié)約通信成本,但其傳輸速度比并行傳輸?shù)汀?br>
同步/異步?
異步方式(使用較多):
①以字符為單位傳送信息。
②相鄰兩字符間的間隔是任意長(zhǎng)。
③因?yàn)橐粋€(gè)字符中的比特位長(zhǎng)度有限,所以需 要的接收時(shí)鐘和發(fā)送時(shí)鐘只要相近就可以。
④異步方式特點(diǎn)簡(jiǎn)單的說就是:字符間異步,字符內(nèi)部各位同步。
同步方式:
①以數(shù)據(jù)塊為單位傳送信息。
②在一個(gè)數(shù)據(jù)塊(信息幀)內(nèi),字符與字符間無間隔。
③因?yàn)橐淮蝹鬏數(shù)臄?shù)據(jù)塊中包含的數(shù)據(jù)較多,所以接收時(shí)鐘與發(fā)送進(jìn)鐘嚴(yán)格同步,通常要有同步時(shí)鐘。
全雙工?
常見的串口軟件的參數(shù)
這里的4個(gè)數(shù)據(jù)發(fā)送端和接收段必須嚴(yán)格保持一致。否則接收到的就是亂碼。
●波特率?
例如9600的波特率意味著每秒鐘可以發(fā)9600位的數(shù)據(jù)。
我們這里起始位就是一個(gè)位(一個(gè)二進(jìn)制的一個(gè)數(shù)0或者1),1bit的變量。中間有8個(gè)數(shù)據(jù)為,然后校驗(yàn)位,停止位。速度9600即每秒最快可以發(fā)960個(gè)這種包,
●數(shù)據(jù)位? 有幾個(gè)2進(jìn)制位的數(shù)據(jù)
●校驗(yàn)位?
●停止位?
●傳輸距離
通信距離很短,如何解決?
以下分別為RS232,RS422,RS485的通信原理圖。
串口的邏輯電平只有5V或者3.3V,如果單片機(jī)是5V供電,邏輯電平只有5V(高電平),因?yàn)殡娖奖容^低,傳輸距離受限,
●串口有什么用
2.STC32的串口通信實(shí)現(xiàn)原理
引腳選擇:實(shí)現(xiàn)分時(shí)復(fù)用
模式選擇
每一種模式的配置參考手冊(cè),這里不再?gòu)?fù)述。這里主要講串口1的模式1(應(yīng)用最廣泛)。
串口1模式1,模式1波特率計(jì)算公式
當(dāng)軟件設(shè)置SCON的SMO、SM1為“01”時(shí),串行口1則以模式Ⅰ進(jìn)行工作。此模式為8位UART格式,一幀信息為10位:1位起始位,8位數(shù)據(jù)位(低位在先)和1位停止位。波特率可變,即可根據(jù)需要進(jìn)行設(shè)置波特率。TxD為數(shù)據(jù)發(fā)送口,RxD為數(shù)據(jù)接收口,串行口全雙工接受/發(fā)送。
模式Ⅰ的發(fā)送過程:串行通信模式發(fā)送時(shí),數(shù)據(jù)由串行發(fā)送端TxD輸出。當(dāng)主機(jī)執(zhí)行一條寫SBUF的指令就啟動(dòng)串行通信的發(fā)送,寫“SBUF”信號(hào)還把“1”裝入發(fā)送移位寄存器的第9位,并通知TX控制單元開始發(fā)送。移位寄存器將數(shù)據(jù)不斷右移送TxD端口發(fā)送,在數(shù)據(jù)的左邊不斷移入“O”作補(bǔ)充。當(dāng)數(shù)據(jù)的最高位移到移位寄存器的輸出位置,緊跟其后的是第9位“1”,在它的左邊各位全為“0”,這個(gè)狀態(tài)條件,使TX控制單元作最后一次移位輸出,然后使允許發(fā)送信號(hào)“SEND”失效,完成一幀信息的發(fā)送,并置位中斷請(qǐng)求位TI,即 TI=1,向主機(jī)請(qǐng)求中斷處理。
模式1的接收過程:當(dāng)軟件置位接收允許標(biāo)志位.REN,即REN=1時(shí),接收器便對(duì)RxD端口的信號(hào)進(jìn)行檢測(cè),當(dāng)檢測(cè)到RxD端口發(fā)送從“1”→“O”的下降沿跳變時(shí)就啟動(dòng)接收器準(zhǔn)備接收數(shù)據(jù),并立即復(fù)位波特率發(fā)生器的接收計(jì)數(shù)器,將IFFH裝入移位寄存器。接收的數(shù)據(jù)從接收移位寄存器的右邊移入,已裝入的IFFH向左邊移出,當(dāng)起始位"0O"移到移位寄存器的最左邊時(shí),使RX控制器作最后一次移位,完成一幀的接收。若同時(shí)滿足以下兩個(gè)條件:
·RI=0;
. SM2=0或接收到的停止位為1。
則接收到的數(shù)據(jù)有效,實(shí)現(xiàn)裝載入SBUF,停止位進(jìn)入RB8,RI標(biāo)志位被置l,向主機(jī)請(qǐng)求中斷,若上述兩條件不能同時(shí)滿足,則接收到的數(shù)據(jù)作廢并丟失,無論條件滿足與否,接收器重又檢測(cè)RxD端口上的"1"→"0"的跳變,繼續(xù)下一幀的接收。接收有效,在響應(yīng)中斷后,RI標(biāo)志位必須由軟件清0。通常情況下,串行通信工作于模式1時(shí),SM2設(shè)置為"0"。
串口1的波特率是可變的,其波特率可由定時(shí)器1或者定時(shí)器2產(chǎn)生。當(dāng)定時(shí)器采用IT模式時(shí)(12倍速),相應(yīng)的波特率的速度也會(huì)相應(yīng)提高12倍。
模式2和模式3,大同小異,不深入展開。
3.串口通信代碼實(shí)現(xiàn)
RXD和TXD接在了P4.6跟P4.7上,使用的是串口2。
編寫串口1通信程序
打開手冊(cè)15.5 范例程序
15.5.4 串口2使用定時(shí)器2做波特率發(fā)生器
新建工程16.串口2通信
復(fù)制"15.NTC溫度采集"工程為"16.串口2通信",HARDWARE目錄中新建usart子目錄,并將usart文件夾加入include,新建usart2.c和usart2.h,:
插入頭文件模板,并修改。
先編寫初始化函數(shù)聲明:void Usart2_Init(void);,入口參數(shù)肯定是無。函數(shù)實(shí)現(xiàn)(先把官方例程的初始化抄寫過來):
#define BRT (65536 - (MAIN_Fosc / 115200+2)/4) //加2操作是為了讓Keil編譯器自動(dòng)實(shí)現(xiàn)四舍五入運(yùn)算
void Usart2_Init(void)
{
P_SW2 = 0X80; //0X80=1000 0000
S2CFG = 0X01;
S2CON = 0X50;
T2L = BRT;
T2H = BRT>>8;
T2x12 = 1;
T2R =1;
wptr = 0x00;
rptr = 0x00;
busy = 0;
}
串口要用到主頻,將該定義從demo.c中移動(dòng)到usart2.h中。單獨(dú)寫在串口里面。
初始化代碼中有三個(gè)小寫的變量,屬于用戶定義變量,需要增加定義。另外,在頭文件中也要增加定義(主函數(shù)中也會(huì)使用到這些變量),使用extern關(guān)鍵字。
extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];
編寫中斷服務(wù)函數(shù),中斷函數(shù)的名字可以任意取,只要后面的中斷號(hào)無錯(cuò)誤即可。
增加發(fā)送函數(shù)Usart2_Send和void Usart2_SendStr(char *p),并在頭文件中聲明。
在主函數(shù)中刪除上節(jié)課無用內(nèi)容,再調(diào)用串口初始化,demo.c中while循環(huán)內(nèi)的usb串口部分可以注釋掉,本節(jié)不使用。
時(shí)間部分可以留著,方便計(jì)時(shí)。
修改后的源代碼如下。
demo.c中的main函數(shù)部分:
void main() //程序開始運(yùn)行的入口
{
sys_init(); //USB功能+IO口初始化
usb_init(); //usb庫(kù)初始化
delay_ms(500);
Timer0_Init(); //定時(shí)器0初始化
Usart2_Init(); //串口初始化
IE2 = 0X01;
EA = 1; //CPU開放中斷,打開總中斷。
Usart2_SendStr("Usart2 Test !\r\n");
while(1) //死循環(huán)
{
if( TIM_10MS_Flag==1 ) //如果10ms到了
{
TIM_10MS_Flag = 0; //清空標(biāo)志位
}
if (rptr != wptr)
{
Usart2_Send(buffer[rptr++]); //字符發(fā)送
rptr &= 0x0f;
}
}
}
Usart2.c:
#include "usart2.h"
#define BRT (65536 - (MAIN_Fosc / 115200+2)/4) //加2操作是為了讓Keil編譯器自動(dòng)實(shí)現(xiàn)四舍五入運(yùn)算
bit busy;
char wptr;
char rptr;
char buffer[16];
void Usart2_Init(void)
{
P_SW2 = 0X80; //0X80=1000 0000
S2CFG = 0X01;
S2CON = 0X50;
T2L = BRT; //BRT為宏定義,
T2H = BRT>>8;
T2x12 = 1;
T2R =1;
wptr = 0x00;
rptr = 0x00;
busy = 0;
}
void Usart_Isr() interrupt 8
{
if( S2TI )
{
S2TI = 0;
busy = 0;
}
if( S2RI )
{
S2RI = 0;
buffer[wptr++] = S2BUF;
wptr &= 0X0F;
}
}
void Usart2_Send(char dat)
{
while(busy);
busy = 1;
S2BUF = dat;
}
void Usart2_SendStr(char *p)
{
while(*p)
{
Usart2_Send(*p++);
}
}
Usart2.h:
#ifndef __USART2_H
#define __USART2_H
#include "COMM/stc.h" //調(diào)用頭文件
#include "COMM/usb.h"
#define MAIN_Fosc 11059200UL //定義為無符號(hào)長(zhǎng)整型,避免計(jì)算溢出
//------------------------引腳定義------------------------//
//------------------------變量聲明------------------------//
extern bit busy;
extern char wptr;
extern char rptr;
extern char buffer[16];
//------------------------函數(shù)聲明-----------------------//
void Usart2_Init(void);
void Usart2_Send(char dat);
void Usart2_SendStr(char *p);
#endif
編譯成功,下載進(jìn)去看一下。注意,這里的時(shí)鐘選擇11.0592。使用串口線(使用usb轉(zhuǎn)串口線usb-RS232),按要求接線,并選擇正確的串口。
錯(cuò)誤排查及代碼分析
下載完成后,無反應(yīng),看一下代碼,在執(zhí)行主函數(shù)之前就應(yīng)該執(zhí)行串口發(fā)送,但是串口工具里無變化,檢查串口工具參數(shù)設(shè)置,
都是對(duì)的,回過頭看手冊(cè),查找問題原因,先找到初始化Usart2_Init,在手冊(cè)中使用高級(jí)搜索功能,查找P_SW2:
找到定義:3.1.2 外設(shè)端口切換控制寄存器2(P_sW2):
使能訪問XFR,EAXFR在sys_init中已經(jīng)使能:EAXFR = 1; //擴(kuò)展寄存器(XFR)訪問使能,所以P_SW2 = 0X80; 不使用也是可以的。
查看S2_S:串口2功能腳選擇位,開發(fā)板上的串口2需切換到P4.6和P4.7引腳上,S2_S位應(yīng)置為1,這里可以使用或等于,在不影響最高位的情況下,設(shè)置S2_S位,即增加:P_SW2 |= 0X01;
再查找S2CFG,目錄對(duì)應(yīng)項(xiàng)跳轉(zhuǎn)至:15.4.3 串口⒉配置寄存器(S2CFG)。這里設(shè)置W1為1,解釋:W1:當(dāng)需要使用串口2時(shí),此位必須設(shè)置為“1”,否則可能會(huì)產(chǎn)生不可預(yù)期的錯(cuò)誤。若不需使用串口
2,則不用特別設(shè)置W1。
搜索S2CON,跳轉(zhuǎn)至15.4.1串口2控制寄存器(S2CON)。
S2CON = 0X50; //0X50=01010000,設(shè)置為模式1:可變波特率8位數(shù)據(jù)方式,S2REN=1:允許串口接收數(shù)據(jù)
T2L,T2H是定時(shí)器相關(guān)設(shè)置,串口需要用到1個(gè)定時(shí)器來生成波特率,也就是作為一個(gè)基準(zhǔn)時(shí)鐘。具體設(shè)置為:首先它傳入的是一個(gè)數(shù)組
T2L = BRT; //BRT為宏定義,
T2H = BRT>>8;
T2x12 = 1;
T2R =1;
接下來是3個(gè)變量。如果說TI需要發(fā)送數(shù)據(jù),發(fā)送完了以后把這個(gè)變量給他清零。發(fā)送時(shí)先檢測(cè)一下busy,如果等于1,說明上次的數(shù)據(jù)還沒有發(fā)完,阻塞,繼續(xù)等待。
如果發(fā)送完了,先把busy置1,然后把數(shù)據(jù)寫入S2BUF的位里面,之后開始發(fā)送,看一下手冊(cè)15.3.6串口1模式1,模式1波特率計(jì)算公式中的時(shí)序圖,和串口2同理,數(shù)據(jù)發(fā)送完之后,才會(huì)變成高電平,
也就是執(zhí)行if( S2TI ):S2T:串口2發(fā)送中斷請(qǐng)求標(biāo)志位。在模式0中,當(dāng)串口發(fā)送數(shù)據(jù)第8位結(jié)束時(shí),由硬件自動(dòng)將S2TI置1,向主機(jī)請(qǐng)求中斷,響應(yīng)中斷后S2TI必須用軟件清零。在其他模式中,則在停止位開始發(fā)送時(shí)由硬件自動(dòng)將S2TI置1,向CPU發(fā)請(qǐng)求中斷,響應(yīng)中斷后S2TI必須用軟件清零。滿足條件后S2TI清0,這個(gè)BUSY其實(shí)是個(gè)忙碌標(biāo)志位。也就是等于0的時(shí)候他才能發(fā)送數(shù)據(jù),把數(shù)據(jù)直接寫進(jìn)S2BUF寄存器中就可以自動(dòng)發(fā)送。S2BUF進(jìn)行讀操作,實(shí)際是讀取串口接收緩沖區(qū),對(duì)S2BUF進(jìn)行寫操作則是觸發(fā)串口開始發(fā)送數(shù)據(jù)。
void Usart2_SendStr(char *p) //發(fā)送整個(gè)字符。while(*p)可以用這個(gè)判斷他這個(gè)字符是否為空,這里用到了一個(gè)指針的技巧,首先傳入的是一個(gè)數(shù)組或者說是地址,把里面的數(shù)不斷發(fā)送出去,直到發(fā)送至最后一位。發(fā)完之后結(jié)束。這樣寫以后,如果想發(fā)字符串只要在雙引號(hào)內(nèi)寫入即可。
接收到8位數(shù)值后,RI會(huì)變高,進(jìn)入中斷,if( S2RI ),進(jìn)入后先清0,將讀到的數(shù)據(jù)存入,只會(huì)把地址加1,也就是接收到的數(shù)值位數(shù)。每接收到1個(gè)就加1,接收到的最大值是0x0f=16。
接下來,demo.c中判斷:if (rptr != wptr),如果rptr不等于tptr,那就就將rptr的數(shù)值不斷累加,然后直到等于這個(gè)數(shù)值。
可以看到,分析過程代碼段中僅增加了1行:P_SW2 |= 0X01; //開發(fā)板上的串口2需切換到P4.6和P4.7引腳上。
重新編譯,手動(dòng)下載,可以看到數(shù)值顯示了,需要打印的參數(shù)顯示出來了,也可以再把需要的數(shù)據(jù)寫進(jìn)去,可以回顯出來,可以試試。
這里的演示功能僅為上電顯示一段文字,運(yùn)行過程中發(fā)送什么文字,返回顯示同樣的文字。重點(diǎn)需要注意默認(rèn)選擇的引腳。寫的時(shí)候一定要按照實(shí)際電路引腳去寫。
總結(jié)
1.學(xué)會(huì)串口的一專業(yè)名詞。
2.學(xué)會(huì)串口的配置和使用(也可以去學(xué)習(xí)一下試驗(yàn)箱代碼,里面的代碼非常全面)
總共有4個(gè)串口,例程包里4個(gè)串口都有示例代碼,基本上所有用的的代碼均已涵蓋,示例里的初始化也寫的非常詳細(xì),可以選擇不一樣的定時(shí)器,只有定時(shí)器2可以同時(shí)為4個(gè)串口作為波特率發(fā)生器,文章來源:http://www.zghlxwxcb.cn/news/detail-727843.html
課后練習(xí):
1.串口發(fā)送字符Ax\r\n,(x表示0-7)板子點(diǎn)亮對(duì)應(yīng)LED
2.串口發(fā)送Bxxxx\r\n,xxxx表示一個(gè)四位數(shù),四位數(shù)碼管顯示這個(gè)4位數(shù)
2.串口發(fā)送Z\r\n,板子給電腦發(fā)送“Hello STC”;
3.串口發(fā)送字符Cx\r\n,(x表示0-1)板子打開/關(guān)閉蜂鳴
4.串口發(fā)送字符Dx\r\n,板子通過串口發(fā)送當(dāng)前溫度給電腦。
能獨(dú)立做出這個(gè)實(shí)驗(yàn)的話,說明你已經(jīng)快出師了。文章來源地址http://www.zghlxwxcb.cn/news/detail-727843.html
到了這里,關(guān)于學(xué)習(xí)筆記|串口通信的基礎(chǔ)知識(shí)|同步/異步|RS232|常見的串口軟件的參數(shù)|STC32G單片機(jī)視頻開發(fā)教程(沖哥)|第二十集:串口通信基礎(chǔ)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!