Posts com Tag ‘sistema operacional de tempo real’

Caro(a) Colega,

semana que vem tem curso gratuito sobre o desenvolvimento de uma aplicação de RTOS utilizando-se o FreeRTOS.  É imperdível! Consulte também os cursos arquivados do CEC. Vale a pena conferir.

Abraço,

.

Henrique

consulte sempre um engenheiro eletrônico

===========================================================================================================

Cursos arquivados

===========================================================================================================

 

CEC Continiuing Education Center - IEEE - Design News
New Free Online Course:
Hands-On Develop an RTOS Application
Using freeRTOS
February 22 – 26 at 11:00 AM Pacific/2:00 PM Eastern
30 to 45 minutes per day
 .
 .

This hands-on course will teach you how to use freeRTOS, a free, open-source cross-platform real-time operating system. We will begin with a look at RTOS basics and work through an example, step-by step, of how to create an RTOS application from scratch. We will use the popular and inexpensive ARM-based STMicroelectronics’ STM32 Nucleo board, an inexpensive Arduino shield (interface board), the Atollic TrueStudio integrated development environment, and the STMVLDiscovery kit. The instructor, Charles Lord, will provide code so that attendees can follow along.

.

  • February 22 – Day 1: Introduction to freeRTOS / RTOS Refresher
    In this leadoff class, we will review the basics of how a task-switching RTOS operates and the design criteria we need to begin our hands-on design project. We will look at the freeRTOS real-time operating system and the elements that we will be using in our project.
  • February 23 – Day 2: RTOS System Development Setup
    Our toolset will be an important part of making our project successful. We will install and investigate these tools, followed by learning how to set them up, consisting of the STMicro STM32 Nucleo and the Atollic TrueStudio IDE, in tandem with the freeRTOS download.
  • February 24 – Day 3: Changing Processors & Making It Work
    A common challenge of RTOS implementations is their limitation to certain chips, development boards, and toolchains. We will bring up our initial solution using the STM32F100 board and then look at how we will have to modify the code to work with our designated STM32 Nucleo processor and board.
  • February 25 – Day 4: Defining and Running the Project
    In this penultimate class, we will take what we learned so far and define the tasks of our project. We will look at some simple “lightweight” elements that we may choose for our project, such as messaging, events, semaphores, and mutexes.
  • February 26 – Day 5: Troubleshooting Our RTOS Design
    Now that our code is written, we will need to test and debug it. In this final class, we will see how the debugger works with the RTOS to provide task-level debugging. The finished code will be available to help course students follow along and compare with their own code.
You can earn IEEE professional development hours by attending CEC cources.
For full details click here.
Reserve Your Place Now Reserve Your Place Now
Busy then? Register anyway – You can listen when it’s convenient for you. The lectures will be available on-demand immediately after the live class ends.
Sponsored by:
Digi-Key

sku_147734_1-550x550

Introdução

Chaves eletromecânicas são uma forma quase primitiva de interface entre um sistema eletrônico e um ser humano. Por meio delas, podemos selecionar, programar e responder a estímulos do sistema.  As chaves organizadas em arranjos matriciais, por exemplo, formam dispositivos mais complexos, que conhecemos por teclados. Este artigo trata de rotinas padronizadas em linguagem C para o MCS-51, para configurar e tratar as particularidades de um teclado, gerando os sinais de estímulo e realizando a leitura, realizando também debouncing por software, identificando a(s) tecla(s) acionada(s) e preparando uma rotina para o tratamento dessa(s) tecla(s). Para uma melhor compreensão do que será tratado nesse artigo, recomendo a leitura dos seguintes artigos técnicos:

Arquitetura de Hardware

Na biblioteca de rotinas padronizadas, que será apresentada a seguir, são consideradas duas formas distintas de seleção da matriz de teclas:

Seleção por linhas codificadas

A seleção por linhas codificadas, como ilustrado na Figura 1, pode ser realizada utilizando-se um decodificador/ Multiplexador na saída dos sinais de seleção. Um componente desse tipo é o 74LS139 [1]. Nessa forma de seleção do teclado são utilizados poucos pinos do port para codificar o número da linha de seleção a ser ativada em código binário. Ou seja, 1 bit seleciona até duas linhas, 2 bits quatro etc. A intenção foi a de economizar pinos nos ports do microcontrolador, especialmente se o teclado for grande. A rotina da biblioteca para essa configuração foi batizada de ROTINA DE LEITURA DE MATRIZ DE CONTATOS I.

Teclado_1_Cod

Figura 1: Teclado matricial com seleção por linhas codificadas

 .

Seleção por linhas separadas

A seleção com linhas separadas é realizada conforme ilustrado na Figura 2. A rotina da biblioteca para essa configuração foi batizada de ROTINA DE LEITURA DE MATRIZ DE CONTATOS II.

Teclado_1

Figura 2: Teclado matricial com seleção por linhas separadas

Rotinas padronizadas em C para o teclados matriciais

O código em linguagem C para os teclados matriciais segue o mesmo padrão do desenvolvido para os timers em Sistemas Operacionais de Tempo Real – Timers. Tem um conjunto de definições e variáveis, uma parte a ser inserida na rotina de interrupção do timer, de forma que quando o timer virtual do teclado terminar a contagem, é sinalizado para o programa principal que a contagem terminou. No programa principal são inseridas algumas inicializações, as rotinas de leitura do teclado, debounce e tratamento da tecla. Essa solução é um pouco diferente da implementada para os displays de 7 segmentos, pois entende-se que tratar teclado não é uma tarefa prioritária para um sistema e não necessita de uma temporização precisa. Assim, o trecho de código para a leitura do teclado não foi colocado dentro da rotina de interrupção do timer. Assim ela é executada na medida em que é possível.

Definições e variáveis

A seguir os códigos exemplo referentes às definições e configurações correspondentes às arquiteturas descritas anteriormente. Esse trecho de código é inserido tipicamente num arquivo do tipo .h do programa.

ROTINA DE LEITURA DE MATRIZ DE CONTATOS I (Sinais de seleção codificados) – Definições e Inicializações

 Software_1

.

ROTINA DE LEITURA DE MATRIZ DE CONTATOS II (Sinais de seleção separados) – Definições e Inicializações

Software_2

.

São utilizadas algumas convenções com relação às definições e uso das constantes. Em todo o programa, 1 quer dizer ligado ou ativo e 0 desligado ou inativo. Este trecho de código é na sua essência o configurador do teclado, amarrando as particularidades do hardware com o software. O que deve ser configurado:

  • #define FREQ_DE_INTERRUP_TIMER_MATRIZ_DE_CONTATOS: Define a frequência com a qual é realizada um a varredura completa do teclado. 10 vezes por segundo é uma taxa razoável;
  • #define NUMERO_DE_LINHAS_DA_MATRIZ: Define o número de linhas de seleção da matriz de teclas;
  • #define PORTA_DE_ENTRADA_DA_MATRIZ:  Define em que port estão conectadas as entradas do teclado;
  • #define PORTA_DE_SAIDA_DA_SELECAO_DA_MATRIZ: Define em que port estão conectadas as linhas de seleção das teclas;
  • #define MASCARA_DA_MATRIZ: Aqui é definida a posição e abrangência das linhas de entrada;
  • #define MASCARA_DA_SELECAO: Filtra os bits dos sinais de seleção;
  • #define SELETOR_DOS_SINAIS_DE_SELECAO: Define posição do primeiro bit do conjunto de seleção que será deslocado em anel para selecionar as colunas de teclas ;
  • #define SAIDAS_INVERTIDAS : Colocar essa linha como comentário, se acaso as linhas de seleção não precisarem ser invertidas;
  • #define INCREMENTO_PARA_O_CONTADOR_DE_SELECAO: Define o “mais 1” no contador, no caso da seleção codificada;
  • unsigned char ucMatrizDeContatosDeEntrada[NUMERO_DE_LINHAS_DA_MATRIZ]: É necessário iniciar com zeros essa matriz;

