OS:Windows 64
Development kit:MDK5.14
IDE:UV4
MCU:STM32F103C8T6/VET6
AD:Altium Designer 18.0.12
1、RS485簡介
RS-485又名TIA-485-A, ANSI/TIA/EIA-485或TIA/EIA-485。
RS485是一個定義平衡數字多點系統中的驅動器和接收器的電氣特性的標准,該標准由電信行業協會和電子工業聯盟定義。使用該標准的數字通信網絡能在遠距離條件下以及電子噪聲大的環境下有效傳輸信號。RS-485使得廉價本地網絡以及多支路通信鏈路的配置成為可能。RS485接口組成的半雙工網絡,一般是兩線制(以前有四線制接法,只能實現點對點的通信方式,現很少采用),多采用屏蔽雙絞線傳輸。這種接線方式為總線式拓撲結構在同一總線上最多可以掛接32個結點。在RS485通信網絡中一般采用的是主從通信方式,即一個主機帶多個從機。很多情況下,連接RS-485通信鏈路時只是簡單地用一對雙絞線將各個接口的“A”、“B”端連接起來。RS485接口連接器采用DB-9的9芯插頭座,與智能終端RS485接口采用DB-9(孔),與鍵盤連接的鍵盤接口RS485采用DB-9(針)。
在低速、短距離、無干擾的場合可以采用普通的雙絞線,反之,在高速、長線傳輸時,則必須采用阻抗匹配(一般為120Ω)的RS485專用電纜(STP-120Ω(用於RS485 & CAN)一對18AWG),而在干擾惡劣的環境下還應采用鎧裝型雙絞屏蔽電纜(ASTP-120Ω(用於RS485 & CAN)一對18AWG)。
2、RS485特性
- RS-485的電氣特性:邏輯“0”以兩線間的電壓差為+(2—6)V表示;邏輯“1”以兩線間的電壓差為-(2—6)V表示。接口信號電平比RS-232降低了,就不易損壞接口電路的芯片,且該電平與TTL電平兼容,可方便與TTL電路連接
- RS-485的數據最高傳輸速率為10Mbps
- RS-485接口是采用平衡驅動器和差分接收器的組合,抗共模干擾能力增強,即抗噪聲干擾性好
- RS-485接口的最大傳輸距離標准值為4000英尺(約1219米),實際上可達3000英尺,另外RS-232接口在總線上只允許連接1個收發器,即單站能力。而RS-485接口在總線上是允許連接多達128個收發器。即具有多站能力,這樣用戶可以利用單一的RS-485接口方便地建立起設備網絡。
3、RS485通信硬件實現
博主使用的485芯片為MAX3485,實現半雙工通信。應用電路如下圖:
R6為120歐的阻抗匹配電阻,如果長距離通信的話,一定要在最后一個節點接上這一個電阻;但是短距離通信的話焊上R6反而出錯(博主在實驗中發現,焊上匹配電阻后,主從節點通信異常,調試發現大量的00字節在自動收發),因此建議大家先不要焊上,但是在電路設計時保留。RXD485、TXD485分別接控制芯片的USART1_RX、USART1_TX(串口號可自行選擇,這里使用串口1),此外;485C接芯片的PA4引腳(隨意選擇)用以切換485的通信狀態。J1、J2為兩個JST接口,方便485通信線路的連接,由於是從節點因而留出兩個。以下為其余連接電路:
4、RS485通信軟件實現

1 #include "sys.h"
2 #include "stdio.h"
3
4 #define USART1_RX_LEN 50 //接收最大字節
5 #define USART1_TX_LEN 50 //發送最大字節
6 #define RS485_TX_EN PAout(4)
7
8
9 extern u8 USART1_RX_Buf[USART1_RX_LEN]; //接收緩沖
10 extern u8 USART1_TX_Buf[USART1_TX_LEN]; //發送緩沖
11 extern u8 USART1_RX_Data_Len; //實際接收數據字節長度
12 extern u8 USART1_TX_Data_Len; //待發送數據字節長度
13 extern u8 USART1_RX_Flag; //是否收到數據
14
15 void RS485_Config(u32 bound); 16 void USART1_IRQHandler(void); 17 void RS485_Send_Data(u8 *buf,u8 len);

