STM32学习心得三十一:485通信原理及实验
記錄一下,方便以后翻閱~
主要內(nèi)容:
1) 485接口原理;
2) 相關(guān)實(shí)驗(yàn)代碼解讀。
實(shí)驗(yàn)功能:兩個(gè)開(kāi)發(fā)板的485接口以A連接A,B連接B的方式直連。兩個(gè)開(kāi)發(fā)版的代碼啟動(dòng)后,主開(kāi)發(fā)版上,按鍵KEY0控制W25Q128的寫(xiě)入數(shù)據(jù)并傳至次開(kāi)發(fā)版,且在串口調(diào)試助手上面顯示相關(guān)信息。同時(shí),主開(kāi)發(fā)版實(shí)時(shí)采集從次開(kāi)發(fā)板傳來(lái)的數(shù)據(jù),也顯示在串口調(diào)試助手上,LED0閃爍提示程序正在運(yùn)行;另一個(gè)開(kāi)發(fā)版,按鍵SW4按下后,寫(xiě)入數(shù)據(jù)并傳至主開(kāi)發(fā)板。
硬件連接:
主開(kāi)發(fā)板
注意:
1)R19和R22是兩個(gè)偏置電阻,用來(lái)保證總線空閑時(shí),AB之間的電壓差都會(huì)大約200mV,避免總線空閑時(shí)壓差不定邏輯混亂;
2)兩個(gè)485接口連接,A連接A,B連接B。
其它原理圖如下:
另一個(gè)開(kāi)發(fā)板芯片采用STM32F103C8T6,原理圖如下所示:
備注:該開(kāi)發(fā)板采用的MAX485收發(fā)器。
1. 485接口原理
1.1 串口
串口是一種接口標(biāo)準(zhǔn),它規(guī)定了接口的電氣標(biāo)準(zhǔn),簡(jiǎn)單說(shuō)只是物理層的一個(gè)標(biāo)準(zhǔn)。沒(méi)有規(guī)定接口插件電纜以及使用的協(xié)議,所以只要我們使用的接口插件電纜符合串口標(biāo)準(zhǔn)就可以在實(shí)際中靈活使用,在串口接口標(biāo)準(zhǔn)上使用各種協(xié)議進(jìn)行通訊及設(shè)備控制。
典型的串行通訊標(biāo)準(zhǔn)是RS232和RS485,它們定義了電壓,阻抗等,但不對(duì)軟件協(xié)議給予定義。
1.2 RS232接口缺陷
缺點(diǎn):
1.2.1 接口的信號(hào)電平值較高(+/-12V),易損壞接口電路的芯片;
1.2.2 傳輸速率較低,在異步傳輸時(shí),波特率為20Kbps;
1.2.3 接口使用一根信號(hào)線和一根信號(hào)返回線而構(gòu)成共地的傳輸形式,這種共地傳輸容易產(chǎn)生共模干擾,所以抗噪聲干擾性弱;
1.2.4 傳輸距離有限,最大傳輸距離標(biāo)準(zhǔn)值為50英尺,實(shí)際上也只能用在50米左右。
備注:早期設(shè)備大都采用RS232接口,因?yàn)樵O(shè)備與設(shè)備之間的傳輸距離和速率要求都不高。
1.3 485接口簡(jiǎn)述
485(一般稱作RS485/EIA-485)是隸屬于OSI模型物理層的電氣特性規(guī)定為2線,半雙工,多點(diǎn)通信的標(biāo)準(zhǔn)。它的電氣特性和RS-232大不一樣。用纜線兩端的電壓差值來(lái)表示傳遞信號(hào)。RS485僅僅規(guī)定了接受端和發(fā)送端的電氣特性。它沒(méi)有規(guī)定或推薦任何數(shù)據(jù)協(xié)議。
1.4 485特點(diǎn)
1.4.1 接口電平低,不易損壞芯片。RS485的電氣特性:邏輯“1”以兩線間的電壓差為+(26)V表示;邏輯“0”以兩線間的電壓差為-(26)V表示。接口信號(hào)電平比RS232降低了,不易損壞接口電路的芯片;
1.4.2 傳輸速率高。10米時(shí),RS485的數(shù)據(jù)最高傳輸速率可達(dá)35Mbps,在1200m時(shí),傳輸速度可達(dá)100Kbps;
1.4.3 抗干擾能力強(qiáng)。RS485接口是采用平衡驅(qū)動(dòng)器和差分接收器的組合,抗共模干擾能力增強(qiáng),即抗噪聲干擾性好;
1.4.4 傳輸距離遠(yuǎn),支持節(jié)點(diǎn)多。RS485總線最長(zhǎng)可以傳輸1200m以上(速率≤100Kbps)一般最大支持32個(gè)節(jié)點(diǎn),如果使用特制的485芯片,可以達(dá)到128個(gè)或者256個(gè)節(jié)點(diǎn),最大的可以支持到400個(gè)節(jié)點(diǎn)。
1.5 485連接方式
RS485推薦使用在點(diǎn)對(duì)點(diǎn)網(wǎng)絡(luò)中,線型,總線型,不能是星型,環(huán)型網(wǎng)絡(luò)。理想情況下RS485需要2個(gè)匹配電阻,其阻值要求等于傳輸電纜的特性阻抗(一般為120Ω)。沒(méi)有特性阻抗的話,當(dāng)所有的設(shè)備都靜止或者沒(méi)有能量的時(shí)候就會(huì)產(chǎn)生噪聲,而且線移需要雙端的電壓差。沒(méi)有終接電阻的話,會(huì)使得較快速的發(fā)送端產(chǎn)生多個(gè)數(shù)據(jù)信號(hào)的邊緣,導(dǎo)致數(shù)據(jù)傳輸出錯(cuò)。485推薦的連接方式:
在上面的連接中,如果需要添加匹配電阻,我們一般在總線的起止端加入,也就是主機(jī)和設(shè)備4上面各加一個(gè)120Ω的匹配電阻。
2. 收發(fā)器SP3485
圖中A、B總線接口,用于連接485總線。RO是接收輸出端,DI是發(fā)送數(shù)據(jù)收入端,RE是接收使能信號(hào)(低電平有效),DE是發(fā)送使能信號(hào)(高電平有效)。
3. 相關(guān)實(shí)驗(yàn)代碼解讀
這里僅給出主開(kāi)發(fā)板的實(shí)驗(yàn)代碼,次開(kāi)發(fā)板的實(shí)驗(yàn)代碼跟主開(kāi)發(fā)板的代碼基本差不多。
3.1 rs485.h頭文件代碼解讀
3.2 rs485.c文件代碼解讀
#include "sys.h" #include "rs485.h" #include "delay.h" #include "usart.h" #ifdef EN_USART2_RX //這里EN_USART2_RX設(shè)1,接收// u8 RS485_RX_BUF[64]; //接收緩存區(qū),最大64個(gè)字節(jié). u8 RS485_RX_CNT=0; void USART2_IRQHandler(void) //串口2中斷服務(wù)函數(shù)// {u8 res; if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET) //判斷USART2_SR寄存器的RXNE位是否不為0,即是否接收到數(shù)據(jù)//{ res =USART_ReceiveData(USART2); //如果不為0,則接收到數(shù)據(jù),讀取接收到的數(shù)據(jù)//if(RS485_RX_CNT<64){RS485_RX_BUF[RS485_RX_CNT]=res; //記錄接收到的值,放置在RS485_RX_BUF[]中//RS485_RX_CNT++; //RS485_RX_CNT加1//} } } #endif //初始化IO 串口2,pclk1:PCLK1時(shí)鐘頻率(Mhz),bound:波特率// void RS485_Init(u32 bound) { GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;NVIC_InitTypeDef NVIC_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD, ENABLE); //使能GPIOA和D的時(shí)鐘//RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //使能USART2時(shí)鐘////初始化PD7,推挽輸出,用來(lái)控制SP3485的接受/發(fā)送使能//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; //PD7端口配置//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出//GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOD, &GPIO_InitStructure);//配置PA2為復(fù)用推挽輸出//GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA2//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復(fù)用推挽//GPIO_Init(GPIOA, &GPIO_InitStructure);//配置PA3為浮空輸入// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3; //PA3//GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入//GPIO_Init(GPIOA, &GPIO_InitStructure); RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,ENABLE); //復(fù)位串口2//RCC_APB1PeriphResetCmd(RCC_APB1Periph_USART2,DISABLE); //停止復(fù)位// #ifdef EN_USART2_RX //如果使能了接收////如果EN_USART2_RX設(shè)1,為接收,還要初始化USART//USART_InitStructure.USART_BaudRate = bound; //波特率設(shè)置//USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位數(shù)據(jù)長(zhǎng)度//USART_InitStructure.USART_StopBits = USART_StopBits_1; //一個(gè)停止位//USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶校驗(yàn)位//USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //無(wú)硬件數(shù)據(jù)流控制//USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收發(fā)模式//USART_Init(USART2, &USART_InitStructure); //編寫(xiě)串口2中斷優(yōu)先級(jí)//NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn; //使能串口2中斷//NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //搶占優(yōu)先級(jí)2級(jí)//NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //從優(yōu)先級(jí)2級(jí)//NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道//NVIC_Init(&NVIC_InitStructure); USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); //開(kāi)啟接收中斷//USART_Cmd(USART2, ENABLE); //使能串口// #endifRS485_TX_EN=0; //默認(rèn)為接收模式// } //RS485發(fā)送len個(gè)字節(jié),buf:發(fā)送區(qū)首地址,len:發(fā)送的字節(jié)數(shù)(為了和本代碼的接收匹配,這里建議不要超過(guò)64個(gè)字節(jié))// void RS485_Send_Data(u8 *buf,u8 len) {u8 t;RS485_TX_EN=1; //設(shè)置為發(fā)送模式for(t=0;t<len;t++) //循環(huán)發(fā)送數(shù)據(jù){ while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); //判斷是否發(fā)送完成//USART_SendData(USART2,buf[t]);} while(USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET); RS485_RX_CNT=0; RS485_TX_EN=0; //設(shè)置為接收模式 } //RS485查詢接收到的數(shù)據(jù),buf:接收緩存首地址,len:讀到的數(shù)據(jù)長(zhǎng)度// void RS485_Receive_Data(u8 *buf,u8 *len) {u8 rxlen=RS485_RX_CNT;u8 i=0;*len=0; //默認(rèn)為0delay_ms(10); //等待10ms,連續(xù)超過(guò)10ms沒(méi)有接收到一個(gè)數(shù)據(jù),則認(rèn)為接收結(jié)束//if(rxlen==RS485_RX_CNT&&rxlen) //==的優(yōu)先級(jí)比&&的高,判斷是否接收到數(shù)據(jù)//{for(i=0;i<rxlen;i++){buf[i]=RS485_RX_BUF[i]; } *len=RS485_RX_CNT; //記錄本次數(shù)據(jù)長(zhǎng)度//RS485_RX_CNT=0; //清零//} }3.3 main.c文件代碼解讀
#include "led.h" #include "delay.h" #include "key.h" #include "sys.h" #include "usart.h" #include "rs485.h" int main(void){ u8 key;u8 i=0,t=0;u8 cnt=0;u8 rs485buf[5]; delay_init(); //延時(shí)函數(shù)初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //設(shè)置中斷優(yōu)先級(jí)分組為組2:2位搶占優(yōu)先級(jí),2位響應(yīng)優(yōu)先級(jí)//uart_init(115200); //串口初始化為115200//LED_Init(); //初始化與LED連接的硬件接口//KEY_Init(); //按鍵初始化// RS485_Init(9600); //初始化RS485// while(1){key=KEY_Scan(0); //有鍵按下時(shí),key就不為0//if(key==KEY0_PRES) //KEY0按下,發(fā)送一次數(shù)據(jù)//{for(i=0;i<5;i++){rs485buf[i]=cnt+i; //填充發(fā)送緩沖區(qū)//printf("\n發(fā)送數(shù)據(jù)為:%d\r\n",rs485buf[i]);}RS485_Send_Data(rs485buf,5); //發(fā)送5個(gè)字節(jié)// } RS485_Receive_Data(rs485buf,&key); //每次循環(huán)都執(zhí)行//if(key) //接收到有數(shù)據(jù)//{if(key>5)key=5; //最大是5個(gè)數(shù)據(jù)//for(i=0;i<key;i++)printf("\n接收數(shù)據(jù)為:%d\r\n",rs485buf[i]);}t++; delay_ms(10);if(t==20){LED0=!LED0; //提示系統(tǒng)正在運(yùn)行// t=0;cnt++; } } }4. 實(shí)驗(yàn)結(jié)果
舊知識(shí)點(diǎn)
1)復(fù)習(xí)如何新建工程模板,可參考STM32學(xué)習(xí)心得二:新建工程模板;
2)復(fù)習(xí)基于庫(kù)函數(shù)的初始化函數(shù)的一般格式,可參考STM32學(xué)習(xí)心得三:GPIO實(shí)驗(yàn)-基于庫(kù)函數(shù);
3)復(fù)習(xí)寄存器地址,可參考STM32學(xué)習(xí)心得四:GPIO實(shí)驗(yàn)-基于寄存器;
4)復(fù)習(xí)位操作,可參考STM32學(xué)習(xí)心得五:GPIO實(shí)驗(yàn)-基于位操作;
5)復(fù)習(xí)寄存器地址名稱映射,可參考STM32學(xué)習(xí)心得六:相關(guān)C語(yǔ)言學(xué)習(xí)及寄存器地址名稱映射解讀;
6)復(fù)習(xí)時(shí)鐘系統(tǒng)框圖,可參考STM32學(xué)習(xí)心得七:STM32時(shí)鐘系統(tǒng)框圖解讀及相關(guān)函數(shù);
7)復(fù)習(xí)延遲函數(shù),可參考STM32學(xué)習(xí)心得九:Systick滴答定時(shí)器和延時(shí)函數(shù)解讀;
8)復(fù)習(xí)ST-LINK仿真器的參數(shù)配置,可參考STM32學(xué)習(xí)心得十:在Keil MDK軟件中配置ST-LINK仿真器;
9)復(fù)習(xí)ST-LINK調(diào)試方法,可參考STM32學(xué)習(xí)心得十一:ST-LINK調(diào)試原理+軟硬件仿真調(diào)試方法;
10)復(fù)習(xí)串口通信相關(guān)知識(shí),可參考STM32學(xué)習(xí)心得十四:串口通信相關(guān)知識(shí)及配置方法。
總結(jié)
以上是生活随笔為你收集整理的STM32学习心得三十一:485通信原理及实验的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: [MySQL] 分组排序取前N条记录以及
- 下一篇: OC基础学习