欧美成人黄色网_欧美精品久久_国产在线一区二区三区_免费视频久久久_亚洲二区视频_欧美大片免费高清观看

產品分類

當前位置: 首頁 > 工業電子產品 > 其他電子產品 > IoT物聯網 > IoT傳感器

類型分類:
科普知識
數據分類:
IoT傳感器

物聯網之LoRa開發與應用六(LoRa自組網絡設計)

發布日期:2022-05-25 點擊率:148

p>

2、LoRaWAN終端(重點掌握)

3、LoRaWAN服務器

LoRaWAN是什么:

LoRaWAN采用星型無線拓撲:End Nodes(節點)、Gateway(網關)、Network Server(網絡服務器)、Application Server(應用服務器)

LoRaWAN通信協議:

低功耗、可擴展、高服務質量、安全的長距離無線網絡

LoRaWAN通信機制:

LoRaWAN與其他組網協議對比:

LoRaWAN網關SX1301:(8通道的LoRa接口用于LoRa節點的接入、一個FSK接口用于FSK節點的接入、1個LoRa網關間通訊的接口)

大容量的網絡規模、高速度的通信機制

有三種節點類型:Class A、Class B、Class C

LoRaWAN終端Class A:(平時處于休眠模式,當他需要工作的時候才會去發送數據包,所以功耗比較低。但是實時性較差,間隔一段時間才能下行通信)

LoRaWAN終端Class B:(當需要節點去響應實時性問題的時候,首先網關會發送一個信標,告訴節點要加快通訊,快速工作,節點收到信標之后,會在128秒內去打開多個事件窗口,每個窗口在3-160ms,在128秒內可以實時對節點進行監控)

LoRaWAN終端Class C:(如果不發送數據的情況下,節點一直打開接收窗口,既保證了實時性,也保證了數據的收發,但是功耗非常高)

LoRaWAN服務器框架:

LoRaWAN服務器通信接口:

LoRaWAN服務器通信協議:

LoRa自組網架構設計

內容概要:

1、MAC協議設計

2、LoRa自組網協調器設計

3、LoRa自組網節點設計

MAC協議重要性:解決信號沖突的問題、盡可能地節省電能、保證通信的健壯和穩定性

MAC協議種類:

1、信道劃分的MAC協議:時分(TDMA)、頻分(FDMA)、碼分(CDMA)

2、隨機訪問MAC協議:

ALOHA,S-ALOHA,CSMA,CSMA/CD

CSMA/CD應用于以太網

CSMA/CA應用于802.11無線局域網

3、輪訊訪問MAC協議:

主節點輪詢

工業Modbus通信協議

時分復用:(在一定的事件內去分配時間槽,每個時間槽分給一個節點,使節點在這個時間槽里通信,如果不在這個時間槽是不能通信的。和電腦CPU的時間片是一個道理)

優點:節省電能、最大化使用帶寬

缺點:所有節點需要精確的時鐘源,并且需要周期性校時;

向網絡中添加和刪除節點都要有時隙分配和回收算法。

頻分復用:(CPU是多核,多任務同時進行:不同頻率的通信可以同時進行)

優點:增加通信容量、提高通信可靠性

缺點:物理通道增加,成本增加

輪詢訪問:

優點:協議簡單,易開發

缺點:通訊效率低、網絡規模小(只能接入1-247個節點)

基于時分復用LoRa自組網設計:

入網機制:(隨機訪問,競爭入網)

時分復用:(每個節點在規定的時間槽內通信)

LoRa自組網協調器設計:

LoRa自組網節點設計:

LoRa自組網集中器程序開發

內容概要:

1、通信協議

2、工程修改

3、搭建框架

4、源碼分析

通信協議:

LoRa自組網協調器設計:

根據協調器業務流程需要在之前工程里添加兩個外設:定時器(用于節點入網超時的判斷,后面有配置說明)、RTC(實時時鐘,用于時鐘同步,后面有配置說明)

IAR工程修改:

添加外設需要修改STM32CubeMX工程,需要把我們編寫的代碼放在BEGIN和END中間

