I am trying to create a list of files on my SD card this is easy enough to do once but the moment I run the program more than once the list become either shortened or the program say there is no files at all.
To make this as easy as possible I am using the SD example that comes with the arduino SD library and just putting the setup part ( that would normally run once ) in the loop part.
Heres what I have with that.
#include <SD.h>
File root;
void setup()
{
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Serial.print("Initializing SD card...");
// On the Ethernet Shield, CS is pin 4. It's set as an output by default.
// Note that even if it's not used as the CS pin, the hardware SS pin
// (10 on most Arduino boards, 53 on the Mega) must be left as an output
// or the SD library functions will not work.
pinMode(10, OUTPUT);
if (!SD.begin(10)) {
Serial.println("initialization failed!");
return;
}
Serial.println("initialization done.");
}
void loop()
{
Serial.println("hit any key then enter to run the list");
while(!Serial.available())
{;}
Serial.read();
root = SD.open("/");
printDirectory(root, 0);
Serial.println("done!");
// nothing happens after setup finishes.
}
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
if (! entry) {
// no more files
//Serial.println("**nomorefiles**");
break;
}
for (uint8_t i=0; i<numTabs; i++) {
Serial.print('\t');
}
Serial.print(entry.name());
if (entry.isDirectory()) {
Serial.println("/");
printDirectory(entry, numTabs+1);
} else {
// files have sizes, directories do not
Serial.print("\t\t");
Serial.println(entry.size(), DEC);
}
}
}
But then I get this weird output after running it
Initializing SD card...initialization done.
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
WSXZAQ.TXT 7
1478523.TXT 7
QWSDFRE.TXT 7
ZXCVBNM.TXT 7
MKOLIJY.TXT 7
done!
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
WSXZAQ.TXT 7
1478523.TXT 7
QWSDFRE.TXT 7
ZXCVBNM.TXT 7
MKOLIJY.TXT 7
done!
hit any key then enter to run the list
HFBVYRG.TXT 7
THBVFG.TXT 7
WAZXDSQ.TXT 7
QAZXSW.TXT 21
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
done!
hit any key then enter to run the list
////////////////////////////////////////////////////////////////////////////////////
as you can see it gets shorter and shorter then just stops altogether.
Does anyone have any ideas why ?
I have tried playing around with pointers and closing and reopening the file but I have come up with nothing.
Any ideas would be greatly appreciated.
No good can come from mismatched open()'s and close()'s. You open the root directory every pass through the loop:
root = SD.open("/");
but never
root.close();
First, fix this error and also check that when you open the root that you succeed before trying to print a listing:
root = SD.open("/");
if(root) {
printDirectory(root, 0);
Serial.println("done!");
root.close();
}
else {
Serial.println("failed to open directory");
}
Second, close the files that are opened in the directory walk
void printDirectory(File dir, int numTabs) {
while(true) {
File entry = dir.openNextFile();
...
entry.close();
}
return;
}
Lastly, consider not blocking in the loop(). Other things can happen outside your loop() and they will be blocked indefinitely depending on how long you wait to hit a key. A more typical code pattern is to spin wildly through the loop() as opposed to blocking waiting for user input. For example:
boolean bNeedPrompt = true;
void loop() {
// Show the prompt once, then mark as displayed so that text does not
// continuously scroll on the screen
if(bNeedPrompt) {
Serial.println("hit any key then enter to run the list");
bNeedPrompt = false;
}
if(Serial.available()) {
Serial.read();
// do action
// set flag so that prompt will display again
bNeedPrompt = true;
}
return;
}
jdr5ca's answer addresses a lot of the problems with your setup - by not closing files you are going to be leaking resources which won't end well. It is particularly important on such a low memory setup as the Arduino, which has only 2k RAM for the original chips, so worth bearing in mind throughout your code.
Short answer for your remaining question: it won't be entirely predictable, but low memory is likely the cause of your problem. Read on for more details.
I've had some similar experiences with the SD library recently, though not with such an obvious cause. I found that if the free memory on my system got below about 500 bytes (a quarter of the total RAM) then the SD library starts to behave very oddly when trying to list directories.
I saw similar things to you, for example:
list entries under root directory and find two sub-directories
list entries in one of those sub-directories, worked fine
list entries under root directory and now I find only one sub-directory! The one I had listed the contents of has vanished!
I could still list the contents of the sub-directory fine, ie. it is still there!
resetting the Arduino and starting again gave the same results, again showing that the files were still present on SD card
I think all of this comes down to SD library being both quite memory hungry (#include SD.h uses up 500 bytes off the bat!), and not handling low memory errors particularly obviously.
So if things are acting strangely then:
check your memory usage (see eg. freeRam() from http://playground.arduino.cc/Code/AvailableMemory)
reduce your memory usage where ever possible. In rough order:
remove libraries you don't need
get rid of any hard coded strings that you don't need (eg. in calls to Serial.print())
for hard coded strings you do need make them as short as possible, and store them in flash (eg. Serial.print(F("String in flash"));) rather than RAM
you can't stick format strings (eg. for snprintf) in flash currently, so avoid using those and just build up the output manually (it is more long handed but saves memory)
make sure you are using appropriate variable types everywhere (ie. the smallest sized type that will suit your purposes) - especially important if you have any arrays, for obvious reasons!
Related
I am trying to input GPS coordinate into the serial monitor to use in my drone project
However, whenever I try to input GPS coordinate, it automatically writes one of the GPS coordinates without my input. For example, GPS latitude is shown as 0.00, but the program waits for GPS Longitude info.
For a detailed situation please look at the picture attached.
int GPSNumCor;
void setup() {
// put your setup code here, to run once:
Serial.begin (115200);
Serial.print("What is the number of your GPS Coordinate? ");
while (Serial.available() == 0);
GPSNumCor = Serial.parseInt();
Serial.println(GPSNumCor);
delay (200);
float GPSLat[GPSNumCor], GPSLon[GPSNumCor];
for (int i = 0; i < GPSNumCor; i++)
{
if (i == 0)
{
Serial.println("What is your 1st GPS Coordinate");
}
if (i == 1)
{
Serial.println("What is your 2nd GPS Coordinate");
}
if (i == 2)
{
Serial.println("What is your 3rd GPS Coordinate");
}
if (i > 2)
{
Serial.print("What is your ");
Serial.print(i + 1);
Serial.println(" th GPS Coordinate");
}
delay(200);
Serial.print ("Latitude: ");
while (Serial.available() == 0);
GPSLat[i] = Serial.parseFloat();
Serial.println(GPSLat[i]);
Serial.print("Longitude: ");
while (Serial.available() == 0);
GPSLon[i] = Serial.parseFloat();
Serial.println(GPSLon[i]);
}
}
It has to wait for all input until I make an input to the program, but it does not wait.
I know while (Serial.available()==0) is a way to go, but I do not know why it would not work.
First, there's no reason to use while (Serial.available() == 0);. The parseFloat function you are about to use waits for data to be available and, if it didn't, merely checking for zero wouldn't be sufficient anyway because that would stop waiting as soon as a single character was available.
So here's why that while loop is a bad idea:
If you really do need to wait for the input before calling parseFloat, this won't do it. It only waits until at least one character is received and the coordinates may be more than one character.
The parseFloat function doesn't return until it has read an entire float anyway. So it already waits for you.
But that's not your problem. Think about the input stream, say it's "11.0<newline>22.0newline44.0". Where is the code to read the spaces between those numbers? When parseFloat tries to read a space, it returns a zero, as the documentation says. That's why you're getting zeroes -- you don't have any code to do anything with the separators between the floats.
Think about how parseFloat must work when it reads "12.34newline". First it reads the 1 and has no idea whether that's the whole number of not, so it keeps checking. Then it reads the "2.34" and still has no idea it has the whole number. Not until it sees the newline does it know that 12.34 is the correct float to return. But it does not consume the newline. Why? Because that might mean something.
With the code you showed, your next call to parseFloat will then try to read the newline and see that this is not a valid character to be part of a floating point number. So, as the documentation says, it will return zero.
Look closely at parseFloat's documentation to find out how to correctly match the delimiters in your serial stream. The parseFloat function has the ability to behave differently, consuming and ignoring delimeters rather than returning zero.
I don't know how it work, I just add Serial.read() in every time I want to read.
If u don't want to add Serial.read(), u can also use old version like 1.6.0, it still work fine but it don't work when u make like C# Serial app.
Just add Serial.read(), it work fine every place.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
// put your main code here, to run repeatedly:
while(Serial.available()==0){}
int r=Serial.parseInt();
Serial.println(r);
Serial.read(); // it work fine
while(Serial.available()==0){}
int g=Serial.parseInt();
Serial.println(g);
Serial.read();
}
In the Serial Monitor window, in the drop-down menu on the bottom-right, change from "Newline" to "No line ending" and that will solve the problem (by preventing the Serial Monitor from automatically entering zero value(s)).
Both the parseInt() and parseFloat() have a hard time reading other data types (this also includes white spaces such as new lines) than the ones specified, and as a result they automatically return zero.
Reference: This page on Programming electronics offers valuable, detailed explanations (look for a paragraph with bold text):
https://www.programmingelectronics.com/parseint/
I am using Olimex EKG Shield with Arduino Uno.
void setup() {
// put your setup code here, to run once:
// initialize serial communication at 9600 bits per second:
Serial.begin(115200);
}
void loop() {
// put your main code here, to run repeatedly:
// read the input on analog pin 0:
int sensorValue = analogRead(A0);
// Convert the analog reading (which goes from 0 - 1023) to a voltage (0 - 5V):
float value = sensorValue * (5.0 / 1023.0);
// print out the value you read:
Serial.println(value);
}
With this code provided here, I am getting a voltage value from 0-5V.
Since its a loop, the data keep shows in the serial monitor until it is disconnected.
So, what I am trying to do is that measure ECG for a certain amount of time (let's say 5 min) or data points (let's say a million points), and then save this data into a .txt file.
//From Arduino to Processing to Txt or cvs etc.
//import
import processing.serial.*;
//declare
PrintWriter output;
Serial udSerial;
void setup() {
udSerial = new Serial(this, Serial.list()[0], 115200);
output = createWriter ("data.txt");
}
void draw() {
if (udSerial.available() > 0) {
String SenVal = udSerial.readString();
if (SenVal != null) {
output.println(SenVal);
}
}
}
void keyPressed(){
output.flush();
output.close();
exit();
}
I found this processing code that imports data from Arduino serial monitor and saves as a .txt file, but it doesn's work somehow.
I think I need to make some change to the code on Arduino side and also on Processing side.
If anyone can help with me, I would really appreciate.
Thank you.
You need to be more specific than saying "it doesn't work somehow" - we have no idea what that means. What exactly did you expect this code to do? What exactly does it do instead?
You also need to split this up into smaller problems.
Can you create a simple example program that simply sends the values to Processing? Just print them to the console for now.
Can you create a separate example program that stores values in a text file? Just use hard-coded values or random values for now- don't worry about the arduino yet.
When you have both of those working perfectly, then you can think about combining them into one program that does both: sends values from the arduino and saves those values to a text file.
You can't just "find code" and expect it to work. You have to break your problem down and then approach each individual step by itself. Then if you get stuck on a specific step, you can post a MCVE and we can go from there. Good luck.
I have an Arduino and an APC220 wireless transceiver. I'm writing a library that reads in data from the APC using the SoftwareSerial class. I originally started with the (incorrect) code below that was causing a seg fault because the i variable is incremented even when there is no data available to read. In cases where it happened to work (by chance when the data was immediately available), this function took approximately 6 milliseconds to execute. When I put the i++; statement in its proper place (above the closing brace immediately above it), the function takes over 270 ms to run. Speed is crucial for this function, so I'm wondering what it is about that statement's placement that causes such a dramatic increase in time.
For the code below, buff is declared as char buff[10]; and sSerial is an instance of SoftwareSerial
unsigned long updateLocation(Marker* marker) {
this->sSerial->print('~');
//initiate request from vision system
this->sSerial->flush();
this->sSerial->print('#');
this->sSerial->print(marker->num);
this->sSerial->print('*');
this->sSerial->flush();
unsigned long start = millis();
int state = 0, i = 0;
while((millis() - start) < 600) {
if(this->sSerial->available()) {
buff[i] = this->sSerial->read();
if(buff[i] == ',') {
buff[i] = 0;
switch(state) {
case 0:
i = -1;
state++;
break;
case 1:
marker->x = atof(buff);
i = -1;
state++;
break;
case 2:
marker->y = atof(buff);
i = -1;
state++;
break;
case 3:
marker->theta = atof(buff);
i = -1;
return (millis() - start);
break;
default:
return 0;
break;
}
}
// Correct location for i++; takes 270 ms to execute
}
// Incorrect location for i++; Takes 6 ms to execute
i++;
}
this->sSerial->print('~');
this->sSerial->flush();
return 0;
}
Assuming that there's data ready and waiting from sSerial, there's no effective difference in the placement of i++.
You said yourself, in most cases the data isn't ready. With the incorrect placement of i++, i quickly grows to greater than the size of buff which causes the segfault.
With the correct placement, your code blocks for up to 600ms waiting for enough data to come in to reach case 3 and return. On average, you're seeing that it takes 270ms for that to happen.
You can test this theory yourself by timing the same function operating directly on a string rather than reading in from serial.
You may want to a) increase your baud rate b) check to see if there's a more efficient software serial implementation you can use c) switch to hardware serial. If you are only using hardware serial currently for debugging output, you can switch that around. Use an FTDI adapter ($6-10 on eBay) to pipe software serial to USB and reserve the hardware serial for your time sensitive function.
You might also be able to reconfigure your code so it doesn't block the whole time waiting. You can read in what's available, store it in a global and go back to your main loop to do something else until there's data available again.
edit: I see now that the APC220 is 9600 baud max. That's pretty slow, so the bottle neck may not be software serial (but you should test it). If the bottle neck is simply the baud rate, you will need to look at optimizing your code not to block waiting for input if there are other things your system can work on while it's waiting.
I am using SIM900 GPS/GPRS module shield connected to an Arduino Uno, how will I be able to parse the response of my AT commands? Or how will I be able to remove the 1st line printed in the serial after sending an AT command?
AT+CMGL="ALL"
+CMGL: 1,"REC READ","+XXXXXXXXXX","","16/04/25,15:20:59+32"
Hilp akp si ralphh the pogi one mmalit mi pizza hehehehehe
+CMGL: 2,"REC READ","+XXXXXXXXXX","","16/04/25,21:51:33+32"
Yow!!!
OK
Example on the output above, I want to get rid of the AT+CMGL="ALL" and then parse the data left. What is the best way in parsing?
How will I be able to parse the response of my AT commands?
Yes, this is the right question to ask.
How will I be able to remove the 1st line printed in the serial after sending an AT command?
No, this is the wrong question to ask, because if you care about whether echo is on or not you are doing it wrong.
The correct strategy for parsing AT command output is as follows:
Send the AT command line (correctly terminated with "\r").
Read one and one character received from the modem until you have a complete line terminated with "\r\n" and then parse that line.
If the line equals a final result code, then all output from the command line is finished (and the modem is ready to receive new commands). This must be the first thing you test for!
If the AT command running has a prefix for its information text response lines (almost all have) check if the line starts with that, and if so process the line else ignore it.
If the AT command running does not have a prefix you probably want to print everything until the final result code is received. This applies only for legacy commands like ATI, and for parsing these you might legitimately care about echo or not.
Now for the AT+CMGL command it is a little bit more work since the responses are split on multiple lines.
First of all, the best source of information should be the manufacturer specific AT documentation, the second best being the official 3GPP 27.005 specification that standardize the AT+CMGL command.
The response for AT+CMGL in text mode is specified as
+CMGL: <index>,<stat>,<oa/da>,[<alpha>],[<scts>][,<tooa/toda>,
<length>]<CR><LF><data>[<CR><LF>
+CMGL: <index>,<stat>,<da/oa>,[<alpha>],[<scts>][,<tooa/toda>,
<length>]<CR><LF><data>[...]]
hence after receiving a line starting with "+CMGL: " all the lines following until you read a blank line ("\r\n") belongs to this.
See this answer on the general code structure and flow, although as written above the multi-line property of the response needs a bit more handling. I would have used something like the following (untested code):
enum CMGL_state {
CMGL_NONE,
CMGL_PREFIX,
CMGL_DATA
};
// Extra prototype needed because of Arduino's auto-prototype generation which often breaks compilation when enums are used.
enum CMGL_state parse_CMGL(enum CMGL_state state, String line);
enum CMGL_state parse_CMGL(enum CMGL_state state, String line)
{
if (line.equals("\r\n") {
return CMGL_NONE;
}
if (line.startsWith("+CMGL: ") {
return CMGL_PREFIX;
}
if (state == CMGL_PREFIX || state == CMGL_DATA) {
return CMGL_DATA;
}
return CMGL_NONE;
}
...
write_to_modem("AT+CMGL=\"ALL\"\r");
CMGL_state = CMGL_NONE;
goto start;
do {
CMGL_state = parse_CMGL(CMGL_state, line);
switch (CMGL_state) {
case CMGL_PREFIX:
process_prefix(line); // or whatever you want to do with this line
break;
case CMGL_DATA:
process_data(line); // or whatever you want to do with this line
break;
case CMGL_NONE:
default:
break;
}
start:
line = read_line_from_modem();
} while (! is_final_result_code(line))
The first line AT+CMGL="ALL" seems to be the echo. You can disable it by sending ATE0 to your module in your setup function.
As for the rest of the data, it all have the same format. You can easily write your parser using different string manipulation functions.
If you are using arduino I would recommend to use a good library! You don't need to deal about these stuff. Try http://www.gsmlib.org/ or you can find any other you like.
I will include one example here.
#include "SIM900.h"
#include <SoftwareSerial.h>
//If not used, is better to exclude the HTTP library,
//for RAM saving.
//If your sketch reboots itself proprably you have finished,
//your memory available.
//#include "inetGSM.h"
//If you want to use the Arduino functions to manage SMS, uncomment the lines below.
#include "sms.h"
SMSGSM sms;
//To change pins for Software Serial, use the two lines in GSM.cpp.
//GSM Shield for Arduino
//www.open-electronics.org
//this code is based on the example of Arduino Labs.
//Simple sketch to send and receive SMS.
int numdata;
boolean started=false;
char smsbuffer[160];
char n[20];
void setup()
{
//Serial connection.
Serial.begin(9600);
Serial.println("GSM Shield testing.");
//Start configuration of shield with baudrate.
//For http uses is raccomanded to use 4800 or slower.
if (gsm.begin(2400)){
Serial.println("\nstatus=READY");
started=true;
}
else Serial.println("\nstatus=IDLE");
if(started){
//Enable this two lines if you want to send an SMS.
//if (sms.SendSMS("3471234567", "Arduino SMS"))
//Serial.println("\nSMS sent OK");
}
};
void loop()
{
if(started){
//Read if there are messages on SIM card and print them.
if(gsm.readSMS(smsbuffer, 160, n, 20))
{
Serial.println(n);
Serial.println(smsbuffer);
}
delay(1000);
}
};
So I have this old motorized wheelchair that I am trying to convert into a robot. I replaced the original motor driver with a sabertooth 2x12 and I’m using an Arduino micro to talk to it. The motors shaft goes all the way threw so I attached a magnet and a Hall Effect sensor to the back side to act as a rotary encoder. My current goal is to be able to tell the robot to move forward a certain amount of feet then stop. I wrote some code to do this linearly however this didn't work so well. Then I learned about interrupts and that sounded like exactly what I needed. So I tried my hand at that and things went wrong on several different levels.
LEVEL ONE: I have never seemed to be able to properly drive the motors it seems like any time I put the command to turn them on inside of a loop or if statement they decide to do what they want and move sporadically and unpredictably
LEVEL TWO: I feel like the interrupts are interrupting themselves and the thing I set in place to stop the wheels from moving forward because I can tell it to move 14 rotary encoder clicks forward and one wheel will continue moving way past 1000 clicks while the other stops
LEVEL THREE: couple times I guess I placed my interrupts wrong because when I uploaded the code windows would stop recognizing the Arduino and my driver would break until I uploaded the blink sketch after pressing the reset button which also reloaded and fixed my drivers. Then if I deleted one of my interrupts it would upload normally.
LEVEL FOUR: my Hall Effect sensors seem to not work right when the motors are on. They tend to jump from 1 to 200 clicks in a matter of seconds. This in turn floods my serial port and crashes the Arduino ide.
So as you can see there are several flaws somewhere in the system whether it’s hardware or software I don't know. Am I approaching this the right way or is there some Arduino secret I don’t know about that would make my life easier? If I am approaching this right could you take a look at my code below and see what I’m doing wrong.
#include <Servo.h>//the motor driver uses this library
Servo LEFT, RIGHT;//left wheel right wheel
int RclickNum=0;//used for the rotory encoder
int LclickNum=0;//these are the number of "clicks" each wheel has moved
int D =115;//Drive
int R =70;//Reverse
int B =90;//Break
int Linterrupt = 1;//these are the interrupt numbers. 0 = pin 3 and 1 = pin 2
int Rinterrupt = 0;
int clickConvert = 7;// how many rotery encoder clicks equal a foot
void setup()
{
Serial.begin(9600); //starting serial communication
LEFT.attach( 9, 1000, 2000);//attaching the motor controller that is acting like a servo
RIGHT.attach(10, 1000, 2000);
attachInterrupt(Linterrupt, LclickCounter, FALLING);//attaching the rotory encoders as interrupts that will
attachInterrupt(Rinterrupt, RclickCounter, FALLING);//trip when the encoder pins go from high to low
}
void loop()
{//This is for controling the robot using the standard wasd format
int input= Serial.read();
if(input == 'a')
left(2);
if(input == 'd')
right(2);
if(input == 'w')
forward(2);
if(input == 's')
backward(2);
if(input == 'e')
STOP();
}
void forward(int feet)//this is called when w is sent threw the serial port and is where i am testing all of my code.
{
interrupts(); //turn on the interrupts
while(RclickNum < feet * clickConvert || LclickNum < feet * clickConvert)// while either the left or right wheel hasnt made it to the desired distance
{
if(RclickNum < feet * clickConvert)//check if the right wheel has gone the distance
RIGHT.write(D); //make the right wheel move
else
RIGHT.write(B);//stop the right wheel
if(LclickNum < feet * clickConvert)
LEFT.write(D);
else
LEFT.write(B);
}
noInterrupts();//stop the interrupts
resetCount();//set the click counters back to zero
}
//once i have the forward function working i will implament it through out the other functions
//----------------------------------------------------------------------
void backward(int feet)
{
RIGHT.write(R);
LEFT.write(R);
}
void left(int feet)
{
RIGHT.write(D);
LEFT.write(R);
}
void right(int feet)
{
RIGHT.write(R);
LEFT.write(D);
}
void STOP()
{
resetCount();
RIGHT.write(B);
LEFT.write(B);
}
void LclickCounter()//this is called by the left encoder interrupt
{
LclickNum++;
Serial.print("L");
Serial.println(LclickNum);
}
void RclickCounter()//this is called by the right encoder interrupt
{
RclickNum++;
M Serial.print("R");
Serial.println(RclickNum);
}
void resetCount()
{
RclickNum=0;
LclickNum=0;
}
don't use interrupt() and nointerrupt() (or cli() and sei()) as they will stop timer and serial interrupt, breaking a lot of things. Just set to 0 the counting variable OR use detachInterrupt and attachInterrupt.
variable used inside interrupt AND normal execution flow should be declared as volatile, or their value my be unsyncornized. So declare them like volatile int RclickNum=0;
interrupt should be fast to execute, as by default other interrupt will NOT execute while inside an interrupt.
NEVER use Serial inside interrupt; if Serial buffer is full, it will call Serial.flush(), that will wait for Serial interrupt of byte written, but because you are alreadi inside an interrupt will never happen...dead lock aka you code hangs forever!
because your "moving" function use quite a long time to execute, if multiple command arrive to the serial, thay will remain isnode the buffer until readed. So if in the terminal you write "asd" and then "e", you will see robot go left, backward, right, stop (yes, actually the stop function is not usefull as it does nothing because your "moving" function are "blocking", that mean they won't return until they ended, so the loop() code (and the read of "e") will not execute until the buffer of serial has been processed.