ESP32 ModBus master half duplex read coil input registers - modbus

I'm trying to read a MODBUS sensor via an ESP32.
I'm using the following library: https://github.com/emelianov/modbus-esp8266
I have the following code:
#include <ModbusRTU.h>
#include <SoftwareSerial.h>
SoftwareSerial modBusSerial;
ModbusRTU modbus;
#define startReg 100
#define endReg 123
uint16_t res[endReg - startReg + 1];
// Callback to monitor errors in the modbus
bool cb(Modbus::ResultCode event, uint16_t transactionId, void* data) {
if (event != Modbus::EX_SUCCESS) {
Serial.print("Request result: 0x");
Serial.print(event, HEX);
}
return true;
}
void setup() {
Serial.begin(115200); // Default serial port (Hardware serial)
modBusSerial.begin(9600, SWSERIAL_8E1, MB_RX, MB_TX); // modbus configuration SWSERIAL_8E1 = 8 bits data, even parity and 1 stop-bit
modbus.begin(&modBusSerial);
modbus.master();
Serial.println("starting modbus...");
while (true) {
Serial.println(modBusSerial.read());
res[endReg - startReg] = 0; // string terminator to allow to use res as char*
if (!modbus.slave()) {
modbus.readIreg(16, startReg, res, endReg - startReg, cb);
}
modbus.task();
Serial.print("result: ");
Serial.println((char*) res);
delay(1000); // every second
}
}
Response I get;
When I do the exact same in QModMaster, I do get the correct output. Anyone any idea what I'm doing wrong here?
These are the settings I use;
I am aware of the "wrong" address in my code. I have 2 identical sensors but one is connected to my computer while the other one is connected to my ESP32.
Thanks in advance!

Related

Failure to send data from client to server in ESP-01 WiFi

Using the ESP8266WiFi library, I have two ESP-01's/ESP8266's connected over WiFi. It works perfectly when the client sends a request (all non HTML!) to the server (using port 5000 - to prevent any confusion with HTTP, FTP etc.). But I cannot get the client to receive an answer back from the server. Now, in the ESP8266WiFi library (3.0.2) there is a note that server.write() is not implemented, and that I should use server.accept() instead of server.available(); though I did not see any applicable examples using server.accept(), but I see many examples using client.print() so I try to follow those - to no avail, yet. What I am doing is the following: 1. establish connectivity to the WiFi; 2. have the client connect to the server and send two bytes to the server. 3. Do a digital write to a pin of the server-ESP8266.(this toggles a relay, which works fine) 4. write back from server to client that the digital write has been done. On the client side, after writing to the server, I run in a loop for some 10 seconds trying to receive something from the server, which never comes. Then I cycle back to the beginning, and the client asks to toggle the relay again - this runs nicely for hours.
Any insights here on what I should do differently are highly appreciated. I really want to be able to get some acknowledgement back to the client once the server has toggled the relay. Or if someone has a working example with server.accept() - I would try that too.
Client side code:
int pin_value;
uint8_t ip[4];
void setup()
{
Serial.begin(115200);
ip[0]=10;
ip[1]=0;
ip[2]=0;
ip[3]=6;
//We connect to the WiFi network
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
//Wait until connected
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.print("Client - ");
Serial.println("WiFi connected");
}
void loop(){
//Variable that we will use to connect to the server
WiFiClient client;
//if not able to connect, return.
if (!client.connect(ip, SERVER_PORT)){ return; }
// We create a buffer to put the send data
uint8_t buffer[Protocol::BUFFER_SIZE];
//We put the pin number in the buffer
// whose state we want to send
buffer[Protocol::PIN] = RELAY;
//put the current state of the pin in the send buffer
buffer[Protocol::VALUE] = pin_value;
//We send the data to the server
client.write(buffer, Protocol::BUFFER_SIZE);
// try to read the answer from the server for about 10 seconds
int nr_of_tries = 10000;
while (client.connected() && nr_of_tries > 0)
{if (client.available())
{ String line = client.readStringUntil('\n');
nr_of_tries = 0;
Serial.print("line= ");
Serial.println(line);
}
else
{delay(1);
nr_of_tries=nr_of_tries-1;
}
}
Serial.print("nr of tries= ");
Serial.println(nr_of_tries);
Serial.print("connected: ");
Serial.println(client.connected());
client.flush();
client.stop();
Serial.println(" change sent");
if (pin_value == 0)
{pin_value =1;
Serial.println("Pin_value set to 1");
}
else
{pin_value=0;
Serial.println("Pin_value set to 0");}
delay(10000);
}
Server side code:
WiFiServer server(SERVER_PORT);
void setup()
{
Serial.begin(115200); // must have the same baud rate as the serial monitor
pinMode(RELAY,OUTPUT);
digitalWrite(RELAY, LOW);
// Connect to the WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED){
delay(500);
Serial.print(".");
}
Serial.println("Server - ");
Serial.println("WiFi connected");
// Set this ESP to behave as a WiFi Access Point
// WiFi.mode(WIFI_AP);
// set SSID and Password to connect to this ESP
// WiFi.softAP(SSID, PASSWORD);
// Start the server
server.begin();
Serial.println("Server started");
// Output of the IP address
Serial.print("Use this IP to connect: ");
Serial.println(WiFi.localIP());
}
void loop()
{
// Check if there is any client connecting
WiFiClient client = server.available();
if (client)
{
//Serial.println("Client detected");
//If the client has data he wants to send us
//check for a second or so as transmission can take time
int nr_of_tries = 1000;
while(!client.available() && nr_of_tries > 0)
{ nr_of_tries=nr_of_tries-1;
delay(1);
}
if (client.available())
{
// Serial.println(" Client data");
// create a buffer to put the data to be received
uint8_t buffer[Protocol::BUFFER_SIZE];
// We put the data sent by the client in the buffer
// but do not read more than the buffer length.
int len = client.read(buffer, Protocol::BUFFER_SIZE);
// retrieve which pin number the client sent
int pinNumber = buffer[Protocol::PIN];
Serial.print("Pin Number: ");
Serial.println(pinNumber);
// retrieve the value of this pin
int value = buffer[Protocol::VALUE];
Serial.print("Value: ");
Serial.println(value);
// Set the pin indicated by the received pin number in output mode
// but only if the pin is the GPIO0 pin!
if (pinNumber == RELAY)
{ pinMode(pinNumber, OUTPUT);
// Set the pin indicated by the received pin number to the passed value
digitalWrite(pinNumber, value);
}
// tell the client that the relay has been set or reset.
size_t i;
if (value == 0) {
i=server.println("Set");
Serial.print("i= ");
Serial.println(i);
}
else {
i=server.println("Reset");
Serial.print("i= ");
Serial.println(i);
}
}
}
//Close the connection with the client
//client.stop();
}
Common definitions:
#include <ESP8266WiFi.h>
const char* ssid = "blablabla";
const char* password = "blublublu";
#define SERVER_PORT 5000
#define RELAY 0
//Protocol that the Server and Client will use to communicate
enum Protocol{
PIN, // Pin whose state you want to change
VALUE, // State to which the pin should go (HIGH = 1 or LOW = 0)
BUFFER_SIZE // The size of our protocol. IMPORTANT: always leave it as the last item of the enum
};
Solved! By changing server.println("Set"); into client.println("Set") and doing the same for the transmission of "Reset" a few lines lower in the server side code it works!

PCF8574 doesnot send ACK

