Corrupted value in Arduino array - c++

The program's supposed to constantly listen for 433 MHz messages coming from soil moisture sensors in plant pots and decide whether or not to activate a pump based on those readings.
Additionally it's supposed to check wired water sensors while it's listening.
All 433 MHz Received Messages should be stored within the array sensor_data[i].
At startup the positions 1to NUM_Sensors(in this case 3) is filled with the constant int NO_DATA (500).
The Problem is, that for some reason I get corrupted Number in the array number 3:
Serial Print:
Wired Flower Pots Checked
All Sensors or Timeout reached
Array_Print: 500
Array_Print: 500
Array_Print: 30001
In this case the 30001 appears in the array with no specific reason (I guess).. there's no received message.
Here's the code changed to the minimum so that the error occurs:
#include <RCSwitch.h>
RCSwitch mySwitch = RCSwitch();
//Receiver Setup for wireless soil moisture readings
unsigned long last_ground_check = 0;
const int NUM_SENSORS = 3;
const uint32_t SENSOR_TIMEOUT = 30000;
int sensor_data[NUM_SENSORS];
uint32_t last_message_time = 0;
uint32_t elapsed = 0;
float total_value = 0;
float real_value = 0;
int count = 0;
const int NO_DATA = 500;
boolean received = false;
//###################//
void setup()
{
Serial.begin(9600);
mySwitch.enableReceive(INT1); // Interrupt 2 = Pin 2
delay(1500);
Serial.println("<><><><><><><><><><><><>");
Serial.println(" Start ");
Serial.println("<><><><><><><><><><><><>");
for (int i = 0; i <= NUM_SENSORS; i++) {
sensor_data[i] = NO_DATA;
}
} // Setup END
void loop()
{
if (received == false) {
if (millis() - last_ground_check > 10000) {
Serial.println("Checking Wired Flower Pot");
}
Serial.println("Wired Flower Pots Checked");
last_ground_check = millis();
}
if (mySwitch.available()) { // Start whenever a 433 MHz Message is received
received = true;
double value = mySwitch.getReceivedValue();
delay(1000);
int sensor_id = 1;
int sensor_value = 2;
if (sensor_value >= 0 && sensor_value <= 100) {
sensor_data[sensor_id] = sensor_value;
last_message_time = millis();
mySwitch.resetAvailable();
}
}
byte sensors_reported = 0;
for (int i = 0; i <= NUM_SENSORS; i++) {
if (NO_DATA != sensor_data[i]) {
sensors_reported += 1; // CODE Gets here because of corrupted Array Value although no message was received
}
}
if (sensors_reported != 0) {
uint32_t elapsed = millis() - last_message_time;
if (NUM_SENSORS == sensors_reported || elapsed > SENSOR_TIMEOUT) {
Serial.println("All Sensors or Timeout reached");
for (int i = 1; i <= NUM_SENSORS; i++) {
Serial.print("Array_Print: ");
Serial.println(sensor_data[i]);
}
for (int i = 1; i <= NUM_SENSORS; i++) {
if (sensor_data[i] < NO_DATA) {
count++;
total_value += sensor_data[i];
}
}
real_value = total_value / count;
Serial.print("Soil Moisture: ");
Serial.println(real_value);
if (real_value <= 20) {
//Set Pump ON
}
for (int i = 1; i <= NUM_SENSORS; i++) {
sensor_data[i] = NO_DATA;
}
total_value = 0;
real_value = 0;
sensors_reported = 0;
count = 0;
received = false;
Serial.println("RESET #### RESET ####");
delay(5000);
}
}
} //LOOP

You first allocate an array of size NUM_SENSORS=3, and then you continue to use it as if it was of size 4.
Your array has 3 elements sensor_data[0], [1] and [2]. Your loop condition i <= NUM_SENSORS results in accessing sensor_data[3] which is just some memory after your last array element. Even if you set sensor_data[3] in your setup, if the same memory is referenced by some other variable, the NO_DATA will be overwritten.
Index your loops over the data array from i = 0 to i < NUM_SENSORS.

Related

I'm coding Arduino, but I'm confused about combining 2 sensors and 1 servo with a push button

I'm coding Arduino, but I'm confused about combining 2 sensors and 1 servo with a push button. I hope someone can help me.
I have made one by one the sensor coding and it works, but I want to combine them into one program.
// code void loop water temperatur sensor
void loop(void`{
sensors.requestTemperatures();
Celcius = sensors.getTempCByIndex(0);
Serial.print(Celcius);
Serial.println(" C ");
delay(1000);
}
// this code push button with servo
// code void servo with push button
void loop() {
if (digitalRead(pushButtonPin) == LOW) {
buttonPushed = 1;
Serial.println("Servo ON");
delay(1000);
}
if (buttonPushed) {
// change the angle for next time through the loop:
angle = angle + angleStep;
// reverse the direction of the moving at the ends of the angle:
if (angle >= maxAngle) {
angleStep = -angleStep;
if (type == 1) {
buttonPushed =0;
}
}
if (angle <= minAngle) {
angleStep = -angleStep;
if (type == 2) {
buttonPushed =0;
}
}
myservo.write(angle); // move the servo to desired angle
delay(100); // waits for the servo to get there
}
}
// Ph Sensor code
void loop(void) {
static unsigned long samplingTime = millis();
static unsigned long printTime = millis();
static float pHValue, voltage;
if (millis() - samplingTime > samplingInterval) {
pHArray[pHArrayIndex++] = analogRead(SensorPin);
if (pHArrayIndex==ArrayLenth)
pHArrayIndex=0;
voltage = avergearray(pHArray, ArrayLenth) * 5.0 / 1024;
pHValue = 3 * voltage + Offset;
samplingTime=millis();
}
if (millis() - printTime > printInterval) { //Every 800 milliseconds, print a numerical, convert the state of the LED indicator
Serial.print("Voltage:");
Serial.print(voltage, 2);
Serial.print(" pH value: ");
Serial.println(pHValue, 2);
digitalWrite(LED, digitalRead(LED) ^ 1);
printTime = millis();
}
}
double avergearray(int* arr, int number){
int i;
int max, min;
double avg;
long amount = 0;
if (number <= 0) {
Serial.println("Error number for the array to avraging!/n");
return 0;
}
if (number<5) { //less than 5, calculated directly statistics
for (i=0; i<number; i++) {
amount += arr[i];
}
avg = amount / number;
return avg;
} else {
if (arr[0] < arr[1]) {
min = arr[0];
max = arr[1];
} else {
min = arr[1];
max = arr[0];
}
for (i=2; i<number; i++) {
if (arr[i] < min) {
amount += min; //arr<min
min = arr[i];
} else {
if (arr[i] > max) {
amount += max; //arr>max
max = arr[i];
} else {
amount += arr[i]; //min<=arr<=max
}
} //if
} //for
avg = (double)amount / (number - 2);
} //if
return avg;
}
Your "Ph Sensor code" demonstrates how to do 2 things at different time intervals in one loop.
void loop() {
if (/* time is right to do thing 1 */) {
// do thing 1
}
if (/* time is right to do thing 2 */) {
// do thing 2
}
}
This is called a state machine. You can extend this logic to do 4 or more things in one loop.
Obviously you can't use delay as it blocks the entire loop, preventing other work from continuing. So you need to convert the first two loops into the structure similar to the one above. Then you will be able to merge all the loops into a single one.

if statement doesn't work on Nucleo64 but it does on Maple mini

I have a code that works on Maple Mini but I have to change hardware to Nucleo F030r8 because it has more ADC's and it totally sucks.
In the modbus_update() function there is a check of the size of inputBuffer and the following code should run only if the value of this variable is bigger than 0.
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
...
}
But it runs even if value of inputBuffer is exactly 0. The strange thing is that this code (with different serial ports opening method) runs perfectly on Maple Mini. Does anyone have any idea what can be be the problem?
Here is the whole code:
#define BAUDRATE 19200
#define RE_PIN PC12
#define TE_PIN PF4
#define LED_PIN LED_BUILTIN
#define SLAVE_ID 1
#define BUFFER_SIZE 256 // max frame size
#define READ_INTERNAL_REGISTERS 4 // function code
#define MIN_REGISTER_ADDRESS 30001
#define MAX_REGISTER_ADDRESS 30020
#define MAX_SENSORS_PER_ROW 10
#define SENSORS_PER_ROW 7
#define MAX_ROWS 2
#define ROWS 1
#define DEBUG true
#define INVALID_VALUE 0x7FFF
const byte INPUTS[] = {PA0, PA1, PA4, PB0, PC1, PC0};
unsigned char frame[BUFFER_SIZE];
unsigned char functionCode;
unsigned int T1;
unsigned int T1_5; // inter character time out
unsigned int T3_5; // frame delay
unsigned long millisFlag = 0;
unsigned long microsFlag = 0;
unsigned char inputBuffer = 0;
int dlyCounter = 0;
int16_t sensorVals[MAX_SENSORS_PER_ROW * MAX_ROWS];
/*
HardwareSerial *modbus = &Serial;
HardwareSerial Serial1(PA10, PA9);
HardwareSerial *debug = &Serial1;
*/
HardwareSerial debug(PA10, PA9);
void setup() {
pinMode(LED_PIN, OUTPUT);
for (int i = 0; i < SENSORS_PER_ROW; i++) {
pinMode(INPUTS[i], INPUT_PULLUP);
}
debug.begin(BAUDRATE, SERIAL_8E1);
modbus_configure(BAUDRATE, 0); // baud rate, low latency
microsFlag = micros();
}
void loop() {
readSensorVals(100);
modbus_update();
}
unsigned int modbus_update() {
unsigned char overflow = 0;
while (Serial.available()) {
if (overflow) {
Serial.read(); // empty the input buffer
} else {
if (inputBuffer == BUFFER_SIZE) {
overflow = 1;
} else {
frame[inputBuffer] = Serial.read();
inputBuffer++;
}
}
microsFlag = micros();
}
// If an overflow occurred return to the main sketch
// without responding to the request i.e. force a timeout
if (overflow) {
debug.println("Error: input buffer overflow");
return 0;
}
// if inter frame delay occurred, check the incoming package
if (inputBuffer > 0 && micros() - microsFlag >= T3_5) {
debug.println("\nIncoming frame:");
for (int i = 0; i < inputBuffer; i++) {
debug.print(frame[i], HEX);
debug.print(" ");
}
debug.println();
// check CRC
unsigned int crc = ((frame[inputBuffer - 2] << 8) | frame[inputBuffer - 1]); // combine the crc Low & High bytes
if (calculateCRC(frame, inputBuffer - 2) != crc) {
debug.println("Error: checksum failed");
inputBuffer = 0;
return 0;
}
debug.println("CRC OK");
// check ID
unsigned char id = frame[0];
if (id > 242) {
debug.println("Error: Invalid ID");
inputBuffer = 0;
return 0;
}
// check if it's a broadcast message
if (id == 0) {
debug.println("Broadcast message");
inputBuffer = 0;
return 0;
}
if (id != SLAVE_ID) {
debug.println("Not my ID");
inputBuffer = 0;
return 0;
}
debug.println("ID OK");
// check function code
functionCode = frame[1];
if (functionCode != READ_INTERNAL_REGISTERS) {
debug.println("Exception: illegal function");
exceptionResponse(1);
inputBuffer = 0;
return 0;
}
debug.println("Function code OK");
// check frame size (function 4 frame MUST be 8 bytes long)
if (inputBuffer != 8) {
// some workaround here:
//if (inputBuffer != 8 || !(inputBuffer == 9 && frame[inputBuffer] == 0)) {
debug.println("Error: inaccurate frame length");
inputBuffer = 0;
return 0;
}
debug.println("Frame size OK");
// check data address range
unsigned int noOfRegisters = ((frame[4] << 8) | frame[5]); // combine the number of register bytes
if (noOfRegisters > 125) {
debug.println("Exception: illegal data address");
exceptionResponse(2);
inputBuffer = 0;
return 0;
}
unsigned int firstRegAddress = ((frame[2] << 8) | frame[3]); // combine the starting address bytes
debug.print("First address: ");
debug.println(firstRegAddress);
unsigned int lastRegAddress = firstRegAddress + noOfRegisters - 1;
debug.print("Last address: ");
debug.println(lastRegAddress);
unsigned char noOfBytes = noOfRegisters * 2;
unsigned char responseFrameSize = 5 + noOfBytes; // ID, functionCode, noOfBytes, (dataLo + dataHi) * number of registers, crcLo, crcHi
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = 0x04;
responseFrame[2] = noOfBytes;
unsigned char address = 3; // PDU starts at the 4th byte
for (int index = (int)(firstRegAddress - MIN_REGISTER_ADDRESS); index <= (int)(lastRegAddress - MIN_REGISTER_ADDRESS); index++) {
int16_t temp = (index >= 0 && index < MAX_ROWS * MAX_SENSORS_PER_ROW) ? sensorVals[index] : INVALID_VALUE;
responseFrame[address] = temp >> 8; // split the register into 2 bytes
address++;
responseFrame[address] = temp & 0xFF;
address++;
}
unsigned int crc16 = calculateCRC(responseFrame, responseFrameSize - 2);
responseFrame[responseFrameSize - 2] = crc16 >> 8; // split crc into 2 bytes
responseFrame[responseFrameSize - 1] = crc16 & 0xFF;
debug.println("Frame to send:");
for (int i = 0; i < responseFrameSize; i++) {
debug.print(responseFrame[i], HEX);
debug.print(" ");
}
debug.println();
sendPacket(responseFrame, responseFrameSize);
inputBuffer = 0;
while (Serial.available()) { // empty input buffer
Serial.read();
}
}
}
void modbus_configure(long baud, unsigned char _lowLatency) {
Serial.begin(baud, SERIAL_8E1);
pinMode(TE_PIN, OUTPUT);
pinMode(RE_PIN, OUTPUT);
rxEnable(); // pin 0 & pin 1 are reserved for RX/TX. To disable set TE and RE pin < 2
if (baud == 1000000 && _lowLatency) {
T1 = 1;
T1_5 = 1;
T3_5 = 10;
} else if (baud >= 115200 && _lowLatency) {
T1 = 50;
T1_5 = 75;
T3_5 = 175;
} else if (baud > 19200) {
T1 = 500;
T1_5 = 750;
T3_5 = 1750;
} else {
T1 = 10000000 / baud;
T1_5 = 15000000 / baud; // 1T * 1.5 = T1.5
T3_5 = 35000000 / baud; // 1T * 3.5 = T3.5
}
}
void exceptionResponse(unsigned char exception) {
unsigned char responseFrameSize = 5;
unsigned char responseFrame[responseFrameSize];
responseFrame[0] = SLAVE_ID;
responseFrame[1] = (functionCode | 0x80); // set the MSB bit high, informs the master of an exception
responseFrame[2] = exception;
unsigned int crc16 = calculateCRC(responseFrame, 3); // ID, functionCode + 0x80, exception code == 3 bytes
responseFrame[3] = crc16 >> 8;
responseFrame[4] = crc16 & 0xFF;
sendPacket(responseFrame, responseFrameSize); // exception response is always 5 bytes (ID, functionCode + 0x80, exception code, 2 bytes crc)
}
unsigned int calculateCRC(unsigned char f[], byte bufferSize) {
unsigned int temp, temp2, flag;
temp = 0xFFFF;
for (unsigned char i = 0; i < bufferSize; i++) {
temp = temp ^ f[i];
for (unsigned char j = 1; j <= 8; j++) {
flag = temp & 0x0001;
temp >>= 1;
if (flag)
temp ^= 0xA001;
}
}
// Reverse byte order.
temp2 = temp >> 8;
temp = (temp << 8) | temp2;
temp &= 0xFFFF;
return temp; // the returned value is already swapped - crcLo byte is first & crcHi byte is last
}
void rxEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, LOW);
digitalWrite(RE_PIN, LOW);
digitalWrite(LED_PIN, LOW);
}
}
void txEnable() {
if (TE_PIN > 1 && RE_PIN > 1) {
digitalWrite(TE_PIN, HIGH);
digitalWrite(RE_PIN, HIGH);
digitalWrite(LED_PIN, HIGH);
}
}
void sendPacket(unsigned char f[], unsigned char bufferSize) {
txEnable();
delayMicroseconds(T3_5);
for (unsigned char i = 0; i < bufferSize; i++) {
Serial.write(f[i]);
}
Serial.flush();
delayMicroseconds(T3_5); // allow frame delay to indicate end of transmission
rxEnable();
}
// #param dly delay between sensor readings in milliseconds
void readSensorVals(int dly) {
if (millis() != millisFlag) {
dlyCounter++;
millisFlag = millis();
}
if (dlyCounter >= dly) { // read sensor values
for (int i = 0; i < MAX_ROWS; i++) {
for (int j = 0; j < MAX_SENSORS_PER_ROW; j++) {
int actualIndex = i * MAX_SENSORS_PER_ROW + j;
if (i < ROWS && j < SENSORS_PER_ROW) {
sensorVals[actualIndex] = random(20, 30);
//sensorVals[actualIndex] = (4096 - analogRead(INPUTS[j])) / 20 - 133;
} else {
sensorVals[actualIndex] = INVALID_VALUE;
}
}
}
dlyCounter = 0;
}
}

Arduino RTC subtracting 1 second every 8 hours

I used the RTC, from an Arduino MKR 1300 with integrated RTC, as an alarm that will trigger a "boolean"(it's an integer) that will tell the loop to run a certain method every minute and then send some data every 5 minutes. It's on an active loop but the method to send data ONLY WORKS if it's inside the loop (no idea why). The problem is the RTC apparently is subtracting 1 second at every 8 hours or so after a few days the timing might come off and instead of sending data every xx:10:xx-xx:15:xx it might send data xx:09:xx-xx:14:xx.
Here's the code:
#include <EmonLib.h>
#include <RTCZero.h>
#include <MKRWAN.h>
EnergyMonitor emon1;
EnergyMonitor emon2;
EnergyMonitor emon3;
RTCZero rtc;
LoRaModem modem;
String appEui = "1234567891011121";
String appKey = "ffffffffffffffffffffffffffffffff";
/* INITIAL_TIME */
const byte seconds = 0;
const byte minutes = 0;
const byte hours = 0;
const byte day = 17;
const byte month = 12;
const byte year = 18;
byte second_alarm = 0;
byte minute_alarm = 0;
byte hour_alarm = 0;
byte INTERVAL = 60;
int SEND_LOOP = 5;
int totalKW;
int counter= 0;
int alarm_Triggered = 0;
void setup()
{
Serial.begin(115200);
if (!modem.begin(EU868)) {
Serial.println("Failed to start module");
while (1) {}
};
Serial.print("Your module version is: ");
Serial.println(modem.version());
Serial.print("Your device EUI is: ");
Serial.println(modem.deviceEUI());
Serial.println("Connecting");
int connected = modem.joinOTAA(appEui, appKey);
if (!connected) {
Serial.println("Something went wrong; are you indoor? Move near a window and retry");
while (1) {}
}
Serial.println("Connected");
// Set poll interval to 60 secs.
modem.minPollInterval(60);
analogReadResolution(9);
emon1.current(1, 53);
emon2.current(2, 53);
emon3.current(3, 53);
counter= 0;
rtc.begin(); // initialize RTC
rtc.setAlarmTime(hour_alarm, minute_alarm, second_alarm);
rtc.enableAlarm(rtc.MATCH_HHMMSS);
rtc.attachInterrupt(triggerAlarm);
// Set the time
rtc.setHours(hours);
rtc.setMinutes(minutes);
rtc.setSeconds(seconds);
// Set the date
rtc.setDay(day);
rtc.setMonth(month);
rtc.setYear(year);
}
void loop() {
if (alarm_Triggered == 1) {
dataMonitor();
alarm_Triggered = 0;
}
}
void dataMonitor() {
int totalWatt = 0;
unsigned long delay_send = 0;
int sending = 0;
double Irms1 = emon1.calcIrms(600);
if (Irms1 < 0.3) Irms1 = 0;
double Watt1 = Irms1 * 230;
double Irms2 = emon2.calcIrms(600);
if (Irms2 < 0.3) Irms2 = 0;
double Watt2 = Irms2 * 230;
double Irms3 = emon3.calcIrms(600);
if (Irms3 < 0.3) Irms3 = 0;
double Watt3 = Irms3 * 230;
totalWatt = Watt1 + Watt2 + Watt3;
totalKW = totalKW + totalWatt / 1000;
Serial.println(counter);
sendDataChecker(Irms1, Irms2, Irms3);
setAlarm();
counter= counter+ 1;
}
void sendDataChecker(double Irms1, double Irms2, double Irms3) {
if (counter== SEND_LOOP) {
double IrmsTotal = Irms1 + Irms2 + Irms3;
String msg = "{\"id\":\"avac_aud2\",\"kW\":" + String(totalKW) + ", \"current\":" + String(IrmsTotal) + "}";
int err;
Serial.println("Ready to Send");
modem.beginPacket();
modem.print(msg);
err = modem.endPacket(true);
Serial.println("Sent1");
if (err > 0) {
//message sent correctly
Serial.println("Sent");
counter= 0;
totalKW = 0;
} else {
Serial.println("ERR");
counter= 0;
}
}
}
void setAlarm() {
second_alarm += INTERVAL;
if (second_alarm >= 60) {
minute_alarm++;
second_alarm = 0;
}
if (minute_alarm >= 60) {
hour_alarm++;
minute_alarm = 0;
}
if (hour_alarm >= 24) {
hour_alarm = 0;
}
rtc.setAlarmTime(hour_alarm, minute_alarm, second_alarm);
}
void triggerAlarm() {
alarm_Triggered = 1;
}

How to set a timeout in a function that is running in a thread

I'm doing a blocking communication with a server using a client. the function is running in a thread. I would like to set a time out functionality. I'm not using boost or something like that. I'm using windows threading library.
Here is the function that I want to set a time out functionality in it.
bool S3W::IWFSData::WaitForCompletion(unsigned int timeout)
{
if (m_Buffer)
{
while (!m_Buffer.IsEmpty())
{
unsigned int i = 0;
char gfname[255]; // must be changed to SBuffer
char minHeightArr[8], maxHeightArr[8], xArr[8], yArr[8];
m_PingTime += timeout;
if (m_PingTime > PONG_TIMEOUT)
{
m_PingTime = 0;
return false;
}
while (m_Buffer[i] != '\0')
{
gfname[i] = m_Buffer[i];
i++;
}
gfname[i] = '\0';
for (unsigned int j = 0; j < 8; j++)
{
minHeightArr[j] = m_Buffer[i++];
}
for (unsigned int j = 0; j < 8; j++)
{
maxHeightArr[j] = m_Buffer[i++];
}
double minH = *(double*)minHeightArr;
double maxH = *(double*)maxHeightArr;
for (unsigned int j = 0; j < 8; j++)
{
xArr[j] = m_Buffer[i++];
}
for (unsigned int j = 0; j < 8; j++)
{
yArr[j] = m_Buffer[i++];
}
double x = *(double*)xArr;
double y = *(double*)yArr;
OGRFeature *poFeature = OGRFeature::CreateFeature(m_Layer->GetLayerDefn());
if(poFeature)
{
poFeature->SetField("gfname", gfname);
poFeature->SetField("minHeight", minH);
poFeature->SetField("maxHeight", maxH);
OGRPoint point;
point.setX(x);
point.setY(y);
poFeature->SetGeometry(&point);
if (m_Layer->CreateFeature(poFeature) != OGRERR_NONE)
{
std::cout << "error inserting an area" << std::endl;
}
else
{
std::cout << "Created a feature" << std::endl;
}
}
OGRFeature::DestroyFeature(poFeature);
m_Buffer.Cut(0, i);
}
}
return true;
}
There is a thread that is setting the data to the buffer
int S3W::ImplConnection::Thread(void * pData)
{
SNet::SAutoLock lockReader(m_sLock);
// RECEIVE DATA
SNet::SBuffer buffer;
m_data->SrvReceive(buffer);
// Driver code for inserting data into the buffer in blocking communication
SNet::SAutoLock lockWriter(m_sLockWriter);
m_data->SetData("ahmed", strlen("ahmed"));
double minHeight = 10;
double maxHeight = 11;
double x = 4;
double y = 2;
char minHeightArr[sizeof(minHeight)];
memcpy(&minHeightArr, &minHeight, sizeof(minHeight));
char maxHeightArr[sizeof(maxHeight)];
memcpy(&maxHeightArr, &maxHeight, sizeof(maxHeight));
char xArr[sizeof(x)];
memcpy(&xArr, &x, sizeof(x));
char yArr[sizeof(y)];
memcpy(&yArr, &y, sizeof(y));
m_data->SetData(minHeightArr, sizeof(minHeightArr));
m_data->SetData(maxHeightArr, sizeof(maxHeightArr));
m_data->SetData(xArr, sizeof(xArr));
m_data->SetData(yArr, sizeof(yArr));
m_data->WaitForCompletion(1000);
return LOOP_TIME;
}
In general, you should not use threads for these purposes, because when terminating a thread like this, the process and the other threads could be left in an unknown state. Look here for the explanation.
Therefore, consider using procceses instead. Read here about opening processes in c++.
If you do want to use threads, you can exit the thread after the time passed.
Make a loop (as you have) that will break when some time has elapsed.
#include <ctime>
#define NUM_SECONDS_TO_WAIT 5
// outside your loop
std::time_t t1 = std::time(0);
// and in your while loop, each iteration:
std::time_t t2 = std::time(0);
if ((t2 - t1) >= NUM_SECONDS_TO_WAIT)
{
break; // ...
}
You can have a class member which holds a time stamp (when to timeout, set its value to currentTime + intervalToTimeout). In WaitForCompletion(), get current time and compare with the timeout time.
I assume in your code, m_PingTime is the time you start communication. You want to timeout after 1000 ms. What you need to do is, in WaitForCompletion():
while (!m_Buffer.IsEmpty())
{
...
long time = getCurrentTime(); // fake code
if (m_PingTime + timeout < time)
{
m_PingTime = 0;
return false;
}
...
}
Here is something I did, if you want to implement it yourself:
clock_t startTime = clock();
clock_t timeElapsed;
double counter;
while(true){
if(counter>=10){
//do what you want upon timeout, in this case it is 10 secs
}
startTime = clock();
}

Mbed Guitar Tuner Code Problems?

I'm trying to tune a guitar using the mbed LPC microcontrolller.
There is a link below for an example of the project.
https://developer.mbed.org/users/adurand/notebook/guitar-tuner/
However, I am having some problems with it. Firstly, I am simulating the guitar input using an arbitrary waveform generator at the required frequency of each string. The amplifier circuit is constructed the same. I have also changed the code to utilise the Mbed LCD instead of the Nokia. I have used an oscilloscope to validate that the output going into AnalogueIn p20 of the Mbed is amplified and at the correct frequency. This is where I have problems.
Here is the code (with credit to Andrew Durand):
#include "mbed.h"
#include "adc.h"
#include "C12832.h"
#include <math.h>
#define PI 3.1415
#define SAMPLE_RATE 24000
InterruptIn button1(p12);
C12832 lcd(p5, p7, p6, p8, p11);
DigitalOut myled1(LED1);
DigitalOut myled2(LED2);
DigitalOut myled3(LED3);
//LCD and Other Random Variables
int string_select = 0;
float high, high1, in_tune, in_tune1, in_tune2, in_tune3,
low, low1, note, low_mod, high_mod;
char* key;
int Counter = 0;
int Buffer[6000];
float goertzelFilter(int samples[], float freq, int N) {
float s_prev = 0.0;
float s_prev2 = 0.0;
float coeff,normalizedfreq,power,s;
int i;
normalizedfreq = freq / SAMPLE_RATE;
coeff = 2*cos(2*PI*normalizedfreq);
for (i=0; i<N; i++) {
s = samples[i] + coeff * s_prev - s_prev2;
s_prev2 = s_prev;
s_prev = s;
}
power = s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2;
return power;
}
ADC adc(SAMPLE_RATE, 1);
void sample_audio(int chan, uint32_t value) {
Buffer[Counter] = adc.read(p20);
Counter += 1;
}
void button1_pressed() {
string_select++;
if (string_select > 5) string_select = 0;
}
int main() {
//Interupt for Switching Strings
button1.mode(PullDown);
button1.rise(&button1_pressed);
while (1) {
switch (string_select) {
case 0:
note = 82;
key= "E2";
break;
case 1:
note = 110;
key= "A2";
break;
case 2:
note = 147;
key= "D3";
break;
case 3:
note = 196;
key= "G3";
break;
case 4:
note = 247;
key= "B3";
break;
case 5:
note = 330;
key= "E4";
break;
}
//Prepare for burst mode on all ADC pins and set up interrupt handler (using ADC library from Simon Blandford
adc.append(sample_audio);
adc.startmode(0,0);
adc.burst(1);
adc.setup(p20,1);
//start the interrupt and wait for about 4096 samples
adc.interrupt_state(p20,1);
wait(.2);
//Finsh up - Unset pin 20
adc.interrupt_state(p20,0);
adc.setup(p20,0);
int actual_rate = adc.actual_sample_rate();
//for debugging tell the terminal sample rate and how many samples we took
printf("Requested max sample rate is %u, actual max sample rate is %u.\n",
SAMPLE_RATE, actual_rate);
printf("We did %i samples\n",Counter);
high = 0;
low = 0;
for (int i=3; i<46; i+=3) {
high1 = goertzelFilter(Buffer, (note + i ), Counter);
if (high1 > high) high=high1;
}
for (int i=3; i<46; i+=3) {
low1 = goertzelFilter(Buffer, (note - i ), Counter);
if (low1 > low) low=low1;
}
in_tune1 = goertzelFilter(Buffer, (note+1), Counter);
in_tune2 = goertzelFilter(Buffer, note, Counter);
in_tune3 = goertzelFilter(Buffer, (note-1), Counter);
if ((in_tune1 > in_tune2) && (in_tune1 > in_tune3)) in_tune = in_tune1;
else if ((in_tune2 > in_tune1) && (in_tune2 > in_tune3)) in_tune = in_tune2;
else in_tune = in_tune3;
printf("high = %.2f, low = %.2f, in_tune = %.2f", high, low, in_tune);
high_mod = high/in_tune;
low_mod = low/in_tune;
if ((high_mod > .8)&&(low_mod > .8)) {
myled1 = 0;
myled2 = 0;
myled3 = 0;
}
if ((high_mod < .8)&&(low_mod > .8)) {
myled1 = 0;
myled2 = 0;
myled3 = 0;
}
if ((high > in_tune) && (low < in_tune)) { //Guitar string is at correct frequency
myled1 = 0;
myled2 = 1;
myled3 = 0;
} else if (high > in_tune) { // String is higher than the desired frequency
myled1 = 1;
myled2 = 0;
myled3 = 0;
} else if (low < in_tune){ // String is below that of the desired frequency
myled1 = 0;
myled2 = 0;
myled3 = 1;
} else { // Else no input, display squiggles
myled1 = 0;
myled2 = 0;
myled3 = 0;
}
// Display on the LCD
lcd.cls();
lcd.locate(0,0);
lcd.printf("Tuning String: %i", (6-string_select));
lcd.locate(0,11);
lcd.printf("%s at %i Hz",key, (int) note);
lcd.locate(0,23);
if (myled2) lcd.printf("In Tune!"); // if myled2 is on, guitar is in tune
else if (myled3) lcd.printf("Too Low "); // if myled3 is on, guitar is lower than desired tone
else if (myled1) lcd.printf("Too High"); // if myled1 is on, guitar is higher than desired tone
else lcd.printf("No Input Detected"); // corresponds to led case 4 - no guitar input present
Counter = 0;
}
}
Now, when I compile the program, the messages print. However, the LEDs alternate between "Too high", "Too low", and to the squiggles. I'll be the first to admit I'm not the best coder, something I am really going to work on over the Summer. There could be a very significant problem with the code, or it may be something relatively simple. All inputs are appreciated.
Note: I have not connected the debounce circuit on the breadboard - it is connected to the Nokia LCD which I did not use. I am able to change the desired string, between 1-6, using the joystick on the mbed application board instead. Is that okay? Or is the debounce circuit of pivotal importance?
Thanks again.
The loop which finds low is (almost) the same as the loop which finds high in this code:
high = 0;
low = 0;
for (int i=3; i<46; i+=3) {
high1 = goertzelFilter(Buffer, (note + i ), Counter);
if (high1 > high) high=high1;
}
for (int i=3; i<46; i+=3) {
low1 = goertzelFilter(Buffer, (note - i ), Counter);
if (low1 > low) low=low1;
}
I suggest the low part should be like this
low = FLT_MAX;
for (int i=3; i<46; i+=3) {
low1 = goertzelFilter(Buffer, (note - i ), Counter);
if (low1 < low) low=low1;
}
...although I could be mistaken at the intended use of low.