Initial arduino examples
This commit is contained in:
parent
494e1a385b
commit
2a149a93ec
4
examples/arduino/README.md
Normal file
4
examples/arduino/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
## Arduino examples
|
||||
|
||||
This folder contains nanoMODBUS examples for Arduino.
|
||||
To build and load a sketch with the Arduino IDE, copy `nanomodbus.c` and `nanomodbus.h` inside its folder.
|
||||
90
examples/arduino/client-rtu/client-rtu.ino
Normal file
90
examples/arduino/client-rtu/client-rtu.ino
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
This example client application connects via RTU to a server and sends some requests to it.
|
||||
*/
|
||||
|
||||
#include "nanomodbus.h"
|
||||
|
||||
// The server address
|
||||
#define RTU_SERVER_ADDRESS 1
|
||||
|
||||
|
||||
int32_t read_serial(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) {
|
||||
Serial.setTimeout(byte_timeout_ms);
|
||||
return Serial.readBytes(buf, count);
|
||||
}
|
||||
|
||||
|
||||
int32_t write_serial(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) {
|
||||
Serial.setTimeout(byte_timeout_ms);
|
||||
return Serial.write(buf, count);
|
||||
}
|
||||
|
||||
|
||||
void onError() {
|
||||
// Make the LED blink on error
|
||||
while (true) {
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
pinMode (LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
nmbs_platform_conf platform_conf;
|
||||
platform_conf.transport = NMBS_TRANSPORT_RTU;
|
||||
platform_conf.read = read_serial;
|
||||
platform_conf.write = write_serial;
|
||||
|
||||
nmbs_t nmbs;
|
||||
nmbs_error err = nmbs_client_create(&nmbs, &platform_conf);
|
||||
if (err != NMBS_ERROR_NONE)
|
||||
onError();
|
||||
|
||||
nmbs_set_read_timeout(&nmbs, 1000);
|
||||
nmbs_set_byte_timeout(&nmbs, 100);
|
||||
|
||||
nmbs_set_destination_rtu_address(&nmbs, RTU_SERVER_ADDRESS);
|
||||
|
||||
// Write 2 coils from address 64
|
||||
nmbs_bitfield coils;
|
||||
nmbs_bitfield_write(coils, 0, 1);
|
||||
nmbs_bitfield_write(coils, 1, 1);
|
||||
err = nmbs_write_multiple_coils(&nmbs, 64, 2, coils);
|
||||
if (err != NMBS_ERROR_NONE)
|
||||
onError();
|
||||
|
||||
// Read 3 coils from address 64
|
||||
nmbs_bitfield_reset(coils); // Reset whole bitfield to zero
|
||||
err = nmbs_read_coils(&nmbs, 64, 3, coils);
|
||||
if (err != NMBS_ERROR_NONE)
|
||||
onError();
|
||||
|
||||
// Write 2 holding registers at address 26
|
||||
uint16_t w_regs[2] = {123, 124};
|
||||
err = nmbs_write_multiple_registers(&nmbs, 26, 2, w_regs);
|
||||
if (err != NMBS_ERROR_NONE)
|
||||
onError();
|
||||
|
||||
// Read 2 holding registers from address 26
|
||||
uint16_t r_regs[2];
|
||||
err = nmbs_read_holding_registers(&nmbs, 26, 2, r_regs);
|
||||
if (err != NMBS_ERROR_NONE)
|
||||
onError();
|
||||
|
||||
// Turn off the led on success
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
// No need to destroy the nmbs instance, bye bye
|
||||
exit(0);
|
||||
}
|
||||
144
examples/arduino/server-rtu/server-rtu.ino
Normal file
144
examples/arduino/server-rtu/server-rtu.ino
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
This example application sets up an RTU server and polls from modbus requests
|
||||
|
||||
This server supports the following function codes:
|
||||
FC 01 (0x01) Read Coils
|
||||
FC 03 (0x03) Read Holding Registers
|
||||
FC 15 (0x0F) Write Multiple Coils
|
||||
FC 16 (0x10) Write Multiple registers
|
||||
*/
|
||||
|
||||
#include "nanomodbus.h"
|
||||
|
||||
// The data model of this sever will support coils addresses 0 to 100 and registers addresses from 0 to 32
|
||||
#define COILS_ADDR_MAX 100
|
||||
#define REGS_ADDR_MAX 32
|
||||
|
||||
// Our RTU address
|
||||
#define RTU_SERVER_ADDRESS 1
|
||||
|
||||
// A single nmbs_bitfield variable can keep 2000 coils
|
||||
nmbs_bitfield server_coils = {0};
|
||||
uint16_t server_registers[REGS_ADDR_MAX] = {0};
|
||||
|
||||
|
||||
int32_t read_serial(uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) {
|
||||
Serial.setTimeout(byte_timeout_ms);
|
||||
return Serial.readBytes(buf, count);
|
||||
}
|
||||
|
||||
|
||||
int32_t write_serial(const uint8_t* buf, uint16_t count, int32_t byte_timeout_ms, void* arg) {
|
||||
Serial.setTimeout(byte_timeout_ms);
|
||||
return Serial.write(buf, count);
|
||||
}
|
||||
|
||||
|
||||
void onError() {
|
||||
// Make the LED blink on error
|
||||
while (true) {
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
delay(1000);
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
delay(1000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
nmbs_error handle_read_coils(uint16_t address, uint16_t quantity, nmbs_bitfield coils_out) {
|
||||
if (address + quantity > COILS_ADDR_MAX + 1)
|
||||
return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;
|
||||
|
||||
// Read our coils values into coils_out
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
bool value = nmbs_bitfield_read(server_coils, address + i);
|
||||
nmbs_bitfield_write(coils_out, i, value);
|
||||
}
|
||||
|
||||
return NMBS_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
nmbs_error handle_write_multiple_coils(uint16_t address, uint16_t quantity, const nmbs_bitfield coils) {
|
||||
if (address + quantity > COILS_ADDR_MAX + 1)
|
||||
return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;
|
||||
|
||||
// Write coils values to our server_coils
|
||||
for (int i = 0; i < quantity; i++) {
|
||||
nmbs_bitfield_write(server_coils, address + i, nmbs_bitfield_read(coils, i));
|
||||
}
|
||||
|
||||
return NMBS_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
nmbs_error handler_read_holding_registers(uint16_t address, uint16_t quantity, uint16_t* registers_out) {
|
||||
if (address + quantity > REGS_ADDR_MAX + 1)
|
||||
return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;
|
||||
|
||||
// Read our registers values into registers_out
|
||||
for (int i = 0; i < quantity; i++)
|
||||
registers_out[i] = server_registers[address + i];
|
||||
|
||||
return NMBS_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
nmbs_error handle_write_multiple_registers(uint16_t address, uint16_t quantity, const uint16_t* registers) {
|
||||
if (address + quantity > REGS_ADDR_MAX + 1)
|
||||
return NMBS_EXCEPTION_ILLEGAL_DATA_ADDRESS;
|
||||
|
||||
// Write registers values to our server_registers
|
||||
for (int i = 0; i < quantity; i++)
|
||||
server_registers[address + i] = registers[i];
|
||||
|
||||
return NMBS_ERROR_NONE;
|
||||
}
|
||||
|
||||
|
||||
void setup() {
|
||||
pinMode (LED_BUILTIN, OUTPUT);
|
||||
digitalWrite(LED_BUILTIN, HIGH);
|
||||
|
||||
Serial.begin(9600);
|
||||
while (!Serial);
|
||||
}
|
||||
|
||||
|
||||
void loop() {
|
||||
nmbs_platform_conf platform_conf = {0};
|
||||
platform_conf.transport = NMBS_TRANSPORT_RTU;
|
||||
platform_conf.read = read_serial;
|
||||
platform_conf.write = write_serial;
|
||||
platform_conf.arg = NULL;
|
||||
|
||||
// These functions are defined in server.h
|
||||
nmbs_callbacks callbacks = {0};
|
||||
callbacks.read_coils = handle_read_coils;
|
||||
callbacks.write_multiple_coils = handle_write_multiple_coils;
|
||||
callbacks.read_holding_registers = handler_read_holding_registers;
|
||||
callbacks.write_multiple_registers = handle_write_multiple_registers;
|
||||
|
||||
// Create the modbus server
|
||||
nmbs_t nmbs;
|
||||
nmbs_error err = nmbs_server_create(&nmbs, RTU_SERVER_ADDRESS, &platform_conf, &callbacks);
|
||||
if (err != NMBS_ERROR_NONE) {
|
||||
onError();
|
||||
}
|
||||
|
||||
nmbs_set_read_timeout(&nmbs, 1000);
|
||||
nmbs_set_byte_timeout(&nmbs, 100);
|
||||
|
||||
while (true) {
|
||||
err = nmbs_server_poll(&nmbs);
|
||||
// This will probably never happen, since we don't return < 0 in our platform funcs
|
||||
if (err == NMBS_ERROR_TRANSPORT)
|
||||
break;
|
||||
}
|
||||
|
||||
// Turn off the led at the end
|
||||
digitalWrite(LED_BUILTIN, LOW);
|
||||
|
||||
// No need to destroy the nmbs instance, bye bye
|
||||
exit(0);
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user