NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Sending a string

July 26, 2010
by ioScream
ioScream's Avatar

I'm having some problems figuring out what I'm doing wrong here. I'm expanding my CPU/GPU temp project where I use the momentary switch to display different information. The problem is when I'm trying to use Python to send those strings it's coming out of sync, and I think it has to do with how I'm receiving the strings with the MCU.

Here the relevant code:

MCU Receiving (I think this is where the problem is):

    fgets(osName, 32, stdin);
    osName[strlen(osName)-1] = '\0';

MCU Displaying:

    fprintf_P(&lcd_stream, PSTR("%s"), &osName);

Python Sending:

        osName = "Windows 7\n"
        serial.write(osName)

I already had 7 integers being sent before with no sync'ing issues. The problem arose when I started to send/receive strings.

Here is some sample code of that happening:

MCU Receive:

    scanf_P(PSTR("%d"), &core0);

MCU Display:

    fprintf_P(&lcd_stream, PSTR("%dc "), core0);

Python Setup/Send (I felt like I needed add n to simulate an enter button - could be right or wrong but it works):

        cpu0 = str(core0) + "\n"
        serial.write(cpu0)
July 26, 2010
by mrobbins
(NerdKits Staff)

mrobbins's Avatar

Hi ioScream,

First of all, your

osName[strlen(osName)-1] = '\0';

is not necessary, because fgets will automatically terminate the string it reads.

Overall, I think the issue might have to do with C strings and pointers. If you remove the .hex file and re-run "make", do you get any messages (warnings) from the compiler?

Since you didn't include your definition of osName itself, I've got to guess. Here's my guess as to what you want to be doing:

// Initialize an array of characters.
// osName itself is a (char *) -- it's a pointer to a char.
// osName is the same as &osName[0]
char osName[32];
// Keep the string in a "safe" state -- start it empty.
osName[0] = '\0';

...

// Read from the serial port.
fgets(osName,32, stdin);

...

// Display to the LCD
fprintf_P(&lcd_stream, PSTR("%s"), osName);

Notice that I did not use the & (address of) operator in either the fgets or fprintf_P calls.

Please give this a try and let me know if it helps! If not, let us know what compiler warnings you get, and what variable definitions you're using.

Mike

July 26, 2010
by ioScream
ioScream's Avatar

Alright. I've tried a few things now in conjunction with your suggestions. I am declaring the strings as char at a length of 32. I didn't show it, because I didn't think to at the time, but your assumption was correct.

 char osName[32]

I didn't give an initial value, though I went ahead and set it to an empty state, as per your suggestion.

I am still having an issue with what appears to be the information coming out of sync.

As far as the line:

 osName[strlen(osName)-1] = '\0';

If I do not include this line, the MCU will display "WhateverString|||" which to the best of my knowledge is a representation of "\n", so I've kept that line. If my python code doesn't include the "\n" when sent the sync issue becomes even worse. In fact, fgets will not stop receiving UNTIL it reaches 32, unless given a terminator character or end-of-line character of some sort. At least this is my experience with it.

The idea with the strings being sent is that I do not know how long they are (I do, but for the sake of being dynamic), their maximum length should be 32. In all actuality the maximum length will be 20, but for now it's sort of irrelevant, as none of them exceed 20 anyway, and I will put in some trap-code to ensure they are no longer than 20 on the python side.

Also, with the .hex file removed I received no errors or warnings. It happily re-created the file and went on about it's business.

July 26, 2010
by ioScream
ioScream's Avatar

Ok. I've gotten everything working.. sort of. But for whatever reason it appears that I'm either getting an extra "\n" somewhere or there is a leading "\n" in this line:

(From Python)

operName = "Windows 7"

That doesn't seem normal. I've try removing some of the trailing "\n" I've added to the other lines that were working fine until I started this addition. Here are the previous working lines combined with my additions which I will comment.

(From Python)

# Combine the values with \n to simulate the enter button
# ORGINAL WORKING
cpu0 = str(core0) + "\n"
cpu1 = str(core1) + "\n"
cpu2 = str(core2) + "\n"
cpu3 = str(core3) + "\n"

gpuS = str(gpu) + "\n"
fanS = str(fan) + "\n"
fanspeedS = str(fanspeed) + "\n"

# ADDITIONS
# Not a very EXACT way of seeing how long it has run
# but for what it's being used for it's probably the easiest
elapsed = (datetime.now() - start)
print "Run Time: ", elapsed, "-- Times out-of-sync:", sync, "\r",

#ADDITIONS
operName = "Windows 7"
tempTime = time.strftime("%I:%M:%S %p", time.localtime())
currentTime = tempTime[:-3] + "\n"
timeRun = str(elapsed) + "\n"

#ORIGINAL WORKING
serial.write(cpu0)
serial.write(cpu1)
serial.write(cpu2)
serial.write(cpu3)
serial.write(gpuS)
serial.write(fanS)
serial.write(fanspeedS)
#ADDITIONS
serial.write(operName)
serial.write(currentTime)
serial.write(timeRun)

The MCU Code APPEARS to be okay, and I left in one of the lines that was previously considered unneeded, because without it the MCU translates "\n" to "|||".

Here are the DECLARATIONS:

// initialize variables
int16_t core0 = 0;
int16_t core1 = 0;
int16_t core2 = 0;
int16_t core3 = 0;
int16_t gpu = 0;
int16_t fanSpeed = 0;
int16_t fanDuty = 0;
int8_t button = 0;
char osName[32];
char currentTime[32];
char timeRun[32];

osName[0] = '\0';
currentTime [0] = '\0';
timeRun[0] = '\0';

Here is the receive side with comments to show previous working and additions:

    #ORIGINAL WORKING
scanf_P(PSTR("%d"), &core0); 
scanf_P(PSTR("%d"), &core1);
scanf_P(PSTR("%d"), &core2);
scanf_P(PSTR("%d"), &core3);
scanf_P(PSTR("%d"), &gpu);
scanf_P(PSTR("%d"), &fanDuty);
scanf_P(PSTR("%d"), &fanSpeed);

    #ADDITIONS
fgets(osName, 32, stdin);
osName[strlen(osName)-1] = '\0';

fgets(currentTime, 32, stdin);
currentTime[strlen(currentTime)-1] = '\0';

fgets(timeRun, 32, stdin);
timeRun[strlen(timeRun)-1] = '\0';

What I see happening is that osName becomes "\n" and after the string mod it becomes "", and currentTime becomes osName + currentTime. So, I'm either getting a leading "\n" for osName from Python, or I have an extra "\n" coming through unexpectedly.

NOTE: You might see some weird naming and variable exchanging in the code. This is just from my troubleshooting.

July 26, 2010
by ioScream
ioScream's Avatar

I have it working by adding another input between the end of the integers, and start of the string receiving code:

    scanf_P(PSTR("%d"), &fanSpeed);

    // Added as a bandaid - Works, but I don't like it.
    scanf_P(PSTR("%d"), &blankLine);

    fgets(osName, 32, stdin);
    osName[strlen(osName)-1] = '\0';
July 26, 2010
by ioScream
ioScream's Avatar

How the integers are formatted:

 core0 - fanduty = xx    (6 of the vars)        //  \n added to Python to simulate
 fanspeed        = xxxx  (the 7th var for ints) //  the press of the enter key

Post a Reply

Please log in to post a reply.

Did you know that you can turn a $20 digital scale into a live weight sensor using our kit with a few extra parts? Learn more...