利用无线串口进行单片机通信(基于MK60)
利用無(wú)線串口進(jìn)行單片機(jī)通信(基于MK60)
文章目錄
- 利用無(wú)線串口進(jìn)行單片機(jī)通信(基于MK60)
- 前言
- 一、串口通信的基本知識(shí)
- 1.串口通信
- 2.串口通信的方式
- 并行通信
- 串行通信
- 3.同步通信和異步通信
- 異步通信:
- 同步通信:
- 4.串行通信的傳輸方向
- 單工:單工是指數(shù)據(jù)傳輸僅能沿一個(gè)方向,不能實(shí)現(xiàn)反向傳輸。
- 半雙工:半雙工是指數(shù)據(jù)傳輸可以沿兩個(gè)方向,但需要分時(shí)進(jìn)行。
- 全雙工:全雙工是指數(shù)據(jù)可以同時(shí)進(jìn)行雙向傳輸。
- 5.波特率
- 6.異步通信數(shù)據(jù)格式
- 7.異步通信的數(shù)據(jù)發(fā)送過(guò)程
- 8.異步通信的數(shù)據(jù)接收過(guò)程
- 9.硬件配置
- 二、具體實(shí)現(xiàn)方法(基于UART通信協(xié)議)
- 1.庫(kù)中常用的函數(shù)
- -串口發(fā)送一個(gè)字節(jié)
- -發(fā)送指定長(zhǎng)度數(shù)組
- -接收一個(gè)字節(jié)
- 2.電腦到單片機(jī)之間的通信
- 3.單片機(jī)到電腦
- 4.單片機(jī)之間的通信
前言
? 最近學(xué)習(xí)了使用宏佳電子 HJ-WUS1 XP2(1).0 無(wú)線串口模塊和MK60進(jìn)行單片機(jī)和電腦、單片機(jī)和單片機(jī)之間的通信,在這里記錄一下學(xué)習(xí)筆記。
一、串口通信的基本知識(shí)
1.串口通信
? 串口通信(Serial Communications)的概念非常簡(jiǎn)單,串口按位(bit)發(fā)送和接收字節(jié)。
2.串口通信的方式
? 在通信領(lǐng)域內(nèi),有兩種數(shù)據(jù)通信方式:并行通信和串行通信。
并行通信
? 并行通信通常是將數(shù)據(jù)字節(jié)的各位用多條數(shù)據(jù)線同時(shí)進(jìn)行傳送。
? 其特點(diǎn)是控制簡(jiǎn)單、傳輸速度快;但是由于傳輸線較多,長(zhǎng)時(shí)間傳送時(shí)成本高且接收方的各位同時(shí)接收存在困難。
串行通信
? 串行通信是將數(shù)據(jù)字節(jié)分成一位一位的形式在一條傳輸線上逐個(gè)地傳送。
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-cK3u3vN6-1608828104274)(C:\Users\hp01\Desktop\Snipaste_2020-12-25_00-37-55.png)]
? 其特點(diǎn)為傳輸線少,長(zhǎng)距離傳送時(shí)成本低,且可以利用電話網(wǎng)等現(xiàn)成的設(shè)備,但是數(shù)據(jù)的傳送控制比并行通信復(fù)雜。
3.同步通信和異步通信
? 兩者都是串行通信的通信方式。
異步通信:
? 異步通信是指通信的發(fā)送與接收設(shè)備使用各自的時(shí)鐘控制數(shù)據(jù)的發(fā)送和接收過(guò)程。為使雙方的收發(fā)協(xié)調(diào),要求發(fā)送和接收設(shè)備的時(shí)鐘盡可能一致。異步通信是以字符(構(gòu)成的幀)為單位進(jìn)行傳輸,字符與字符之間的間隙(時(shí)間間隔)是任意的,但每個(gè)字符中的各位是以固定的時(shí)間傳送的,即字符之間不一定有“位間隔”的整數(shù)倍的關(guān)系,但同一字符內(nèi)的各位之間的距離均為“位間隔”的整數(shù)倍。
? 通信的數(shù)據(jù)以相同的幀格式傳送,每一幀由固定的起始位、數(shù)據(jù)位、奇偶校驗(yàn)位和停止位組成。在單片機(jī)中,使用異步收發(fā)器實(shí)現(xiàn)異步通信。
同步通信:
? 同步通信時(shí)要建立發(fā)送方時(shí)鐘對(duì)接收方時(shí)鐘的直接控制,使雙方達(dá)到完全同步。此時(shí),傳輸數(shù)據(jù)的位之間的距離均為“位間隔”的整數(shù)倍,同時(shí)傳送的字符間不留間隙,即保持位同步關(guān)系,也保持字符同步關(guān)系。
? 同步通信的幀頭往往是1個(gè)或2個(gè)同步字符,表示標(biāo)題開(kāi)始,標(biāo)題中包含源地址、目標(biāo)地址和路由指示等信息,之后是數(shù)據(jù)開(kāi)始字符,表示傳送的數(shù)據(jù)塊開(kāi)始。數(shù)據(jù)塊是傳送的正文內(nèi)容,有多個(gè)字符組成。之后是組終字符或文終字符,最后為校驗(yàn)碼。
4.串行通信的傳輸方向
單工:單工是指數(shù)據(jù)傳輸僅能沿一個(gè)方向,不能實(shí)現(xiàn)反向傳輸。
半雙工:半雙工是指數(shù)據(jù)傳輸可以沿兩個(gè)方向,但需要分時(shí)進(jìn)行。
全雙工:全雙工是指數(shù)據(jù)可以同時(shí)進(jìn)行雙向傳輸。
5.波特率
? 波特率指調(diào)制速率,指的是有效數(shù)據(jù)訊號(hào)調(diào)制載波的速率,即單位時(shí)間內(nèi)載波調(diào)制狀態(tài)變化的次數(shù)。
? 波特率可以被理解為一個(gè)設(shè)備在一秒鐘內(nèi)發(fā)送(或接收)了多少碼元的數(shù)據(jù),它是對(duì)符號(hào)傳輸速率的一種度量,表示單位時(shí)間內(nèi)傳輸符號(hào)的個(gè)數(shù)(傳符號(hào)率)。波特(Baud,單位符號(hào):B)這一單位是以法國(guó)電訊工程師埃米爾·博多(1845-1903)的姓氏來(lái)命名的,他是數(shù)位通訊的先驅(qū)之一,是電傳與博多式電報(bào)機(jī)的發(fā)明人。
6.異步通信數(shù)據(jù)格式
起始位:起始位必須是持續(xù)一個(gè)比特時(shí)間的邏輯0電平,標(biāo)志傳輸一個(gè)字符的開(kāi)始,接收方可用起始位使自己的接收時(shí)鐘與發(fā)送方的數(shù)據(jù)同步。起始位起到的作用就是表示傳送的開(kāi)始。
數(shù)據(jù)位:數(shù)據(jù)位緊跟在起始位之后,是通信中的真正有效信息。數(shù)據(jù)位的位數(shù)可以由通信雙方共同約定,一般可以是5位、7位或8位,標(biāo)準(zhǔn)的ASCII碼是0127(7位),擴(kuò)展的ASCII碼是0255(8位)。傳輸數(shù)據(jù)時(shí)先傳送字符的低位,后傳送字符的高位。
校驗(yàn)位:串口一般都會(huì)使用奇偶校驗(yàn)位,奇偶校驗(yàn)位僅占一位,用于進(jìn)行奇校驗(yàn)或偶校驗(yàn)如果是奇校驗(yàn),需要保證傳輸?shù)臄?shù)據(jù)總共有奇數(shù)個(gè)邏輯高位;如果是偶校驗(yàn),需要保證傳輸?shù)臄?shù)據(jù)總共有偶數(shù)個(gè)邏輯高位。其他校驗(yàn)方法還有0校驗(yàn)、1校驗(yàn)、和校驗(yàn)以及無(wú)校驗(yàn)等,這個(gè)需要通過(guò)通信協(xié)議確定。
停止位:停止位可以是是1位、1.5位或2位,可以由軟件設(shè)定。它一定是邏輯1電平,標(biāo)志著傳輸一個(gè)字符的結(jié)束。
7.異步通信的數(shù)據(jù)發(fā)送過(guò)程
? 清楚了異步通信的數(shù)據(jù)格式之后,就可以按照指定的數(shù)據(jù)格式發(fā)送數(shù)據(jù)了,發(fā)送數(shù)據(jù)的具體步驟如下:
(1)初始化后或者沒(méi)有數(shù)據(jù)需要發(fā)送時(shí),發(fā)送端輸出邏輯1,可以有任意數(shù)量的空閑位。
(2)當(dāng)需要發(fā)送數(shù)據(jù)時(shí),發(fā)送端首先輸出邏輯0,作為起始位。
(3)接著就可以開(kāi)始輸出數(shù)據(jù)位了,發(fā)送端首先輸出數(shù)據(jù)的最低位D0,然后是D1,最后是數(shù)據(jù)的最高位。
(4)如果設(shè)有奇偶檢驗(yàn)位,發(fā)送端輸出檢驗(yàn)位。
(5)最后,發(fā)送端輸出停止位(邏輯1)。
(6)如果沒(méi)有信息需要發(fā)送,發(fā)送端輸出邏輯1(空閑位),如果有信息需要發(fā)送,則轉(zhuǎn)入步驟(2)。
8.異步通信的數(shù)據(jù)接收過(guò)程
? 在異步通信中,接收端以接收時(shí)鐘和波特率因子決定每一位的時(shí)間長(zhǎng)度。下面以波特率因子等于16(接收時(shí)鐘每16個(gè)時(shí)鐘周期使接收移位寄存器移位一次)為例來(lái)說(shuō)明。
(1)開(kāi)始通信,信號(hào)線為空閑(邏輯1),當(dāng)檢測(cè)到由1到0的跳變時(shí),開(kāi)始對(duì)接收時(shí)鐘計(jì)數(shù)。
(2)當(dāng)計(jì)到8個(gè)時(shí)鐘的時(shí)候,對(duì)輸入信號(hào)進(jìn)行檢測(cè),若仍然為低電平,則確認(rèn)這是起始位,而不是干擾信號(hào)。
(3)接收端檢測(cè)到起始位后,隔16個(gè)接收時(shí)鐘對(duì)輸入信號(hào)檢測(cè)一次,把對(duì)應(yīng)的值作為D0位數(shù)據(jù)。
(4)再隔16個(gè)接收時(shí)鐘,對(duì)輸入信號(hào)檢測(cè)一次,把對(duì)應(yīng)的值作為D1位數(shù)據(jù),直到全部數(shù)據(jù)位都輸入。
(5)檢驗(yàn)奇偶檢驗(yàn)位。
(6)接收到規(guī)定的數(shù)據(jù)位個(gè)數(shù)和校驗(yàn)位之后,通信接口電路希望收到停止位(邏輯1),若此時(shí)未收到邏輯1,說(shuō)明出現(xiàn)了錯(cuò)誤,在狀態(tài)寄存器中置“幀錯(cuò)誤”標(biāo)志;若沒(méi)有錯(cuò)誤,對(duì)全部數(shù)據(jù)位進(jìn)行奇偶校驗(yàn),無(wú)校驗(yàn)錯(cuò)時(shí),把數(shù)據(jù)位從移位寄存器中取出送至數(shù)據(jù)輸入寄存器,若校驗(yàn)錯(cuò),在狀態(tài)寄存器中置“奇偶錯(cuò)”標(biāo)志。
(7)本幀信息全部接收完,把線路上出現(xiàn)的高電平作為空閑位。
(8)當(dāng)信號(hào)再次變?yōu)榈蜁r(shí),開(kāi)始進(jìn)入下一幀的檢測(cè)。
以上就是異步通信中數(shù)據(jù)發(fā)送和接收的全過(guò)程了。
9.硬件配置
? 在初次使用無(wú)線串口時(shí)需要對(duì)串口模塊進(jìn)行配置,通常商家會(huì)提供配置的文檔,照著上面的方法進(jìn)行配置就行。
? 需要注意串口模塊的主機(jī)和無(wú)線從機(jī)都需要進(jìn)行配置,兩者的主從機(jī)地址、波特率、頻率必須相同。同時(shí)如果需要進(jìn)行單片機(jī)之間的通信,這兩個(gè)無(wú)線串口模塊的地址、波特率和無(wú)限頻率也都必須相同,兩個(gè)無(wú)線模塊只有在無(wú)線頻率和地址相同的情況下,才可以進(jìn)行通信。
二、具體實(shí)現(xiàn)方法(基于UART通信協(xié)議)
? 這里使用的是來(lái)自與山外的庫(kù)。
1.庫(kù)中常用的函數(shù)
-串口發(fā)送一個(gè)字節(jié)
/*!* @brief 串口發(fā)送一個(gè)字節(jié)* @param UARTn_e 模塊號(hào)(UART0~UART5)* @param ch 需要發(fā)送的字節(jié)* @since v5.0* @note printf需要用到此函數(shù)* @see fputc* Sample usage: uart_putchar (UART3, 'A'); //發(fā)送字節(jié)'A'*/ void uart_putchar (UARTn_e uratn, char ch) {//等待發(fā)送緩沖區(qū)空while(!(UART_S1_REG(UARTN[uratn]) & UART_S1_TDRE_MASK));//發(fā)送數(shù)據(jù)UART_D_REG(UARTN[uratn]) = (uint8)ch; }-發(fā)送指定長(zhǎng)度數(shù)組
/*!* @brief 發(fā)送指定len個(gè)字節(jié)長(zhǎng)度數(shù)組 (包括 NULL 也會(huì)發(fā)送)* @param UARTn_e 模塊號(hào)(UART0~UART5)* @param buff 數(shù)組地址* @param len 發(fā)送數(shù)組的長(zhǎng)度* @since v5.0* Sample usage: uart_putbuff (UART3,"1234567", 3); //實(shí)際發(fā)送了3個(gè)字節(jié)'1','2','3'*/ void uart_putbuff (UARTn_e uratn, uint8 *buff, uint32 len) {while(len--){uart_putchar(uratn, *buff);buff++;} }?
-接收一個(gè)字節(jié)
/*!* @brief 發(fā)送指定len個(gè)字節(jié)長(zhǎng)度數(shù)組 (包括 NULL 也會(huì)發(fā)送)* @param UARTn_e 模塊號(hào)(UART0~UART5)* @param buff 數(shù)組地址* @param len 發(fā)送數(shù)組的長(zhǎng)度* @since v5.0* Sample usage: uart_putbuff (UART3,"1234567", 3); //實(shí)際發(fā)送了3個(gè)字節(jié)'1','2','3'*/ void uart_putbuff (UARTn_e uratn, uint8 *buff, uint32 len) {while(len--){uart_putchar(uratn, *buff);buff++;} }2.電腦到單片機(jī)之間的通信
void main() {char ch;//uart_init(UART3,115200); //初始化串口(由于 printf 函數(shù) 所用的端口就是 UART3,已經(jīng)初始化了,因此此處不需要再初始化)uart_putstr (UART3 , "\n\n\n接受數(shù)據(jù),并進(jìn)行發(fā)送:"); //發(fā)送字符串while(1){if(uart_query (UART3) != 0) //查詢是否接收到數(shù)據(jù){uart_getchar (UART3,&ch); //等待接收一個(gè)數(shù)據(jù),保存到 ch里uart_putchar(UART3, ch); //發(fā)送1個(gè)字節(jié)}if(uart_querychar (UART3, &ch) != 0) //查詢接收1個(gè)字符{uart_putchar(UART3, ch); //發(fā)送1個(gè)字節(jié)}//注:上面兩個(gè) if 的實(shí)現(xiàn)功能都是一樣的。//uart_getchar 和 uart_querychar 的區(qū)別在于 ,前者 需要等待接收到數(shù)據(jù),后者查詢是否接收到,接收到就接收,接收不到就退出} }? 這段代碼可以實(shí)現(xiàn)電腦到單片機(jī)的簡(jiǎn)單通信,由上位機(jī)發(fā)出一個(gè)字節(jié),單片機(jī)接收后原樣發(fā)回。可以用作試驗(yàn)串口是否正常。
3.單片機(jī)到電腦
void Data_Send(UARTn_e uartn,unsigned short int *pst,uint8 x) {unsigned char _cnt=0; unsigned char sum = 0;unsigned char data_to_send[23]; //發(fā)送緩存data_to_send[_cnt++]=0xAA;data_to_send[_cnt++]=0xAA;data_to_send[_cnt++]=x;data_to_send[_cnt++]=0;data_to_send[_cnt++]=(unsigned char)(pst[0]>>8); //高8位data_to_send[_cnt++]=(unsigned char)pst[0]; //低8位data_to_send[_cnt++]=(unsigned char)(pst[1]>>8);data_to_send[_cnt++]=(unsigned char)pst[1];data_to_send[_cnt++]=(unsigned char)(pst[2]>>8);data_to_send[_cnt++]=(unsigned char)pst[2];data_to_send[_cnt++]=(unsigned char)(pst[3]>>8);data_to_send[_cnt++]=(unsigned char)pst[3];data_to_send[_cnt++]=(unsigned char)(pst[4]>>8);data_to_send[_cnt++]=(unsigned char)pst[4];data_to_send[_cnt++]=(unsigned char)(pst[5]>>8);data_to_send[_cnt++]=(unsigned char)pst[5];data_to_send[_cnt++]=(unsigned char)(pst[6]>>8);data_to_send[_cnt++]=(unsigned char)pst[6];data_to_send[_cnt++]=(unsigned char)(pst[7]>>8);data_to_send[_cnt++]=(unsigned char)pst[7];data_to_send[_cnt++]=(unsigned char)(pst[8]>>8);data_to_send[_cnt++]=(unsigned char)pst[8];data_to_send[3] = _cnt-4;sum = 0;for(unsigned char i=0;i<_cnt;i++)sum += data_to_send[i];data_to_send[_cnt++] = sum;for(unsigned char i=0;i<_cnt;i++)uart_putchar (uartn,data_to_send[i] );}? 這是一段符合匿名地面站V5的通訊協(xié)議的單片機(jī)發(fā)送代碼,每個(gè)上位機(jī)的通訊協(xié)議可能有所不同,所以在編寫單片機(jī)發(fā)送函數(shù)時(shí)必循根據(jù)自己所用的上位機(jī)的通訊協(xié)議進(jìn)行編寫,如圖就是匿名地面站的通信部分協(xié)議。可以看到它的格式為AAAA的幀頭,然后是功能字和數(shù)據(jù)的長(zhǎng)度(不包括幀頭、功能字、長(zhǎng)度字節(jié)和最后的校驗(yàn)位),最后是需要發(fā)送的數(shù)據(jù)和和校驗(yàn)位(SUM等于從該數(shù)據(jù)幀第一字節(jié)開(kāi)始,也就是幀頭開(kāi)始,至該幀數(shù)據(jù)的最后一字節(jié)所有字節(jié)的和,只保留低八位,高位舍去)。同時(shí)由于每次發(fā)送數(shù)據(jù)時(shí)是8位一次進(jìn)行發(fā)送,而一個(gè)完整的數(shù)據(jù)一共是16位,所以需要將數(shù)據(jù)進(jìn)行拆分。
? [外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來(lái)直接上傳(img-r0SnH9l4-1608828104278)(C:\Users\hp01\Desktop\Snipaste_2020-12-25_00-39-06.png)]
4.單片機(jī)之間的通信
? 這里我為了方便將單片機(jī)的接收函數(shù)按照上位機(jī)的通訊協(xié)議進(jìn)行編寫,這樣較為方便。
void GetData(u8 data) {static u8 _sta = 0;static u8 _datalen = 0; //協(xié)議的長(zhǎng)度static u8 _datacnt = 0; //已經(jīng)接收到的長(zhǎng)度if(_sta == 0){DataGet[0]=data;_datacnt=0;_datalen=0;if(data == 0xAA)_sta = 1;}else if(_sta == 1) //地址不做判斷{DataGet[1]=data;_sta = 2;}else if(_sta == 2) //ID也不判斷,用于分辨事什么數(shù)據(jù){DataGet[2]=data;_sta = 3;}else if(_sta == 3) //{if(data > 50)_sta = 0;else {_sta = 4;DataGet[3] = data;_datalen = data;}}else if(_sta == 4){DataGet[4+_datacnt++] = data;if(_datacnt >= _datalen)_sta = 5; }else if(_sta == 5){DataGet[4+_datacnt++] = data;_sta = 6; }else if(_sta == 6){DataGet[4+_datacnt++] = data;_sta = 0; Anl(); //數(shù)據(jù)解析函數(shù),用于得到接收到的數(shù)據(jù)} }? 由于這里我換用了匿名地面站V7,所以協(xié)議上有一些不同,總的來(lái)說(shuō)是添加了一個(gè)附加校驗(yàn)位和幀頭不同,這里的附加校驗(yàn)位是對(duì)于每次計(jì)算和校驗(yàn)位的累加和。這個(gè)函數(shù)需要在中斷當(dāng)中調(diào)用。
? 在這之后需要對(duì)所接收到的數(shù)據(jù)進(jìn)行解析,這里先將接收到的數(shù)據(jù)存放于一個(gè)數(shù)組當(dāng)中,方便之后操作。在解析時(shí)注意判斷接收到的數(shù)據(jù)是否符合協(xié)議,如果不符合協(xié)議,則不進(jìn)行解析。解析函數(shù)的編寫注意對(duì)照你自己設(shè)定的協(xié)議或者上位機(jī)的協(xié)議。下面是簡(jiǎn)單的解析函數(shù)。
void Anl(void) {u8 sumc = 0;u8 ac = 0;u8 _datalen = DataGet[3];for(u8 i=0;i<DataGet[3]+4;i++){sumc += DataGet[i];ac += sumc;}if( sumc != DataGet[DataGet[3]+4] || ac!=DataGet[DataGet[3]+5]) //判斷數(shù)據(jù)是否合法return;if(DataGet[2] == 0xE1){uint16 _id = DataGet[4] + (uint16)(DataGet[5]<<8);switch(_id){case 1:_SendPar(_id,userdata1);break;default:_SendPar(_id,0);break;}} }發(fā)送函數(shù)基本上和單片機(jī)到電腦的發(fā)送函數(shù)一致,這里就不再多說(shuō)。
總結(jié)
以上是生活随笔為你收集整理的利用无线串口进行单片机通信(基于MK60)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: n位整数去掉m位后求最大值问题
- 下一篇: Node.js升级或降低版本