As demais variáveis e constantes são calculadas automaticamente pelo programa.

.

Rotina de debounce – Definições e Inicializações

 debounce

.

Rotina de  Identificação de Contatos – Definições e Inicializações

Ident

.

Código a ser inserido no corpo do programa principal

O código a seguir testa um flag (bFlagDeTemporizacaoDaMatrizDeContatos) que é ativado pela rotina de interrupção quando for terminada a contagem do temporizador virtual de leitura do teclado. Se o flag foi acionado, é realizada a varredura do teclado e testado se há teclas acionadas. Se houver teclas acionadas, a rotina sinaliza com outro flag (bFlagDeNovaLeituraDeMatrizDeContatos) de que há contatos acionados.  Nesse código estão indicadas as rotinas de debounce, identificação dos contatos acionados e de execução de ações em função dos contatos acionados. Esses códigos serão apresentados mais adiante.

ROTINA DE LEITURA DE MATRIZ DE CONTATOS I (Sinais de seleção codificados)

Scan1AScan1b

 .

ROTINA DE LEITURA DE MATRIZ DE CONTATOS II (Sinais de seleção separados)

 Scan2AScan2b

.

Rotina de debounce

 Na saída da rotina de leitura de contatos é acionado um flag (bFlagDeNovaLeituraDeMatrizDeContatos) para sinalizar que há novos dados. Esse flag é testado e se afirmativo inicia-se o processo de debounce. A rotina de debounce basicamente testa se o que foi lido está estável há pelo menos N leituras. Se não, é reiniciado o contador de debounce. Como a frequência de leitura do teclado é baixa, o valor de N pode ser pequeno também, por exemplo 2 ou 3. Quando a rotina decide que a leitura está estável e tem tecla acionada, é acionado um flag (bFlagDeTerminoDeDebounce) para ativar o próximo passo do tratamento de teclas.

Debounce

.

Rotina que identifica os contatos acionados

Esta rotina varre a matriz de teclas, verifica se há teclas acionadas, determina a posição dessas teclas e o número total de teclas acionadas. Se houver teclas acionadas, a rotina sinaliza com um flag ()  para ativar o próximo passo do programa de tratamento de teclas.

Testa_Contato
.

Rotina de execução de ações em função dos contatos

Exec

 .

Código a ser inserido na rotina de interrupção do Timer 0

O trecho de código a seguir implementa um temporizador virtual para temporização do início de varredura do teclado. Sempre que o contador termina a contagem, o contador é reinicializado e é sinalizado que a temporização terminou.

Timer_0

EXEMPLO

Nesse programa foi aproveitado o mesmo programa desenvolvido para a demonstração de operação dos timers e displays de 7 segmentos de tempo real, acrescidos os trechos relativos ao teclado. Aqui será programado o Timer 0 no modo 2 de operação, com o microcontrolador operando com um clock de 4 MHz e uma frequência de interrupção de 1,5 kHz. Foram definidos 3 displays de 7 segmentos do tipo II com a seleção separada, e atualizados a cada 30 contagens cada um. Também foi definido um teclado matricial, cujas linhas de entrada estão alocadas aos bits 0 a 2 do Port 2 e as linhas de seleção aos bits 4 a 7 do mesmo Port. Confira o código no quadro abaixo.

.

  Exemplo1Exemplo2Exemplo3Exemplo4Exemplo5Exemplo6Exemplo7Exemplo8Exemplo9Exemplo10Exemplo11

Exemplo12

Simulação do exemplo

Se você quiser simular o programa exemplo acima e explorá-lo um pouco mais, siga os seguintes passos:

  • Instale o KEIL C51 μVision [2];
  • Baixe o arquivo Testa_Teclado.zip [3];
  • Instale os arquivos de Testa_Teclado.zip num diretório para testes;
  • Navegue até o diretório de testes e acione o arquivo Testa_teclado.uvproj (2 “clickes”)  (Figura 3).

Teclado_Soft_1a

 Figura 3: Arquivos no diretório de teste

.

Nesse instante deverá abrir o programa Keil e a tela deverá ser a retratada na Figura 4. Esse painel permite navegar no código em C, editá-lo e compilá-lo. Não é necessário fazer isso para realizar a simulação, mas você poderá posteriormente alterar alguns parâmetros do código e testar o programa com as novas alterações.

Teclado_Soft_2

 Figura 4: Programa Keil pronto com o programa exemplo carregado

.

A seguir coloque o programa no modo de Debug (Figura 5, Figura 6 e Figura 7) para que se possa iniciar a simulação.

Teclado_Soft_3Figura 5: Selecionando o modo Debug do programa

.

Antes de entrar no modo de depuração, aparece na tela a mensagem da Figura 6. Clique no “OK” para continuar.

Displ_9

 Figura 6: Aviso de que no modo de avaliação, o código fica limitado a 2K

.

Teclado_Soft_3

   Figura 7: Modo Debug de operação

.

Observe que já estão destacados os painéis de monitoramento do Timer 0,  do Port 1, cujo bit 1 deverá ser alternado a cada término de contagem do temporizador de software do teste do timer e cujos bits 5, 6 e 7 são usados como linhas de seleção dos 3 displays, e o Port 3, onde aparecem os códigos de cada dígito de 7 segmentos. Nessa simulação, aparecem os números 1, 2 e 3 respectivamente nos displays 0, 1 e 2. Também aparece o painel de monitoramento do Port 2, onde os bits de 0 a 2 são as entradas do teclado e os bits 4 a 7 os sinais de seleção da matriz

É possível utilizar as teclas de função F11 para executar o programa passo a passo ou F5 entrar em execução. Recomendo que você inicie a simulação utilizando o passo a passo para poder observar detalhadamente como que funciona o mecanismo de operação desse programa.

Resumo

Neste artigo técnico foram apresentadas algumas possíveis soluções padronizadas para a leitura e tratamento de teclados matriciais com auxílio de um timer de hardware. Essas soluções constituem uma biblioteca padronizada para a utilização dos teclados  matriciais em microcontroladores da família MCS-51, codificada em C, para ser compilada no programa da Keil. Depois foi desenvolvido um programa exemplo para que você possa simular o que foi apresentado e observar os detalhes dessa implementação. Repare que a aplicação tem uma complexidade razoável e foi montada a partir das rotinas de biblioteca em menos de meia hora. E funciona!!!!

Este artigo é o quarto da série de artigos que abordam algumas funções comuns em projetos de sistemas embarcados de tempo real. Confira os demais artigos (em breve).

Sistemas Operacionais de Tempo Real

Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51

  • Timers – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso dos Timers do MCS-51;
  • Displays de 7 segmentos  – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos;
  • Teclados Matriciais (este artigo) – É apresentada uma biblioteca desenvolvida em linguagem C para varredura, leitura, debounce, identificação da tecla acionada e desvio para a rotina de tratamento. A forma como as rotinas foram escritas, permitem sua fácil reutilização em outros projetos;
  • Periféricos (Em breve) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso de alguns periféricos, tais como conversores A/D, sensor de temperatura e memórias seriais.

Referências

[1] http://www.ti.com/lit/ds/symlink/sn54s139.pdf

