Using SoftwareSerial as a private member variable - arduino

I'm trying to convert Sparkfun's example code for the SM130 RFID Reader into a class/library that's encapsulated nicely and can be used in multiple arduino sketches.
Sparkfun Example Code: https://github.com/sparkfun/RFID_Evaluation_Shield/blob/master/Firmware/RFID_Eval_13_56MHz.ino
Most of it went pretty smoothly, until I tried to make the Software Serial communications a member variable -- I keep getting errors like:
/Users/scottnla/Dropbox/arduino/libraries/SM130/SM130.cpp: In constructor 'SM130::SM130()':
/Users/scottnla/Dropbox/arduino/libraries/SM130/SM130.cpp:8: error: no matching function for call to 'SoftwareSerial::SoftwareSerial()'
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/SoftwareSerial.h:83: note: candidates are: SoftwareSerial::SoftwareSerial(uint8_t, uint8_t, bool)
/Applications/Arduino.app/Contents/Resources/Java/libraries/SoftwareSerial/SoftwareSerial.h:48: note: SoftwareSerial::SoftwareSerial(const SoftwareSerial&)
I found a stackoverflow post that seems to address this issue (Creating a Library for an Arduino), but their solution doesn't seem to work for me. The IDE's error messages seem to indicate that I can only use a 'base initializer' in a constructor; but this isn't what I want. What's the best way to deal with the problem that I'm having in my code?
Thanks!
Code below:
SM130.h
#ifndef SM130_h
#define SM130_h
#include<Arduino.h>
#include <WConstants.h>
class SM130 {
public:
SM130();
void connect(int RX, int TX);
void check_for_notag();
void halt_tag();
void parse_tag();
void print_serial();
void seek_tag();
void set_flag();
private:
int rfid_flag;
int data[11];
SoftwareSerial rfid;
};
#endif
SM130.cpp
#include <WProgram.h>
#include <SoftwareSerial.h>
#include "SM130.h"
SM130::SM130() {
rfid_flag = 0;
}
void SM130::connect(int RX, int TX) : rfid(RX, TX) {
if(!Serial.available()) {
Serial.begin(9600);
}
Serial.println("Connecting to SM130 RFID Reader...");
//rfid = SoftwareSerial(RX, TX);
rfid.begin(19200);
if(rfid.available()) {
rfid.println("Connected to SM130 RFID Reader!");
}
delay(10);
}
void SM130::check_for_notag() {
seek_tag();
delay(10);
parse_tag();
set_flag();
if(rfid_flag == 1) {
seek_tag();
delay(10);
parse_tag();
}
}
void SM130::halt_tag() {
rfid.write(0xFF);
rfid.write((byte)0x00); //manual typecasting needed for 0x00 to differentiate it from null pointer -- silly c compilers!
rfid.write(0x01);
rfid.write(0x93);
rfid.write(0x94);
}
void SM130::parse_tag() {
while(rfid.available()) {
if(rfid.read() == 0xFF) {
for(int i = 1; i < 11; i++) {
data[i] = rfid.read();
}
}
}
}
void SM130::print_serial() {
if(rfid_flag == 1) {
Serial.print(data[5],HEX);
Serial.print(data[6],HEX);
Serial.print(data[7],HEX);
Serial.print(data[8],HEX);
Serial.println();
}
}
void SM130::seek_tag() {
//insert hex tags here
rfid.write(0xFF);
rfid.write((byte)0x00); //manual typecasting needed for 0x00 to differentiate it from null pointer -- silly c compilers!
rfid.write(0x01);
rfid.write(0x82);
rfid.write(0x83);
}
void SM130::set_flag() {
if(data[2] == 6) {
rfid_flag++;
}
if(data[2] == 2) {
rfid_flag = 0;
}
}
My arduino sketch:
#include <SM130.h>
void read_serial();
SM130 rfidReader;
void setup() {
//Connect to computer
Serial.begin(9600);
//connect to SM130
rfidReader.connect(7,8);
}
void loop() {
read_serial();
}
void read_serial() {
rfidReader.seek_tag();
delay(10);
rfidReader.parse_tag();
rfidReader.set_flag();
rfidReader.print_serial();
delay(100);
}

/Users/scottnla/Dropbox/arduino/libraries/SM130/SM130.cpp: In
constructor 'SM130::SM130()':
/Users/scottnla/Dropbox/arduino/libraries/SM130/SM130.cpp:8: error: no
matching function for call to 'SoftwareSerial::SoftwareSerial()'
This part tells you everything. SoftwareSerial has no constructor without argument list, so you try to call a non-existing function.
If you don't specify a class member in constructor's initialization list, compiler by default calls () constructor for it. It is equivalent of:
SoftwareSerial ss;
if we weren't talking about classes.
http://www.cprogramming.com/tutorial/initialization-lists-c++.html
Unfortunately SoftwareSerial has no Set methods.
http://arduino.cc/de/Reference/SoftwareSerial
But worry not, dynamic memory allocation comes to the rescue! For example:
SM130.h
#ifndef SM130_h
#define SM130_h
#include<Arduino.h>
#include <WConstants.h>
class SM130 {
public:
SM130();
~SM130();
void connect(int RX, int TX);
void check_for_notag();
void halt_tag();
void parse_tag();
void print_serial();
void seek_tag();
void set_flag();
private:
int rfid_flag;
int data[11];
SoftwareSerial* rfid;
};
#endif
SM130.cpp (only some methods)
SM130::SM130() : rfid(NULL) {
rfid_flag = 0;
}
void SM130::connect(int RX, int TX) {
if(!Serial.available())
{
Serial.begin(9600);
}
Serial.println("Connecting to SM130 RFID Reader...");
if (NULL != rfid)
{
delete rfid;
}
rfid = new SoftwareSerial(RX, TX)
rfid->begin(19200);
if(rfid->available())
{
rfid->println("Connected to SM130 RFID Reader!");
}
delay(10);
}
~SM130::SM130()
{
if (NULL != rfid)
{
delete rfid;
}
}
I only posted my versions of constructor, connect and destructor (good to have it for avoiding memory leaks).
Don't forget about:
Checking if rfid is not NULL (better use NULL != rfid instead of rfid != NULL, because compiler will tell you about mistakes like if (rfid = NULL))
Changing rfid. to rfid->
You can even add disconnect method, which deletes old rfid and sets pointer to NULL:
void SM130::disconnect() {
delete rfid;
rfid = NULL;
}

Related

Send and read the button state via CAN bus using Arduino

I'm intending to read the change of button input using 2 separate Arduino that connected via CAN bus (MP2515). The transmitter will connect to button with internal pulldown resistor, that pin will act as external interrupt. My reference is coming from here. By not assign any value to data frame (canMsg1 and canMsg2 in the code below), is that enough for the receiver to understand the input pin state?
The origin code using digitalRead(pin) to read and later write state of the button by single Arduino.
transmitter of CAN massage
#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg1;
struct can_frame canMsg2;
MCP2515 mcp2515(10);
int incPin(2);
int decPin(3);
unsigned long current_time = 0;
unsigned long previous_time = 0;
void setup() {
Serial.begin(9600);
SPI.begin();
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
mcp2515.setNormalMode();
canMsg1.can_id = 0xAA;
canMsg1.can_dlc = 1;
canMsg2.can_id = 0xBB
canMsg2.can_dlc = 1;
pinMode(incPin, INPUT_PULLUP);
pinMode(decnPin, INPUT_PULLUP);
attachInterrupt(incpPin, inc, FALLING);
attachInterrupt(decPin, dec, FALLING);
}
void loop() {}
void inc() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.sendMessage(&canMsg1);
}
previous_time = current_time;
}
void dec() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.sendMessage(&canMsg2);
}
previous_time = current_time;
}
receiver/reader of CAN massage
#include <SPI.h>
#include <mcp2515.h>
struct can_frame canMsg1;
struct can_frame canMsg2;
MCP2515 mcp2515(10);
int pos = 0;
int up;
int down;
void setup() {
Serial.begin(9600);
SPI.begin();
mcp2515.reset();
mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
mcp2515.setNormalMode();
}
void loop() {
if (mcp2515.readMessage(&canMsg1) == MCP2515::ERROR_OK) { //read CAN increment button message
if (canMsg1.can_id==0xAA) {
up = canMsg1.data[0];
if (up == LOW) {
pos++;
} else {}
}
}
if (mcp2515.readMessage(&canMsg2) == MCP2515::ERROR_OK) { //read CAN decrement button message
if (canMsg2.can_id==0xBB) {
down = canMsg2.data[0];
if (down == LOW) {
pos--;
} else {}
}
}
}
You are right, your CAN events do not require any data. But then, why do you set can_dlc to 1? No data is 0 bytes.
You can try this:
Get rid of:
struct can_frame canMsg1; // these only hog global memory for no practical use.
struct can_frame canMsg2;
Change your interrupt routines to:
void inc() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.beginPacket(0xAA);
mcp2515.endPacket();
}
previous_time = current_time;
}
void dec() {
current_time = millis();
if (current_time - previous_time > 200) { //debouncing for 0.2s
mcp2515.beginPacket(0xBB);
mcp2515.endPacket();
}
previous_time = current_time;
}
I could not figure out what canMsg7 and canMsg8 were. Nor why you'd need several message structures in global memory to receive one CAN message at a time... I really don't think that's necessary. Since your packets have no data, receiving gets streamlined as well:
int loop() {
if (mcp2515.parsePacket() != 0) { // != 0 => we have fully received a packet.
switch (mcp2515.packetId()) {
case 0xAA:
// inc switch was pressed
// ...
break;
case 0xBB:
// dec switch was pressed
// ...
break;
}
}
}

How to control the display and non-display of sensor values ​in Arduino using Bluetooth?

I have a sensor that connects to the body and displays muscle signals.
In the setup guide of this sensor, it is said to upload the following code on Arduino, and when we open the Serial Monitor, the sensor values start to be displayed.
Now I want to control the display of these signals using Bluetooth.
So that when I click on the start button in my App, Serial.print() will start working. Also, when I click on the Stop button, the display of these signals and numbers will stop.
Sensor setup guide is this :
void setup() {
Serial.begin(9600);
}
void loop() {
Serial.println(analogRead(A0));
}
And this is how it works properly :
But when I upload a piece of code that I wrote to my Arduino, it only shows me just on value.
this is my code :
#include <SoftwareSerial.h>
SoftwareSerial BTserial(0, 1); // RX | TX
char Incoming_value = 0;
void setup() {
Serial.begin(9600);
BTserial.begin(9600);
}
void loop() {
Incoming_value = Serial.read(); // "1" is for Start
if (Incoming_value == '1') {
Serial.println(Incoming_value);
StartSensor();
}
}
int StartSensor() {
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
delay(200);
}
also please tell me How to write StopSensor Function for Stop print Sensor Value.
Try this code first (Without Bluetooth module)
#include <SoftwareSerial.h>
SoftwareSerial BTserial(0, 1); // RX | TX
char Incoming_value = 0;
int state = 0;
void setup() {
Serial.begin(9600);
//BTserial.begin(9600);
}
void loop() {
Incoming_value = Serial.read(); // "1" is for Start
if (Incoming_value == '1') {
state = 1;
}
else if (Incoming_value == '0') {
state = 0;
}
if (state == 1) {
StartSensor();
} else {
Serial.println(0);
}
}
int StartSensor() {
int sensorValue = analogRead(A0);
Serial.println(sensorValue);
delay(200);
}

Arduino byte[] to string

Hello I am programming a bluetooth connection from Android Studio to Arduino. The connection works and it sends the String. I only get something like this tho on my Arduino (x?xx?xx??xxx?xxx?x) the questionmarks are the other way the string I send is on
This is my code:
#include <SoftwareSerial.h>
#define rxPort 11
#define txPort 10
char btData;
String string;
SoftwareSerial btSerial(rxPort, txPort);
void setup(){
Serial.begin(9600);
btSerial.begin(38400);
Serial.println("bluetooth available");
pinMode(LED_BUILTIN, OUTPUT);
}
void loop(){
if(btSerial.available()>0){
string = "";
}
while(btSerial.available()>0){
btData = (byte)btSerial.read();
if(btData==":"){
break;
}else{
string += btData;
}
delay(1);
Serial.println(string);
}
if(string == "on"){
digitalWrite(LED_BUILTIN,HIGH);
}
}
why do you cast the read to byte??
char it is :)
it should work with 9600 BAUD rate as well
example from my project (I didn't build String though - used single char as command)
SoftwareSerial blue(3, 5); // BlueTooth RX, TX;
void BluetoothSetup()
{
blue.begin(9600);
blue.print("AT+NAMEKuku"); // give it a name
delay(2000);
Serial.println("got BT");
}
void setup() {
....
BluetoothSetup();
....
}
void loop() {
if (blue.available()) {
char r = blue.read();
ProcessRemoteCommand(r);
}
}

Arduino interfacing with GPS gy Neo 6Mv2

I have written the following code. I want the string returned from the method
displayInfo( )
to be updated and printed just once, but the method sends strings repeatedly. If I copy the same code in void setup( ) function it is not printing any value.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 12, TXPin = 13;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS
SoftwareSerial ss(RXPin, TXPin);
String msg="";
String message="";
void setup()
{
Serial.begin(9600);
ss.begin(GPSBaud);
}
void loop()
{
while (ss.available() > 0)
if (gps.encode(ss.read()))
message = displayInfo();
Serial.print(message);
}
String displayInfo()
{
if (gps.location.isValid())
{
String lati=String(gps.location.lat(), 3);
String logi=String(gps.location.lng(),3);
msg=lati+","+logi+"\n";
return(msg);
}
}
I have updated the code to recover some of the errors like function returning value with a global variable but it still does not provide me a single String value even after I had put the void loop( ) code in void setup( )
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 12, TXPin = 13;
static const uint32_t GPSBaud = 9600;
// The TinyGPS++ object
TinyGPSPlus gps;
// The serial connection to the GPS device
SoftwareSerial ss(RXPin, TXPin);
String msg="";
void setup()
{
Serial.begin(9600);
ss.begin(GPSBaud);
while (ss.available()>0)
if (gps.encode(ss.read()))
displayInfo();
Serial.print(msg);
}
void loop()
{
// This sketch displays information every time a new sentence is correctly encoded.
}
void displayInfo()
{
//Serial.print(F("Location: "));
if (gps.location.isValid())
{
String lati=String(gps.location.lat(), 3);
String longi=String(gps.location.lng(), 3);
msg="location: "+lati+","+longi+"\n";
}
else
{
msg=msg+"invalid";
}
}
EDIT:
The ss (SoftwareSerial) has a buffer wich contains the data that is ready to be send. ss.begin() will return 0 in your setup since the buffer is still empty, therefore the while loop will not be iterated even once.
The loop() function of the arduino works like a while so by placing the content of that while loop, and replacing the while with an if, you will be able to keep testing until you have a message in the buffer.
By adding a boolean to check if you have already sent a message, you can make sure only 1 message will be sent.
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
static const int RXPin = 12, TXPin = 13;
static const uint32_t GPSBaud = 9600;
TinyGPSPlus gps;
SoftwareSerial ss(RXPin, TXPin);
boolean sent = false;
void setup()
{
Serial.begin(9600);
ss.begin(GPSBaud);
}
void loop()
{
if (ss.available()>0 && sent == false){
if (gps.encode(ss.read())){
String msg = displayInfo();
if (msg != NULL){
Serial.print(msg);
sent = true;
}
}
}
}
String displayInfo()
{
if (gps.location.isValid())
{
String msg="";
String lati=String(gps.location.lat(), 3);
String logi=String(gps.location.lng(),3);
msg=lati+","+logi+"\n";
return(msg);
}
else{
return NULL;
}
}
By returning a NULL in the displayinfo()'s else statement, and testing for it within the loop(), you can ensure that you will only print a message when everything was working.

I2C between RPI and Arduino using Processing

Posted here is my code for my RPi master and Arduino slave project. I have an analog sensor connected to the Arduino and i am reading this data with Processing on the RPi. I am using Processing because I intend on generating a graph and waveform with the data. The code below seems to work, however, any slight movement of setup "disconnects" the slave device because I get the following message. "The device did not respond. Check the cabling and whether you are using the correct address." I have narrowed the problem down and found out that it always disconnects at the i2c.read();function. My question is whether there is some type of break function so that when this does happen processing moves on and tries again in the next iteration? Or if it is stuck in a loop is it waiting for some signal from the slave device? Does anyone have any suggestions on how to approach this?
Processing Code
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
byte[] in = i2c.read(1);
int accel = in[0];
println (accel);
}
}
Arduino Code
#include <Wire.h>
#define SLAVE_ADDRESS 0x04
int number = 5;
int state = 0;
const int zInput = A0;
int zRawMin = 493;
int zRawMax = 530;
float acceleration;
int accel;
void setup() {
analogReference(EXTERNAL);
pinMode(13,OUTPUT);
Serial.begin(9600); // start serial for output
Wire.begin(SLAVE_ADDRESS); // join i2c bus with address #8
Wire.onReceive(receiveData); // register event
Wire.onRequest(sendData);
Serial.println ("Ready");
}
void loop() {
int zRaw = ReadAxis (zInput);
acceleration = map (float(zRaw), float (zRawMin), float(zRawMax), -9.81, 9.81);
accel = int(acceleration);
//delay(100);
}
void receiveData(int byteCount)
{
while (0 < Wire.available())
{ // loop through all but the last
number = Wire.read(); // receive byte as a character
//Serial.print("data received");
Serial.println(number); // print the character
if (number==1)
{
if (state == 0)
{
digitalWrite(13,HIGH);
state = 1;
}
else
{
digitalWrite(13,LOW);
state = 0;
}
}
}
}
void sendData()
{
Wire.write(accel);
}
int ReadAxis(int axisPin)
{
long reading = 0;
int raw = analogRead(axisPin);
return raw;
}
Looks like a solution might be to use a try/catch block courtesy of #Kevin Workman. It works well for what I need it to do thx.
here is the updated Processing code.
import processing.io.*;
I2C i2c;
int val = 0;
void setup()
{
i2c = new I2C(I2C.list()[0]);
}
void draw ()
{
if (I2C.list() != null)
{
i2c.beginTransmission(0x04);
i2c.write(8);
try
{
byte[] in = i2c.read(1);
}
catch(Exception e)
{
i2c.endTransmission();
}
int accel = in[0];
println (accel);
}
}

Resources