I am trying to connect a PCF8574 I/O ex-pander to 89S51 MCU.
The device address as per data sheet is 27h and after adding write bit 0
the address is 4Eh and for read it is 4Fh. I am sending write request i.e.
4Eh and it somehow works. If i try to read by sending 4Fh then the ACK is
never received.
I have noticed that during the write request i can write any value that
does not have LSB 0. If any value with LSB 0 is sent for write then again
the chip doesnot send ACK.
From above i understood that LSB of the data or command that I am sending have
something to do with the ACK. If the LSB is 0 then the SDA line is set to
LOW by master. So the slave don't have to bring the SDA line low to send
back ACK. Does it mean that the slave is not sending the ACK at all. It is the
Master that is thinking falsely that ACK is available only because it has bring the
SDA line LOW and checking the same LOW and thinking its ACK from slave.
I may be mistaken, but in don't know how to get over this situation.
Below is my sample C code written in SDCC compiler. This is only the Write part.
Job of this code is to continuously send AAh and 55h to the slave so that is can
observe the port activity by connecting LED. It can send AAh but goes into infinite
loop while checking of ACK when tries to send 55h. Again here 55h have LSB 1 so it fails.**
#include<8052.h>
#define SDA P0_0
#define SCL P0_1
#define HEARTBEAT_LED P1_0
void msDelay(unsigned int);
void I2CStart(void);
void I2CStop(void);
void i2c_write_byte(unsigned char Data);
/*****************************************
* Write to slave device with
* slave address e.g. say 0x27+/W=0x4E
*****************************************/
void main(void)
{
I2CStart(); // Send start condition
i2c_write_byte(0x4E); // Send slave address + write request
while(1)
{
i2c_write_byte(0xAA); //Send data
msDelay(100);
i2c_write_byte(0xFF); //Send data
msDelay(100);
}
}
void I2CStart(void)
{
SDA = 1;
SCL = 1;
SDA = 0;
SCL = 0;
}
void I2CStop(void)
{
SDA = 0;
SCL = 1;
SDA = 1;
SCL = 0;
}
void i2c_write_byte(unsigned char Data)
{
unsigned char i;
for(i=0;i<8;i++)
{
SCL=0;
SDA=(Data &(0x80>>i));
SCL=1;
}
while(SDA!=0);
SCL=0;
SCL=1;
SCL=0;
}
void msDelay(unsigned int itime)
{
unsigned int i, j;
for(i=0;i<itime;i++)
for(j=0;j<127;j++);
}

Arduino mkr1000 does not Serial print upon GET using aRest library

I'm trying to create a REST server on an arduino mkr1000. upon searching google i came upon the aRest library which handles most of the stuff i need.
aRest library documentation
So i created a sample sketch based on the guides. Here is the code:
#include < SPI.h >
#include < WiFi101.h >
#include < aREST.h >
aREST rest = aREST();
int status = WL_IDLE_STATUS;
WiFiServer restServer(80);
char ssid[] = "user"; // not actual username
char pass[] = "pass"; // not actual password
int clapMode(String data){
Serial.println("Request Recieved: " + data);
}
void setup() {
Serial.begin(115200);
rest.set_id("000");
rest.set_name("MKR1000");
rest.function("test",clapMode);
while ( status != WL_CONNECTED) {
Serial.print("Attempting to connect to SSID: ");
Serial.println(ssid);
// Connect to WPA/WPA2 network. Change this line if using open or WEP
network:
status = WiFi.begin(ssid, pass);
// wait 10 seconds for connection:
delay(10000);
}
Serial.println();
// you're connected now, so print out the status:
printWifiStatus();
// Start server
restServer.begin();
Serial.println(F("Listening for connections..."));
}
void loop() {
WiFiClient client = restServer.available();
if (!client) {
return;
}
while(!client.available()){
delay(1);
}
rest.handle(client);
}
void printWifiStatus() {
// print the SSID of the network you're attached to:
Serial.print("SSID: ");
Serial.println(WiFi.SSID());
// print your WiFi shield's IP address:
IPAddress ip = WiFi.localIP();
Serial.print("IP Address: ");
Serial.println(ip);
IPAddress subnet = WiFi.subnetMask();
Serial.print("Netmask: ");
Serial.println(subnet);
IPAddress gateway = WiFi.gatewayIP();
Serial.print("Gateway: ");
Serial.println(gateway);
// print the received signal strength:
long rssi = WiFi.RSSI();
Serial.print("signal strength (RSSI):");
Serial.print(rssi);
Serial.println(" dBm");
}
The code works mostly. Upon using POSTMAN to perform a GET the arduino is able to give the appropriate response.
Now for the part that is not working is the endpoint i just have created using this code
rest.function("test",clapMode);
upon performing a GET in postman, the arduino is able to give a response, but it should perform this code
int clapMode(String data){
Serial.println("Request Recieved: " + data);
}
but on my serial Monitor i am not getting anything.
Also i could not find on how to tailor the response of the arduino from the request. How do i it ?
Thank you very much
You have to send the request to <host>/test?params=0, not <host>/clapMode.
Furthermore, you can modify the ID and name with
rest.set_id("device ID");
rest.set_name("device name");
and add variables with
rest.variable("variable name", &variable);
The response is hard-coded into the library, therefore if you want to add/remove other stuff, you have to edit the library by yourself.