RTC外設配置:

1、修改RTC時鐘源為外部高速時鐘

2、配置RTC分頻系數

3、初始化日期和時間

4、配置Alarm參數

5、使能RTC全局中斷

定時器外設配置:

1、配置TIM2分頻系數

2、使能TIM2定時器中斷

搭建框架

1、RTC任務

2、定時器任務

3、通信協議

4、數據處理任務

5、網絡處理任務

RTC任務:

1、RTC初始化


sTime.Hours = startUpDateHours;
sTime.Minutes = startUpDateMinute;
sTime.Seconds = startUpDateSeconds;
sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
sTime.StoreOperation = RTC_STOREOPERATION_RESET;


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));

2、Alarm中斷任務

//
//
//函數名稱: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;
gAlarm.AlarmTime.Minutes = masterTime.Minutes;
gAlarm.AlarmTime.Seconds = masterTime.Seconds;
gAlarm.AlarmTime.SubSeconds = masterTime.SubSeconds;

#else
sendUpDataFlag = 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;
#endif


if (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 ");
//使能鬧鐘中斷
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;
}

定時器任務:

1、定時器初始化:CubeMX重初始化已經完成,這里不需要修改

2、定時器中斷任務

//
//
//函數名稱: HAL_TIM_PeriodElapsedCallback
//
//函數描述: 定時器2溢出中斷回調函數
//
//函數參數: TIM_HandleTypeDef *htim
//
//返回值: 無
//
//創建者:
//

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
//判斷是否為定時器2中斷
//累加全局計數值
if(htim->Instance == htim2.Instance)
{

JionNodeTimeCount++;
}
}

通信協議:

1、CRC8校驗函數



#include "protocol.h"


uint8_t crc8(uint8_t *data, uint8_t length)
{
uint8_t i;
uint8_t crc = 0; // Initial value
while(length--)
{
crc ^= *data++; // crc ^= *data; data++;
for ( i = 0; i < 8; i++ )
{
if ( crc & 0x80 )
crc = (crc << 1) ^ 0x07;
else
crc <<= 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! ");
return 1;
}
else
{
// PRINTF1("CRC8 Failed! ");
return 0;
}
}

2、協議數據結構

數據處理任務:(先了解大致框架,后面具體分析)

串口任務

-->串口接收

無線任務

-->無線接收

-->主機協議解析

-->網絡數據包解析

-->入網請求解析



#include "dataprocess.h"
#include "usart.h"
#include "led.h"
#include "protocol.h"
#include "rtc.h"

#include "string.h"
#include "stdio.h"
//sx1278
#include "platform.h"
#include "radio.h"
#include "sx1276-Hal.h"
#include "sx1276-LoRa.h"
#include "sx1276-LoRaMisc.h"

extern uint16_t BufferSize;
extern uint8_t Buffer[BUFFER_SIZE];

#if defined(MASTER)
extern uint8_t EnableMaster;

#elif defined(SLAVE)

extern uint8_t EnableMaster;

#endif

extern tRadioDriver *Radio;

extern uint32_t Master_RxNumber;
extern uint32_t Master_TxNumber;

extern uint32_t Slave_RxNumber;
extern uint32_t Slave_TxNumber;

extern volatile uint8_t SendDataOkFlag;

uint8_t startUpDateHours = 0;
uint8_t startUpDateMinute = 0;
uint8_t startUpDateSeconds = 0;
uint16_t startUpDateSubSeconds = 0;

//Master存儲入網的設備信息
SlaveInfo slaveNetInfo_t[NodeNumber];

//Salve入網信息包
SlaveJionNet jionPacke_t;

//Salve保存自己的地址
SlaveInfo slaveNativeInfo_t;
//節點數據
SlaveDataNet DataPacke_t;


//
//
//函數名稱:UartDmaGet
//
//函數描述:串口數據獲取
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void UartDmaGet(void)
{
if(UsartType1.receive_flag == 1)//如果過新的數據
{

//串口接收到的數據原封發給SX1278
Radio->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++;
else
Slave_RxNumber++;
}
//
//
//函數名稱: TxDataPacketNum
//
//函數描述: 發送數據包計數
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void TxDataPacketNum(void)
{
if(EnableMaster == true)
Master_TxNumber++;
else
Slave_TxNumber++;
}
//
//
//函數名稱: Sx127xDataGet
//
//函數描述: 讀取sx127x射頻射頻數據
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

uint8_t Sx127xDataGet(void)
{
uint8_t status = 0;
switch( Radio->Process( ) )
{
case RF_RX_TIMEOUT:
printf("RF_RX_TIMEOUT ");
break;
case RF_RX_DONE:
Radio->GetRxPacket( Buffer, ( uint16_t* )&BufferSize );
if(EnableMaster == true)
printf("master Rx Len = %d ",BufferSize);
else
printf("slave Rx Len = %d ",BufferSize);
if( BufferSize > 0 )//&& (BufferSize == strlen((char*)Buffer)))
{
//接收數據閃爍
LedBlink( LED_RX );
//計算接收數據的個數
RxDataPacketNum();

//清空sx127x接收緩沖區
#ifdef MASTER
status = MasterProtocolAnalysis(Buffer,BufferSize);
#else
status = SlaveProtocolAnalysis(Buffer, BufferSize);
#endif
memset(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 ");
break;
default:
break;
}
return status;
}


//
//



//
//
//函數名稱: SendJionNetPacke
//
//函數描述: 從機入網數據發送
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void SendJionNetPacke(void)
{
uint16_t addr = ADDR;
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 ",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 ");
for (int i = 0; i < len; i++)
{
printf("0x%x ",buff[i]);
}
printf(" ");

if (buff[0] == NETDATA)
{
if (buff[1] == HI_UINT16(PAN_ID) && buff[2] == LO_UINT16(PAN_ID))
{
Crc8Data = crc8(&buff[3], len - 4);

if (Crc8Data != buff[len - 1])
{
memset(buff, 0, len);
return 0;
}
if (buff[3] == 0x21)
{
printf("Slave_NETDATA ");
}
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 ");
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 ");
printf("H:%d,M:%d,S:%d,SUB:%d ", 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 ", DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);
//使能RTC
MX_RTC_Init();
return 0xFF;
}
}
return 1;
}

//
//
//函數名稱: SendSensorDataUP
//
//函數描述: 上傳節點傳感器數據
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void SendSensorDataUP(void)
{

printf("SendSensorDataUP ");
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 = 0x09;
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] = 0x1;
DataPacke_t.buff[1] = 0x2;
DataPacke_t.buff[2] = 0x3;
DataPacke_t.buff[3] = 0x4;

//校驗碼
DataPacke_t.crcCheck = crc8((uint8_t *)&DataPacke_t,DataPacke_t.dataLength + 4);
//發送數據包
Radio->SetTxPacket((uint8_t *)&DataPacke_t, DataPacke_t.dataLength + 5);
}


//
//



//
//
//函數名稱: 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 ");
for (int i = 0; i < len; i++)
{
printf("0x%x ",buff[i]);
}
printf(" ");

if(buff[0] == NETDATA)
{
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] == DATAHEAD)
{

NetDataProtocolAnalysis(&buff[3], len - 3);
}
}
else
return 0;
}
else if(buff[0] == JIONREQUEST)
{
deviceID = JionNetProtocolAnalysis(buff, len);
printf("deviceID = %d ",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 ");
for (int i = 0; i < 9; i++)
{
printf("0x%x ",SendAck[i]);
}
printf(" ");
}
}
return 1;
}



