Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

1-Wire / I2C / PWM #58

Open
DpunktS opened this issue May 2, 2020 · 12 comments
Open

1-Wire / I2C / PWM #58

DpunktS opened this issue May 2, 2020 · 12 comments

Comments

@DpunktS
Copy link

DpunktS commented May 2, 2020

Is there a possibility to integrate 1-wire sensors (ds18b20), I2C sensors (BME280) and PWM in your code?

@yaacov
Copy link
Owner

yaacov commented May 3, 2020

yes, but you will need to be careful with timing.

the modbus pool routine and the connected devices communication routines need to be called in a way that does not break each other, can be tricky :-)

@yaacov
Copy link
Owner

yaacov commented May 3, 2020

p.s.
If you get an example code to work ( e.g. modbus still answer requests and device comunication does not fail ) please add an example here for others that will have a similar problem.

p.p.s.
added a "need help" label, in case someone already have a code example that do that :-)

@ysmilda
Copy link
Contributor

ysmilda commented May 3, 2020

Integrating different sensors and PWM into your modbus enabled sketch is very easy, as long as you make sure you're able to call the poll() function often enough.

How I usually do it is like this:

// Initialise modbus, sensors etc.

unsigned long last_measurement = 0;

void loop()
{
    watchdog.clear(); // Clear the watchdog.

    if ((millis() - last_measurement) > 6000) // Start measurement every 6 seconds.
    {
        last_measurement = millis();

        // Read your sensors here
    }
    else if (millis() < last_measurement)
    {
        last_measurement = millis();
    }

    slave.poll();
}

What it does is read out the sensors every 6 seconds and in in between those readings constantly poll the modbus serial line.

Also setting a PWM output using analogWrite() doesn't mess with the modbus timing.

@DpunktS
Copy link
Author

DpunktS commented May 3, 2020

Can you show me an example of a BME280 (i2c) sensor? I do not know exactly which I have to insert the sensor.

@ysmilda
Copy link
Contributor

ysmilda commented May 3, 2020

@DpunktS We're not here to create your projects for you. I will however give you some more guidelines as in how to read the sensor values via modbus.

What you want to do is choose a proper register type to read your data from. As it is a humidity sensor which is read only a Input Register seems to be the best fitting option. To this register/function code you will connect a function in the setup.

slave.cbVector[CB_READ_INPUT_REGISTERS] = your_function;

Now you have two options, either you read the sensor periodically in your main sketch (like described here) and store that value somewhere. This way you can manipulate the data and do stuff like averaging. your_function() would look something like this:

uint8_t your_function(uint8_t fc, uint16_t address, uint16_t length)
{
  slave.writeRegisterToBuffer(address, BME280_sensor_value);

  return STATUS_OK;
}

The other option is to read the sensor when you read the modbus register and then your_function() would look like this:

uint8_t your_function(uint8_t fc, uint16_t address, uint16_t length)
{
  slave.writeRegisterToBuffer(address, read_BME280_function());

  return STATUS_OK;
}

When you have multiple measurements/sensors the first version could be extended by storing the measured values in an array and read that out at various addresses. Hope this helps you finish your project.

@DpunktS
Copy link
Author

DpunktS commented May 5, 2020

I have now got it so far that the sketch runs but as soon as I query the sensor with address 10 the Arduino hangs. Can someone help with that again please.

// Handle the function code Read Input Registers (FC=04) and write back the values from
// the analog input pins (input registers).
uint8_t readAnalogIn(uint8_t fc, uint16_t address, uint16_t length)
{
  if (address == 10)
  {
    slave.writeRegisterToBuffer(10, bme280.getTemperature());

    return STATUS_OK;
  }
  
   else {// Check if the requested addresses exist in the array
        if (address > analog_pins_size || (address + length) > analog_pins_size)
        {
            return STATUS_ILLEGAL_DATA_ADDRESS;
        }

        // Read the analog inputs
        for (int i = 0; i < length; i++)
        {
            // Write the state of the analog pin to the response buffer.
            slave.writeRegisterToBuffer(i, analogRead(analog_pins[address + i]));
        }

        return STATUS_OK;
        }
}

@Apulanta
Copy link

Apulanta commented May 5, 2020

Try if you are interested enough to edit "https://github.com/yaacov/arduino-irrigation-timer"
application. It has an EEPROM as well as an I2C bus RTC device to which other I2C devices can be added.
In this "irrigation-timer" the application writes directly to the modbus register and not to the buffer as that other.
I made an EC-fan control app for this "irrigation-timer" with an OLED Adafruit_SSD1306 display which is updated in 1/1000 loop round and modbus works without any problems when making registry queries.
I got a well-functioning and interesting application with eg: PID control, PWM output 0-10V, 0-10V Control voltage, NTC-10 temperature measurement, RPM measurement, OLED-SSD1306 display and modbus bus wirelessly with LORA radio.

@ysmilda
Copy link
Contributor

ysmilda commented May 5, 2020

@DpunktS usually when a i2c sensor hangs the Arduino when being read it is due to the Wire interface not initialised properly. Try calling Wire.begin() in your setup.

P.s. Also you shouldn't insert the measurement at place 10. This 10 refers to the amount of response values. Try writing the measurement to register 0

@DpunktS
Copy link
Author

DpunktS commented May 12, 2020

I have now managed to read a BME280. The sketch doesn't look nice, but it is enough for a beginner.
Temperature, pressure, air humidity, absolute air humidity and dew point are transmitted and if the sensor is not connected, a 0 is displayed if the pullups keep SCL and SDA high. Maybe someone doesn't want to make the sketch beautiful and record it on Github.
Modbus_BME280.txt

@yaacov
Copy link
Owner

yaacov commented May 12, 2020

@DpunktS nice !

@ysmilda
Copy link
Contributor

ysmilda commented May 12, 2020

@DpunktS As it seems that you're only using this to read the BME280 sensor I would simplify it to this:
Modbus_BME280.txt
That makes it easiere for you to follow your logic and expand it further.

By adding sensor names to the enum you automatically enlarge the struct which can be read over modbus. This way you can add any measurement to modbus easily.

@DpunktS
Copy link
Author

DpunktS commented May 13, 2020

hello i still use the analog and digital pins + bme280. The Arduino controls and monitors a heating circuit distributor heating / cooling.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants