NodeMCU interrupts triggering wrong IREs - interrupt

I'm kinda lost here with attaching interrupts for a V3 NodeMCU while programming it with the Arduino IDE.
So I've written this setup code:
void setup() {
//declare output and input pins
pinMode(D4, OUTPUT);
pinMode(D2, INPUT);
attachInterrupt(digitalPinToInterrupt(D2), buttonPressed, CHANGE);
pinMode(D7, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(D7), motionDetected, CHANGE);
//start the serial monitor (test purposes only)
Serial.begin(115200);
//initiate the EEPROM access and check stored values
EEPROM.begin(512);
getSetupVariables();
//setup the wifi connection to previous set SSID and password
setup_wifi();
//set the MQTT server to previous declared values and set the callback function
client.setServer(mqtt_server, 1883);
client.setCallback(handleMQTTCommands);
}
The interrupt ISRs are these two functions:
void buttonPressed() {
if(!isBusy && digitalRead(D2) == HIGH) {
Serial.println("button pressed");
if(targetDoorState == DOOR_STATE_OPEN) {
initiateOperation(DOOR_STATE_CLOSED);
} else if(targetDoorState == DOOR_STATE_CLOSED) {
initiateOperation(DOOR_STATE_OPEN);
}
}
}
void motionDetected() {
char MQTT_channel[100];
char msg[100];
detachInterrupt(D7);
MQTT_CHANNEL_SET_VALUE.toCharArray(MQTT_channel, (MQTT_CHANNEL_SET_VALUE.length() + 1));
if(digitalRead(D7) == HIGH) {
Serial.println("reached");
String MQTT_PAYLOAD_OBSTRUCTION_DETECTED = "{\"name\":\"" + DEVICE_NAME + "\", \"service_name\":\"garagedoor\",\"characteristic\":\"ObstructionDetected\", \"value\":"+ DOOR_STATE_OPEN +"}";
} else if(digitalRead(D7) == LOW) {
String MQTT_PAYLOAD_OBSTRUCTION_DETECTED = "{\"name\":\"" + DEVICE_NAME + "\", \"service_name\":\"garagedoor\",\"characteristic\":\"ObstructionDetected\", \"value\":"+ DOOR_STATE_CLOSED +"}";
}
MQTT_PAYLOAD_OBSTRUCTION_DETECTED.toCharArray(msg, (MQTT_PAYLOAD_OBSTRUCTION_DETECTED.length() + 1));
client.publish(MQTT_channel, msg);
delay(500);
attachInterrupt(digitalPinToInterrupt(D7), motionDetected, CHANGE);
}
So on pin D2 a button is attached. D7 has to listen to changes from a motion sensor. But when the motion sensor is triggered (thus the D7 interrupt needs to happen) both the D2 and D7 interrupt IREs are called. Does anyone have the same problem? Or sees what I'm doing wrong here?
I've tried different NodeMCU boards and all of them have this issue. I also searched for code examples, but all of them implement one attachInterrupt. When I comment out one of them, they work fine...
Thanks in advance!

Related

Why does xQueueReceive throw an unhandled exception (LoadProhibited)?

