NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.
Microcontroller Programming » sprintf won't convert to a float.
July 13, 2011 by Robotnik |
I am making my own functions for displaying things with a MCU and I am almost done. There is just one problem, when I use sprintf to convert floats to a char array and display it, all it displays is '?'. Does anyone know what im doing wrong? this is my code... char buffer[20]; float number = 3.14; sprintf(buffer,"%5.2f",number); print_string(buffer); // I wrote this function, and tested it. It works. |
---|---|
July 13, 2011 by Noter |
The easiest thing to do is use sprintf_P and PSTR( ) -
|
July 15, 2011 by Robotnik |
What header are sprintf_P() and PSTR() in ? Because I am trying to right my own functions for displaying data to the lcd, just to learn how it works. So I don't want to include the nerdkit's lcd.h or anything like that, because then I might as well use their display functions. |
July 15, 2011 by Noter |
|
July 16, 2011 by BobaMosfet |
Instead of assuming it is sprintf() - which your implementation is correct, why don't you output what the value of sprintf() is prior to entering your function (which is likely where the problem is). Here's my version and it works. Width is 5 chars, default left-padded with a space, per the C standard spec.
BM |
July 16, 2011 by Noter |
BM, this is the result of compiling your code -
|
July 16, 2011 by Robotnik |
I tried using sprintf_P and PSTR() and it did the same thing. I have also tried printing the chars one at time, like BM suggested, and that gave me the same result, a '?' right adjusted in the field. I have tested sprintf with integers and it works fine. I have also tried using sprintf() on my computer and it works as expected. :/ this is my main function...
|
July 16, 2011 by Noter |
We'll have to see your lcd.h and any other source to be of more help. Could be a problem in print_string(). If you want to post it I'll load it and see if I get the same results and go from there. It would be a good idea to name your module a little different from the nerdkits one then maybe you could use them both at the same time and see if the same ? for array is displayed with each. |
July 16, 2011 by Robotnik |
Okay, there are 3 functions, lcd_init(), print_char(), and print_string(). I have the lcd wired up like this... pin 1 to ground, pin 2 to +5, pin 3 to contrast resistor, pin 4 to PB3, pin 5 to PB4, pin 6 to PB5, pin 11 to PC2, pin 12 to PC3, pin 13 to PC4, and pin 14 to PC5.
|
July 16, 2011 by Noter |
That was a little more involved than I expected but I have it going and I get "14" on the display with a blinking cursor so the 1st couple of characters "3." are not showing up. I think you are missing some steps and delays in the lcd initalization routine. Look at the nerdkit lcd.c lcd_init() and you'll see what I mean. You can also find the 4 bit initalization sequence in the HD44780 datasheet (pp 46 in my copy). I'm running on a 328p with a 18.432Mhz crystal so that may be why I don't see exactly the same "?" as you do? Or maybe a wire is crossed? |
July 16, 2011 by Noter |
BTW - are you really running your mcu at 1Mhz? It's important to have the F_CPU match the actual frequency of your mcu clock so delays are accurate. |
July 17, 2011 by Noter |
I inserted initalization commands like in the nerdkit lcd_init() and still didn't work. So then I removed that code and changed the delay from 15 to 1000 and it works on power up but not on reset. So, the sprintf is working fine and the issue is one of timing. It's probably a good idea to follow the initalization sequence even though the lcd might work without it. Then use the same delays as the nerdkit guys do in their lcd subroutines and you will be on your way. Another good practice is to use the ready/busy indicator from the display instead of just waiting a while before sending another command or data nibble/byte. After the display is initialized you can query and wait pending the busy flag value instead of relying on timeouts. Maybe do that after you get it working with timeouts. |
July 17, 2011 by Robotnik |
This is strange, I have tried printing all of the following and they work for me...
The only thing that doesn't work is this...
Which pin is the busy flag read from? That definitely sounds like a better way of doing things. And I am also going too use the initialization sequence specified on the data sheet. As soon as I have time to test it, I will post back my results. |
July 17, 2011 by BobaMosfet |
Noter, avrTest.c:37: warning: format '%5.2f' expects type 'double', but argument 3 has type 'float' 'f' used to mean float, not double. Coercion can fix that. avrTest.c:39: warning: implicit declaration of function 'strlen' avrTest.c:39: warning: incompatible implicit declaration of built-in function 'strlen' strlen used to be part of stdio.h, but may have moved to strings.h. I couldn't remember. avrTest.c:42: warning: control reaches end of non-void function Obviously because main() is expected to return non-void value, but I didn't bother with that (wasn't germain to the example). The code I wrote was more for an example of how sprintf() can be used- what he did wasn't wrong. And the fact that it his result is right-aligned is also correct. I'm wondering if he's getting the result he's getting because 'double' might be too big for the MCU.... just a thought. BM |
July 17, 2011 by Rick_S |
Read the HD44780 datasheet. The read status isn't just read from a pin, you have to change the mode of the display to read mode by changing the R/W line and then you read the from the data lines. Which means you have to change your I/O from output to input for the read. Unless timing is critical, it is much simpler programatically to just wait x# of milliseconds. Most libraries you find will do this. It also saves pins as you don't have to connect R/W to the micro-controller, you just connect it straight to ground since you never need to toggle it into read mode. If you search the forum, you will also find a library I wrote based off the NK library for 8 bit interfacing through an I2C port. You could look at my timings there and where they are used. Rick |
July 17, 2011 by Noter |
Signal timing issues do cause strange results and are sometimes hard to figure out. Did you try 1000 us instead of 15us for your bus time and did it work? You must become very familiar with the HD44780 datasheet to be successful programming any of the common lcd character displays. 8-bit is a little easier to program than 4-bit but unless you want to use even more pins 4-bit is the way to go. Using the ready/busy flag will only require 1 more mcu pin for read/write control. It is a little tricky to implement but works very well. Since you are doing this to learn programming the display, I recommend you get the timeout version going first then move on to the busy flag version. Also study the nerdkits 4-bit version along with the datasheet and you'll make better progress. |
July 17, 2011 by Noter |
Thanks BM. When you said in your 1st post that it works and then didn't I just wondered if I was missing something about it. |
July 17, 2011 by Robotnik |
Okay, I redid my lcd_init() function, and I still have the same problem. The thing that drives me crasy is, the following code works for me...
But when i use sprintf() to convert a double to a char array like this, it doesn't work...
Correct me if i am wrong, but shouldn't buffer contain the same charactors as array from the 1st prgm? |
July 17, 2011 by Noter |
Did you try the 1000 for your delay? Maybe you are linking with the wrong library. Here's the lib line from my makefile -
|
July 18, 2011 by Robotnik |
I just tried it with 1000 and 1000000 microsecond delays and both displayed the same right adjusted '?'. kinda cool to see the cursor move slowly across the screen though... :/ I might be linking it wrong, I don't know how to make makefiles so I have just been modifying a blink_led makefile. I would get warnings when it compiled though like "sprintf() implicit declaration" or something like that wouldn't I? |
July 18, 2011 by Noter |
Post your makefile and I'll use it and see if I get the '?'. |
July 18, 2011 by Robotnik |
Okay, here it is...
I'm using a usb to serial programmer though, so it probably won't work with the nerdkit one... |
July 18, 2011 by Noter |
Append this to the end of your CFLAGS and give it a go.
|
July 18, 2011 by Robotnik |
YAY!!! that fixed it. Thanks for your help, Noter, I appreciate it. |
July 18, 2011 by Noter |
Whew! I was starting to think you were going to have to buy a windows box to get it working - LOL - just kidding ;-) |
July 18, 2011 by Robotnik |
I actually do have a windows partition, but it is strictly for playing games. lol |
July 19, 2011 by Robotnik |
Okay, so I understand how make files work now, but I don't know the cmds for avr-gcc, does anyone know a good place to learn them? |
July 19, 2011 by Noter |
It's in your installation directory somewhere. My win-avr is installed on drive E and this is the documentation -
|
July 19, 2011 by BobaMosfet |
Noter, I had compiled the program and run it in a console on a PC- my concern was the syntax around sprintf()-- because the op's implementation looked correct I wanted to prove it. It compiled and worked without error or warning. Sorry I wasn't more clear. BM |
Please log in to post a reply.
Did you know that first-order systems have a exponentially decaying response to step inputs? Learn more...
|