I have been trying to get Timer related stuff for my Arduino Project and its been 3 days I am stuck with timers. I am having little trouble understanding this. So here is the ideal setup:
I want to run an interrupt that always interrupting when there is a serial data available. So there are two inputs coming to micro controller. 1. Analog sensor data and 2. Serial data coming to hardware serial port. So I want an interrupt which stops my analog signal and deals with the serial data first reset the timer to 0 and runs the analog signal back when there is no serial available. I tried with serialEvent function but the processing of MC is so fast that it reads both analog and serial data. I fully want to stop analog signal when there is Serial available. I have tried to use timer interrupt if there is a serial available and reset it back once its processed but nothings working out. I have attached my code below.
-Can I use hardware Serial port with interrupts or are there any other pins for that?
I just really don't understand this timers and interrupts. Internet tutorials / example code are a bit cyptic, as is the data sheet there are no such example which could be helpful. Any help, guidance and/or example code guys your could give me would be stupendous. Thanks
Here is my code:
void setup() {
// put your setup code here, to run once:
cli();
TCCR1A = 0; // Reset control registers timer1
TCCR1B = 0; // Reset control registers timer1
TCNT1 = 0;
OCR1A = 1000;
TCCR1B |=(1<<CS12); //Prescaler of 256
//TCCR1A |= (1 << WGM21);
sei();
inputString.reserve(200);
xbSerial.begin(9600);
Serial.begin(38400);
while(!Serial);
Serial.print("begin");
}
void loop() {
analogReference(EXTERNAL);
// put your main code here, to run repeatedly:
if(flag == false)//timer expired
{
processAD(); //another function. data from sensor
}
else
{
processSerial();
}
}
}
void processSerial()
{
// data arriving at Serial Port{"x":"right","y":"up","angle":"up","force":74.51258283001603}
int index=0;
int inc=0;
for(inc=0;inc<11;inc++)
{
while(inputString[index]!='"')
{
index++;
}
index++;
}
angle="";
while(inputString[index]!='"')
{
Serial.print(inputString[index]);
angle+=inputString[index];
index++;
}
{
if(angle== "up")
xbSerial.write('f');
else if(angle== "down")
xbSerial.write('b');
else if(angle== "left")
xbSerial.write('l');
else if(angle== "right")
xbSerial.write('r');
else
xbSerial.write('s');
}
}
ISR(TIMER1_COMPA_vect)
{
while (Serial.available()>0 && flag == false) {
// get the new byte:
char inChar = (char)Serial.read();
if(stringComplete)
return;
if(inChar=='{')
{
inputString="";
}
if(startrecvd)
{
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n') {
stringComplete = true;
startrecvd =false;
flag = true;
}
}
}
}
To make it easy for people to help you please modify your post and use the code button </> so your code looks like this and is easy to copy to a text editor. See How to use the Forum
Your code is too long for me to study quickly without copying to a text editor.
Also please use the AutoFormat tool to indent your code for easier reading.
Serial data is very slow compared to an Arduino so I don't see any need for interrupts. And note that serialEvent() is not interrupt driven.
Have a look at the examples in Serial Input Basics - simple reliable ways to receive data.
Why would you use a timer interrupt to start reading the serial port? I suggest that you apply the principles in the above link.
If newData is false, you can do the processAD, else process the serial data.
If your processAD takes too long, break it up into steps and use a state machine to step through the states (steps). That will allow you to react quicker on the serial data.
Thanks for your reply. There were tutorial about receiving serial serial string that was really helpful thanks for that aswell.
But right now i have a different situation. I have constant analog reading coming to arduino from sensor and then arduino is processing that analog signal and transmitting via xbee further. In this meanwhile process if I receive serial data at my hardware serial port so i want to process it first and completely ignore the analog reading during this process. Without interrupt as you said. I tried without interrupt I don't see any output from my serial port.
So in my code there are two processes 1. Process AD() that is for analog signal and 2. processSerial(). if there is a no serial available i want to call processAD() function otherwise processSerial(). It looks simple but i am after this since 3 days.
hasan121: But right now i have a different situation. I have constant analog reading coming to arduino from sensor and then arduino is processing that analog signal and transmitting via xbee further. In this meanwhile process if I receive serial data at my hardware serial port so i want to process it first and completely ignore the analog reading during this process. Without interrupt as you said. I tried without interrupt I don't see any output from my serial port.
I'm not convinced that it is really different. However if you post your program so I can conveniently access it I will look at it.
I have attached my sensors input pin A0 and A1 which is continuously processing analaog input and transmitting via xbee further. if there is any serial data coming to serial ports from bluetooth, i want to process that data first and transmitt via xbee and arduino is allowed to read analog data again. I have initialize serialEvent function which tracks my incoming serial data at hardware serial ports. I have also attached the screenshot of my output. I can only read analog data but no serial data. Please have a look.
if (startrecvd)
{
inputString += inChar;
// if the incoming character is a newline, set a flag so the main loop can
// do something about it:
if (inChar == '\n')
{
stringComplete = true;
startrecvd = false;
}
but nowhere in the code do you set startrecvd to true.
void loop() {
// put your main code here, to run repeatedly:
if(Serial.available()>0){
serialEvent();
}
else{
processAD();
}
}
Leaving aside the question of calling serialEvent() I don't understand why processAD() is in an ELSE.
There is no guarantee that a single call to serialEvent() will get the full message and I would have expected that the decision to call processAD() would depend on the content of the message rather than simply (as here) the fact that a message is in the process of arriving.
Have you studied the examples in Serial Input Basics. They allow the message to be received in bits and pieces and then the main program to be alerted when the full message has been received.
As a completely separate issue it is not a good idea to use the String (capital S) class on an Arduino as it can cause memory corruption in the small memory on an Arduino. Just use cstrings - char arrays terminated with 0.
And note that when using Cstrings you must use strcmp() to compare values rather than ==
I am receiving serial data now as expected together with analog. At the receiver end I don't get any output because if I don't use my sensor it sends stop command continuously as default case is set for processAd(). If I send up command from Bluetooth its transmitted further with stop command from sensor so therefor no movement or if I keep pressing the up button still it transmit both analog and serial data. I dont know why its happening. If I try it with delay of 100ms I can get output at receiver end but with delays. In loop() if I don't set newData = false then it begins with analog reading and suddenly if I send anything to serialport and it gets stuck there and doesn't receive any data after, neither from sensor. Attached you can see the output of serial monitor.
Is there any process to stop sensor data from processing or delay it if serial is available otherwise process sensor data without any delays. Because I am not receiving serial really fast because the amount of analog data processed by microcontroller is really high. what should I do in this case ?
Thanks in advance.
Output:
upstop
upstop
rightstop
rightstop
void loop() {
// put your main code here, to run repeatedly:
if(newData == false){
processAD();
}
else{
processSerial();
}
newData = false;
}
void serialEvent()
{
while (Serial.available()>0 && newData == false) {
// get the new byte:
char inChar = (char)Serial.read();
if (recvInProgress == true) {
if(inChar != '\n')
{
inputString += inChar;
}
else{
inChar ='\n';
recvInProgress = false;
newData = true;
}
}
else if(inChar == '{'){
recvInProgress = true;
inputString = "";
}
}
}
hasan121:
So I am receiving serial data now as expected together with analog. At the receiver end I don't get any thing because if I don't use my sensor it sends stop as default case is set of processAd(). If I send up from Bluetooth its transmitted further with stop so no movement. If I try it with delay of 100ms I can get output at receiver end but with delays. In loop() if I don't set newData = false then it begins with analog reading and suddenly if I send anything to serialport and it gets stuck there and doesn't receive any data after, neither from sensor.
Please re-read this and see if you can express it more clearly because I can't understand it after the first sentence which seems to be saying that everything is working OK.
I can read data from serial that was not the problem before. Problem was to interrupt the process of Analog data if serial arrives. Process serial data first and transmit further via XBEE. and then process Analog data but now the data from analog sensor is also continuously being processed and transmitted further via XBEE together with serial. So at the receiver's end i get only data of analog sensor. Analog processing is too fast and serial is too slow. Serial data gets ignore even if it has been processed and transmitted.
Problem I am facing is I want to delay or terminate this analog process only if serial arrives otherwise process analog without delays. Is it possible without timers or interrupts?
That is much clearer but I'm still not sure I understand the process properly. Is it the case that most of the time characters lrbfs are sent as a result of analog input but sometimes they are sent as a result of what is received by Serial?
If that is the case then I would put the appropriate character into a variable and send the variable. The character could be put into the variable by the function processAD() or by the function processSerial(). Rather than have xbSerial.write('X'); scattered all over the place you would just have one line with xbSerial.write(currentCharacter); and it would neither know nor care where the data came from.
It may also be wise to reduce the frequency with which processAD() is called - I suspect 10 times per second would be sufficient. Also for xbSerial.write(). And don't use delay(). Use millis() for non blocking timing as illustrated in Several Things at a Time
yes you are right. Doesn't matter if that character is from analog input or serial input. you can see in my code i have converted the sensor values into lrbfs and same as with the bluetooth joystick. I took the value of angle from the received string from bluetooth and converted in to lrbfs. I have used your method sending directly a variable.
If I am not using my analog sensor it will still transmit stop signal. On the other hand if I send anything from bluetooth lets say up command so the up signal is transmitted with stop signal of sensor. It causes interrupt in motor rotation.
you mean to reduce frequency with millis()like this ?
int period = 100;
unsigned long time_now = 0;
void loop() {
time_now = millis();
while(millis() < time_now + period){
// put your main code here, to run repeatedly:
if(newData == false){
processAD();
}
else{
processSerial();
}
newData = false;
}
}
I am not sure whether to use a timer or interrupt in this case or will it work with millis(). Let say if I use timer, it starts counting and if serial is available it overflows and process serial and starts counting again. Is it possible ? what are your suggestions
Serial is not fast enough to require anything more than millis().
I don't understand what you want but it seems a little like something I have done before:
If external data is available over Serial, use that data.
If no valid external data has arrived in the last 8 seconds, use the internal (analog) data.
This is easy enough to do if you record the time in millis() when you last got a valid Serial data packet. Then you know if you are allowed to send the internal data.
I would like to understand the project this way --
1. You have a serial device connected at hardware UART Port. You are expecting to receive messages (time-to-time) from this port. The term message has a definition: It is a string of characters clearly marked by a startSign (a control character/code) to indicate the beginning of message and clearly marked by an endSign (a control character/code) to indicate the end of message. The message will arrive at the Receiver Section of the UART Port one character at a time including the startSign and the endSign characters/codes.
2. You have another serial device (XBEE) connected at the sofware UART Port.
3. You have two analog sensors connected with Ch-A0 and Ch-A1.
4. You will collect the message from the UART Post, process it, and transmit it via XBEE. During this event, the acquisition-processing-transmission of the analog signals will remain OFF.
5. At the end of the event of Step-4, you will handle the analog channels which involves -- acquisition, processing, and transmission of the analog signals via XBEE. During this event, the acquisition-processing-transmission of the message (to be arrived via UART Port) will remain OFF.
6. Implementation using Polling Strategy
#include<SoftwareSerial.h>
SoftwareSerial mySerial (2, 3); //SRX, STX
bool flagRcv = false;
unsigned long presentMillis = 0;
char msgString[50] = "";
int i = 0;
byte x;
bool n;
bool flagx = false;
void setup()
{
Serial.begin(9600);
bitClear(UCSR0B, 7); //TX interrupt disable
bitClear(UCSR0B, 6); //RX interrupt disable
bitClear(UCSR0B, 5); //TxEmpty interruptdisable
presentMillis = millis();
}
void loop()
{
while (flagRcv == false)
{
presentMillis = millis();
do
{
n = bitRead(UCSR0A, 7); //RX Complete flag
if (n == HIGH)
{
//x = UDR0;
flagx = true;
break; //byte x = UDR0;
}
else
{
;
}
}
while (millis() - presentMillis <= 3000); //3-sec arbitrary delay to receive message via UART Port
if (flagx == false)
{
analogSignals();
}
x = UDR0;
// Serial.write(x);
// while(1);
if (x == '
Alternate Codes (that have replaced the register level instructions)
#include<SoftwareSerial.h>
SoftwareSerial mySerial (2, 3); //SRX, STX
bool flagRcv = false;
unsigned long presentMillis = 0;
char msgString[50] = "";
int i = 0;
byte x;
bool n;
bool flagx = false;
void setup()
{
Serial.begin(9600);
}
void loop()
{
while (flagRcv == false)
{
presentMillis = millis();
do
{
n = Serial.available();
if (n == 1)
{
flagx = true; //a charctaer has arrived
break; //charcater ahs arrived; no need next try;
}
else
{
;
}
} while (millis() - presentMillis <= 3000);//do the avove for 3-sec maximum
if (flagx == false)
{
analogSignals(); //try for 3-sec over; now acquire/process/xmit analog signal
}
x = Serial.read(); //read character fro serial buffer
if (x == '
Testing Procedures: (a) Set analogReference() to DEFAULT. (b) Connect 3.3V at A0-pin as Test Signal for analog channel-A0. (c) Let us upload the sketch in UNO. (d) Bring in the Serial Monitor. (e) Observe that ADC value for 3.3V appears on Serial Monitor (approx: 0x02A8 = (hex)1024/5*3.3). (f) In the InBox of the Serial Mobitor, let us enter $ABCD1234& and click on send button. (g) Let us observe that the string ABCD1234& has appeared (echoed back) on the Serial Monitor.
***a little bit work is required to remove the endSign(&) character from the msgString.
7. Implementation using Interrupt Strategy
If polling strategy does not provide acceptable performance/result, interrupt strategy could be thought about whose actual implementation, certainly, would not be so straightforward!) //startSign
{
flagRcv = true;
}
else
{
analogSignals();
}
}
// Serial.print("OK");
do
{
n = bitRead(UCSR0A, 7); //RX Complete flag
if (n == HIGH)
{
x = UDR0;
// Serial.write(x);
msgString[i] = x;
i++;
//while (1);
}
else
{
;
}
}
while (x != '&'); //endSign
flagRcv = false;
Serial.print(msgString);
Serial.println();
}
void analogSignals()
{
int x = analogRead(A0);
Serial.print(highByte(x), HEX);
Serial.println(lowByte(x), HEX);
}
**Alternate Codes** (that have replaced the register level instructions)
§DISCOURSE_HOISTED_CODE_1§
**Testing Procedures:**
**(a)** Set analogReference() to DEFAULT.
**(b)** Connect 3.3V at A0-pin as Test Signal for analog channel-A0.
**(c)** Let us upload the sketch in UNO.
**(d)** Bring in the Serial Monitor.
**(e)** Observe that ADC value for 3.3V appears on Serial Monitor (approx: 0x02A8 = (hex)1024/5*3.3).
**(f)** In the InBox of the Serial Mobitor, let us enter $ABCD1234& and click on **send** button.
**(g)** Let us observe that the string ABCD1234& has appeared (echoed back) on the Serial Monitor.
***a little bit work is required to remove the **endSign(&)** character from the msgString.
**7.** Implementation using Interrupt Strategy
If polling strategy does not provide acceptable performance/result, interrupt strategy could be thought about whose actual implementation, certainly, would not be so straightforward!) //checking if it is the beginning of message (startSign)
{
flagRcv = true; //yes beginnin of message
}
else
{
analogSignals(); //this is not the beginning of message; some other character
}
}
// Serial.print("OK"); //debugging point
do
{
n = Serial.available(); //checking if charcater has arrived
if (n == 1)
{
x = Serial.read();
msgString[i] = x; //store the charcaters into charcater array
i++; //increment array index
}
else
{
;
}
}
while (x != '&'); //end-of-message (endSign)
flagRcv = false; //flag reset
Serial.print(msgString); //display received message
Serial.println(); //new line charctaer
}
void analogSignals()
{
int x = analogRead(A0);
Serial.print(highByte(x), HEX);
Serial.println(lowByte(x), HEX);
}
Testing Procedures: (a) Set analogReference() to DEFAULT. (b) Connect 3.3V at A0-pin as Test Signal for analog channel-A0. (c) Let us upload the sketch in UNO. (d) Bring in the Serial Monitor. (e) Observe that ADC value for 3.3V appears on Serial Monitor (approx: 0x02A8 = (hex)1024/5*3.3). (f) In the InBox of the Serial Mobitor, let us enter $ABCD1234& and click on send button. (g) Let us observe that the string ABCD1234& has appeared (echoed back) on the Serial Monitor.
***a little bit work is required to remove the endSign(&) character from the msgString.
7. Implementation using Interrupt Strategy
If polling strategy does not provide acceptable performance/result, interrupt strategy could be thought about whose actual implementation, certainly, would not be so straightforward!) //startSign
{
flagRcv = true;
}
else
{
analogSignals();
}
}
// Serial.print("OK");
do
{
n = bitRead(UCSR0A, 7); //RX Complete flag
if (n == HIGH)
{
x = UDR0;
// Serial.write(x);
msgString[i] = x;
i++;
//while (1);
}
else
{
;
}
}
while (x != '&'); //endSign
flagRcv = false;
Serial.print(msgString);
Serial.println();
}
void analogSignals()
{
int x = analogRead(A0);
Serial.print(highByte(x), HEX);
Serial.println(lowByte(x), HEX);
}
**Alternate Codes** (that have replaced the register level instructions)
§DISCOURSE_HOISTED_CODE_1§
**Testing Procedures:**
**(a)** Set analogReference() to DEFAULT.
**(b)** Connect 3.3V at A0-pin as Test Signal for analog channel-A0.
**(c)** Let us upload the sketch in UNO.
**(d)** Bring in the Serial Monitor.
**(e)** Observe that ADC value for 3.3V appears on Serial Monitor (approx: 0x02A8 = (hex)1024/5*3.3).
**(f)** In the InBox of the Serial Mobitor, let us enter $ABCD1234& and click on **send** button.
**(g)** Let us observe that the string ABCD1234& has appeared (echoed back) on the Serial Monitor.
***a little bit work is required to remove the **endSign(&)** character from the msgString.
**7.** Implementation using Interrupt Strategy
If polling strategy does not provide acceptable performance/result, interrupt strategy could be thought about whose actual implementation, certainly, would not be so straightforward!
while (millis() - presentMillis <= 3000); //3-sec arbitrary delay to receive message via UART Port
You know, while I don't usually care about the people that insist that every } or { must be on a line by itself, in this case, it makes it much easier to understand if this is written as...
} while (millis() - presentMillis <= 3000); //keep doing the above for 3 seconds maximum