Piscando LED com PIC12F675 e MPLAB X

Posted by

Hoje usaremos o PIC12F675 e o MPLAB X para piscar um LED, usando interrupções Timer0 em vez da função delay(). O compilador que estou usando é o XC8 instalado junto com o MPLAB X 6.20, o programador é o (agora aposentado, 2024?) PICkit3. Isso faz parte de um projeto maior meu, onde uso o PIC12F675 para criar um timer de ovo/pomodoro (15/30/45/60 minutos) que emite luz e som quando o tempo é atingido.

A ideia é ensinar a você o passo a passo completo de como implementar uma interrupção de timer no PIC12F675 (Timer0), enquanto usa essa interrupção para piscar um LED em um intervalo conhecido. Estamos configurando todos os registradores necessários, cujos valores mostrarei a você aos poucos.

A placa de circuito que vou usar está na imagem abaixo, como dito, é um pomodoro/egg timer contendo dois botões de pressão, um LED e um buzzer. Ele é alimentado por um conector micro USB e possui um conector de programação de 5 pinos.

placa com PIC12F675 e LED
Placa de temporizador com PIC12F675

Diagrama esquemático

Precisamos apenas de dois componentes além do próprio PIC12F675: um resistor de 1k e um LED (qualquer cor). Isso se deve ao fato de que estamos usando o oscilador interno do PIC como clock, e nenhum pino como master clear. Então, tudo o que precisamos é VCC (5V), GND e o LED + resistor no pino GP5 (pino 2). No meu caso, estou recebendo energia de um cabo USB, como visto na imagem abaixo.

Diagrama esquemático para piscar um LED com PIC
Diagrama esquemático para piscar um LED com PIC

Todos os outros componentes presentes na minha placa de circuito não serão usados ​​neste tutorial, apenas o LED, o resistor e os 5V do micro USB.

Programando o microcontrolador PIC

Fiz uma série de vídeos sobre como configurar o software MPLAB X IDE, assista aqui (em Inglês). Você pode ver abaixo a maneira como conectei meu PIC12F675 ao programador PICkit3, são necessários cinco fios: +5V (VCC), GND, master clear (MCLR), data (PGD) e clock (PGC).

Como gravar o PIC12F675 com PICkit3
Como gravar o PIC12F675 com PICkit3

Por padrão, o programador PICkit3 não fornece energia para o PIC que está sendo programado, então você teria que fornecer 5 V externamente (caso contrário, a programação falha). Mas o MPLAB X tem uma configuração (uma caixa de seleção) onde você pode fazer o PICkit3 fornecer tal voltagem, você pode até selecionar qual voltagem você quer.

Na minha experiência com o PIC12F675, qualquer voltagem abaixo de 3,6 V não funcionará (para programação), então eu sempre seleciono o padrão 5 V. Para habilitar tal opção, no software MPLAB X eu vou em “Arquivo > Propriedades do projeto”.

Menu "propriedades de projeto"
Menu “propriedades de projeto”

À esquerda há uma janela chamada “Categorias”, clique uma vez em “PICkit3”. Depois, na parte superior da tela, no menu “Categorias de opções”, selecione “Energia”.

Opções de energização do PICkit3
Opções de energização do PICkit3

Agora marque “Power target circuit from PICkit3” e selecione 5V (pelo menos para este PIC12F675, o seu pode exigir voltagem diferente). Então clique em “Apply” e “OK”.

Seleção de opções de energização
Seleção de opções de energização

Agora, da próxima vez que você clicar em compilar e baixar, nosso PIC será alimentado e programado pelo PICkit3, sem necessidade de alimentação externa.

O código/firmware

Para ser completamente honesto com você, há várias maneiras de usar um timer para piscar um LED, o PIC12F675 tem dois timers, você pode usar interrupções ou não e assim por diante. Eu tenho o compilador XC8 instalado na minha máquina (além do MPLAB X), então pesquisei na internet por código que usasse tal compilador.

Na verdade, encontrei um monte (cerca de 10) de códigos-fonte diferentes (que faziam exatamente o que eu queria), mas nenhum funcionou na primeira tentativa para mim. Todos exigiram modificações ou não funcionaram imediatamente. O que eu escolhi e trabalhei para ele é este, tendo que modificar principalmente o cabeçalho da função de interrupção para ficar assim:

void __interrupt() isr() //interruption vector
{ 

}

Os fusíveis (brown-out, master clear, etc.) são assim:

#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-Up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF         // Data Code Protection bit (Data memory code protection is enabled)

Agora dentro da função principal na primeira inicialização eu configuro todos os registradores necessários, começando pelo TRISIO (todos os pinos são saídas):

TRISIO = 0b000000;

Option_reg é configurado desta forma (apenas bits importantes são mostrados): bit 7 pull-ups desabilitados, bit 5 relógio de ciclo de instrução interno (CLKOUT), bit 3 prescaler é atribuído ao módulo TIMER0, bits 2, 1 e 0 prescaler de 256:

OPTION_REG = 0b10000111;

O bit 7 do registro INTCON habilita todas as interrupções não mascaradas, o bit 6 habilita todas as interrupções periféricas não mascaradas, o bit 5 habilita a interrupção TMR0 e os outros bits não são importantes:

INTCON = 0b11100000;

Agora, para definir o tempo de piscada, primeiro fazemos com que o registrador OSCCAL tenha a frequência máxima possível, que vem do oscilador interno em 4MHz:

OSCCAL = 0b11111111;

A propósito, o datasheet do PIC12F6275 está aqui se você quiser acompanhar. Como este PIC está rodando a 4 MHz, sua frequência útil interna é de 1 MHz. Isso nos dá um temporizador de ciclo completo de 1 microssegundo. Como o Timer0 é um temporizador de 8 bits, há 256 “etapas” antes que ele transborde. Além disso, nosso prescaler é 256, então nosso tempo de estouro do timer0 é 256 * 256us * 1us = 65536 microssenconds, ou 65,536 milissegundos.

Então, eu crio uma variável que incrementa toda vez que ocorre uma interrupção, até oito. Isso ocorre porque 65,536 ms * 8 = 524,2 milissegundos. Então, a cada 524,2 ms, ocorre uma alternância de LED.

Código completo e testes

O código completo está abaixo, comentado para você. Lembre-se de que estamos usando o MPLAB X 6.20 IDE, o compilador XC8 e o programador PICkit3. Além do LED, também joguei um buzzer para fazer algum barulho na mesma frequência.

/*
 Based on this code: https://microcontroladores-c.blogspot.com/2014/09/timer0-com-pic12f675.html
 */
#include <stdio.h>
#include <stdlib.h>
#include <xc.h>
#define _XTAL_FREQ 4000000

#define LED GP5
#define Buzzer GP2
/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////
#pragma config FOSC = INTRCIO   // Oscillator Selection bits (INTOSC oscillator: I/O function on GP4/OSC2/CLKOUT pin, I/O function on GP5/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-Up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // GP3/MCLR pin function select (GP3/MCLR pin function is digital I/O, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config CP = OFF         // Code Protection bit (Program Memory code protection is disabled)
#pragma config CPD = OFF         // Data Code Protection bit (Data memory code protection is enabled)


volatile uint8_t counter= 0;

void __interrupt() isr()//interrupt vector
{   
    counter++;
    if(counter == 8){
        counter= 0;
        LED = ~LED;
        Buzzer= ~Buzzer;    
        
    }
    
    TMR0IF = 0;//  clear timer0 interrupt flag
    TMR0 = 0;// zeroes timer 0 counting, so that it couts from 256 down to 0 again
}


//////////////////////////////////////////////////////Main routine///////////////////////////////////////////////////////////////
void main(void) {
    TRISIO = 0b000000;// all outputs
    CMCON = 7;// disable comparators
    ANSEL = 0;//no analog ports
    WPU = 0X00;// pull ups disabled
    TMR0 = 0;
    OSCCAL = 0b11111111;// internal oscillator to max frequency
    OPTION_REG = 0b10000111;
    INTCON = 0b11100000;
    
    
    Buzzer= 1;
    
    while(1)
    {
        
        
    }//infinite loop

}

Ative as legendas do vídeo:

Quer ver também como se piscar um LED com o Raspberry Pi Pico? clica aqui.

Uma resposta

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *