Enunciado do exercício:

“Considerando um 8051 com um cristal de 11,0592 MHz, desenvolver um programa em C para fazer um LED piscar em uma frequência de 1 segundo.”

 

Solução:

  • Frequência do clock externo (cristal) = 11,0592 MHz
  • Frequência de 1 pulso de clock no 8051 = 11,0592 MHz / 12 = 921.600 Hz
  • Período de 1 pulso de clock no 8051 = 1/921.600 = 1,0851 μs
  • Consequentemene, são necessários aproximadamente 921.574 pulsos de clock para gerar um atraso de 1 segundo. O maior valor que conseguimos representar nos registradores dos temporizadores do 8051 possui 16 bits, ou seja, 65.535.
  • Assim, no lugar de configurar o timer do 8051 para contar 1 segundo, vai ser necessário dividir esse valor por 1.000, e o timer será configurado para gerar um atraso de 1 ms.
  • Utilizando o Timer 0 no modo 1, os registradores TH0 e TL0 são utilizados em conjunto, formando um timer de 16 bits, realizando uma contagem de 0 a 65.535 (total de 65.536 valores).
  • Como 1 pulso de clock no 8051 possui um período de 1,0851 μs, logo para realizar as 65.536 contagens, o Timer 0 irá demorar: 65.536 x 1,0851 μs = 71,1066 ms.
  • Vai ser necessário calcular o número de contagens do Timer 0, necessário para obter o atraso de 1 ms.
  • Logo, 1ms / 1,085μs = 921,6589862 contagens
  • Valor inicial a ser utilizado para obter 921,7 contagens: 65.536 – 921,7 = 64.614,3
  • Esse será o valor inicial da contagem a ser carregado nos registradores TH0 e TL0 do Timer 0, visando gerar um overflow a cada aproximadamente 922 contagens (aproximadamente 1 ms).
  • Para ficar mais simples na hora de escrever o programa que inicializa os registradores TH0 e TL0, esse valor deve ser convertido para hexadecimal: 64.614 = FC66H
  • Os passos necessários para configurar e utilizar o Timer 0 como um temporizador de 1 ms são os seguintes:
  1. Configurar o Timer 0 no Modo 1 (timer/counter de 16 bits): TMOD = 0x01;
  2. Inicializar os registradores do Timer 0 para o atraso desejado de 1 ms: TH0 = 0xFC; e TL0 = 0x66;
  3. Iniciar o Timer 0 (disparar o temporizador): TR0 = 1;
  4. Usando polling ou interrupção, permanecer verificando se ocorreu overflow: TF0 == 1 ??
  5. Quando o bit TF0 do registrador TCON receber 1, isso significa que ocorreu um overflow (FFFFH -> 0000H), e se passou o tempo de 1 ms.
  6. Fazer TR0 = 0 (bit do registrador TCON), para garantir que a temporização de 1 ms ficará interrompida até a próxima rodada (até retornar ao passo 2).
  7. Se usar interrupção, o bit TF0 do registrador TCON irá receber 0 automaticamente, no momento do desvio para a rotina de tratamento de interrupção. Se usar polling, logo não vai haver desvio para a rotina de tratamento de interrupção, e o programa deverá conter uma instrução explícita de TF = 0.
  8. Quando ocorrer o overflow, precisa recarregar TH0 e TL0 com os valores necessários para gerar a temporização de 1 ms, ou seja, retornar ao passo 2.
  • A rotina de atraso de 1 segundo deverá ser implementada de forma a executar os passos de 2 a 8 por 1.000 (mil) vezes, uma vez que esses passos foram definidos para gerar um atraso de 1 ms.
  • Sugestão de solução com polling:
/*
   Descricao: Pisca LED com Timer usando polling
   Autor: Eduardo Augusto Bezerra
   Data: 12/07/2021
   Instituicao: UFSC
   Entradas: 
   Saidas:
*/
#include <reg51.h>
void delay(unsigned int t);
sbit P1_0 = P1^0;
void main (void){
   P0 = 0xFF; 
   P1 = 0xFF; 
   P2 = 0xFF;
   P3 = 0xFF;
   // Configuracao do Timer para geracao do atraso
   TMOD = 0x01; // Timer 0 no modo 1
   while(1){
      P1_0 = 1;
      delay(1000);
      P1_0 = 0;
      delay(1000);
   }
}
// Versao com Polling
void delay(unsigned int t){
   unsigned int i;
   for(i = 0; i < t; i++){
      // Inicializa o timer para gerar temporizacao de 1 ms
      TH0 = 0xFC; 
      TL0 = 0x66; 
      TR0 = 1; // dispara a contagem 
      while(TF0 != 1); // verifica overflow
      TR0 = 0; // Suspende o temporizador
      TF0 = 0; // Limpa o flag do temporizador
   }
}
  • Sugestão de solução com interrupção:
/*
   Descricao: Pisca LED com Timer usando interrupcao
   Autor: Eduardo Augusto Bezerra
   Data: 12/07/2021
   Instituicao: UFSC
   Entradas: 
   Saidas:
*/
#include <reg51.h>
void delay(unsigned int t);
void int_timer0 (void);
unsigned char state = 0;
sbit P1_0 = P1^0;
void main (void){
   P0 = 0xFF; 
   P1 = 0xFF; 
   P2 = 0xFF;
   P3 = 0xFF;
   // Configuracao do Timer para geracao do atraso
   TMOD = 0x01; // Timer 0 no modo 1 (temporizador de 16 bits)
   ET0 = 1;     // Habilita interrupcao do Timer 0
   EA = 1;      // Habilita interrupcoes
   while(1){
      P1_0 = 1;
      delay(1000);
      P1_0 = 0;
      delay(1000);
   }
}
void delay(unsigned int t){ 
   unsigned int i;
   for(i = 0; i < t; i++){
      // Inicializa o timer para gerar temporizacao de 1 ms
      TH0 = 0xFC; 
      TL0 = 0x66; 
      TR0 = 1; // dispara a contagem 
      while(state != 1); // verifica overflow
      state = 0;
      TR0 = 0; // Suspende o temporizador
      // Nao precisa fazer TF = 0, pois isso foi feito automaticamente 
      // ao desviar para ao tratador da interrupcao.
   }
}
// Tratador da interrupcao do Timer 0
void int_timer0 (void) interrupt 1 {
   state++;
}