Firstly I must say that this Arduino is a very groovy piece of kit...
I am trying to interface two devices and obtain a reliable output over the serial connection:
Device 1: a commercial device that prints a line of ASCII text every two seconds (usually 60 characters, but every so often it prints some useless stuff all at once totalling ~185 characters). i can capture this output via digital pins 0 & 1 and transmit it onwards to the PC.
Device 2: A pair of on-off switches that i monitor (pins 8 & 12), when both are pressed, it increments a variable and sends the variablel over serial.
I have both devices working on their own with their own scripts.
I would like to be able to combine these two scripts so that i send a single line of the most recently updated data when either of the devices gets new data. it's critical that the data is streamed in the correct order (device 2, then device 1, newline) since i process the data in a python script.
This where is need help. I presume i will need to use interrupts, but I just dont know how to proceed.
You don't have to use interrupts. You can poll the two devices alternately and then act accordingly if one or other becomes active. There's a function that returns the number of serial characters available, and that'll return zero if the serial port is quiet. Alternate that with something that tests your buttons/switches, and you should be OK.
one thing i have built in to one of the scripts is 500ms delay to light up an LED after both switches are pressed on device 2. i thought maybe this would increase the chance of a 'crash'.
so i guess i can have a third 'if' loop with an internal timer that's triggered and then the state of the LED checked/set during each loop?
for Device 1 should i transmit each character as it arrives or should i collect them in a buffer and retransmit when i get char(13)char(10)?
ie. if i have a serial.Println() command, does that complete itself entirely before moving on to the next line in the program? if the order of the serial information gets mushed, i'm in deep stuch.
OK i have a series of loops running
thanks for the tip.
Now i have a new query - i have Device 1 (above) running well.
however, i also want to be able to send the arduino a message from the PC via serial during the loop. when device 1 is not connected, it works fine. however, anything i send from the PC serial monitor to the arduino when it is receiving/transmitting from device 1 , the PC is ignored.
here's the relevant bit:
CR=13, LF=10, restartCounter=64 (the @ character) that i want to send in order to reset the variable buttonPresses. you can see a few lines of Serial.print for debugging.
/*START OF LOOP 1 - serial monitor
monitors serial input, stores everything in a buffer until gets CR/LF sequence,
then sends entire buffer to serial output and resets.
if @ character is recieved, do not add to buffer but reset the buttonPresses variable
*/
if (Serial.available() > 0) {
// read the incoming byte:
incomingByte = Serial.read();
//Serial.print("read: ");
//Serial.print (incomingByte);
if (incomingByte ==restartCounter)
{
//resets buttonPresses, does not touch the buffer
Serial.println("reset counter?");
buttonPresses=0;
}
else if (incomingByte ==CR) ///ie. end of line character
{
// prints to serial port,
// prefixes the data with the buttonPresses value
Serial.print(buttonPresses);
Serial.print(" ");
Serial.println(buffered);
// char* lastline[]=buffered;
char buffered[128];
bufferIndex=-1;
}
else if (incomingByte ==LF)
{ //do nothing at all
}
else
{ //add the character to the buffer
bufferIndex += 1;
buffered[bufferIndex]=incomingByte;
}
if (bufferIndex ==126)
{//empty buffered if it fills to 127 chars (need one extra)
Serial.println(buffered);
char buffered[128];
bufferIndex=-1;
}
}
//END OF LOOP 1
sent from the PC over the USB
-sent from an external device through digital pin 0,1
when the device is not plugged into 0 &1 it reads the PC-USB input fine. when i plugin the external device to 0 & 1, the arduino 'ignores' the PC-USB datastream.
according to http://forums.ladyada.net/viewtopic.php?f=25&t=8212&p=40917 the afosftserial module can also only deal with one port, and importantly the afsoftserial port has no buffer, so if the void loop() is bust with something else, i lose the signal.
is there another technique i can try to reset the buttonPresses variable? maybe i need to add a button for a hard-reset >:( but i kinda wanted to control this from software
I think you only need the code in the second link if you need more than two serial streams (the USB port and the standard afSoftSerial port). Your first post indicates only two streams so the standard afSoftSerial should work alongside the USB port
the softserial thang isnt working for me. same afsoftserial
well, it works fine if i have softserial.read and Serial.read in the loop() but as soon as i add any other programming it all goes kaput. i think there may be a problem with the lack of buffering on the softserial
[sobs loudly]
and all i want to do is to be able to reset a buttonPresses variable to zero from the computer...
i would be doing this every few minutes
[/sob loudly]
if i delete 'loop 3' it runs fine.
if i leave it in and press buttons, everything freezes. no error message.
thanks
/*
* Dr Ben Fox drbenfox@gmail.com
* Using arduino and two switches(s1, s2)
* when both S1 && S2 are HIGH, adds a counter, activates LEDs; pause 250ms
*/
//variables for handling loop 2, switches & LED
int S2 = 8;
int S1 = 12;
int ledLocal=10;
int ledDistant=9;
int buttonState;
int buttonPresses=0;
int val;
int debounce;
long timestamp;
//variables for handling serial communication
int CR =13;
int LF=10;
int restartCounter =64; //ASCII 64 = @ character
int incomingByte = 0; // for incoming serial data
char buffered[128]; //storage array for incomingBytes
int bufferIndex=-1; //index of most recently added Byte to buffered
char lastline[128]; //saves last line so that if the swicthes are activated there is something to send
#include <AFSoftSerial.h>
AFSoftSerial mySerial = AFSoftSerial(3, 2);
void setup() // run once, when the sketch starts
{
pinMode(13, OUTPUT);
Serial.begin(9600); // set up Serial library at 9600 bps
mySerial.begin(9600) ; //set up software serial on pins 2,3
//Sets up input and output pins, baseline buttonstate
pinMode(S2, INPUT);
pinMode(S1, INPUT);
pinMode(ledLocal, OUTPUT);
pinMode(ledDistant, OUTPUT);
buttonState =digitalRead(S2);
//forces ledDistant to flash to show that device connected
int WarmUp;
WarmUp = WarmUpFlash(5,100);
}
void loop()
/* passes thru 4 loops
1. monitor soft serial port.
- if text detected from pulse ox, store in buffer until end-of-line, then transmit
- if receives '@' via serial (from PC) then resets the buttonPresses variable to zero
2. monitor USB-serial port for communication from the PC
3, monitor switches ->if both pressed, send
4. monitor timer ->if active and >500ms, switches off leds
*/
{
/*START OF LOOP 1 - serial monitor
monitors software serial input, stores everything in a buffer until gets CR/LF sequence,
then sends entire buffer to USB serial output and resets.
*/
if (mySerial.available()) {
// read the incoming byte:
incomingByte = mySerial.read();
if (incomingByte ==CR) ///ie. end of line character
{
// prints to USBserial port,
// prefixes the data with the buttonPresses value
Serial.print(buttonPresses);
Serial.print(" ");
Serial.println(buffered);
// char* lastline[]=buffered;
char buffered[128];
bufferIndex=-1;
}
else if (incomingByte ==LF)
{ //do nothing at all
}
else
{ //add the character to the buffer
bufferIndex += 1;
buffered[bufferIndex]=incomingByte;
}
if (bufferIndex ==126)
{//empty buffered if it fills to 127 chars (need one extra)
Serial.println(buffered);
char buffered[128];
bufferIndex=-1;
}
}
//END OF LOOP 1
//START OF LOOP 2
// if @ character is recieved, do not add to buffer but reset the buttonPresses variable
if (Serial.available()) {
incomingByte=Serial.read()
// while (Serial.available()) {
Serial.print(incomingByte);
if (incomingByte ==restartCounter)
{
//resets buttonPresses, does not touch the buffer
Serial.println("reset counter?");
buttonPresses=0;
}
}
//END OF LOOP2
//START LOOP3
if (digitalRead(S2) == 1 && digitalRead(S1) == 1)
{
val =1;
}
else
{
val = 0 ;
}
delay(10);
if (digitalRead(S2) == 1 && digitalRead(S1) == 1)
{
debounce =1;
}
else
{
debounce = 0 ;
}
if (val == debounce)
{
if (val !=buttonState)
{ //If both are pressed, light up LED and increment count
if (val == 1)
{
buttonPresses++;
Serial.println(buttonPresses);
digitalWrite(ledLocal,LOW);
digitalWrite(ledDistant,LOW);
delay(250); // longish delay to prevent retriggering
}
}
else
{
digitalWrite(ledLocal,HIGH);
digitalWrite(ledDistant,HIGH);
}
buttonState=val;
}
//LOOP 3
//END OF LOOPS
}
//WarmUpFlash makes ledDistant/ledLocal flash to prove connection
int WarmUpFlash(int nFlash, int nDuration) {
int i;
for (i=0; i<nFlash; i++){
digitalWrite(ledDistant, HIGH);
digitalWrite(ledLocal, HIGH);
delay(nDuration);
digitalWrite(ledDistant, LOW);
digitalWrite(ledLocal, LOW);
delay(nDuration);
}
return 1;
}
You have two large static char arrays:
char buffered[128]; //storage array for incomingBytes
char lastline[128];
plus you have another array that uses 128 bytes in loop 1. That array is called char buffered[128], and although it has the same name as the static one declared at the top of your sketch, the compiler will treat it as a new array because its inside the loop function.
Hardware Serial uses 128 bytes for its receive buffer and afSoftSerial also declares a buffer.
The Arduino ATmega168 chip only has 1024 byts of RAM and some of this is used by the Arduino core code.
Try getting rid of one of your buffered arrays. I think its only used in loop 1 so the static one at the top is redundant. Also, I don't think lastline is doing anything (other than hogging RAM) , try removing it.
But if it's not RAM but the delays in loop 3 causing the problem, try modifying the code so you are not waiting so long (over 250ms) between calls to the serial routine. You can do this by changing the debounce logic so that it services the serial ports while waiting on the debounce time.
It may be easier to think through the logic if you try a test sketch that just handles the debounce logic while reading data from the hardware serial port (i.e. ignore softSerial for this learning exercise) Try to get the debounce working in way that so that you can still check serial available and read data within the debounce delay period. You can achieve by having a for loop delaying short amounts of time and servicing the serial routine each time through. You can also implement this in a loop calling millis to see if enough time has passed.
interesting - i didnt know that the static variables in the preamble arent global. you're right that the lastline variable is redundant - i thought about pre-processing the text on the arduino but i will leave it in the python script waiting for the data on the PC.
i will have a bash at rewriting, seems like it will be a complete rehash
Variables declared at the top of the sketch, outside of any of the functions are global. But variables declared within a function will be treated as new variables and therefore consume memory even if though they have the same name.
This is known as variable scope. The general rule of variable scope is this: all variables exist within the brackets that surround them and variables declared outside any brackets are global.
There is a little more to it than that and I recommend checking out one of the online references on variable scope in C programs.