quinta-feira, agosto 28, 2008

Microcontroladores - Parte 8

O meu primeiro contato com desenvolvimento de sistemas embarcados foi dando manutenção e desenvolvendo firmwares para terminais de vídeo na Scopus*. O hardware era baseado no microprocessador Intel 8080, que é menos poderoso que a maioria dos processadores dos microcontroladores atuais.

Nesta época praticamente todo o desenvolvimento, tanto para os terminais de vídeo como para o microcomputador de 8 bits, era feito em Assembly. Era uma programação trabalhosa, tediosa e muito propícia a erros. Foi somente quando se começou a desenvolver software para 16 bits que se começou a usar linguagens de alto nível no software 'básico'. Posteriormente isto foi estendido para os terminais de vídeo, apesar de algumas desconfianças em termos de desempenho e requisitos de memória.

A linguagem C foi justamente desenvolvida para a programação de baixo nível em sistemas com poucos recursos
  • implementa as estruturas básicas de programação (if, while, switch)
  • dispõe de recursos para operações de baixo nível (ponteiros, manipulação de bits)
  • requer um runtime bastante simples
Mesmo assim, alguns microcontroladores são grandes desafios para quem quer criar um compilador C:
  • arquiteturas não apropriadas
  • memória Ram limitada
  • memória dividida em partes com características diferentes
O resultado às vezes é o proverbial "urso de circo andando de bicicleta": ele não anda muito bem mas o simples fato de andar alguma coisa já é incrível.

O código abaixo é uma simplificação do software para o "Grilo Pulsante Fantasma" e dá uma primeira idéia do que é programar em C para microcontroladores:

#include <12F675.h>
#use delay(clock=4000000)
#fuses INTRC_IO, MCLR, BROWNOUT

volatile int1 fBeep;
volatile int16 contBeep;

void bipa (void)
{
fBeep = TRUE; contBeep = 0;
enable_interrupts (INT_TIMER0);
while (fBeep)
;
disable_interrupts (INT_TIMER0);
}

#int_TIMER0
TIMER0_isr()
{
if (++contBeep == 0x1000)
fBeep = FALSE;
else if (contBeep & 1)
output_low (BUZZER);
else
output_high (BUZZER);
}

void main()
{
set_tris_a (0x06);
#use fast_io(A)
setup_adc_ports (AN1_ANALOG);
setup_adc (ADC_CLOCK_INTERNAL);
set_adc_channel (1);
setup_timer_1 (T1_DISABLED);
setup_comparator (NC_NC_NC_NC);
enable_interrupts (global);
output_low (BUZZER);

while (1)
{
sleep ();
if (input (BOTAO) == 0)
bipa ();
if (read_adc() < ESCURO)
continue;
AcendeLed (LED_R);
delay_ms (10);
ApagaLed (LED_R);
if ((rand() & 0x07) == 0)
bipa ();
}
}

No código acima podemos reparar que:
  • um programador C de desktop não vai ter dificuldade em entender boa parte do código
  • existem uma série de comandos não padrão para o compilador (#use, #fuses, #int_TIMER0)
  • existem uma grande quantidade de rotinas específicas para controle do hardware (neste caso em particular muitas destas rotinas na realidade geram diretamente código in-line)
A qualidade do código gerado e do ambiente de desenvolvimento varia bastante de caso para caso. É o que veremos nos próximos posts.

* brinde inesperado: clique em "Conheça nossa história" e encontre uma menção nominal ao autor do blog!

Nenhum comentário: