Send converted DS1820 temperature over PIC16 uart - c

I'm trying to send a converted temperature reading from my DS1820 to my PC using a PIC16F877 uart. I am using MPLABX and the XC8 compiler, which has a build in usart.h, though it's only useful for the PIC18 series, so I'm using usart_pic16.h which has been written to work with the PIC16 series by a third party.
I am successfully collecting the temperature in its hex form from the DS1820 and have converted it to a human readable float, but I can't find a way to forward the float value to the PC via the UART.
The usart_pic16.h library allows for direct sending of chars, strings, lines and ints over the usart using the following methods:-
void USARTWriteChar(char ch);
void USARTWriteString(const char *str);
void USARTWriteLine(const char *str);
void USARTWriteInt(int16_t val, int8_t field_length);
I'm stuck at finding a way to send the float value across the uart using this library, which includes extraction and sending a decimal point.
I did try sending a string like this:-
USARTWriteString( "TempC= %7.3f degrees C \r\n", temp_c );
Where temp_c is the float value of the temp, but it errorred with "too many function arguments" while compiling. Probably obvious to those c gurus out there, which I'm unfortunately not :(
Maybe one way would be to extract each value from the float and sent it as an int, with the exception of the decimal point which could probably be found with an 'if' check of each value, then when the decimal point is found just send it as a char e.g. USARTWriteChar('.');, which does work. Unfortunately I don't know how to extract individual float values or if it's the best way to do it.
I wasn't sure if my code was required to solve this so thought I'd avoid spamming it unless someone asks.
Any help would be great.
Thanks.

The general equivalent would be to include <stdio.h> and do something like the following:
char s[64];
sprintf(s, "TempC= %7.3f degrees C \r\n", temp_c);
USARTWriteString(s);
Although for an embedded platform you may be best to avoid the printf style functions that can use a fair bit of code space on a small microcontroller. Also in the above example it would make sense to break just the floating point conversion into a seperate sprintf and output the rest of the string seperately so the buffer s doesn't have to be so large.
That should get you running for the moment but in the longer term you might want to look at converting the temperature to integer say by multiplying it by 1000 and then decoding the value on the PC, that's assuming eventually you intend to write your own application to communicate with the microcontroller.

Related

float or double value is not getting displayed when used in printf statement in C code

I want to display a value to a precision of 2 decimals in our project.
So I decided to use float as data type for my variable - the basic knowledge which we all obtained when learnt C language.
However, to my surprise after compilation when I executed the binary, I see no print in the place of value of the float variable.
Below is the code snippet used -
float rate_sent = 0, rate_received = 0;
printf("\n Direct printf - %.2f/%.2f", rate_sent, rate_received);
Expected output -
Direct printf - 0.00/0.00
Actual output -
Direct printf - /
I tried using double as my data type. But no difference.
I tried using %g as the format specifier, still no difference.
When I use the code snippet on any online C compilers it works fine, but when I am trying this code snippet in our code base, we don't see it work as expected.
It looks to be basic C stuff but still not able to understand why it is not printing.
The software is simulated to work on x86_64 Linux environment. I am running my application on x86_64 RHEL VM. So I think the machine would support the floating point.
Could this be a limitation with the compiler?
Can you someone identify what could be the problem here?
Edit: However, when I use the %u format specifier, I see some garbage value
Figured out that float/double variables are declared and allocated space by the compiler.
When the same variables are printing under gdb session value gets printed in decimal format.
So it is just the printing issue. I think the printf function is overridden using macro to not process %f format specifier.

Convert Alsa frames to analog values

I'm writing a program in C which should visualize audio. As audio source I use a microphone and the Alsa C Sound library. I take the sound frames from the Alsa library, make some transformations (Fourier analysis and similar), and then visualise them. I almost have a working program besides one exception, it seems I'm converting the Alsa-frames to doubles in a wrong way.
This is how I do it:
unsigned char x=getFirstByte();
signed char y=getSecondByte();
double analog_signal=(y*256+x)/32768.;
Now this code works, but sometimes (relatively often) I get spikes where the value of analog_signal is about 0.99... where it shouldn't be.
So I started printing the values of x and y when such spikes occur.
The output was quite clear: always when such a spike occurred y was equal to 127 and x was some value around 230.
My conversion is still correct in my understanding, but it seems that Alsa treats its values in a different way. So that this special value of 127 in the second byte has to be converted differently, for whatever reason?!
I don't want to believe that my microphone is broken, so could someone who has worked with the Alsa-library, kindly give me some advice on my problem.
I would also be happy with a function of the Alsa-library which does this conversion for me as I haven't found one but maybe overlooked it.

makes pointer from integer without a cast... DS1307, RTC, BCD

