Asynchronous UART transfer in microcontroller 8051 - serial-port

Hi i am trying to communicate my 89c52 with sim548c module. I am sending AT commands and then making the microcontroller store all replies in an array and go through a search function to see if proper reply was sent so it can move on to next AT command. This requires two way serial transfer. i have to first send serially the AT command, then enable reception and store all replies from the module in an array. I am using this program but i cant get the microcontroller to accept the incoming data and store it in an array. it transfers successfully but doesnt receive. Can you kindly identify what is the problem?
int check=0;
int out=0;
unsigned char info[20]={"00000000000000000000"};
unsigned char *s;
unsigned char a[3],b[3];
void transmit_data(unsigned char str)
{
SBUF=str;
while(TI==0);
TI=0;
}
void send_serial(unsigned char *s)
{
delay(50);
while(*s!=0x0)
{
SBUF=*s;
while(TI==0)
{
}
TI=0;
s++;
}
}
void receive_data() interrupt 4
{
if(RI)
{
info[check++]=SBUF;
RI=0;
}
if(TI)
TI=0;
}
void search(unsigned char b[])
{
int l=0;
for(l;l<18;l++)
{
if(info[l]==b[0] && info[l+1]==b[1] && info[l+2]==b[2])
{
out=1;
break;
}
}
}
void compare(unsigned char *s, unsigned char a[]) //for CIPSEND
{
while(1)
{
out=0;
check=0;
delay(50);
send_serial("AT+CIPSEND\r");
delay(100);
send_serial(s);
transmit_data(0x0D);
transmit_data(0x0A);
transmit_data(0x1A);
IE=0x90;
delay(200);
IE=0x88;
search(a);
if (out==1)
break;
}
}

i have seen this a couple of times and th mistake is that your serial receive works with an interrupt and it is not a voidable function smply remove the VOID that is attached to INTERRUPT 4 so tha ur code becomes
receive_data() interrupt 4
{
if(RI)
{
info[check++]=SBUF;
RI=0;
}
if(TI)
TI=0;
}

I would suggest making a smaller (as simple as you can) program that does nothing more than receive (by interrupt?) data and blink a LED or echo it back or in some other way indicate that you can reliably receive. Use that to talk to a terminal emulator or another known working interface. Cut out all possible middlemen and unknowns.
Check also UART error registers and configuration to make sure your clock/parity/data settings match in both ends. Start with a slow rate first.
Make one piece at a time work reliably, then put them together.

Related

How to configure watchdog for the arduino Nano 33 BLE Sense board?

For the arduino Nano 33 BLE Sense board, the standard avr/wdt.h is not available. And it seems that no standard library provides it. How to use the watchdog system for this board ? I found no full information about it.
I've found the page https://www.mysensors.org/apidocs/group__avr__watchdog.html which allow to configure the reboot mode. And it works.
But no way to configure the interruption mode with ISR() function.
Moreover, there's no explanation about the manipulation of used register/variables for any fine configuration.
Simple code example with regular asynchronous stuff using the watchdog ISR() mechanism. It which works well with ATmega328 (e.g.UNO). But I do not find equivalent configuration for the Nano 33 BLE using the nRF52840.
# include <avr/wdt.h>
volatile byte led;
int k;
ISR(WDT_vect) {
Serial.println("Asynchronous stuff in ISR() function");
digitalWrite(LED_BUILTIN,led);
led=!led;
}
void setup() {
pinMode(LED_BUILTIN,OUTPUT);
led=0;
Serial.begin(9600);
while(!Serial) {}
Serial.println("== R E B O O T ==");
WDTCSR = ( 1 << WDE ) | ( 1 << WDCE );
WDTCSR = ( 1 << WDP2 ) | ( 1 << WDP0 ) | ( 1 << WDIE ) ; // Interruption and timeout 1/2 s
}
void loop() {
Serial.print("Loop #");
Serial.println(k);
if (k++%2) {
Serial.println("Some stuff (even branch)");
delay(1200);
}
else {
Serial.println("Some stuff (odd branch)");
delay(4800);
}
}
Thks.
In fact, for the RF52940, I'm not sure that the watchdog can provide the needed interruption mechanism despite it exists the INTENSET bit for interruption according to the chipset doc https://content.arduino.cc/assets/Nano_BLE_MCU-nRF52840_PS_v1.1.pdf).
But the good way is for sure the use of timers (and one can use more than just one, quite good).
For a similar behaviour as the code given for the UNO before, here is the code one can write for the Nano BLE using a timer interrupt (see https://github.com/khoih-prog/NRF52_MBED_TimerInterrupt for full and usefull doc).
#include "NRF52_MBED_TimerInterrupt.h"
volatile byte led;
volatile uint32_t count=0;
NRF52_MBED_Timer myTimer(NRF_TIMER_1);
unsigned k=0;
void myHandler() {
digitalWrite(LED_BUILTIN,led);
led=!led;
count++;
}
void setup() {
pinMode(LED_BUILTIN,OUTPUT);
led=0;
Serial.begin(9600);
while(!Serial) {}
Serial.println("== R E B O O T ==");
if (myTimer.attachInterruptInterval(500*1000, myHandler)) // each 1/2 second
Serial.println("myTimer launched");
else
Serial.println("Can not set the timer");
}
void loop() {
Serial.print("Loop #");
Serial.print(k);
Serial.print(" and nb times in Handler : ");
Serial.println(count);
if (k++%2) {
Serial.println("Some stuff (even branch)");
delay(1200);
}
else {
Serial.println("Some stuff (odd branch)");
delay(4800);
}
}

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

How to make a response in Bluetooth module (Arduino)

I connected my Bluetooth module to the mobile phone and made up a code to communicate between Arduino and mobile through Bluetooth (send messages from Bluetooth module to device and vice versa).
Now I want to make a response, which means that if I send from the mobile "hi" the arduino replies and says "Hello" or whatever.
I have tried tons of codes but none worked, so would anyone please help me?
#include <SoftwareSerial.h>
SoftwareSerial myserial (6,5);
void setup() {
myserial.begin(9600);
Serial.begin (9600);
}
void loop() {
if (myserial.available()) {
Serial.write(+ myserial.read());
}
if (Serial.available()) {
myserial.write(Serial.read());
}
}
Another code but making a loop without sending anything
#include <SoftwareSerial.h>
SoftwareSerial myserial(6,5); //Arduino: R:5,T:6; bluetooth: T:5, R:6;
void setup() {
myserial.begin(9600);
Serial.begin (9600);
}
void loop() {
if (myserial.available()) {
Serial.write(myserial.read());
}
if (Serial.available()) {
myserial.write(Serial.read());
}
for (int i = 0; i=2; i++) {
myserial.write("hello");
}
if (myserial.read() =="n") {
myserial.write("hello");
}
}
You need to build your serial string char by char using the SerialEvent() interrupt, then do a String comparison using the .equals method. Despite many people will tell you that String types are 'evil' (see this and this) it might be a good solution for making things clearer (and perhaps a bit easier if you don't want to mess with C char strcmp() functions and pointers. In the end, the String type is there for you and I see no reason for not using it in general projects.
Based on the SerialEvent() documentation [1], and the String reference [2], you could do something like:
String inputString = ""; // a String to hold incoming data
bool stringComplete = false; // whether the string is complete
void setup() {
// initialize serial:
Serial.begin(9600);
// reserve 200 bytes for the inputString:
inputString.reserve(200);
}
void loop() {
// print the string when a newline arrives:
if (stringComplete) {
//Then you compare the inputString with the word you want to detect using the .equals method from the String class
if(inputString.equals("Hi"){
Serial.println("Hello");
}
// clear the string for a new comparison:
inputString = "";
stringComplete = false;
}
}
/*
SerialEvent occurs whenever a new data comes in the hardware serial RX. This
routine is run between each time loop() runs, so using delay inside loop can
delay response. Multiple bytes of data may be available.
*/
void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
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;
}
}
}
EDIT 1: Of course, you can replace the Serial object from this example code with your own myserial object from the BlueTooth communication.

how to read char array from serial monitor and command arduino accordingly?

