Arduino Mega to 2x UNO over Serial - serialization

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");

Related

NodeMCU interrupts triggering wrong IREs

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!

Receiving data from a server using ESP8266 /Arduino Uno

I have a Raspberry Pi working as a WiFi hotspot and an Arduino Uno trying to get data from it using an ESP8266 module.
This is my receiver code for Arduino:
#include <SoftwareSerial.h>
#include <SerialESP8266wifi.h>
#define sw_serial_rx_pin 4 // Connect this pin to TX on the esp8266
#define sw_serial_tx_pin 6 // Connect this pin to RX on the esp8266
#define esp8266_reset_pin 5 // Connect this pin to CH_PD on the esp8266, not reset. (let reset be unconnected)
SoftwareSerial swSerial(sw_serial_rx_pin, sw_serial_tx_pin);
// the last parameter sets the local echo option for the ESP8266 module..
SerialESP8266wifi wifi(swSerial, swSerial, esp8266_reset_pin, Serial);//adding Serial enabled local echo and wifi debug
String inputString;
boolean stringComplete = false;
unsigned long nextPing = 0;
void setup() {
inputString.reserve(20);
swSerial.begin(9600);
Serial.begin(9600);
while (!Serial)
;
Serial.println("Starting wifi");
wifi.setTransportToTCP();// this is also default
// wifi.setTransportToUDP();//Will use UDP when connecting to server, default is TCP
wifi.endSendWithNewline(true); // Will end all transmissions with a newline and carriage return ie println.. default is true
wifi.begin();
wifi.connectToAP("RPi", "raspberry");
wifi.connectToServer("192.168.50.1", "1234");
wifi.send(SERVER, "ESP8266 test app started");
}
void loop() {
//Make sure the esp8266 is started..
if (!wifi.isStarted())
wifi.begin();
//Send what you typed in the arduino console to the server
static char buf[20];
if (stringComplete) {
inputString.toCharArray(buf, sizeof buf);
wifi.send(SERVER, buf);
inputString = "";
stringComplete = false;
}
//Send a ping once in a while..
if (millis() > nextPing) {
wifi.send(SERVER, "Ping ping..");
nextPing = millis() + 10000;
}
//Listen for incoming messages and echo back, will wait until a message is received, or max 6000ms..
WifiMessage in = wifi.listenForIncomingMessage(6000);
if (in.hasData) {
if (in.channel == SERVER)
Serial.println("Message from the server:");
else
Serial.println("Message a local client:");
Serial.println(in.message);
//Echo back;
wifi.send(in.channel, "Echo:", false);
wifi.send(in.channel, in.message);
nextPing = millis() + 10000;
}
//If you want do disconnect from the server use:
// wifi.disconnectFromServer();
}
//Listen for serial input from the console
void serialEvent() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
stringComplete = true;
}
}
}
When I execute, the serial monitor shows:
OK ARFa C⸮C⸮j⸮H⸮AT+AWJAP="RPi",#raspberry" WIFI DISCONNECT WIFI
CONNECVED WIFI GOT IP
OK AT+CIFSR
+CIFSR:STAIP,"192.168.50.13"
+CIFQR:STAMAC,"2c:3a:eAT+CIPSTART=4,"TCP","192.0n8.50.1",121l
Link type ERROR
Raspberry Pi's ISC DHCP server:
wlan0: STA 2c:3a:e8:4e:bf:70 RADIUS: starting accounting session
5A3B2C85-000000E9 wlan0: STA 2c:3a:e8:4e:bf:70 WPA: pairwise key
handshake completed (RSN)
I also referred to this SO thread with no luck.
Some assumptions because you have not given the info:
Arduino IDE >=1.85
ESP8266 Community package >=2.41
ESP Module ESP8266-12E with latest AT firmware
if that is the case and these fragments (enclosed by X X) are no typos
+CIFQR:STAMAC,"2c:3a:eXAT+CIPSTART=4,"TCP","192.0XnX8.50.1",121l
this leaves the following points to check
hardware connectors - serial connectors between arduino and esp module
stable power source 3.3V for the ESP module
Sure this is ok - but just in case and as reference for other readers
serial speed - try to increase from 9600 to 57600 or even to 115200 baud
These pieces of code should be in the setup() and not in the loop()
//Make sure the esp8266 is started..
if (!wifi.isStarted())
wifi.begin();
//Send what you typed in the arduino console to the server
static char buf[20];
Code processing
nextPing = millis() + 10000;
at the end of
if (in.hasData) {
might lead to interuptions in the communication
Reason due to the processing of code this might trigger at an unwanted point

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);
}

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.