How to get the MAC adress of an access point when esp8266 is in client (station) mode?

I would like my esp8266 to retrieve the mac address of the AP it`s connected to as a client (station), following this discussion on How to get Access Point MAC adress.
Here is my code:
#include <ESP8266WiFi.h>
const char* ssid = "somrmthing";
const char* password = "somrmthing"; //
const char* host = "aubs.gear.host"; //create webserver & correct address
uint8_t MAC_array[6];
char MAC_char[18];
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
delay(100);
// We start by connecting to a WiFi network
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
int value = 0;
void loop() {
// put your main code here, to run repeatedly:
/*
* http://stackoverflow.com/questions/34078497/esp8266-wificlient-simple-http-get
*/
delay(30000);
++value;
/*
* https://github.com/esp8266/Arduino/blob/master/libraries/ESP8266WiFi/examples/WiFiClient/WiFiClient.ino
*/
Serial.print("connecting to ");
Serial.println(host);
// Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// getting the mac address http://bbs.espressif.com/viewtopic.php?f=15&t=3102&p=10569&hilit=Access+Point+MAC+adress&sid=a68dcff311ea05ece032126d6f93902f#p10569
void wifi_handle_event_cb(System_Event_t *evt)
{
os_printf("event %x\n", evt->event);
switch (evt->event){
case EVENT_STAMODE_CONNECTED:
os_printf("connect to ssid %s, channel %d\n", evt->event_info.connected.ssid, evt->event_info.connected.channel);
os_printf("AP MAC address is %s\n", evt->event_info.connected.bssid);
break;
case ....
....
}
}
//old wrong MAC ADDRESS
// getting the mac address //Serial.println(MAC_char); - See more at: http://www.esp8266.com/viewtopic.php?f=29&t=3587#sthash.bwWPqcc6.dpuf
WiFi.macAddress(MAC_array);
for (int i = 0; i < sizeof(MAC_array); ++i){
sprintf(MAC_char,"%s%02x:",MAC_char,MAC_array[i]);
}
// We now create a URI for the request
String url = "/store.php"; // String url = "/input/";
url += "?dev_id=";
url += "BikeShare9";
url += "&hoster=";
url += MAC_char;
url += "&ip_add=";
url += WiFi.localIP();
Serial.print("Requesting URL: ");
Serial.println(url);
// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
unsigned long timeout = millis();
while (client.available() == 0) {
if (millis() - timeout > 5000) {
Serial.println(">>> Client Timeout !");
client.stop();
return;
}
}
// Read all the lines of the reply from server and print them to Serial
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}
Serial.println();
Serial.println("closing connection");
}
For void wifi_handle_event_cb(System_Event_t *evt) I get the following error:
C:\Users\Tinotenda\Desktop\ver1.0\ver1.0.ino: In function 'void setup()':
ver1.0:48: error: a function-definition is not allowed here before '{' token
void loop() {
^
ver1.0:129: error: expected '}' at end of input
}
^
exit status 1
a function-definition is not allowed here before '{' token
How can I fix that?
Your setup()-function doesn't have it's closing bracket.
You should also place all the global variables at the top, or make them static inside the function that uses them. (ref: int value = 0 ,although I don't know what you're using the variable for)
Furthermore, avoid the user of very long delays. delay(30000)causes the ESP8266 IP-stack to behave strangely. You should better use the millis-structure:
static unsigned long lastMillis = 0;
if (millis() - lastMillis < 30 * 1000UL) {
lastMillis = millis();
//do your stuff
}
This answer should help other beginners:
Copy and pasting code without understanding the basics is never a good idea.
Basic structure of an Arduino program (=sketch)
Definitions, global vars
int value = 0;
should be placed there
SETUP
void setup(){
All one time functions, initalization routines, etc
}
LOOP
void loop(){
recuring tasks call functions from here in the above example
Call the example function like this
wifi_handle_event_cb(SomeParamToHandOver);
NEVER use delay - it stops processing for the given time
Not a good idea in server client scenarios ->
look for blink without delay in the Arduino examples for more
Never use while in here it may lead to dead locks
}
functions/modules you call from the setup or loop
void wifi_handle_event_cb(System_Event_t *evt) {
Exmple from the question
}
plus all remarks in the answer above
All beginners should start with https://www.arduino.cc/en/Tutorial/BuiltInExamples

Unable to transfer data between two ESP8266

I am trying to connect two esp 8266 (Wi-fi) module with each other one as hotspot (server) using Wifi of ESP12 E module 8266 and other is (client).I am Using Arduino IDE for programming
my server starts properly and client is connected to server but when I send data from client to server I got nothing. I google about data transfer between client and server, but nothing is there for client data transfer using Arduino coding.
Here is My code in Arduino
server side code
#include <ESP8266WiFi.h>
WiFiServer server(80); //Initialize the server on Port 80
void setup()
{
WiFi.mode(WIFI_AP); // ESP8266-12E is an AccessPoint
WiFi.softAP("11111111", "12345678"); // Provide the (SSID, password)
server.begin(); // Start the Server
Serial.begin(115200); //Start communication between the ESP8266-12E and the monitor window
IPAddress HTTPS_ServerIP= WiFi.softAPIP(); // Obtain the IP of the Server
Serial.print("Server IP is: "); // Print the IP to the monitor window
Serial.println(HTTPS_ServerIP);
}
void loop()
{
WiFiClient client = server.available();
if (!client)
{
return;
}
//Looking under the hood
Serial.println("Somebody has connected :)");
}
client side code
#include <ESP8266WiFi.h>
const char *ssid = "11111111";
const char *password = "12345678";
const char *host = "192.168.4.2";
const int httpPort = 80;
void setup()
{
Serial.begin(115200);
delay(10);
Serial.println();
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED)
{
delay(500);
Serial.print(".");
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
}
void loop()
{
delay(8000);
Serial.print("connecting to ");
Serial.println(host);
WiFiClient client;
client.connect(host,httpPort);
if (!client.connect(host,httpPort))
{
Serial.println("connection failed");
return;
}
else
client.print("connected");
}
can any one suggest me how to transfer data from client to server
The Arduino ESP8266 class WiFiClient inherits from Stream, so, all stream functions are available to you. You can find documentation for that class here.
You could use readBytes, readString, or just plain read to do what you want.
Additionally, if you do plan to use HTTP, you may be interested in using the libraries ESP8266WebServer and ESP8266HTTPClient which come with your ESP8266 Arduino environment and implement a lot of this low level code you are attempting to write. You can find examples for the server here, and the client here