//
//
//函數名稱: 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 ");
for (int i = 0; i < len; i++)
{
printf("0x%x ",buff[i]);
}
printf(" ");
while(len--)
{
switch(status)
{
case JION_HEADER:
if (buff[status] == JIONREQUEST)
{
status = JION_LENGHT;
}
else
{
goto ERR;
}
break;
case JION_LENGHT:
if (buff[status] == 0x06)
{
status = JION_TYPE;
}
else
{
goto ERR;
}
break;
case JION_TYPE:
if (buff[status] == '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 ",i);
printf("deviceId=%x ",slaveNetInfo_t[i].deviceId);
printf("deviceAddr[0]=%x ",slaveNetInfo_t[i].deviceAddr[0]);
printf("deviceAddr[1]=%x ",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 ",i);
printf("deviceId=%x ",slaveNetInfo_t[i].deviceId);
printf("deviceAddr[0]=%x ",slaveNetInfo_t[i].deviceAddr[0]);
printf("deviceAddr[1]=%x ",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;
printf("JIonDONE i = %d ",i);
printf("deviceId=%x ",slaveNetInfo_t[i].deviceId);
printf("deviceAddr[0]=%x ",slaveNetInfo_t[i].deviceAddr[0]);
printf("deviceAddr[1]=%x ",slaveNetInfo_t[i].deviceAddr[1]);

}
break;
default:
break;
}
}
return i;

ERR:
memset(buff, 0, lenOld);
status = JION_HEADER;
return -1;
}

//
//
//函數名稱: NetDataProtocolAnalysis
//
//函數描述: 網絡數據包解析
//
//函數參數: uint8_t *buff,uint8_t len
//
//返回值: 無
//
//創建者:
//

void NetDataProtocolAnalysis(uint8_t *buff,uint8_t len)
{
printf("NetDataProtocolAnalysis ");
for (int i = 0; i < len; i++)
{
printf("0x%x ",buff[i]);
}
printf(" ");
}

網絡處理任務:(先了解大致框架,后面具體分析)

1、等待入網完成

2、主機發送時鐘同步數據包



#include "netprocess.h"
#include "dataprocess.h"
#include "tim.h"
#include "rtc.h"
#include "adc.h"
#include "protocol.h"

#include "math.h"
#include "stdlib.h"
#include "string.h"
#include "stdio.h"
//sx1278
#include "platform.h"
#include "radio.h"
#include "sx1276-Hal.h"
#include "sx1276-LoRa.h"
#include "sx1276-LoRaMisc.h"

//所有節點的更新周期(在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;

uint8_t startUpTimeHours = 0;
uint8_t startUpTimeMinute = 0;
uint8_t startUpTimeSeconds = 0;
uint32_t startUpTimeSubSeconds = 0;

uint8_t DataUpTimeHours = 0;
uint8_t DataUpTimeMinute = 0;
uint8_t DataUpTimeSeconds = 0;
uint32_t DataUpTimeSubSeconds = 0;

//時鐘同步
SlaveRtcSync rtcSync_t;

//初始化網絡狀態
volatile DeviceJionStatus NetStatus = NO_JION;

extern tRadioDriver *Radio;


//
//


//
//
//函數名稱: RandomNumber
//
//函數描述: 生成隨機數
//
//函數參數: 無
//
//返回值: 隨機數
//
//創建者:
//

uint16_t RandomNumber(void)
{
uint16_t randNumber = 0;
float adcValue = 0;
uint32_t u32adcValue = 0;

//開啟DMA轉換ADC
HAL_ADC_Start_DMA(&hadc, (uint32_t*)ADC_DMA_Value, ADC_NUM);

HAL_Delay(100);
// printf("ADC_DMA_Value[0] = %d ",ADC_DMA_Value[0]);
// printf("ADC_DMA_Value[1] = %d ",ADC_DMA_Value[1]);
// printf("ADC_DMA_Value[2] = %d ",ADC_DMA_Value[2]);
// printf("ADC_DMA_Value[3] = %d ",ADC_DMA_Value[3]);
// printf("ADC_DMA_Value[4] = %d ",ADC_DMA_Value[4]);
//轉換為mv值
adcValue = ADC_DMA_Value[ADC_IN5];
adcValue = (adcValue * 3300) / 4096;

printf("adcValue = %f ",adcValue);

u32adcValue = (uint32_t)((adcValue-floor(adcValue))*1000000);
printf("u32adcValue = %d ",u32adcValue);
//獲取隨機數
srand(u32adcValue);
for(int i = 0;i< 10;i++)
randNumber += (uint8_t)rand();
return randNumber;
}

//
//
//函數名稱: 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 ");
}
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;

}
//
//
//函數名稱: SlaveGetSendTime
//
//函數描述: 節點獲取時間片
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void SlaveGetSendTime(void)
{
float TransTimeUP = 0; //數據傳輸時間
TransTimeUP = SX1276LoRaGetTransferTime();
DataUpTime = Sx127xGetSendTime(NodeNumber,TransTimeUP, DataUpTimePeriod);
printf("DataUpTime = %d ",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 ", startUpTimeHours, startUpTimeMinute, startUpTimeSeconds, startUpTimeSubSeconds);
}
GetTimeHMS(DataUpTimePeriod, &DataUpTimeHours, &DataUpTimeMinute, &DataUpTimeSeconds, &DataUpTimeSubSeconds);
printf("DataUpTimePeriod->H:%d,M:%d,S:%d,SUB:%d ", DataUpTimeHours, DataUpTimeMinute, DataUpTimeSeconds, DataUpTimeSubSeconds);
}