1 #include "sys.h"
2 #include "delay.h"
3 #include "rs485.h"
4
5 u8 USART1_RX_Buf[USART1_RX_LEN]; //接收緩沖
6 u8 USART1_TX_Buf[USART1_TX_LEN]; //發送緩沖
7 u8 USART1_RX_Data_Len = 0; //實際接收數據字節長度
8 u8 USART1_TX_Data_Len = 0; //待發送數據字節長度
9 u8 USART1_RX_Flag = 0; //串口1是否接收完數據
10
11 void USART1_IRQHandler(void) 12 { 13 u8 res; 14 if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收到數據
15 { 16 res =USART_ReceiveData(USART1); //讀取接收到的數據
17 if(USART1_RX_Data_Len<USART1_RX_LEN) 18 { 19 USART1_RX_Buf[USART1_RX_Data_Len]=res; //記錄接收到的值
20 USART1_RX_Data_Len++; //接收數據增加 1
21 } 22 USART1_RX_Flag=1; //串口1接收到數據
23 } 24 } 25
26 void RS485_Config(u32 bound) 27 { 28 GPIO_InitTypeDef GPIO_InitStructure; 29 USART_InitTypeDef USART_InitStructure; 30 NVIC_InitTypeDef NVIC_InitStructure; 31
32 /*********************配置串口1**************************/
33
34 /* config USART1 clock */
35 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 , ENABLE); 36 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA , ENABLE); 37
38 /* USART1 GPIO config */
39 /* Configure USART1 Tx (PA.02) as alternate function push-pull *///TX
40 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; 41 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //復用推挽輸出
42 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 43 GPIO_Init(GPIOA, &GPIO_InitStructure); 44 /* Configure USART1 Rx (PA.03) as input floating *///RX
45 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; 46 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空輸入
47 GPIO_Init(GPIOA, &GPIO_InitStructure); 48
49
50
51
52 /* USART1 mode config */
53
54 USART_InitStructure.USART_BaudRate = bound; 55 USART_InitStructure.USART_WordLength = USART_WordLength_8b; 56 USART_InitStructure.USART_StopBits = USART_StopBits_1; 57 USART_InitStructure.USART_Parity = USART_Parity_No ; 58 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; 59 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 60 USART_Init(USART1, &USART_InitStructure); 61
62 /* USART1 接收中斷 */
63 NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //使能串口 2 中斷
64 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3; //先占優先級 3 級
65 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2; //從優先級 2級
66 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能外部中斷通道
67 NVIC_Init(&NVIC_InitStructure);//初始化 NVIC 寄存器
68
69 USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //開啟中斷
70 USART_Cmd(USART1, ENABLE); //使能串口 71
72 //USART_ClearFlag(USART1, USART_FLAG_TC);//清發送完成標志
73
74
75 /**********************配置485控制口*********************/
76
77 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4; 78 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽輸出 ,PA4,485Ctr
79 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 80 GPIO_Init(GPIOA, &GPIO_InitStructure); 81 GPIO_ResetBits(GPIOA, GPIO_Pin_4); //設置為接收模式,默認接收
82
83 } 84
85 void RS485_Send_Data(u8 *buf,u8 len) //發送完改為接收
86 { 87 u8 t; 88 RS485_TX_EN=1;//設置為發送模式
89 for(t=0;t<len;t++) 90 { 91 while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 92 USART_SendData(USART1,buf[t]); 93 } 94 while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); 95
96 USART1_RX_Data_Len=0; 97 RS485_TX_EN=0;//設置為接收模式
98 }
通過以上代碼我么們就能通過STM32的串口資源實現485的正常通信了。注意事項:
- 初始化串口:RX設置為浮空輸入、TX設置為復用推挽輸出
- 因為是從節點,默認為接收模式,485C初始化為低電平;主節點則相反。可根據需要修改
- 每次發送或接收時都應切換通信狀態