目錄
一、硬件配置
1、RCC、DEBUG、CodeGenerator
2、USART3
3、 RS485_DIR
4、NVIC?
二、軟件設計
1、RS485的收發控制
2、main.c
三、運行調試
1、修改RS485_DIR為SET后需要延遲
2、向串口助手發送的數據不能太長
????????MCU上的串口UART(USART)是邏輯電平(TTL或CMOS電平),在開發板上實現與串口助手之間的RS485通信,就是把單片機上的邏輯電平通過RS485物理層芯片轉換為RS485電平。
? ? ? ? 本文繼續使用旺寶紅龍開發板STM32F407ZGT6 KIT V1.0。本文的目的是通過MAX485物理層芯片把開發板上的USART3(PB10、PB11)邏輯電平轉換為RS485電平,然后通過一條USB轉RS485的轉換線連接到串口助手上。原理圖如下:
? ? ? ? P18的管腳A+連接USB轉RS485的線的T/R+,P18的管腳A-連接USB轉RS485的線的T/R-。
????????在串口助手上識別出識別出該線的驅動,選擇并設置波特率,通過幾次調試可以選擇到不失真時的最大波特率,其它參數可以默認。串口助手的波特率與MCU里配置USART3時選擇的波特率要一致。
一、硬件配置
1、RCC、DEBUG、CodeGenerator
- RCC:外部晶振25MHz,HCLK=168MHz,PCLK1=42MHz,PCLK2=84MHz;
- DEBUG:Serial Wire;
- CodeGenerator:勾選?Generate peripheral initialization as a pair of '.c/.h' files per peripheral
2、USART3
????????配置PB10、PB11為USART3,波特率9600,其它參數默認;
? ? ? ? 本文作者測試到波特率14400,不失真,15200失真。
3、 RS485_DIR
? ? ? ? RS485是半雙工通信的,因此有方向控制,設置PF7為RS485_DIR,默認為高電平。
4、NVIC?
? ? ? ? 把Times base的中斷優先級修改為0。USART3的全局中斷可以設置為優先級1。如果不需要也可以不選擇。
二、軟件設計
? ? ? ? 實例程序很短,只是為了演示RS485的收發控制。
1、RS485的收發控制
? ? ? ? ?每次向串口助手發送前,要先把RS485_DIR置位。
//修改RS485為發送HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET);
????????每次接收數據前要先把RS485_DIR復位。
//默認RS485為接收狀態
HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_RESET);
2、main.c
/* USER CODE BEGIN Includes */
#include <stdio.h>
uint8_t rxbuf[8];
uint8_t ackbuf[]="123\r\n";
/* USER CODE END Includes */
/* USER CODE BEGIN 2 *///默認RS485為發送狀態uint8_t txbuf1[]="Hello,world!\r\n";HAL_UART_Transmit(&huart3,txbuf1,sizeof(txbuf1),1000);HAL_Delay(500);HAL_UART_Transmit(&huart3,txbuf1,sizeof(txbuf1),1000);HAL_Delay(500);uint8_t txbuf2[]="TEST RS485!\r\n";HAL_UART_Transmit(&huart3,txbuf2,sizeof(txbuf2),1000);HAL_Delay(500);HAL_UART_Transmit(&huart3,ackbuf,sizeof(ackbuf),1000);HAL_Delay(500);//修改RS485為接收HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_RESET);//485改為接收后,不能發送HAL_UART_Transmit(&huart3,ackbuf,sizeof(ackbuf),1000);HAL_Delay(500);//修改RS485為發送HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET);//沒有適當的延遲,則亂碼HAL_Delay(200); //切換測試,注釋掉,以觀察亂碼uint8_t txbuf3[]="can transmit again.\r\n";HAL_UART_Transmit(&huart3,txbuf3,sizeof(txbuf3),1000);HAL_Delay(500);HAL_UART_Transmit(&huart3,ackbuf,sizeof(ackbuf),1000);HAL_Delay(500);HAL_UART_Transmit(&huart3,txbuf1,sizeof(txbuf1),1000);HAL_Delay(500);//修改為小于16字節后,亂碼消失.uint8_t txbuf4[]="transmit again.\r\n";HAL_UART_Transmit(&huart3,txbuf4,sizeof(txbuf4),1000);HAL_Delay(500);/* USER CODE END 2 */
/* USER CODE BEGIN WHILE */
while (1)
{/* USER CODE END WHILE *//* USER CODE BEGIN 3 *//* 如果MCU接收到數據,則執行發送任務,發送前修改485為發送*/if(HAL_UART_Receive(&huart3,rxbuf,sizeof(rxbuf),1000) == HAL_OK){/*設置485為發送*/HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET);//修改RS485收發控制后要有延遲,否則,立刻發送的數據會有亂碼HAL_UART_Transmit(&huart3,ackbuf,sizeof(ackbuf),1000);printf("\r\n");HAL_Delay(200);printf("修改RS485_DIR后要有延遲,");printf("否則,立刻發送的數據會有亂碼.\r\n");HAL_Delay(500); //這是必需,否則會亂碼HAL_UART_Transmit(&huart3,ackbuf,sizeof(ackbuf),1000);HAL_Delay(500);char str[8];sprintf(str,"%s",ackbuf);printf("test:%s\r\n",str);HAL_Delay(500);uint8_t txbuf6[]="RS485發送的數據:";HAL_UART_Transmit(&huart3,txbuf6,sizeof(txbuf6),1000);//printf("RS485發送的數據:");HAL_Delay(500);HAL_UART_Transmit(&huart3,rxbuf,sizeof(rxbuf),1000);HAL_Delay(500);printf("\r\n");HAL_Delay(200);uint8_t txbuf7[]="\r\n";HAL_UART_Transmit(&huart3,txbuf7,sizeof(txbuf7),1000);HAL_Delay(200);}/默認RS485為接收狀態HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_RESET);
}
/* USER CODE END 3 */
/* USER CODE BEGIN 4 */
//串口打印
int __io_putchar(int ch)
{HAL_UART_Transmit(&huart3,(uint8_t*)&ch,1,0xFFFF);return ch;
}
/* USER CODE END 4 */
三、運行調試
? ? ? ? 重要的調試發現,在調試RS485通訊時,發現串口助手上顯示亂碼,最終找到2個原因:
1、修改RS485_DIR為SET后需要延遲
? ? ? ? 每次HAL_GPIO_WritePin(RS485_DIR_GPIO_Port, RS485_DIR_Pin, GPIO_PIN_SET)后應該適當地延遲,不然,顯示到串口助手上的數據亂碼。
2、向串口助手發送的數據不能太長
? ? ? ? 向串口助手上發送的數據不能太長,不然,也會亂碼。具體達到多長的數據才開始亂碼,要測試后確定。過長的數據可以分批次傳送,printf()函數更適合發送長的數據,也適合發送和顯示有換行要求的數據;