Forum Replies Created
-
AuthorPosts
-
Alright, here’s something. I can’t promise it *works*, but I’d like to see the results.
C++1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798#include <Arduino.h>#include <Wire.h>#define DEVICE_I2C_ADDRESS \0x4D // I *think* this is the address it's using for itself// https://github.com/NorthernWidget-Skunkworks/Project-Walrus/blob/b5d9cc1fdfe2cf16fb5048a1f9ff0b27253c3a94/Firmware/Walrus_I2C_5BA/Walrus_I2C_5BA.ino#L155// A helpful union for flipping between bytes to longstypedef union leFrame {byte Byte[4]; // 4 bytes will occupy 4 bytesuint32_t uInt32; // a single float occupies 4 bytes} leFrame;void setup() {Wire.begin(); // join i2c bus (address optional for master)Serial.begin(9600); // start serial for output// NOTE: Something may have to happen here to "start the thing up"// I can't tell if they intend that or not}void loop() {// It looks like the control register (0x00) is being set to 0x7F// (0b1111111) when values are being written (ie, values aren't ready) and// to 0x80 (0b10000000) when it's ready.// https://github.com/NorthernWidget-Skunkworks/Project-Walrus/blob/b5d9cc1fdfe2cf16fb5048a1f9ff0b27253c3a94/Firmware/Walrus_I2C_5BA/Walrus_I2C_5BA.ino#L242byte control_flag = 0x7f;while (control_flag == 0x7f) {Wire.beginTransmission(DEVICE_I2C_ADDRESS); // select device with "beginTransmission()"Wire.write(0x00); // select starting register with "write()"Wire.endTransmission(); // end write operation, as we just wanted to// select the starting registerWire.requestFrom(DEVICE_I2C_ADDRESS,1); // select number of bytes to get from the device// (1 byte in this case)control_flag = Wire.read(); // read from the starting register}// We'll try reading all the registers at once sequentially instead of// reading one after the other// the registers are loaded starting on line 242:// https://github.com/NorthernWidget-Skunkworks/Project-Walrus/blob/master/Firmware/Walrus_I2C_5BA/Walrus_I2C_5BA.ino#L242Wire.beginTransmission(DEVICE_I2C_ADDRESS); // select device with "beginTransmission()"Wire.write(0x02); // select starting register with "write()"// the first data register is pressure starting in register 0x02Wire.endTransmission(); // end write operation, as we just wanted to select// the starting register// select number of bytes to get from the device// + 4 for pressure in microbars (ie mbar*1000)// + 4 for temp0 - This is the temperature from the MCP9808 (*10000.0)// + 4 for temp1 - This is the temperature from the MS5803 (*10000.0)Wire.requestFrom(DEVICE_I2C_ADDRESS, 12);// We won't bother to read the next 8 bytes of unchanging sensor// information:// + 2 for model (uint16_t)// + 2 for group id (uint16_t)// + 2 for "INDID" ?dummy? (uint16_t)// + 2 for firmware id (uint16_t))// my helpful unionleFrame fram;// NOTE: may need to flop endinaness for the values.// if getting garbage, try switching all for loops to// 'for (int8_t i = 0; i<4; i++)'// get pressure from the first 4 bytes, reversing order/endiannessfor (int8_t i = 4; i; i--) { fram.Byte[i] = Wire.read(); }float pressure = fram.uInt32 / 1000;// get MCP9808 temp from the next 4 bytes, reversing order/endiannessfor (int8_t i = 4; i; i--) { fram.Byte[i] = Wire.read(); }float temp_mcp9808 = fram.uInt32 / 10000;// get MS5803 temp from the last 4 bytes, reversing order/endiannessfor (int8_t i = 4; i; i--) { fram.Byte[i] = Wire.read(); }float temp_ms5803 = fram.uInt32 / 10000;// print the resultsSerial.print("MS5803 Pressure: ");Serial.print(pressure);Serial.println(" mbar");Serial.print("MCP9808 Temperature: ");Serial.print(temp_mcp9808);Serial.println(" °C");Serial.print("MS5803 Temperature: ");Serial.print(temp_ms5803);Serial.println(" °C");// wait 5s and then repeatSerial.println("---");delay(5000);}post deleted
I’m sorry, I’m looking through their firmware and trying to figure something out for you. I hate half-answering a question.
WRT to the wire distance, yes and no.
RS485 is a two-wire protocol where 0’s and 1’s are differentiated by the difference in voltage between the two wires. Electrically, this means it can be used over long distances (ie, up to 4,000 feet). To use RS485 the processors that are talking each need to have their own internal clocks and each separately need to be told the speed at which they will send the bits and how many bits make up one letter. The processors also need to agree on a way to determine whose turn it is to talk and whose turn it is to listen. Modbus is a common choice, but there are many others.
I2C is also a two-wire protocol, but the 0’s and 1’s are based on the voltage of a single wire and the second wire works as the clock. This configuration does not lend itself to long wires; I2C is usually used between chips on the same circuit board. It’s theoretical limit is only about 1m, but, as you’ve seen when using the MPL directly, 3m can sometimes be managed.
I2C and RS485 are two different communication protocols. They specify what change marks a 1 or a 0 when transferring information. I2C also (mostly) specifies the question-and-answer format. So knowing you have I2C firmware gets you some of the way there, but not very far. You need to know what question to ask the board and what it’s response will be.
I’m guessing this is the firmware they gave you: https://github.com/NorthernWidget-Skunkworks/Project-Walrus/blob/master/Firmware/Walrus_I2C_5BA/Walrus_I2C_5BA.ino. That would be the program the microcontroller on the Walrus itself is running, not what the Mayfly needs to run to talk to it.
Someone has to dig through their firmware file and reverse engineer the communication protocol.
Bobby Shultz or Northern Widget did some of the work to incorporate the MPL115A into ModularSensors, but I haven’t followed what they’ve been doing.
It looks like this Walrus thing has an on-board processor that in between the Mayfly and the MPL115A. So you need to use whatever protocol they’ve developed for themselves not the MPL’s I2C protocol. It looks like they have both I2C and RS485 firmware available and some instructions on how to upload the firmware to said on-board processor. Do you know which you have? Their demo code, true to it’s warning, is based on a library that doesn’t yet exist. Have you tried contacting Northern Widget directly to ask for help?
The “best” way to work with ModularSensors would be to write the c/h files and submit them as a pull request. 🙂 But if the calculated variable is working, then feel free to keep using it that way for yourself.
If you define your variable for the DS18 temperature as something like
Variable* ds18Temp = new MaximDS18_Temp(&ds18, "12345678-abcd-1234-ef00-1234567890ab);
then in your calculation equation you would use something like
float ds18TempVal = ds18Temp ->getValue();
The “baro_rho_correction” example is probably the best one to look at to see something similar in action: https://github.com/EnviroDIY/ModularSensors/blob/master/examples/baro_rho_correction/baro_rho_correction.ino
Oops, sorry that I missed this.
Are you using slashDevin’s original NeoSWSerial or are you using my fork? (It’s in SRGDamia1, not EnviroDIY.) The original didn’t implement the peek function which would cause it to fail.
The address of the DS3231 isn’t changeable – it’s permanently set when the chip is manufactured. Is there any other way your sensor can communicate? Does it have a physical addressing method? Many I2C sensors have an “addr” pin that you can set to be high or low to change the address. Can it communicate via SPI or UART so you can use one of those to change the address?
-
AuthorPosts