I'm working on an esp32 FreeRTOS application with two tasks. Its purpose is to take UART messages received from a peripheral device and transmit them via mqtt to a central broker.
The first task reads input from Serial1, processes the contents into a message structure, and adds it to a FreeRTOS queue:
typedef struct {
int length;
char buffer[AZ_EL_MAX_MESSAGE_LENGTH];
} tag_message_t;
void uart_read_task(void * pvParameters){
BaseType_t xStatus;
tag_message_t tag_message;
while(true) {
while(Serial1.available())
{
first_char = Serial1.read();
if (first_char == '+') // Indicates the beginning of a message
{
for(int i = 0; i < AZ_EL_MAX_MESSAGE_LENGTH; i++)
{
message_buffer[i] = Serial1.read();
if (message_buffer[i] == '\n') // End of message received
{
ESP_LOGV(TAG, "Message found: %s", message_buffer);
strncpy(tag_message.buffer, message_buffer, i + 1);
tag_message.length = i + 1;
xStatus = xQueueSend(xMessagesToSendQueue, (void*) &tag_message, 0);
if (xStatus != pdPASS)
ESP_LOGW(TAG, "Failed to queue message.");
break;
}
}
}
}
vTaskDelay(pdMS_TO_TICKS(20)); // Wait the minimum BLE advertisement period for messages to come in, i.e. 20ms
}
}
The main loop() (which is technically the second FreeRTOS task) then attempts to receive from that queue and transmit over MQTT to a local broker:
void setup()
{
Serial.begin(115200);
// Configure and start WiFi
configure_network();
connect_network();
// Configure the MQTT connection
configure_mqtt_client();
// Configure and create the inter-task queues
xMessagesToSendQueue = xQueueCreate(100, sizeof(tag_message_t));
if (xMessagesToSendQueue == NULL) {
ESP_LOGE(TAG, "Unable to create messaging queue. Will not create UART handling message queue.");
delay(10000);
esp_restart();
} else {
ESP_LOGI(TAG, "Messaging queue generated");
configure_uart();
xTaskCreate(uart_read_task, "UART_Processing", 20000, NULL, 1, NULL);
}
}
void loop()
{
const TickType_t xTicksToWait = pdMS_TO_TICKS(100); // milliseconds to wait
tag_message_t received_message;
if (network_connected) {
connect_mqtt_client();
while(mqtt_client.connected())
{
mqtt_client.loop();
// Process messages on the xMessagesToSendQueue
if (xMessagesToSendQueue != NULL)
{
ESP_LOGI(TAG, "Processing message");
if (xQueueReceive(xMessagesToSendQueue, &received_message, xTicksToWait) == pdPASS)
{
ESP_LOGD(TAG, "Received message, transmitting.");
if(!mqtt_client.publish("aoa", received_message.buffer, received_message.length));
ESP_LOGW(TAG, "Failed transmission.");
}
else
{
vTaskDelay(pdMS_TO_TICKS(50));
}
}
else
{
ESP_LOGE(TAG, "Messages queue is null.");
}
}
} else {
ESP_LOGE(TAG, "WARNING Device not connected to the network. Reconnecting.");
connect_network();
}
delay(5000);
}
I've verified that the MQTT broker works, that it connects to WiFi, and it can properly read messages from Serial1. HOWEVER, the xQueueReceive() call in loop() throws a LoadProhibited exception every time it's called.
Can anyone tell me what I'm getting wrong here?
All, thank you for your help. It turns out this wasn't a FreeRTOS issue. After a little research (i.e. reading this and watching a more experienced engineer explain things: [link]https://hackaday.com/2017/08/17/secret-serial-port-for-arduinoesp32/) it turns out ESP32 Serial1 pins are connected to flash memory.
Every time I tried Serial1.read() or Serial1.readBytesUntil() the ESP32 crashed. Turns out reading the flash is taboo?
I replaced '''Serial1.read()''' with '''Serial2.read()''' and others. That fixed everything. Now I'm off to optimizing my queues!
You are trying to receive an address on the Queue without casting it.
2 solutions: You either declare received_message as a Pointer:
tag_message_t* received_message;
...
received_message = new tag_message_t;
if (xQueueReceive(xMessagesToSendQueue, received_message, xTicksToWait) == pdPASS)
and don't forget to delete it right after usage.
Or you can cast it after receiving :
if (xQueueReceive(xMessagesToSendQueue, &received_message, xTicksToWait) == pdPASS)
{
received_message = *(static_cast<tag_message_t*>(&received_message));
ESP_LOGD(TAG, "Received message, transmitting.");
if(!mqtt_client.publish("aoa", received_message.buffer, received_message.length));
ESP_LOGW(TAG, "Failed transmission.");
}
or any other sort of dereferencing you might wanna try.
There is also the possibility xQueueReceive is already doing that! So let's be sure of what is going on by adding this:
ESP_LOGD(TAG, "Received message, transmitting. %s", received_message.buffer);
Right after you get the message.
I don't think tag_message is being deleted inside the task, so if the struct is still valid and present, if you properly parse/cast its address, you should be able to acquire the message without any issues.

Why HM-10 doesn't send an OK if i send AT from an MSP430 Launchpad?