//
//


//
//
//函數名稱: WaiitJionNetFinish
//
//函數描述: 等待入網完成
//
//函數參數: 超時時間
//
//返回值: 無
//
//創建者:
//

DeviceJionFlag WaitJionNetFinish(uint8_t timout)
{
JionNodeTimeCount = 0;
while(1)
{
Sx127xDataGet();
if (JionNodeTimeCount > timout)
{
if (oldNodeNumber == currentDeviceNumber)
{
printf("無新節點加入 ");
//無新節點加入
JionNodeTimeOutFlag = Node_Jion_Finish_Flag;
//停止定時器
HAL_TIM_base_Stop_IT(&htim2);
return JionNodeTimeOutFlag;
}
else
{
//有新節點加入
printf("有新節點加入 ");
JionNodeTimeOutFlag = Node_Jion_No_Finish_Flag;
//保存當前節點數量
oldNodeNumber = currentDeviceNumber;
}

}//等待加入網絡
}
}
//
//
//函數名稱: MasterSendClockData
//
//函數描述: 主機發送同步時鐘
//
//函數參數: 無
//
//返回值: 無
//
//創建者:
//

void MasterSendClockData(void)
{
RTC_TimeTypeDef thisTime;

rtcSync_t.msgHead = JIONREQUEST;
rtcSync_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);
}

源碼分析(具體分析:該源碼涵蓋了集中器 和 節點 的源代碼,可以從main函數開始分析,先屏蔽掉節點的代碼,只分析集中器的相關代碼,然后屏蔽掉集中器的代碼,只分析節點代碼。分析過程中有遇到沒見過的或者不知道的函數,直接追入分析即可)

main函數相關代碼分析:

//所有設備加入網絡的當前情況
DeviceJionFlag JionDeviceStatu = No_Node_Jion_Flag;

//時間同步標志
volatile uint8_t MasterSendTimeSliceFlag = 0;

volatile uint8_t SendDataOkFlag = 0;

extern volatile uint8_t SendClockFlag;




#if SLAVE
//獲取隨機入網時間
DelayTime = RandomNumber();
printf("JionTime = %d ",DelayTime);
HAL_Delay(DelayTime);
//等待入網成功
while (SlaveJionNetFuction());
//獲取節點發送時間片
SlaveGetSendTime();

#else
//主機直接初始化RTC
MX_RTC_Init();--------------------------------------------->第一步:主機初始化RTC
HAL_TIM_base_Start_IT(&htim2);----------------------------->第二步:主機初始化定時器(包括中斷)
#endif

while (1)
{




Sx127xDataGet();

#if SLAVE
if(sendUpDataFlag == 1)
{
SendSensorDataUP();
sendUpDataFlag = 0;
}
#else
UartDmaGet();------------------------------------------->第三步:串口數據獲取,并把數據發送出去
//等待節點入網
if (JionDeviceStatu != Node_Jion_Finish_Flag)----------->第四步:如果沒有入網完成
{
printf("main 等待加入網絡 ");
JionDeviceStatu = WaitJionNetFinish(10);
}


if (currentDeviceNumber != oldNodeNumber)
{
printf("main 新節點加入網絡 ");
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 舊節點加入網絡 ");
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 發送時鐘同步 ");
//告訴所有節點開始上傳數據
MasterSendClockData();
SendClockFlag = 1;
while(!SendDataOkFlag) //等待發送完成
{
Sx127xDataGet();
}
SendDataOkFlag = 1;
}
}
#endif
if(EnableMaster == true)
{
MLCD_Show();
}
else
{
SLCD_Show();
}
}

LoRa自組網節點程序開發

內容概要:

1、工程修改

2、搭建框架

3、源碼分析

4、組網實驗

LoRa自組網節點設計:

根據節點業務流程需要在之前工程里添加一個外設用于隨機數發生:ADC

ADC外設配置:

1、配置ADC為連續采集

2、配置DMA通道

3、配置ADC標簽

搭建框架:

1、網絡處理任務

2、數據處理任務

數據處理任務:

數據解析任務

-->從機數據解析

-->網絡數據包解析

-->網絡應答包解析

-->時間同步包解析

數據上傳任務

-->入網信息上傳

-->數據信息上傳

網絡處理任務:

1、入網隨機時間獲取

2、無線加入網絡

3、獲取數據包發送時長

4、獲取節點時間片

硬件準備:LoRa設備X3、STlinkX1、USBmini線X3

程序燒寫:

1、燒寫Master程序

2、燒寫Slave程序:配置從機設備地址,分別燒錄

實驗現象:

1、從機入網請求

2、主機入網應答

3、從機1分鐘定時上傳數據
---------------------
作者:許新天
來源:CSDN
原文:https://blog.csdn.net/weixin_39148042/article/details/81744537


閱讀更多: LoRa中文學習資料, LoRa實驗室


參考分類:

首頁-推薦學習

上一篇: 物聯網之LoRa開發與應用五(串口透傳開發)

下一篇: Semtech的LoRa技術被用于金廷科技(YoSmart)的企業和商業樓宇的物聯網應用中

下一篇: PLC、DCS、FCS三大控

上一篇: 玩轉LoRa物聯網之天線

推薦產品

更多
主站蜘蛛池模板: 日本免费一区二区三区中文字幕 | 天天看黄色片 | 四虎影视在线观看2022a | 久久久久久久综合综合狠狠 | 女性一级全黄生活片免费看 | 校花高潮抽搐冒白浆视频 | 久草免费公开视频 | 亚洲人成网站在线观看播放动漫 | 久久亚洲私人国产精品 | 99久久精品国产免看国产一区 | 奇米777四色欧美成人 | 欧美性黑人极品hd | 国产精品国产亚洲区艳妇糸列短篇 | 日本特级全黄一级毛片 | 天天爽夜夜爽人人爽曰 | 日韩成人影院 | 韩日午夜在线资源一区二区 | 同性男男黄g片免费网站 | 亚洲综合一区二区三区四区 | 少妇被躁爽到高潮 | 亚洲精品久久久蜜桃 | 日韩精品无码中文字幕电影 | 亚洲天天在线 | 亚洲婷婷五月综合狠狠爱 | 色婷婷资源网 | 精品人妻无码一区二区三区 | 五月综合激情婷婷六月色窝 | 大帝av在线一区二区三区 | 一级特黄一欧美俄罗斯毛片 | 久久久久亚洲av片无码 | 在线观看午夜视频 | 久热精品视频 | 99婷婷久久精品国产一区二区 | 思思99精品国产自在现线 | 欧美肉大捧一进一出免费视频 | 国产高跟黑色丝袜在线 | 亚洲国产成人久久综合一区 | 国产精品资源网站在线观看 | s级毛片 | 女人爽到高潮免费视频大全 | 亚洲综合在线观看视频 |