[2 https://www.keil.com/demo/eval/c51.htm

[3] http://www.embarcados.com.br/download/Testa_Teclado.zip

Licença Creative Commons
Esta obra, “Sistemas Operacionais de Tempo Real – Teclados Matriciais“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 3.0 Não Adaptada.

Displ_1

Introdução

Este artigo faz parte da série de artigos que apresenta Bibliotecas de funções e rotinas padronizadas em linguagem C para microcontroladores da família MCS-51, que podem facilmente ser adaptadas para outros microcontroladores. Para a melhor compreensão do que será desenvolvido aqui, é recomendável que você leia os seguintes artigos

A filosofia utilizada para o desenvolvimento das rotinas para os displays de 7 segmentos é a mesma utilizada nas rotinas apresentadas no artigo Sistemas Operacionais de Tempo Real – Timers. Cria-se um temporizador virtual por software, que é baseado na interrupção de um timer de hardware definindo assim a frequência com a qual os displays são atualizados. Deve-se escolher uma frequência de atualização alta o suficiente para que  não se tenha a desagradável sensação de que o display está “piscando”. Em geral essa frequência é da ordem de 20 a 30 vezes por segundo para cada display. A transferência de dados entre o programa principal e a rotina de interrupção é feita através de um vetor dedicado cujo conteúdo é o que deve ser apresentado no display e de eventuais mecanismos para controlar o acesso a esse vetor.

A biblioteca permite que se opere com algumas soluções de hardware distintas, tais como linhas de seleção multiplexadas, ou então separadas, dependendo do tipo de solução e compromissos desenvolvidos no projeto. Também é ilustrado como se pode de maneira simples codificar as letras e símbolos a serem mostrados nos displays.

Arquitetura de Hardware

Para que se possa desenvolver rotinas de programação padronizadas para os displays de 7 segmentos e cuja adaptação ao hardware seja simples é necessário definir arbitrariamente e fixar alguns modelos físicos para as conexões. A mais óbvia é a alocação de um port inteiro de 8 bits para gerar os segmentos e o ponto decimal dos displays. Para recordar como que é uma interface com um display de 7 segmentos, veja um exemplo na Figura 1.

Displ_2

Figura 1: Conexões de acionamento de um display de 7 segmentos

Acionamento dos segmentos de LED

A atribuição dos segmentos de LED aos pinos do Port foi arbitrária. Por questão de simplicidade eles foram conectados em sequência numa mesma porta: bits 0123456 nos segmentos ABCDEFG. e o ponto decimal foi colocado no bit 7. Pode-se observar na Figura 2 uma ilustração simplificada disso. Essa solução de hardware para conexão dos segmentos do display ao microcontrolador é pressuposta nas rotinas em linguagem C da biblioteca, que serão apresentadas mais adiante, agrupadas como ROTINA DOS DISPLAYS DE 7 SEGMENTOS I e ROTINA DOS DISPLAYS DE 7 SEGMENTOS II. O que diferencia os dois grupos, são as formas de seleção dos displays.

 Displ_3

Figura 2: Exemplo de alocação dos segmentos dos displays a um port de 8 bits

 Nessa atribuição arbitrária, pode-se formar os dígitos e alguns caracteres caracteres conforme ilustrado na Tabela 1 .

Tabela 1: Códigos para acender os segmentos de acordo com o dígito ou caracter desejado

Programa_1

Outra forma de conectar o display de LED de 7 segmentos a um microprocessador é por meio de um decodificador BCD para 7 segmentos, tais como por exemplo os circuitos integrados 74LS49 [1], ou então o 74HC4511 [2]. Na Figura 3 é ilustrada uma solução de hardware onde é utilizado um decodificador desse tipo, com a atribuição arbitrária dos pinos e ports utilizada nas rotinas padronizadas em linguagem C agrupadas como  ROTINA DOS DISPLAYS DE 7 SEGMENTOS III.
 

Displ_4

Figura 3: Solução de hardware com decodificador BCD / 7 segmentos

 Formas de seleção dos displays

Nas rotinas padronizadas foram previstas duas formas de seleção dos displays: linhas de seleção separadas, utilizadas nos grupos de rotinas ROTINA DOS DISPLAYS DE 7 SEGMENTOS II e III, e linhas de seleção codificadas, utilizadas na ROTINA DOS DISPLAYS DE 7 SEGMENTOS I.

Linhas Separadas

As linhas de seleção separadas são alocadas num segundo Port.A definição das variável do programa padronizado, permite que se selecione em que bit do Port começam as linhas. Essas linhas de seleção devem estar necessariamente alocadas em ordem crescente nos pinos do Port. Veja por exemplo o código em C mostrado na Figura 4.

No exemplo da figura, foram definidos que são 3 displays, os segmentos conectados ao Port 3, as linhas de seleção ao Port 1 e será utilizado o ponto decimal. Na parte específica relacionado com as linhas de seleção, é definido que as linhas estão alocadas nos pinos 6 e 7 do Port 1 (0xE0)

 Programa_2

 Figura 4: Definições relacionadas com as linhas de seleção

Linhas codificadas

Nessa forma de seleção dos displays são utilizados poucos pinos do port para codificar o número do display a ser ativado em código binário. Ou seja, 1 bit seleciona até dois displays, 2 bits quatro etc. A intenção foi a de economizar pinos nos Ports do microcontrolador, especialmente se o número de displays for grande. É necessária a utilização de um decodificador / multiplexador na saída do Port, conforme ilustrado na Figura 5. Um exemplo desse tipo de componente é o 74LS139 [3].

Displ_5

 Figura 5: Solução de hardware usando um decodificador

Rotinas padronizadas em C para os displays de 7 segmentos

O código em linguagem C para os displays segue o mesmo padrão do desenvolvido para os timers em Sistemas Operacionais de Tempo Real – Timers. Tem um conjunto de definições e variáveis, uma parte a ser inserida na rotina de interrupção do timer, de forma que quando o timer virtual do display terminar a contagem, é executado um trecho curto de código para atualizar os displays. No programa principal são inseridas algumas inicializações.

Definições e variáveis

A seguir os códigos exemplo referentes às definições e configurações correspondentes às arquiteturas descritas anteriormente. Esse trecho de código é inserido tipicamente num arquivo do tipo .h do programa.

ROTINA DOS DISPLAYS DE 7 SEGMENTOS I  (Sinais de seleção codificados)

Programa_3a

Programa_3b

Programa_3c

ROTINA DOS DISPLAYS DE 7 SEGMENTOS II  (Sinais de seleção separados)

Programa_4a

Programa_4b

Programa_4c

ROTINA DOS DISPLAYS DE 7 SEGMENTOS III  (Utiliza decodificador BCD para 7 segmentos e sinais de seleção separados)

Programa_5a

Programa_5b

Programa_5c

São utilizadas algumas convenções com relação às definições e uso das constantes. Em todo o programa, 1 quer dizer ligado ou ativo e 0 desligado ou inativo. Este trecho de código é na sua essência o configurador dos displays, amarrando as particularidades do hardware com o software. O que deve ser configurado:

  • #define DISPLAY_INVERTIDO: Essa linha deve ser colocada como comentário, se acaso as saídas para os segmentos não necessitam de inversão lógica;
  • #define TEM_PONTO_DECIMAL: Essa linha deve ser colocada como comentário, se acaso não for utilizado o ponto decimal;
  • #define NUMERO_DE_DISPLAYS: Nessa linha deverá ser colocado o número de displays multiplexados que existem no hardware;
  • #define FREQ_DE_INTERRUP_TIMER_DISPLAYS: é a frequência de atualização de um display multiplicada pelo número de displays;
  • #define NUMERO_DE_LINHAS_DO_DISPLAY: Aqui é definido o número de linhas de seleção que serão utilizadas;
  • #define PORTA_DE_SAIDA_DOS_DISPLAYS: Aqui deve ser definida em que Port estão conectados os segmentos dos displays;
  • #define PORTA_DE_SAIDA_DA_SELECAO_DOS_DISPLAYS: Aqui é definido em que Port estão conectadas as linhas de seleção;
  • #define MASCARA_DA_SELECAO_DE_DISPLAY: Aqui é definida a posição e abrangência das linhas de seleção;
  • #define SELETOR_DOS_SINAIS_DE_SELECAO_DISPLAY: Define a posição do bit de seleção que será deslocado em anel para selecionar os diversos displays;
  • #define SAIDAS_INVERTIDAS_SEL_DISP : Colocar essa linha como comentário, se acaso as linhas de seleção não precisarem ser invertidas;
  • unsigned char ucFilaDeSaidaDosDisplays[NUMERO_DE_DISPLAYS]: É necessário dimensionar e inicializar corretamente esse vetor.

As demais variáveis e constantes são calculadas automaticamente pelo programa.

.

Código a ser inserido na rotina de interrupção do Timer 0

Os trechos de códigos a seguir implementam um temporizador virtual para o acionamento dos displays. Sempre que o contador termina a contagem, é desligado o display atual e ativado o próximo, tomando as providências de hardware para isso.

ROTINA DOS DISPLAYS DE 7 SEGMENTOS I  (Sinais de seleção codificados)

Programa_6

ROTINA DOS DISPLAYS DE 7 SEGMENTOS II (Sinais de seleção separados)

 Programa_7

ROTINA DOS DISPLAYS DE 7 SEGMENTOS III   (Utiliza decodificador BCD para 7 segmentos e sinais de seleção separados)

Programa_8

Programa_8a

Código a ser inserido nas inicializações do programa principal

O trecho de código a seguir inicializa uma variável auxiliar e desativa as linhas de seleção dos displays.

Programa_9

Como transferir dígitos para os displays?

Da forma como foi projetado esse programa, o gerenciamento do display propriamente dito é totalmente automático e transparente para o programa principal. Você só precisa converter o dígito para o código, usando-o como índice na tabela ucTabelaDeDisplayDeSeteSegmentos[dígito] e transferí-lo para a fila de saída dos displays (ucFilaDeSaidaDosDisplays[]) na posição correspondente. Veja no exemplo a seguir.

EXEMPLO

Nesse programa foi aproveitado o mesmo programa desenvolvido para a demonstração de operação dos timers [5] de tempo real, acrescidos os trechos relativos aos displays. Aqui será programado o Timer 0 no modo 2 de operação, com o microcontrolador operando com um clock de 4 MHz e uma frequência de interrupção de 1,5 kHz. Foram definidos 3 displays de 7 segmentos do tipo II com a seleção separada, e atualizados a cada 30 contagens cada um. Confira o código no quadro abaixo.

Programa_10a

Programa_10b

Programa_10c

Programa_10d

Programa_10e

  Programa_10f

Simulação do exemplo

Se você quiser simular o programa exemplo acima e explorá-lo um pouco mais, siga os seguintes passos:

  • Instale o KEIL C51 μVision [4];
  • Baixe o arquivo Testa_Display.zip [6];
  • Instale os arquivos de Testa_Display.zip num diretório para testes;
  • Navegue até o diretório de testes e acione o arquivo Testa_Display.uvproj (2 “clickes”)  (Figura 6).

 Displ_6

Figura 6: Arquivos no diretório de teste

Nesse instante deverá abrir o programa Keil e a tela deverá ser a retratada na Figura 7. Esse painel permite navegar no código em C, editá-lo e compilá-lo. Não é necessário fazer isso para realizar a simulação, mas você poderá posteriormente alterar alguns parâmetros do código e testar o programa com as novas alterações.

 Displ_7

Figura 7: Programa Keil pronto com o programa exemplo carregado

A seguir coloque o programa no modo de Debug (Figura 8, Figura 9 e Figura10) para que se possa iniciar a simulação.

 Displ_8

Figura 8: Selecionando o modo Debug do programa

Antes de entrar no modo de depuração, aparece na tela a mensagem da Figura 9. Clique no “OK” para continuar.

 Displ_9

Figura 9: Aviso de que no modo de avaliação, o código fica limitado a 2K

 Displ_10

Figura 10: Modo Debug de operação

Observe que já estão destacados os painéis de monitoramento do Timer 0,  do Port 1, cujo bit 1 deverá ser alternado a cada término de contagem do temporizador de software do teste do timer e cujos bits 5, 6 e 7 são usados como linhas de seleção dos 3 displays, e o Port 3, onde aparecem os códigos de cada dígito de 7 segmentos. Nessa simulação, aparecem os números 1, 2 e 3 respectivamente nos displays 0, 1 e 2.

 É possível utilizar as teclas de função F11 para executar o programa passo a passo ou F5 para entrar em execução. Recomendo que você inicie a simulação utilizando o passo a passo para poder observar detalhadamente como que funciona o mecanismo de operação desse programa.

Resumo

Neste artigo técnico foram apresentadas algumas possíveis soluções padronizadas para acionamento de displays de 7 segmentos com auxílio de um timer de hardware. Essas soluções constituem uma biblioteca padronizada para a utilização dos displays de 7 segmentos em microcontroladores da família MCS-51, codificada em C, para ser compilada no programa da Keil. Depois foi desenvolvido um programa exemplo para que você possa simular o que foi apresentado e observar os detalhes dessa implementação.

 Este artigo é o terceiro da série de artigos que abordam algumas funções comuns em projetos de sistemas embarcados de tempo real. Confira os demais artigos (em breve).

Sistemas Operacionais de Tempo Real

Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51

  • Timers – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso dos Timers do MCS-51;
  • Displays de 7 segmentos (este artigo) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos;
  • Teclados Matriciais – É apresentada uma biblioteca desenvolvida em linguagem C para varredura, leitura, debounce, identificação da tecla acionada e desvio para a rotina de tratamento. A forma como as rotinas foram escritas, permitem sua fácil reutilização em outros projetos;
  • Periféricos (Em breve) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso de alguns periféricos, tais como conversores A/D, sensor de temperatura e memórias seriais.

Referências

 [1] http://www.ti.com/lit/ds/sdls111/sdls111.pdf

[2] http://www.nxp.com/documents/data_sheet/74HC_HCT4511_CNV.pdf

[3] http://www.ti.com/lit/ds/symlink/sn54s139.pdf

[4] https://www.keil.com/demo/eval/c51.htm

[5] https://consulteengenheiroeletronico.wordpress.com/2013/09/28/biblioteca-de-funcoes-e-rotinas-padronizadas-em-linguagem-c-para-mcs-51-timers/

[6] http://www.embarcados.com.br/download/Testa_Display.zip

Licença Creative Commons
Esta obra, “Sistemas Operacionais de Tempo Real – Displays de 7 segmentos“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 3.0 Não Adaptada.

Perifericos_1

Introdução

 Este artigo é o último da série sobre rotinas padronizadas, desenvolvidas em C, para o sistema MCS-51 (8051) e para serem compilados no programa da Keil. Nesse contexto é necessário lembrar que o microcontrolador 8051 não possui em seu hardware muitas interfaces dedicadas e de certa forma autônomas para conexão com periféricos externos. Considerando isso, as rotinas dessa biblioteca realizam o acesso diretamente através dos pinos (bits) dos Ports do microcontrolador e a temporização desses procedimentos fica sendo definida implicitamente pelo clock da CPU ou pelos ciclos de máquina das instruções.

 As arquiteturas mais modernas de microcontroladores já possuem hardwares dedicados para a implementação de barramentos de comunicação I2C, saídas PWM, entre outras, o que melhora o rendimento da execução do seu software embarcado, por conta do paralelismo das operações.

 As rotinas apresentadas aqui, não são rotinas de tempo real propriamente ditas, mas funcionam bem como rotinas padronizadas, que podem ser utilizadas em ambientes de tempo real. São rotinas para o acesso a EEPROM serial, aos conversores A/D ADC0838 e AD7730 e ao sensor de temperatura DS1820.

 

Descrição das Rotinas

 As rotinas que serão detalhadas a seguir foram desenvolvidas seguindo as sugestões apresentadas no artigo Boas práticas para o desenvolvimento de software – Parte I no que diz respeito a encapsular algumas funções de acesso aos periféricos.

Rotinas para memórias seriais do tipo EEPROM

A EEPROM serial modelo NM24CXX da Fairchild, que já está obsoleta, mas pode ser substituída pelo componente CAT24CXX da ON Semiconductor. Na Figura 1, pode-se observar o diagrama funcional da EEPROM serial.

Cat24CXX_1Figura 1: Diagrama funcional da EEPROM serial CAT24CXX

Definições

O trecho de código a seguir pode ser inserido num arquivo de definições do tipo *.h.

 Perifericos 1

Observe que no trecho de código acima foram definidos um contador ucContadorTimerEEPROM,  que deverá ser inserido na rotina de interrupção do timer principal, uma constante de inicialização e um bit de sinalização para indicar ao processo no loop principal que a temporização terminou. Esse recurso permite uma temporização virtual de 10 ms e é explicado em detalhes no artigo Sistemas Operacionais de Tempo Real – Timers.

 

Rotina do Timer de 10 ms

Perifericos 2

Rotina de escrita da EEPROM

Perifericos 3

Perifericos 4

Rotina de leitura na EEPROM

Perifericos 5

Perifericos 6

Perifericos 7

.

Rotinas para acesso ao conversor A/D ADC0838

O conversor ADC0838 é um conversor A/D de 8 bits que possui um multiplexador de 8 canais na entrada do conversor. É um componente eletrônico muito robusto e versátil. Na Figura 2, pode-se observar uma aplicação típica para esse componente.

ADC0838Figura 2: Aplicação típica do ADC 0838

Definições

O trecho de código a seguir pode ser inserido num arquivo de definições do tipo *.h.

Perifericos 8

Rotina de leitura do ADC0838

Perifericos 9

Perifericos 10

 .

Rotinas para o conversor A/D AD7730

O conversor A/D AD7730 é um componente de grande precisão e ideal para a medição de sinais extraídos de pontes de strain gages, mais especificamente para a aplicação em balanças de precisão. Algumas características desse componente:

  • Conversor sigma-delta de 24 bits;
  • Resolução de até 1/230.000;
  • Medidas razométricas com relação à fonte;
  • Filtro digital programável;
  • Etc.

Na Figura 3 pode ser observada uma aplicação típica desse componente e alguns módulos internos.

 AD7730_1

Figura 3: Aplicação típica do conversor AD7730

Para se aprofundar nos conceitos de medidas em ponte, recomendo a leitura do artigo técnico Ponte de Wheatstone.

Definições

 O trecho de código a seguir pode ser inserido num arquivo de definições do tipo *.h.

Perifericos 11

Rotina para escrever uma palavra no AD7730

Perifericos 12

Rotina para ler dados do AD7730

Perifericos 13

Rotina para verificar se há dados disponíveis

Perifericos 14

Exemplo de rotina de interrupção gerada pelo conversor AD7730

Perifericos 15Perifericos 16

Rotinas para o termômetro digital DS1820

O termômetro DS1820 é um componente com boa precisão, incrementos de 0,5ºC na faixa de medição de temperaturas entre -55º a +125ºC. Como pode ser observado na Figura 4, trata-se de um termômetro digital, compacto com a interface de comunicação 1-wire (um único fio). Esse componente já está obsoleto e não há reposição direta.

DS1820

Figura 4: Detalhes do componente DS 1820

Definições

O trecho de código a seguir pode ser inserido num arquivo de definições do tipo *.h.

Perifericos 17

Rotina para aguardar n vezes 10 ms

Perifericos 18

Rotina para escrever no DS1820

Perifericos 19

Perifericos 20

Rotina para gerar Reset no Bus do DS1820

Perifericos 21

Rotina para ler do DS1820

Perifericos 22

Resumo

Neste artigo técnico foram apresentadas algumas rotinas padronizadas, codificadas em C, para serem compiladas no programa da Keil. Essas rotinas permitem configurar e acessar alguns periféricos utilizando-se os microcontroladores da família MCS-51. Essas rotinas foram utilizadas em projetos reais e funcionam!

Este artigo é o quinto da série de artigos que abordam algumas funções comuns em projetos de sistemas embarcados de tempo real. Confira os demais artigos.

Sistemas Operacionais de Tempo Real

Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51

  • Timers – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso dos Timers do MCS-51;
  • Displays de 7 segmentos  – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos;
  • Teclados Matriciais  – É apresentada uma biblioteca desenvolvida em linguagem C para varredura, leitura, debounce, identificação da tecla acionada e desvio para a rotina de tratamento. A forma como as rotinas foram escritas, permitem sua fácil reutilização em outros projetos;
  • Periféricos (este artigo) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso de alguns periféricos, tais como conversores A/D, sensor de temperatura e memórias seriais.

Licença Creative Commons
Esta obra, “Sistemas Operacionais de Tempo Real – Alguns Periféricos“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 3.0 Não Adaptada.

 Relogios-660x364

 Introdução

Estava desenvolvendo algumas idéias para um novo artigo técnico, quando encontrei perdida, no fundo de uma gaveta virtual, uma biblioteca de rotinas em C que desenvolvi há algum tempo. É uma preciosidade!!! Eu mesmo já utilizei essas funções em vários projetos. Estou aqui disponibilizando esse material para você.

Vou contar um pouco a história dessa biblioteca. Houve uma época em que o meu trabalho era focado em projetos de desenvolvimento de sistemas dedicados baseados em processadores da família 8051. Desenvolvemos uma célula de carga digital, um sistema de monitoramento ambiental, um mini CLP, um sistema de monitoramento e controle de um processo químico, sistema de controle de elevadores etc. Daí surgiu a ideia de elaborar funções e rotinas padronizadas, pois quase todos esses sistemas tinham alguma coisa em comum, como por exemplo teclas, displays etc. e deveriam operar em tempo real. O objetivo foi diminuir o tempo gasto para o desenvolvimento de um novo projeto. Antes de prosseguir, recomendo a leitura do artigo Sistemas Operacionais de Tempo Real – Introdução, onde são abordados alguns conceitos que serão aplicados neste artigo.

É necessário apresentar aqui alguns esclarecimentos a respeito  da filosofia usada na elaboração dessas rotinas. Eu parti do princípio de que os nossos sistemas são de tempo real e que realizam periodicamente algumas funções rotineiras, tais como verificar um teclado, atualizar displays, administrar LEDs de sinalização, realizar medidas, etc. Outras ações são tomadas por demanda, ou seja, apenas quando ocorrem. Essas demandas podem ser periódicas ou assíncronas (aleatórias). Daí já reconhecemos o primeiro elemento a ser implementado no nosso Sistema Oeracional: um temporizador (Timer). Para quem não sabe, os processadores tradicionais da família 8051 têm apenas 2 temporizadores, enquanto outras versões oferecem pelo menos mais um. Antes de continuar, acho interessante recordarmos a arquitetura dos microcontroladores da família MCS-51 e os modos de operação dos seus temporizadores. Na parte final desse artigo será desenvolvido um pequeno exemplo prático, cujo código poderá ser compilado e simulado. 

TIMERS da família MCS-51

 Para ilustrar o que será abordado aqui, vamos nos referenciar aos microcontroladores de fabricação da ATMEL, com a arquitetura baseada no 8051, cujo documento completo você pode consultar aqui: ATMEL 8051 Microcontrollers Hardware Manual. Na Figura 1 podemos observar a arquitetura interna de um microcontrolador AT89S8253, que continua sendo produzido, mostrando em destaque o bloco dos temporizadores.

 Arquitetura_8253

 Figura 1: Diagrama em blocos da arquitetura interna de um microcontrolador AT89S8253

Sem entrar nos detalhes referentes aos contadores / temporizadores Timer 0 e Timer 1 dessa família de microcontroladores, basta dizer que eles podem ser programados para funcionarem em 4 modos distintos de operação:

  • Modo 0: O temporizador é configurado como um contador de 13 bits, que pode receber um valor inicial e conta para cima. Na transição do valor limite superior 0x1FFF para  0x0000, é acionado um flag de sinalização;
  • Modo 1: Similar ao modo 0, porém é configurado o contador para 16 bits;
  • Modo 2: O temporizador é configurado como um contador de 8 bits, com um registro de 8 bits associado para recarregar o valor inicial automaticamente. Na transição, é acionado um flag;
  • Modo 3: Nesse modo de operação, o Timer 0 opera como 2 contadores distintos de 8 bits, enquanto o Timer 1 nesse modo de operação permite que se congele a contagem.

 Convenções para o uso dos Timers

Para o objetivo de projetar uma biblioteca com rotinas padronizadas, foi definido que o Timer 0 seria o temporizador padrão do sistema e o Timer 1 também poderia ser usado para isso, se acaso não fosse necessário usá-lo para gerar baud-rate da comunicação serial.

O período de interrupção do temporizador deve ser o maior possível e baixo o suficiente para atender às necessidades prioritárias do sistema. Para que se entenda o motivo disso, observe o seguinte exemplo:

 Suponhamos que:

  • Um microcontrolador que, por restrições de sua arquitetura e do oscilador (clock)  utilizado, possa executar no máximo 10.000 instruções por segundo;
  • Uma rotina de interrupção provocada pelo temporizador execute 20 instruções na média a cada interrupção.

Se numa hipótese absurda o temporizador for dimensionado para gerar 500 interrupções por segundo, a rotina de interrupção vai consumir todo o tempo disponível para executar as instruções do microcontrolador (500 x 20 = 10.000)! Se por exemplo esse número puder cair para 50 interrupções por segundo, sem prejudicar a operação do sistema, a rotina de interrupção vai consumir apenas 10% do total disponível (1.000), deixando os outros 90% para as demais atividades do microprocessador.

A compreensão do que foi ilustrado nesse exemplo é fundamental. As rotinas que são executadas com maior frequência devem ser otimizadas para serem executadas no menor tempo possível e na menor frequência possível tembém. Voltando ao exemplo das 500 interrupções, se acaso a rotina de interrupção executasse apenas 18 instruções ao invés das 20, já sobrariam 1.000 instruções por segundo que poderiam ser executadas por outras atividades. Em muitos casos isso é suficiente. Note que para esse exemplo em particular, só analisamos uma das soluções possíveis para viabilizar a operação do sistema. Poderia-se também lançar mão de outros recursos, como por exemplo aumentar a frequência do oscilador do microcontrolador.

Assim a frequência da interrupção do nosso timer deve ser dimensionada de modo que:

  • A função que deverá ser executada com maior frequência possa ser atendida pelas interrupções do timer no menor tempo necessário para isso (e maior possível), definindo assim as especificações do timer de referência do sistema;
  • Outras temporizações mais lentas sejam realizadas como múltiplos da interrupção do timer e implementadas por meio de temporizadores virtuais de software.

Um temporizador virtual de software é uma estrutura no programa em que a cada temporizador é associado um valor inicial, que se traduz num número inteiro de interrupções do Timer 0, e um flag de sinalização. A cada interrupção do Timer 0, o temporizador de software é decrementado e testado se zero. Se for zero, é ligado o flag para avisar que a contagem de software foi terminada e o temporizador é reinicializado para o seu valor inicial. O tratamento do final de contagem é realizado no programa principal, testando-se o flag e reinicializando-o depois.

O timer de referência deverá funcionar no modo 2 de operação. Observe que a programação do Timer 0 depende da frequência de clock do microcontrolador, do fator de divisão do clock, que nas CPUs tradicionais do MCS-51 é de 12 vezes, e da frequência requerida de interrupção. Um último limitante é que o valor inicial do Timer nessa configuração é de no máximo 255 (8 bits). Na biblioteca também foi desenvolvido um padrão para a programação do Timer 1, especialmente se não for usado para gerar baud-rate.

Detalhes da Biblioteca em C

O código em C a seguir foi desenvolvido para o compilador KEIL C51 μVision, na versão de avaliação. Se você quiser testar o programa exemplo que desenvolveremos no final deste artigo, recomendo que você baixe e instale esse programa.  O arquivo de biblioteca com os trechos de código em C para a utilização dos timers de forma padronizada está dividido em segmentos. O primeiro segmento define uma série de constantes, que podem ser ajustadas conforme as especificações do projeto. Veja o trecho do código a seguir.

//*******************************************************************************
//*                                                                             *
//*		ROTINAS PADRONIZADAS PARA USO EM APLICAÇÕES                     *
//*	 	DE SISTEMAS MICROCONTROLADOS (FAMÍLIA 8051)                     *
//*			    (Resp. Engº Puhlmann)                               *
//*                                                                             *
//*			(31/05/2000 - Rev. 14/06/2000)                          *
//*                                                                             *
//*******************************************************************************


//===============================================================================
//=                                                                             =
//=		ROTINAS PADRONIZADAS PARA PROGRAMAÇÃO DOS TIMERS                =
//=                                                                             =
//===============================================================================

//Para manter alguma padronização até na utilização dos timers, vamos definir
// que sempre utilizaremos o Timer 0 para gerar interrupções periódicas, funcionando
// como um relógio interno, para temporizar a todas as funções que necessitem de serem
// executadas com alguma periodicidade. E tb para gerenciar os timers de software, que 
// eventualmente forem necessários
//
//	O Timer 1, será reservado para realizar a geração de Baud Rate
//   

//===============================================================================
//
//	ROTINA DE PROGRAMACAO DO TIMER GLOBAL PARA GERAÇÃO DE TEMPORIZAÇÕES
//				(Timer 0 e Timer 1)
//
// OBS: Utilizar só o Timer 0, para essa função, se for utilizar a interface serial...
//      na serial, utiliza-se o Timer 1, como gerador de Baud Rate
//================================================================================

// Aqui faz-se necessário incluir o "header file" do componente a ser utilizado 

#include <reg51.h>

//----------------------------

#define DESLIGA	0
#define LIGA	1

// Define-se aqui a freqüência de clock da CPU

#define FREQUENCIA_DO_CLOCK_DA_CPU	   12.0e+6   // Hz ----> 12 MHz por exemplo

// Define o pre-scaler

#define FATOR_DE_ESCALA_CLOCK_TIMER    12.0f     // Divide o clock por 12

// Define a freqüência de interrupção do timer

#define FREQUENCIA_DE_INTERRUPCAO_TIMER_0 5.0e+3  // Hz ---- > 5 kHz por exemplo

//--------------

// Definição de variáveis referentes aos timers

//------- Timer 0 ----------

#define MASCARA_CT_0					0xfb

// Definição utilizada apenas quando o timer estiver no modo 2 de operação
// se acaso nao for usado no modo 2, comentar a linha abaixo

#define TIMER0_MODO2					1

#ifdef TIMER0_MODO2

// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_0_MODO_2       (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_0))+ 0.5))

#endif

#define MASCARA_DO_MODO_DO_TIMER_0      0xfc
#define MODO_0_TIMER_0                  0x00
#define MODO_1_TIMER_0                  0x01
#define MODO_2_TIMER_0                  0x02
#define MODO_3_TIMER_0                  0x03

//------------ Timer 1 ------

// No caso de usar-se o timer 1 no modo 2 também, define-se a frequência de interrupção

#define FREQUENCIA_DE_INTERRUPCAO_TIMER_1 5e+3  // Hz, 5 kHz por exemplo

// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 

#define MASCARA_CT_1			0xbf
 
// Definição utilizada apenas quando o timer estiver no modo 2 de operação

#define TIMER1_MODO2					1

#ifdef TIMER1_MODO2

// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_1_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_1))+0.5))

#endif

#define MASCARA_DO_MODO_DO_TIMER_1      0xcf
#define MODO_0_TIMER_1                  0x00
#define MODO_1_TIMER_1                  0x10
#define MODO_2_TIMER_1                  0x20

//******************** Fim das definições das variáveis referentes aos timers **************

Nesse código há alguns parâmetros que precisam ser alterados, conforme o projeto:

  • #define   FREQUENCIA_DO_CLOCK_DA_CPU 12.0e+6 // Hz —->  12 MHz, por exemplo. Inicializar essa constante com o valor do clock do seu microcontrolador;
  • #define   FATOR_DE_ESCALA_CLOCK_TIMER    12.0f     // Divide o clock por 12 (Valor do pre-scaler);
  • #define   FREQUENCIA_DE_INTERRUPCAO_TIMER_0 5e+3  // Hz —- > 5 kHz, por exemplo. Define a frequência da interrupção do timer.

São apenas esses três parâmetros que devem ser inicializados. Não é necessário alterar outras partes do código!

O segundo segmento da biblioteca refere-se às inicializações dos timers, conforme o modo de operação, e os comandos para iniciar a operação do temporizador. Observe que nesse segmento é mostrada a rotina principal (void main(void)) e indicado onde devem ser inseridos os trechos do código.

//******************************************************************************************
//********* O Bloco seguinte refere-se às inicializações, conforme o modo de operação ******
//*********																			  ******

// No bloco principal, onde são realizadas as inicializações globais, ou na rotina de inicialização
// insere-se os seguintes blocos, apenas um, conforme o modo de operação:

void main(void)
{
   .
   .
   .
   .
//********************* Inicialização *************


//************************ TIMER 0	********************************************
//************************ inicio 	*********************************************

//***************************** MODO 0 ******************************************

// Inicializa os bits do timer 0 - 13 bits

TR0   = DESLIGA;						// Desliga Timer
TMOD &= MASCARA_CT_0;					// Seleciona função de "timer"
TMOD &= MASCARA_DO_MODO_DO_TIMER_0;		// Seta M1 e M0 para timer 0 - modo 0
TMOD |= MODO_0_TIMER_0;

//********************************************************************************

//***************************** MODO 1 ******************************************

// Inicializa os bits do timer 0 - 16 bits

TR0   = DESLIGA;
TMOD &= MASCARA_CT_0;					// Seleciona função de "timer"
TMOD &= MASCARA_DO_MODO_DO_TIMER_0;		// Seta M1 e M0 para timer  0 - modo 1
TMOD |= MODO_1_TIMER_0;

//********************************************************************************

//***************************** MODO 2 ******************************************


#define FREQUENCIA_DO_CLOCK_DA_CPU	   12.0e+6   // Hz
#define FREQUENCIA_DE_INTERRUPCAO_TIMER_0 5e+3  // Hz

// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_0_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_0))+0.5))
*/

// Inicializa os bits do timer 0

TR0   = DESLIGA;
TMOD &= MASCARA_CT_0;					// Seleciona função de "timer"

T2CON = 0x00;
TR2   = DESLIGA;
T2MOD &= 0x0f;							// Seleciona função de "timer"


TH0	  = PRESET_TIMER_0_MODO_2;			// Inicializa o preset do contador
TL0   = PRESET_TIMER_0_MODO_2;

TMOD &= MASCARA_DO_MODO_DO_TIMER_0;		// Seta M1 e M0 para timer 0 - modo 2
TMOD |= MODO_2_TIMER_0;


//************************ TIMER 0 	*********************************************
//************************ fim   	*********************************************


//************************ TIMER 1	********************************************
//************************ inicio 	*********************************************


//***************************** MODO 0 ******************************************

// Inicializa os bits do timer 1 - 13 bits

TR1   = DESLIGA;						// Desliga Timer
TMOD &= MASCARA_CT_1;					// Seleciona função de "timer"
TMOD &= MASCARA_DO_MODO_DO_TIMER_1;		// Seta M1 e M0 para timer 1 - modo 0
TMOD |= MODO_0_TIMER_1;

//********************************************************************************

//***************************** MODO 1 ******************************************

// Inicializa os bits do timer 1 - 16 bits

TR1   = DESLIGA;
TMOD &= MASCARA_CT_1;					// Seleciona função de "timer"
TMOD &= MASCARA_DO_MODO_DO_TIMER_1;		// Seta M1 e M0 para timer  1 - modo 1
TMOD |= MODO_1_TIMER_1;

//********************************************************************************

//***************************** MODO 2 ******************************************


#define FREQUENCIA_DO_CLOCK_DA_CPU	   12.0e+6   // Hz
#define FREQUENCIA_DE_INTERRUPCAO_TIMER_1 5e+3  // Hz

// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_1_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_1))+0.5))


// Inicializa os bits do timer 0

TR1   = DESLIGA;
TMOD &= MASCARA_CT_1;					// Seleciona função de "timer"

TH1	  = PRESET_TIMER_1_MODO_2;			// Inicializa o preset do contador
TL1   = PRESET_TIMER_1_MODO_2;

TMOD &= MASCARA_DO_MODO_DO_TIMER_1;		// Seta M1 e M0 para timer 1 - modo 2
TMOD |= MODO_2_TIMER_1;

//************************ TIMER 1 	*********************************************
//************************ fim   	*********************************************

 .
 .
 .
 .

//******************************************************************************************
//*** O bloco seguinte deve ser inserido imediatamente antes do "loop principal ************
//*** ************

 .
 .

//********************************************************************************
//
// TIMER 0
//
// Este bloco deve ser colocado no programa principal, para iniciar a operação do timer


TR0 = LIGA; // Liga o timer
ET0 = LIGA; // Libera a interrupção do timer
EA = LIGA; // Habilita as interrupções

//*******************************************************************************


//********************************************************************************
//
// TIMER 1
//
// Este bloco deve ser colocado no programa principal, para iniciar a operação do timer


TR1 = LIGA; // Liga o timer
ET1 = LIGA; // Libera a interrupção do timer
EA = LIGA; // Habilita as interrupções

//*******************************************************************************
 .
 .
 .

for(;;;)
{
}
 .
 .
 .
 .
 .
}

O terceiro segmento mostra como são definidas as rotinas de interrupção.

//*******************************************************************************************************
//******************************* Rotinas de interrupção dos timers *************************************
//*******************************									*************************************

//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//

void vInterrupcaoTimer0() interrupt 1 
{
}

//*******************************************************************************
//								 TIMER 1 	
//							rotina de interrupção
//

void vInterrupcaoTimer1() interrupt 3 
{
}

EXEMPLO

A seguir vamos desenvolver o nosso programa de exemplo. Nesse programa, será programado o Timer 0 no modo 2 de operação, com o microcontrolador operando com um clock de 4 MHz e uma frequência de interrupção de 1,5 kHz. Confira o código no quadro abaixo.

//***************************************************************************
//**                                                                       **
//**         ROTINA EXEMPLO PARA TESTE DO USO DO TIMER                     **
//**         PARA SISTEMAS OPERACIONAIS DE TEMPO REAL                      **
//**                   (Resp. Eng. Puhlmann)                               **
//**                                                                       **
//**              (27/08/2014 - rev. 28/08/2014)                           **
//**                                                                       **
//***************************************************************************

#include <reg8253.h>                   // AT89S8253

//----------------------------

#define DESLIGA	0
#define LIGA	1

// Define-se aqui a freqüência de clock da CPU

#define FREQUENCIA_DO_CLOCK_DA_CPU	   4.0e+6   // Hz ----> 4 MHz

// Define o pre-scaler

#define FATOR_DE_ESCALA_CLOCK_TIMER    12.0f     // Divide o clock por 12

// Define a freqüência de interrupção do timer

#define FREQUENCIA_DE_INTERRUPCAO_TIMER_0 1.5e+3  // Hz ---- > 1,5 kHz

//--------------

// Definição de variáveis referentes aos timers

//------- Timer 0 ----------

#define MASCARA_CT_0					0xfb

// Definição utilizada apenas quando o timer estiver no modo 2 de operação
// se acaso nao for usado no modo 2, comentar a linha abaixo

// Define o Timer 0 como operando no modo 2
// A conta desse preset tem que dar um número de 0 a 255, senão não funciona... 
 
#define PRESET_TIMER_0_MODO_2          (255 - (unsigned char)((FREQUENCIA_DO_CLOCK_DA_CPU/(FATOR_DE_ESCALA_CLOCK_TIMER * FREQUENCIA_DE_INTERRUPCAO_TIMER_0))+ 0.5))


#define MASCARA_DO_MODO_DO_TIMER_0      0xfc
#define MODO_0_TIMER_0                  0x00
#define MODO_1_TIMER_0                  0x01
#define MODO_2_TIMER_0                  0x02
#define MODO_3_TIMER_0                  0x03


//=============== Fim da definição dos parâmetros do Timer 0 ===========

#define PRESET_TIMER_DE_SOFTWARE        10        // Define o valor inicial do temporizador de software
int nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE;  // Inicializa o temporizador de software com 10
bit bFlagTimerDeSoftware = DESLIGA;               // Inicializa a sinalização de término de contagem



//*******************************************************************************
//								 TIMER 0 	
//							rotina de interrupção
//

void vInterrupcaoTimer0() interrupt 1 
{
	nTimerDeSoftware--;                            // Decrementa o temporizador de software
	if(nTimerDeSoftware == 0)
	{
		bFlagTimerDeSoftware = LIGA;                 // Sinaliza que terminou a temporização de software
		nTimerDeSoftware = PRESET_TIMER_DE_SOFTWARE; // Reinicializa o temporizador
		
	}
}



//================================================================================
//
//                   PROGRAMA PRINCIPAL

void main(void)
{
	int nContadorSemFuncao = 0;
	
	//********************* Inicializações *************
  
	//************************ TIMER 0	********************************************
	// Inicializa os bits do timer 0

	TR0   = DESLIGA;
	TMOD &= MASCARA_CT_0;					// Seleciona função de "timer"

	T2CON = 0x00;
	TR2   = DESLIGA;
	T2MOD &= 0x0f;							// Seleciona função de "timer"


	TH0	  = PRESET_TIMER_0_MODO_2;			// Inicializa o preset do contador
	TL0   = PRESET_TIMER_0_MODO_2;

	TMOD &= MASCARA_DO_MODO_DO_TIMER_0;		// Seta M1 e M0 para timer 0 - modo 2
	TMOD |= MODO_2_TIMER_0;
    
	//******
	
	//********** Fim das Inicializações ******************

		
	//********************************************************************************
    //
    //						   TIMER 0
    //
    // Este bloco deve ser colocado no programa principal, para iniciar a operação do timer


    TR0 = LIGA;								// Liga o timer
    ET0 = LIGA;								// Libera a interrupção do timer
    EA  = LIGA;								// Habilita as interrupções

    //****

	for(;;)                              // Loop principal
	{
		nContadorSemFuncao++;              // Soma um no contador. Essa instrução foi inserida aqui apenas para não dar a impressão que a simulação está parada             
		
		if(bFlagTimerDeSoftware == LIGA)   // Verifica se terminou a temporização por software (10 vezes a interrupção do Timer 0)
		{
			P3_1 = ~P3_1;					           // Inverte o bit 1 da porta 3 - ;
			bFlagTimerDeSoftware = DESLIGA;  // Desliga a sinalização de término
		}
	}
	
}

Simulação do Exemplo

Se você quiser simular o programa exemplo acima e explorá-lo um pouco mais, siga os seguintes passos:

  • Instale o KEIL C51 μVision;
  • Baixe o arquivo Testa_Timer.zip;
  • Instale os arquivos de Testa_Timer.zip num diretório para testes;
  • Navegue até o diretório de testes e acione o arquivo Testa_Timer.uvproj (2 “clickes”)  (Figura 1).

 Diretorio-Projeto

 Figura 1: Arquivos no diretório de teste

Nesse instante deverá abrir o programa Keil e a tela deverá ser a retratada na Figura 2. Esse painel permite navegar no código em C, editá-lo e compilá-lo. Não é necessário fazer isso para realizar a simulação, mas você poderá posteriormente alterar alguns parâmetros do código e testar o programa com as novas alterações.

 Keil_Abriu

  Figura 2: Programa Keil pronto com o programa exemplo carregado

A seguir coloque o programa no modo de Debug (Figura 3, Figura 4 e Figura 5) para que se possa iniciar a simulação.

Keil_Seleciona_Debug

Figura 3: Selecionando o modo Debug do programa

Antes de entrar no modo de depuração, aparece na tela a mensagem da Figura 4. “Clicke” no  “OK” para continuar.

Keil_warning

Figura 4: Aviso de que no modo de avaliação, o código fica limitado a 2K

 Keil_Debug

 Figura 5: Modo Debug de operação

Observe que já estão destacados os painéis de monitoramento do Timer 0 e do Port 3, cujo bit 1 deverá ser alternado a cada término de contagem do temporizador de software. As duas variáveis principais (bFlagTimerDeSoftware e nTimerDeSoftware) poderão ser monitoradas na janela Watch 1 durante a simulação.

É possível utilizar as teclas de função F11 para executar o programa passo a passo ou F5 para entrar em execução. Recomendo que você inicie a simulação utilizando o passo  a passo para poder observar detalhadamente como que funciona o mecanismo de operação desse programa.

Resumo

Neste artigo técnico foram apresentados alguns conceitos relativos à utilização de temporizadores de hardware de um microcontrolador associados a temporizadores de software para a implementação de arquiteturas de software típicas de  sistemas operacionais de tempo real. Também foi apresentada e explicada uma biblioteca padronizada para a utilização dos timers de microcontroladores da família MCS-51, codificada em C, para ser compilada no programa da Keil. Depois foi desenvolvido um programa exemplo para que você possa simular o que foi apresentado e observar os detalhes dessa implementação.

Este artigo é o segundo de série de artigos que abordam algumas funções comuns em projetos de sistemas embarcados de tempo real. Confira os demais artigos (em breve).

Sistemas Operacionais de Tempo Real

Bibliotecas de funções e rotinas padronizadas em linguagem C para MCS-51

  • Timers (este artigo) – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso dos Timers do MCS-51.
  • Displays de 7 segmentos – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso em displays de 7 segmentos.
  • Teclados Matriciais – É apresentada uma biblioteca desenvolvida em linguagem C para varredura, leitura, debounce, identificação da tecla acionada e desvio para a rotina de tratamento. A forma como as rotinas foram escritas, permitem sua fácil reutilização em outros projetos.
  • Periféricos – É apresentada uma biblioteca desenvolvida em linguagem C para a inicialização e o uso de alguns periféricos, tais como conversores A/D, sensor de temperatura e memórias seriais.

Licença Creative Commons
Esta obra, “Sistemas Operacionais de Tempo Real – Timers“, de Henrique Frank W. Puhlmann, foi licenciada sob uma Licença Creative Commons Atribuição-NãoComercial-CompartilhaIgual 3.0 Não Adaptada.