Serial: Printf and Scanf a string

10 Aug 2011

Hello! I'm trying to send a string from one mbed to another using the Serial functions printf and scanf and it doesn´t works. The code I have on the mbed who sends is the next:

#include "mbed.h"

Serial micro(p9, p10);//tx, rx
Serial pc(USBTX,USBRX);//tx, rx

const char command[9]={0xF2, 0x00, 0x09, 0xff, 0x22, 0x00, 0x05, 0x79, 0x6F};
int err;

int main() {
    micro.format(8, Serial::None, 1);
    micro.baud(19200);
    pc.format(8, Serial::None, 1);
    pc.baud(9600);

    while (true) {
        if (micro.writeable()) {           
            err=  micro.printf(command);
            break;
        }
    }    
    pc.printf("Printf returns: %d\r\n", err);
}

And in the mbed who receives:

#include "mbed.h"

Serial micro(p9, p10);
Serial pc(USBTX,USBRX);
int err;
char command[9];

int main() {
    micro.format(8, Serial::None, 1);
    micro.baud(19200);
    pc.format(8, Serial::None, 1);
    pc.baud(9600);   

    while (true) {       
        if (micro.readable()) {
            err= micro.scanf(command);            
            break;
        }
    }
    pc.printf("Command Received: \r\n");
    for (int i=0;i<sizeof(command);i++){
    pc.printf("%X",command[i]);
    }
    pc.printf("\r\n");
    pc.printf("Scanf returns: %d\r\n",err);
}

