O objetivo deste BLOG é demonstrar como é possível utilizar o VISUINO para programação do WISOL LSM110A. Foi utilizado o Starter Kit LSM110A para o teste. O exemplo permitirá com linhas de comando o envio de texto via LoRA (ABP, AU915) a um servidor MQTT da U_BLOX (ThingStream), via Gateway Dragino, ou seja, não necessário ter um servidor LoRaWAN TTN ou CHIRPSTACK, ou nem mesmo acesso à Internet.
Os parâmetros de acesso ao ABP são passados pela UART e gravados na FLASH
@0000000000000099
$0080E115051FD80A
#FF9F138B40180AA45D6846E0A0146954
%OTA
%ABP <===
&00000000
*00000000000000000000000000000000
+00000000000000000000000000000000
O LSM110A é um módulo de última geração que integra o STMicroelectronics STM32WL. É muito menos consumo atual para o dispositivo IoT para estender a vida útil da bateria. E, também suporta ambas as tecnologias – Sigfox e LoRa – com o próprio módulo LSM110A.
VISUINO
Visuino é o mais recente software inovador da Mitov Software. Um ambiente de programação visual que permite programar suas placas Arduino.
Os componentes encontrados no software Visuino representam seus componentes de hardware e você poderá facilmente criar e projetar seus programas arrastando e soltando. Nenhum equipamento ou hardware é necessário para executar o software no modo de design. Depois de concluir o projeto, você pode conectar o upload da placa Arduino e executá-lo.
Para aquelas pessoas que não são fortes em escrever código, projetar, compilar e criar programas Arduino nunca foi tão fácil! Por que perder tempo codificando quando todo o trabalho duro é feito para você? Você tem sua placa Arduino e um ótimo design de hardware, coloque-a em funcionamento em minutos, não em horas!
Ok, o ambiente de desenvolvimento está pronto. Abra Projeto Visuino abaixo
No CustomCode, Declarations
/**
* This is a an example of the asynchronous API. This sketch is not
* completely asynchronous (see ScheduledAsync.ino for that) and its
* flow still follows the LoRa flow, but this sketch shows how some
* background work can be done while waiting for the LoRa library to
* complete its work.
*
* Revised BSD License - https://spdx.org/licenses/BSD-3-Clause.html
*/
//transmit interval
unsigned long last_tx = 0;
//LoRa LOG
char buffer[256];
HardwareSerial Serial1(PB6, PB7);
STM32LoRaWAN modem;
//Payload Mount
uint8_t payload_size;
char payload[1024];
String setAppEuiString;
String setAppKeyString;
String setDevEuiString;
String OTA_ABP;
String setDevAddrString;
String setNwkSKeyString;
String setAppSKeyString;
/*********************************************************************
* This part of the sketch defines a very simple scheduler and defines
* two tasks that handle the actual work.
*********************************************************************/
struct Task {
unsigned long time; /* When to run, 0 == never */
void (*callback)();
};
enum Tasks {
LORA_WORK_TASK,
LORA_MAINTAIN_TASK,
NUM_TASKS,
};
void do_lora_maintain();
void do_lora_work();
void maintain_needed_callback();
Task tasks[NUM_TASKS] = {
[LORA_WORK_TASK] = {0, do_lora_work},
[LORA_MAINTAIN_TASK] = {0, do_lora_maintain},
};
void run_scheduler()
{
// Super-simple scheduler that just checks all tasks and runs
// any that are due.
for (size_t i = 0; i < NUM_TASKS; ++i) {
if (tasks[i].time != 0 && (int)(millis() - tasks[i].time) >= 0) {
tasks[i].time = 0;
tasks[i].callback();
}
}
}
/*********************************************************************
* This part of the sketch defines the lora work task, which iniates new
* work and the lora_done() function that processes the results.
*********************************************************************/
static const unsigned long TX_INTERVAL = 30000; /* ms */
static const unsigned long RETRY_JOIN_INTERVAL = 5000; /* ms */
enum LoraState {
IDLE,
JOINING,
TRANSMITTING,
};
LoraState lora_state;
void start_join()
{
setAppEuiString = readStringEEPROM(0);
setAppKeyString = readStringEEPROM(17);
setDevEuiString = readStringEEPROM(50);
OTA_ABP = readStringEEPROM(67);
setDevAddrString = readStringEEPROM(71);
setNwkSKeyString = readStringEEPROM(80);
setAppSKeyString = readStringEEPROM(113);
//Serial.println(setAppEuiString);
//Serial.println(setAppKeyString);
//Serial.println(setDevEuiString);
//Serial.println(OTA_ABP);
//Serial.println(setDevAddrString);
//Serial.println(setNwkSKeyString);
//Serial.println(setAppSKeyString);
//found bug on STM32LoRaWAN.h (reported)
//bool setAppEui(String value) { return setDevEui(value.c_str()); }
//bool setAppEui(String value) { return setAppEui(value.c_str()); } //MIGUEL
//@0000000000000099
//$0080E115051FD80A
//#FF9F138B40180AA45D6846E0A0146954
//%OTA
//%ABP
//&00000000
//*00000000000000000000000000000000
//+00000000000000000000000000000000
if(OTA_ABP=="OTA")
{
modem.setAppEui(setAppEuiString); //@
modem.setAppKey(setAppKeyString); //#
modem.setDevEui(setDevEuiString); //$
modem.joinOTAAAsync();
lora_state = JOINING;
}
if(OTA_ABP=="ABP")
{
//bool connected = modem.joinABP(/* DevAddr */ setDevAddrString, /* NwkSKey */ setNwkSKeyString, /* AppSKey */ setAppSKeyString);
bool connected = modem.joinABP(/* DevAddr */ setDevAddrString, /* NwkSKey */ setNwkSKeyString, /* AppSKey */ setAppSKeyString);
if (connected) {
StatusLoRa("Joined");
//Serial.println("Joined");
} else
StatusLoRa("Join failed");
//Serial.println("Join failed");
//while (true) /* infinite loop */;
}
//modem.setDevAddr("00000000"); //&
//modem.setNwkSKey("00000000000000000000000000000000"); //*
//modem.setAppSKey("00000000000000000000000000000000"); //+
//modem.joinABPAsync();
}
void send_packet()
{
String s = String(payload);
payload_size = s.length();
modem.setPort(10);
modem.beginPacket();
modem.write(payload, payload_size);
if(OTA_ABP=="OTA")
{
if (modem.endPacketAsync() == payload_size) {
StatusLoRa("Queued packet");
//Serial.println("Queued packet");
} else {
StatusLoRa("Failed to queue packet");
//Serial.println("Failed to queue packet");
}
lora_state = TRANSMITTING;
}
if(OTA_ABP=="ABP")
{
if (modem.endPacket() == payload_size) {
StatusLoRa("Queued packet");
//Serial.println("Queued packet");
} else {
//Serial.println("Failed to queue packet");
StatusLoRa("Failed to queue packet");
}
lora_state = TRANSMITTING;
}
}
void process_rx()
{
if (modem.available()) {
sprintf(buffer,"Received packet on port %d:",modem.getDownlinkPort());
StatusLoRa(buffer);
//Serial.print("Received packet on port ");
//Serial.print(modem.getDownlinkPort());
//Serial.print(":");
while (modem.available()) {
uint8_t b = modem.read();
sprintf(buffer," %x%x",b >> 4,b & 0xF);
StatusLoRa(buffer);
//Serial.print(" ");
//Serial.print(b >> 4, HEX);
//Serial.print(b & 0xF, HEX);
}
sprintf(buffer,"%c%c",13,10);
StatusLoRa(buffer);
//Serial.println();
}
}
void do_lora_work()
{
// Time to start new work
if (!modem.connected()) {
start_join();
} else {
send_packet();
}
}
void lora_done()
{
// If, after calling maintain() the library is no longer
// busy, then the asynchronous operation has completed,
// so check its results.
if (lora_state == TRANSMITTING) {
StatusLoRa("Sent packet");
//Serial.println("Sent packet");
// Done transmitting
process_rx();
lora_state = IDLE;
// Schedule transmission of next packet
tasks[LORA_WORK_TASK].time = millis() + TX_INTERVAL;
} else if (lora_state == JOINING) {
if (modem.connected()) {
StatusLoRa("Joined");
//Serial.println("Joined");
send_packet();
} else {
StatusLoRa("Join failed");
//Serial.println("Join failed");
lora_state = IDLE;
tasks[LORA_WORK_TASK].time = millis() + RETRY_JOIN_INTERVAL;
}
}
}
/*********************************************************************
* This part of the sketch defines the lora maintain task, which calls
* maintain() to let the lora library do any background work that it
* needs to do. It is called whenever request by the callback.
*********************************************************************/
void do_lora_maintain()
{
modem.maintain();
// If, after calling maintain() the library is no longer
// busy, then the asynchronous operation has completed,
// so check its results.
if (!modem.busy()) {
lora_done();
}
}
void maintain_needed_callback()
{
// This is called from interrupt context, so this must *not*
// call maintain() directly and return as fast as possible.
// So just schedule the maintain task to run ASAP.
tasks[LORA_MAINTAIN_TASK].time = millis();
}
/*********************************************************************
* And this is the entry points of the sketch.
*********************************************************************/
No CustomCode, OnInit
StatusLoRa("Starting");
//Serial.println("Starting");
modem.begin(AU915);
modem.powerdB(22);
modem.dataRate(10); //spread
OTA_ABP = readStringEEPROM(67);
if(OTA_ABP=="OTA")
modem.setMaintainNeededCallback(maintain_needed_callback);
do_lora_work();
No CustomCode, OnExecute
if(OTA_ABP=="OTA")
{
run_scheduler();
}
if(OTA_ABP=="ABP")
{
if (!last_tx || millis() - last_tx > TX_INTERVAL) {
do_lora_work();
//send_packet();
last_tx = millis();
}
}
No CustomCode, Global Implementations
//https://roboticsbackend.com/arduino-write-string-in-eeprom/
//FIRST BYTE IS THE LENGHT
String readStringEEPROM(int addrOffset)
{
int newStrLen = EEPROM.read(addrOffset);
char data[newStrLen + 1];
for (int i = 0; i < newStrLen; i++)
{
data[i] = EEPROM.read(addrOffset + 1 + i);
}
data[newStrLen] = 0; //NULL
return String(data);
}
void StatusLoRa(String Txt)
{
Declarations::Instances::LoRaWAN.LoRaWANStatus.Send(Txt);
}
No CustomCode, Includes
#include <STM32LoRaWAN.h>
Compilando
Pacote a ser enviado
Qualquer texto não comece com @#$%, é identificado como no novo pacote a ser enviado
Executando
Log - System Log (Dragino)
Wed Nov 30 11:11:59 2022 daemon.info lora_pkt_fwd[307]: PKT_FWD~ DATA_CONF_UP-> {"DevAddr": "00000000", "FCtrl": ["ADR": 0, "ADRACKReq": 0, "ACK": 0, "RFU" : "RFU", "FOptsLen": 0], "FCnt": 0, "FPort": 2, "MIC": "B1F93D67"}
Wed Nov 30 11:11:59 2022 daemon.info lora_pkt_fwd[307]: RXTX~ {"rxpk":[{"tmst":248124740,"time":"2022-11-30T14:11:59.008966Z","chan":1,"rfch":0,"freq":917.000000,"stat":1,"modu":"LORA","datr":"SF12BW125","codr":"4/5","lsnr":10.5,"rssi":-90,"size":18,"data":"gAAAAAAAAAACvR2eYW9nPfmx"}]}
Dados no THINGSTREAM
Para ver os dados, acompanhe o vídeo a partir do tempo 07:19
MONTAGEM
DÚVIDAS
suporte@smartcore.com.br
REFERÊNCIAS
ATENÇÃO: RTC BACKUP (generic_clock.c)
C:\Users\Usuario\AppData\Local\arduino15\packages\STMicroelectronics\hardware\stm32\2.6.0\variants\STM32WLxx\WL54JCI_WL55JCI_WLE4J(8-B-C)I_WLE5J(8-B-C)I
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
HAL_PWR_EnableBkUpAccess();
__HAL_RCC_LSEDRIVE_CONFIG(RCC_LSEDRIVE_LOW);
__HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE2);
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI|RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.LSEState = RCC_LSE_ON;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK3|RCC_CLOCKTYPE_HCLK
|RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_PCLK1
|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.AHBCLK3Divider = RCC_SYSCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
Sobre a SMARTCORE
A SmartCore fornece módulos para comunicação wireless, biometria, conectividade, rastreamento e automação.
Nosso portfólio inclui modem 2G/3G/4G/NB-IoT/Cat.M, satelital, módulos WiFi, Bluetooth, GNSS / GPS, Sigfox, LoRa, leitor de cartão, leitor QR code, mecanismo de impressão, mini-board PC, antena, pigtail, LCD, bateria, repetidor GPS e sensores.
Nenhum comentário:
Postar um comentário