LOM204A - MEDINDO CONSUMO DE ÁGUA E ENVIANDO VIA LoRaWAN, para TTN.
Baseado no Artigo
SMART WATER: UM PROTÓTIPO PARA MONITORAMENTO DO CONSUMO DE ÁGUA Matheus Eduardo Hoeltgebaum Pereira, Miguel Alexandre Wisintainer, Aurélio Faustino Hoppe – Orientador
O objetivo geral deste BLOG é demonstrar como é possível programar o módulo WISOL LOM204A via KEIL C e assim utilizá-lo como OPENCPU.
O objetivo específico neste projeto é programar o LOM204A para permitir coletar oas medições reais realizadas por um Hidrômetro e via OTAA enviar para um Gateway LoRaWAN da Dragino e finalmente para TTN.
O tradicional sistema de medição de hidrômetros, através de leituristas, apesar de ainda ser
amplamente utilizado pelas empresas que prestam serviço de abastecimento de água, tende a se tornar um
processo cada vez mais inviável ao longo dos anos, devido ao crescimento urbano. Com o objetivo de
buscar uma solução para esta questão, este BLOG apresenta o desenvolvimento de um protótipo para
monitorar o consumo de água e uma aplicação que possibilite ao usuário visualizar o seu consumo. O
presente trabalho também discorre sobre questões técnicas em relação a hidrômetros e o funcionamento do
hardware e da rede LoRaWAN, detalhando os processos de conversão de pulsos emitidos pelos sensores de fluxo, além da utilização do módulo LOM204Apara controle e envio de mensagens através da
rede LoRaWAN.
A água é um recurso essencial para os seres humanos, sendo necessária desde a absorção de alimentos até a
eliminação de resíduos. Todo ser vivo tem que manter seu suprimento de água próximo do
normal, do contrário morre. Um homem pode viver sem alimento sólido por mais de um mês, mas sem água só poderá
viver cerca de dois ou três dias.
Hoje, a sociedade tem acesso à água potável devido ao trabalho realizado por empresas responsáveis pelo
tratamento e distribuição deste recurso. A Agência Nacional de Águas elaborou um estudo em 2010, para
identificar os tipos de empresas que prestavam este serviço de abastecimento. No estudo, verificou-se que a maioria das
empresas são companhias estaduais de saneamento, em 69% dos municípios, enquanto em 27% são entidades
municipais e, em 4%, empresas do setor privado
Para a água chegar até a população, estando própria para consumo, requer-se todo um
processo de obtenção, tratamento, para enfim, possibilitar a distribuição. Primeiramente, deve-se realizar a captura da
água em mananciais, os quais podem ser lagos, rios ou água do subsolo, e logo após, realiza-se um processo de
tratamento dela, a fim de que se torne pura e própria para o consumo
Estando a água disponível para a população, faz-se necessário realizar um controle sobre o consumo, por parte
das distribuidoras, através da obtenção das informações contidas nos hidrômetros das residências. Atualmente, trata-se
de um processo manual, necessitando da presença de uma pessoa responsável por visitar a casa dos consumidores e
cadastrar o valor contido no hidrômetro. Por se tratar de um procedimento que é realizado através de caminhada, acaba
gerando desgaste físico e de tempo, podendo influenciar na qualidade de vida dos funcionários e no atendimento à
população.
O sistema tradicional de leitura de hidrômetros, utilizando-se de leituristas, pode até ser aceitável atualmente,
entretanto, com o crescimento urbano, tende a se tornar um processo cada vez mais complexo e demorado. Assim, a
utilização de microcontroladores podem propiciar o desenvolvimento de soluções que buscam conectar dispositivos em
rede, para o gerenciamento de processos industrias e residenciais. Para viabilizar a leitura de hidrômetros em um curto
espaço de tempo, desenvolveram-se sistemas de medição remota, reduzindo o tempo de leitura e sem nenhum custo de
mão de obra. No Brasil, já existem fornecedores para este novo sistema de medição, embora o seu custo de implantação
seja mais caro do que o sistema tradicional.
A questão do desperdício de água tem causado uma elevada preocupação
na população mundial, pelo crescimento exorbitante das taxas de desperdício, sendo necessário a utilização de
equipamentos que visam evitar que o mesmo aconteça. Desta maneira, demanda-se um ferramental capaz de apresentar
ao usuário o seu consumo em tempo real, para que ele possa controlar o seu gasto desnecessário, algo que ainda não
está presente no Brasil.
Diante do exposto, este trabalho apresenta o desenvolvimento de um protótipo para monitoramento
automatizado do consumo de água em residências. Acredita-se que ele facilitará o processo de coleta de informações,
por parte das empresas que prestam o serviço de distribuição de água e permitirá que o usuário possa acompanhar o seu
consumo de água.
Os hidrômetros são aparelhos que servem para as empresas de saneamento básico realizarem a verificação do
consumo de água por parte dos moradores. Eles possuem um contador, registrando a quantidade de água consumida. O
cálculo é realizado com base na última leitura realizada e a leitura atual.
Os hidrômetros podem ser divididos em duas categorias: residenciais e industriais. Os
primeiros tendem a ser mais pequenos, visto que lidam com volumes menores de água, e terem um princípio de
funcionamento relativamente simples, geralmente baseado em partes móveis. Os segundos, trabalham e precisam
suportar grandes volumes e forças, são geralmente mais robustos e utilizam princípios de funcionamento mais
complexos que tendem a não implicar o envolvimento de partes móveis.
Os hidrômetros residenciais podem ter princípios de funcionamento diferentes, no entanto o seu aspecto
exterior é bastante semelhante. A Figura abaixo mostra um contador de água residencial típico. Ele é composto por um
indicador digital numérico, usualmente exibindo o volume de água consumido, em m3
, e seis totalizadores, ou
ponteiros, apresentando o consumo em frações de m3
. Estes ponteiros são mais orientados para o uso do consumidor
visto que o operador da companhia fornecedora de água, ao registrar o consumo mensal, registra exclusivamente o
indicado valor no mostrador numérico.
Para residências, existem dois tipos principais de hidrômetros: hidrômetros taquimétricos e hidrômetros
volumétricos. O hidrômetro taquimétrico realiza a medição da velocidade pela qual a água atravessa, determinando o
volume consumido. A água passa pelo hidrômetro, em forma de jato (s) e, ao entrar em contato com
uma parte móvel, que pode ser uma turbina, hélice, entre outros, realiza o movimento de rotação. O número de rotações
realizadas por esta parte móvel, após determinado tempo, está relacionado com a quantidade de água consumida.
Dentro da classe de hidrômetros taquimétricos, existem dois tipos: 1) monojatos, no qual a parte móvel é
atingida por um único jato tangencial de água; 2) multijatos, no qual a parte móvel é atingida por vários jatos
tangenciais de água, gerando equilíbrio no movimento de rotação, por atingir pontos igualmente espaçados. Veja a ilustração dos dois tipos de hidrômetros
taquimétricos descritos acima
O funcionamento de hidrômetros taquimétricos monojatos parte do princípio que um único jato de água incide sobre uma pá da hélice existente no hidrômetro, aplicando efeito de rotação sobre a hélice. Assim, considera-se que a velocidade de rotação da hélice está diretamente relacionada com o fluxo de água e qualquer alteração sobre o fluxo pode modificar a curva de erro do hidrômetro. Com relação ao funcionamento de hidrômetros taquimétricos multijatos, o princípio deles consiste em distribuir o fluxo de água ao longo da parte móvel do hidrômetro, gerando jatos simétricos de água e mantendo a hélice em um movimento de equilíbrio. O hidrômetro do tipo multijato tem uma melhor sensibilidade, devido a distribuição de jatos que ocorre dentro dele, não se desgastando tão facilmente e por consequência, tendo uma vida útil maior.
Os hidrômetros volumétricos possuem uma câmara, ao qual internamente existe um componente móvel que
realiza um movimento periódico sempre que a água passa por ela. O período é proporcional ao volume de água
consumido. Este movimento ocorre devido a diferença de pressão antes e depois do hidrômetro,
forçando a água a passar. No Brasil, este tipo de hidrômetro não é utilizado em sistemas de saneamento convencionais,
devido ao alto custo e a facilidade de alojamento de partículas na câmara interna do hidrômetro, deixando o consumidor
sem água. Os dois tipos mais comuns de hidrômetros volumétricos são os de disco oscilante e os de pistão rotativo.
O hidrômetro de disco oscilante possui um disco dentro de sua câmara, na qual a água ultrapassa a câmara
apenas quando o disco realizar uma rotação completa. Como o volume para completar esta rotação é conhecido
previamente, é necessário apenas saber o número de rotações que foram realizadas pelo disco, para identificar a
quantidade de água consumida. Com relação aos hidrômetros de pistão rotativo, eles consistem em
um pistão que separa a câmara em dois compartimentos. O movimento da água permite que o pistão execute rotações,
uma vez que o cálculo do consumo de água está relacionado com o número de rotações realizadas pelo pistão. A Figura abaixo ilustra o funcionamento dos dois tipos de hidrômetros volumétricos comentados anteriormente.
Estes tipos de hidrômetros tendem a ser muito mais precisos, sendo uma de suas principais vantagens o
funcionamento em vazões de água baixas. Entretanto, conforme abordado anteriormente, sua arquitetura torna-os
impróprios para a utilização em serviços de abastecimento, por conta de impurezas que podem estar contidas na água,
afetando o abastecimento ao consumidor. Contudo, caso estejam instalados em condições favoráveis, eles têm uma vida útil mais longa, além do fato da posição de montagem não ser tão importante quanto nos hidrômetros taquimétricos.
Para realizar o processo de coleta do consumo de cada consumidor, as empresas de saneamento contam com os
leituristas, que são profissionais responsáveis por caminharem de residência em residência, identificando os hidrômetros
de cada uma e emitir a fatura ao morador, através de um microcomputador, com base na quantidade de água utilizada.
Também é de responsabilidade deles verificar a instalação do hidrômetro, prestar informações e conferir os dados de
cada domicílio.
REDE LoRaWAN - TTN
A Rede de Coisas é uma iniciativa iniciada pela sociedade civil holandesa. O objetivo é ter redes LoRaWAN instaladas em todas as cidades do mundo. Ao interconectar essas redes locais, a TTN quer construir uma infra-estrutura mundial para facilitar uma Internet das Coisas (IoT) pública.
A The Things Network é o servidor IoT na nuvem utilizado nesse projeto. É um dos servidores gratuitos para LoRaWAN mais utilizados, com mais de 90 mil desenvolvedores, mais de 9 mil gateways de usuários conectados à rede ao redor do mundo e mais de 50 mil aplicações em funcionamento.
A TTN comercializa nós e gateways LoRa e provê treinamento individual e coletivo para empresas e desenvolvedores que desejam utilizar o LoRa. Possui uma comunidade bem ativa nos fóruns, sempre colaborando e ajudando a resolver problemas, além de prover diversos meios de integrar a TTN com a aplicação que se deseja usar. Possui integração nativa com diversas aplicações como: Cayenne (utilizado nesse trabalho), Hypertext Transfer Protocol (HTTP), permitindo ao usuário realizar uplink para um gateway e receber downlink por HTTP, OpenSensors e EVRYTHNG . Caso o usuário queira criar sua própria aplicação, a TTN disponibiliza Application Programming Interface (API) para uso com Message Queuing Telemetry Transport (MQTT) e diversos Software Developer Kits (SDK) para uso com as linguagens Python, Java , Node.Js , NODE-RED e Go
A rede TTN utiliza o protocolo LoRaWAN objetivando uma cobertura em longo alcance para os dispositivos da rede, caracterizando-a assim com uma Wide Area Network (WAN). Devido ao baixo consumo de energia e ao uso da tecnologia LoRa, é chamada de LPWAN (Low Power Wide Area Network). O grande diferencial da TTN é seu estabelecimento como uma rede aberta (open-source) e colaborativa (crowd-sourced), onde qualquer usuário pode contribuir instalando um gateway em sua residência.
Os elementos da TTN são classificados como:
• Endpoints (nós): Os dispositivos responsáveis pela camada de sensoriamento da rede, o endpoint LoRaWAN. Podem coletar informações através de sensores e também acionar dispositivos/máquinas via atuadores. São configurados através de uma das três classes distintas do protocolo LaRaWAN;
• Gateways: Elementos responsáveis por concentrar e processar as informações enviadas pelos endpoints. Os gateways em geral estão conectados a internet, seja por WiFi/Ethernet ou 3G/4G em locais remotos. Mesmo que uma mesma rede LoRaWAN tenha diferentes objetivos, baseados em aplicações distintas, os gateways possuem o objetivo comum de fornecer a maior área de cobertura possível;
• Aplicações: Conectar e interligar os diferentes dispositivos da rede TTN para o fornecimento de informações gerais sobre a coleta de dados dos dispositivos.
CONFIGURAÇÃO AUTENTICAÇÃO NA REDE LoRaWAN
OTAA
• Vantagem: a rede gera e envia as chaves de criptografia; isto torna mais seguro. Devido ao maior nível de segurança, o OTAA é o método mais utilizado em IoT / LoRaWAN.
• AppEUI: Este é um identificador de aplicativo exclusivo usado para agrupar objetos. este
endereço, 64 bits, é usado para classificar os dispositivos periféricos por aplicação. Essa configuração pode seja ajustado.
• DevEUI: Este identificador, configurado de fábrica, torna cada objeto único. Em princípio, esta
configuração não pode ser ajustada.
• AppKey: esta é uma chave secreta compartilhada entre o dispositivo periférico e a rede. É usado para determinar as chaves da sessão. Essa configuração pode ser ajustada.
Concentre-se na OTAA
O Servido de Rede é o componente de software encarregado de estabelecer uma conexão com os objetos e gerenciando o núcleo da rede. Durante a conexão OTAA, e supondo que o dispositivo esteja autorizado a conectar-se a rede, a rede troca chaves de criptografia específicas da sessão com o núcleo da rede. O Servidor de Rede então aloca informações específicas para a sessão e as envia para o aparelho periférico:
• DevAddr: Endereço lógico (equivalente a um endereço IP) que será usado para todos comunicação subseqüente.
• NetSKey (chave de sessão de rede): chave de criptografia entre o objeto e o operador usado para transmissões e para validar a integridade das mensagens.
• AppSKey (chave de sessão do aplicativo): chave de criptografia entre o objeto e operador (através da aplicação) utilizado para as transmissões e para validar a integridade das mensagens
Configurando um gateway LoRaWAN
LG308 é totalmente compatível com o protocolo LoRaWAN. Ele usa o legado “Semtech Packet forward” para encaminhar os pacotes LoRaWAN ao servidor. A estrutura é a abaixo.
Informações do LG308
O método para trabalhar com outros servidores LoRaWAN será semelhante.
Passo 1: Obter uma ID do gateway único.
Cada LG308 tem um ID de porta de entrada única. O ID pode ser encontrada na página LoRaWAN do gateway.
Cada LG308 tem um ID de porta de entrada única. O ID pode ser encontrada na página LoRaWAN do gateway.
Passo 2: Cadastre-se uma conta de usuário no servidor TTN
Clique no ícone Gateways para abrir a página a seguir:
Depois de criar o gateway, você pode ver a informação gateway, como abaixo.
Configurar LG308 para se conectar ao TTN
Agora você pode configurar o LG308 para deixá-lo se conectar à rede TTN.
Verifique se o seu LG308 tem uma conexão com a internet em primeiro lugar.
Passo 1: Configurar LG308 para atuar como despachante de matéria
Passo 2: Entrada de informação do servidor e ID do gateway
Escolha o correto o endereço do servidor e ID gateway.
Resultado da verificação
Depois de fazer as configurações acima, o LG308 deve ser capaz de se conectar ao TTN. Abaixo está o resultado visto de TTN:
Configurar frequência
Depois de fazer as definições acima, o LG308 será capaz de atuar como um gateway LoRaWAN.
Adicionar um dispositivo EndDevice LoRaWan
Esta seção mostra como adicionar um dispositivo EndDevice LoRaWAN à uma rede LoRaWAN e ver os dados de TTN no web site.
O LOM204A foi utilizado como dispositivo de referência - a configuração para outros dispositivos LoRaWAN será semelhante.
Passo 1: Criar uma definição de dispositivos no TTN como exemplo "COLETOR XYY"
Três códigos são necessários para definir o dispositivo em TTN:
DEVEUI - código de identificação único para um dispositivo em particular.
APPEUI - código de identificação para um aplicativo definido no TTN.
APPKey - Chave exclusiva para proteger as comunicações com um dispositivo em particular.
Três códigos são necessários para definir o dispositivo em TTN:
DEVEUI - código de identificação único para um dispositivo em particular.
APPEUI - código de identificação para um aplicativo definido no TTN.
APPKey - Chave exclusiva para proteger as comunicações com um dispositivo em particular.
Um conjunto destes códigos são armazenados em cada dispositivo pelo fabricante como os códigos padrão para esse dispositivo particular. Cada dispositivo é fornecido com uma etiqueta com o EUI dispositivo padrão como mostrado abaixo.
Nota: Você pode ser capaz de alterar estes códigos em um dispositivo usando uma instalação de configuração do dispositivo, por exemplo o LOM204A utiliza um acesso porta série e uma série de comandos AT. Alterar os códigos podem ser necessárias no caso em que você tem que usar os códigos atribuídos por um servidor WAN Lora.
Para o servidor TTN, você pode usar os códigos estabelecidos no dispositivo como no exemplo a seguir.
Selecionar Adicionar aplicativo para abrir a tela abaixo.
Note-se que há uma APPEUI já criado pela TTN, mas esta não é a definida no dispositivo.
Selecionar Devices e Register Device para abrir a tela abaixo.
Nota-se que há uma APP EUI já criado pela TTN, mas esta não é a definida no dispositivo. Para adicionar o APP EUI do dispositivo LOM204A, selecioneApplicationEUI e ApplicationKey no aplicativo LoRAWAN_GUI_CUSTOMER (CLI), em seguida, insira o código necessário. Pode ser Hardcoded depois no projeto implementado no KEIL C.
Passo 2: Ligar dispositivo LOM204A e vai juntar-se automaticamente a rede TTN.
Depois de ingressar com sucesso, ele vai começar a fazer Upload de mensagens para a TTN. Selecione a guia Dados e você vai ver os dados que aparecem no painel.
Note que isso pode levar algum tempo para que os dados do dispositivo para aparecer no visor TTN.
Testado no STARTER KIT LOM204A e também no Breakout LOM204A
Código Fonte
//----------------------------------------------------------------------------
// Project Name : LoRa WAN
//----------------------------------------------------------------------------
// File Name : Main.c
//----------------------------------------------------------------------------
// Processor : STM32L071CZY WLCSP
// Compiler : uVision V5.20.0.0
// RF Transceiver : SX1276
// Frequency : 917 ~ 928Mhz
// Modulation : LoRa
// Version : H/W(1.3), LIB(2.02)
#define MAIN_C_
#include <stddef.h>
#include <string.h>
#include "stm32l0xx_hal.h"
#include <math.h>
#include "board.h"
#include "Utilities.h"
#include "misc.h"
#include "process.h"
#include "timer.h"
#include "init.h"
#include "timer.h"
#include "main.h"
#include "WISOL_API.h"
#include "stm32l0xx_hal_lptim.h"
//lptim reference
LPTIM_HandleTypeDef hlptim1;
//https://community.st.com/s/question/0D53W00000DhAV7/lptimcounterstart-problem
void LPTIM1_Init(void) {
LPTIM_HandleTypeDef* hlptim = &hlptim1;
HAL_NVIC_SetPriority(LPTIM1_IRQn, 2/*0*/, 0);
HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
hlptim->Instance->CFGR |= LPTIM_CFGR_PRELOAD;
/* Enable Autoreload match interrupt */
hlptim->Instance->ICR |= 0x0002; // ARRMCF clear flag
__HAL_LPTIM_ENABLE_IT(hlptim, LPTIM_IT_ARRM);
/* Enable the Peripheral */
__HAL_LPTIM_ENABLE(hlptim);
/* Load the period value in the autoreload register */
__HAL_LPTIM_AUTORELOAD_SET(hlptim, 65535); //65535
/* Start timer in freerun mode */
__HAL_LPTIM_START_CONTINUOUS(hlptim);
}
/**
* @brief LPTIM1 Initialization Function
* @param None
* @retval None
*/
static void MX_LPTIM1_Init(void)
{
/* USER CODE BEGIN LPTIM1_Init 0 */
/* USER CODE END LPTIM1_Init 0 */
/* USER CODE BEGIN LPTIM1_Init 1 */
/* USER CODE END LPTIM1_Init 1 */
hlptim1.Instance = LPTIM1;
hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_ULPTIM;
hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_FALLING; //<======================
hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL;
if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
{
__disable_irq();
}
}
//Uart Para receber LTS
UART_HandleTypeDef huart1;
static void MX_USART1_UART_Init(void)
{
/* USER CODE BEGIN USART1_Init 0 */
/* USER CODE END USART1_Init 0 */
/* USER CODE BEGIN USART1_Init 1 */
/* USER CODE END USART1_Init 1 */
huart1.Instance = USART1;
huart1.Init.BaudRate = 115200;
huart1.Init.WordLength = UART_WORDLENGTH_8B;
huart1.Init.StopBits = UART_STOPBITS_1;
huart1.Init.Parity = UART_PARITY_NONE;
huart1.Init.Mode = UART_MODE_TX_RX;
huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart1.Init.OverSampling = UART_OVERSAMPLING_16;
huart1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart1) != HAL_OK)
{
__disable_irq();
}
/* USER CODE BEGIN USART1_Init 2 */
/* USER CODE END USART1_Init 2 */
}
//LTS CONSUMIDOS E INTERVALO DE WAKEUP
uint32_t LTS;
uint32_t WAKEUP;
void LPTIM1_IRQHandler(void) {
// HAL_LPTIM_IRQHandler(&hlptim1); // ==> HAL_LPTIM_AutoReloadMatchCallback(&hlptim2);
/* Autoreload match interrupt */
if(__HAL_LPTIM_GET_FLAG(&hlptim1, LPTIM_FLAG_ARRM) != RESET)
{
if(__HAL_LPTIM_GET_IT_SOURCE(&hlptim1, LPTIM_IT_ARRM) != RESET)
{
/* Clear Autoreload match flag */
//A cada 65536 contagem de LPTIM, incrementa LTS (16-->XX XX XX XX)
LTS++; //BYTES MAIS SIGNIFICATIVOS
__HAL_LPTIM_CLEAR_FLAG(&hlptim1, LPTIM_FLAG_ARRM);
/* Autoreload match Callback */
}
}
}
//Backup litros consumidos na FLASH
uint8_t eeprom_cnt=0;
uint8_t prt_flag=0;
typedef struct _LORA_EEPROM_tag
{
uint32_t test1;
uint32_t test2;
} lora_eeprom_t;
lora_eeprom_t eeprom;
//Para poder mandar em BCD pela TTN
unsigned char bcd2int(unsigned char bcd)
{
return 10 * (bcd >> 4) + (bcd & 0xF);
}
//CANAIS DE UPLOAD (8)
char* opt1 = "FF00";
char* opt2 = "0000";
char* opt3 = "0000";
char* opt4 = "0000";
char* opt5 = "0000";
char* opt6 = "0000";
#if 1
//---------------------------------------------------------------------------------------------------------
// Example
// CLASS A mode, Confirmed up data(1234567890) transfer every 20 seconds.
// After data transmission , enter sleep mode.
// Run User_fn function when waking up.
// Get Device EUI and Print
//---------------------------------------------------------------------------------------------------------
void User_fn(void)
{
}
//LEITURA DO LPTIM
uint16_t Counter;
//MENSAGEM PARA SER ENVIADA A TTN
unsigned char Msg[32];
//Para não transmitir já quando ligar o LOM204 a primeira vez
unsigned char Wake_Up = 0;
//Para controlar envio TTN depois de 7 dias
unsigned char Days_Flash_Store = 0;
//Status da Transmissao do Pacote depois do JOIN!
unsigned char Status_Transmit;
//Status do JOIN ????
unsigned char Status_JOIN;
//Force Send Data immediately
unsigned char Force_Send_Message_immediately = 0;
//Segundo datasheet leitura nao confiável
uint32_t read_count()
{
uint32_t tmp1, tmp2;
tmp1 = HAL_LPTIM_ReadCounter(&hlptim1); // hlptim1 is a global variable
while ((tmp2 = HAL_LPTIM_ReadCounter(&hlptim1)) != tmp1) tmp1 = tmp2;
return tmp1;
}
//Para leitura de dados via UART
char buff[ 132 ]; //mais null
//#define Um_Dia 1*24*3600*1000
//#define Um_Dia 5*1000
#define Um_Dia 3600*1000
//Gravação na FLASH (BACKUP)
void Gravando_Flash_LTS(void)
{
//PRINTF("---LTS %d---\r\n",LTS);
sprintf(buff, "---LTS %d---\r\n",LTS);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
//Guarda LTS na variavel test1 para gravação na EEPROM!
//PRINTF("---GRAVANDO %d NA FLASH (DESCONTANDO LPTIM)----\r\n",LTS);
sprintf(buff,"---GRAVANDO %d NA FLASH (DESCONTANDO LPTIM)----\r\n",LTS);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
eeprom.test1 = LTS;
nvm_write_user(NVM_USER + offsetof(lora_eeprom_t, test1),(void *)(&eeprom.test1), 4 ); // NVM_USER Address: 0x08080800
//PRINTF("---GRAVADO %d---\r\n",LTS);
sprintf(buff, "---GRAVADO %d---\r\n",LTS);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
}
//Gravação na FLASH (BACKUP)
void Gravando_Flash_WAKEUP(void)
{
//PRINTF("---WAKEUP %d---\r\n",WAKEUP);
sprintf(buff, "---WAKEUP %d---\r\n",WAKEUP);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
//Guarda WAKEUP na variavel test2 para gravação na EEPROM!
//PRINTF("---GRAVANDO %d NA FLASH WAKEUP----\r\n",WAKEUP);
sprintf(buff,"---GRAVANDO %d NA FLASH WAKEUP----\r\n",WAKEUP);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
eeprom.test2 = WAKEUP;
nvm_write_user(NVM_USER + offsetof(lora_eeprom_t, test2),(void *)(&eeprom.test2), 4 ); // NVM_USER Address: 0x08080800
//PRINTF("---GRAVADO---\r\n",WAKEUP);
sprintf(buff,"---GRAVADO %d---\r\n",WAKEUP);
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
}
//Entra em SLEEP
void Sleep()
{
Enable_enter_stop_mode(); // Setting condition for entry into sleep mode.
Device_State_Sleep_Fn(); // GPIO/TImer event check. Enter sleep mode at CLASS A
}
//Mensagens de Parametros
uint8_t LTS_Mens[] = "*****************QUAL A QUANTIDADE DE LITROS NO HIDROMETRO******************\r\n";
uint8_t LTS_Mens_Error[] = "Tamanho pacote invalido, maximo 7 digitos\r\n";
uint8_t WAKEUP_Mens[] = "*****************QUAL INTERVALO PARA WAKEUP (EM SEGUNDOS)******************\r\n";
uint8_t WAKEUP_Mens_Error[] = "Tamanho pacote invalido, maximo 7 digitos\r\n";
uint8_t APP_EUI_Mens[] = "*****************QUAL APPLICATION EUI ******************\r\n";
uint8_t APP_EUI_Mens_Error[] = "Tamanho pacote invalido, tem que ter 16 digitos\r\n";
uint8_t APP_KEY_Mens[] = "*****************QUAL APPLICATION KEY ******************\r\n";
uint8_t APP_KEY_Mens_Error[] = "Tamanho pacote invalido, tem que ter 32 digitos\r\n";
uint8_t TKS_Mens[] = "Obrigado!\r\n";
uint8_t DEVICE_EUI_Info[] = "*****************DEVICE EUI******************\r\n";
uint8_t APP_EUI_Info[] = "*****************APP EUI******************\r\n";
uint8_t APP_KEY_Info[] = "*****************APP KEY******************\r\n";
uint8_t SPLASH[] = "****************Hidrometro****************\r\n*****************Indriya******************\r\n";
uint8_t QNT_LTS_Mens[] = "----LENDO DA FLASH LTS----\r\n";
uint8_t WKP_FLASH_Mens[] = "----LENDO DA FLASH WAKEUP----\r\n";
uint8_t TTN_DOWNLOAD_Mens[] = "----RECEBIDO MENSAGEM LTS VIA TTN PARA FLASH----\r\n";
uint8_t WKP_NOW_Mens[] = "===WAKE UP IMEDIATAMENTE===\r\n";
uint8_t SEND_TTN_Mens[] = "---MANDANDO DADOS TTN---\r\n";
//MAC
uint8_t* res;
//Acordar para fazer JOIN (rand)
uint16_t WAKEUP_JOIN;
//Programa Principal
int main(void)
{
//Init
Start_Init();
//Configuração LPTIM
MX_LPTIM1_Init();
//Configuração LPTIM (Interrupt)
LPTIM1_Init();
//Abre UART1 para recebimento LTS
MX_USART1_UART_Init();
//Splash
//PRINTF("****************Hidrometro****************\r\n");
//PRINTF("*****************Indriya******************\r\n");
HAL_UART_Transmit(&huart1, SPLASH,sizeof(SPLASH), 10);
//Verifica se durante o BOOT, o pino WKUP1 esta em NIVEL ALTO
//Se sim, já força (APÓS JOIN), pegar algum pacote DOWNLOADING
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1)
Force_Send_Message_immediately = 1;
//PRINTF("*****************DEVICE EUI******************\r\n");
HAL_UART_Transmit(&huart1,DEVICE_EUI_Info, sizeof(DEVICE_EUI_Info),10);
res = getDeviceEUI();
sprintf(buff,"Dev Eui :%02x%02x%02x%02x%02x%02x%02x%02x\r\n",res[0],res[1],res[2],res[3],res[4],res[5],res[6],res[7]);
PRINTF(buff);
PRINTF("---- Dev EUI ----\r\n");
HAL_UART_Transmit(&huart1, (uint8_t *) buff,sizeof(buff), 10);
memset( buff, 0, 128 ); //preenche com NULL
//Lendo Application EUI
PRINTF("---- Application EUI %s ----\r\n",getOtaaAppEUI());
//HAL_UART_Transmit(&huart1, APP_EUI_Info,sizeof(APP_EUI_Info), 10);
//Lendo Application Key
PRINTF("---- Application Key %s ----\r\n",getOtaaPseudoAppKey());
//HAL_UART_Transmit(&huart1, APP_KEY_Info,sizeof(APP_KEY_Info), 10);
//Aguarda 5 segundos para receber LTS
//Tem que ser 8 digitos!
//PRINTF("*****************QUAL A QUANTIDADE DE LITROS NO HIDROMETRO******************\r\n");
HAL_UART_Transmit(&huart1, LTS_Mens,sizeof(LTS_Mens), 10);
HAL_UART_Receive( &huart1, (uint8_t *) buff, 32, 5000 );
//pacote nao esta vazio
if(!(strlen(buff)==0))
{
//tamanho igual até 7 digitos Hidrometro tem 7 digitos
if(!(strlen(buff)>7))
{
//String para INT
LTS = atoi(buff);
//Grava Flash
Gravando_Flash_LTS();
//Preenche buff com NULL
memset( buff, 0, 128 );
}
else
{
//PRINTF("Tamanho pacote invalido, maximo 7 digitos\r\n");
HAL_UART_Transmit(&huart1, LTS_Mens,sizeof(LTS_Mens_Error), 10);
}
//PRINTF("*****************QUAL INTERVALO PARA WAKEUP (EM SEGUNDOS)******************\r\n");
HAL_UART_Transmit(&huart1, WAKEUP_Mens,sizeof(WAKEUP_Mens), 10);
HAL_UART_Receive( &huart1,(uint8_t *) buff, 32, 5000 );
//pacote nao esta vazio
if(!(strlen(buff)==0))
{
//tamanho igual até 7 digitos Hidrometro tem 7 digitos
// 604800 (1 semana)
if(!(strlen(buff)>7))
{
//String para INT
WAKEUP = atoi(buff);
//Grava Flash
Gravando_Flash_WAKEUP();
//Preenche buff com NULL
memset( buff, 0, 128 );
}
else
{
//PRINTF("Tamanho pacote invalido, maximo 7 digitos\r\n");
HAL_UART_Transmit(&huart1, WAKEUP_Mens_Error,sizeof(WAKEUP_Mens_Error), 10);
}
}
//PRINTF("*****************QUAL APPLICATION EUI ******************\r\n");
HAL_UART_Transmit(&huart1, APP_EUI_Mens,sizeof(APP_EUI_Mens), 10);
HAL_UART_Receive( &huart1, (uint8_t *) buff, 32, 5000 );
//pacote nao esta vazio
if(!(strlen(buff)==0))
{
//tamanho igual à 16 caracteres
if(!(strlen(buff)<16))
{
setOtaaAppEUI( (uint8_t *) buff, 16 );
memset( buff, 0, 128 );
}
else
{
//PRINTF("Tamanho pacote invalido, tem que ter 16 digitos\r\n");
HAL_UART_Transmit(&huart1, APP_EUI_Mens_Error,sizeof(APP_EUI_Mens_Error), 10);
}
}
//PRINTF("*****************QUAL APPLICATION KEY ******************\r\n");
HAL_UART_Transmit(&huart1, APP_KEY_Mens,sizeof(APP_KEY_Mens), 10);
HAL_UART_Receive( &huart1, (uint8_t *) buff, 32, 5000 );
//pacote nao esta vazio
if(!(strlen(buff)==0))
{
//tamanho igual à 16 caracteres
if(!(strlen(buff)<32))
{
setOtaaPseudoAppKey ((uint8_t *) buff, 32 );
memset( buff, 0, 128 );
}
else
{
//PRINTF("Tamanho pacote invalido, tem que ter 32 digitos\r\n");
HAL_UART_Transmit(&huart1, APP_KEY_Mens_Error,sizeof(APP_KEY_Mens_Error), 10);
}
}
}
//PRINTF("Obrigado!\r\n");
HAL_UART_Transmit(&huart1, TKS_Mens,sizeof(TKS_Mens), 10);
//Le o ultimo valor Armazenado caso ocorra um RESET para troca de bateria
//PRINTF("----LENDO DA FLASH LTS----\r\n");
HAL_UART_Transmit(&huart1, QNT_LTS_Mens,sizeof(QNT_LTS_Mens), 10);
nvm_read_user(NVM_USER + offsetof(lora_eeprom_t, test1), (void *)(&eeprom.test1), 4 );
//SE CHEGUEI NESTE PONTO, SIGNIFICA QUE FOI POR RESET, LPTIM ESTARA COM 0000H
LTS = eeprom.test1;
//
//PRINTF("----LIDO %d LTS----\r\n",LTS);
sprintf(buff, "----LIDO %d LTS----\r\n", LTS);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
//Le o ultimo valor Armazenado caso ocorra um RESET para troca de bateria
//PRINTF("----LENDO DA FLASH WAKEUP----\r\n");
HAL_UART_Transmit(&huart1, WKP_FLASH_Mens, sizeof(WKP_FLASH_Mens), 10);
nvm_read_user(NVM_USER + offsetof(lora_eeprom_t, test2), (void *)(&eeprom.test2), 4 );
WAKEUP = eeprom.test2;
//PRINTF("----LIDO WAKEUP %d SEGUNDOS----\r\n", WAKEUP);
sprintf(buff, "----LIDO WAKEUP %d SEGUNDOS----\r\n", WAKEUP);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
//Class,Mascara de Canais, OTA
setClass( 0 ); // Set CLASS A mode.
setChannelMask(opt1, opt2, opt3, opt4, opt5, opt6);
//Pegue parte do MAC address e use ele como Seed para Rotina de delay
//Mac está em uint8_t* res;
srand(res[6]*256+res[7]);
WAKEUP_JOIN = (((rand() & 0x0003) + 2) * 10) + (rand() & 0x000F); //2X a 6X segundos antes do primeiro JOIN
//PRINTF("----Aguardando %d minuto(s) antes do primeiro JOIN\r\n",WAKEUP_JOIN);
sprintf(buff, "----Aguardando %d segundo(s) antes do primeiro JOIN----\r\n",WAKEUP_JOIN);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
memset( buff, 0, 128 ); //<====TIVE QUE COLOCAR!
//1
Wakeup_Timer(&TxUser,User_fn,WAKEUP_JOIN*1000,0U); // It wakes up after WAKEUP_JOIN seconds before first JOIN
Sleep();
//The Stack try N times!
JOIN_TIME_START(8);
JOIN_START(); // Join start OTA
Status_JOIN = getJoinDoneStatus();
//While not Completed the JOIN
//Join is complited: 0, Join is not complited : 1, BUSY : 2
while(Status_JOIN > 0)
{
WAKEUP_JOIN = (((rand() & 0x0003) + 2) * 10) + (rand() & 0x000F) + (read_count() & 0x000F); //2X a 6X segundos antes do primeiro JOIN + LTS
//PRINTF("----JOIN FALHOU...AGUARDE %d MINUTO(S)----\r\n",WAKEUP_JOIN);
sprintf(buff, "----JOIN FALHOU...AGUARDE %d SEGUNDO(S)----\r\n",WAKEUP_JOIN);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 200);
Wakeup_Timer(&TxUser,User_fn,WAKEUP_JOIN*1000,0U); //give a time do TTN bring up <====RANDOM
Sleep();
JOIN_TIME_START(7);
JOIN_START(); // Join start OTA
Status_JOIN = getJoinDoneStatus();
}
//PRINTF("Status JOIN %d\r\n",Status_JOIN);
sprintf(buff, "Status JOIN %d\r\n",Status_JOIN);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
//Loop infinito
while(true)
{
//while(true)
//{
Counter = read_count(); // hlptim1 is a global variable
//https://www.st.com/resource/en/application_note/dm00290631-lowpower-timer-lptim-applicative-use-cases-on-stm32-microcontrollers-stmicroelectronics.pdf
Counter = Counter + 5;
//BoardGetBatteryLevel();
//Imprime LTS para DEBUG
sprintf(Msg,"%d",LTS+Counter);
//PRINTF("\r\nValor no Hidrometro __%s__%d__\r\n\r\n", Msg, Counter);
sprintf(buff, "\r\nValor no Hidrometro __%s__%d__\r\n\r\n", Msg, Counter);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
//}
CLI_Command_Process(); // To receive CLI command through serial port(UART) (Setup via SERIAL com LoRAWAN_GUI_CUSTOMER
//Recebe quantidade de LTS registrado no Hidrometro (Analogico) Schedule downlink
if( Check_Received_Msg()) // Check for received messages. return value : 1 [SUCCESS], 2: [FAIL], 0: No messages received.
{
//Atualiza Contador Interno
//Como será digitado no TTN XX XX XX XX
//Virá 4 bytes (BCD)
if(rx_msg.payload_size==4)
{
//PRINTF("PORT: %d\r\n",rx_msg.port); // Get the port of the received message.
//PRINTF("----RECEBIDO MENSAGEM LTS VIA TTN PARA FLASH----\r\n");
HAL_UART_Transmit(&huart1, TTN_DOWNLOAD_Mens, sizeof(TTN_DOWNLOAD_Mens), 10);
//78992211 (JÁ EM BCD) 22*100, 99*10000..etc
LTS = (bcd2int(rx_msg.mac_payload[0])*1000000) +
(bcd2int(rx_msg.mac_payload[1])*10000) +
(bcd2int(rx_msg.mac_payload[2])*100) +
(bcd2int(rx_msg.mac_payload[3]));
//Será somente em Fábrica ?
//Desconta o q tem registrado já no LPTIM Timer (o mesmo não se consegue ZERAR)
LTS = LTS - read_count();
//Grava Flash
Gravando_Flash_LTS();
}
}
//Para não começar já transmitindo, a nao ser que faça WAKE UP
if(Wake_Up==0)
{
if(Force_Send_Message_immediately==0)
{
//PRINTF("===WAKE UP DAQUI %d SEGUNDOS===\r\n", WAKEUP);
sprintf(buff, "===WAKE UP DAQUI %d SEGUNDOS===\r\n", WAKEUP);
HAL_UART_Transmit(&huart1, (uint8_t *) buff, sizeof(buff), 10);
Wakeup_Timer(&TxUser,User_fn,WAKEUP*1000,0U); // It wakes up every WAKEUP seconds to FLASH the LTS
}
else
{
//PRINTF("===WAKE UP IMEDIATAMENTE===\r\n");
HAL_UART_Transmit(&huart1,WKP_NOW_Mens, sizeof(WKP_NOW_Mens), 10);
Wakeup_Timer(&TxUser,User_fn,1*1000,0U); // It wakes up in 1 second
Days_Flash_Store = 6; //++ force send Data
}
Wake_Up = 1; //STATE MACHINE
}
else
{
//Pegando LTS e Gravando na FLASH
Counter = read_count();
//PRINTF("---GRAVANDO LTS NA FLASH DEPOIS DE %d SEGUNDOS---\r\n",WAKEUP);
sprintf(buff, "---GRAVANDO LTS NA FLASH DEPOIS DE %d SEGUNDOS---\r\n",WAKEUP);
HAL_UART_Transmit(&huart1,(uint8_t *) buff, sizeof(buff), 10);
//Gravando LTS na FLASH
eeprom.test1 = LTS + Counter;
nvm_write_user(NVM_USER + offsetof(lora_eeprom_t, test1),(void *)(&eeprom.test1), 4 ); // NVM_USER Address: 0x08080800
//PRINTF("---GRAVADO LTS DEPOIS %d DIA---\r\n\r\n",Days_Flash_Store+1);
sprintf(buff, "---GRAVADO LTS DEPOIS %d DIA---\r\n\r\n",Days_Flash_Store+1);
HAL_UART_Transmit(&huart1,(uint8_t *) buff, sizeof(buff), 10);
//Quantas gravações na SEMANA
Days_Flash_Store++;
//A cada 7 dias wake up para enviar LTS para TTN
if(Days_Flash_Store==7)
{
//PRINTF("---MANDANDO DADOS TTN---\r\n");
HAL_UART_Transmit(&huart1,SEND_TTN_Mens, sizeof(SEND_TTN_Mens), 10);
//Sem confirmação!
data_Tx(1,0,1,strlen(Msg),Msg);
//API DONE: 1, FAIL : 2
Status_Transmit = API_MODE(); // Run LoRa protocol.
//Sucesso envio Pacote!
if(Status_Transmit == 1)
{
//PRINTF("===WAKE UP DAQUI %d SEGUNDOS===\r\n",WAKEUP);
sprintf(buff, "===WAKE UP DAQUI %d SEGUNDOS===\r\n",WAKEUP);
HAL_UART_Transmit(&huart1,(uint8_t *) buff, sizeof(buff), 10);
//Sucesso, repete ciclo de 7 dias
Days_Flash_Store=0;
Wakeup_Timer(&TxUser,User_fn,WAKEUP*1000,0U); // It wakes up every WAKEUP seconds to FLASH the LTS
}
//Erro envio Pacotes
else
{
//Temos problema com JOIN e DATA SEND, melhor tentar repetir o ciclo...
Days_Flash_Store = 6; //++
//Faz um WAKE UP imediatamente para tentar JOIN ou transmissao do pacote, ou seja, 1s
Wakeup_Timer(&TxUser,User_fn,1*1000,0U); // Transmit Error, try again imediatly
}
}
else
{
//Prepara Wake up para o proximo dia!
Wakeup_Timer(&TxUser,User_fn,WAKEUP*1000,0U);
}
}
//Entrando em SLEEP, pode sair por Wake up timer ou Wake up externo
Sleep();
//Verifica se a saida do SLEEP foi pelo botao WAKEUP
//Se sim, já força manda LTS para TTN
if(HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0)==1)
{
Force_Send_Message_immediately = 1;
Days_Flash_Store = 6; //++ force send Data
}
}
}
#endif
//Não mexer
void Start_Init(void)
{
HW_SystemClock_Config();
StartNVInit();
BoardInitPeriph( );
BoardInitMcu( );
Var_Init();
sub_process_init(); // set receive mode for uart
TimerInit( &TxNext, Txnext_fn ); // Do not modify
nvm_init(); // To read the configuration saved in EEPROM.
Clr_BIT2();
LDO_on();
}
void Restart_Init(void)
{
BoardInitPeriph( );
BoardInitMcu( );
Var_Init();
sub_process_init(); // set receive mode for uart
TimerInit( &TxNext, Txnext_fn ); // Do not modify
nvm_init(); // To read the configuration saved in EEPROM.
Clr_BIT2();
LDO_on();
}
Hardware
O sensor efeito Hall utilizado foi o drv5032, por causa da Tensão de Trabalho e Consumo (Bateria)
Compilação
Altere em seu Gateway SUB-BAND para 2
//CANAIS DE UPLOAD (8)
char* opt1 = "FF00";
char* opt2 = "0000";
char* opt3 = "0000";
char* opt4 = "0000";
char* opt5 = "0000";
char* opt6 = "0000";
Faça a gravação
Pegue Credenciais OTAA na TTN
Execução
A interação é realizada através de 2 UARTS do LOM204A
Caso os parâmetros não sejam digitados...
Pela UART1 vai solicitar a medição no Hidrômetro, Credenciais e Intervalo de Leitura em segundos (Respeitar Tamanho dos Campos) - Gravado em FLASH
#define Um_Dia 3600*1000
Mostrando dados medidos pelo Hidrômetro - No caso foi escolhido a cada 10 segundos
(no intervalo entra em baixo consumo de Bateria)
Pela UART5 mostrar as Credenciais da TTN e STATUS da conexão (Debug) da Publicação na TTN
POR QUE 5 PULSOS ? SE ZEREI CONTADOR ?
PORQUE LOWPOWER TIME COMEÇA A CONTAR A PARTIR DO 5 PULSO
DOWNLINK para zerar contador de PULSOS
if( Check_Received_Msg()) // Check for received messages. return value : 1 [SUCCESS], 2: [FAIL], 0: No messages received.
{
//Atualiza Contador Interno
//Como será digitado no TTN XX XX XX XX
//Virá 4 bytes (BCD)
if(rx_msg.payload_size==4)
{
//PRINTF("PORT: %d\r\n",rx_msg.port); // Get the port of the received message.
//PRINTF("----RECEBIDO MENSAGEM LTS VIA TTN PARA FLASH----\r\n");
HAL_UART_Transmit(&huart1, TTN_DOWNLOAD_Mens, sizeof(TTN_DOWNLOAD_Mens), 10);
//78992211 (JÁ EM BCD) 22*100, 99*10000..etc
LTS = (bcd2int(rx_msg.mac_payload[0])*1000000) +
(bcd2int(rx_msg.mac_payload[1])*10000) +
(bcd2int(rx_msg.mac_payload[2])*100) +
(bcd2int(rx_msg.mac_payload[3]));
//Será somente em Fábrica ?
//Desconta o q tem registrado já no LPTIM Timer (o mesmo não se consegue ZERAR)
LTS = LTS - read_count();
//Grava Flash
Gravando_Flash_LTS();
}
}
Exemplo de envio do valor BCD 1111 para ser registrado na Flash do LOM204A
Detectado pelo Downlink
LOW POWER TIMER (Contador de Pulsos)
Init
//https://community.st.com/s/question/0D53W00000DhAV7/lptimcounterstart-problem
void LPTIM1_Init(void) {
LPTIM_HandleTypeDef* hlptim = &hlptim1;
HAL_NVIC_SetPriority(LPTIM1_IRQn, 2/*0*/, 0);
HAL_NVIC_EnableIRQ(LPTIM1_IRQn);
hlptim->Instance->CFGR |= LPTIM_CFGR_PRELOAD;
/* Enable Autoreload match interrupt */
hlptim->Instance->ICR |= 0x0002; // ARRMCF clear flag
__HAL_LPTIM_ENABLE_IT(hlptim, LPTIM_IT_ARRM);
/* Enable the Peripheral */
__HAL_LPTIM_ENABLE(hlptim);
/* Load the period value in the autoreload register */
__HAL_LPTIM_AUTORELOAD_SET(hlptim, 65535); //65535
/* Start timer in freerun mode */
__HAL_LPTIM_START_CONTINUOUS(hlptim);
}
static void MX_LPTIM1_Init(void)
{
/* USER CODE BEGIN LPTIM1_Init 0 */
/* USER CODE END LPTIM1_Init 0 */
/* USER CODE BEGIN LPTIM1_Init 1 */
/* USER CODE END LPTIM1_Init 1 */
hlptim1.Instance = LPTIM1;
hlptim1.Init.Clock.Source = LPTIM_CLOCKSOURCE_ULPTIM;
hlptim1.Init.Clock.Prescaler = LPTIM_PRESCALER_DIV1;
hlptim1.Init.UltraLowPowerClock.Polarity = LPTIM_CLOCKPOLARITY_FALLING; //<======================
hlptim1.Init.UltraLowPowerClock.SampleTime = LPTIM_CLOCKSAMPLETIME_DIRECTTRANSITION;
hlptim1.Init.Trigger.Source = LPTIM_TRIGSOURCE_SOFTWARE;
hlptim1.Init.OutputPolarity = LPTIM_OUTPUTPOLARITY_HIGH;
hlptim1.Init.UpdateMode = LPTIM_UPDATE_IMMEDIATE;
hlptim1.Init.CounterSource = LPTIM_COUNTERSOURCE_EXTERNAL;
if (HAL_LPTIM_Init(&hlptim1) != HAL_OK)
{
__disable_irq();
}
}
Handler
void LPTIM1_IRQHandler(void) {
// HAL_LPTIM_IRQHandler(&hlptim1); // ==> HAL_LPTIM_AutoReloadMatchCallback(&hlptim2);
/* Autoreload match interrupt */
if(__HAL_LPTIM_GET_FLAG(&hlptim1, LPTIM_FLAG_ARRM) != RESET)
{
if(__HAL_LPTIM_GET_IT_SOURCE(&hlptim1, LPTIM_IT_ARRM) != RESET)
{
/* Clear Autoreload match flag */
//A cada 65536 contagem de LPTIM, incrementa LTS (16-->XX XX XX XX)
LTS++; //BYTES MAIS SIGNIFICATIVOS
__HAL_LPTIM_CLEAR_FLAG(&hlptim1, LPTIM_FLAG_ARRM);
/* Autoreload match Callback */
}
}
}
Código parcial gerado pelo STM32CubeMX
Fontes:
SMART WATER: UM PROTÓTIPO PARA MONITORAMENTO
DO CONSUMO DE ÁGUA
Dúvidas sobre o código fonte
suporte@smartcore.com.br
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.
Mais detalhes em www.smartcore.com.br
Nenhum comentário:
Postar um comentário