关键词:CubeMX,CubeIDE,STM32G031C8T6,AHT10,DRF1609H
本项目的全部源码资料下载
本项目中使用了Zigbee模块(DRF1609H),作为无线数据传输使用,初始化DRF1609H主要涉及以下几个方面的内容:
1,设置节点的类型,可以设置为:Router、End Device。Zigbee网络有3种类型的节点:Coordinator、Router、End Device,Cordinator接在电脑上面收集数据,我们这里是采集节点,所以只设置为Router或End Device。
2,检测节点是否加入了网络
3,如果节点没有加入网络,则启动自动扫描加入网络
首先读取DRF1609H的参数:G031向DRF1609H发送读取参数指令,发完参数后,有一个500MS的超时等待参数的回复,参数回复总共是53个字节,放在receiveConfigData里面。
//--Read DRF1609H Configures --
drf1609h_readModule();
HAL_UART_Receive( &huart1, receivedConfigData, 53, 500 );
//------------------------------
void drf1609h_readModule(void)
{
drf1609h_sendedIns = sendIns_read;
HAL_UART_Transmit_DMA( &huart1, readIns, 9 );
}
读取参数完成后,把读取到的参数整理后放入drf1609这个结构体中:以后取用的时候就非常方便了,建议用户不要改这部分代码,直接拷贝使用就好了。
//---If DRF1609H Error or Read Error ------
while( readParameterProcess(receivedConfigData, 53) == 0 )
{
drf1609h_readModule();
HAL_UART_Receive( &huart1, receivedConfigData, 53, 500 );
}
//------------------------------
uint8_t readParameterProcess(uint8_t *inputData, uint16_t inputLen)
{
uint8_t result=0;
uint8_t tempXY=0;
uint8_t tempRight=0;
uint8_t i=0;
tempXY = getXY(inputData, inputLen);
if(inputData[0]==0xFA) { tempRight++; }
if(inputData[1]==0x31) { tempRight++; }
if(inputData[2]==0x0A) { tempRight++; }
if(inputData[inputLen-1]==tempXY) { tempRight++; }
if(tempRight==4)
{
//------
drf1609.pointType = inputData[readHeaderLen +0];
drf1609.PAN_ID = inputData[readHeaderLen +1]*256 + inputData[readHeaderLen +2];
drf1609.Channel = inputData[readHeaderLen +3];
drf1609.transferModel = inputData[readHeaderLen +4];
drf1609.userAddress = inputData[readHeaderLen +5]*256 + inputData[readHeaderLen +6];
drf1609.X7X8 = inputData[readHeaderLen +7]*256 + inputData[readHeaderLen +8];
drf1609.uartBraudRate = inputData[readHeaderLen +9];
drf1609.uartDataBits = inputData[readHeaderLen +10];
drf1609.uartStopBits = inputData[readHeaderLen +11];
drf1609.uartParity = inputData[readHeaderLen +12];
drf1609.X13X14 = inputData[readHeaderLen +13]*256 + inputData[readHeaderLen +14];
drf1609.antennaSelect = inputData[readHeaderLen +15];
//-------
for(i=0; i<8; i++)
{
drf1609.macAddress[i] = inputData[readHeaderLen +16 +i];
}
//--------
drf1609.prePointType = inputData[readHeaderLen +24];
drf1609.prePAN_ID = inputData[readHeaderLen +25]*256 + inputData[readHeaderLen +26];
drf1609.preChannel = inputData[readHeaderLen +27];
drf1609.preTransferModel = inputData[readHeaderLen +28];
drf1609.preUserAddress = inputData[readHeaderLen +29]*256 + inputData[readHeaderLen +30];
drf1609.X31X32 = inputData[readHeaderLen +31]*256 + inputData[readHeaderLen +32];
drf1609.preUartBraudRate = inputData[readHeaderLen +33];
drf1609.preUartDataBits = inputData[readHeaderLen +34];
drf1609.preUartStopBits = inputData[readHeaderLen +35];
drf1609.preUartParity = inputData[readHeaderLen +36];
drf1609.X37X38 = inputData[readHeaderLen +37]*256 + inputData[readHeaderLen +38];
drf1609.preAntennaSelect = inputData[readHeaderLen +39];
//-----------
drf1609.shortAddress = inputData[readHeaderLen +40]*256 + inputData[readHeaderLen +41];
drf1609.X42 = inputData[readHeaderLen +42];
drf1609.isSecurity = inputData[readHeaderLen +43];
for(i=0; i<4; i++)
{
drf1609.securityCode[i] = inputData[readHeaderLen +44 +i];
}
result =1;
}
return result;
}
接着比较读出来的节点类型与要设置的节点类型是否一致,如果不一致的话,就重新写入要设置的节点类型:
if( drf1609H_setPontType != drf1609H_readPointType )
写的过程:
1,产生写入参数
2,写入
3,接收回复的参数,看看写入是否正确
getWriteIns(drf1609);
drf1609h_writeModule();
HAL_UART_Receive( &huart1, receivedConfigData, 5, 500 );
写入正确以后,则重启模块(注意:DRF1609H的写入参数生效,都需要重启),这里是用一个IO口,控制DRF1609H的RESET脚拉低重启。
if( is_InsBack(receivedConfigData, 5) )
{
if(receivedConfigData[2] == 0x0A)
{
drf1609h_reset();
HAL_Delay(2000);
drf1609h_status = drf1609h_powerOn;
}
else
{
errorStart=1;
}
}
else
{
errorStart=1;
}
需要注意的是,getWriteIns(drf1609),这个函数是把drf1609结构体,直接变换成写入指令,建议用户不要修改这部分,直接拷贝使用
//---------------------------------------------------
void getWriteIns(_zigbeeParameters inputParameter)
{
uint8_t i=0;
uint8_t tempXY=0;
writeIns[0]= 0xFC;
writeIns[1]= 0x27;
writeIns[2]= 0x07;
writeIns[writeHeaderLen +0]= inputParameter.pointType;
writeIns[writeHeaderLen +1]= (inputParameter.PAN_ID & 0xFF00)>>8;
writeIns[writeHeaderLen +2]= inputParameter.PAN_ID & 0x00FF;
writeIns[writeHeaderLen +3]= inputParameter.Channel;
writeIns[writeHeaderLen +4]= inputParameter.transferModel;
writeIns[writeHeaderLen +5]= (inputParameter.userAddress & 0xFF00)>>8;
writeIns[writeHeaderLen +6]= inputParameter.userAddress & 0x00FF;
writeIns[writeHeaderLen +7]= (inputParameter.X7X8 & 0xFF00)>>8;
writeIns[writeHeaderLen +8]= inputParameter.X7X8 & 0x00FF;
writeIns[writeHeaderLen +9]= inputParameter.uartBraudRate;
writeIns[writeHeaderLen +10]= inputParameter.uartDataBits;
writeIns[writeHeaderLen +11]= inputParameter.uartStopBits;
writeIns[writeHeaderLen +12]= inputParameter.uartParity;
writeIns[writeHeaderLen +13]= (inputParameter.X13X14 & 0xFF00)>>8;
writeIns[writeHeaderLen +14]= inputParameter.X13X14 & 0x00FF;
writeIns[writeHeaderLen +15]= inputParameter.antennaSelect;
writeIns[writeHeaderLen +16]= inputParameter.prePointType;
writeIns[writeHeaderLen +17]= (inputParameter.prePAN_ID & 0xFF00)>>8;
writeIns[writeHeaderLen +18]= inputParameter.prePAN_ID & 0x00FF;
writeIns[writeHeaderLen +19]= inputParameter.preChannel;
writeIns[writeHeaderLen +20]= inputParameter.preTransferModel;
writeIns[writeHeaderLen +21]= (inputParameter.preUserAddress & 0xFF00)>>8;
writeIns[writeHeaderLen +22]= inputParameter.preUserAddress & 0x00FF;
writeIns[writeHeaderLen +23]= (inputParameter.X31X32 & 0xFF00)>>8; //--AS ReadParameter's X31 X32
writeIns[writeHeaderLen +24]= inputParameter.X31X32 & 0x00FF; //--AS ReadParameter's X31 X32
writeIns[writeHeaderLen +25]= inputParameter.preUartBraudRate;
writeIns[writeHeaderLen +26]= inputParameter.preUartDataBits;
writeIns[writeHeaderLen +27]= inputParameter.preUartStopBits;
writeIns[writeHeaderLen +28]= inputParameter.preUartParity;
writeIns[writeHeaderLen +29]= (inputParameter.X37X38 & 0xFF00)>>8; //--AS ReadParameter's X37 X38
writeIns[writeHeaderLen +30]= inputParameter.X37X38 & 0x00FF; //--AS ReadParameter's X37 X38
writeIns[writeHeaderLen +31]= inputParameter.preAntennaSelect;
writeIns[writeHeaderLen +32]= 0x1;
writeIns[writeHeaderLen +33]= inputParameter.isSecurity;
for(i=0; i<4; i++)
{
writeIns[writeHeaderLen +34 +i]= inputParameter.securityCode[i];
}
tempXY = getXY(writeIns, writeInsLen);
writeIns[writeInsLen-1]= tempXY;
}
检测节点是否加入网络,我们这里使用了读取DRF1609H节点信号强度指令,如果读取信号强度成功(回复的数据是正确的),则表明DRF1609H已经加入了网络并且与Coordinator通讯正常。
这个函数用来检测DRF1609H是否加入了网络,加入则回复1,没有则回复0:
注意:这里是检测10次,没有加入也回复1,主要考虑在低功耗情况下,如果Coordinator没有开机,如果节点一直检测,则对耗电不利,用户应根据实际情况修改使用。
uint8_t drf1609h_isJoinedNet()
//----------------------
uint8_t drf1609h_isJoinedNet()
{
uint8_t result=0;
uint8_t i=0;
//MX_USART1_UART_Init();
//HAL_Delay(10);
for(i=0; i<8; i++)
{
receivedSignalData[i]=0;
}
drf1609h_requestSignalIndex();
HAL_UART_Receive( &huart1, receivedSignalData, 8, 500 );
HAL_Delay(1000);
if( checkSignalData(receivedSignalData, 8) )
{
result=1;
receivedSignalData[8] = drf1609.pointType;
HAL_UART_Transmit_DMA( &huart1, receivedSignalData, 9 );
}
else
{
haveTryToJoinTimers++;
if(haveTryToJoinTimers >= maxJoinTimers)
{
result=1;
}
else
{
result=0;
}
}
return result;
}
检测的过程:
1,发送读取信号强度指令
2,等待接收回复数据
3,如果接收回复数据成功(已经加入网络),这里将收到的数据加上自己的节点类型发送给Coordinator,通知节点已经加入成功
drf1609h_requestSignalIndex();
HAL_UART_Receive( &huart1, receivedSignalData, 8, 500 );
HAL_Delay(1000);
if( checkSignalData(receivedSignalData, 8) )
{
result=1;
receivedSignalData[8] = drf1609.pointType;
HAL_UART_Transmit_DMA( &huart1, receivedSignalData, 9 );
}
如果连按三次DRF1609H的Function按键,则开始自动扫描,如果扫描到Coordinator,则可以自动加入网络,并从Coordinator处获得“给Router预设的参数”,所以节点是不要设置的,我们节点的板子上也没有把DRF1609H的串口留出来,而是通过连按三次按键,自动加入网络,自动取得参数。
1,检测DRF1609H是否加入网络,用的是读取信号强度的指令
2,如果没有加入网络,则启动自动加入网络
3,启动后,等待12秒,再读取信号强度,判断是否加入了网络
注意,板子上有按键,如果是低功耗模式,建议不要启动这个功能,用按键手工加入网络,如果Coordinator没开机,一直扫描网络,会很快耗光电池。
//-- Do 5 timers get Signal Index ----//
for(i=0; i<5; i++)
{
drf1609h_requestSignalIndex();
HAL_UART_Receive( &huart1, receivedSignalData, 8, 500 );
HAL_Delay(500);
if( checkSignalData(receivedSignalData, 8) )
{
tempVal++;
i=5;
}
else
{
notGetSignalVal++;
}
}
drf1609h_autoJoinNet_Start();
HAL_Delay(12000);
进去自动加入网络的代码看看,其实就是模拟三次按键:
开始以后,DRF1609H上的2个灯会快闪,观察到一个灯灭,一个灯慢闪以后,说明已经加入网络。
//---------------------------------------
/* This Simulate Function Key to start
* point auto join net
* ____ ______ ______ ______
* |__| |__| |__|
*
* 120 200 120 200 120 200
*
* ----------------------------------*/
void drf1609h_autoJoinNet_Start()
{
uint8_t i=0;
set_autoJoinNetPin_output();
set_autoJoinNetPin_out_1();
HAL_Delay(100);
for(i=0; i<3; i++)
{
set_autoJoinNetPin_out_0();
HAL_Delay(120);
set_autoJoinNetPin_out_1();
HAL_Delay(200);
}
set_autoJoinNetPin_input();
}
主要有读取参数、读取信号强度、写入参数等指令,项目里面都已经列出来了
如果需要增加其它的功能,要参考DRF1609H的说明书
uint8_t linkIns[9] = {0xFC, 0x06, 0x04, 0x44, 0x54, 0x4B, 0x52, 0x46, 0x81}; //---INS01
uint8_t restartIns[9] = {0xFC, 0x06, 0x06, 0x44, 0x54, 0x4B, 0xAA, 0xBB, 0x50}; //---INS02
uint8_t readIns[9] = {0xFC, 0x06, 0x0E, 0x44, 0x54, 0x4B, 0x52, 0x46, 0x8B}; //---INS05
uint8_t writeIns[42]; //--INS06
uint8_t requestSignalIns[9] = {0xFC, 0x06, 0x0C, 0x44, 0x54, 0x4B, 0x52, 0x46, 0x89}; //--INS08