LusoRobótica - Robótica em Português

Sistemas específicos => Arduino / AVR => Tópico iniciado por: metRo_ em 21 de Novembro de 2009, 19:48

Título: [AVR-GCC] Divisão Atmega8
Enviado por: metRo_ em 21 de Novembro de 2009, 19:48
Olá,
Eu preciso de imprimir pela porta série um uint8_t em hexadecimal.
Imprimir o valor hexadecimal não é o problema mas sim a conversão de decimal para hexadecimal.
A rotima que quero implementar faz o seguinte:
Para o numero 53 em decimal:

   1 - 53/16 = 3,3125
O resultado da divisão é 3 e este é o valor da esquerda do hexadecimal.
   2 - 0.3125*16 = 5

O resultado em hexadecimal para 53 é 35.
a minha duvida é onde vou buscar a parte fraccionaria, os 0,3125.

Eu sei que a função div() tem mas como accesso aos valores? http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g7486ea9a8a90ac6b93bed37d08ebbd9e (http://www.nongnu.org/avr-libc/user-manual/group__avr__stdlib.html#g7486ea9a8a90ac6b93bed37d08ebbd9e)

Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: metRo_ em 21 de Novembro de 2009, 20:24
Eu estava a complicar um bocadinho em cima, bastava-me ter acesso ao resto.
Parece que é só isto:

Código: [Seleccione]
int x=53;
int quot;   // The quotient
    int rem;    // The remainder
int y=16;
div_t temp;
temp = div( x, y );
int a = temp.quot;
int b = temp.rem;
Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: Njay em 21 de Novembro de 2009, 23:35
É muito fácil converter de decimal para hexa... dividir por 16 é o mesmo que shiftar 4 bits para a direita (no sentido do bit menos significativo) e o resto da divisão são os 4 bits que "deitamos fora" com o shift. Pode usar-se uma tabela ou uns ifs para converter para ASCII.
Com uma tabela seria assim:

Código: [Seleccione]
int  x = 53;
char  TabelaConv[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
uart_send(TabelaConv[(x >> 4) & 0x0F]);
uart_send(TabelaConv[x & 0x0F]);

Com ifs seria assim:

Código: [Seleccione]
#define DecDigitToHex(digit)  ( (digit) < 10? '0' + (digit) : 'a' + (digit) - 10 )
int  x = 53;
unsigned char  tmp = (x >> 4) & 0x0F;
uart_send(DecDigitToHex(tmp));
tmp = x & 0x0F;
uart_send(DecDigitToHex(tmp));

Assumi que existe uma função 'uart_send' que serve para enviar um character pela uart.
Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: metRo_ em 22 de Novembro de 2009, 01:58
Realmente o teu código está muito mais simples e mais prático, muito obrigado.
Só acho tens ali um erro, na 5ª linha do segundo exemplo:
Código: [Seleccione]
tmp = TabelaConv[x & 0x0F];Aqui seria:
Código: [Seleccione]
tmp = DecDigitToHex[x & 0x0F];
certo?
Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: Njay em 22 de Novembro de 2009, 02:02
Quase! Era "tmp = x & 0x0F;". Erro de copy&paste, obrigado :). Vou alterar na mensagem anterior.

Mas entendeste o código? Os 2 blocos são independentes, ou se usa 1 ou o outro.
Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: metRo_ em 22 de Novembro de 2009, 02:08
sim percebi,
eu tinha colocado
Código: [Seleccione]
tmp = DecDigitToHex[x & 0x0F]; pois pensei que era o tmp que era enviado na porta serie ;)
Título: Re: [AVR-GCC] Divisão Atmega8
Enviado por: Njay em 22 de Novembro de 2009, 03:26
Não poderia ser "DecDigitToHex[x & 0x0F]" porque DecDigitToHex é uma macro e não um array, e os [] só se usam com arrays.

A conversão para hexadecimal (hex) é muito simples porque é fácil converter de binário para hex, e é por isso que se usa tanto em programação e electrónica digital. Repara no teu número 53:

   53      (decimal)
0011 0101  (binário)
   3 5     (hexadecimal)

Se partires do número na representação binária, basta dividir o número em grupos de 4 bits e converter cada grupo de 4 para hexadecimal. Cada grupo corresponde a um digito em hexadecimal: 0011b = 3h e 0101b = 5h ("b" indica que o número é binário e "h" que é hexadecimal). Desta forma é muito mais simples converter entre binário e hex do que entre binário e decimal.