char x 0xffff类型的0x84怎么写

floating point - Unexpected float behaviour in C with AVR atmega8 - Stack Overflow
to customize your list.
Join the Stack Overflow Community
Stack Overflow is a community of 6.6 million programmers, just like you, helping each other.
J it only takes a minute:
I've been trying to figure out why I cannot get a sensible value from multiplying an unsigned int with a float value.
Doing something like
works as expected but multiplying a float with a uint from memory creates mad values. I have a function that reads an ADC and returns an uin16_t. With this value I am printing it to a 4-digit led-display, which is working fine.
Multiplying the same value with 1.0 returns something different entirely (it's too large for my display so I don't really know what it is).
My code is below but the area of contention is at the bottom in main(). Any help would be great. Thanks
#include &avr/io.h&
#include &util/delay.h&
#include &avr/interrupt.h&
#include &stdint.h&
#define BAUD 9600
#include &util/setbaud.h&
#define DISP_BRIGHT_CMD
#define DISP_RESET
#define ADC_AVG
volatile uint8_t
volatile uint16_
ISR(ADC_vect)
lo = ADCL;
hi = ADCH;
MCUCR &= ~_BV(SE); //Clear enable sleep
void initSerial(void)
// set baud rate
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
// set frame format
UCSR0C |= (0x3 && UCSZ00); // 8n1
// set enable tx/rx
UCSR0B = _BV(RXEN0) | _BV(TXEN0);
void initADC(void)
// AVCC and ADC0
= _BV(REFS0);
// Enable, div128, + 1st setup
|= _BV(ADEN)|_BV(ADSC)|_BV(ADPS2)|_BV(ADPS1)|_BV(ADPS0)|_BV(ADIE);
uint16_t readADC(void)
uint16_t average=0;
// Start Conversion
ADCSRA |= _BV(ADSC);
for (char i=0;i&ADC_AVG;i++) {
|= _BV(SE);
|= _BV(ADSC);
__asm volatile("sleep");
&= ~_BV(SE);
= (hi&&8);
average +=
average /= ADC_AVG;
void sendByte(char val)
while (! (UCSR0A & (1&&UDRE0)) ); //wait until tx is complete
* Convert voltage to temperature based on a negative coefficient for MAX6613
uint16_t analogToTemp(uint16_t val)
= 5 * (val/1023.0);
= (1.8455 - (5.0*(val/1023.0)))/0.01123;
= (1.8455 - (5.0*(val/1023.0)))*89;
//temp = val * M_PI;
= 5 * ( val/1024);
= (2 - v) * 89;
void initDisplay()
sendByte(DISP_RESET);
sendByte(DISP_BRIGHT_CMD);
sendByte(0);
void serialSegments(uint16_t val)
// 4 digit display
sendByte(val / 1000);
sendByte((val / 100) % 10);
sendByte((val / 10) % 10);
sendByte(val % 10);
int main(void)
uint16_t calc=0,sense=0;
|= _BV(DDB5);
|= _BV(PORTB5);
initSerial();
initADC();
initDisplay();
|= (1 && SM0); // Setting sleep mode to "ADC Noise Reduction"
|= (1 && SE);
// Sleep enable
^= _BV(PORTB5);
if (calc&=9999){ // I can't see the real value. Max val on display is 9999
//if (sense&=330){
PORTB |= _BV(PORTB5);
PORTB &= ~_BV(PORTB5);
= readADC();
= sense*1.0;
// refuses to calculate properly
= analogToTemp(sense);
// a bunch of zeroes
//calc = ;
serialSegments(calc);
_delay_ms(500);
serialSegments(sense);
_delay_ms(500);
# AVR-GCC Makefile
PROJECT=Temp_Display
SOURCES=main.c
CC=avr-gcc
OBJCOPY=avr-objcopy
MMCU=atmega328p
OPTIMISATION=2
PORT=/dev/ttyUSB0
CFLAGS=-mmcu=${MMCU} -std=gnu99 -Wall -O${OPTIMISATION}
-DF_CPU=${OSC_HZ} -lm -lc
${PROJECT}.hex: ${PROJECT}.out
${OBJCOPY} -j .text -O ihex ${PROJECT}.out ${PROJECT}.hex
avr-size ${PROJECT}.out
$(PROJECT).out: $(SOURCES)
${CC} ${CFLAGS} -I./ -o ${PROJECT}.out ${SOURCES}
program: ${PROJECT}.hex
stty -F ${PORT} hupcl
avrdude -V -F -c arduino -p m168 -b 57600 -P ${PORT} -U flash:w:${PROJECT}.hex
rm -f ${PROJECT}.out
rm -f ${PROJECT}.hex
OK, i've simplified the code somewhat
#include &avr/io.h&
#include &util/delay.h&
#include &stdint.h&
#define BAUD 9600
#include &util/setbaud.h&
#define DISP_BRIGHT_CMD
#define DISP_RESET
void initSerial(void)
// set baud rate
UBRR0H = UBRRH_VALUE;
UBRR0L = UBRRL_VALUE;
// set frame format
UCSR0C |= (0x3 && UCSZ00); // 8n1
// set enable tx/rx
UCSR0B = _BV(TXEN0);
void sendByte(char val)
while (! (UCSR0A & (1&&UDRE0)) ); //wait until tx is complete
void initDisplay()
sendByte(DISP_RESET);
sendByte(DISP_BRIGHT_CMD);
sendByte(0);
void serialSegments(uint16_t val) {
// 4 digit display
sendByte(val / 1000);
sendByte((val / 100) % 10);
sendByte((val / 10) % 10);
sendByte(val % 10);
int main(void)
uint16_t i=0,
|= _BV(DDB5);
initSerial();
initDisplay();
val = (uint16_t)(i++ * 1.5);
serialSegments(i);
_delay_ms(500);
serialSegments(val);
_delay_ms(500);
if (val & 9999){
PORTB |= _BV(PORTB5);
PORTB &= ~_BV(PORTB5);
1,96722237
Unsuffixed floating point constant are of type double not float.
Use f suffix to have a float literal, e.g., 0.1f
This can make a huge overhead as MCUs like atmega8 don't have a floating point unit and all floating point operations have to be implemented in firmware by the implementation.
With small devices like atmega8 one usually try to avoid using float operations as without a FPU they are very expensive in CPU cycles.
Now there is no reason an implementation would no correctly translate an expression like:
calc = sense * 1.0;
when calc and sense are of uint16_t type.
109k11156245
Not exactly your code, maybe close enough, maybe not.
First off when I display the output and compare these to lines:
val = (unsigned int)(i++ * 1.5);
val = i+(i&&1); i++;
the result is the same.
Disassembling shows a few things as well.
First off avr-gcc
avr-gcc --version
avr-gcc (GCC) 4.3.4
Copyright (C) 2008 Free Software Foundation, Inc.
T see the source for copying conditions.
There is NO
not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
uses floats not doubles, so the comments about 1.5F vs 1.5 are quite valid in general but not relevant here.
Second it is producing floating point values, single precision, and is doing floating point math, the compiler did not take a shortcut there, it converts to float, does the multiply then converts back.
Using my hex display routine and your decimal display routine (modified to output on a serial terminal), here again it produces the same output, the floating point math does not appear to be the problem.
I started this task to see if the floating point performance was a killer, and it is, but the timing changes depending on how I test it.
it took as much as 157 times longer for the code with the floating point compared to fixed point.
If I leave in the call to serialSegments(), but have that call a dummy routine instead of the serial port it is 3 times slower for the float.
Also I built two different ways and pulled in a libc/m which used a different set of floating point routines, the floating point routines chosen by the C compiler were 7 times slower than the libc/libm.a sitting in the /usr/lib64/avr/lib/ directory.
Once you add the waiting on serial port and other delays you may not notice the difference in timing so this experiment while demonstrating that the float is quite painful, is probably not the smoking gun even if your code is timing sensitive, we are talking a few milliseconds.
In addition to the code below I tried this as well:
for(i=0;i&9999;i++)
vala = (unsigned int)(i * 1.5);
valb = i+(i>>1); i++;
if(vala!=valb)
hexstring16(i);
hexstring16(vala);
hexstring16(valb);
I limited to 9999 because serialSegments() only chops up decimals from 0 to 9999.
Now your loop goes beyond that to 65535, but you would see that cause problems without the float though, right?
#define UCSRA (*((volatile unsigned char *)(0xC0)))
#define UDR
(*((volatile unsigned char *)(0xC6)))
#define TCCR0A
(*((volatile unsigned char *)(0x44)))
#define TCCR0B
(*((volatile unsigned char *)(0x45)))
#define TCNT0
(*((volatile unsigned char *)(0x46)))
#define TCCR1A
(*((volatile unsigned char *)(0x80)))
#define TCCR1B
(*((volatile unsigned char *)(0x81)))
#define TCNT1L
(*((volatile unsigned char *)(0x84)))
#define TCNT1H
(*((volatile unsigned char *)(0x85)))
void dummy ( unsigned int );
void uart_putc ( unsigned char c )
while(1) if(UCSRA&0x20)
void hexstring16 ( unsigned int d )
rc=(d&&rb)&0xF;
if(rc&9) rc+=0x37; else rc+=0x30;
uart_putc(rc);
uart_putc(0x0D);
uart_putc(0x0A);
#ifdef SEGMENTS
void sendByte(char val)
uart_putc(0x30+val);
void serialSegments(unsigned int val) {
// 4 digit display
dummy(val / 1000);
dummy((val / 100) % 10);
dummy((val / 10) % 10);
dummy(val % 10);
//void serialSegments(unsigned int val) {
//// 4 digit display
//sendByte(val / 1000);
//sendByte((val / 100) % 10);
//sendByte((val / 10) % 10);
//sendByte(val % 10);
//uart_putc(0x0D);
//uart_putc(0x0A);
void serialSegments(unsigned int val)
dummy(val);
//void serialSegments(unsigned int val)
//hexstring(val);
int main(void)
unsigned int i,
volatile unsigned int xal,xbl,
volatile unsigned int xah,xbh,
hexstring16(0x1234);
TCCR1A = 0x00;
TCCR1B = 0x05;
xal=TCNT1L;
xah=TCNT1H;
for(i=0;i&9999;)
val = (unsigned int)(i++ * 1.5);
//serialSegments(val);
//hexstring16(val);
dummy(val);
xbl=TCNT1L;
xbh=TCNT1H;
for(i=0;i&9999;)
val = i+(i&&1); i++;
//serialSegments(val);
//hexstring16(val);
dummy(val);
xcl=TCNT1L;
xch=TCNT1H;
xal|=xah&&8;
xbl|=xbh&&8;
xcl|=xch&&8;
hexstring16(xal);
hexstring16(xbl);
hexstring16(xcl);
hexstring16(xbl-xal);
hexstring16(xcl-xbl);
.globl dummy
.globl _start
rjmp reset
rcall main
.globl dummy
all : avrone.hex avrtwo.hex
avrone.hex : avr.c dummy.s
avr-as dummy.s -o dummy.o
avr-gcc avr.c dummy.o -o avrone.elf -mmcu=atmega328p -std=gnu99 -Wall -O2 -DSEGMENTS
avr-objdump -D avrone.elf & avrone.list
avr-objcopy avrone.elf -O ihex avrone.hex
vrtwo.hex : avr.c vectors.s
avr-as vectors.s -o vectors.o
avr-as dummy.s -o dummy.o
avr-gcc -c avr.c -o avrtwo.o -mmcu=atmega328p -std=gnu99 -Wall -O2 -nostartfiles
avr-ld vectors.o avrtwo.o -o avrtwo.elf
libc.a libm.a
avr-objdump -D avrtwo.elf & avrtwo.list
avr-objcopy avrtwo.elf -O ihex avrtwo.hex
rm -f *.hex
rm -f *.elf
This was all run on an arduino pro mini (atmega328p).
38.4k548101
Multiplication
works because it is optimized and precalculated by the compiler, so it translates to 6554.
calc and sense variables are of type uint16_t, and your function analogToTemp() is of that same type and returns that type too. Your runtime calculation inside this function is with uint16_t. It should be done with float, and then truncated to just integer part and casted to the uint16_t result of the function.
Your Answer
Sign up or
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Post as a guest
By posting your answer, you agree to the
Not the answer you're looking for?
Browse other questions tagged
rev .24932
Stack Overflow works best with JavaScript enabled君,已阅读到文档的结尾了呢~~
课程设计实验报告,c课程设计实验报告,课程设计报告,课程设计,厦门理工学院,课程设计实验报告模板,网页设计实验报告,输入法 搜狗,课程设计实验报告格式,uml课程设计报告
扫扫二维码,随身浏览文档
手机或平板扫扫即可继续访问
课程设计实验报告
举报该文档为侵权文档。
举报该文档含有违规或不良信息。
反馈该文档无法正常浏览。
举报该文档为重复文档。
推荐理由:
将文档分享至:
分享完整地址
文档地址:
粘贴到BBS或博客
flash地址:
支持嵌入FLASH地址的网站使用
html代码:
&embed src='/DocinViewer--144.swf' width='100%' height='600' type=application/x-shockwave-flash ALLOWFULLSCREEN='true' ALLOWSCRIPTACCESS='always'&&/embed&
450px*300px480px*400px650px*490px
支持嵌入HTML代码的网站使用
您的内容已经提交成功
您所提交的内容需要审核后才能发布,请您等待!
3秒自动关闭窗口2011年6月 移动平台大版内专家分月排行榜第二
2012年8月 C/C++大版内专家分月排行榜第三2012年7月 C/C++大版内专家分月排行榜第三
2012年8月 C/C++大版内专家分月排行榜第三2012年7月 C/C++大版内专家分月排行榜第三
2010年12月 C/C++大版内专家分月排行榜第三
2013年3月 总版技术专家分月排行榜第三
2014年5月 移动开发大版内专家分月排行榜第一2014年4月 移动开发大版内专家分月排行榜第一
本帖子已过去太久远了,不再提供回复功能。1305人阅读
首先运行环境是51单片机+KEIL C
最近写一个16进制数据转换成ASCII形式的函数,多次运行发现,当16进制数据高4位大于8时,转换就
最开始出错的程序如下:
void hex2ascii(char hex, char ascii[])
char i = 0;
ascii[0] = (hex & 0xf0) && 4;
ascii[1] = hex & 0x0f;
sendNChar(ascii, 2);
for (i=0; i&=1; i++)
if (ascii[i] &= 0xa)
ascii[i] = ascii[i] - 0xa + 'A';
ascii[i] = ascii[i] + '0';
sendNChar(ascii, 2);
在KEIL C51环境下,输入0xe3,输出fe 03 2e 33。
在VC环境下,输出输入0xe3,输出e 3 45 33
后来多次修改尝试,并分析原因。终于发现原因:hex是char类型,是有符号型,移位左边补符号位1。
故得fe,ascii[0]=0xfe是负数,小于0xa,故结果=0xfe+'0'=0x2e(溢出后结果)。
但不对,VC上运行正常呀,再分析
在VC上,int型占32位
按照C语言的自动类型转换原理
hex & 0xf0,分别是char和const int类型,转换成int型0xffffffe3 & 0x = 0x
看来是,VC上运算移位时左边填充0,KEIL C51上运算移位时左边填充的是1.
int debug = 0;
debug = hex & 0xf0;
sendNChar(&debug, 2);
KEIL C51下输出ff e0
VC下输出e0
找到这里知道程序错误的起因了,但hex & 0xf0处理的原因还不了解。
先断续调我的51程序。
这种地方 以后都要用unsigned char类型了,免得不必要的麻烦!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:43983次
排名:千里之外
原创:11篇
评论:11条
(1)(2)(1)(2)(2)(1)(1)(3)}

我要回帖

更多关于 date类型参数怎么写 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信