文章目錄
- 一 RS-232
- 二 RS485
- 三 Modbus
- 四 stm32多路超聲波測距
- 4.1 設計方案
- 4.2 代碼
- 參考資料
- 總結
實驗要求
一. 采用stm32F103和HC-SR04超聲波模塊, 使用標準庫或HAL庫+ 定時器中斷,完成1或2路的超聲波障礙物測距功能。
1)測試數據包含噪聲,程序需要進行濾波處理;將測距數值通過串口上傳到上位機串口助手;
2)根據障礙物距離遠近,控制一個蜂鳴器(可以用LED燈代替)發出頻率不同的聲音(或LED不同閃爍),即輸出占空比變化的PWM波形;
3)在沒有超聲波模塊硬件的場景下,先使用Keil中的仿真邏輯分析儀,觀察分析對應管腳上的時序波形,判讀是否符合協議規范。
二. 當前智能汽車上一般配置有12路超聲波雷達,這些專用超聲波雷達內置了MCU,直接輸出數字化的測距結果,一般硬件接口采用串口RS485,通信協議采用modbus。請思考:
1)RS485與RS232(UART)有什么不同?
2)Modbus協議是什么?
3)如果讓你設計一款 12路車載超聲波雷達,采用 stm32F103+HC-SR04超聲波模塊,對外提供RS485和Modbus協議,你的設計方案是什么?
一 RS-232
是異步串行通信接口標準之一,規定了連接電纜和機械、電氣特性、信號功能及發送過程
特點:
- 支持全雙工通信
- 波特率可選
- 負邏輯傳送
- 傳送距離較遠
缺點:
- 接口信號電平值較高,易損壞接口電路芯片
- 傳輸速率較低,只有20Kbps
- 共地傳輸,易產生共模干擾
- 傳輸距離有限
引腳定義
通信機理
A向B發送數據:
1、A先設置RTS為1,表示要發數據給B
2、B檢測到RTS為1,先看自己是否準備好:
如果準備好,就設置CTS為1表示A可以發數據給B了
如果沒有準備好,繼續處理自己的數據。弄完了,再將CTS設置為1,讓A發送數據
3、A發現CTS置1后,將數據通過TXD信號線發送出去
4、A每發送一次數據給B之前,都會繼續上面的邏輯
5、A發送完數據后,就將RTS置0,表示數據發送完畢
二 RS485
為針對RS232的缺點,出現了RS485
半雙工網絡
特點
-
RS-485的電氣特性:以兩線間的電壓差表示電平1和0
-
最高傳輸速率是10Mbps
-
平衡驅動器和差分接收器組合,抗共模干擾能力強,抗噪聲干擾性好
-
RS232在總線上只允許連接1個收發器。RS485允許連接多達128個收發器,可使用單一的RS485建立設備網絡
485驅動電路
RXD和TXD是連接串口的,choose是選擇作為接收端還是發送端(二選一)。右邊就輸出A和B,即差分信號的線,與其它的485器件的AB連接。
三 Modbus
- Modbus是一種由Modicon(施耐德電氣公司)于1979年開發的串行通信協議,主要用于可編程邏輯控制器(PLC)和其他工業電子設備之間的通信。
- Modbus網絡遵循主/從模型,其中主站(Master)負責請求信息,而從站(Slave)提供信息。如下圖所示。
地址標識:每個從設備都有一個唯一的地址標識。
信息交互:主站可以讀取從站的內部寄存器,也可以向其寫入信息。
四 stm32多路超聲波測距
4.1 設計方案
這里假設設定四路超聲波。設定4個輸入捕獲通道,當超聲波模塊echo收到回波后,即觸發輸入捕獲上升沿,開始echo持續時間的計時,然后下降沿后開始使用公式進行換算,得到距離,通過串口發送出去。其中,著重要考慮以下問題;
- stm32的定時器資源是否足夠,同一定時器可以采用多路記錄超聲波嗎
可知stm32一個定時器有幾個通道,這些通道可以用來進行輸入捕獲,此方案也節省了io口資源。但是需要考慮如何設定定時器計數頻率,以及如何避免這種情況:假設定時器的重載值為200,echo在180時收到上升沿開始計數,會持續50個計數值,即在下一輪的30得到下降沿,此時如果直接使用減法,會造成負數或者不準確數值的問題。所以為了避免這種情況,需要使用一個變量來判斷是否完成了一個計數周期。
- stm32的定時器之間是否會有計數沖突:
在實驗檢驗過程中,單獨測試一個通道時記錄結果大致準確,但是接入兩個模塊時,似乎結果發生了干擾,但無法確認是否是定時器問題還是其它問題,后續有待解決。
- 若采用輪詢(狀態機)方案訪問會出現當一個超聲波停止工作時,其它超聲波也無法正常工作的狀態。
4.2 代碼
GPIO定時器初始化
void GPIO_Init(void) {// 配置Trig引腳為輸出,Echo引腳為輸入RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_2; // Trig1, Trig2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_3; // Echo1, Echo2GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);
}void Timer_Init(void) {// 配置定時器用于捕獲Echo信號RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;TIM_TimeBaseStructure.TIM_Period = 65535;TIM_TimeBaseStructure.TIM_Prescaler = 72-1; // 1MHzTIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);TIM_ICInitTypeDef TIM_ICInitStructure;TIM_ICInitStructure.TIM_Channel = TIM_Channel_1;TIM_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;TIM_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;TIM_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;TIM_ICInitStructure.TIM_ICFilter = 0x0;TIM_ICInit(TIM2, &TIM_ICInitStructure);TIM_Cmd(TIM2, ENABLE);
}
Modbus設計
void USART_Init(void) {// 配置USART用于RS485通信RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; // USART1_TXGPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // USART1_RXGPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_Init(GPIOA, &GPIO_InitStructure);USART_InitTypeDef USART_InitStructure;USART_InitStructure.USART_BaudRate = 9600;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);USART_Cmd(USART1, ENABLE);
}void Send_Modbus_Response(uint8_t* response, uint8_t length) {// 發送Modbus響應幀for (uint8_t i = 0; i < length; i++) {USART_SendData(USART1, response[i]);while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);}
}
參考資料
https://blog.csdn.net/LX567567/article/details/139182689?spm=1001.2014.3001.5502
https://mp.weixin.qq.com/s/6wBNP-9SHh1OGiTV51gH1w
總結
進一步了解了RS232及RS485,為后續設計打下基礎。