Рассмотрим в данной статье работу Lora и Stm32 на примере модуля e32 ebyte. Так же вы сможете скачать библиотеку для работы с данным модулем.
Lora. Теория.
LoRa (Long Range) – технология передачи данных на большие расстояния с низким потреблением. Для передачи данных используются нелицензируемые частоты, такие как 433,05-434,79 МГц, 902—928 МГц, 865—867 МГц. Сама технология LORA описывает только физический уровень передачи данных, и является видом модуляции сигнала, но название перешло в широкие массы и теперь обозначает всю систему в совокупности.
Характеристики модуля E32
Даташит на данный модуль находится в конце статьи. Характеристики данного модуля следующие:
- Расстояние передачи до 3 км.
- Мощность передатчика 100 мВт. Регулируется.
- Скорость передачи 0,3 кбит / с~19,2 кбит / с.
- Напряжение питания 3,3 В ~ 5,2 В. При напряжении 5,0 В обеспечивается наилучшая работа модуля.
- Температура работы от -40 до 85 ° C.
- Интерфейс связи с контроллером UART.
На практике у меня получилось достичь расстояния в 1300 метров.
E32 ebyte: назначение выводов
E32 ebyte: подключение к MCU
На схеме показано как подключается модуль E32 Ebyte к микроконтроллеру.
Библиотека lora sx1276 для STM32
Библиотека Lora Stm32 можно использовать с любым микроконтроллером STM32 имеющим в своем составе UART модуль. Прием сообщений осуществлен по прерыванию.
Что бы использовать библиотеку необходимо:
- Создать переменную типа lora_t.
- Заполнить поля структуры lora_t.
- Вызвать функцию инициализации.
- Установить режим LORA_MODE_NORMAL.
- Активировать приемник сообщений.
lora_t Lora; Lora.LoraPortSpeed = LORA_PORT_SPEED_9600; Lora.LoraChannel = LORA_CHANNEL; Lora.LoraSelfAddr = LORA_ADDRESS; Lora.LoraAirSpeed = LORA_AIR_SPEED_2400; Lora.LoraTxPower = LORA_TX_POWER_20dbm; Lora.LoraRxIndex = 0; // инициализируем Лора Status = Lora_Init(Lora); // Переход в режим приема Lora_SetMode(Lora, LORA_MODE_NORMAL); // Старт приема сообщений Lora_Message_RX(Lora);
Lora.h
#include <stdbool.h> /* Includes ------------------------------------------------------------------*/ /* USER CODE BEGIN Private defines */ #define LORA_PORT huart3 #define LORA_TX_COMPL 0x00000000U #define LORA_PIN_M0_PORT GPIOD #define LORA_PIN_M1_PORT GPIOD #define LORA_PIN_AUX_PORT GPIOC #define LORA_M0_PIN Lora_M0_PD0_Pin #define LORA_M1_PIN Lora_M1_PD1_Pin #define LORA_AUX_PIN Lora_AUX_PC12_Pin #define LORA_PORT_SPEED_1200 0 #define LORA_PORT_SPEED_2400 1 #define LORA_PORT_SPEED_4800 2 #define LORA_PORT_SPEED_9600 3 #define LORA_PORT_SPEED_19200 4 #define LORA_PORT_SPEED_38400 5 #define LORA_PORT_SPEED_57800 6 #define LORA_PORT_SPEED_115200 7 #define LORA_AIR_SPEED_0_3 0 #define LORA_AIR_SPEED_1200 1 #define LORA_AIR_SPEED_2400 2 #define LORA_AIR_SPEED_4800 3 #define LORA_AIR_SPEED_9600 4 #define LORA_AIR_SPEED_19200 5 #define LORA_TX_POWER_20dbm 0 #define LORA_TX_POWER_17dbm 1 #define LORA_TX_POWER_14dbm 2 #define LORA_TX_POWER_10dbm 3 #define LORA_CHANNEL 6 #define LORA_ADDRESS 1 #define LORA_BC_MESSAGE_ADDR 0xFFFF #define LORA_END_OF_MESSAGE_STRING "\r\n" #define LORA_MODE_NORMAL 0 #define LORA_MODE_WAKEUP 1 #define LORA_MODE_POWER_SAVING 2 #define LORA_MODE_SLEEP 3 #define LORA_MODE_NOT_IDENT 4 #define LORA_PACKET_SIZE 50 #define LORA_SIZE_BUFFER 56 /* USER CODE END Private defines */ typedef struct { //UART_HandleTypeDef LoraPort; uint32_t LoraPortSpeed; //GPIO_TypeDef * LoraPinPort; uint16_t LoraM0Pin; uint16_t LoraM1Pin; uint16_t LoraAuxPin; uint16_t LoraChannel; uint16_t LoraSelfAddr; uint16_t LoraAirSpeed; uint16_t LoraTxPower; uint8_t LoraTxBuff[LORA_SIZE_BUFFER]; uint8_t LoraRxBuff[LORA_SIZE_BUFFER]; uint8_t LoraRxByte; volatile uint16_t LoraRxIndex; } lora_t; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* USER CODE BEGIN Prototypes */ bool Lora_Init(lora_t lorastr); bool Lora_TX_ReadyStatus(lora_t lorastr); uint16_t Lora_SetMode(lora_t lorastr, uint16_t Mode); uint16_t Lora_GetMode(lora_t lorastr); bool Lora_Message_TX(lora_t* lorastr, uint8_t *pData, uint16_t size, uint8_t channel, uint16_t addr, uint8_t ack, uint16_t timeout); void Lora_Message_RX(lora_t lorastr); void Lora_Get_Message_RX(lora_t lorastr, uint8_t *pData); uint16_t Lora_RxNbrBytes(lora_t lorastr); void Lora_Flush_Buf(uint8_t* Buffer); bool Lora_Reset(lora_t lorastr); bool Lora_RxBuf_String(lora_t lorastr, uint8_t* str); bool Lora_RxBuf_Bytes(lora_t lorastr, uint8_t* bytes, uint8_t sizeofbytes); uint8_t MyStsrStsr(lora_t lorastr, uint8_t* bytes, uint8_t sizeofbytes); bool Lora_GetOptions(lora_t lorastr);
Lora.c
#include "usart.h" #include "gpio.h" #include "Lora.h" #include "crc.h" #include <string.h> //#include <stdbool.h> /*************************************/ bool Lora_Init(lora_t lorastr){ bool ret = true; uint32_t portspeed; Lora_Reset(lorastr); HAL_Delay(500); Lora_Flush_Buf(lorastr.LoraRxBuff); Lora_Flush_Buf(lorastr.LoraTxBuff); portspeed = LORA_PORT.Init.BaudRate; LORA_PORT.Init.BaudRate = 9600; ret = HAL_UART_Init(&LORA_PORT); if (ret != HAL_OK) { return ret; } lorastr.LoraTxBuff[0]= 0xC0; //first byte lorastr.LoraTxBuff[1]= (uint8_t)((lorastr.LoraSelfAddr & 0xFF00)>>8); //second byte - high address lorastr.LoraTxBuff[2]= (uint8_t)(lorastr.LoraSelfAddr & 0x00FF); //3 byte - lowbyte address lorastr.LoraTxBuff[3]= (uint8_t) ((0x38&(lorastr.LoraPortSpeed<<3))|(0x07&lorastr.LoraAirSpeed)); // 4 byte - speed lorastr.LoraTxBuff[4]= (uint8_t) (0x1F&lorastr.LoraChannel); // 5 byte - channel lorastr.LoraTxBuff[5]= (uint8_t) ((0xC4) | (0x03&lorastr.LoraTxPower)); while (!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} Lora_SetMode(lorastr, LORA_MODE_SLEEP); HAL_Delay(4); ret = HAL_UART_Transmit(&LORA_PORT, lorastr.LoraTxBuff,6,100); if (ret != HAL_OK) { return ret; } HAL_Delay(50); Lora_Flush_Buf(lorastr.LoraTxBuff); LORA_PORT.Init.BaudRate = portspeed; ret = HAL_UART_Init(&(LORA_PORT)); return ret; } uint8_t MyStsrStsr(lora_t lorastr, uint8_t* bytes, uint8_t sizeofbytes) { for (int i = 0; i<sizeofbytes-1;i++) { if ((lorastr.LoraRxBuff[i] == bytes[1]) && (lorastr.LoraRxBuff[i - 1] == bytes[0])) { return i; } } return 0; } /******************************************/ bool Lora_RxBuf_Bytes(lora_t lorastr, uint8_t* bytes, uint8_t sizeofbytes) { for (int i = 0; i<sizeofbytes-1;i++) { if ((lorastr.LoraRxBuff[i] == bytes[1]) && (lorastr.LoraRxBuff[i - 1] == bytes[0])) { return true; } } return false; } /****************************************/ bool Lora_Message_TX(lora_t* lorastr, uint8_t *pData, uint16_t size, uint8_t channel, uint16_t addr, uint8_t ack, uint16_t timeout){ bool ret = true; if(Lora_GetMode(*lorastr) != LORA_MODE_NORMAL) { Lora_SetMode(*lorastr, LORA_MODE_NORMAL); } if((addr>0x1F)&&(addr !=LORA_BC_MESSAGE_ADDR)) { ret = false; return ret; } Lora_Flush_Buf(lorastr->LoraTxBuff); lorastr->LoraTxBuff[0] = (uint8_t) addr>>8; lorastr->LoraTxBuff[1] = (uint8_t) (addr & 0x00FF); lorastr->LoraTxBuff[2] = channel; if (size > LORA_PACKET_SIZE) { ret = false; return ret; } for (int i = 0; i<size; i++) { lorastr->LoraTxBuff[i + 3] = pData[i]; } strcat((char *)&lorastr->LoraTxBuff[size + 3], (char*) LORA_END_OF_MESSAGE_STRING); while (!Lora_TX_ReadyStatus(*lorastr)) {} ret = HAL_UART_Transmit(&LORA_PORT, lorastr->LoraTxBuff, size+3+strlen(LORA_END_OF_MESSAGE_STRING), timeout); while (!Lora_TX_ReadyStatus(*lorastr)) {} HAL_Delay(timeout); Lora_Flush_Buf(lorastr->LoraTxBuff); return true; } /***************************************/ void Lora_Message_RX(lora_t lorastr){ HAL_UART_Receive_IT(&LORA_PORT, &lorastr.LoraRxByte, 1); lorastr.LoraRxIndex = 0; } void Lora_Get_Message_RX(lora_t lorastr, uint8_t *pData){ uint32_t lenght; if(Lora_RxBuf_Bytes(lorastr, (uint8_t *) LORA_END_OF_MESSAGE_STRING,LORA_SIZE_BUFFER)){ uint8_t ret; ret = MyStsrStsr(lorastr, (uint8_t *) LORA_END_OF_MESSAGE_STRING,LORA_SIZE_BUFFER); lenght = ret; for (int i=0; i<lenght; i++) { pData[i] = lorastr.LoraRxBuff[i]; } } } /***************************************/ bool Lora_Reset(lora_t lorastr) { uint16_t status; Lora_SetMode(lorastr, LORA_MODE_SLEEP); Lora_Flush_Buf(lorastr.LoraTxBuff); lorastr.LoraTxBuff[0] = 0xC4; lorastr.LoraTxBuff[1] = 0xC4; lorastr.LoraTxBuff[2] = 0xC4; HAL_Delay(3); status = HAL_UART_Transmit(&LORA_PORT, lorastr.LoraTxBuff,3,100); HAL_Delay(100); Lora_SetMode(lorastr, LORA_MODE_NORMAL); if(status!= 0x00U) {return false;} return true; } /*******************************************/ bool Lora_TX_ReadyStatus(lora_t lorastr){ if (HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {return true;} return false; } /*******************************************/ bool Lora_RxBuf_String(lora_t lorastr, uint8_t* str){ char *ret; ret = strstr((char *) lorastr.LoraRxBuff, (char *) str); if (ret != NULL) { return true; } return false; } /*******************************************/ uint16_t Lora_RxNbrBytes(lora_t lorastr) { return lorastr.LoraRxIndex; } /*******************************************/ void Lora_Flush_Buf(uint8_t* Buffer){ for (uint16_t i=0; i<LORA_SIZE_BUFFER;i++){ Buffer[i] = 0; } } /***********************************************/ uint16_t Lora_SetMode(lora_t lorastr, uint16_t Mode) { uint16_t ret; while(!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} switch (Mode) { case LORA_MODE_NORMAL: while (!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} HAL_GPIO_WritePin(LORA_PIN_M0_PORT, LORA_M0_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(LORA_PIN_M1_PORT, LORA_M1_PIN, GPIO_PIN_RESET); break; case LORA_MODE_WAKEUP: while (!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} HAL_GPIO_WritePin(LORA_PIN_M0_PORT, LORA_M0_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LORA_PIN_M1_PORT, LORA_M1_PIN, GPIO_PIN_RESET); break; case LORA_MODE_POWER_SAVING: while (!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} HAL_GPIO_WritePin(LORA_PIN_M0_PORT, LORA_M0_PIN, GPIO_PIN_RESET); HAL_GPIO_WritePin(LORA_PIN_M1_PORT, LORA_M1_PIN, GPIO_PIN_SET); break; case LORA_MODE_SLEEP: while (!HAL_GPIO_ReadPin(LORA_PIN_AUX_PORT, LORA_AUX_PIN)) {} HAL_GPIO_WritePin(LORA_PIN_M0_PORT, LORA_M0_PIN, GPIO_PIN_SET); HAL_GPIO_WritePin(LORA_PIN_M1_PORT, LORA_M1_PIN, GPIO_PIN_SET); break; } HAL_Delay(10); ret = Mode; return ret; } /***************************************/ uint16_t Lora_GetMode(lora_t lorastr) { uint16_t mode; if((!(HAL_GPIO_ReadPin(LORA_PIN_M0_PORT, LORA_M0_PIN)))&&(!(HAL_GPIO_ReadPin(LORA_PIN_M1_PORT, LORA_M1_PIN)))){mode = LORA_MODE_NORMAL;} if((HAL_GPIO_ReadPin(LORA_PIN_M0_PORT, LORA_M0_PIN))&&(!(HAL_GPIO_ReadPin(LORA_PIN_M1_PORT, LORA_M1_PIN)))){mode = LORA_MODE_WAKEUP;} if((HAL_GPIO_ReadPin(LORA_PIN_M1_PORT, LORA_M1_PIN))&&(!(HAL_GPIO_ReadPin(LORA_PIN_M0_PORT, LORA_M0_PIN)))){mode = LORA_MODE_POWER_SAVING;} if((HAL_GPIO_ReadPin(LORA_PIN_M0_PORT,LORA_M0_PIN))&&(HAL_GPIO_ReadPin(LORA_PIN_M1_PORT, LORA_M1_PIN))){mode = LORA_MODE_SLEEP;} HAL_Delay(1); return mode; } bool Lora_GetVersion(lora_t lorastr) { uint16_t status; Lora_SetMode(lorastr, LORA_MODE_SLEEP); Lora_Flush_Buf(lorastr.LoraTxBuff); lorastr.LoraTxBuff[0] = 0xC3; lorastr.LoraTxBuff[1] = 0xC3; lorastr.LoraTxBuff[2] = 0xC3; status = HAL_UART_Transmit(&LORA_PORT, lorastr.LoraTxBuff,3,100); HAL_Delay(2); Lora_SetMode(lorastr, LORA_MODE_NORMAL); if(status!= 0x00U) {return false;} return true; } bool Lora_GetOptions(lora_t lorastr) { uint16_t status; Lora_SetMode(lorastr, LORA_MODE_SLEEP); Lora_Flush_Buf(lorastr.LoraTxBuff); lorastr.LoraTxBuff[0] = 0xC1; lorastr.LoraTxBuff[1] = 0xC1; lorastr.LoraTxBuff[2] = 0xC1; status = HAL_UART_Transmit(&LORA_PORT, lorastr.LoraTxBuff,3,100); HAL_Delay(2); if (status == HAL_OK) return true; else return false; }