High bit rate in Arduino Mega - arduino

I am calculating throughput of BLE module using Arduino Mega. Module works on 3.3V so i have Logic Level Shifter between BLE and Arduino. BLE UART is set at 115200 and is sending data at the speed of 64Kbps(verified using CC2540 BLE packet sniffer). Packet send by BLE are in this format in hex:400102030405060708090A0B0C0D0E0F1011121323{40=#,23=#}. I am sending 100 number of packets.Here is the abstract of my code. Code works fine for lower bit rate 32Kbps but not for 64Kbs(BLE Connection interval to 10ms). It does not show any result in this bit rate.
void loop()
{
if(rxflag)
{
rxflag = false;
switch(rxState)
{
case get_first_header:
if(rxChar=='#')
{
startPoint=millis();
rxState=get_last_header;
}
break;
case get_last_header:
if(rxChar=='#')
{
packetNo++;
if(packetNo==100)
{
endPoint=millis();
totalTime= endPoint-startPoint;
Serial.print("Total Time of Packet=");
Serial.println(totalTime);
}
break;
}
}
}
void serialEvent1()
{
if (Serial1.available()>0)
{
rxChar = (char)Serial1.read();
rxflag = true;
}
}

When you 'purge' the serial buffer:
void serialEvent1()
{
if (Serial1.available()>0)
{
rxChar = (char)Serial1.read(); // was previous value of rxChar read ? mystery...
// this is a serious problem.
// 1 byte at a time? This can slow down
rxflag = true; // reception quite a bit, esp. if there
} // is xon/xoff.
}
When you have an event that's been set in an interrupt routine, you need to reset it before reading the data, unless you use the flag as a lock for interrupt data.
Here's what you should consider to dramatically improve throughput and reduce receive errors.
void serialEvent1()
{
rxflag = true;
}
//...
void lopp()
{
// ...
if (rxflag)
{
rxflag = false; // reset/read order is to avoid stalling.
while (Serial1.available())
{
// reading 4 or up 16 bytes at a time on a local buffer
// would help the tiny mega get this done job done faster.
//
// char buffer[8] buffer; // 2 dwords on the stack. don't overuse!
//
char c = (char)Serial.read();
// run state machine...
}
}
// ...
}

Related

How to make serial reading asynchronously to main loop

I have arduino with code below. It has encoder, and prints something on encoder turn. But also it receive a lot of data, so if arduino is reading serial main loop stops and encoder loosing steps. How can I write code where encoders printing has always priority?
code:
#include <Encoder.h>
String receivedData = "";
Encoder encoder1(24, 25);
long position1 = -999;
long newPosition1;
void setup() {
Serial.begin(57600);
}
void loop() {
newPosition1 = encoder1.read();
if (newPosition1 != position1) {
Serial.print("PrintSomething");
}
position1 = newPosition1;
Serial.flush();
if(Serial.available() > 0) {
receivedData = Serial.readStringUntil(';');
if (receivedData == "?") {
Serial.print("3," + String(deviceId) + ",0,0,3;");
}
doSomethingImmediatly();
}
}
Important thing is in reality i have 6 encoders, so i can't use interrupts. And doSomethingImmediatly function should run as fast as possible.
Funny thing is if i use higher braud the problem is even more visible.
I would strongly suggest using SerialEvent instead of polling for serial data. This way, you build the serial string char by char and you can decide where to stop reading.
I would rather poll the encoders to avoid using clock cycles reading the status of every encoder sequentially. Otherwise, reconsider using a different library that might offer better performance (like RotaryEncoder from mathertel)
Based on the number of encoders that you are trying to read and the potential bottlenecks that you will encounter at 16 MHz (most common clock speed from Arduino - unless us Due or Mega-), I advise porting your application to a Teensy Microcontroller (> 3.2)
Keep in mind, there is no such thing as 'priorities' unless, as lurker mentioned, you use RTOS. You have to play with timings and efficient logic
For instance, a skimmed example code would look like the following (it shows only one polling routine):
unsigned long previousEncoderTime;
unsigned long pollPeriod = 200; // Poll every 200 ms
char serialString[] = " "; // Empty serial string variable
bool stringFinished = false; // Flag to indicate reception of a string after terminator is reached
void setup(){
previousEncoderTime = 0;
}
void loop(){
unsigned long now = millis();
if (now - previousEncoderTime >= pollPeriod){
previousEncoderTime = now;
// Encoder reading routine
}
if (stringFinished){ // When the serial Port has received a command
stringFinished = false;
// Implement your logic here
}
}
void serialEvent()
{
int idx = 0;
while (Serial.available())
{
char inChar = (char)Serial.read();
if (inChar == '\n') // The reading event stops at a new line character
{
serialTail = true;
serialString[idx] = inChar;
}
if (!serialTail)
{
serialString[idx] = inChar;
idx++;
}
if (serialTail)
{
stringFinished = true;
Serial.flush();
serialTail = false;
}
}
}

Data loss during communication via car's CAN bus (Arduino Uno + MCP2515)

I am very new to Arduino and this is my very first topic here. I am currently working on car's CAN BUS (500,000bps) communication in order to read and translate the CAN message real time. The UNO together with MCP2515 are connected to the car OBD2 port in order to sniff all supported PID data and the available output are now printed out and it looks promising enough (attached picture). However, I experienced frequent data loss, even though there is the delay of 5 seconds to read the next loop of data. I did try searching but never get any closer to the proper solution. Is this situation is called either Race Condition or data overflow? or I have to take a look at buffer size of transmitted data?
All source file and sketch are referred to https://github.com/sandeepmistry/arduino-OBD2.
Here is the sketch I used (libraries\OBD2-0.0.1\examples\OBD2_01_SupportedPIDs);
Please see the result of printout attached.
[#include <CAN.h> // the OBD2 library depends on the CAN library
#include <OBD2.h>
void setup() {
Serial.begin(9600);
while (!Serial);
Serial.println(F("OBD2 data printer"));
while (true) {
Serial.print(F("Attempting to connect to OBD2 CAN bus ... "));
if (!OBD2.begin()) {
Serial.println(F("failed!"));
delay(1000);
} else {
Serial.println(F("success"));
break;
}
}
Serial.println();
Serial.print("VIN = ");
Serial.println(OBD2.vinRead());
Serial.print("ECU Name = ");
Serial.println(OBD2.ecuNameRead());
Serial.println();
}
void loop() {
// loop through PIDs 0 to 95, reading and printing the values
for (int pid = 0; pid < 96; pid++) {
processPid(pid);
}
Serial.println();
// wait 5 seconds before next run
delay(5000);
}
void processPid(int pid) {
if (!OBD2.pidSupported(pid)) {
// PID not supported, continue to next one ...
return;
}
// print PID name
Serial.print(OBD2.pidName(pid));
Serial.print(F(" = "));
if (OBD2.pidValueRaw(pid)) {
// read the raw PID value
unsigned long pidRawValue = OBD2.pidReadRaw(pid);
Serial.print(F("0x"));
Serial.print(pidRawValue, HEX);
} else {
// read the PID value
float pidValue = OBD2.pidRead(pid);
if (isnan(pidValue)) {
Serial.print("error");
} else {
// print value with units
Serial.print(pidValue);
Serial.print(F(" "));
Serial.print(OBD2.pidUnits(pid));
}
}
Serial.println();
}][1]
Printout of sketch OBD2_03_DataPrinter.ino
Upgrading from a UNO to a Mega2560 solved my problems. Now my sketches upload much faster and the frequent crashes have disappeared. Clearly, the UNO has insufficient memory to cope with a can-bus shield.

The WiFi ESP8266 modifies my power values in Arduino monitor

Here is a link to openenergy monitor where I got the current sensor, you can find the type CT3100.
I'm working on an energy monitor using an Arduino Uno. I'm already able to get values (which are correct) of total power in the Arduino monitor. I would like to send that data to a database using an ESP8266 WiFi module.
The problem that occurs is when I add ESP module to Arduino, the values of total power I get in the monitor are not correct anymore.
void setup(){
wifi.setBootMarker(F("Version:0.9.2.4]\r\n\r\nready"));
softser.begin(9600); // Soft serial connection to ESP8266
Serial.begin(9600);;
emon1.current(1, 55.6); // Current: input pin, calibration.
char buffer[50];
Serial.print(F("Hard reset..."));
if(!wifi.hardReset()) {
Serial.println(F("no response from module."));
for(;;);
}
Serial.println(F("OK."));
Serial.print(F("Soft reset..."));
if(!wifi.softReset()) {
Serial.println(F("no response from module."));
for(;;);
}
Serial.println(F("OK."));
Serial.print(F("Checking firmware version..."));
wifi.println(F("AT+GMR"));
if(wifi.readLine(buffer, sizeof(buffer))) {
Serial.println(buffer);
wifi.find(); // Discard the 'OK' that follows
} else {
Serial.println(F("error"));
}
Serial.print(F("Connecting to WiFi..."));
if(wifi.connectToAP(F(ESP_SSID), F(ESP_PASS))) {
Serial.print(F("OK\nChecking IP addr..."));
wifi.println(F("AT+CIFSR"));
if(wifi.readLine(buffer, sizeof(buffer))) {
Serial.println(buffer);
wifi.find(); // Discard the 'OK' that follows
}
}
}
void loop(){
Serial.print(F("Connecting to host..."));
if(wifi.connectTCP(F(HOST), PORT)) {
Serial.print(F("OK\nRequesting page..."));
double Irms = emon1.calcIrms(1480); //extract Irms into Variable
double power = Irms*208;
String data;
data+="{\"IdClient\":";
data+=Client_id;
data+=",\"Nom\":\"";
data+=Nom;
data+="\",\"Irms\":";
data+=Irms;
data+=",\"Power\":";
data+=power;
data+="}";
softser.print(data);
String Post="POST / HTTP/1.1\r\nHost: 13.81.244.50\r\nContent-Type:
application/json\r\nContent-Length:";
Post+=String(data.length());
Post+="\r\n\r\n";
Post+=data;
Post+="\r\n\r\n";
String Send = "AT+CIPSEND=";
Send+=String(Post.length());
wifi.println(Send);
if (wifi.find(F(">"))){
wifi.print(Post);
}
//Test
if(wifi.find(F("OK"), true)) {
Serial.println(F("found!"));
} else {
Serial.println(F("not found."));
}
wifi.closeTCP();
} else { // TCP connect failed
Serial.println(F("D'oh!"));
}
delay(1000);
}

Arduino Serial Input to Stop and Start

I am trying to wait for user input to start a program operation and then when the user sends a stop command, the loop stops running. I have been unable to get the Serial port to keep reading an input while the loop is running.
So I want the user to Press 1 and then it'll go into the loop and will display the data from the interrupt. But I want it to keep monitoring the Serial Input so when I type in 2, I will get out of the loop and stop printing to the Serial Port.
The serial port isn't registering my second input.
I left out some of the code, but the important stuff should be there.
int userStart = 0; // Holder for user input to start program
int userStop = 0; // Holder for user input to stop program
void setup() {
Serial.begin(115200);
pinMode(motorEncoderA, INPUT);
digitalWrite(motorEncoderA, HIGH); // Pull up resistor
pinMode(motorEncoderB, INPUT);
digitalWrite(motorEncoderB,HIGH); // Pull up resistor
// Interrupt on change of Pin A
attachInterrupt(digitalPinToInterrupt(2), encoderFunc, CHANGE);
Serial.print("Press 1 to start the Process & 2 to Stop");
}
void loop() {
if (Serial.available() > 0)
{
userStart = Serial.read();
if (userStart = 1) {
Serial.print('\n');
while(userStop != 2) {
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print(userStart);
}
if (Serial.available() > 0) {
userStop = Serial.read();
Serial.print(userStop);
}
}
}
}
Well, I think your problem is that userStart and userStop should not be 1 and 2, but '1' and '2'.
That said, there are some things in your code I dislike.
First of all why is everybody using int as the base type for all numeric variables? If one single byte is enough, use it. On 32bit machines int and byte are almost the same, but on 8bit ones working with ints wastes space and time.
Secondly, I highly discourage you to block the loop function, otherwise you won-t be able to do anything else. Instead, use a variable to track wheter you are running or not, update it with the serial interface, and then execute the code if you are running.
This code should do it. And IMHO it is much better than blocking the loop:
bool running = false;
void setup()
{
...
running = false;
}
void loop()
{
if (Serial.available() > 0)
{
switch(Serial.read())
{
case '1':
running = true;
Serial.print('\n');
break;
case '2':
running = false;
Serial.print("stopped");
break;
}
}
if (running)
{
unsigned long timee = millis();
// Only update if the shaft has moved
if (encoderPositionLast != rotationCounter) {
Serial.print("Time: ");
Serial.print(timee);
Serial.print(" Count: ");
Serial.print (rotationCounter);
Serial.print('\n');
encoderPositionLast = rotationCounter;
Serial.print("running");
}
}
}

Transmitting a single character over UART from pic16f887 to a PC terminal(Putty, Hyperterminal, etc..)

I am trying to transmit a character "a" from pic16f887 and see the result on the terminal, but all I get is a question mark(using USART terminal), or nothing at all(Putty, Hyperterminal). I am not so great with C, as I'm only a beginer, but I really need to get this working for my school project.. I have tried many codes I've found over the internet, and I did manage to receive a character from the terminal and, lets say, turn on a LED, but I just can't manage to make it send anything. And I have a strong feeling its somewhere in the code.. Im using MPLAB and Hi-Tech C compiler to build the project. Here it is:
unsigned char cUART_char;
unsigned char cUART_data_flg;
void init_uart(void);
void UART_putc(unsigned char c);
void InterruptHandlerLow ();
void main()
{
TRISA = 0;
PORTA = 0;
TRISB = 0;
PORTB = 0;
TRISD = 0;
PORTD = 0;
ANSELH = 0;
init_uart();
while (1)
{
if (cUART_data_flg==1)
{
UART_putc(cUART_char);
cUART_data_flg=0;
}
}
}
void InterruptHandlerLow ()
{
if (RCIF==1)//is interrupt occured by EUSART receive?,
//then RCREG is full we have new data (cleared when RCREG is read)
{
if(RCSTA&0x06) //more efficient way than following commented method to check for reception error
//if(RCSTAbits.FERR==1 || RCSTAbits.OERR==1 )
{
CREN=0; //Overrun error (can be cleared by clearing bit CREN)
cUART_char=RCREG; //clear Framing error
CREN=1;
}
else
{
cUART_char = RCREG; // read new data into variable
cUART_data_flg = 1; // new data received. so enable flg
}
}
}
void init_uart(void) // init UART module for 9600bps boud, start bit 1, stopbit 1, parity NONE
{
// init data receive flag to zero (no data)
TRISC7=1; //Make UART RX pin input
TRISC6=0; //Make UART TX pin output
SYNC = 0; // enables for asynchronous EUART
SPEN = 1; // enables EUSART and sets TX (RC6) as output; ANSEL must be cleared if shared with analog I/O
CREN = 1;
TX9 = 0; // 8bit mode
RX9 = 0;
TXEN = 1; // enables Transmitter
BRGH = 1; // baud rate select
BRG16 = 0;
SPBRG = 25; //baud rate select 9600#4Mhz
SPBRGH = 0;
RCIE=1; // receive interrupt enable
GIE=1; // global interrupt enable
PEIE=1 ; // Peripheral Interrupt Enable bit
}
void UART_putc(unsigned char c)
{
TXEN=0;// disable transmission
TXREG=0x61; // load txreg with data
TXEN=1; // enable transmission
while(TRMT==0) // wait here till transmit complete
{
}
}
Please if someone sees a problem (or more) in this code, help me to crack this ;)
Oh and I am transmitting when pressing a button connected to a TX pin (RC6)..

Resources