After executing the scanf works but it receives all 0 and returns a 0 too. I use the USBTX and USBRX to see in the Terminal what is happening. I tried too using "%s" before the string (micro.scanf("%s", command)) but in this way, I don´t receive anything. The scanf doesn´t work. I also realized that the printf and the scanf returns an integer, but I have no idea what it means (I didn't find information anywhere)

Does anybody what is wrong in my code?

Thank you so much!!!!

María.

10 Aug 2011

First off, the transmitted data array 'command' has a 0x00 as it's second byte. The is the string terminator character. The only thing that will be sent is the first character in the array, 0xF2. If you want to transmit binary data you need to send it using putc.

You would need to use scanf("%s", command).

scanf(command) is returning 0 meaning that it found zero items that matched. Likely because command is defaulting to all zeros, meaning it is an empty string and therefore it has no items to search for.

scanf("%s", command) isn't returning because it is (I think) still looking for a carriage return which isn't being sent.

scanf also isn't appropriate for binary data.

You need to set up a loop using a timeout and and checking for data on the incoming serial line using micro.available() (I think that's right, I might be thinking of some other system).

As a test try changing in the sending mbed from: const char command[9]={0xF2, 0x00, 0x09, 0xff, 0x22, 0x00, 0x05, 0x79, 0x6F}; to: const char command[] = "ABCD\r";

10 Aug 2011

Thank you! I´ll use putc and getc.

16 Aug 2011

I´m using now putc and getc but I have a problem. If I send, for example, 22 bytes using putc, I only can receive on the other side the 16 first bytes. Is there any size limit to send and receive chars? Thank you so much!

16 Aug 2011

You could try calling fflush(stdout); after you send the 22 bytes to make sure that they don't just sit in a buffer.

16 Aug 2011

I call fflush(stdout) after sending the 22 bytes and it´s the same. On the other mbed I just receive the 16 first bytes. Have you any idea? Thanks a lot!

17 Aug 2011

why you don't use interrupts to catch the incoming data?

Something like this:

#include <string>
string b;

newData(void) {

    //buffer variables
    char lezen;

    //if data is ready in the buffer
    while (zender.readable()) {
        //read 1 character
        lezen = micro.getc();

        //if character is $ than it is the start of a sentence
        if (lezen == '$') {
            //so the pointer should be set to the first position
            b.clear();

        }
        //write buffer character to big buffer string
        b += lezen;

        //if the character is # than the end of the sentence is reached and some stuff has to be done
        if (lezen == '#') {

            char * cstr, *p;
            string c1,c2,c3,c4;
            int set = 1;
            int n;
            float f;

            //remove start and stop characters
            b.erase(0,1);
            b.erase(b.length()-1,1);

//do something witth string b, like:
if (b=="some command"){
de something
}


}

main(){
...
micro.attach(&newData);

}



01 Sep 2011

Hi! I realized that if after the putc I send something to the USBRX pin, it works. The code is the next:

  for (int i=0; i<long_command; i++) {
                        while (true) {
                            if (micro.writeable()) {
                                result =  micro.putc(command[i]);
                                pc.printf("Putc result: %X\r\n",result);
                                break;
                            }
                        }
                    }

But, I don´t understand why it works in this way. Serial pins and USB pins use the same buffer? What is the relationship between them?

Does anybody know how it works??

Thanks!!

María.

01 Sep 2011

what exactly are you trying to accomplish?

<<quote>>Hello! I'm trying to send a string from one mbed to another using the Serial functions printf and scanf and it doesn´t works. The code I have on the mbed who sends is the next:<</quote>>

the best way to accomplish this is using an interrupt. Basically, if something arrives on the serial port on your receiving mbed, it automatically saves the data someplace where you can process later

<<quote>>But, I don´t understand why it works in this way. Serial pins and USB pins use the same buffer? What is the relationship between them?<</quote>>

They probably have different buffers

for (int i=0; i<long_command; i++) {
                        while (true) {
                            if (micro.writeable()) {
                                result =  micro.putc(command[i]);
                                pc.printf("Putc result: %X\r\n",result);
                                break;
                            }
                        }
                    }

is this the code on the transmitter?

01 Sep 2011

Yes, it´s in the transmitter. I´m sending a string from one mbed to another using putc and getc because they are binary data. The problem is that without the pc.printf only I can send 16 bytes.

01 Sep 2011

I think I know the problem

on the transmitter side

for(counter=0; counter<"length of string"; counter++) { serial_send.putc(command[counter]); wait(0.1); <<this is crucial as the receiver cannot react right away when a character arrives at the serial receiver }

The transmitter side is fine. The problem is on the receiver side. If you have other processes running on it, then the receiver may not be able to retrieve the character before a new character arrives. You can prevent this by using interrupts. That way, as soon as a character arrives at the serial port, the receiver can react right away and copy this character to a buffer somewhere.

01 Sep 2011

Thanks, I know that with interrupts is possible , but my question is if anybody knows why is there a relationship between the putc on the serial pins and the printf on the USB pins... It works without interrupts but I don´t know why... it´s a mistery :-)

01 Sep 2011

Im assuming the pc.printf("something") introduces somewhat a sufficient delay before a new character is send over the serial port.This gives time on your receiver to process the data.

The usb-to-serial is connected to a different serial port than what you're using

30 Apr 2012

Maria,

Could I have a copy of your working code please? I'm trying to achieve similar.

Did you use interrupts in the end?

Craig

02 May 2012

Hi Craig, Finally, I didn´t use interrupts, just the delay that te printf to de USB port introduce. Here you are the code to send:

  while (true) {
                    if (micro.writeable()) {
                        err=micro.putc(long_response);
                        break;
                    }
                }
                pc.printf("Response sent:\r\n");
                for (int i=0; i<long_response; i++) {
                    while (true) {
                        if (micro.writeable()) {
                            err=  micro.putc(response[i]);
                            pc.printf("%X", err);
                            break;
                        }
                    }
                }
                pc.printf("\r\n");

Where "long_response" is the size of the buffer you want to send. I send first this information to manage the loop on the reciving side.

And to receive:

  while (true) {
                    if (micro.readable()) {
                        size_command=micro.getc();
                        break;

                    }
                }
                char command[size_command];
                pc.printf("Command received:");
                for (int i=0; i<size_command; i++) {
                    while (true) {
                        if (micro.readable()) {
                            command[i]= micro.getc();
                            pc.printf("%X", command[i]);
                            break;
                        }
                    }
                }
                pc.printf("\r\n");

Where "size_command" is the size of the buffer I send first on the other side.

I hope you can understand something :P

María.

25 Jun 2014

Could someone please place the entire code. I'm having problems following this. Thank you

29 Apr 2016

/media/uploads/sour/doudt.png

in this code section before running scanf "j =1" and after scanf function again j=1, can somebody tell me, after taking data from scan why readable()'s output is not zero, while i am sending only one string.

29 Apr 2016

scanf("%s") will read up to the first whitespace character. The transmitted string includes "\r\n" at the end, they both count as whitespace. So you buffer isn't empty because it still contains two bytes, '\r' and '\n'.

16 May 2016

Somebody else may take issue with this but I would suggest you don't try to use scanf on incoming data generally unless you are communicating with an operator and you don't mind the program blocking waiting for input.

I wouldn't recommend scanf for m2m, I think it would be better to pull in characters with getc, assemble them into a string and then you might use sscanf to convert values.

26 May 2016

try lower rate 9600 in place of 19200..

13 Jan 2017

It is often useful to use some more advanced RS232 terminal program to see all received data even if not ASCII readable format. For example http://docklight.de/ or similar one.

Then you can see 0x00 enter or any other special character that user is not aware that is sent since it is not ASCII visible character..