Professional Documents
Culture Documents
net/a/5b8cd4122b7177188335e7a9
1.優劣
優勢:RS485 的可靠傳輸距離遠,接線簡單成爲了相對於 RS232 的最大優勢。
不足:RS485 總線是一種常規的通信總線,它不能夠做總線的自動仲裁,也就是不能夠同時發送數據以
避免總線競爭,所以整個系統的通信效率必然較低,數據冗餘量較大,對於速度要求高的應用場所不適
應用 RS485 總線。同時由於 RS485 總線上通常只有一臺主機,所以這種總線方式是典型的集中—分散型
控制系統。一旦主機出現故障,會使整個系統的通信限於癱瘓狀態,因此做好主機的在線備份是一個重
要措施。
2. 硬件層協議
通訊協議主要是實現兩個設備之間的數據交換功能,通訊協議分硬件層協議和軟件層協議。
硬件層協議決定數據如何傳輸問題,比如要在設備 1 向設備 2 發送 0x63,0x63 的二進制數
爲 0110 0011,這 8 個二進制數從設備 1 傳輸到設備 2,涉及到 1 怎麼傳,0 怎麼傳的問題,
這就是硬件層要解決的問題。
硬件層協議目前比較多見的有 RS-232、RS-485、SPI、IIC 等。RS-232 規定,線上的電壓
爲 x 伏都表示傳輸的是 0,y 伏傳輸的則是 1。再者,比如要選擇多少條線傳輸數據,選擇什
麼材質的線傳輸輸入,這些也屬於硬件層協議約束的。
3.RS-485 通訊協議
MCU 管腳輸出 TTL 電平,TTL 電平的意思是,當 MCU 管腳輸出 0 電平時,一般情況下電壓
是 0V,當 MCU 管腳輸出 1 電平時,電壓是 5V。因 TTL 電平的是由一條信號線,一條地線
產生,信號線上的干擾信號會跟隨有效信號傳送到接收端,使得有效信號受到干擾,485 通
訊實際上是把 MCU 出來的 TTL 電平通過硬件層的一個轉換器芯片進行轉換:
把 MCU 出來的一條的 TTL 信號經過芯片轉換爲兩根線(線 A、線 B)上的信號。當 MCU 給轉
換器輸入低 TTL 電平時,轉換器會使得 B 的電壓比 A 的電壓高,反之,A 的電壓比 B 的電壓
高。
485 協議規約兩條電平線上差值爲多少表示 0 或者 1,電壓是通過儀表可以測量得到的,所
以說 RS-485 是硬件層協議。
485 協議的接收端可能是另一個 MCU,MCU 管腳也只接受 TTL 電平,轉換芯片過來的是兩
條線的電壓,所以需要對此兩條線差分電壓轉換爲 TTL 電平。
把 TTL 轉爲 485,實質是一個集成芯片,其間無任何程序代碼,純粹硬件邏輯。同理,將
485 電平轉爲 TTL 也是如此。現在很多芯片把接收和轉換都集成到一塊 IC,注意,轉換器和
接收器依舊是沒有同時工作的,常見的轉換芯片是 MAX485。
可以這樣理解,硬件層協議是公路,路的目的是爲了讓車輛能夠過去。
4.半雙工通訊
首先了解什麼是單工通訊,單工通訊是指數據只能朝着一個方向傳輸的通訊方式。而半雙工
通訊則是指對於通訊兩端,不能同時相對方法發送數據,必須錯開時間段發送。
5.基本電路
三種常用電路如下:
5.3 自動切換電路
上圖中,TX,RX 引腳均需要上拉電阻,這一點特別重要。
接收:默認沒有數據時,TX 爲高電平,三極管導通,RE 爲低電平使能,RO 收數
據有效,MAX485 爲接收態。
發送:發送數據 1 時,TX 爲高電平時,三極管導通,DE 爲低電平,此時收發器處
於接收狀態,驅動器就變成了高阻態,也就是發送端與 A\B 斷開了,此時 A\B 之
間的電壓就取決於 A\B 的上下拉電阻了,A 爲高電平、B 爲低電平,也就成爲了邏
輯 1 了。
發送數據 0 時,TX 爲低電平,三極管截止,DE 爲高電平,驅動器使能,
此時正好 DI 是接地的,也就是低電平,驅動器也就會驅動輸出 B 爲 1,A 爲 0,也
就是所謂的邏輯 0 了。
理解自收發的作用,關鍵是要理解 RE 和 DE 的作用,尤其是 DE 爲 0 時,驅
動器與 A\B 之間就是高阻態,也就是斷開狀態,而且 A\B 都要有上下拉電阻。然
後就有了邏輯 0-1 之間的切換了。所以很巧妙,但是這裏也有一個很明顯的
bug,也就是隻適用於“半雙工”,如果是全雙工,就不行了,因爲 TX 爲 1 時,
接收使能,此時從機如果回覆數據,那麼也就亂了。
基本原理了解了,除了使用三極管實現,還可以使用施密特觸發器,也就是所
謂的“非”門,來顯現,如下圖所示:
基本原理與三極管相同,TX 爲 1 時,經過施密特觸發器進行“非”運算,DE 爲
0,則接收使能,驅動器呈高阻態,此時 A\B 的電平就是上下拉電阻的電平,也就
是邏輯 1。TX 爲 0 時,DE 爲 1,發送使能,由於 DI 接地,也就是 0,A\B 輸出也
是 0.
6.SP3485 內部結構圖:
圖中:
A、B 總線接口,用於連接 485 總線。RO 是接收輸出端,DI 是發送數據收入端,RE 是接收
使能信號(低電平有效),DE 是發送使能信號(高電平有效)。
SP3485 硬件連接:
注意:
R55 和 R56 是兩個偏置電阻,用來保證總線空閒時,AB 之間的電壓差都會大約 200mV,
避免總線空閒時壓差不定邏輯混亂。
7. RS485 串口編程
7.1 編程思路
7.2 功能模塊代碼
① 串口初始化
void Uart1_Init(void)
{
//USART1 初始化
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //開啓
GPIOA 時鐘
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE); //開啓
USART1 時鐘
//串口 1 對應引腳複用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9
複用爲 USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10
複用爲 USART1
//USART1 端口配置
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10;
//GPIOA9,GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //複用功
能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度
50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推輓複
用輸出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化
PA9,PA10
//USART1 端口配置
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx |
USART_Mode_Tx;
USART_Init(USART1, &USART_InitStructure);
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
//Usart1 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =3;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
void Uart2_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);
//串口 2 對應引腳複用映射
GPIO_PinAFConfig(GPIOA,GPIO_PinSource2,GPIO_AF_USART2);
GPIO_PinAFConfig(GPIOA,GPIO_PinSource3,GPIO_AF_USART2);
//USART2 端口配置
USART_InitStructure.USART_BaudRate = 115200;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl =
USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
//Usart2 NVIC 配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3;
NVIC_InitStructure.NVIC_IRQChannelSubPriority =2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
② 接收數據
void USART2_IRQHandler(void)
{
static u32 rx_i=0;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
USART_ClearITPendingBit(USART2,USART_IT_RXNE); //清除標誌位
rx_buf[rx_i++] = USART_ReceiveData(USART2); //rx_buf 是在
main.c 定義的全局變量
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
}
rx_flag = 1;
}
③RS485 初始化
void Rs485_Init(void)
{
GPIO_InitTypeDef GPIO_InitStruct;
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOG, ENABLE);
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8;
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_100MHz;
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
GPIO_Init(GPIOG, &GPIO_InitStruct);
// RS485_TX_EN = 0; //默認爲接收模式
}
④ 主函數
int main(void)
{
char *tx_buf = "I believe I can fly!";
u8 len;
Led_Init();
Key_Init();
Systick_Init();
Uart1_Init();
Uart2_Init();
Rs485_Init();