currently, I am working on a project to read char inputs from serial monitor and command Arduino to switch on/off specific pins. The problem I am facing is, I am unable to read the complete char array entered in the serial monitor. can anyone tell me what am I doing wrong?
#define X 13 //led pin
char txt[15];
int i;
int Status=0;
void setup() { // put your setup code here, to run once:
pinMode(X,OUTPUT);// setting the pin flow of control as output
Serial.begin(9600);
while(!Serial)
{
; //to wait for pc to connect
}
Serial.println("\nHome Automation");
dashprint();
}
void loop() { // put your main code here, to run repeatedly:
if(Serial.available()>0)
{ i=0;
while(Serial.available()>0) //if serial available
{ char inchar=Serial.read();
txt[i]=inchar; // add char to txt string
i++;// increment to where to write next
txt[i]='\0'; //null termination
}
Serial.print(txt);
check();
}
}
void dashprint() //to print dashes
{
Serial.println("-----------------------------------------------");
Serial.println("give me some command"); //ask for command
}
void check()
{ if(strncmp(txt,"ON",2)==0)
{
digitalWrite(X,HIGH);
Status=1;
}
else if(strncmp(txt,"OFF",3)==0)
{ digitalWrite(X,LOW);
Status=0;
}
else if(txt=="STATUS")
{
}
else Serial.println("ERROR");
}
output:
Home Automation
give me some command
OERROR
NERROR
ERROR
expected output:
Home Automation
give me some command
ON
Your arduino is too fast to read the text "ON" in one round.
9600 is 1 ms per character.
A simple workaround is, to add a little delay
if(Serial.available()>0) {
delay(3); // wait for the whole message
i=0;
while(Serial.available()>0) {
...
ADD:
Additionally, you obviously receive a '\n' (newline) character. Make sure it's not causing troubles.
And increase the delay or have a better approach in general, if you expect more than 3 characters ( "STATUS" )
struct MYObject {char a[256];};
//structure works well with EEPROM put and get functions.
//also lets to input large strings, more then 64 bytes, as http
void setup() {
MYObject str ={" "};
Serial.begin(115200);
while (!Serial.available()) delay (10); //wait for string
int i = 0;
int k= Serial.available();
while (k > 0){
char inchar = Serial.read(); //read one by one character
str.a[i] = inchar;
i++;
if (k < 3) delay (10); //it gives possibility to collect more characters on stream
k = Serial.available();
}
str.a[i]='\0'; //null terminator
//now lets see result
Serial.println(str.a);
//.....
}

Unable to store stream data in variable in Arduino programming

I'm unable to store the serial.port value in a variable. I want to send a message from Android telnet app, on and off. If on comes I want to print fan on, if off comes I want to print off. I'm able to print on and off while I'm statically fixing value. I'm unable to store the stream in a variable.
String stringOne;
void setup() {
digitalWrite(13, LOW);
// Open serial communications and wait for port to open:
Serial.begin(9600);
while (!Serial) {
; // wait for serial port to connect. Needed for native USB port only
}
// send an intro:
Serial.println("\n\nString substring():");
Serial.println();
pinMode(13,OUTPUT);
}
void loop() {
digitalWrite(13,LOW);
// Set up a String:
stringOne ="+IPD 0,14 :ON";
int length = stringOne.length();
Serial.println(stringOne.length());
Serial.println(stringOne);
if (Serial.available() > 0) {
// substring(index) looks for the substring from the index position to the end:
if (stringOne.substring(length-2,length) == "ON") {
Serial.println("FAN ON");
digitalWrite(13,HIGH);
// delay(2000);
}
if (stringOne.substring(length-3,length) == "OFF") {
Serial.println("FAN OFF");
digitalWrite(13,LOW);
// delay(2000);
}
}
// you can also look for a substring in the middle of a string:
// do nothing while true:
while (true);
}
Well, while editing your question, I couldnt help noticing that infinite loop at the end of your code.
// do nothing while true:
while(true)
In this case, even if your code was all right, you cant expect to get next data.
void loop --> Remember it is itself a infinite loop
update 1:
your logic to use the serial port is wrong;
Remember, serial port only recieves a single character at a time.
if you send "hello" from pc, at the other end, arduino will recieve h, e, l, l, o
The trick is to collect all letters into a array. and then use our logic in it.
char commandbuffer[20]; //an array to hold our characters
int i=0;
if (Serial.available() > 0) {
while( Serial.available() >0) { //read until all data we send arrives
char c = Serial.read();
commandbuffer[i]= c; //we are actually storing it one by one
i++;
}
}
commandbuffer[i]='\n';
for(int j = 0; j<i; j++){
Serial.print(commandbuffer[j]);// and show it one by one too
}
now when you send "hello", it will print hello back. I hope this give you some idea. Happy coding.

Resources