U-BLOX NINA B302 RODANDO MODBUS TCP SERVER E SENDO ACESSADO VIA WAN COM SCADA - GESTURE
O objetivo deste BLOG é demonstrar como é possível utilizar o ARDUINO para programar o módulo U-BLOX NINA B302 e transformá-lo num servidor MODBUS TCP, e então ser acessado via cliente SCADA LAquis pela rede WAN sem se preocupar com detalhes de configuração do NAT.
Valores para 2 Input Registers e 1 Coil serão Random.
Um BUTTON no SCADA acionará um segundo Coil.
Um terceiro Input Register será alterado com o estado do sensor APDS9960 (Gesture):
Movimento para direita fará com que este último Input Register incremente, para esquerda decremente e para cima zerar.
MODBUS
Modbus é um Protocolo de comunicação de dados utilizado em sistemas de automação industrial. Criado originalmente no final da década de 1970, mais especificamente em 1979, pela fabricante de equipamentos Modicon. É um dos mais antigos e até hoje mais utilizados[2] protocolos em redes de Controladores lógicos programáveis (PLC) para aquisição de sinais(0 ou 1) de instrumentos e comandar atuadores. A Schneider Electric (atual controladora da Modicon) transferiu os direitos do protocolo para a Modbus Organization em 2004 e a utilização é livre de taxas de licenciamento.Por esta razão, e também por se adequar facilmente a diversos meios físicos, é utilizado em milhares de equipamentos existentes e é uma das soluções de rede mais baratas a serem utilizadas em Automação Industrial.
Originalmente implementado como um protocolo de nível de aplicação destinado a transferir dados por uma camada serial, o Modbus foi ampliado para incluir implementações em comunicações seriais, TCP/IP e UDP (user datagram protocol).
O Modbus é um protocolo de requisição-resposta que utiliza um relacionamento mestre-escravo. Em um relacionamento mestre-escravo, a comunicação sempre ocorre em pares — um dispositivo deve iniciar a requisição e então aguardar por uma resposta — e o dispositivo iniciador (o mestre) é responsável por iniciar cada interação. Tipicamente, o mestre é uma interface homem-máquina (IHM) ou sistema SCADA (Supervisory Control and Data Acquisition) e o escravo é um sensor, controlador lógico programável (CLP) ou controlador programável para automação (CPA). O conteúdo dessas requisições e respostas e as camadas de rede pelas quais essas mensagens são enviadas são definidos pelas diferentes camadas do protocolo.
Acesso aos dados no Modbus e o modelo de dados do Modbus
Os dados que podem ser acessados pelo Modbus são armazenados, de forma geral, em um dos quatro bancos de dados, ou faixas de endereço: coils, entradas discretas, registradores holding e registradores de entrada. Como ocorre com muitas partes da especificação, esses nomes podem variar, dependendo da indústria ou aplicação. Por exemplo, os registradores holding podem ser denominados registradores de saída, e os coils podem ser referidos como saídas digitais ou discretas. Esses bancos de dados definem o tipo e os direitos de acesso dos dados contidos. Os dispositivos escravo têm acesso direto a esses dados, que são hospedados localmente nos dispositivos. Os dados que podem ser acessados pelo Modbus são de forma geral um subconjunto da memória principal do dispositivo. Por outro lado, os mestres Modbus precisam solicitar acesso a esses dados, utilizando diversos códigos de função
Endereçamento do modelo de dados
A especificação define que cada bloco contém um espaço de endereçamento de até 65.536 (216) elementos. Com a definição da PDU, o Modbus define o endereço de cada elemento de dados na faixa de 0 a 65.535. Entretanto, cada elemento de dados é numerado de 1 a n, onde n tem o valor máximo de 65.536. Assim, o coil 1 está no endereço 0 do bloco de coils, enquanto que o registrador holding 54 está no endereço 53 da seção de memória reservada pelo escravo para os registradores holding.
Não é obrigatório implementar as faixas completas permitidas pela especificação no dispositivo. Por exemplo, pode ser escolhido para um dado dispositivo não implementar coils, entradas discretas ou registradores de entrada e, em vez disso, utilizar registradores holding de 150 a 175 e 200 a 225. Isso é perfeitamente aceitável; nesse caso, tentativas de acesso inválidas seriam tratadas por exceções.
Faixas de endereçamento de dados
Embora a especificação defina que diferentes tipos de dados devem existir em blocos diferentes e atribua uma faixa de endereços local para cada tipo, isso não implica que haverá necessariamente um esquema de endereçamento intuitivo ou facilmente compreensível para a documentação da memória que pode ser acessada pelo Modbus para um determinado dispositivo. Para simplificar a discussão sobre as posições dos blocos de memória, foi introduzido um esquema de numeração que inclui prefixos ao endereço dos dados em questão.
Por exemplo, em vez de se referir a um item como registrador holding 14 no endereço 13, o manual do dispositivo pode se referir a um item de dados no endereço 4.014, 40.014 ou 400.014. Em todos esses casos, o primeiro número especificado é 4, que representa os registradores holding; os demais números especificam um endereço. A diferença entre 4XXX, 4XXXX e 4XXXXX depende do espaço de endereços utilizado pelo dispositivo. Se todos os 65.536 registradores estiverem em uso, utilizaremos a notação 4XXXXX, pois ela permite o uso da faixa de 400.001 a 465.536. Se apenas alguns registradores forem usados, uma prática comum é usar a faixa de 4.001 a 4.999.
Maiores detalhes neste excelente LINK
MODBUS TCP (Utilizado)
Modbus TCP/IP, também conhecido como Modbus-TCP é simplesmente o protocolo Modbus RTU com uma interface TCP que é executada na Ethernet.
TCP/IP chamado de Protocolo de Controle de Transmissão e Protocolo de Internet, que fornece o meio de transmissão para mensagens Modbus TCP/IP.
O TCP/IP facilita um grande número de conexões simultâneas, por isso é a escolha do iniciador se reconectar uma conexão ou reutilizar uma conexão vivida.
LAquis
MODBUS SCADA
O que significa o SCADA?
SCADA significa: Supervisory Control and Data Acquisition. Os sistemas SCADA são usados principalmente para aquisição de dados de automação industrial e controle de processos usando tecnologia PLC ou equipamento RTU com comunicação em um sistema de controle distribuído (DCS) dentro do sistema de controle industrial (ICS). Essa tecnologia auxilia o gerenciamento do processo industrial em tempo real. No software SCADA, uma interface de usuário é projetada em um computador para monitorar e controlar o processo. Relatórios personalizados podem ser gerados com os dados de armazenamento para mostrar o cálculo e as informações estatísticas de gerenciamento e a qualidade do processo. Os sistemas SCADA devem ter um alto nível de segurança. A segurança é uma questão importante dentro dos sistemas SCADA, de forma que tanto a rede quanto o sistema tenham proteções sobre o processo industrial. Eles reúnem os dados da rede de equipamentos industriais em tempo real e fornecem monitoramento, alarmes e relatórios estatísticos e de qualidade. Cada projeto pode ser editado por um usuário ou projetado por um engenheiro. Esses dados de processo também podem ser distribuídos na rede de computadores usando o conceito de internet das coisas industrial (IIOT).
A solução do sistema LAquis SCADA é uma ferramenta e software de linguagem para aquisição de dados, controle, supervisão de processos, automação, armazenamento, geração de relatórios e desenvolvimento de aplicações. Definir tags (pontos de I / O), equipamentos (módulos, dispositivos, PLC, IIOT, ...), DCS (sistema de controle distribuído), variáveis, bancos de dados, propriedades customizáveis, interfaces visuais HMI SCADA, relatórios customizáveis até processos avançados através de um linguagem de programação de scripts orientada para automação industrial. Baixe o LAquis SCADA aqui.
GESTOS
O sensor de gestos é amplamente utilizado e fortemente estudado em todo o mundo. Como resultado, a maioria dos smartphones tem uma característica de usar o controle de gestos hoje em dia, em vez de usar botões. O controle de gestos sem toque é uma fronteira no mundo das interfaces homem-máquina. Você pode controlar as coisas principais sentindo o toque com a ajuda deste sensor.
APDS-9960
O sensor de gestos APDS-9960 é um sensor multifuncional. É um sensor ir. Ele pode detectar os gestos, a luz ambiente e os valores RGB na luz. Ele se comunica com outros dispositivos através do protocolo I2C. A tensão necessária para este sensor é de 3.3V.
Gesto | Descrição |
---|---|
UP | Deslize da parte inferior da placa para o topo e fora do alcance do sensor. Certifique-se de que seu pulso / braço não esteja na faixa do sensor no final da passagem! |
DOWN | Deslize de cima para baixo no quadro e fora do alcance do sensor. |
LEFT | Deslize do lado direito da placa para a esquerda e fora do alcance do sensor. |
RIGHT | Deslize do lado esquerdo do tabuleiro para a direita e fora do alcance do sensor. |
NEAR | Começa muito acima do sensor, move-se perto do sensor, paira por pelo menos 1 segundo e se move fora do alcance do sensor |
FAR | O objeto começa perto do sensor, paira por pelo menos 1 segundo e depois se move acima e fora do alcance do sensor |
NONE | O sensor não conseguiu adivinhar corretamente o gesto que está sendo executado. |
W5500
O chip W5500 é um controlador Ethernet integrado TCP/IP com fio que permite uma conexão mais fácil com a Internet para sistemas embarcados usando SPI (Interface Periférica Serial).
UPnP
Por que precisamos dessa biblioteca UPnP_Generic ?
Características
Muitos de nós estamos manualmente encaminhando a porta no Internet Gateway Device (IGD, Router) a fim de fornecer acesso aos Serviços Web locais da Internet.
Esta biblioteca fornece a maneira mais fácil de avançar automaticamente usando o Simple Service Discovery Protocol (SSDP), rodando no nRF52.
O SSDP é usado para publicidade e descoberta de serviços de rede e informações de presença. Ele realiza a tarefa sem assistência de mecanismos de configuração baseados em servidor, como O Dynamic Host Configuration Protocol (DHCP) ou DNS (Domain Name System) e sem configuração estática especial de um host de rede. O SSDP é a base do protocolo de descoberta do Universal Plug and Play (UPnP) e destina-se a ser usado em ambientes residenciais ou de pequeno porte.
O tempo entre as verificações para atualizar os Mapeamentos de Porta UPnP é configurável para corresponder ao seu caso de uso, e é definido nos exemplos em 10 minutos. O LEASE_DURATION também é configurável e padrão para 10hrs (36000s). O Nome do Servidor Virtual também pode ser especificado no esboço e é mostrado no IGD, por exemplo, NRF52-W5X00
Instalando Arduino Adafruit no NINA B302
Abaixo o roteiro para você seguir:
Baixe e instale o Arduino IDE
Inicie o Arduino IDE, vá em Preferências e adicione
https://www.adafruit.com/package_adafruit_index.json
como "URL adicional do gerenciador de pastas"
Abra o Boards Manager no menu Tools -> Board e instale o "Adafruit nRF52 by Adafruit"
Selecione sua placa nRF5 no menu Ferramentas -> Placa
Adafruit Bluefruit nRF52 Feather
OBSERVAÇÃO: Durante a instalação, o Arduino IDE leva alguns minutos para extrair as ferramentas após o download, por favor, seja paciente.
Gravando bootloader da Adafruit
Use o gravador SEGGER JLINK para gravar o BREAKOUT com módulo NINA B302, conecte nos pinos do SWCLK (pino 7) e SWDIO (pino 9) do SEGGER JLINK nos pinos SWDCLK e SWDIO do BREAKOUT(pinos nas laterais, próximo à antena). Não esquecer de ligar os GND do BREAKOUT no GND do SEGGER JTAG, bem como alimentar o BREAKOUT com 3.3V.
Ligue os pinos SWD DIO e CLK ...
Abra J-FLASH lite e grave o bootloader da Adafruit
Mudar NRF52840
O mesmo se encontra em
....\packages\adafruit\hardware\nrf52\0.19.0\bootloader\feather_nrf52840_express
Compile depois para o NINA B302
Com ele, você poderá transferir programas via DFU USB. Maiores detalhes sobre este bootloader
Segundo a documentação, se você pressionar o reset, o módulo aguardará por um certo tempo se há algo sendo enviado pelo Arduino, ou seja, o programa a ser gravado via DFU.
ATENÇÃO, o bootloader usa USB para gravação do NINA 302, OU SEJA, CRIA UMA COMM VIRTUAL, TAMBÉM PARA SER A SERIAL PADRÃO DO ARDUINO
INSTALE OS DRIVERS
Conecte na USB + e USB - um cabo USB, AGUARDE INSTALAR OS DRIVERS
Baixe e instale o Arduino IDE
Inicie o Arduino IDE, vá em Preferências e adicione
https://www.adafruit.com/package_adafruit_index.json
Inicie o Arduino IDE, vá em Preferências e adicione
https://www.adafruit.com/package_adafruit_index.json
como "URL adicional do gerenciador de pastas"
Abra o Boards Manager no menu Tools -> Board e instale o "Adafruit nRF52 by Adafruit"
Selecione sua placa nRF5 no menu Ferramentas -> Placa
Adafruit Bluefruit nRF52 Feather
Abra o Boards Manager no menu Tools -> Board e instale o "Adafruit nRF52 by Adafruit"
Selecione sua placa nRF5 no menu Ferramentas -> Placa
Adafruit Bluefruit nRF52 Feather
OBSERVAÇÃO: Durante a instalação, o Arduino IDE leva alguns minutos para extrair as
ferramentas após o download, por favor, seja paciente.
Use o gravador SEGGER JLINK para gravar o BREAKOUT com módulo NINA B302, conecte nos pinos
do SWCLK (pino 7) e SWDIO (pino 9) do SEGGER JLINK nos pinos SWDCLK e SWDIO do BREAKOUT
(pinos nas laterais, próximo à antena). Não esquecer de ligar os GND do BREAKOUT no GND do SEGGER
JTAG, bem como alimentar o BREAKOUT com 3.3V.
Ligue os pinos SWD DIO e CLK ...
Abra J-FLASH lite e grave o bootloader da Adafruit
Mudar NRF52840
O mesmo se encontra em
....\packages\adafruit\hardware\nrf52\0.19.0\bootloader\feather_nrf52840_express
Compile depois para o NINA B302
Com ele, você poderá transferir programas via DFU USB. Maiores detalhes sobre este bootloader
Segundo a documentação, se você pressionar o reset, o módulo aguardará por um certo tempo
se há algo sendo enviado pelo Arduino, ou seja, o programa a ser gravado via DFU.
ATENÇÃO, o bootloader usa USB para gravação do NINA 302, OU SEJA, CRIA UMA COMM VIRTUAL,
TAMBÉM PARA SER A SERIAL PADRÃO DO ARDUINO
INSTALE OS DRIVERS
Conecte na USB + e USB - um cabo USB, AGUARDE INSTALAR OS DRIVERS
ÓTIMA REFERÊNCIA PARA PINOS DO ARDUINO E PINOS (GPIOS) DO NINA B302
Consulte
Conexão com NINA B302 e W5500
Conexão com NINA B302 e GESTURE SENSOR
#define PIN_WIRE_SDA (20)#define PIN_WIRE_SCL (21)
INSTALE LIB e pré-requisitosEsta biblioteca implementa o protocolo Modbus em dois diferentes tipos de transporte: comunicação serial sobre RS485 com RTU (Remote Terminal Unit) ou Ethernet e comunicação WiFi com protocolo TCP. Existem algumas diferenças nas APIs dependendo do transporte, mas a maioria das funções é a mesma para ambos.Modbus também é um protocolo cliente-servidor onde Cliente = mestre e Servidor = escravo na terminilogia Modbus; sugerimos ler alguns artigos sobre este protocolo se você não tiver nenhuma experiência anterior, pois ele se baseia fortemente em algumas convenções formais.Organizamos esta referência para que você encontre as funções comuns de ambos os transportes juntos e apenas as funções relacionadas ao transporte são fornecidas individualmente. Como regra geral, a comunicação RTU é multiponto e, portanto, o ID da unidade envolvida na comunicação precisa ser especificado. O TCP é ponto a ponto usando o endereço IP e, portanto, não há necessidade de um ID nos parâmetros.e o mais importanteLeia o README
Thanks to Khoi Hoang, a great person, a great programmer!
Altere define.h no programa fonte abaixo!
// Only one if the following to be true
#define USE_ETHERNET true
#define USE_ETHERNET2 false //true
#define USE_ETHERNET3 false //true
#define USE_ETHERNET_LARGE false
#define USE_ETHERNET_ESP8266 false //true
#define USE_ETHERNET_ENC false
Compile o programa NRF52_Simple_Server e pressione o botão para gravar.
E altere no INO
DDNSGeneric.client("xxxxxxxxx.duckdns.org", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
Necessário criar URL no DuckDNS
Segue código Alterado (Upnp e MODBUS TCP SERVER) juntos
/**************************************************** ***************************************************** ****************************
nRF52_LED_GESTURE_MODBUS_Server.ino
For all Generic boards such as ESP8266, ESP32, WT32_ETH01, SAMD21/SAMD51, nRF52, STM32F/L/H/G/WB/MP1,Teensy
with WiFiNINA, ESP8266/ESP32 WiFi, ESP8266/ESP32-AT, W5x00, ENC28J60, Native Ethernet shields
DDNS_Generic is a library to automatically add port mappings to router using UPnP SSDP
(Simple Service Discovery Protocol) in order to provide access to local Web Services from the Internet.
Based on and modified from Ofek Pearl's TinyUPnP Library (https://github.com/ofekp/TinyUPnP)
Built by Khoi Hoang https://github.com/khoih-prog/UPnP_Generic
Licensed under GPL-3.0 license
Version: 3.3.1
Based on EthenetModbusServerLED
https://www.arduino.cc/en/ArduinoModbus/ArduinoModbus
Version Modified By Date Comments
------- ----------- ---------- -----------
3.1.4 K Hoang 23/09/2020 Initial coding for Generic boards using many WiFi/Ethernet modules/shields.
3.1.5 K Hoang 28/09/2020 Fix issue with nRF52 and STM32F/L/H/G/WB/MP1 using ESP8266/ESP32-AT
3.2.0 K Hoang 11/06/2021 Add support to RP2040-based boards using ESP-AT, WiFiNINA, W5x00 / ENC28J60
3.3.0 K Hoang 16/07/2021 Add support to WT32_ETH01 (ESP32 + LAN8720)
3.3.1 M Wisintainer 22/07/2021 Add Modbus example
***************************************************** ***************************************************** ****************************/ /*
Note: This example uses the DDNS_Generic library (https://github.com/khoih-prog/DDNS_Generic)
You can access this WebServer by either localIP:LISTEN_PORT such as 192.169.2.100:5953/?percentage=20
or DDNS_Host:LISTEN_PORT, such as account.duckdns.org:5953/?percentage=20
*/
#include "defines.h"
#define UPNP_USING_ETHERNET true
#include <UPnP_Generic.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include "Adafruit_APDS9960.h"
int Gesture_Cont = 0;
Adafruit_APDS9960 apds;
#define LISTEN_PORT 502
#define LEASE_DURATION 36000 // seconds
#define FRIENDLY_NAME "NRF52-MODBUS-W5X00" // this name will appear in your router port forwarding section
EthernetServer EthServer ( LISTEN_PORT );
ModbusTCPServer modbusTCPServer ;
UPnP * uPnP ;
#if defined(LED_BLUE)
#define LED_PIN LED_BLUE // BLUE_LED on nRF52840 Feather Express, Itsy-Bitsy
#else
#define LED_PIN 3 // RED LED
#endif
#define LED_PIN2 16 //SECOND LED IO27
void onUpdateCallback ( const char * oldIP , const char * newIP )
{
Serial.print ( F ( "DDNSGeneric - IP Change Detected: " ));
Serial.println ( newIP );
}
void LEDOn ( void )
{
digitalWrite ( LED_PIN , HIGH );
}
void LEDOff ( void )
{
digitalWrite ( LED_PIN , LOW );
}
void LEDOn2 ( void )
{
digitalWrite ( LED_PIN2 , HIGH );
}
void LEDOff2 ( void )
{
digitalWrite ( LED_PIN2 , LOW );
}
void showLED ( void )
{
for ( int i = 0 ; i < 5 ; i ++)
{
LEDOn ();
delay ( 100 );
LEDOff ();
delay ( 100 );
}
}
bool s = false;
unsigned long Coil_Write_Time ;
void updateLED ()
{
// read the current value of the coil
int coilValue = modbusTCPServer . coilRead ( 0x00 );
if ( coilValue == 1 )
{
// coil value set, turn LED on
LEDOn ();
}
else if ( coilValue == 0 )
{
// coil value set, turn LED on
LEDOff ();
}
//using the second coil to control LED when receive a Write command from SCADA
coilValue = modbusTCPServer . coilRead ( 0x01 );
if(coilValue == 1)
LEDOn2();
if(coilValue == 0)
LEDOff2();
if ( millis ( ) > Coil_Write_Time )
{
modbusTCPServer . coilWrite ( 0x00 , s );
s = ! s ;
Coil_Write_Time = millis () + 1000 ;
//Simulate Reading data to send to SCADA
modbusTCPServer.inputRegisterWrite( 0x00, random(0,1000) );
modbusTCPServer.inputRegisterWrite( 0x01, random(0,1000) );
modbusTCPServer.inputRegisterWrite( 0x02, Gesture_Cont );
}
}
void setup ( void )
{
Serial.begin( 115200 );
while (! Serial );
Serial.println("Start...");
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);
//second LED
pinMode ( LED_PIN2, OUTPUT );
pinMode ( LED_PIN , OUTPUT );
showLED ();
Serial.print("\nStart nRF52_LED_MODBUS_Server on "); Serial.print(BOARD_NAME);
Serial.print(" using "); Serial.println(SHIELD_TYPE);
Serial.println(UPNP_GENERIC_VERSION);
ET_LOGWARN3(F("Board :"), BOARD_NAME, F(", setCsPin:"), USE_THIS_SS_PIN);
ET_LOGWARN(F("Default SPI pinout:"));
ET_LOGWARN1(F("MOSI:"), MOSI);
ET_LOGWARN1(F("MISO:"), MISO);
ET_LOGWARN1(F("SCK:"), SCK);
ET_LOGWARN1(F("SS:"), SS);
ET_LOGWARN(F("========================="));
#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET)
// For other boards, to change if necessary
#if ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
// Must use library patch for Ethernet, Ethernet2, EthernetLarge libraries
Ethernet.init (USE_THIS_SS_PIN);
#elif USE_ETHERNET3
// Use MAX_SOCK_NUM = 4 for 4K, 2 for 8K, 1 for 16K RX/TX buffer
#ifndef ETHERNET3_MAX_SOCK_NUM
#define ETHERNET3_MAX_SOCK_NUM 4
#endif
Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (ETHERNET3_MAX_SOCK_NUM);
#elif USE_CUSTOM_ETHERNET
// You have to add initialization for your Custom Ethernet here
// This is just an example to setCSPin to USE_THIS_SS_PIN, and can be not correct and enough
//Ethernet.init(USE_THIS_SS_PIN);
#endif //( ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
#endif
// start the ethernet connection and the server:
// Use DHCP dynamic IP and random mac
uint16_t index = millis() % NUMBER_OF_MAC;
// Use Static IP
//Ethernet.begin(mac[index], ip);
Ethernet.begin(mac[index]);
IPAddress localIP = Ethernet.localIP();
////////////////
DDNSGeneric.service ( "duckdns" ); // Enter your DDNS Service Name - "duckdns" / "noip"
/*
For DDNS Providers where you get a token:
DDNSGeneric.client("domain", "token");
For DDNS Providers where you get username and password: ( Leave the password field empty "" if not required )
DDNSGeneric.client("domain", "username", "password");
*/
DDNSGeneric.client("xxxxxxxxxxx.duckdns.org", "94a6dc4f-2102-4d96-88c8-5622d04597bd");
DDNSGeneric.onUpdate ( onUpdateCallback );
////////////////
uPnP = new UPnP(60000); // -1 means blocking, preferably, use a timeout value (ms)
if (uPnP)
{
uPnP->addPortMappingConfig(localIP, LISTEN_PORT, RULE_PROTOCOL_TCP, LEASE_DURATION, FRIENDLY_NAME);
bool portMappingAdded = false;
#define RETRY_TIMES 4
int retries = 0;
while (!portMappingAdded && (retries < RETRY_TIMES))
{
Serial.println("Add Port Forwarding, Try # " + String(++retries));
int result = uPnP->commitPortMappings();
portMappingAdded = ( (result == PORT_MAP_SUCCESS) || (result == ALREADY_MAPPED) );
//Serial.println("commitPortMappings result =" + String(result));
if (!portMappingAdded)
{
// for debugging, you can see this in your router too under forwarding or UPnP
//uPnP->printAllPortMappings();
//Serial.println(F("This was printed because adding the required port mapping failed"));
if (retries < RETRY_TIMES)
delay(10000); // 10 seconds before trying again
}
}
uPnP->printAllPortMappings();
Serial.println(F("\nUPnP done"));
}
showLED();
EthServer . begin ();
Serial.print ( F ( "Modbus server is @ IP : " ));
Serial.print ( localIP );
Serial.print ( F ( ", port = " ));
Serial.println ( LISTEN_PORT );
Serial.print ( F ( "Gateway Address: " ));
Serial.println ( Ethernet . gatewayIP ());
Serial.print ( F ( "Network Mask: " ));
Serial.println ( Ethernet . subnetMask ());
// start the Modbus TCP server
if (! modbusTCPServer.begin ())
{
Serial.println ( "Failed to start Modbus TCP Server!" );
while ( 1 );
}
// set two coil at address 0x00 and 0x01
Serial.println ( "Configure two coil at address 0x00" );
modbusTCPServer.configureCoils ( 0x00 , 2 );
// set three input register at address 0x00, 0x01, 0x02
Serial.println ( "Configure two input register at address 0x00" );
modbusTCPServer.configureInputRegisters(0x00, 3);
Coil_Write_Time = millis () + 1000 ;
}
void loop(void)
{
DDNSGeneric.update(300000);
uPnP->updatePortMappings(600000); // 10 minutes
EthernetClient client = EthServer.available ();
if ( client )
{
// a new client connected
Serial.println ( "new client" );
// let the Modbus TCP accept the modbusTCPServer connection
modbusTCPServer.accept ( client );
while ( client.connected ())
{
// poll for Modbus TCP requests, while client connected
modbusTCPServer.poll (); // update the LED
updateLED ();
uint8_t gesture = apds.readGesture();
if(gesture == APDS9960_DOWN) Serial.println("v");
if(gesture == APDS9960_UP)
{
Serial.println("^");
Gesture_Cont = 0;
}
if(gesture == APDS9960_LEFT)
{
Serial.println("<");
if(!(Gesture_Cont==0))
Gesture_Cont--;
}
if(gesture == APDS9960_RIGHT)
{
Serial.println(">");
Gesture_Cont++;
}
}
Serial.println ( "client disconnected" );
}
}
Compile e grave no NINA B302.
ÓTIMA REFERÊNCIA PARA PINOS DO ARDUINO E PINOS (GPIOS) DO NINA B302
Consulte
Conexão com NINA B302 e W5500
Conexão com NINA B302 e GESTURE SENSOR
#define PIN_WIRE_SDA (20)
#define PIN_WIRE_SCL (21)
INSTALE LIB e pré-requisitos
Esta biblioteca implementa o protocolo Modbus em dois diferentes tipos de transporte: comunicação serial sobre RS485 com RTU (Remote Terminal Unit) ou Ethernet e comunicação WiFi com protocolo TCP. Existem algumas diferenças nas APIs dependendo do transporte, mas a maioria das funções é a mesma para ambos.
Modbus também é um protocolo cliente-servidor onde Cliente = mestre e Servidor = escravo na terminilogia Modbus; sugerimos ler alguns artigos sobre este protocolo se você não tiver nenhuma experiência anterior, pois ele se baseia fortemente em algumas convenções formais.
Organizamos esta referência para que você encontre as funções comuns de ambos os transportes juntos e apenas as funções relacionadas ao transporte são fornecidas individualmente. Como regra geral, a comunicação RTU é multiponto e, portanto, o ID da unidade envolvida na comunicação precisa ser especificado. O TCP é ponto a ponto usando o endereço IP e, portanto, não há necessidade de um ID nos parâmetros.
e o mais importante
Leia o README
Thanks to Khoi Hoang, a great person, a great programmer!
Thanks to Khoi Hoang, a great person, a great programmer!
Altere define.h no programa fonte abaixo!
// Only one if the following to be true
#define USE_ETHERNET true
#define USE_ETHERNET2 false //true
#define USE_ETHERNET3 false //true
#define USE_ETHERNET_LARGE false
#define USE_ETHERNET_ESP8266 false //true
#define USE_ETHERNET_ENC false
Compile o programa NRF52_Simple_Server e pressione o botão para gravar.
E altere no INO
DDNSGeneric.client("xxxxxxxxx.duckdns.org", "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx");
Necessário criar URL no DuckDNS
Segue código Alterado (Upnp e MODBUS TCP SERVER) juntos
/**************************************************** ***************************************************** ****************************
nRF52_LED_GESTURE_MODBUS_Server.ino
For all Generic boards such as ESP8266, ESP32, WT32_ETH01, SAMD21/SAMD51, nRF52, STM32F/L/H/G/WB/MP1,Teensy
with WiFiNINA, ESP8266/ESP32 WiFi, ESP8266/ESP32-AT, W5x00, ENC28J60, Native Ethernet shields
DDNS_Generic is a library to automatically add port mappings to router using UPnP SSDP
(Simple Service Discovery Protocol) in order to provide access to local Web Services from the Internet.
Based on and modified from Ofek Pearl's TinyUPnP Library (https://github.com/ofekp/TinyUPnP)
Built by Khoi Hoang https://github.com/khoih-prog/UPnP_Generic
Licensed under GPL-3.0 license
Version: 3.3.1
Based on EthenetModbusServerLED
https://www.arduino.cc/en/ArduinoModbus/ArduinoModbus
Version Modified By Date Comments
------- ----------- ---------- -----------
3.1.4 K Hoang 23/09/2020 Initial coding for Generic boards using many WiFi/Ethernet modules/shields.
3.1.5 K Hoang 28/09/2020 Fix issue with nRF52 and STM32F/L/H/G/WB/MP1 using ESP8266/ESP32-AT
3.2.0 K Hoang 11/06/2021 Add support to RP2040-based boards using ESP-AT, WiFiNINA, W5x00 / ENC28J60
3.3.0 K Hoang 16/07/2021 Add support to WT32_ETH01 (ESP32 + LAN8720)
3.3.1 M Wisintainer 22/07/2021 Add Modbus example
***************************************************** ***************************************************** ****************************/ /*
Note: This example uses the DDNS_Generic library (https://github.com/khoih-prog/DDNS_Generic)
You can access this WebServer by either localIP:LISTEN_PORT such as 192.169.2.100:5953/?percentage=20
or DDNS_Host:LISTEN_PORT, such as account.duckdns.org:5953/?percentage=20
*/
#include "defines.h"
#define UPNP_USING_ETHERNET true
#include <UPnP_Generic.h>
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include "Adafruit_APDS9960.h"
int Gesture_Cont = 0;
Adafruit_APDS9960 apds;
#define LISTEN_PORT 502
#define LEASE_DURATION 36000 // seconds
#define FRIENDLY_NAME "NRF52-MODBUS-W5X00" // this name will appear in your router port forwarding section
EthernetServer EthServer ( LISTEN_PORT );
ModbusTCPServer modbusTCPServer ;
UPnP * uPnP ;
#if defined(LED_BLUE)
#define LED_PIN LED_BLUE // BLUE_LED on nRF52840 Feather Express, Itsy-Bitsy
#else
#define LED_PIN 3 // RED LED
#endif
#define LED_PIN2 16 //SECOND LED IO27
void onUpdateCallback ( const char * oldIP , const char * newIP )
{
Serial.print ( F ( "DDNSGeneric - IP Change Detected: " ));
Serial.println ( newIP );
}
void LEDOn ( void )
{
digitalWrite ( LED_PIN , HIGH );
}
void LEDOff ( void )
{
digitalWrite ( LED_PIN , LOW );
}
void LEDOn2 ( void )
{
digitalWrite ( LED_PIN2 , HIGH );
}
void LEDOff2 ( void )
{
digitalWrite ( LED_PIN2 , LOW );
}
void showLED ( void )
{
for ( int i = 0 ; i < 5 ; i ++)
{
LEDOn ();
delay ( 100 );
LEDOff ();
delay ( 100 );
}
}
bool s = false;
unsigned long Coil_Write_Time ;
void updateLED ()
{
// read the current value of the coil
int coilValue = modbusTCPServer . coilRead ( 0x00 );
if ( coilValue == 1 )
{
// coil value set, turn LED on
LEDOn ();
}
else if ( coilValue == 0 )
{
// coil value set, turn LED on
LEDOff ();
}
//using the second coil to control LED when receive a Write command from SCADA
coilValue = modbusTCPServer . coilRead ( 0x01 );
if(coilValue == 1)
LEDOn2();
if(coilValue == 0)
LEDOff2();
if ( millis ( ) > Coil_Write_Time )
{
modbusTCPServer . coilWrite ( 0x00 , s );
s = ! s ;
Coil_Write_Time = millis () + 1000 ;
//Simulate Reading data to send to SCADA
modbusTCPServer.inputRegisterWrite( 0x00, random(0,1000) );
modbusTCPServer.inputRegisterWrite( 0x01, random(0,1000) );
modbusTCPServer.inputRegisterWrite( 0x02, Gesture_Cont );
}
}
void setup ( void )
{
Serial.begin( 115200 );
while (! Serial );
Serial.println("Start...");
if(!apds.begin()){
Serial.println("failed to initialize device! Please check your wiring.");
}
else Serial.println("Device initialized!");
//gesture mode will be entered once proximity mode senses something close
apds.enableProximity(true);
apds.enableGesture(true);
//second LED
pinMode ( LED_PIN2, OUTPUT );
pinMode ( LED_PIN , OUTPUT );
showLED ();
Serial.print("\nStart nRF52_LED_MODBUS_Server on "); Serial.print(BOARD_NAME);
Serial.print(" using "); Serial.println(SHIELD_TYPE);
Serial.println(UPNP_GENERIC_VERSION);
ET_LOGWARN3(F("Board :"), BOARD_NAME, F(", setCsPin:"), USE_THIS_SS_PIN);
ET_LOGWARN(F("Default SPI pinout:"));
ET_LOGWARN1(F("MOSI:"), MOSI);
ET_LOGWARN1(F("MISO:"), MISO);
ET_LOGWARN1(F("SCK:"), SCK);
ET_LOGWARN1(F("SS:"), SS);
ET_LOGWARN(F("========================="));
#if !(USE_BUILTIN_ETHERNET || USE_UIP_ETHERNET)
// For other boards, to change if necessary
#if ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
// Must use library patch for Ethernet, Ethernet2, EthernetLarge libraries
Ethernet.init (USE_THIS_SS_PIN);
#elif USE_ETHERNET3
// Use MAX_SOCK_NUM = 4 for 4K, 2 for 8K, 1 for 16K RX/TX buffer
#ifndef ETHERNET3_MAX_SOCK_NUM
#define ETHERNET3_MAX_SOCK_NUM 4
#endif
Ethernet.setCsPin (USE_THIS_SS_PIN);
Ethernet.init (ETHERNET3_MAX_SOCK_NUM);
#elif USE_CUSTOM_ETHERNET
// You have to add initialization for your Custom Ethernet here
// This is just an example to setCSPin to USE_THIS_SS_PIN, and can be not correct and enough
//Ethernet.init(USE_THIS_SS_PIN);
#endif //( ( USE_ETHERNET || USE_ETHERNET_LARGE || USE_ETHERNET2 || USE_ETHERNET_ENC )
#endif
// start the ethernet connection and the server:
// Use DHCP dynamic IP and random mac
uint16_t index = millis() % NUMBER_OF_MAC;
// Use Static IP
//Ethernet.begin(mac[index], ip);
Ethernet.begin(mac[index]);
IPAddress localIP = Ethernet.localIP();
////////////////
DDNSGeneric.service ( "duckdns" ); // Enter your DDNS Service Name - "duckdns" / "noip"
/*
For DDNS Providers where you get a token:
DDNSGeneric.client("domain", "token");
For DDNS Providers where you get username and password: ( Leave the password field empty "" if not required )
DDNSGeneric.client("domain", "username", "password");
*/
DDNSGeneric.client("xxxxxxxxxxx.duckdns.org", "94a6dc4f-2102-4d96-88c8-5622d04597bd");
DDNSGeneric.onUpdate ( onUpdateCallback );
////////////////
uPnP = new UPnP(60000); // -1 means blocking, preferably, use a timeout value (ms)
if (uPnP)
{
uPnP->addPortMappingConfig(localIP, LISTEN_PORT, RULE_PROTOCOL_TCP, LEASE_DURATION, FRIENDLY_NAME);
bool portMappingAdded = false;
#define RETRY_TIMES 4
int retries = 0;
while (!portMappingAdded && (retries < RETRY_TIMES))
{
Serial.println("Add Port Forwarding, Try # " + String(++retries));
int result = uPnP->commitPortMappings();
portMappingAdded = ( (result == PORT_MAP_SUCCESS) || (result == ALREADY_MAPPED) );
//Serial.println("commitPortMappings result =" + String(result));
if (!portMappingAdded)
{
// for debugging, you can see this in your router too under forwarding or UPnP
//uPnP->printAllPortMappings();
//Serial.println(F("This was printed because adding the required port mapping failed"));
if (retries < RETRY_TIMES)
delay(10000); // 10 seconds before trying again
}
}
uPnP->printAllPortMappings();
Serial.println(F("\nUPnP done"));
}
showLED();
EthServer . begin ();
Serial.print ( F ( "Modbus server is @ IP : " ));
Serial.print ( localIP );
Serial.print ( F ( ", port = " ));
Serial.println ( LISTEN_PORT );
Serial.print ( F ( "Gateway Address: " ));
Serial.println ( Ethernet . gatewayIP ());
Serial.print ( F ( "Network Mask: " ));
Serial.println ( Ethernet . subnetMask ());
// start the Modbus TCP server
if (! modbusTCPServer.begin ())
{
Serial.println ( "Failed to start Modbus TCP Server!" );
while ( 1 );
}
// set two coil at address 0x00 and 0x01
Serial.println ( "Configure two coil at address 0x00" );
modbusTCPServer.configureCoils ( 0x00 , 2 );
// set three input register at address 0x00, 0x01, 0x02
Serial.println ( "Configure two input register at address 0x00" );
modbusTCPServer.configureInputRegisters(0x00, 3);
Coil_Write_Time = millis () + 1000 ;
}
void loop(void)
{
DDNSGeneric.update(300000);
uPnP->updatePortMappings(600000); // 10 minutes
EthernetClient client = EthServer.available ();
if ( client )
{
// a new client connected
Serial.println ( "new client" );
// let the Modbus TCP accept the modbusTCPServer connection
modbusTCPServer.accept ( client );
while ( client.connected ())
{
// poll for Modbus TCP requests, while client connected
modbusTCPServer.poll (); // update the LED
updateLED ();
uint8_t gesture = apds.readGesture();
if(gesture == APDS9960_DOWN) Serial.println("v");
if(gesture == APDS9960_UP)
{
Serial.println("^");
Gesture_Cont = 0;
}
if(gesture == APDS9960_LEFT)
{
Serial.println("<");
if(!(Gesture_Cont==0))
Gesture_Cont--;
}
if(gesture == APDS9960_RIGHT)
{
Serial.println(">");
Gesture_Cont++;
}
}
Serial.println ( "client disconnected" );
}
}
Compile e grave no NINA B302.
Associe Tag aos Objetos Visual (Coil)
Mais detalhes em
No Arduino, atenção aos comandos:
modbusTCPServer.configureCoils ( 0x00 , 2 );
modbusTCPServer.configureInputRegisters(0x00, 3);
modbusTCPServer.inputRegisterWrite( 0x00, random(0,1000) );
modbusTCPServer.coilWrite(0x00, s);
int coilValue = modbusTCPServer.coilRead(0x00);
Execução
Scada rodando em outra LAN e lendo Sensor de Gestos
Questões: suporte@smartcore.com.br
FONTES:
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