Serial communication not working when class is instantiated in Arduino Environment - c++

I'm trying to write code for my Arduino Mega to communicate with ADXL345 accelerometer using c++ style library.
This is my Accelerometer.h file:
#include <Wire.h>
#define ADXL345 (0x53) // I2C Address of ADXL345 accelerometer
struct Acceleration
{
float x;
float y;
float z;
};
class Accelerometer
{
public:
Accelerometer(void); // Constructor
Acceleration readData(void); // Read sensor data
private:
char buffer[6]; // Buffer to store data (x, y, z: LSB and MSB of each)
char DATA_FORMAT; // Address of DATA_FORMAT Register
char POWER_CTL; // Address of POWER_CTL Register
char DATAX0; // Address of X-Axis LSB Data
char DATAX1; // Address of X-Axis MSB Data
char DATAY0; // Address of Y-Axis LSB Data
char DATAY1; // Address of Y-Axis MSB Data
char DATAZ0; // Address of Z-Axis LSB Data
char DATAZ1; // Address of Z-Axis MSB Data
void writeToAccelerometer(char address, char value);
void readFromAccelerometer(char address, int numOfBytes);
};
And this is my Accelerometer.cpp file:
#include "Accelerometer.h"
#include <Wire.h>
Accelerometer::Accelerometer()
{
Wire.begin(); // Initialize I2C bus
writeToAccelerometer(DATA_FORMAT, 0x01); // +/- 4g range
writeToAccelerometer(POWER_CTL, 0x08); // Measurement Mode
DATA_FORMAT = 0x31; // Address of DATA_FORMAT Register
POWER_CTL = 0x2D; // Address of POWER_CTL Register
DATAX0 = 0x32; // Address of X-Axis LSB Data
DATAX1 = 0x33; // Address of X-Axis MSB Data
DATAY0 = 0x34; // Address of Y-Axis LSB Data
DATAY1 = 0x35; // Address of Y-Axis MSB Data
DATAZ0 = 0x36; // Address of Z-Axis LSB Data
DATAZ1 = 0x37; // Address of Z-Axis MSB Data
}
void Accelerometer::writeToAccelerometer(char address, char value)
{
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.write(address); // send register address
Wire.write(value); // send value to write
Wire.endTransmission(); // end transmission
}
void Accelerometer::readFromAccelerometer(char address, int numOfBytes)
{
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.write(address); // send register address
Wire.endTransmission(); // end transmission
Wire.beginTransmission(ADXL345); // start transmission to ADXL345
Wire.requestFrom(ADXL345, numOfBytes); // request some bytes from device
int i = 0;
while(Wire.available()) // while there is data
{
buffer[i] = Wire.read(); // receive a byte and save it in the buffer
i++;
}
Wire.endTransmission(); // end transmission
}
Acceleration Accelerometer::readData()
{
Acceleration R;
readFromAccelerometer(DATAX0, 6); // Read data from sensor
// Merge of data and conversion to int format
int x_acceleration = (((int)buffer[1]) << 8) | buffer[0];
int y_acceleration = (((int)buffer[3]) << 8) | buffer[2];
int z_acceleration = (((int)buffer[5]) << 8) | buffer[4];
R.x = x_acceleration*0.0078;
R.y = x_acceleration*0.0078;
R.z = x_acceleration*0.0078;
return R;
}
I'm using this library im my Arduino sketch with this code:
#include <Wire.h>
#include "Accelerometer.h"
Accelerometer accel;
Acceleration Racc;
void setup()
{
Serial.begin(9600); // Start serial for outbut at 9600 bps
}
void loop()
{
Racc = accel.readData();
// Print data
Serial.print("ACCELERATION - X: ");
Serial.print( Racc.x );
Serial.print(" G / Y: ");
Serial.print( Racc.y );
Serial.print(" G / Z: ");
Serial.print( Racc.z );
Serial.print(" G\n");
delay(100);
}
This code is compilated without erros. However, because of the instantiation of Accelerometer class, Serial communication is not working (I can't see any text in Serial Monitor). When I remove the class instance of the code (letting just Serial communication in code), I can see what is print in Serial Monitor.
Does anybody have any idea about what is going on? I would appreciate any help.

As the ADXL345 can operate either SPI or I2C it needs to be configured, as such. In your case of trying to use it as I2C, the CS of the ADXL345 need to be tied to 3.3V
I2C mode is enabled if the CS pinis tied high to VDD I/O. The CS pin
should always be tied high to VDD I/O or be driven by an external
controller because there is nodefault mode if the CS pin is left
unconnected. Therefore, not taking these precautions may result in an
inability to ommunicatewith the part.
Where in your above code I do not see any pins configured as output to drive the CS.
It has been my experience that when the I2C (wire.h) library is not properly connected to a device it can be blocking. Which is similar to your described symptom here.
You may want to reference your code against others, such as https://github.com/jenschr/Arduino-libraries/tree/master/ADXL345. which appears to fully support the many features of the ADXL345 over I2C

Related

Arduino .read() function interfering with BLE connection

Firstly, I want to apologize as I am new to BLE connectivity and much of Arduino programming. I am busy with a project which in involved making a smart coffee scale which can output data to a smartphone via a BLE connection. I am working with an Arduino nano 33 IoT, and an hx711 load cell amplifier.
I need to create a program where I can send and receive data to and from the Arduino to the smartphone app. I have used standard ArduinoBLE peripheral libraries such as the "BatteryMonitor" sketch and the "ButtonLED" sketch. By combining both of these example sketches together I have managed to established a connection where I can send and receive data.
The problem arises when I try to use functions within the HX711 library such as scale.read(); to retrieve values being output from the hx711 amplifier. When I use a serial read function such as scale.read() the bluetooth connection fails before establishing itself properly. I imagine this is due to the scale.read() function interfering with the serial data being transmitted and received by the Arduino, but I have no clue how to get around this problem.
I basically want to change the battery monitor output to be the output of the value read from the hx711 load cell amplifier but I am struggling to get this to work.
#include "HX711.h"
#include <ArduinoBLE.h>
HX711 scale;
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service
// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEByteCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);
BLEUnsignedCharCharacteristic batteryLevelChar("2A19", // standard 16-bit characteristic UUID
BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes
int oldBatteryLevel = 0; // last battery level reading from analog input
long previousMillis = 0; // last time the battery level was checked, in ms
const int ledPin = LED_BUILTIN; // pin to use for the LED
double val;
void setup() {
Serial.begin(9600);
scale.begin(A1, A0); //Initialized scale on these pins
while (!Serial);
scale.set_scale(432.f); // this value is obtained by calibrating the scale with known weights; see the README for details
scale.tare(); // reset the scale to 0
// set LED pin to output mode
pinMode(ledPin, OUTPUT);
// begin initialization
if (!BLE.begin()) {
Serial.println("starting BLE failed!");
while (1);
}
// set advertised local name and service UUID:
BLE.setLocalName("COFFEE");
BLE.setAdvertisedService(ledService);
// add the characteristic to the service
ledService.addCharacteristic(switchCharacteristic);
ledService.addCharacteristic(batteryLevelChar); // add the battery level characteristic
// add service
BLE.addService(ledService);
// set the initial value for the characeristic:
switchCharacteristic.writeValue(0);
// start advertising
BLE.advertise();
Serial.println("BLE LED Peripheral");
}
void loop()
{
// listen for BLE peripherals to connect:
BLEDevice central = BLE.central();
// if a central is connected to peripheral:
if (central) {
Serial.print("Connected to central: ");
// print the central's MAC address:
Serial.println(central.address());
// while the central is still connected to peripheral:
while (central.connected())
{
// Battery Monitor
// scale.read();
long currentMillis = millis();
// if 200ms have passed, check the battery level:
if (currentMillis - previousMillis >= 200) {
previousMillis = currentMillis;
// scale.read(); // This function alone will prevent the BLE connection from establishing properly.
updateBatteryLevel();
// outputScale();
}
// if the remote device wrote to the characteristic,
// use the value to control the LED:
if (switchCharacteristic.written()) {
if (switchCharacteristic.value()) { // any value other than 0
Serial.println("LED on");
digitalWrite(ledPin, HIGH); // will turn the LED on
} else { // a 0 value
Serial.println(F("LED off"));
digitalWrite(ledPin, LOW); // will turn the LED off
}
}
}
// when the central disconnects, print it out:
Serial.print(F("Disconnected from central: "));
Serial.println(central.address());
}
}
void updateBatteryLevel()
{
/* Read the current voltage level on the A0 analog input pin.
This is used here to simulate the charge level of a battery.
*/
int battery = analogRead(A0);
int batteryLevel = map(battery, 0, 1023, 0, 100);
if (batteryLevel != oldBatteryLevel) { // if the battery level has changed
// Serial.print("Battery Level % is now: "); // print it
Serial.println(batteryLevel);
batteryLevelChar.writeValue(batteryLevel); // and update the battery level characteristic
oldBatteryLevel = batteryLevel; // save the level for next comparison
}
}
void outputScale(){
int t, i, n, T;
double val, sum, sumsq, mean;
float stddev;
n = 20;
t = millis();
i = sum = sumsq = 0;
while (i<n) {
val = ((scale.read() - scale.get_offset()) / scale.get_scale());
sum += val;
sumsq += val * val;
i++;
}
t = millis() - t;
mean = sum / n;
stddev = sqrt(sumsq / n - mean * mean);
// Serial.print("Mean, Std Dev of "); Serial.print(i); Serial.print(" readings:\t");
Serial.print(sum / n, 3); Serial.print("\n"); // Serial.print(stddev, 3);
// Note: 2 sigma is 95% confidence, 3 sigma is 99.7%
//Serial.print("\nTime taken:\t"); Serial.print(float(t)/1000, 3); Serial.println("Secs\n");
/*
scale.power_down(); // put the ADC in sleep mode
delay(5000);
scale.power_up();
*/
}
You are initialising as scale.begin(A1, A0) while trying to read from the same A0 pin.

Separating a MQ4 gas Sensor particle photon code into a .h and .cpp files

I am new here. I was working with particle Photon and MQ4 I2C gas sensor.
I have a normal I2C code for this sensor
#include <application.h>
#include <spark_wiring_i2c.h>
// ADC121C_MQ4 I2C address is 0x50(80)
#define Addr 0x50
int raw_adc = 0;
double ppm = 0.0;
void setup()
{
// Set variable
Particle.variable("i2cdevice", "ADC121C_MQ4");
Particle.variable("PPM", ppm);
// Initialise I2C communication as MASTER
Wire.begin();
// Initialise serial communication, set baud rate = 9600
Serial.begin(9600);
delay(300);
}
void loop()
{
unsigned int data[2];
// Start I2C transmission
Wire.beginTransmission(Addr);
// Select data register
Wire.write(0x00);
// Stop I2C transmission
Wire.endTransmission();
// Request 2 bytes of data
Wire.requestFrom(Addr, 2);
// Read 2 bytes of data
// raw_adc msb, raw_adc lsb
if (Wire.available() == 2)
{
data[0] = Wire.read();
data[1] = Wire.read();
}
delay(300);
// Convert the data to 12-bits
raw_adc = ((data[0] & 0x0F) * 256) + data[1];
ppm = (10000 / 4096.0) * raw_adc + 200.0;
// Output data to dashboard
Particle.publish("Methane concentration : ", String(ppm));
delay(1000);
}
So I am a noob in coding and don't know how to separate this code into .cpp and .h files to get the clean code.
Please help me out, how this code can be converted into .cpp and .h files.
Thanx in advance.

communicating state of a potentiometer with a second arduino board

I am trying to get an arduino board to read the state of a potentiometer which is connected to a master arduino board, without connecting the potentiometer to the second board with physical cables
I have tried using Wire.write and Wire.read to just transfer the one value.
The master arduino code:
#include <Wire.h>
const int dial = A0;
int reading = 0;
void setup() {
pinMode(dial, INPUT);
Wire.begin();
}
void loop() {
reading = analogRead(dial);
Wire.beginTransmission(9);
Wire.write(reading);
Wire.endTransmission();
}
The slave arduino code:
#include <Wire.h>
int reading = 0;
void setup() {
Wire.begin(9);
Serial.begin(9600);
Wire.onReceive(receiveEvent);
}
void receiveEvent(int bytes) {
reading = Wire.read();
}
void loop() {
Serial.println(reading);
}
When I read the Serial Monitor, the potentiometer or "reading" in the slave arduino limits at 255 (I don't know why) in 6 intervals (goes from 0 to 255, then drops to 0 and does that 6 times). I expect it to do the full range of the potentiometer to cap out at 1023.
Your ADC is 10bit and won’t fit in a byte. (Wire.write(value) sends value as a single byte). You need to send reading in 2 bytes. Here is how to make 2 bytes.
byte data1 = highByte(reading);
byte data2 = lowByte(reading);
On receiving side, reconstruct an int this way.
byte data1 = Wire.read();
byte data2 = Wire.read();
reading = int(data1) << 8 | data2;

Transmitting data from GPS to SIGFOX

I'm working on an Arduino board (microprocessor: ATMega328P) for a University project. I'd like to build a GPS tracker which receives data, stores it, and retransmit it via SIGFOX module.
Basically, I'm able to receive data, and I'm able to send simple SIGFOX commands via serial.
#include <TinyGPS++.h>
#include <String.h>
#include <SoftwareSerial.h>
static const int RXPin = 4, TXPin = 3;
static const uint32_t GPSBaud = 4800;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
void setup()
{
Serial.begin(115200);
ss.begin(GPSBaud);
Serial.println(F("DeviceExample.ino"));
Serial.println(TinyGPSPlus::libraryVersion());
Serial.println();
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
while (ss.available() > 0)
if (gps.encode(ss.read())) {
Serial.print(gps.location.lat(), 6); // 4 bytes
Serial.print(F(",")); // 1 byte
Serial.print(gps.location.lng(), 6); // 4 bytes
Serial.print('\n');
delay(4000);
}
if (millis() > 5000 && gps.charsProcessed() < 10){
Serial.println(F("No GPS detected: check wiring."));
while (true);
}
}
This prints correctly on screen the two values (latitude and longitude) that I need to store.
This is the part of the code in TinyGPS++.cpp :
double TinyGPSLocation::lat()
{
updated = false;
double ret = rawLatData.deg + rawLatData.billionths / 1000000000.0;
return rawLatData.negative ? -ret : ret;
}
double TinyGPSLocation::lng()
{
updated = false;
double ret = rawLngData.deg + rawLngData.billionths / 1000000000.0;
return rawLngData.negative ? -ret : ret;
}
Now I'd like to store this data and send it through the SIGFOX module.
A SIGFOX command is:
'N X'
Where N represents the number of bytes that are to be transmitted, and X are the values of the bytes. For example: '1 255' is 1 byte with value 255, and returns FF as output.
The problem is that the values are doubles so I don't know how to write them in the SIGFOX command.
Another problem is that I don't know how to create two serial communications in the code. I tried it but it doesn't seem to work.
Thank you so much in advance.
I saw some of the API info on the SIGFOX, I'm assuming it is this. Even if it isn't it's probably close enough for the point I'm trying to make.
https://support.sigfox.com/apidocs#operation/getDevice
You need to understand to some extent what IEEE 754 is as in my experience this is how equipment passes the data back and forth if you look at the raw bit stream.
https://en.wikipedia.org/wiki/IEEE_754
So, it is a double you send over 8 bytes on most platforms and 4 bytes for a float. When you print to the screen of hover over a variable in debug mode, the IDE/compiler takes care of this for you and gives you number with decimal points.
For making another serial port, you need to make another variable and pass in the baud rate etc of that device.

no matching function for call unresolved overloaded function type

First I'm a newbie to C++ so my question might be already answered somewhere but I couldn't find a straightforward answer to it.
I'm creating a simple library for my hardware. I'm using a Scheduler library which is working fine on Arduino IDE (here is the example), but when I compile the code with my own IDE (Atom+PlatformIO) this error comes up:
lib\SRF08\SRF08.cpp:43:30: error: no matching function for call to 'SchedulerClass::startLoop(<unresolved overloaded functi
on type>)'
I removed some of the codes but if you need the rest I can put it.
SRF08.h
#ifndef SRF08_h
#define SRF08_h
#include "Arduino.h"
class SRF08
{
public:
//main constructor
SRF08(uint8_t address=address_1);
// init the sensor
void begin(void);
//change sensor address from oldAddress to newAddress
void changeAddress(uint16_t oldAddress, uint16_t newAddress);
// scan for a single sensor address
int8_t scanner(void);
// scan for multiple sensors and return the table of addresses
struct table_value scan_all(void);
uint16_t output_value;
void read(void);
private:
// the main I2C address of Sensor
uint16_t _address;
//read sansor value base on centimiter
};
#endif
SRF08.cpp
#include "Wire.h"
#include "SRF08.h"
// Include Scheduler since we want to manage multiple tasks.
#include "Scheduler.h"
SRF08::SRF08(uint8_t address)
{
//main constructor, address is the sensor address if u dont know it try scanner first
//address must be an integer number between 1 to 9
if (address == 1) _address = address_1;
else _address = address_1;
}
void SRF08::begin(){
//initilize I2C
Wire.begin();
output_value = 0;
Scheduler.startLoop(SRF08::read); //here is my error
}
void SRF08::read(){
int reading = 0;
// step 1: instruct sensor to read echoes
Wire.beginTransmission(_address); // transmit to device #112 (0x70)
// the address specified in the datasheet is 224 (0xE0)
// but i2c adressing uses the high 7 bits so it's 112
Wire.write(byte(0x00)); // sets register pointer to the command register (0x00)
Wire.write(byte(0x51)); // command sensor to measure in "inches" (0x50)
// use 0x51 for centimeters
// use 0x52 for ping microseconds
Wire.endTransmission(); // stop transmitting
// step 2: wait for readings to happen
delay(70); // datasheet suggests at least 65 milliseconds
// step 3: instruct sensor to return a particular echo reading
Wire.beginTransmission(_address); // transmit to device #112
Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02)
Wire.endTransmission(); // stop transmitting
// step 4: request reading from sensor
Wire.requestFrom(_address, 2); // request 2 bytes from slave device #112
// step 5: receive reading from sensor
if (2 <= Wire.available()) { // if two bytes were received
reading = Wire.read(); // receive high byte (overwrites previous reading)
reading = reading << 8; // shift high byte to be high 8 bits
reading |= Wire.read(); // receive low byte as lower 8 bits
output_value = reading; // print the reading
}
//yield();
}
Scheduler.h
#ifndef _SCHEDULER_H_
#define _SCHEDULER_H_
#include <Arduino.h>
extern "C" {
typedef void (*SchedulerTask)(void);
typedef void (*SchedulerParametricTask)(void *);
}
class SchedulerClass {
public:
SchedulerClass();
static void startLoop(SchedulerTask task, uint32_t stackSize = 1024);
static void start(SchedulerTask task, uint32_t stackSize = 1024);
static void start(SchedulerParametricTask task, void *data, uint32_t stackSize = 1024);
static void yield() { ::yield(); };
};
extern SchedulerClass Scheduler;
#endif
Scheduler.cpp
#include "Scheduler.h"
extern "C" {
#define NUM_REGS 10 // r4-r11, sp, pc
typedef struct CoopTask {
uint32_t regs[NUM_REGS];
void* stackPtr;
struct CoopTask* next;
struct CoopTask* prev;
} CoopTask;
static CoopTask *cur = 0;
...
void yield(void) {
coopDoYield(cur);
}
}; // extern "C"
SchedulerClass::SchedulerClass() {
coopInit();
}
static void startLoopHelper(void *taskData) {
SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
while (true)
task();
}
void SchedulerClass::startLoop(SchedulerTask task, uint32_t stackSize) {
coopSpawn(startLoopHelper, reinterpret_cast<void *>(task), stackSize);
}
static void startTaskHelper(void *taskData) {
SchedulerTask task = reinterpret_cast<SchedulerTask>(taskData);
task();
}
void SchedulerClass::start(SchedulerTask task, uint32_t stackSize) {
coopSpawn(startTaskHelper, reinterpret_cast<void *>(task), stackSize);
}
void SchedulerClass::start(SchedulerParametricTask task, void *taskData, uint32_t stackSize) {
coopSpawn(task, taskData, stackSize);
}
SchedulerClass Scheduler;
Thanks to #Someprogrammerdude to help. I needed to declare the read function as static.
SRF08.h
#ifndef SRF08_h
#define SRF08_h
#include "Arduino.h"
class SRF08
{
public:
//main constructor
SRF08(uint8_t address=address_1);
// init the sensor
void begin(void);
//change sensor address from oldAddress to newAddress
void changeAddress(uint16_t oldAddress, uint16_t newAddress);
// scan for a single sensor address
int8_t scanner(void);
// scan for multiple sensors and return the table of addresses
struct table_value scan_all(void);
static uint16_t output_value;
static void read(void);
static uint16_t static_address;
private:
// the main I2C address of Sensor
uint16_t _address;
//read sansor value base on centimiter
};
#endif
SRF08.cpp
#include "Wire.h"
#include "SRF08.h"
// Include Scheduler since we want to manage multiple tasks.
#include "Scheduler.h"
//initilize static members
uint16_t SRF08::output_value;
uint16_t SRF08::static_address;
SRF08::SRF08(uint8_t address)
{
//main constructor, address is the sensor address if u dont know it try scanner first
//address must be an integer number between 1 to 9
if (address == 1) _address = address_1;
else _address = address_1;
static_address = _address;
//begin();
}
void SRF08::begin(){
//initilize I2C
Wire.begin();
output_value = 0;
Scheduler.startLoop(read); //here is my error
}
void SRF08::read(){
int reading = 0;
// step 1: instruct sensor to read echoes
Wire.beginTransmission(static_address); // transmit to device #112 (0x70)
// the address specified in the datasheet is 224 (0xE0)
// but i2c adressing uses the high 7 bits so it's 112
Wire.write(byte(0x00)); // sets register pointer to the command register (0x00)
Wire.write(byte(0x51)); // command sensor to measure in "inches" (0x50)
// use 0x51 for centimeters
// use 0x52 for ping microseconds
Wire.endTransmission(); // stop transmitting
// step 2: wait for readings to happen
delay(70); // datasheet suggests at least 65 milliseconds
// step 3: instruct sensor to return a particular echo reading
Wire.beginTransmission(static_address); // transmit to device #112
Wire.write(byte(0x02)); // sets register pointer to echo #1 register (0x02)
Wire.endTransmission(); // stop transmitting
// step 4: request reading from sensor
Wire.requestFrom(static_address, 2); // request 2 bytes from slave device #112
// step 5: receive reading from sensor
if (2 <= Wire.available()) { // if two bytes were received
reading = Wire.read(); // receive high byte (overwrites previous reading)
reading = reading << 8; // shift high byte to be high 8 bits
reading |= Wire.read(); // receive low byte as lower 8 bits
output_value = reading; // print the reading
//output_value = reading;
}
yield();
}