I'm trying to set up an UART communication with a HM-10 chip on a Texas Instruments MSP430 Launchpad, but I ran into a very elementary problem.
What I want to achieve is to send an "AT" through UART to HM-10, and receive an answer for that. By the way this is a code I found here and I slightly modified for my purposes.
#include "msp430g2553.h"
const char string[] = { "AT" };
unsigned int i;
void main(void)
{
WDTCTL = WDTPW + WDTHOLD; // Stop the Watch dog
//------------------- Configure the Clocks -------------------//
if (CALBC1_1MHZ==0xFF) // If calibration constant erased
{
while(1); // do not load, trap CPU!!
}
DCOCTL = 0; // Select lowest DCOx and MODx settings
BCSCTL1 = CALBC1_1MHZ; // Set range
DCOCTL = CALDCO_1MHZ; // Set DCO step + modulation
//---------------- Configuring the LED's ----------------------//
P1DIR |= BIT0 + BIT6; // P1.0 and P1.6 output
P1OUT &= ~BIT0 + BIT6; // P1.0 and P1.6 = 0
//--------- Setting the UART function for P1.1 & P1.2 --------//
P1SEL |= BIT1 + BIT2; // P1.1 UCA0RXD input
P1SEL2 |= BIT1 + BIT2; // P1.2 UCA0TXD output
//------------ Configuring the UART(USCI_A0) ----------------//
UCA0CTL1 |= UCSSEL_2 + UCSWRST; // USCI Clock = SMCLK,USCI_A0 disabled
UCA0BR0 = 104; // 104 From datasheet table-
UCA0BR1 = 0; // -selects baudrate =9600,clk = SMCLK
UCA0MCTL = UCBRS_1; // Modulation value = 1 from datasheet
//UCA0STAT |= UCLISTEN; // loop back mode enabled
UCA0CTL1 &= ~UCSWRST; // Clear UCSWRST to enable USCI_A0
//---------------- Enabling the interrupts ------------------//
IE2 |= UCA0TXIE; // Enable the Transmit interrupt
IE2 |= UCA0RXIE; // Enable the Receive interrupt
_BIS_SR(GIE); // Enable the global interrupt
i = 0;
UCA0TXBUF = string[i]; // Transmit a byte
_BIS_SR(LPM0_bits + GIE); // Going to LPM0
}
//-----------------------------------------------------------------------//
// Transmit and Receive interrupts //
//-----------------------------------------------------------------------//
#pragma vector = USCIAB0TX_VECTOR
__interrupt void TransmitInterrupt(void)
{
P1OUT ^= BIT0;//light up P1.0 Led on Tx
if (i == sizeof string - 1)
{
UC0IE &= ~UCA0TXIE;
}
UCA0TXBUF = string[i++];
}
#pragma vector = USCIAB0RX_VECTOR
__interrupt void ReceiveInterrupt(void)
{
// light up P1.6 LED on RX
if (UCA0RXBUF == 'O')
{
P1OUT ^= BIT6;
}
IFG2 &= ~UCA0RXIFG; // Clear RX flag
}
According to the datasheet I should receive an OK answer for this command.
If there was an 'O' in the RX buffer, I would expect the LED to light up on my board, but that doesn't happen.
Using Code Composer, I also verified with adding a breakpoint to the RX interrupt that there is indeed no RX answer.
I believe this is entirely a software question, that's why I put it here. I'm using the correct rotation of jumpers(http://xanthium.in/Serial-Communication-MSP430-UART-USCI_A) and RX is wired to TX and vica versa.
I would appreciate if you could point out if I was doing anything conceptionally wrong or if I just made a mistake. Thank you!
I see a problem in the interrupt routine TransmitInterrupt(): you should use UCA0TXBUF = string[++i]; because using "i++" you transmit two times the letter "A". The test about sizeof(string) should also be retouched.
Then, I would not trust too much the datasheet. I think that, despite what the datasheet says, every command sent to the modem must be terminated by CR (\r), otherwise how could the modem discern an "AT" from an "AT+RESET"? I am not really sure but the datasheet doesn't seem a high quality one. Anyway, it's a quick test (to add a \r to the end of the string).
Finally, the CTS and RTS signals can play a role too. Some modem wants RTS asserted, other modems don't care, and terminology sometimes is confusing: when datasheet says RTS, does it mean RTS of the modem or RTS of the host? I hope this helps, you should do a few scientific tries.
I think for everyone who is working with HM-10 devices in the future I want to answer this question, because it has I think its own sort of mini-literature, which was first frustrating, but then I kind of liked the challenges it posed to me.
Some of the problems are hardware related, so this post might need to be moved to an embedded engineering section. (Great consequence - you cannot be 100% sure before checking it with a scope)
Know your hardware - HM-10 has tons of versions, and it turned our one needed an extra potential divider because it has a 3.3V logic level high instead of 5V. This website is a fantastic place to start. Though, ours turned out to be an MLT-BT05 which is a clone of a clone. It doesn't have iBeacon capability on its firmware, so if you don't want to power cycling, then you should probably avoid this one.
About the coding bit the most important thing is to check with \n, \r and \n\r, as linuxfan briefly mentioned its importance above, because some of the devices need it. The best place to start is AT and if it works, then use AT+HELP and find the version, usually AT+VERSION command so you can identify with 100% certainty which chip you have.
Currenetly it is prototyped on an Arduino, but I will include working code as soon as its finished on MSP430.
The Arduino code:
#include <SoftwareSerial.h>
SoftwareSerial bluetooth(9, 10); // RX, TX
char commandbuffer[50];
int j = 0;
void setup()
{
memset(commandbuffer, 0, sizeof(commandbuffer));
analogWrite(12, 255);
analogWrite(11, 0);
// Start the hardware serial port
Serial.begin(19200);
bluetooth.begin(9600);
// un REM this to set up a Master and connect to a Slave
Serial.println("BLE CC41A Bluetooth");
Serial.println("----------------------------------");
Serial.println("");
Serial.println("Trying to connect to Slave Bluetooth");
delay(1000);
bluetooth.println("AT"); // just a check
delay(2000);
bluetooth.println("AT+NAMEHIST");
delay(2000);
bluetooth.println("AT+ROLE0");
delay(2000);
bluetooth.println("AT+INQ"); // look for nearby Slave
delay(5000);
bluetooth.println("AT+CONN1"); // connect to it */
}
void loop()
{
bluetooth.listen();
// while there is data coming in, read it
// and send to the hardware serial port:
while (bluetooth.available() > 0) {
char inByte = bluetooth.read();
Serial.write(inByte);
}
// Read user input if available.
if (Serial.available()) {
delay(10); // The DELAY!
char temp = Serial.read();
if (temp == '\n')
{
bluetooth.println(commandbuffer);
Serial.println(commandbuffer);
memset(commandbuffer, 0, sizeof(commandbuffer));
j = 0; // Reset
}
else
{
commandbuffer[j++] = temp;
}
delay(500);
}

Arduino Mega to 2x UNO over Serial

Hi This is my first time posting, so bear with me.
My problem is with the serial communication between the Arduino Mega and 2x Arduino UNO's.
My setup comprises of a Mega as my master device and 1x UNO + Adafruit sound shield & 1x UNO + Adafruit Motor Shield. I have them via serial port i.e Serial1 RxTx on the mega to Serial TxRx on the UNO and same again for Serial2 for the other UNO, (I have x2 UNO's as both sheilds take up the whole PWM pin of the UNO)
Serial.begin(9600); //<--mega//
Serial1.begin(9600); //<--mega//
Serial2.begin(9600); //<--mega//
Serial.begin(9600); //<--UNO Sound//
Serial.begin(9600); //<--UNO motor//
Mega code:
Serial.println("Entering While loop1"); // Debug //
while(CommFlag1 == 0){
while (Serial2.available()){
SerialReceive2 = Serial2.read();
RxContent2.concat(SerialReceive2); //Store Content of Serial Data into Global Variable//
delay(10);
}
Serial.print("Sound MCU: "); // Debug //
Serial.println(RxContent2); // Debug //
delay(100); // Debug //
if (RxContent2 == "Alive$$$") {
Serial2.println("CommEst");
Serial.println("Alive Response Recieved Sound MCU"); // Debug //
RxContent2 = "";
CommFlag1 = 1;
}
}
Serial.println("Entering While loop2"); // Debug //
while(CommFlag2 == 0){
while (Serial1.available()){
SerialReceive1 = Serial1.read(); //Store Content of Serial Data into Global Variable//
RxContent1.concat(SerialReceive1);
delay(10);
}
Serial.print("Motor MCU: "); // Debug //
Serial.println(RxContent1); // Debug //
delay(100); // Debug //
if (RxContent1 == "Alive"){
Serial1.println("CommEst");
Serial.println("Alive Response Recieved Motor MCU");
RxContent1 = "";
CommFlag2 = 1;
}
}
UNO Code(Both are the same except the Serial.print statement which is Alive for the motor):
Serial.println("Alive$$$");
while(CommFlag == 0){
delay(250);
while (Serial.available()){
SerialReceive = Serial.read();
RxContent.concat(SerialReceive);
delay(50);
if (RxContent == "CommEst"){
CommFlag = 1;
RxContent = "";
}
}
}
In the serial window I can see the UNO's "alive$$$" response when PC is connected to the USB (Serial) on the mega, but the mega doesn't seem to accept the response value and doesn't execute the if statement?
Am I doing something wrong? Any help would be greatly appreciated!
Rich
In UNO code you send string by using Serial.println(), That means the string is prefix by \r\n character. But when you compare is not ending with \r\n. Please change if statement by add \r\n at the end of compare string.
if (RxContent2 == "Alive$$$\r\n")
and
if (RxContent1 == "Alive\r\n")
Or change code in UNO to print not println
Serial.print("Alive$$$");
and
Serial.print("Alive");

Traffic lights simulation and xbee communication

So i am having this project. The system will give priority to emergency vehicles when they get close to traffic lights and when they get close i want to change the state of the traffic lights from red to green but in correct sequence.
I have managed to pull it off but it doesnt work with a real car because the xbees (coordinator on the vehicle and end device on home-made traffic lights) take sometime to communicate which is not enough for the speed of a vehicle approaching traffic lights with lets say an average speed of 60km/h.
The system works like this. There is an arduino on the vehicle which has a GPS shield and an xbee set to COORDINATOR on it. In the program on the arduino it checks if the gps reads coordinates that are saved inside the arduino so it checks against real time coordinates and if they match, the xbee gets to send a message across to the corresponding xbees that are set as end-devices on the traffic lights which again setup is arduino + xbee.
The problem 1 is i need to make a faster connection between the xbees (COORDINATOR - END DEVICE)
Here is the arduino sketch for ARDUINO-GPS-COORDINATOR. Note: GPS Shield is from adafruit and i use their code plus some of mine.
// Test code for Adafruit GPS modules using MTK3329/MTK3339 driver
//
// This code shows how to listen to the GPS module in an interrupt
// which allows the program to have more 'freedom' - just parse
// when a new NMEA sentence is available! Then access data when
// desired.
//
// Tested and works great with the Adafruit Ultimate GPS module
// using MTK33x9 chipset
// ------> http://www.adafruit.com/products/746
// Pick one up today at the Adafruit electronics shop
// and help support open source hardware & software! -ada
#include <Adafruit_GPS.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11);
SoftwareSerial xbee(13,12);
// If using hardware serial (e.g. Arduino Mega), comment out the
// above SoftwareSerial line, and enable this line instead
// (you can change the Serial number to match your wiring):
//HardwareSerial mySerial = Serial1;
Adafruit_GPS GPS(&mySerial);
// Set GPSECHO to 'false' to turn off echoing the GPS data to the Serial console
// Set to 'true' if you want to debug and listen to the raw GPS sentences.
#define GPSECHO true
// this keeps track of whether we're using the interrupt
// off by default!
boolean usingInterrupt = false;
void useInterrupt(boolean); // Func prototype keeps Arduino 0023 happy
void setup()
{
Serial.begin(115200);
Serial.println("Adafruit GPS library basic test!");
xbee.begin(9600);
xbee.println("SoftwareSerial on coordinator working!");
GPS.begin(9600);
// uncomment this line to turn on RMC (recommended minimum) and GGA (fix data) including altitude
GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA);
// uncomment this line to turn on only the "minimum recommended" data
//GPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCONLY);
// For parsing data, we don't suggest using anything but either RMC only or RMC+GGA since
// the parser doesn't care about other sentences at this time
// Set the update rate
GPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ); // 1 Hz update rate
// For the parsing code to work nicely and have time to sort thru the data, and
// print it out we don't suggest using anything higher than 1 Hz
// Request updates on antenna status, comment out to keep quiet
GPS.sendCommand(PGCMD_ANTENNA);
// the nice thing about this code is you can have a timer0 interrupt go off
// every 1 millisecond, and read data from the GPS for you. that makes the
// loop code a heck of a lot easier!
useInterrupt(true);
delay(1000);
// Ask for firmware version
mySerial.println(PMTK_Q_RELEASE);
}
// Interrupt is called once a millisecond, looks for any new GPS data, and stores it
SIGNAL(TIMER0_COMPA_vect) {
char c = GPS.read();
// if you want to debug, this is a good time to do it!
#ifdef UDR0
if (GPSECHO)
if (c) UDR0 = c;
// writing direct to UDR0 is much much faster than Serial.print
// but only one character can be written at a time.
#endif
}
void useInterrupt(boolean v) {
if (v) {
// Timer0 is already used for millis() - we'll just interrupt somewhere
// in the middle and call the "Compare A" function above
OCR0A = 0xAF;
TIMSK0 |= _BV(OCIE0A);
usingInterrupt = true;
} else {
// do not call the interrupt function COMPA anymore
TIMSK0 &= ~_BV(OCIE0A);
usingInterrupt = false;
}
}
// difference_ratio
float diff_ratio = 0.010;
// COORDINATES INDEX
float coord_lat = 23;
float coord_lon = 23;
uint32_t timer = millis();
void loop() // run over and over again
{
// in case you are not using the interrupt above, you'll
// need to 'hand query' the GPS, not suggested :(
if (! usingInterrupt) {
// read data from the GPS in the 'main loop'
char c = GPS.read();
// if you want to debug, this is a good time to do it!
if (GPSECHO)
if (c) Serial.print(c);
}
// if a sentence is received, we can check the checksum, parse it...
if (GPS.newNMEAreceived()) {
// a tricky thing here is if we print the NMEA sentence, or data
// we end up not listening and catching other sentences!
// so be very wary if using OUTPUT_ALLDATA and trytng to print out data
//Serial.println(GPS.lastNMEA()); // this also sets the newNMEAreceived() flag to false
if (!GPS.parse(GPS.lastNMEA())) // this also sets the newNMEAreceived() flag to false
return; // we can fail to parse a sentence in which case we should just wait for another
}
// if millis() or timer wraps around, we'll just reset it
if (timer > millis()) timer = millis();
// approximately every 2 seconds or so, print out the current stats
if (millis() - timer > 2000) {
timer = millis(); // reset the timer
Serial.print("\nTime: ");
Serial.print(GPS.hour, DEC); Serial.print(':');
Serial.print(GPS.minute, DEC); Serial.print(':');
Serial.print(GPS.seconds, DEC); Serial.print('.');
Serial.println(GPS.milliseconds);
Serial.print("Date: ");
Serial.print(GPS.day, DEC); Serial.print('/');
Serial.print(GPS.month, DEC); Serial.print("/20");
Serial.println(GPS.year, DEC);
Serial.print("Fix: "); Serial.print((int)GPS.fix);
Serial.print(" quality: "); Serial.println((int)GPS.fixquality);
if (GPS.fix) {
//Serial.print("Location: ");
//Serial.print(GPS.latitude, 4); Serial.print(GPS.lat);
//Serial.print(", ");
//Serial.print(GPS.longitude, 4); Serial.println(GPS.lon);
Serial.print("Location (in degrees, works with Google Maps): ");
Serial.print(GPS.latitudeDegrees, 4);
Serial.print(", ");
Serial.println(GPS.longitudeDegrees, 4);
//Serial.print("Speed (knots): "); Serial.println(GPS.speed);
//Serial.print("Angle: "); Serial.println(GPS.angle);
//Serial.print("Altitude: "); Serial.println(GPS.altitude);
//Serial.print("Satellites: "); Serial.println((int)GPS.satellites);
if(GPS.latitudeDegrees + diff_ratio >= coord_lat && coord_lat >= GPS.latitudeDegrees - diff_ratio) {
if(GPS.longitudeDegrees + diff_ratio >= coord_lon && coord_lon >= GPS.longitudeDegrees - diff_ratio){
Serial.println("location OKAY");
xbee.println("K");
}
}
//if((float)GPS.latitude > (home_lat - diff_ratio) && (float)
}
}
}
The important part is where it says if(GPS.fix()) and later on.
And here is the sketch for the traffic light simulation which if it receives the message "K" it will stay to green light until it does not receive it anymore.
#include <SoftwareSerial.h>
SoftwareSerial xbee(3,2);
int greenled = 8; //Led's and pins
int yellowled = 9;
int redled = 10;
int ard_led = 13;
void setup(){
pinMode(greenled,OUTPUT);
pinMode(yellowled, OUTPUT);
pinMode(redled, OUTPUT);
pinMode(ard_led,OUTPUT);
Serial.begin(9600);
xbee.begin(9600);
}
void loop(){
delay(700);
if(xbee.available() > 0 && xbee.read() == 'K' && digitalRead(ard_led) == 0){
//Serial.println("second block");
digitalWrite(redled,HIGH);
delay(1000);
digitalWrite(yellowled, HIGH); //Yellow and red on for 2 seconds
digitalWrite(ard_led,HIGH);
}else if(xbee.available() > 0 && xbee.read() == 'K' && digitalRead(ard_led) == 1){
//Serial.println("third block");
blinking_green();
}
else if(!xbee.available() && xbee.read() != 'K' && digitalRead(greenled) == 0){
//Serial.println("first block");
digitalWrite(redled, HIGH);
delay(1000);
digitalWrite(yellowled, HIGH); //Yellow and red on for 2 seconds
delay(1000);
digitalWrite(redled, LOW); //Red and Yellow off
digitalWrite(yellowled, LOW);
digitalWrite(greenled, HIGH); //Green on for 5 seconds
delay(3000);
digitalWrite(greenled, LOW); //Green off, yellow on for 2 seconds
digitalWrite(yellowled, HIGH);
delay(1000);
digitalWrite(yellowled,LOW);
digitalWrite(redled,HIGH);
} else if(!xbee.available() && xbee.read() != 'K' && digitalRead(greenled) == 1 && digitalRead(yellowled == 0)){
//Serial.println("fourth block");
digitalWrite(greenled,LOW);
digitalWrite(yellowled, HIGH);
delay(1000);
digitalWrite(yellowled, LOW);
digitalWrite(redled,HIGH);
digitalWrite(ard_led,LOW);
}
}
void blinking_green(){
digitalWrite(redled, LOW); //Red and Yellow off
digitalWrite(yellowled, LOW);
digitalWrite(greenled,HIGH);
delay(2500);
}
Problem 2: How can i interrupt the traffic lights simulation instantly when it receives a message from a nearby arduino to change the traffic light to green BEFORE it finishes that loop? Because in a real example green and red light would say for over 20 seconds.
Question: Will a faster baud rate on the xbees achieve faster xbee communication?
thank you in advance
You need to change the loop() on your traffic light simulation. Have a variable you use to store the "state" of the light, along with a timer to keep track of when the next state change happens. This way, your loop can also check the XBee serial input every time around.
if (xbee_event_happened()) {
set_leds_off();
timer = millis();
state = STATE_FLASH_GREEN_OFF;
}
switch (state) {
case STATE_FLASH_GREEN_OFF:
if (millis() - timer > 1000) {
set_leds_green();
state = STATE_FLASH_GREEN_ON;
timer = millis();
}
break;
case STATE_FLASH_GREEN_ON:
if (millis() - timer > 1000) {
set_leds_off();
state = STATE_FLASH_GREEN_OFF;
timer = millis();
}
break;
case STATE_RED:
if (millis() - timer > 5000) {
set_leds_green();
state = STATE_GREEN;
timer = millis();
}
break;
case STATE_GREEN:
if (millis() - timer > 3000) {
set_leds_yellow();
state = STATE_YELLOW;
timer = millis();
}
break;
// etc.
}
This just covers the basics, but it shows an important aspect of loop() function design -- it should never run for more than a few milliseconds. Don't have a delay inside of your main loop, track the state of the device and then use logic to decide if the state needs to change on that pass of the loop.
Additionally, use higher baud rates when possible to avoid latency from serial transmissions, get rid of the 700ms delay in your loop, and organize your if/else structure better:
if (xbee.available() > 0) {
character = xbee.read();
if (character == 'K') {
if (digitalRead(ard_led)) {
// second block
} else {
// third block
}
} else if (character == 'X') {
// do something different? Vehicle left area?
}
}

SD over SPI returns invalid response on CMD8

I'm working on an SPI SD driver for an LPC4088 microcontroller. However, when I send CMD8 (after CMD0) to detect if I'm working with a V2 or high capacity card, I get a weird response. Instead of getting a correct response( 0x01 for highest bits, 0x1AA for the lower 12) or an error I get 0x00 00 00 02 1F, which doesn't make any sense to me at all.
Code I use for initialization:
bool initialize () {
//0. Initialize SPI
SPI::init();
//1. Set clock to 400kHz
SPI::set_clock(400000);
//2. Assert CS signal (=0)
assert_cs();
// 3. Delay at least 74 clocks
delay8(10);
// 4. Deassert CS signal
deassert_cs();
// 5. Delay at least 16 clocks
delay8(2);
uint8_t argument[4];
reset_argument(argument);
// 6. Send CMD0 (reset, go to idle)
if (!send_command(CMD::GO_IDLE_STATE, CMD_RESPONSE_SIZE::GO_IDLE_STATE, response, argument)) {
return false;
}
// 7. Send CMD8
bool version2;
reset_argument(argument);
pack_argument(argument, 0x1AA);
if (!send_command(CMD::SEND_IF_COND, CMD_RESPONSE_SIZE::SEND_IF_COND, response, argument)) {
return false;
}
if ((response[0] & 0xFE) == 0x04) {
//unknown command. This means we have version1
version2 = false;
} else if (response[0] & 0xFE) {
//other error, let's bail
return false;
} else {
//Response, we're version2
version2 = true;
if (response[4] != 0xAA) {
return false;
}
}
//....
}
send_command code:
bool send_command(CMD::value cmd, uint8_t response_size, uint8_t *response, uint8_t *argument) {
assert_cs();
Crc7_SD crc;
crc += cmd | 0x40;
crc += argument[3] & 0xFF;
crc += argument[2] & 0xFF;
crc += argument[1] & 0xFF;
crc += argument[0] & 0xFF;
SPI::send(cmd | 0x40);
SPI::send(argument[3] & 0xFF);
SPI::send(argument[2] & 0xFF);
SPI::send(argument[1] & 0xFF);
SPI::send(argument[0] & 0xFF);
SPI::send((crc << 1) | 1);
volatile uint8_t data;
{
unsigned int timeout = SD_CMD_TIMEOUT;
do {
data = SPI::receive();
--timeout;
} while(timeout && (data & 0x80));
if (timeout == 0) {
deassert_cs();
return false;
}
}
for (int i = 0; i < response_size; i++) {
//First byte is already read above
if (response) {
response[i] = data;
}
data = SPI::receive();
}
deassert_cs();
return true;
}
To make sure that I didn't had an error in the SPI protocol I've verified the input and output with a logic analyzer. Result: CMD0 followed by CMD8. It seems that I'm sending the correct commands, but still I get this weird response.
Additional info about the setup:
Microcontroller is an LPC4088
Microcontroller is connected with this OEM board
The SD card module is connected to the serial expansion connector of the OEM board
The logic analyzer is connected to the SD card module
I've used 2 different versions of both the microcontroller and the OEM board to rule out that there is a hardware error in one of those. Unfortunately I don't have a second SD controller available.
I've used a SanDisk Ultra SDHC 4GB Class 6 SD card and a Transcend SDHC 4GB Class 4 SD card, both gave exactly the same result.
And last but not least, I have very little experience with embedded software, so it might just be some small stupid error.
It turned out that there was some noise on the MISO line. The code was correct, but due to the noise the microcontroller got a different result then intended. With the help of some electronics guy I was able to filter this by soldering a capacitor between MISO and ground.