Не совсем ваш код, может быть, достаточно близко, а может и нет.
Во-первых, когда я отображаю вывод и сравниваю их со строками:
val = (unsigned int)(i++ * 1.5);
...
val = i+(i>>1); i++;
результат тот же. Разборка также показывает несколько вещей. Сначала от avr-gcc
avr-gcc --version
avr-gcc (GCC) 4.3.4
Copyright (C) 2008 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
использует числа с плавающей запятой, а не двойные, поэтому комментарии о 1.5F против 1.5 в целом вполне допустимы, но здесь они не актуальны. Во-вторых, он генерирует значения с плавающей запятой с одинарной точностью и выполняет вычисления с плавающей запятой, компилятор там не использует ярлык, он конвертирует в число с плавающей запятой, умножает, а затем конвертирует обратно.
Используя мою процедуру шестнадцатеричного отображения и вашу подпрограмму десятичного отображения (измененную для вывода на последовательный терминал), здесь снова получается тот же вывод, математика с плавающей запятой, похоже, не является проблемой.
Я запустил эту задачу, чтобы посмотреть, была ли производительность с плавающей запятой убийственной, и это так, но время меняется в зависимости от того, как я ее тестировал. Код с плавающей точкой занимал в 157 раз больше времени по сравнению с фиксированной точкой. Если я оставлю в вызове serialSegments (), но при этом вызову фиктивной подпрограммы вместо последовательного порта, это будет в 3 раза медленнее для float. Также я построил два разных способа и использовал libc / m, который использовал другой набор подпрограмм с плавающей запятой, подпрограммы с плавающей запятой, выбранные компилятором C, были в 7 раз медленнее, чем libc / libm.a, находящаяся в / usr / lib64 / avr / lib / каталог. Как только вы добавите ожидание на последовательном порту и другие задержки, вы можете не заметить разницу во времени, поэтому этот эксперимент, демонстрирующий, что поплавок довольно болезненный, вероятно, не является курящим пистолетом, даже если ваш код чувствителен ко времени, мы говорим о нескольких миллисекунды.
В дополнение к приведенному ниже коду я тоже попробовал:
для (я = 0; я <9999; я ++)
{
vala = (без знака int) (i * 1,5);
valb = i + (i >> 1); я ++;
если (Вала! = valb)
{
hexstring16 (я);
hexstring16 (Вал);
hexstring16 (valb);
}
}
Без сбоев. Я ограничился 9999, потому что serialSegments () только сокращает десятичные дроби от 0 до 9999. Теперь ваш цикл выходит за пределы этого значения до 65535, но вы увидите, что это вызывает проблемы без числа с плавающей точкой, верно?
avr.c
#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) break;
UDR=c;
}
void hexstring16 ( unsigned int d )
{
unsigned int rb;
unsigned int rc;
rb=16;
while(1)
{
rb-=4;
rc=(d>>rb)&0xF;
if(rc>9) rc+=0x37; else rc+=0x30;
uart_putc(rc);
if(rb==0) break;
}
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);
//}
#else
void serialSegments(unsigned int val)
{
dummy(val);
}
//void serialSegments(unsigned int val)
//{
//hexstring(val);
//}
#endif
int main(void)
{
unsigned int i,val;
volatile unsigned int xal,xbl,xcl;
volatile unsigned int xah,xbh,xch;
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);
return 0;
}
dummy.s
.globl dummy
dummy:
ret
vectors.s
.globl _start
_start:
rjmp reset
reset:
rcall main
1:
rjmp 1b
.globl dummy
dummy:
ret
Makefile
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
a 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
clean :
rm -f *.hex
rm -f *.elf
Все это работало на Arduino Pro Mini (Atmega328P).