Pesquise

25 de dez. de 2013

[PIC Tutorial] Blink

Decidi retomar meus projetos com PIC, porém utilizando um programa diferente. Desde o meu primeiro contato com PICs que eu usei o PICC CCS, que é pago. Daí, sempre pensava em adotar uma alternativa gratuita, mas sempre adiei a mudança, até hoje. Agora, estou decidido a aprender e desenvolver os projetos no MPLAB X, a IDE da própria Microchip, fabricante dos PICs. Quem sabe eu também faça a migração dos meus projetos antigos para ela.

Baixadas e instaladas as ferramentas, tanto o MPLAB X IDE quanto o MPLAB XC8 (compilador para PICs de 8-bits), tive dificuldades para produzir meu primeiro código teste. Não sei se procurei direito, mas não achei nenhum "dummy's guide", ou um exemplo básico para ao menos compilar alguma coisa. Na verdade, depois de começar a ler o manual do compilador, resolvi procurar, e acabei encontrando este ótimo tutorial, que expande o que estou falando aqui.


Antes de prosseguir, vale ressaltar que este tutorial assume que você tem conhecimentos básicos de programação, conhece alguns termos de PIC/Microcontroladores (Arduino ajuda), e de eletrônica digital (lógica booleana). Para aqueles que não conhecem alguns termos de PICs, pretendo fazer um breve post explicando, ou então indicar alguma bibliografia (em breve).

Vamos à prática. Para este exemplo, utilizei o PIC 16F628A. Seguem os passos para a crição do projeto. Com o MPLAB X aberto:
  1. File > New Project...
  2. Categories: Microchip Embedded, Projects: Standalone Project
  3. Device: PIC16F628A
  4. Debug Header: none
  5. Hardware Tools: Simulator (ou qualquer outra, tanto faz)
  6. Compiler: XC8
  7. Project Name: Blink
  8. Clique em Finish
Na árvore do projeto (à esquerda), clique com o botão direito em Source Files > New > C Source File > File name: main, e clique em Finish. Será gerado um arquivo em branco. Vamos, então, configurar o nosso PIC. No menu Window, vá em PIC Memory Views > Configuration Bits, e ajuste as configurações como na imagem abaixo:


Explicando algumas configurações:
  • FOSC = INTOSCIO: seleciona o oscilador interno como fonte de clock, e libera os pinos A6 e A7 para IO
  • WTDE = OFF: desabilita o Watchdog
  • PWRTE = OFF: desabilita o Power-up timer
  • MCLRE = OFF: libera o pino A5 para entrada (ON seta como pino de Reset)
  • BOREN = OFF: desabilita o Brown-out detect
  • LVP = OFF: libera o pino B4 para IO
Ao clicar em Generate Source Code, será gerado o código base para o programa. Copie-o para o arquivo main.c. Você pode ver que ao lado de cada configuração há um comentário explicando. Se quiser poupar espaço, pode apagar os comentários e colocar todas as configurações em uma linha só, separando-as com vírgula.

Código gerado (com alguns comentários removidos):

#include <xc.h>

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable bit (PWRT disabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has digital I/O function, HV on MCLR must be used for programming)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)

Configuração em uma linha só:

#include <xc.h>

#pragma config FOSC = INTOSCIO, WDTE = OFF, PWRTE = OFF, MCLRE = OFF, BOREN = OFF, LVP = OFF, CPD = OFF, CP = OFF

Se quiser manter organizado, você pode também criar um arquivo config.h para colocar estas configurações, e depois fazer o include no main.c. Para criar o arquivo config.h, clique com o botão direito em Header Files (árvore do projeto) > New > C Header file. Pode apagar o conteúdo e colocar o código gerado.

No arquivo main.c criaremos a função main, que será executada pelo microcontrolador. Segue o código:

int main(void) {

    TRISAbits.TRISA1 = 0;       // pin mode: 0 = saída, 1 = entrada
    PORTAbits.RA1 = 1;          // escreve no pino
    
    while(1) {
        PORTAbits.RA1 = ~PORTAbits.RA1;      // inverte o valor
        __delay_ms(1000);       // fica 1000ms sem fazer nada
    }

    return 0;
}

Assim como no Arduino, antes de usar um pino você deve configurá-lo para atuar como entrada ou saída de dados. Isto é feito através dos bits TRIS, associados a cada pino de IO do PIC. Neste caso, TRISA é o registrador de configuração dos bits da porta A. Para acessar os bits individualmente, adiciona-se 'bits' ao final do nome do registrador, e indica-se o bit que se deseja alterar, no caso TRISA1. Todos esses nomes estão no datasheet do PIC. Para simplificar, você pode também acessar os bits apenas com o nome após o ponto:

int main(void) {

    TRISA1 = 0;       // pin mode: 0 = saída, 1 = entrada
    RA1 = 1;          // escreve no pino
    
    while(1) {
        RA1 = ~RA1;      // inverte o valor
        __delay_ms(1000);       // fica 1000ms sem fazer nada
    }

    return 0;
}

Para "escrever" no pino, utiliza-se também registradores do PIC: PORTX, onde X é a letra da porta (A, B, C, ...). Da mesma forma que o TRIS, pode-se tanto configurar todos os bits de uma vez, quanto escrever um por um.

Para gerar um delay, a biblioteca padrão CCI (Common C Interface) provê três macros: _delay, __delay_ms e __delay_us. A primeira recebe o valor de ciclos, a segunda e a terceira em ms e us.  Vale ressaltar que o tempo de delay não é preciso. Como o próprio guia do compilador explica, "If an accurate delay is required, or if there are other tasks that can be performed during the delay, then using a timer to generate an interrupt is the best way to proceed".

Assim, o código completo pode ser visto a seguir:

#include "config.h"

#define _XTAL_FREQ 4000000      // necessário para as funções de delay

int main(void) {

    TRISA1 = 0;       // pin mode: 0 = saída, 1 = entrada
    RA1 = 1;          // escreve no pino
    
    while(1) {
        RA1 = ~RA1;      // inverte o valor atual
        __delay_ms(1000);       // fica 1000ms sem fazer nada
    }

    return 0;
}

Com o código pronto, vá no menu Run > Clean and build project. O arquivo .hex será gerado na pasta dist\default\production, dentro da pasta do projeto (por padrão em C:\Users\<usuário>\MPLABXProjects\<nome-do-projeto>.X no Windows 7). Para simular ou montar, o circuito é este aqui (a alimentação está implícita):


Para fins de comparação, o código fonte para Arduino é:


int led = 13;

void setup() {
  pinMode(led, OUTPUT);    
}

void loop() {
  digitalWrite(led, HIGH);
  delay(1000);
  digitalWrite(led, LOW);
  delay(1000);
}

Observe que a parte de configuração do microcontrolador é omitida, e que a linguagem é bem mais amigável e intuitiva. Provavelmente este é um dos motivos para o Arduino ser mais popular do que os PICs.

Observa-se que os bits de configuração variam de acordo com o PIC escolhido. Para mais detalhes, consulte o datasheet do PIC que você pretende utilizar.

Downloads

MPLAB X IDE: http://www.microchip.com/mplabx-ide-windows-installer
MPLAB XC8 Compiler (para as famílias PIC12, PIC16 e PIC18): http://www.microchip.com/mplabxc8windows
Datasheet do PIC 16F628A: http://ww1.microchip.com/downloads/en/DeviceDoc/40044G.pdf

Nenhum comentário:

Postar um comentário