外贸营销型网站制作,网站建设翻译,优化wordpress访问,如何与网站管理员联系1 深入了解LoRaWan
1.1 LoRaWan概述 LoRaWAN采用星型无线拓扑 End Nodes 节点 Gateway 网关 Network Server 网络服务器 Application Server 应用服务器
LoRa联盟是2015年3月Semtech牵头成立的一个开放的、非盈利的组织#xff0c;发起成员还有法国Actility#xff0c;中国…1 深入了解LoRaWan
1.1 LoRaWan概述 LoRaWAN采用星型无线拓扑 End Nodes 节点 Gateway 网关 Network Server 网络服务器 Application Server 应用服务器
LoRa联盟是2015年3月Semtech牵头成立的一个开放的、非盈利的组织发起成员还有法国Actility中国AUGTEK和荷兰皇家电信kpn等企业。至2016年4月联盟已经发展成员公司290余家其中不乏IBM、思科、法国Orange等重量级产商
1.2 LoRaWan通信协议
128AES加密功能 节点与server之间的加密通信 HAL驱动SPI驱动物理层phy物理层通过lora或者fsk协议再与网关通信网关可以通过spi或usb与网关模块通信 网关也可以通过3Gwifi与我们网络服务器通讯 1.3 LoRaWAN与其他组网协议对比
zigbee属于mesh 1.4 LoRawan终端
1.4.1 LoRaWAN网关SX1301
拓扑图 大容量的网络规模高速度的通信机制 8通道Lora IF9 1个FSk IF8 1个网关间通信 非常适合做网关 200元左右需要Arm9高速处理器我们只需要了解我们学习节点 1.4.2 LoRaWAN终端Class A
LoRaWAN Server选择最佳Gateway下行通信都是通过LoRaServer选择 开启两个接收窗口平时处于休眠模式当他需要工作的时候才会去发送数据包功耗最低实时性不高比如1小时才能发送1次信息控制不太合适采集信息用classA最合适 1.4.3 LoRaWAN终端Class B
解决classA实时性不高当需要节点去响应实时性问题的时候首先网关会发送一个信标告诉节点要加快通讯快速工作节点收到信标之后会在128秒内去打开多个事件窗口每个窗口在3-160ms在128秒内可以实时对节点进行监控 1.4.4 LoRaWAN终端Class C
既保持实时性也保证了数据收发一直会打开接收窗口缺点能耗高 1.5 LoRawan服务器
1.5.1 LoRaWAN服务器框架
与ABCclass建立了Star通讯 网络服务器与网关建立通讯 控制网络服务器协议算法是通过控制服务器做得服务器如何决定通过那个网关进行通讯 应用服务器根据行业需求布置不同应用使用接口比较单一 客户服务器 二次开发人机交互等在此开发 1.5.2 不同server的通信 tcp udp 客户服务网、应用服务器、网络服务器、控制服务器都是通过TCP进行通讯可靠性 网关、节点和网络服务器是通过UDP保证实时性 1.5.3 LoRaWAN服务器通信协议
TCP、UDP、网关通过JSON字符串进行交互的 思考 如何设计Class C终端进行私有组网
1.只能联网内才开发loraWan 2.loraWan网关成本高 3.要具备Sever开发能力 2 LoRa自组网络架构设计
2.1 MAC协议的重要性 类似交通信号灯无线信道只有1个不设计会产生冲突 解决信号冲突的问题 尽可能地节省电能 保证通信的健壮和稳定性
2.2 MAC协议种类 设计要基于3种协议
2.3 时分复用
用时间片的思想多任务。在一定的事件内去分配时间槽每个时间槽分给一个节点使节点在这个时间槽里通信如果不在这个时间槽是不能通信的。和电脑CPU的时间片是一个道理 时分多路复用是将时间划分为一段段等长的时分复用帧TDM帧每个用户在每个TDM帧中占用固定序号的时隙。 每个用户所占用的时隙是周期性出现其周期就是TDM帧的长度。 时分复用的所有用户是在不同的时间占用相同的频带宽度。
2.4 频分复用
1301 芯片 频分多路复用的个用户占用不同的带宽资源这里的“带宽”是频率带宽单位Hz而不是数据的发送速率。 用户在分配到一定的频带后在通信过程中自始至终都占用这个频道。 应用有线电视网络。
2.5 码分复用
CPU是多核多任务同时进行不同频率的通信可以同时进行 SF扩频SF不同进行不同的通信
LoRa 中的码分复用通过以下方式实现 唯一的扩频因子Spreading Factor 在 LoRa 中每个终端设备使用唯一的扩频因子这个扩频因子决定了数据信号的频带扩展程度。不同的扩频因子对应着不同的码片序列。每个终端设备在发送数据时使用其唯一的扩频因子进行调制因此即使在相同的频率上不同的终端设备也可以同时发送数据而不会相互干扰。 自适应数据速率Adaptive Data RateADR LoRa 网络可以根据终端设备的距离和环境条件动态调整扩频因子和发送功率以最大程度地提高通信的可靠性和覆盖范围。 碰撞避免技术 LoRa 中还采用了碰撞避免技术通过随机选取发送时间和采用随机退避算法来减少终端设备之间的碰撞进一步提高了网络的性能。
总的来说LoRa 中的码分复用技术使得多个终端设备可以在同一时间和频率上进行通信从而实现了低功耗、远距离和大规模连接的物联网应用场景。
2.6 轮询访问 modbus只有一个主机节点可以是1-247只允许主机发送从机应答。实时性差
2.7 我们的设计 时间 随机访问竞争入网 信号协调器 节点1 发送收到 节点2 先判断网络是否冲突再延时发送 接收 节点3 先判断网络是否冲突再延时发送 接收 时间槽分配、或者时间片在规定时间内进行收发rx、tx从而实现整个网络的通信 同时设置冗余、revered slot和空闲任务used idle
2.7.1 LoRa自组网协调器设计 串口我们需要牧场监控内的信息控制器要与协调器进行数据通信 无线数据入网没完成等待是否有新节点加入断电是否有旧节点加入 解决时钟飘移缺点时钟同步 2.7.2 LoRa自组网节点设计 思考 基于时分复用MAC协议如何开发协调器与节点程序
3 LoRa自组网集中器程序开发网关 3.1 制定通信协议
入网请求
从机-入网请求名称字节数描述举例帧头10x3C0x3C长度1最长126字节长度范围内不检测包头计算整个帧长度0x0c网络类型1字符J代表入网请求J网络标识符2PANID用于网络区分只有PANID一样才可以组网通信0x0102设备地址2设备唯一地址标识0x1235CRC8校验1数据包校验整个数据包除校验位0x08主机-入网应答名称字节数描述举例帧头10x3C0x3C长度1最长126字节长度范围内不检测包头计算整个帧长度0x0c网络类型1字符A代表入网成功A网络标识符2PANID用于网络区分只有PANID一样才可以组网通信0x0102设备地址2设备唯一地址标识0x1235设备序号1设备是第几个入网1CRC8校验1数据包校验整个数据包除校验位0x08 设备标识符 PANID和zigbee组网一样相同才能在一个网通信
时间同步 设备序号第几个入网的同时给节点分时间片
网络数据包 网络数据包名称字节数描述举例帧头1字符N代表网络数据包N网络标识符2PANID用于网络区分只有PANID一样才可以组网通信0x0102数据包包头10x210x21包长1数据包长度代表数据域数据长度1数据类型10x00数据、0x01命令0x00设备地址2设备标识符0x0001传感器类型10x01温湿度、0x02三轴、0x03风机、0x04水表、0x05地磁 0x06灌溉0x01数据4每种传感器数值用一个字节标识比如温湿度占两个字节0x01298113CRC8校验1数据包校验整个数据包除校验位0x08
3.2 工程模板修改 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_7|GPIO_PIN_15, GPIO_PIN_SET);
3.2.1 Cubmx RTC外设配置
修改RTC时钟源为外部高速时钟 配置RTC分频系数 初始化日期和时间 配置Alarm参数 使能RTC全局中断 1s为单位.rtc时钟为250hz 3.2.2 Cubmx 定时器外设配置
配置TIM2分频系数 使能TIM2定时器中断 1s为单位 3.2.3 Cubmx 串口和ADC外设配置 把main函数的功能移到task文件夹下数据解析、网络解析、协议等 如果是从机增加一个ADC用于生成随机数 配置ADC为连续采集 配置DMA通道 配置ADC标签 3.2.4 RTC任务
主要任务RTC 提供实时时钟,用于时钟同步开启闹钟中断
sTime的初值和sAlarm的初值都为0
void MX_RTC_Init(void)
{RTC_TimeTypeDef sTime;RTC_DateTypeDef sDate;RTC_AlarmTypeDef sAlarm;/**Initialize RTC Only */hrtc.Instance RTC;hrtc.Init.HourFormat RTC_HOURFORMAT_24;hrtc.Init.AsynchPrediv 125-1;hrtc.Init.SynchPrediv 2000-1;hrtc.Init.OutPut RTC_OUTPUT_DISABLE;hrtc.Init.OutPutPolarity RTC_OUTPUT_POLARITY_HIGH;hrtc.Init.OutPutType RTC_OUTPUT_TYPE_OPENDRAIN;if (HAL_RTC_Init(hrtc) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}/**Initialize RTC and set the Time and Date */sTime.Hours startUpDateHours; // --------sTime.Minutes startUpDateMinute; // --------sTime.Seconds startUpDateSeconds; // --------sTime.DayLightSaving RTC_DAYLIGHTSAVING_NONE;sTime.StoreOperation RTC_STOREOPERATION_RESET;if (HAL_RTC_SetTime(hrtc, sTime, RTC_FORMAT_BCD) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}sDate.WeekDay RTC_WEEKDAY_MONDAY;sDate.Month RTC_MONTH_APRIL;sDate.Date 0x1;sDate.Year 0x18;if (HAL_RTC_SetDate(hrtc, sDate, RTC_FORMAT_BCD) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}if(HAL_RTCEx_BKUPRead(hrtc, RTC_BKP_DR0) ! 0x32F2){HAL_RTCEx_BKUPWrite(hrtc,RTC_BKP_DR0,0x32F2);}/**Enable the Alarm A */sAlarm.AlarmTime.Hours DataUpTimeHours; // --------sAlarm.AlarmTime.Minutes DataUpTimeMinute; // --------sAlarm.AlarmTime.Seconds DataUpTimeSeconds; // --------sAlarm.AlarmTime.SubSeconds DataUpTimeSubSeconds; // --------sAlarm.AlarmTime.DayLightSaving RTC_DAYLIGHTSAVING_NONE;sAlarm.AlarmTime.StoreOperation RTC_STOREOPERATION_RESET;sAlarm.AlarmMask RTC_ALARMMASK_DATEWEEKDAY;sAlarm.AlarmSubSecondMask RTC_ALARMSUBSECONDMASK_ALL;sAlarm.AlarmDateWeekDaySel RTC_ALARMDATEWEEKDAYSEL_DATE;sAlarm.AlarmDateWeekDay 0x1;sAlarm.Alarm RTC_ALARM_A;memcpy(gAlarm, sAlarm, sizeof(sAlarm));if (HAL_RTC_SetAlarm_IT(hrtc, sAlarm, RTC_FORMAT_BIN) ! HAL_OK) //设置闹钟中断{_Error_Handler(__FILE__, __LINE__);}}
闹钟事件回调函数触发事件用于处理任务 协调器(主机 同步时钟标志因为每加入的设备都需要同步时钟 获取时间设置下次闹钟时间5小时节点从机 发送更新数据标志 闹钟发送数据的时间赋值使能闹钟中断
毫秒单位转换为时分秒
//**********************************//
//函数名称HAL_RTC_AlarmAEventCallback
//函数描述 闹钟事件回调函数
//函数参数 RTC_HandleTypeDef *hrtc
//返回值 无
//*******************************//void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc)
{RTC_TimeTypeDef masterTime;RTC_TimeTypeDef SlaveTime;RTC_DateTypeDef masterDate;#if MASTER //置位同步时钟标志SendClockFlag 0;//获取下次闹钟时间HAL_RTC_GetTime(hrtc, masterTime, RTC_FORMAT_BIN);HAL_RTC_GetDate(hrtc, masterDate, RTC_FORMAT_BIN);gAlarm.AlarmTime.Hours masterTime.Hours CLOCKHOURS; //5hourgAlarm.AlarmTime.Minutes masterTime.Minutes;gAlarm.AlarmTime.Seconds masterTime.Seconds;gAlarm.AlarmTime.SubSeconds masterTime.SubSeconds;#else //SLAVERsendUpDataFlag 1;HAL_RTC_GetTime(hrtc, SlaveTime, RTC_FORMAT_BIN);HAL_RTC_GetDate(hrtc, masterDate, RTC_FORMAT_BIN);gAlarm.AlarmTime.Hours SlaveTime.Hours DataUpTimeHours; gAlarm.AlarmTime.Minutes SlaveTime.Minutes DataUpTimeMinute;gAlarm.AlarmTime.Seconds SlaveTime.Seconds DataUpTimeSeconds;gAlarm.AlarmTime.SubSeconds SlaveTime.SubSeconds DataUpTimeSubSeconds;
#endifif (gAlarm.AlarmTime.Seconds 59){gAlarm.AlarmTime.Seconds - 60;gAlarm.AlarmTime.Minutes 1;}if ( gAlarm.AlarmTime.Minutes 59){gAlarm.AlarmTime.Minutes - 60;gAlarm.AlarmTime.Hours 1;}if (gAlarm.AlarmTime.Hours 23){gAlarm.AlarmTime.Hours - 24;}printf(RTC\n);//使能闹钟中断if (HAL_RTC_SetAlarm_IT(hrtc, gAlarm, RTC_FORMAT_BIN) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}
} 时分秒转换函数
//**********************************//
//函数名称 GetTimeHMS
//函数描述 时分秒转换
//函数参数 uint32_t timeData,uint8_t *hours,uint8_t *minute,uint8_t *seconds,uint32_t *subSeconds
//返回值 无
//*******************************//void GetTimeHMS(uint32_t timeData,uint8_t *hours,uint8_t *minute,uint8_t *seconds,uint32_t *subSeconds)
{/* 获得亚秒 */*subSeconds timeData % 1000;/* 获得秒钟*/timeData timeData / 1000;*seconds timeData % 60;/* 获得分钟*/timeData timeData / 60;*minute timeData % 60;/* 获得小时 */*hours timeData / 60;
}3.2.5 定时器任务
定时器 用来节点超时的判断
定时器初始化
开启定时器中断
void MX_TIM2_Init(void)
{TIM_ClockConfigTypeDef sClockSourceConfig;TIM_MasterConfigTypeDef sMasterConfig;htim2.Instance TIM2;htim2.Init.Prescaler 480-1;htim2.Init.CounterMode TIM_COUNTERMODE_UP;htim2.Init.Period 100*1000-1;htim2.Init.ClockDivision TIM_CLOCKDIVISION_DIV1;htim2.Init.AutoReloadPreload TIM_AUTORELOAD_PRELOAD_DISABLE;if (HAL_TIM_Base_Init(htim2) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}sClockSourceConfig.ClockSource TIM_CLOCKSOURCE_INTERNAL;if (HAL_TIM_ConfigClockSource(htim2, sClockSourceConfig) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}sMasterConfig.MasterOutputTrigger TIM_TRGO_RESET;sMasterConfig.MasterSlaveMode TIM_MASTERSLAVEMODE_DISABLE;if (HAL_TIMEx_MasterConfigSynchronization(htim2, sMasterConfig) ! HAL_OK){_Error_Handler(__FILE__, __LINE__);}} 定时器定时事件任务 定时器中断溢出要在里面做一些处理判断节点是否入网超时 //**********************************//
//函数名称 HAL_TIM_PeriodElapsedCallback
//函数描述 定时器2溢出中断回调函数
//函数参数 TIM_HandleTypeDef *htim
//返回值 无
//*******************************//void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//判断是否为定时器2中断
//累加全局计数值if(htim-Instance htim2.Instance){JionNodeTimeCount;}
}
3.2.5 CRC校验码及通信协议宏定义 protocol.c 1生成crc8校验码 2判断crc8校验码是否正确
#include protocol.h/******************************************************************************
* Name: CRC-8 x8x2x1
* Poly: 0x07
* Init: 0x00
* Refin: False
* Refout: False
* Xorout: 0x00
* Note:
*****************************************************************************/
uint8_t crc8(uint8_t *data, uint8_t length)
{uint8_t i;uint8_t crc 0; // Initial valuewhile(length--){crc ^ *data; // crc ^ *data; data;for ( i 0; i 8; i ){if ( crc 0x80 )crc (crc 1) ^ 0x07;elsecrc 1;}}return crc;
}//**********************************//
//函数名称 DataCrcVerify
//函数描述 CRC8校验
//函数参数 uint8_t * buff, uint8_t len
//返回值 uint8_t
//*******************************//uint8_t DataCrcVerify(uint8_t * buff, uint8_t len)
{uint8_t Crc8Data 0;//验证数据是否正确 Crc8Data crc8(buff, len - 1);if (Crc8Data buff[len - 1]){
// PRINTF1(CRC8 Success!\n);return 1;}else{
// PRINTF1(CRC8 Failed!\n);return 0;}
}
#ifndef _PROTOCOL_H
#define _PROTOCOL_H#include stm32f0xx.h#define JIONREQUEST 0x3C
#define NETDATA N
#define DATAHEAD 0x21
#define PAN_ID 0x1010#ifdef MASTER
#define ADDR 0xFFFF
#else
#define ADDR 0x1201 //0x1202 0x1203 ...
#endif#define HI_UINT16(a) (((a) 8) 0xFF)
#define LO_UINT16(a) ((a) 0xFF)uint8_t DataCrcVerify(uint8_t * buff, uint8_t len);
uint8_t crc8(uint8_t *data, uint8_t length);#endif3.2.6 数据处理任务
dataprocess.c
主机 从机 3.2.6.1 串口数据获取并无线发出去
//**********************************//
//函数名称UartDmaGet
//函数描述串口数据获取
//函数参数 无
//返回值 无
//*******************************//void UartDmaGet(void)
{if(UsartType1.receive_flag 1)//如果过新的数据,在串口中断回调函数中实现{//串口接收到的数据原封发给SX1278Radio-SetTxPacket(UsartType1.usartDMA_rxBuf, UsartType1.Usart_rx_len);memset(UsartType1.usartDMA_rxBuf,0,UsartType1.Usart_rx_len);UsartType1.receive_flag 0; //接收数据标志清零}
}
接收数据包计数、发送数据包计数
//**********************************//
//函数名称 RxDataPacketNum
//函数描述 接收数据包计数
//函数参数 无
//返回值 无
//*******************************//
void RxDataPacketNum(void)
{if(EnableMaster true)Master_RxNumber;elseSlave_RxNumber;
}//**********************************//
//函数名称 TxDataPacketNum
//函数描述 发送数据包计数
//函数参数 无
//返回值 无
//*******************************//
void TxDataPacketNum(void)
{if(EnableMaster true)Master_TxNumber;elseSlave_TxNumber;
}
3.2.6.2 读取无线射频数据
//**********************************//
//函数名称 Sx127xDataGet
//函数描述 读取sx127x射频射频数据
//函数参数 无
//返回值 无
//*******************************//uint8_t Sx127xDataGet(void)
{uint8_t status 0;switch( Radio-Process( ) ){case RF_RX_TIMEOUT: //超时printf(RF_RX_TIMEOUT\n);break;case RF_RX_DONE: //接收完成 主机和从机完成解析Radio-GetRxPacket( Buffer, ( uint16_t* )BufferSize );if(EnableMaster true)printf(master Rx Len %d\n,BufferSize);elseprintf(slave Rx Len %d\n,BufferSize); if( BufferSize 0 )// (BufferSize strlen((char*)Buffer))){//接收数据闪烁LedBlink( LED_RX );//计算接收数据的个数RxDataPacketNum();//清空sx127x接收缓冲区
#ifdef MASTERstatus MasterProtocolAnalysis(Buffer,BufferSize); //主机协议解析
#else status SlaveProtocolAnalysis(Buffer, BufferSize); //从机协议解析
#endifmemset(Buffer,0,BufferSize);} break;case RF_TX_DONE: //发送完成更新发送标志位//发送闪烁LedBlink( LED_TX );//计算发送数据的个数TxDataPacketNum();Radio-StartRx( );SendDataOkFlag 1;break;case RF_TX_TIMEOUT: //发送超时printf(RF_TX_TIMEOUT\n);break; default:break;}return status;
}
根据radio.h process的不同枚举类型进行业务处理
typedef enum
{RF_IDLE, //空闲RF_BUSY,RF_RX_DONE,RF_RX_TIMEOUT, RF_TX_DONE,RF_TX_TIMEOUT,RF_LEN_ERROR,RF_CHANNEL_EMPTY,RF_CHANNEL_ACTIVITY_DETECTED,
}tRFProcessReturnCodes;
3.2.6.3 主机协议解析
//**********************************//
//函数名称 MasterProtocolAnalysis
//函数描述 主机协议解析
//函数参数 uint8_t *buff,uint8_t len
//返回值 uint8_t
//*******************************//uint8_t MasterProtocolAnalysis(uint8_t *buff,uint8_t len)
{uint8_t Crc8Data,deviceID;uint8_t SendAck[12];printf(MasterProtocolAnalysis\n);for (int i 0; i len; i){printf(0x%x ,buff[i]);}printf(\n);if(buff[0] NETDATA) //N{if((buff[1] HI_UINT16(PAN_ID))(buff[2] LO_UINT16(PAN_ID))) // 0x10 0x10{Crc8Data crc8(buff[0], len - 1); //减去校验if(Crc8Data ! buff[len - 1]){memset(buff,0,len);//清空缓存区return 0;}if(buff[3] DATAHEAD) //0x21{NetDataProtocolAnalysis(buff[3], len - 3); //网络数据包解析}}elsereturn 0;}else if(buff[0] JIONREQUEST) //0x3C{deviceID JionNetProtocolAnalysis(buff, len); //入网协议解析printf(deviceID %d\n,deviceID);if(deviceID 0){SendAck[0] JIONREQUEST;SendAck[1] 1;SendAck[2] A;SendAck[3] HI_UINT16(PAN_ID);SendAck[4] LO_UINT16(PAN_ID);SendAck[5] slaveNetInfo_t[deviceID].deviceAddr[0];SendAck[6] slaveNetInfo_t[deviceID].deviceAddr[1];SendAck[7] deviceID;SendAck[8] crc8(SendAck, 8);Radio-SetTxPacket(SendAck, 9); //发送网络数据包printf(MasterAck\n);for (int i 0; i 9; i){printf(0x%x ,SendAck[i]);}printf(\n);}}return 1;
}
入网协议解析新设备添加入网表
/************************************************************************/
/* 入网协议分析状态 */
/************************************************************************/
typedef enum
{JION_HEADER 0,JION_LENGHT,JION_TYPE,JION_PANID,JION_ADDR,JION_CRC
}JionProtocol//**********************************//
//函数名称 JionNetProtocolAnalysis
//函数描述 入网协议解析
//函数参数 uint8_t *buff,uint8_t len
//返回值 uint8_t
//*******************************//
uint8_t JionNetProtocolAnalysis(uint8_t *buff,uint8_t len)
{uint8_t i 0, dataLen 0;uint8_t status 0, lenOld len;printf(JionNetProtocolAnalysis\n);for (int i 0; i len; i){printf(0x%x ,buff[i]);}printf(\n);while(len--){switch(status){case JION_HEADER: //0if (buff[status] JIONREQUEST) //0x3C{status JION_LENGHT; } else{goto ERR;}break;case JION_LENGHT: //1if(buff[status] 0x06) //6个字节{status JION_TYPE; } else{goto ERR;}break;case JION_TYPE:if (buff[status] J) //J代表入网请求{status JION_PANID;} else{goto ERR;}break;case JION_PANID: //网络标识符if (buff[status] HI_UINT16(PAN_ID) buff[status 1] LO_UINT16(PAN_ID)){status JION_ADDR;} else{goto ERR;}break;case JION_ADDR: //旧节点加入for (i 0; i currentDeviceNumber; i){if ((slaveNetInfo_t[i].deviceAddr[0] buff[status 1]) (slaveNetInfo_t[i].deviceAddr[1] buff[status 2])){slaveNetInfo_t[i].deviceNetStatus AGAIN_JION_NET;status JION_CRC; printf(AGAIN_JION_NET i %d\n,i);printf(deviceId%x\n,slaveNetInfo_t[i].deviceId);printf(deviceAddr[0]%x\n,slaveNetInfo_t[i].deviceAddr[0]);printf(deviceAddr[1]%x\n,slaveNetInfo_t[i].deviceAddr[1]);break;} }//新节点加入if(i currentDeviceNumber){currentDeviceNumber;//新增加入节点slaveNetInfo_t[i].deviceId i;slaveNetInfo_t[i].deviceAddr[0] buff[status 1];slaveNetInfo_t[i].deviceAddr[1] buff[status 2];status JION_CRC;printf(CURRENT_JION_NET i %d\n,i);printf(deviceId%x\n,slaveNetInfo_t[i].deviceId);printf(deviceAddr[0]%x\n,slaveNetInfo_t[i].deviceAddr[0]);printf(deviceAddr[1]%x\n,slaveNetInfo_t[i].deviceAddr[1]);}break;case JION_CRC://更新节点入网状态if (slaveNetInfo_t[i].deviceNetStatus ! AGAIN_JION_NET) {slaveNetInfo_t[i].deviceNetStatus JIONDONE;status JION_HEADER; //0printf(JIONDONE i %d\n,i);printf(deviceId%x\n,slaveNetInfo_t[i].deviceId);printf(deviceAddr[0]%x\n,slaveNetInfo_t[i].deviceAddr[0]);printf(deviceAddr[1]%x\n,slaveNetInfo_t[i].deviceAddr[1]);}break;default:break;}}return i;
}
网络数据包解析
//**********************************//
//函数名称 NetDataProtocolAnalysis
//函数描述 网络数据包解析
//函数参数 uint8_t *buff,uint8_t len
//返回值 无
//*******************************//void NetDataProtocolAnalysis(uint8_t *buff,uint8_t len)
{printf(NetDataProtocolAnalysis\n);for (int i 0; i len; i){printf(0x%x ,buff[i]);}printf(\n);
}
3.2.6.4 从机协议解析
//**********************************//
//函数名称 SendJionNetPacke
//函数描述 从机入网数据发送
//函数参数 无
//返回值 无
//*******************************//void SendJionNetPacke(void)
{uint16_t addr ADDR; //0xFFFF 主机地址jionPacke_t.msgHead 0x3C;jionPacke_t.dataLength 0x06;jionPacke_t.netType J;jionPacke_t.netPanid[0] HI_UINT16(PAN_ID);jionPacke_t.netPanid[1] LO_UINT16(PAN_ID);jionPacke_t.deviceAddr[0] HI_UINT16(ADDR);jionPacke_t.deviceAddr[1] LO_UINT16(ADDR);//校验码jionPacke_t.crcCheck crc8((uint8_t *)jionPacke_t,jionPacke_t.dataLength 1);printf(SendJionNetPacke addr %d\n,addr);//发送数据包Radio-SetTxPacket((uint8_t *)jionPacke_t, jionPacke_t.dataLength 2);}
从机协议解析
//**********************************//
//函数名称 SlaveProtocolAnalysis
//函数描述 从机协议解析
//函数参数 uint8_t *buff,uint8_t len
//返回值 uint8_t
//*******************************//uint8_t SlaveProtocolAnalysis(uint8_t *buff,uint8_t len)
{uint8_t Crc8Data;printf(SlaveProtocolAnalysis\n);for (int i 0; i len; i){printf(0x%x ,buff[i]);}printf(\n);if (buff[0] NETDATA) //N 网络数据包{if (buff[1] HI_UINT16(PAN_ID) buff[2] LO_UINT16(PAN_ID)){Crc8Data crc8(buff[0], len - 1);if (Crc8Data ! buff[len - 1]){memset(buff, 0, len);return 0;}if (buff[3] 0x21) //DATAHEAD{printf(Slave_NETDATA\n);if(buff[5] 0x1) //0x01 命令 0x00数据{if (buff[6] HI_UINT16(ADDR) buff[7] LO_UINT16(ADDR)){if(buff[8] 0x3) //传感器类型{
#if defined(FAN) if(buff[9] true){FanOn();}else{FanOff(); }
#endif}}}}return 0;} }else if((buff[0] 0x3C) (buff[2] A)) //主机应答{if (DataCrcVerify(buff, len) 0){return 0;}if (buff[3] HI_UINT16(PAN_ID) buff[4] LO_UINT16(PAN_ID)){if (buff[5] jionPacke_t.deviceAddr[0] buff[6] jionPacke_t.deviceAddr[1]){slaveNativeInfo_t.deviceId buff[7];printf(Slave_ACK\n);return 0xFF;}}}else if((buff[0] 0x3C) (buff[2] T)) //与主机事件同步{if (DataCrcVerify(buff, len) 0){return 0;}if (buff[3] HI_UINT16(PAN_ID) buff[4] LO_UINT16(PAN_ID)){uint32_t alarmTime 0;startUpTimeHours buff[5];startUpTimeMinute buff[6];startUpTimeSeconds buff[7];startUpTimeSubSeconds buff[8] 8 | buff[9];printf(Slave_CLOCK\n);printf(H:%d,M:%d,S:%d,SUB:%d\n, startUpTimeHours, startUpTimeMinute, startUpTimeSeconds, startUpTimeSubSeconds);alarmTime ((DataUpTimeHours * 60 DataUpTimeMinute) * 60 DataUpTimeSeconds) * 1000 (DataUpTimeSubSeconds / 2) DataUpTime;GetTimeHMS(alarmTime, DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);printf(DataUpTime-H:%d,M:%d,S:%d,SUB:%d\n, DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);//使能RTCMX_RTC_Init(); //RTC同步return 0xFF;}}return 1;
}
3.2.6.5 从机数据上传
//**********************************//
//函数名称 SendSensorDataUP
//函数描述 上传节点传感器数据
//函数参数 无
//返回值 无
//*******************************//void SendSensorDataUP(void)
{printf(SendSensorDataUP\n);
#if defined(MPU6050)mpu6050_ReadData(Mx,My,Mz); printf(Mx %.3f\n,Mx);printf(My %3f\n,My);printf(Mz %3f\n,Mz);DataPacke_t.netmsgHead N;DataPacke_t.netPanid[0] HI_UINT16(PAN_ID);DataPacke_t.netPanid[1] LO_UINT16(PAN_ID);DataPacke_t.msgHead 0x21;DataPacke_t.dataLength 0x08;DataPacke_t.dataType 0;DataPacke_t.deviceAddr[0] HI_UINT16(ADDR);DataPacke_t.deviceAddr[1] LO_UINT16(ADDR);DataPacke_t.sensorType 0x2;DataPacke_t.buff[0] (int8_t)(Mx*10);DataPacke_t.buff[1] (int8_t)(My*10);DataPacke_t.buff[2] (int8_t)(Mz*10);//校验码DataPacke_t.crcCheck crc8((uint8_t *)DataPacke_t,DataPacke_t.dataLength 4);//发送数据包Radio-SetTxPacket((uint8_t *)DataPacke_t, DataPacke_t.dataLength 5);
#elif defined(DHT11) DHT11_TEST();printf(TEMP %d\n,ucharT_data_H);printf(HUM %d\n,ucharRH_data_H);DataPacke_t.netmsgHead N;DataPacke_t.netPanid[0] HI_UINT16(PAN_ID);DataPacke_t.netPanid[1] LO_UINT16(PAN_ID);DataPacke_t.msgHead 0x21;DataPacke_t.dataLength 0x07;DataPacke_t.dataType 0;DataPacke_t.deviceAddr[0] HI_UINT16(ADDR);DataPacke_t.deviceAddr[1] LO_UINT16(ADDR);DataPacke_t.sensorType 0x1;DataPacke_t.buff[0] ucharT_data_H;DataPacke_t.buff[1] ucharRH_data_H;//校验码DataPacke_t.crcCheck crc8((uint8_t *)DataPacke_t,DataPacke_t.dataLength 4);//发送数据包Radio-SetTxPacket((uint8_t *)DataPacke_t, DataPacke_t.dataLength 5);#elif defined(FAN)FanStaus FanReadStaus();DataPacke_t.netmsgHead N;DataPacke_t.netPanid[0] HI_UINT16(PAN_ID);DataPacke_t.netPanid[1] LO_UINT16(PAN_ID);DataPacke_t.msgHead 0x21;DataPacke_t.dataLength 0x06;DataPacke_t.dataType 0;DataPacke_t.deviceAddr[0] HI_UINT16(ADDR);DataPacke_t.deviceAddr[1] LO_UINT16(ADDR);DataPacke_t.sensorType 0x3;DataPacke_t.buff[0] FanStaus;//校验码DataPacke_t.crcCheck crc8((uint8_t *)DataPacke_t,DataPacke_t.dataLength 4);//发送数据包Radio-SetTxPacket((uint8_t *)DataPacke_t, DataPacke_t.dataLength 5);#endif }
3.2.7 网络处理任务
netprocess.c
主机 从机 netprocess.h
#ifndef _NETPROCESS_H
#define _NETPROCESS_H#include stm32f0xx.h
#include stdbool.h#define NodeNumber 20extern volatile uint16_t currentDeviceNumber; //当前设备数量
extern volatile uint16_t oldNodeNumber;
extern volatile uint32_t DataUpTime;extern uint8_t startUpTimeHours; //启动时间
extern uint8_t startUpTimeMinute;
extern uint8_t startUpTimeSeconds;
extern uint32_t startUpTimeSubSeconds;extern uint8_t DataUpTimeHours; //更新时间
extern uint8_t DataUpTimeMinute;
extern uint8_t DataUpTimeSeconds;
extern uint32_t DataUpTimeSubSeconds;
/************************************************************************/
/* 定义设备入网时的状态 */
/************************************************************************/
typedef enum
{NO_JION 0, //未加入网络JIONING, //正在加入网络JIONTIMEOUT, //入网超时JIONDONE, //入网完成AGAIN_JION_NET
}DeviceJionStatus;/************************************************************************/
/* 入网协议分析状态 */
/************************************************************************/
typedef enum
{JION_HEADER 0,JION_LENGHT,JION_TYPE,JION_PANID,JION_ADDR,JION_CRC
}JionProtocol;/************************************************************************/
/* 定义设备节点加入标志 */
/************************************************************************/
typedef enum
{No_Node_Jion_Flag 0,Node_Jion_Finish_Flag,Node_Jion_No_Finish_Flag,New_Node_Jion_Flag
}DeviceJionFlag;/************************************************************************/
/* 设备入网发送的消息体 */
/************************************************************************/
typedef struct
{uint8_t msgHead; //入网消息头0x3Cuint8_t dataLength; //数据长度 type~crcuint8_t netType; //模块的网络类型uint8_t netPanid[2]; //设备的PANIDuint8_t deviceAddr[2]; //模块的设备地址uint8_t crcCheck; //数据校验整个数据包除校验位
}SlaveJionNet;/************************************************************************/
/* 设备数据发送的消息体 */
/************************************************************************/
typedef struct
{uint8_t netmsgHead; //入网消息头0x3Cuint8_t netPanid[2]; //设备的PANIDuint8_t msgHead; //数据消息头0x21uint8_t dataLength; //数据长度 type~crcuint8_t dataType; //模块的数据类型uint8_t deviceAddr[2]; //模块的设备地址uint8_t sensorType; //模块的传感器类型uint8_t buff[4]; //每种传感器数值用两个字节标识比如温湿度占四个字节uint8_t crcCheck; //数据校验整个数据包除校验位
}SlaveDataNet;/************************************************************************/
/* 更新RTC发送的消息体 */
/************************************************************************/
typedef struct
{uint8_t msgHead; //入网消息头0x3Cuint8_t dataLength; //数据长度 type~crcuint8_t netType; //模块的网络类型uint8_t netPanid[2]; //设备的PANIDuint8_t timeData[5]; //模块的设备地址uint8_t crcCheck; //数据校验整个数据包除校验位
}SlaveRtcSync;/************************************************************************/
/* 设备信息 */
/************************************************************************/
typedef struct
{uint8_t deviceType; //模块的设备类型DeviceJionStatus deviceNetStatus; //设备的网络状态uint8_t deviceAddr[2]; //模块的设备地址uint8_t deviceId; //表示在网表中加入第几个设备uint8_t deviceData[20];
}SlaveInfo;uint16_t RandomNumber(void);
uint8_t SlaveJionNetFuction(void);
void SlaveGetSendTime(void);
DeviceJionFlag WaitJionNetFinish(uint8_t timout);
void MasterSendClockData(void);#endif
netprocess.c
//所有节点的更新周期(在Time内上传所有数据) 单位Ms
volatile uint32_t DataUpTimePeriod 1000 * 60 * 1; //1分钟volatile static uint32_t currentTime 0;
//当前加入设个的个数
volatile uint16_t currentDeviceNumber 0;
//保存当前加入节点
volatile uint16_t oldNodeNumber 0;
//节点时间片
volatile uint32_t DataUpTime 0;//节点入网状态
volatile DeviceJionFlag JionNodeTimeOutFlag No_Node_Jion_Flag;//时钟同步
SlaveRtcSync rtcSync_t;//初始化网络状态
volatile DeviceJionStatus NetStatus NO_JION;extern tRadioDriver *Radio; 3.2.7.1 主机等待从机入网完成
//**********************************//
//函数名称 WaiitJionNetFinish
//函数描述 等待入网完成
//函数参数 超时时间
//返回值 无
//*******************************//
DeviceJionFlag WaitJionNetFinish(uint8_t timout)
{JionNodeTimeCount 0;while(1){Sx127xDataGet();if (JionNodeTimeCount timout){if (oldNodeNumber currentDeviceNumber){printf(无新节点加入\r\n);//无新节点加入JionNodeTimeOutFlag Node_Jion_Finish_Flag;//停止定时器HAL_TIM_Base_Stop_IT(htim2);return JionNodeTimeOutFlag; }else{//有新节点加入printf(有新节点加入\r\n);JionNodeTimeOutFlag Node_Jion_No_Finish_Flag;//保存当前节点数量oldNodeNumber currentDeviceNumber;}}//等待加入网络}
} 3.2.7.2 主机发送同步时钟
//**********************************//
//函数名称 MasterSendClockData
//函数描述 主机发送同步时钟
//函数参数 无
//返回值 无
//*******************************//void MasterSendClockData(void)
{RTC_TimeTypeDef thisTime;rtcSync_t.msgHead JIONREQUEST; //0x3crtcSync_t.dataLength 0x09;rtcSync_t.netType T;rtcSync_t.netPanid[0] HI_UINT16(PAN_ID);rtcSync_t.netPanid[1] LO_UINT16(PAN_ID);//获取当前时间HAL_RTC_GetTime(hrtc, thisTime, RTC_FORMAT_BIN);rtcSync_t.timeData[0] thisTime.Hours;rtcSync_t.timeData[1] thisTime.Minutes;rtcSync_t.timeData[2] thisTime.Seconds;rtcSync_t.timeData[3] (thisTime.SubSeconds 8) 0xFF;rtcSync_t.timeData[4] thisTime.SubSeconds 0xFF;//计算校验码rtcSync_t.crcCheck crc8((uint8_t *)rtcSync_t, rtcSync_t.dataLength 1);//发送数据包Radio-SetTxPacket((uint8_t *)rtcSync_t, rtcSync_t.dataLength 2);}3.2.7.3 生成随机数
//**********************************//
//函数名称 RandomNumber
//函数描述 生成随机数
//函数参数 无
//返回值 随机数
//*******************************//uint16_t RandomNumber(void)
{uint16_t randNumber 0;float adcValue 0;uint32_t u32adcValue 0;//开启DMA转换ADCHAL_ADC_Start_DMA(hadc, (uint32_t*)ADC_DMA_Value, ADC_NUM);HAL_Delay(100);
// printf(ADC_DMA_Value[0] %d\n,ADC_DMA_Value[0]);
// printf(ADC_DMA_Value[1] %d\n,ADC_DMA_Value[1]);
// printf(ADC_DMA_Value[2] %d\n,ADC_DMA_Value[2]);
// printf(ADC_DMA_Value[3] %d\n,ADC_DMA_Value[3]);
// printf(ADC_DMA_Value[4] %d\n,ADC_DMA_Value[4]);//转换为mv值adcValue ADC_DMA_Value[ADC_IN5];adcValue (adcValue * 3300) / 4096; printf(adcValue %f\n,adcValue);u32adcValue (uint32_t)((adcValue-floor(adcValue))*1000000);printf(u32adcValue %d\n,u32adcValue);//获取随机数srand(u32adcValue);for(int i 0;i 10;i)randNumber (uint8_t)rand();return randNumber;
}
库函数 放到时间数里面循环读10次转换为uint8 最大是2550返回0-2.5s) 3.2.7.4 从机加入网络
//**********************************//
//函数名称 SlaveJionNetFuction
//函数描述 从机加入网络
//函数参数 无
//返回值 入网状态
//*******************************//uint8_t SlaveJionNetFuction(void)
{switch(NetStatus){case NO_JION:SendJionNetPacke();//if(Radio-Process( ) RF_TX_DONE)NetStatus JIONING;currentTime HAL_GetTick();break;case JIONING:if(Sx127xDataGet() 0xFF) //入网成功{NetStatus JIONDONE;printf(Slave_JIONDONE\n); }else{if ((HAL_GetTick() - currentTime) 6000)NetStatus JIONTIMEOUT;}break;case JIONTIMEOUT:NetStatus NO_JION;break;case JIONDONE:Radio-StartRx();return 0;break;default:break;}return 1;
}
3.2.7.5 从机获取时间片
//**********************************//
//函数名称 SlaveGetSendTime
//函数描述 节点获取时间片
//函数参数 无
//返回值 无
//*******************************//
void SlaveGetSendTime(void)
{float TransTimeUP 0; //数据传输时间TransTimeUP SX1276LoRaGetTransferTime(); //获取数据发送时长DataUpTime Sx127xGetSendTime(NodeNumber,TransTimeUP, DataUpTimePeriod);printf(DataUpTime %d\n,DataUpTime);if (DataUpTime 0){startUpTimeHours startUpTimeMinute 0;startUpTimeSeconds startUpTimeSubSeconds 0; }else{GetTimeHMS(DataUpTime, startUpTimeHours, startUpTimeMinute, startUpTimeSeconds, startUpTimeSubSeconds);printf(DataUpTime-H:%d,M:%d,S:%d,SUB:%d\n, startUpTimeHours, startUpTimeMinute, startUpTimeSeconds, startUpTimeSubSeconds);}GetTimeHMS(DataUpTimePeriod, DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);printf(DataUpTimePeriod-H:%d,M:%d,S:%d,SUB:%d\n, DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);
}3.2.8 获取数据发送时长
lora获取时间片的同时需要考虑数据发送的时长 //**********************************//
//函数名称 SX1276LoRaGetTransferTime
//函数描述 获取数据发送时长
//函数参数 无
//返回值 float
//*******************************//
float SX1276LoRaGetTransferTime( void )
{uint16_t PayloadSymNb_Ceil,SF, PayloadSymNb_Ceil_DenoMinator;float Tsym 0,Tpreamble 0,PayloadSymNb 0,Tpayload0,Tpacket0;bool H;uint8_t DE 0;//计算符号速率SF (2 LoRaSettings.SpreadingFactor-1);Tsym (SF*1000 / (float)SignalBw[LoRaSettings.SignalBw]);
// PRINTF2(Tsym:%0.3f\n, Tsym);//前导码时间Tpreamble (SX1276LoRaGetPreambleLength() 4.25)*Tsym;
// PRINTF2(Tpreamble:%0.3f\n, Tpreamble);//有效负载符号数H !LoRaSettings.ImplicitHeaderOn;DE SX1276LoRaGetLowDatarateOptimize();PayloadSymNb_Ceil_DenoMinator (((8 * LoRaSettings.PayloadLength) - (4 * LoRaSettings.SpreadingFactor) 28 16 - (20 * H)));
// PRINTF2(PayloadSymNb_Ceil_DenoMinator:%d\n, PayloadSymNb_Ceil_DenoMinator);PayloadSymNb_Ceil (uint16_t)ceil(((double)PayloadSymNb_Ceil_DenoMinator) / (4 * (LoRaSettings.SpreadingFactor - 2 * DE)));
// PRINTF2(PayloadSymNb_Ceil:%d\n, PayloadSymNb_Ceil);PayloadSymNb 8 max((PayloadSymNb_Ceil)*(LoRaSettings.ErrorCoding 4), 0);Tpayload PayloadSymNb * Tsym;
// PRINTF2(Tpayload:%0.3f\n, Tpayload);//计算传输时间Tpacket (Tpreamble Tpayload)/1000;return Tpacket;
}//**********************************//
//函数名称 Sx127xGetSendTime
//函数描述 获取节点发送时间片
//函数参数 uint8_t num, float timeUp, uint32_t dataUpTimePeriod
//返回值 时间片
//*******************************//uint16_t Sx127xGetSendTime(uint8_t num, float timeUp, uint32_t dataUpTimePeriod)
{uint16_t startTime 0;/* 连个节点之间数据传输间隔最小为500Ms */if ( ((timeUp 500) * num ) dataUpTimePeriod){}/* 每个节点的所占间隙的时间长度已经包含发送时间和空闲时间 */startTime dataUpTimePeriod / num;/* 获得计算数据的整数部分向上取整*/return ((uint16_t)ceil((double)startTime * slaveNativeInfo_t.deviceId));
}3.2.8 主程序
主机:
等待入网 是否是新节点如是改变节点入网状态未完成 是否旧节点如是改变节点入网状态未完成 时钟同步时间是否到到了时钟同步 从机
节点都已经在上面部分实现只需要等待接收数据数据解析 判断是否到达定时发送时间发送数据并清空标志位。
1.adc读取返回随机时间 2.打印地址 3.发送完后收到应答包加入完成 4.时间片是0因为第一个 5.一分钟一个rtc闹钟 6网络同步 7收到同步包 8设置了时间 9 1分钟传一个数据上传一次数据 10 还有另一个设备发送的节点也会收到。 int main(void)
{uint8_t RegVersion 0;uint8_t str[20] {0};uint16_t addr ADDR;HAL_Init();uint32_t DelayTime 0;SystemClock_Config();MX_GPIO_Init();MX_DMA_Init();MX_ADC_Init();MX_USART1_UART_Init();MX_SPI1_Init();MX_RTC_Init();MX_TIM2_Init();#if defined (MPU6050)//初始化三轴传感器 MX_I2C1_Init();InitMpu6050(); #elif defined (FAN)D1_OUT_GPIO_Init();
#endifLcd_Init();// showimage(gImage_logo);HAL_Delay(500);Lcd_Clear(YELLOW);Gui_DrawFont_GBK16(0,0,RED,GREEN, LoRa Topology );
#if defined (SLAVE) Gui_DrawFont_GBK16(0,16,RED,GREEN, Slave );#if defined (MPU6050) //三轴传感器显示Gui_DrawFont_GBK16(0,48,BLACK,YELLOW,X:);Gui_DrawFont_GBK16(0,64,BLACK,YELLOW,Y:);Gui_DrawFont_GBK16(0,80,BLACK,YELLOW,Z:);
#elif defined (DHT11)//空气温湿度传感器显示Gui_DrawFont_GBK16(0,48,BLACK,YELLOW,TEMP:);Gui_DrawFont_GBK16(0,64,BLACK,YELLOW,HUM:);#elif defined (FAN)//风扇传感器显示Gui_DrawFont_GBK16(0,48,BLACK,YELLOW,FAN:);#endif#elif defined (MASTER)Gui_DrawFont_GBK16(0,16,RED,GREEN, Master );Gui_DrawFont_GBK16(0,48,BLACK,YELLOW,RX:);Gui_DrawFont_GBK16(0,64,BLACK,YELLOW,TX:);#endifGui_DrawFont_GBK16(0,32,BLACK,YELLOW,ADDR:);sprintf((char*)str,%x,addr);Gui_DrawFont_GBK16(64,32,BLACK,YELLOW,str);HAL_SPI_DeInit(hspi1);MX_SPI1_Init();//启动串口1使能串口空闲中断 __HAL_UART_ENABLE_IT(huart1,UART_IT_IDLE); HAL_UART_Receive_DMA(huart1,a_Usart1_RxBuffer,RXLENGHT); SX1276Read( REG_LR_VERSION, RegVersion );if(RegVersion ! 0x12){printf(LoRa read Error!\r\n);printf(LoRa RegVersion %d!\r\n,RegVersion);}else{printf(LoRa read Ok!\r\n);printf(LoRa RegVersion %d!\r\n,RegVersion);}//读到版本号后关闭3种灯LedOff(LED_RX);LedOff(LED_TX);LedOff(LED_NT);Radio RadioDriverInit();Radio-Init();printf(systerm init ok!\n);Radio-StartRx( ); #if SLAVE//获取随机入网时间DelayTime RandomNumber();printf(JionTime %d\n,DelayTime);HAL_Delay(DelayTime);//等待入网成功while (SlaveJionNetFuction());//获取节点发送时间片SlaveGetSendTime();#else//主机直接初始化RTCMX_RTC_Init();HAL_TIM_Base_Start_IT(htim2);#endifwhile (1){Sx127xDataGet();#if SLAVEif(sendUpDataFlag 1){SendSensorDataUP();sendUpDataFlag 0;}#elseUartDmaGet();//等待节点入网if (JionDeviceStatu ! Node_Jion_Finish_Flag){printf(main 等待加入网络\n);JionDeviceStatu WaitJionNetFinish(10);}/* 有新节点加入 */if (currentDeviceNumber ! oldNodeNumber){printf(main 新节点加入网络\n);HAL_TIM_Base_Start_IT(htim2);JionDeviceStatu New_Node_Jion_Flag;SendClockFlag 0; //发送分时时间片}/* 有旧节点加入 */for (int i 0; i currentDeviceNumber;i){/* 查询是否有旧节点重新加入*/if (slaveNetInfo_t[i].deviceNetStatus AGAIN_JION_NET){printf(main 旧节点加入网络\n);slaveNetInfo_t[i].deviceNetStatus JIONDONE;JionDeviceStatu New_Node_Jion_Flag;SendClockFlag 0; //发送分时时间片HAL_TIM_Base_Start_IT(htim2);}}/* 给从机分发时间片 */if ((JionDeviceStatu Node_Jion_Finish_Flag)(SendClockFlag 0)(currentDeviceNumber ! 0)){if (SendDataOkFlag 1) {SendDataOkFlag 0;printf(main 发送时钟同步\n);//告诉所有节点开始上传数据MasterSendClockData();SendClockFlag 1;while(!SendDataOkFlag) //等待发送完成{Sx127xDataGet();}SendDataOkFlag 1;}}
#endifif(EnableMaster true){MLCD_Show();}else{SLCD_Show();}}
}