I know this question has been asked before. It's all over Google and on this site too, but I can't understand people when they explain it. I have already spent far too many hours trying to understand and I still don't so please try to understand that there's something fundamental I am NOT understanding... here we go.
When programming in C on Proteus, I often get the warning and/or error (in this case warning):
makes pointer from integer without a cast
and I don't get it. Like I said, I've already spent hours looking into it and I get it has to do with types, and/or pointers, blah. Someone please explain it to me like a normal person.
Also, I get this a lot. Could it be possible to get this warning from other types of variables without a cast? A character? How would I go about fixing this problem now, and avoiding it in the future?
Here's the context...
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include "stdlib.h"
#include "USART.h"
#include "I2C.h"
#include "ds1307.h"
void Wait()
{
uint8_t i;
for(i=0;i<20;i++)
_delay_loop_2(0);
}
uint8_t ss,mm,hh,dd,nn,yy,x; // Appropriately labeled variables
uint16_t sec[3],min[3],hr[3],day[3],month[3],year[3],mode[2];
uint16_t secs,mins,hrs,days,months,years,modes;
int main(void)
{
_delay_ms(50);
USART_interrupt_init(); //
USART_send('\r'); // Send carriage return
_delay_ms(100); // Allows for the LCD module to initialize
I2CInit(); // Initialize i2c Bus
DS1307Write(0x07,0x10); // Blink output at 1Hz
while(1)
{
int i=0;
/* SECONDS */
DS1307Read(0x00,&ss); // Read seconds address
/* MINUTES */
DS1307Read(0x01,&mm); // Read minutes address
/* HOURS */
DS1307Read(0x02,&hh); // Read hours address
/* DAY */
DS1307Read(0x04,&dd); // Read hours address
/* MONTH */
DS1307Read(0x05,&nn); // Read hours address
/* YEAR */
DS1307Read(0x06,&yy); // Read hours address
for(i=0;i<5;i++)
{Wait();i++;}
sec[0]=(0b00001111 & ss);
sec[1]=((0b01110000 & ss)>>4);
sec[2]='\0';
itoa(sec[0],secs,10);
USART_putstring(secs); // place string in buffer
and the 2 errors:
../main.c:59: warning: passing argument 2 of 'itoa' makes pointer from integer without a cast
../main.c:62: warning: passing argument 1 of 'USART_putstring' makes pointer from integer without a cast
Your compiler is telling you that the function expects a pointer, but you've passed an integer. So it's going to automatically treat your integer value as an address and use that as the pointer.
For example, itoa expects a pointer to a memory location for its second parameter - that's where it stores the resulting string that it builds from the integer you pass it. But you've passed secs for that - a uint16_t. The compiler is warning you that whatever value is in that integer is going to be used as the address where itoa puts its resulting string.
This kind of thing would cause a segfault on most targets, but I'm not familiar with Proteus.
Anyway, as an example, to fix the itoa warning, use something like the following:
char secs[3];
...
itoa(sec[0], secs, 10);
Hope that helps.
So here's a completely different answer to the question, at a much higher level, and to make the point clear, we're going to take a step back from C programming and talk about building houses. We're going to give instructions to the people building the house, but we're going to imagine we have some rigid, codified way of doing it, sort of like function calls.
Suppose it's time to paint the outside of the house. Suppose there's a "function" paint_the_house() that looks like this:
paint_the_house(char *main_color, char *trim_color);
You decide you want white trim on a yellow house, so you "call"
paint_the_house("white", "yellow");
and the painters dutifully paint the house white with yellow trim. Whoops! You made a mistake, and nobody caught it, and now the house is the wrong color.
Suppose there's another function, finish_the_floors() that looks like this:
finish_the_floors(char *floor_material, char *color)
The floor_material argument is supposed to be a string like "hardwood", "carpet", "linoleum", or "tile". You decide you want red tile floors in your house, so you call
finish_the_floors("red", "tile");
But the guy who installs the floors comes back and says, "Listen, buddy, 'red' is not a floor material, and 'tile' is not a color, so do you want to try that again?" This time, someone caught your mistake.
Finally, suppose there's a function
furnish_the_bathroom(char *bath_or_shower, int number_of_sinks)
where bath_or_shower is supposed to be the string "bathtub" or "shower", and the second argument is supposed to be the number of sinks you want. You decide you want two sinks and a bathtub and, continuing your careless ways, you call:
furnish_the_bathroom(2, "bathtub");
This time, your bogus "function call" doesn't even make it to the guy who's going to build the bathtub. The architect's dim-bulb nephew, who his brother conned him into hiring for the summer, who can't even tell the difference between a toaster oven and a two-by-four, he's been put in charge of relaying instructions from you to the laborers, and even he can see that there's something wrong. "Um, wait a minute," he whines. "I thought the first thing was supposed to be a string, and the second thing was supposed to be a number?"
And now we can go back to your question, because that's basically what's going on here. When you call a function, you have to pass the right arguments in the right order (just like your instructions to the builders). The compiler can't catch all your mistakes, but it can at least notice that you're doing something impossibly wrong, like passing an int where you're supposed to pass a pointer.
It means that the compiler implicitly casts it for you, however, it notifies you it did by emitting a warning so you know that.
Here's an example using numbers:
float f = 1.0;
int i = f;
Depending the platform, language and compiler settings a couple of scenarios are possible:
compiler implicitly casts float to int without a warning (bad)
idem but issues a warning (better)
compiler settings changed to treat warnings as errors (safe, security critical etc...)
Warnings are a good hint on possible bugs or errors and it's generally wise to fix them instead of suppressing or ignoring them.
In your specific case, I've been looking for an USART_pustring and the first I've found was this one :
void USART_putstring(char* StringPtr)
No need to look further, passing an int to a function expecting char* (if this is the case), 'might' produce an unexpected result.
Solution
Read the documentation of USART_putstring and ensure you 'transform' your input data to the correct type it accepts, the warning will vanish by itself.
EDIT:
+1 for Aenimated1
Ensure that you understand what are the differences between 'integer' and 'pointer to integer' too, he explained that rather well :)
Integers are for counting. Pointers are an abstract indication of where a variable may be found.
To keep things clear in your head it is a good idea to not mix up the two, even if you are on a system where the concrete implementation of a pointer is the same as the implementation of an integer.
It is an error to convert integer to pointer or vice versa, unless you write a cast to say "I know what I'm doing here".
Unfortunately some compilers will spit out "warning" and then generate a bogus binary. If possible, see if you can use compiler switches that will make the compiler say "error" for this case.
If you see this error it usually means that you supplied an integer where the compiler was expecting you to supply a pointer.
In your code, you do this with itoa(sec[0],secs,10); is a problem. The itoa function signature is:
char * itoa ( int value, char * str, int base );
You supplied secs, which is a uint16_t (a 16-bit integer), for the parameter char * str. This is an error because it expects the address of an object, but you supplied a number.
To fix this you need to stop supplying integers for parameters that are pointers.
For assistance with how to convert the output of DS1307Read to a display string, post a question asking about that specifically.

Reading negative values of accelerometer

Im interfacing accelerometer with TivaC and displaying the RAW data on UART.
void main(){
signed int accelerationX;
accelerationX = getAcceleration_X();
if (accelerationX>=0){
UART_OutString("\r\nX Axl: ");
UART_OutUDec((unsigned short) accelerationX);
} else {
UART_OutString("\r\nX Axl: - ");
UART_OutUDec((unsigned short) (accelerationX*-1));
}
}
Such type of code I got on some forum.
I'm not understanding why " accelerationX*-1 " is done when acceleration is negative.
accelerationX is a signed integer, but it would seem that UART_OutUDec expects an unsigned integer. Therefore they have to print a minus sign followed by the absolute value of accelerationX (sign removed).
It's because the number is being sent as an unsigned short instead of a signed quantity. It would be helpful to see what UART_OutUDec is doing, but it also doesn't really matter because a UART will simply send whatever is dropped in its data register. As an aside, UART_OutUDec is most likely translating the unsigned short into ASCII. The receiver is unlikely to understand the value was supposed to be negative, so the minus sign is transmitted with what's effectively the absolute value of the acceleration.
Something to consider is that not all receivers are equal. A lot of people assume the device on the other end is a computer or something that understands ASCII, but that's not always the case. I've worked on embedded systems that transmitted ASCII characters mixed with non-ASCII characters, which is confusing and hard to maintain, but these systems exist. That's almost certainly not applicable to your situation simply because it's rare, but, in the future, if you give additional details about the receiver it will help clarify how the data should be formatted and transmitted.

Any function instead of sprintf() in C? code size is too big after compile

I am working on developing an embedded system (Cortex M3). For sending some data from the device to the serial port (to show on a PC screen), I use some own functions using putchar() method.
When I want to send integer or float, I use sprintf() in order to convert them to string of characters and sending them to the serial port.
Now, them problem is that I am using Keil uVision IDE and it is limited version with max 32 KB.
Whenever I call sprintf() in different functions, I don't know why the size of the code after compile increased too much.
I have surpassed 32 KB now and I wonder I have to change some of my functions and use something else instead of sprintf!
Any clue?
Two potential offerings (neither of which I have used myself - my compiler vendors usually supply a stripped down printf for embedded use):
http://eprintf.sourceforge.net/ - [Sep 2017: unfortunately, seems to have gone away, but source code still here: https://sourceforge.net/projects/eprintf/files/ ]
http://www.sparetimelabs.com/tinyprintf/index.html - 2 files, about 1.4KB code. Option to enable 'longs' (means more code size). Supports leading zeros and field widths. No floating point support.
If you want it to be efficient, the best way is probably to code it yourself, or find some already written code for it on the net. Int to string conversion is however very simple, every programmer can write that in less than 30 minutes. Float to string conversion is a bit more intricate and depends on the floating point format used.
For convenience, here is a simple int-to-string algorithm for use in microcontroller applications:
void get_dec_str (uint8_t* str, size_t len, uint32_t val)
{
uint8_t i;
for(i=1; i<=len; i++)
{
str[len-i] = (uint8_t) ((val % 10UL) + '0');
val/=10;
}
str[i-1] = '\0';
}
You can try itoa() or ftoa() and implement these as your requirement.I mean as they convert those to characters just inside the definition itself use putchar() to print directly.
This is should work , I think.

Resources