- Por que Timer quando temos Delay ()?
- Temporizadores do microcontrolador PIC:
- Explicação de programação e trabalho:
- Diagrama de circuito e simulação Proteus:
Este será o quinto tutorial em nossa Série de Tutoriais PIC, que o ajudará a aprender e usar Timers em PIC16F877A. Em nossos tutoriais anteriores, tínhamos começado com Introdução ao PIC e MPLABX IDE, então escrevemos nosso primeiro programa PIC para piscar o LED usando PIC e então fizemos uma sequência de piscar de LED usando a função de atraso no microcontrolador PIC. Agora vamos usar a mesma sequência de LED piscando que usamos no hardware do tutorial anterior e com isso aprenderemos como usar temporizadores em nosso PIC MCU. Acabamos de adicionar mais um botão na placa de LED para este tutorial. Vá até o tutorial para saber mais.
Os temporizadores são um dos cavalos de batalha importantes para um programador embarcado. Cada aplicativo que projetamos envolverá de alguma forma um aplicativo de temporização, como ligar ou desligar algo após um intervalo de tempo especificado. Ok, mas por que precisamos de temporizadores quando já temos macros de atraso (__delay_ms ()) fazendo a mesma coisa !!
Por que Timer quando temos Delay ()?
Uma macro de atraso é chamada de atraso de “despejo”. Porque durante a execução da função Delay, o MCU fica no dump apenas criando um delay. Durante este processo, o MCU não pode escutar seus valores ADC ou ler qualquer coisa de seus Registradores. Portanto, não é aconselhável usar funções de retardo, exceto para aplicações como LED piscando, onde o retardo de tempo não precisa ser preciso ou longo.
As macros de atraso também têm as seguintes desvantagens,
- O valor do atraso deve ser uma constante para macros de atraso; não pode ser alterado durante a execução do programa. Portanto, ele permanece definido pelo programador.
- O atraso não será preciso em comparação com o uso de temporizadores.
- Valores maiores de atrasos não podem ser criados usando macros, por exemplo, um atraso de meia hora não pode ser criado por macros de atraso. O atraso máximo que pode ser usado é baseado no oscilador de cristal usado.
Temporizadores do microcontrolador PIC:
Fisicamente, o temporizador é um registrador cujo valor aumenta continuamente para 255, e então começa tudo de novo: 0, 1, 2, 3, 4… 255…. 0, 1, 2, 3……etc.
O PIC MCU PIC16F877A tem três Módulos de temporizador. Eles são nomes como Timer0, Timer1 e Timer2. O Timer 0 e o Timer 2 são Timers de 8 bits e o Timer 1 é um Timer de 16 bits. Neste tutorial, usaremos o Timer 0 para nosso aplicativo. Assim que entendermos o Timer 0, será fácil trabalhar no Timer 1 e no Timer 2 também.
O temporizador / contador do módulo Timer0 tem os seguintes recursos:
- Cronômetro / contador de 8 bits
- Legível e gravável
- Prescaler programável por software de 8 bits
- Seleção de relógio interno ou externo
- Interromper no estouro de FFh às 00h
- Seleção de borda para relógio externo
Para começar a usar um cronômetro, devemos entender alguns dos termos sofisticados, como cronômetro de 8 bits / 16 bits, pré-escala, interrupções do cronômetro e Focs. Agora, vamos ver o que cada um realmente significa. Como dito anteriormente, existem os temporizadores de 8 e 16 bits em nosso PIC MCU, a principal diferença entre eles é que o temporizador de 16 bits tem uma resolução muito melhor que o temporizador de 8 bits.
Prescaler é um nome para a parte de um microcontrolador que divide o relógio do oscilador antes que ele alcance a lógica que aumenta o status do temporizador. A faixa do id do prescaler é de 1 a 256 e o valor do Prescaler pode ser definido usando o Registro OPTION (o mesmo que usamos para resistores pull up). Por exemplo, se o valor do divisor 64 é, em seguida, para cada 64 th pulsar o temporizador será incrementado de um.
Conforme o cronômetro aumenta e quando atinge seu valor máximo de 255, ele irá disparar uma interrupção e inicializar-se em 0 novamente. Esta interrupção é chamada de Interrupção do Timer. Esta interrupção informa ao MCU que este tempo específico foi interrompido.
O Fosc significa Frequency of the Oscillator, é a frequência do Cristal usado. O tempo necessário para o registro do Timer depende do valor do Prescaler e do valor do Fosc.
Explicação de programação e trabalho:
Neste tutorial, definiremos dois botões como duas entradas e 8 LED como 8 saídas. O primeiro botão será usado para definir o atraso de tempo (500ms para cada toque) e o segundo botão será usado para iniciar a sequência do cronômetro piscando. Por exemplo, se o primeiro botão for pressionado três vezes (500 * 3 = 1500ms), o atraso será definido para 1,5 seg. E quando o botão dois for pressionado, cada LED será LIGADO e DESLIGADO com o atraso de tempo predefinido. Confira o vídeo de demonstração no final deste tutorial.
Agora, com esses princípios em mente, vamos dar uma olhada em nosso programa fornecido no final da seção Código.
Tudo bem se você não conseguiu o programa, mas se sim !! Dê a si mesmo um cookie e descarte o programa para aproveitar sua saída. Para outros, dividirei o programa em partes significativas e explicarei o que está acontecendo em cada bloco.
Como sempre, as primeiras linhas do código são as definições de configuração e os arquivos de cabeçalho, não vou explicar isso, pois já fiz isso em meus tutoriais anteriores.
A seguir, vamos pular todas as linhas e pular direto para a função void main, dentro da qual temos a configuração PORT para o Timer0.
void main () {/ ***** Configuração de porta para temporizador ****** / OPTION_REG = 0b00000101; // Timer0 com freq externa e 64 como prescalar // Também habilita PULL UPs TMR0 = 100; // Carrega o valor de tempo para 0,0019968s; delayValue pode estar entre 0-256 somente TMR0IE = 1; // Habilita o bit de interrupção do temporizador no registro PIE1 GIE = 1; // Habilita interrupção global PEIE = 1; // Habilite a interrupção periférica / *********** ______ *********** /
Para entender isso, temos que olhar o Registro de OPÇÕES em nossa ficha PIC.
Conforme discutido no tutorial anterior, o bit 7 é usado para habilitar o resistor pull up fraco para o PORTB. Observe a figura acima, o bit 3 é definido como 0 para instruir o MCU que o seguinte prescaler que está sendo definido deve ser usado para o Timer e não para o WatchDogTimer (WDT). O modo temporizador é selecionado apagando o bit 5 T0CS
(OPTION_REG <5>)
Agora, os bits2-0 são usados para definir o valor do prescaler para o temporizador. Conforme mostrado na tabela acima, para definir um valor de prescaler de 64, os bits devem ser definidos como 101.
A seguir, vamos dar uma olhada nos registros associados ao Timer0
O Timer começará a aumentar uma vez configurado e transbordará após atingir um valor de 256, para habilitar a interrupção do Timer durante este ponto, o registro TMR0IE deve ser configurado alto. Visto que o próprio Timer 0 é um periférico, temos que habilitar a Interrupção Periférica tornando PEIE = 1. Finalmente, temos que habilitar a Interrupção Global para que o MCU seja notificado sobre a Interrupção durante qualquer operação, isto é feito tornando GIE = 1.
Atraso = ((256-REG_val) * (Prescal * 4)) / Fosc
A fórmula acima é usada para calcular o valor de Atraso.
Onde
REG_val = 100;
Prescal = 64
Fosc = 20000000
Este cálculo dá, Atraso = 0,0019968s
O próximo conjunto de linhas é definir as portas de E / S.
/ ***** Configuração de porta para E / S ****** / TRISB0 = 1; // Instrui o MCU que o pino 0 da PORTB é usado como entrada para o botão 1. TRISB1 = 1; // Instrui o MCU que o pino 1 da PORTB é usado como entrada para o botão 1. TRISD = 0x00; // Instrui o MCU que todos os pinos na PORTA D têm saída PORTD = 0x00; // Inicialize todos os pinos para 0 / *********** ______ *********** /
Este é o mesmo do nosso tutorial anterior, pois estamos usando o mesmo hardware. Exceto que adicionamos outro botão como entrada. Isso é feito pela linha TRISB1 = 1.
Em seguida, de dentro para fora do loop while infinito, temos dois blocos de código. Um é usado para obter a entrada do temporizador do usuário e o outro para executar a sequência de atraso sobre os LEDs. Eu os expliquei usando comentários em cada linha.
enquanto (1) {contagem = 0; // Não execute o cronômetro enquanto estiver no loop principal // ******* Obtenha o número de atraso do usuário **** ////// if (RB0 == 0 && flag == 0) // Quando entrada fornecida {get_scnds + = 1; // get_scnds = get_scnds + http: // Sinalizador de variável de incremento = 1; } if (RB0 == 1) // Para evitar incremento contínuo flag = 0; / *********** ______ *********** /
Uma variável chamada get_scnds é incrementada cada vez que o usuário pressiona o botão 1. Uma variável sinalizadora (definida por software) é usada para manter o processo de incremento até que o usuário remova o dedo do botão.
// ******* Execute a sequência com atraso **** ////// while (RB1 == 0) {PORTD = 0b00000001 <
O próximo bloco entra em ação se o botão dois for pressionado. Uma vez que o usuário já definiu o atraso de tempo necessário usando o botão um e ele foi salvo na variável get_scnds. Usamos uma variável chamada hscnd, esta variável é controlada pelo ISR (Rotina de serviço de interrupção).
A rotina de serviço de interrupção é uma interrupção que será chamada toda vez que o Timer0 estourar. Vamos ver como ele está sendo controlado pelo ISR no próximo bloco, como queremos aumentar o atraso de tempo em meio segundo (0,5s) a cada pressionamento de botão, então precisamos incrementar a variável hscnd para cada meio segundo. Como programamos nosso temporizador para transbordar a cada 0,0019968s (~ 2 ms), para contar meio segundo a variável de contagem deve ser 250 porque 250 * 2 ms = 0,5 segundo. Então, quando a contagem chega a 250 (250 * 2ms = 0,5 segundo), significa que já se passou meio segundo, então incrementamos hscnd em 1 e inicializamos a contagem para zero.
void interrupt timer_isr () {if (TMR0IF == 1) // O sinalizador do temporizador foi acionado devido ao estouro do temporizador {TMR0 = 100; // Carrega o valor do temporizador TMR0IF = 0; // Limpa a contagem do sinalizador de interrupção do temporizador ++; } if (contagem == 250) {hscnd + = 1; // hscnd será incrementado a cada meio segundo count = 0; }}
Portanto, usamos este valor e comparamos com nosso hscnd e mudamos nosso LED com base no tempo definido pelo usuário. Também é muito semelhante ao último tutorial.
É isso que temos nosso programa entendido e funcionando.
Diagrama de circuito e simulação Proteus:
Como de costume, vamos verificar a saída usando o Proteus primeiro, vinculei aqui os arquivos esquemáticos do Proteus.
Adicione um botão à nossa placa de LED anterior e nosso hardware estará pronto para funcionar. Deve ser parecido com isto:
Depois que a conexão for concluída, carregue o código e verifique a saída. Se você tiver qualquer problema, por favor use a seção de comentários. Verifique também o vídeo abaixo para entender todo o processo.