Como ficar comparando botão em pic 18f4520

Tempo de leitura: 9 minutes

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 vamos aprender 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 aprender mais.

Os Timers 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 “dump”. 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,

  1. 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.
  2. O atraso não será preciso em comparação com o uso de temporizadores.
  3. 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 Crystal usado.

Temporizadores do microcontrolador PIC:

Fisicamente, o temporizador é um registrador cujo valor está continuamente aumentando para 255, e então ele 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 nossa aplicação. 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, Prescaler, Timer interrupts e Focs. Agora, vamos ver o que cada um realmente significa. Como disse 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. O intervalo 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 prescaler for 64, para cada 64 pulsos o Timer será incrementado em 1.

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. Essa interrupção é chamada de interrupção do temporizador. 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.

Como ficar comparando botão em pic 18f4520

Agora, com esses princípios em mente, vamos dar uma olhada em nosso programa fornecido no final da seção Código.

Está tudo bem se você não obteve o programa, mas se você 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 permite PULL UPs TMR0=100; //Carrega o valor de tempo para 0,0019968s; delayValue pode estar entre 0-256 apenas TMR0IE=1; //Habilita o bit de interrupção do temporizador no registro PIE1 GIE=1; //Habilitar interrupção global PEIE=1; //Habilita a interrupção periférica /***********______***********/

Para entender isso, temos que olhar para o Registro de OPÇÕES em nossa ficha PIC.

Como ficar comparando botão em pic 18f4520

Conforme discutido no tutorial anterior, o bit 7 é usado para habilitar o resistor de 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

Como ficar comparando botão em pic 18f4520

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 fazendo 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.

Delay = ((256-REG_val)*(Prescal*4))/Fosc

A fórmula acima é usada para calcular o valor do Delay.

Onde

REG_val = 100;

Prescal = 64

Fosc = 20000000

Este cálculo dá,

Delay = 0,0019968s

O próximo conjunto de linhas é definir as portas de E/S.

/*****Configuração de porta para I/O******/ TRISB0=1; //Instrua o MCU que o pino 0 da PORTB é usado como entrada para o botão 1. TRISB1=1; //Instrua o MCU que o pino 1 da PORTB é usado como entrada para o botão 1. TRISD = 0x00; //Instrua o MCU que todos os pinos na PORTA D são emitidos PORTD=0x00; //Initialize all pins to 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.

while(1) { count =0; //Não execute o cronômetro enquanto estiver no loop principal //*******Obtenha o número do Delay de usor****////// if (RB0==0 && flag==0) //Quando a entrada é fornecida { get_scnds+=1; //get_scnds=get_scnds+1//Variável de incremento flag=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 delay****////// while (RB1==0) { PORTD = 0b00000001<<i; //LED shift esquerdo por i if(hscnd==get_scnds) //Se o tempo requerido for alcançado { i+=1; //Mova para o próximo LED após o definido Delay hscnd=0; } flag=2; } if (flag==2 && RB1==1) //Reinicie o timer se o botão estiver alto novamente { get_scnds=0;hscnd=0;i=0; PORTD=0; //Desligue todos os LEDs } /***********______***********/

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á passou meio segundo, então incrementamos hscnd em 1 e inicializamos a contagem para zero.

void interrupt timer_isr() { if(TMR0IF==1) //A sinalização do cronômetro foi acionada devido ao estouro do cronômetro { TMR0 = 100; //Carregar o valor do temporizador TMR0IF=0; //Limpar sinalizador de interrupção do temporizador count++; } if (count == 250) { hscnd+=1; //hscnd será incrementado a cada meio segundo count=0; } }

Portanto, usamos esse valor e o 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:

Como ficar comparando botão em pic 18f4520

Adicione um botão à nossa placa de LED anterior e nosso hardware estará pronto para funcionar. Deve ser parecido com isto:

Como ficar comparando botão em pic 18f4520

Depois que a conexão for concluída, carregue o código e verifique a saída. Se você tiver qualquer problema, use a seção de comentários.

Código

// CONFIG #pragma config FOSC = HS // Bits de seleção do oscilador (oscilador HS) #pragma config WDTE = OFF // Bit de ativação do temporizador de watchdog (WDT desativado) #pragma config PWRTE = ON // Bit de ativação do temporizador de inicialização (PWRT ativado) #pragma config BOREN = ON // Bit de habilitação de redefinição de Brown-out (BOR habilitado) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 é digital I / O, HV em MCLR deve ser usado para programação) #pragma config CPD = OFF // Bit de proteção de código de memória EEPROM de dados (proteção de código EEPROM de dados desativada) #pragma config WRT = OFF // Bits de habilitação de gravação da memória do programa Flash (proteção contra gravação desligada; toda a memória do programa pode ser gravada pelo controle EECON) #pragma config CP = OFF // Bit de proteção de código de memória de programa Flash (proteção de código desativada) // #pragma config statements should precede project file includes. // Use project enums instead of #define for ON and OFF. #include <xc.h> #define _XTAL_FREQ 20000000 //TIMER0 8-bit $$RegValue = 256-((Delay * Fosc)/(Prescalar*4)) delay in sec and Fosc in hz //FORMULA to calculate Delay //Delay = ((256-REG_val)*(Prescal*4))/Fosc char hscnd = 0; int count = 0; char get_scnds =0; char flag =0; char i=0; void interrupt timer_isr() { if(TMR0IF==1) // Timer flag has been triggered due to timer overflow { TMR0 = 100; //Load the timer Value TMR0IF=0; // Clear timer interrupt flag count++; } if (count == 250) { hscnd+=1; // hscnd will get incremented for every half second count=0; } } void main() { /*****Port Configuration for Timer ******/ OPTION_REG = 0b00000101; // Timer0 with external freq and 64 as prescalar // Also Enables PULL UPs TMR0=100; // Load the time value for 0.0019968s; delayValue can be between 0-256 only TMR0IE=1; //Enable timer interrupt bit in PIE1 register GIE=1; //Enable Global Interrupt PEIE=1; //Enable the Peripheral Interrupt /***********______***********/ /*****Port Configuration for I/O ******/ TRISB0=1; //Instruct the MCU that the PORTB pin 0 is used as input for button 1. TRISB1=1; //Instruct the MCU that the PORTB pin 1 is used as input for button 1. TRISD = 0x00; //Instruct the MCU that all pins on PORT D are output PORTD=0x00; //Initialize all pins to 0 /***********______***********/ while(1) { count =0; //Do not run timer while in main loop //*******Get the number delay from user****////// if (RB0==0 && flag==0) //When input given { get_scnds+=1; //get_scnds=get_scnds+1//Increment variable flag=1; } if (RB0==1) //To prevent continuous incrementation flag=0; /***********______***********/ //*******Execute sequence with delay****////// while (RB1==0) { PORTD = 0b00000001<<i; //Left shit LED by i if(hscnd==get_scnds) //If the required time is reached { i+=1; //Move to next LED after the defined Delay hscnd=0; } flag=2; } if (flag==2 && RB1==1) //Reset timer if button is high again { get_scnds=0;hscnd=0;i=0; PORTD=0; //Turn off all LEDs } /***********______***********/ } }

Visits: 1 Visits: 1108731