風向變送器有8方位風向和360度風向兩種;
外殼分為鋁合金和聚碳兩種;
風向傳感器/變速器測量方式分為:
-
模擬量(4-20mA/0-5V/0-10V) -
RS485
由于風速和風向變送器是分開的,所以我們選擇了RS485總線的測量方式,這樣我們將兩個模塊并到一起,設為不同的地址,這樣就可以只占用一個串口資源就可以獲取風速和風向的數據了。
應用場景
廣泛適用于氣象、海洋、環(huán)境、機場、港口、實驗室、工農業(yè)及交通等領域的風速和風向測量。
數據幀格式定義
采用Modbus-RTU 通訊規(guī)約,格式如下:
初始結構 ≥4 字節(jié)的時間
地址碼 = 1 字節(jié)
功能碼 = 1 字節(jié)
數據區(qū) = N 字節(jié)
錯誤校驗 = 16 位CRC 碼
結束結構 ≥4 字節(jié)的時間
地址碼:為變送器的地址,在通訊網絡中是唯一的(出廠默認0x01)。
功能碼:主機所發(fā)指令功能指示,本變送器只用到功能碼0x03(讀取寄存器數據)。
數據區(qū):數據區(qū)是具體通訊數據,注意16bits數據高字節(jié)在前!
CRC碼:二字節(jié)的校驗碼。
注意:此通訊協議只適用于我購買過的那款風速風向儀,不同廠家協議不同。
主機問詢幀結構:
地址碼 | 功能碼 | 寄存器起始地址 | 寄存器長度 | 校驗碼低位 | 校驗碼高位 |
---|---|---|---|---|---|
1字節(jié) | 1字節(jié) | 2字節(jié) | 2字節(jié) | 1字節(jié) | 1字節(jié) |
從機應答幀結構:
地址碼 | 功能碼 | 有效字節(jié)數 | 數據一區(qū) | 第二數據區(qū) | 第N數據區(qū) | 校驗碼 |
---|---|---|---|---|---|---|
1字節(jié) | 1字節(jié) | 1字節(jié) | 2字節(jié) | 2字節(jié) | 2字節(jié) | 2字節(jié) |
通訊實例:
讀取設備地址0x01的風向
問詢幀:
地址碼 | 功能碼 | 起始地址 | 數據長度 | CRC低位 | CRC高位 |
---|---|---|---|---|---|
0x01 | 0x03 | 0x00 0x00 | 0x00 0x02 | 0xC4 | 0x0B |
應答幀:(例如讀到風向值(0-7檔)為2,(0-360°)為90°)
地址碼 | 功能碼 | 返回字節(jié)數 | 風向(0-7檔) | 風向(0-360°) | CRC低位 | CRC高位 |
---|---|---|---|---|---|---|
0x01 | 0x03 | 0x04 | 0x00 0x02 | 0x00 0x5A | 0xDB | 0xC8 |
風向計算:
(0-7檔):0002H(十六進制)= 2=> 風向 = 東風
(0-360°):005AH (十六進制)= 90=> 風向= 東風
讀取設備地址0x01的風速值
問詢幀:
地址碼 | 功能碼 | 起始地址 | 數據長度 | CRC低位 | CRC高位 |
---|---|---|---|---|---|
0x01 | 0x03 | 0x00 0x00 | 0x00 0x01 | 0x84 | 0x0A |
應答幀:(例如讀到當前風速為8.6m/s)
地址碼 | 功能碼 | 返回字節(jié)數 | 當前風速值 | CRC低位 | CRC高位 |
---|---|---|---|---|---|
0x01 | 0x03 | 0x02 | 0x00 0x56 | 0x38 | 0x7A |
風速計算:
當前風速:0056H(十六進制)= 86=> 風速 = 8.6m/s
硬件連接
-
風速和風向變速器12V供電; -
我們使用一個485接口,將風速和風向變速器并聯到了一起。
由于RS485的子設備之間的設備地址不能相同,所以我們將風速儀的地址設為了1,風向儀的地址設為了2。
RS485總線參考電路
要想獲取風速或風向值,我們要經過如下三步操作:
(1)發(fā)送問詢幀:
if(times%10==1)
{
times2++;
if(times2%10==0)
{
//求風速
sprintf(dtbuf, "%c%c%c%c%c%c%c%c", 0x01,0x03,0x00,0x00,0x00,0x01,0x84,0x0A);
MAX485DE=1;
USART2_OUT((u8 *)dtbuf, 8);
MAX485DE=0;
}
else if(times2%10==5)
{
//求風向
sprintf(dtbuf, "%c%c%c%c%c%c%c%c", 0x02,0x03,0x00,0x00,0x00,0x02,0xC4,0x38);
MAX485DE=1;
USART2_OUT((u8 *)dtbuf, 8);
MAX485DE=0;
}
}
(2)接收串口數據:
u16 USART2_RX_STA=0;
void USART2_IRQHandler(void)
{
u8 res;
if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET)
{
res =USART_ReceiveData(USART2);
if(USART2_RX_STA<USART2_MAX_RECV_LEN)
{
TIM_SetCounter(TIM2,0);
if(USART2_RX_STA==0)
TIM2_Set(1);
USART2_RX_BUF[USART2_RX_STA++]=res;
}
else
{
USART2_RX_STA|=1<<15;
}
}
}
(3)解析數據幀:
//解析RS485信息
if(USART2_RX_STA&0x8000)
{
uart2Len=USART2_RX_STA&0x3f;
if(uart2Len==7)
{
nCRC16 = crc16(USART2_RX_BUF,5);
checkBitHig=(nCRC16>>8)&0xFF;
checkBitLow=nCRC16&0xFF;
if(checkBitHig==USART2_RX_BUF[5]&&checkBitLow==USART2_RX_BUF[6])
{
printf("收到風速數據包\r\n");
u16Value = USART2_RX_BUF[3] * 256 + USART2_RX_BUF[4];
stuAliOSIoT.WindSpeed = u16Value/10.0;
}
}
else if(uart2Len==9)
{
nCRC16 = crc16(USART2_RX_BUF,7);
checkBitHig=(nCRC16>>8)&0xFF;
checkBitLow=nCRC16&0xFF;
if(checkBitHig==USART2_RX_BUF[7]&&checkBitLow==USART2_RX_BUF[8])
{
printf("收到風向數據包\r\n");
stuAliOSIoT.WindDirection = USART2_RX_BUF[4];
}
}
USART2_RX_STA=0;
memset(USART2_RX_BUF, 0, sizeof(USART2_RX_BUF));
}
上面函數返回的數據幀,首先要對返回的數據進行CRC校驗,只有合法的數據幀我們才會對數據幀進行解析,防止出現臟包。
推薦閱讀:
STM32單片機最小系統詳解
STM32F103 串口的使用方法
STM32中精確延時函數的實現
免責聲明:本文內容由21ic獲得授權后發(fā)布,版權歸原作者所有,本平臺僅提供信息存儲服務。文章僅代表作者個人觀點,不代表本平臺立場,如有問題,請聯系我們,謝謝!