當(dāng)前位置:首頁(yè) > 嵌入式培訓(xùn) > 嵌入式學(xué)習(xí) > 講師博文 > FreeModbus溫濕度傳感器試驗(yàn)
【實(shí)驗(yàn)?zāi)康摹?/p>
● 學(xué)習(xí)STM32的Cortex-M0系列芯片的使用
● 學(xué)習(xí)IAR開發(fā)軟件的使用方法,如仿真調(diào)試
● 通過本實(shí)驗(yàn)掌握ModBus協(xié)議
【實(shí)驗(yàn)環(huán)境】
● STM32F051 Cortex-M0模塊
● IAR開發(fā)工具和相應(yīng)的仿真器
● PC機(jī) XP、win7/win8/win10(32/64)
【實(shí)驗(yàn)內(nèi)容】
利用STM32F051庫(kù)函數(shù)編寫ModBus實(shí)驗(yàn)程序,實(shí)現(xiàn)M0模塊上電默認(rèn)為從機(jī),當(dāng)接收到命令時(shí)可以,可以自動(dòng)切換為主機(jī),向溫濕度傳感器發(fā)送請(qǐng)求命令,溫濕度傳感器響應(yīng)返回?cái)?shù)據(jù)。M0通過無線ZigBee(串口2)發(fā)送出去。ZigBee協(xié)調(diào)接收無線數(shù)據(jù)并顯示到串口上。
【實(shí)驗(yàn)原理】
圖 STM32F051原理圖
溫濕度傳感:
【實(shí)驗(yàn)步驟】
完成第“開發(fā)環(huán)境搭建”章節(jié)的IAR環(huán)境搭建,就可以做傳感器實(shí)驗(yàn)了,首先打開光盤中的傳感器工程文件。
工程源碼路徑:【智能農(nóng)業(yè)光盤資料\01程序源碼\03M0節(jié)點(diǎn)源碼\01Modbus_STM32F051(溫濕度1 01)\Project】
編譯下載程序(先編譯后下載)
打開“設(shè)備管理”。
查看COM口,打開串口調(diào)試助手。波特率9600,串口號(hào)COM8。
M0模塊與485總線板子連接在一起。并確保溫濕度傳感器連接到485上。
【實(shí)驗(yàn)現(xiàn)象】
利用串口調(diào)試助手,串口轉(zhuǎn)485調(diào)試板,485總線的線和調(diào)試板相連接。
在串口發(fā)送區(qū)發(fā)送請(qǐng)求命令,返回讀到的溫濕度環(huán)境信息:
發(fā)送請(qǐng)求命令:01 03 00 00 00 02 C4 0B
根據(jù)ModBus協(xié)議:01:設(shè)備地址 03:設(shè)備地址 00 00:起始寄存器地址 00 02:從起始地址,讀取2個(gè)地址,讀取數(shù)據(jù)值。C4 0B: CRC校驗(yàn)
返回環(huán)境信息:01 03 04 00 B8 01 51 BA 7A
根據(jù)ModBus協(xié)議:01:設(shè)備地址 03:設(shè)備地址 04:數(shù)據(jù)長(zhǎng)度 00 B8:溫度值 01 51:濕度值
BA 7A:CRC校驗(yàn)
【實(shí)驗(yàn)代碼】
定義主從關(guān)系,默認(rèn)ModBusSlave = 1,此時(shí)程序?yàn)閺臋C(jī),和溫濕度傳感器是并聯(lián)。
COBOL Code
uint8_t ModBusSlave = 1;
uint8_t ModBusMaster = 0;
當(dāng)從機(jī)接收到命令時(shí),會(huì)有從機(jī)轉(zhuǎn)變?yōu)橹鳈C(jī),主動(dòng)采集溫濕度傳感器環(huán)境信息。并1S上報(bào)一次環(huán)境數(shù)據(jù)。
(1)接收到從機(jī)轉(zhuǎn)主機(jī)的命令(485發(fā)來的數(shù)據(jù)):
00 06 00 03 00 01 B9 DB
廣播地址 + 06 + 0003 + 00 01 + CRC校驗(yàn)
06表示ModBus 寫保持寄存器命令。
0003表示寫第幾個(gè)寄存器。
0001表示向寄存器中寫的內(nèi)容。為1有485網(wǎng)絡(luò)切換到ZigBee網(wǎng)絡(luò)(主機(jī)模式)
B9DB表示CRC校驗(yàn)
ZigBee協(xié)調(diào)器插到電腦上USB,通過串口調(diào)試助手打開ZigBee協(xié)調(diào)器的COM口(波特率115200),顯示接收到M0傳感器采集的數(shù)據(jù)。數(shù)據(jù)格式是21 5A 打頭數(shù)據(jù),含有設(shè)備地址、傳感器類型和數(shù)據(jù)。
M0上傳的協(xié)議數(shù)據(jù)如下:
uint8_t usSendBuf[SendLong] = {0x21,0x5A, SlaveID,0x00,0x74,0x00,0x00,0x00,0x00,0x00,0x00,0x6B};
第5、6、7位為數(shù)據(jù)位,其他的是固定寫法。
接收數(shù)據(jù)
數(shù)據(jù):215A0100740000000000006B
位號(hào):01234567891011
含義:標(biāo)記網(wǎng)絡(luò)從機(jī)ID保留類型采集的數(shù)據(jù)保留位
第0字節(jié)位是標(biāo)記位,用于判斷次數(shù)據(jù)包是否是合法的需要的數(shù)據(jù)包。
第1字節(jié)位是用于區(qū)分網(wǎng)絡(luò)類型的,分為二種網(wǎng)絡(luò):zigbee-5A,RS485-52。
第2字節(jié)表示的是節(jié)點(diǎn)的地址位(ID),1~255之間。
第4字節(jié)位是節(jié)點(diǎn)的類型,包括::溫濕度-74,土壤溫濕度-74,光感-6C,紅外-69,C02-63,加熱器-57,加濕器-48,通風(fēng)-46,照明-4C,噴濕-44,遮陽(yáng)-53,報(bào)警-41 等多種類型的傳感器。
(2)接收到主機(jī)轉(zhuǎn)從此機(jī)的命令(ZigBee發(fā)來的數(shù)據(jù)):
數(shù)據(jù):236352626F7901
位號(hào):0123456
含義:標(biāo)記標(biāo)記網(wǎng)絡(luò)預(yù)留預(yù)留預(yù)留
第0,1字節(jié)位是標(biāo)記位,用于判斷次數(shù)據(jù)包是否是合法的需要的數(shù)據(jù)包。
第0字節(jié)標(biāo)記位:0x23(#) 表示此數(shù)據(jù)為命令字段
第1字節(jié)標(biāo)記位:0x63(c) 表示此數(shù)據(jù)為網(wǎng)絡(luò)切換命令
第2字節(jié)位是網(wǎng)絡(luò)位:用于判斷要切換到那種網(wǎng)絡(luò)
0x5A(Z):zigbee網(wǎng)絡(luò)
0x52(R):rs485網(wǎng)絡(luò)
第3字節(jié)位:此系統(tǒng)預(yù)留--必須為0
第4,5字節(jié)位:此系統(tǒng)預(yù)留--必須為0
第6字節(jié)位:此系統(tǒng)預(yù)留--必須為0
主程序
int main(void)
{
uint8_t i;
uint8_t RxData;
uint8_t Senddata[13] ={0};
uint8_t sendflag = 0;
/*!< At this stage the microcontroller clock setting is already configured,
this is done through SystemInit() function which is called from startup
file (startup_stm32f0xx.s) before to branch to application main.
To reconfigure the default setting of SystemInit() function, refer to
system_stm32f0xx.c file
*/
/* SysTick end of count event each 10ms */
RCC_GetClocksFreq(&RCC_Clocks);
SysTick_Config(RCC_Clocks.HCLK_Frequency / 100);
/* Add your application code here
*/
LED_Init();
//初始化繼電器
Relay_Init(Relay1_PORT,Relay1_PIN);
Relay_Init(Relay2_PORT,Relay2_PIN);
Relay_Init(Relay485_PORT,Relay485_PIN);
Usart_Init(USART2,115200);
if(ModBusMaster)
Usart_Init(USART1,9600);
if(ModBusSlave)
{
//模式 從地址 端口 波特率 校驗(yàn)位
eMBInit(MB_RTU, MSlaveID, 0x01, 9600, MB_PAR_NONE);
//啟動(dòng)FreeModbus
eMBEnable();
}
QueueInit(&FIFO_485);
/* Infinite loop */
while (1)
{
if(ModBusMaster)
{
//向ZigBee發(fā)送接收到ModBus的數(shù)據(jù) ModBus ====》ZigBee
if(FIFO_485.count >= 1)
{
QueueOut(&FIFO_485,&RxData);
if(RxData == SlaveID)
{
Senddata[0] = RxData;
QueueOut(&FIFO_485,&RxData);
if(RxData == 0x03)
{
Senddata[1] = RxData;
for(i=2;i<12;i++)
{
QueueOut(&FIFO_485,&RxData);
Senddata[i] = RxData;
}
usSendBuf[5] = 0;
usSendBuf[6] = (Senddata[3] << 8) | (Senddata[4] /10);
usSendBuf[7] = (Senddata[5] << 8) | (Senddata[6] /10);
for(i=0;i < 12;i++)
{
USART_SendData(USART2, usSendBuf[i]);
/* Loop until the end of transmission */
while (USART_GetFlagStatus(USART2, USART_FLAG_TC) == RESET)
{}
}
}
}
}
if(FIFO_485.count == 0 )
{
Delay(150);
//發(fā)送ModBus命令,通過ZigBee上報(bào)給網(wǎng)關(guān)(不來)
ModBusSend(HUM1_buf);
}
//發(fā)送zigbee串口2接收到的ModBus命令---->請(qǐng)求傳感器命令
if(RxZigbeelen == RxZigbeelong)
{
//判斷接收zigbee的數(shù)據(jù),是否為485繼電器切換命令
if((Rx_Zigbee_buf[1] == 0x63) && (Rx_Zigbee_buf[2] == 0x52))
{
USART_Cmd(USART1, DISABLE);
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
//繼電器切換為常閉狀態(tài)
GPIO_ResetBits(Relay485_PORT, Relay485_PIN);
//清空zigbee接收緩沖區(qū)的數(shù)據(jù)
memset(Rx_Zigbee_buf,0,64);//sizeof(char)*RxModbuslen);
RxZigbeelen = 0;
ModBusSlave = 1;
ModBusMaster = 0;
if(ModBusSlave)
{
//模式 從地址 端口 波特率 校驗(yàn)位
eMBInit(MB_RTU, MSlaveID, 0x01, 9600, MB_PAR_NONE);
//啟動(dòng)FreeModbus
eMBEnable();
}
}//判斷是否為控制繼電器命令(開)
else if(Rx_Zigbee_buf[3] == 'Z'){
if(Rx_Zigbee_buf[4] == MSlaveID){ //判斷控制的地址
if(Rx_Zigbee_buf[6] == '1'){ //繼電器的開
//控制繼電器撥到常開 PB.8
GPIO_SetBits(Relay2_PORT,Relay2_PIN );
//清空zigbee接收緩沖區(qū)的數(shù)據(jù)
memset(Rx_Zigbee_buf,0,64);//sizeof(char)*RxModbuslen);
RxZigbeelen = 0;
}else if(Rx_Zigbee_buf[6] == '0'){
//控制繼電器撥到常開 PB.8
GPIO_ResetBits(Relay2_PORT,Relay2_PIN );
//清空zigbee接收緩沖區(qū)的數(shù)據(jù)
memset(Rx_Zigbee_buf,0,64);//sizeof(char)*RxModbuslen);
RxZigbeelen = 0;
}
}
}
}
else if(RxZigbeelen > RxZigbeelong)
{
memset(Rx_Zigbee_buf,0,64);//sizeof(char)*RxModbuslen);
RxZigbeelen = 0;
}
//如果485切換成功,則燈滅
if(Led_flag == 1)
{
LED2_OFF();//關(guān)閉led燈
Led_flag = 0;
}
}
if(ModBusSlave)
{
eMBPoll( );
//從機(jī)接收到數(shù)據(jù)判斷,可改變主從模式,下面關(guān)閉從模式
if((usRegHoldingBuf[3] & 0xFF) == 0x01)
{
USART_Cmd(USART1, DISABLE);
USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
//主從切換的繼電器切換到常開
GPIO_SetBits(Relay485_PORT,Relay485_PIN );
if(ModBusSlave)
{
eMBDisable();
ModBusSlave = 0;
ModBusMaster = 1;
if(ModBusMaster)
Usart_Init(USART1,9600);
Delay(5);
}
//清空
usRegHoldingBuf[3] &= ~(1 << 0);
}
if(Led_flag == 0)
{
LED2_ON();//開led燈
Led_flag = 1;
}
}
}
}