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:
  1. #include <12F675.h>  
  2. #use delay(clock=4000000)  
  3. #fuses INTRC_IO, MCLR, BROWNOUT  
  4.   
  5. volatile int1 fBeep;  
  6. volatile int16 contBeep;  
  7.   
  8. void bipa (void)  
  9. {  
  10.  fBeep = TRUE; contBeep = 0;  
  11.  enable_interrupts (INT_TIMER0);  
  12.  while (fBeep)  
  13.     ;  
  14.  disable_interrupts (INT_TIMER0);  
  15. }  
  16.   
  17. #int_TIMER0  
  18. TIMER0_isr()  
  19. {  
  20.  if (++contBeep == 0x1000)  
  21.      fBeep = FALSE;  
  22.  else if (contBeep & 1)  
  23.           output_low (BUZZER);  
  24.       else  
  25.           output_high (BUZZER);  
  26. }  
  27.   
  28. void main()  
  29. {  
  30.  set_tris_a (0x06);  
  31.  #use fast_io(A)  
  32.  setup_adc_ports (AN1_ANALOG);  
  33.  setup_adc (ADC_CLOCK_INTERNAL);  
  34.  set_adc_channel (1);  
  35.  setup_timer_1 (T1_DISABLED);  
  36.  setup_comparator (NC_NC_NC_NC);  
  37.  enable_interrupts (global);  
  38.  output_low (BUZZER);  
  39.   
  40.  while (1)  
  41.  {  
  42.     sleep ();  
  43.     if (input (BOTAO) == 0)  
  44.        bipa ();  
  45.     if (read_adc() < ESCURO)  
  46.        continue;  
  47.     AcendeLed (LED_R);  
  48.     delay_ms (10);  
  49.     ApagaLed (LED_R);  
  50.     if ((rand() & 0x07) == 0)  
  51.        bipa ();  
  52.  }  
  53. }  

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: