Curiosity – Explore os pinos de I/O

Curiosity pinos de I/O
Este post faz parte da série Crie projetos com a placa Curiosity

Continuando a sequência de artigos sobre a placa Curiosity da Microchip, neste artigo vamos explorar os pinos de I/Os do PIC16F1619 presentes nela.

Ao final deste artigo o leitor estará apto a utilizar os pinos de I/O para leitura e escrita de sinais digitais.

Pinos de I/O na Curiosity

Os pinos de I/O são os meios pelos quais os microcontroladores se comunicam com o mundo externo. Geralmente podem ser configurados como entradas ou saídas, dessa forma é possível fazer a leitura de teclas (pino como entrada), acionar LEDs (pino como saída), ligar/desligar Reles (pino como saída), por exemplo.

Os pinos presentes no microcontrolador estão agrupados em ports, geralmente com 8 ou menos pinos, conforme a configuração do microcontrolador. Os ports são identificados como PORTA, PORTB, PORTC, etc. Cada port possui um grupo de registradores para configuração, leitura e escrita, que estudaremos mais adiante.

O PIC16F1619 possui  3 ports: PORTA, PORTB e PORTC. Os pinos geralmente apresentam funções alternativas e são multiplexadas para que se possa realizar diversas funções em um mesmo pino, conforme a necessidade da aplicação. Porém, essas funções são habilitadas com o periférico que utilizará tal pino.

Os pinos são organizados no microcontrolador, conforme seu port e seguindo uma sequência. Por exemplo o pino 0 do PORTA é chamado de RA0, o pino 5 do PORTB como RB5, e assim por diante. A figura 1 exibe os pinos do PIC16F1619:

curiosity-pinos-de-i-o
Figura 1 – Pinagem do PIC16F1619 com encapsulamento PDIP

Cada port possui basicamente 3 registradores para controle dos pinos, que são:

  • TRISx – tem a função de definir a direção do pino, ou seja, se funcionará como uma entrada ou saída;
  • PORTx – é onde será feita a leitura do estado lógico presente no pino;
  • LATx – retêm a informação no lach (flip-flop tipo D) no port.

Além desses registradores básicos, alguns ports possuem outros registradores de configuração, por exemplo:

  • ANSELx – Configura se o pino será digital ou analógico;
  • WPUx – Configura resistores de pull-up.

A figura 2 exibe o diagrama de funcionamento de um pino de I/O do PIC16F1619:

curiosity-pinos-de-i-o-diagrama
Figura 2 – Diagrama genério de operação de um pino de I/O

Configurando um pino de I/O como Entrada ou Saída

Para configurar um pino de I/O como entrada ou saída deve-se utilizar o registrador TRISx. Para configurar um pino como entrada deve-se escrever o valor lógico 1 no bit correspondente. Já para configurar o pino como saída, deve-se escrever o valor lógico 0 no bit correspondente ao pino. A figura 3 exibe o registrador TRISA, responsável pela configuração da direção dos pinos do PORTA:

curiosity-pinos-de-i-o-TRISA
Figura 3 – Registrador TRISA

Por exemplo, se quisermos configurar o pino RA0 como entrada, devemos escrever o valor 1 no bit 0 do TRISA. Se o projeto exigir que o pino seja configurado como saída digital, deve-se escrever o valor 0 nesse pino.

A configuração do PORTB e PORTC segue a mesma ideia. Os registradores TRISB e TRISC são exibidos na figura 4:

curiosity-pinos-de-i-o-TRISB-TRISC
Figura 4 – Registradores TRISB e TRISC

Além disso, alguns pinos podem ser configurados como entradas analógicas. No nosso caso estamos trabalhando apenas com pinos de I/O digitais, dessa forma devemos configurar o registrador ANSELX para o correto funcionamento do pino. A figura 5 exibe o registrador ANSELA:

curiosity-pinos-de-i-o-ANSELA
Figura 5 – Registrador ANSELA

Para configurar o pino para funcionar como I/O digital deve-se escrever o valor zero no pino correspondente. Caso o pino for uma entrada analógica, deve-se escrever o valor 1. Para o PORTB e PORTC segue o mesmo padrão de configuração, conforme os registradores ANSELB e ANSELC exibidos na figura 6:

curiosity-pinos-de-i-o-ANSELB-ANSELC
Figura 6 – Registradores ANSELB e ANSELC

Lendo o estado de um pino de I/O

Quando um pino é configurado com entrada, desejamos ler o valor lógico presente nesse pino, ou seja, será um nível lógico 0 ou nível lógico 1, conforme a tensão presente no pino.

Para leitura utiliza-se o registrador PORTx. O valor presente nesse registrador conterá o nível lógico presente no pino. A figura 7 exibe o registrador PORTA.

curiosity-pinos-de-i-o-PORTA
Figura 7 – Registrador PORTA

Para leitura dos pinos do PORTB e PORTC segue o mesmo padrão. A figura 8 exibe esses registradores:

curiosity-pinos-de-i-o-PORTB-PORTC
Figura 8 – Registrador PORTB e PORTC

Escrevendo em um pino de I/O

Quando um pino é configurado como saída, podemos escrever o valor lógico 0 ou o valor lógico 1, conforme a necessidade. Para escrita é utilizado o registrador LATx. Escrevendo o valor 1 coloca-se nível lógico alto no pino, ou seja, tensão máxima. Já quando escrito o valor 0 coloca-se nível lógico baixo no pino, ou seja, tensão vai pra zero.

A figura 9 exibe os registradores LATA, LATB e LATC:

curiosity-pinos-de-i-o-LATA-LATB-LATC
Figura 9 – Registradores para escrita

Exemplo de leitura e escrita nos pinos

Para testar a teoria apresentada vamos criar uma aplicação para leitura de tecla e escrita em LEDs. Para isso vamos usar a chave táctil (S1) presente na Curiosity,  assim como os LEDs (D4, D5, D6 e D7). Cada vez que a tecla for pressionada será ligado um LED e apagados os outros, dando efeito de deslocamento.

Primeiro precisamos identificar no esquema elétrico em quais pinos estão ligados os componentes. A figura 10 exibe parte do esquemático da Curiosity:

curiosity-pinos-de-i-o-Circuito
Figura 10 – Esquema elétrico da Curiosity

Através do esquemático, verificamos que a tecla S1 está ligada ao pino RC4, o LED D4 ao pino RA5, o LED D5 ao pino RA1, o LED D6 ao pino RA2 e o LED D7 ao pino RC5. Dessa forma devemos configurar os pinos dos LEDs como saída e o pino da tecla como entrada.

Para exemplificar vamos fazer o programa sem o uso do MPLAB Code Configurator a principio e, posteriormente, o mesmo programa usando o MPLAB Code Configurator.

Exemplo sem o uso do MCC

Para esse exemplo deve-se seguir os passos para criação de um projeto, apresentados no artigo: Crie projetos com a placa Curiosity: Primeiros passos com MPLAB X e compilador XC8

Após a inicialização e configuração inicial vamos inserir o seguinte código no arquivo main.c:

/*
 * File:   main.c
 * Author: FábioSouza
 *
 * Created on 6 de Janeiro de 2016, 01:03
 */

// PIC16F1619 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switch Over (Internal External Switch Over mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit cannot be cleared once it is set by software)
#pragma config ZCD = OFF        // Zero Cross Detect Disable Bit (ZCD disable.  ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PLLEN = ON       // PLL Enable Bit (4x PLL is always enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = ON       // Low-Power Brown Out Reset (Low-Power BOR is enabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

// CONFIG3
#pragma config WDTCPS = WDTCPSE // WDT Period Select (1:524299 (16 s period))
#pragma config WDTE = SWDTEN    // Watchdog Timer Enable (WDT controlled by the SWDTEN bit in the WDTCON register)
#pragma config WDTCWS = WDTCWS100// WDT Window Select (100 percent window open time (Legacy WDT) )
#pragma config WDTCCS = MFINTOSC// WDT Input Clock Selector (31.25 kHz HFINTOSC (MFINTOSC))

#define _XTAL_FREQ 500000      //define para utilizar funções de tempo - Osc em 500 KHz


//constantes

#define PRESS 1                //sinaliza botão pressionado
#define NOPRESS 0              //sinaliza botão solto

//variáveis
unsigned char posicao = 0;    //variável auxiliar para posição dos leds
bit ST_BT;                    //flag para indicar o status do botão

void main(void) {
  
    //configura PORTA
    LATA = 0;               //desliga todas as saídas
    TRISA = 0B11011001;     //RA5 e RA2 como saídas, demais pinos como entrada
    ANSELA = 0;             //pinos como digitais
    
    //configura PORTB
    LATB = 0;               //desliga todos as saídas
    TRISB = 0XFF;           //todos os pinos como entradas
    ANSELB = 0;             //pinos como digitais
    
    //configura PORTC
    LATC = 0;               //desliga todos as saídas
    TRISC = 0B11011111;     //todos os pinos como entradas
    ANSELB = 0;             //pinos como digitais
   
      
    while(1){
        
        if(RC4 == 0){               //se botão pressionado
            
            if(ST_BT == NOPRESS){           //se não estava pressionado
                ST_BT = PRESS;              //sinaliza que o botão foi pressionado
                posicao++;                  //incrementa indexador dos LEDs
                if(posicao>=4)posicao = 0;  //se chegou no máximo reinicia
            } 
        }
        else{
            ST_BT = NOPRESS;
        }
        
        //atualiza leds
        switch(posicao){
                   
            case 0: 
                RA5 = 1; //D4 = LIGADO
                RA1 = 0; //D5 = DESLIGADO
                RA2 = 0; //D6 = DESLIGADO
                RC5 = 0; //D7 = DESLIGADO
                break; 
                   
            case 1: 
                RA5 = 0; //D4 = DESLIGADO
                RA1 = 1; //D5 = LIGADO
                RA2 = 0; //D6 = DESLIGADO
                RC5 = 0; //D7 = DESLIGADO
                break; 
                    
            case 2: 
                RA5 = 0; //D4 = DESLIGADO
                RA1 = 0; //D5 = DESLIGADO
                RA2 = 1; //D6 = LIGADO
                RC5 = 0; //D7 = DESLIGADO
                break; 
                     
            case 3: 
                RA5 = 0; //D4 = DESLIGADO
                RA1 = 0; //D5 = DESLIGADO
                RA2 = 0; //D6 = DESLIGADO
                RC5 = 1; //D7 = LIGADO
                break; 
        }
    }    
}

Compilando e executando o código acima na placa, a cada pressionamento da tecla será acendido um LED. Note como foi feita a configuração dos registradores e como foi elaborado o loop principal para leitura e escrita nos pinos.

Para deixar o código mais fácil de se entender, podemos criar defines que ajudam a identificar os LEDs e botão. O código a seguir apresenta essas modificações:

/*
 * File:   main.c
 * Author: FábioSouza
 *
 * Created on 6 de Janeiro de 2016, 01:03
 */

// PIC16F1619 Configuration Bit Settings

// 'C' source line config statements

#include <xc.h>

// #pragma config statements should precede project file includes.
// Use project enums instead of #define for ON and OFF.

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection Bits (INTOSC oscillator: I/O function on CLKIN pin)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = OFF      // MCLR Pin Function Select (MCLR/VPP pin function is digital input)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switch Over (Internal External Switch Over mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config PPS1WAY = ON     // Peripheral Pin Select one-way control (The PPSLOCK bit cannot be cleared once it is set by software)
#pragma config ZCD = OFF        // Zero Cross Detect Disable Bit (ZCD disable.  ZCD can be enabled by setting the ZCDSEN bit of ZCDCON)
#pragma config PLLEN = ON       // PLL Enable Bit (4x PLL is always enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = ON       // Low-Power Brown Out Reset (Low-Power BOR is enabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

// CONFIG3
#pragma config WDTCPS = WDTCPSE // WDT Period Select (1:524299 (16 s period))
#pragma config WDTE = SWDTEN    // Watchdog Timer Enable (WDT controlled by the SWDTEN bit in the WDTCON register)
#pragma config WDTCWS = WDTCWS100// WDT Window Select (100 percent window open time (Legacy WDT) )
#pragma config WDTCCS = MFINTOSC// WDT Input Clock Selector (31.25 kHz HFINTOSC (MFINTOSC))

#define _XTAL_FREQ 500000      //define para utilizar funções de tempo - Osc em 500 KHz


//constantes
#define PRESS 1                //sinaliza botão pressionado
#define NOPRESS 0              //sinaliza botão solto
#define HIGH 1
#define LOW 0
#define POSICAO_FINAL 4
#define POSICAO_INICIAL 0

#define D4 RA5
#define D5 RA1
#define D6 RA2
#define D7 RC5
#define TECLA RC4


//variáveis
unsigned char posicao = 0;    //variável auxiliar para posição dos leds
bit ST_BT;                    //flag para indicar o status do botão

void main(void) {
  
    //configura PORTA
    LATA = 0;               //desliga todas as saídas
    TRISA = 0B11011001;     //RA5 e RA2 como saídas, demais pinos como entrada
    ANSELA = 0;             //pinos como digitais
    
    //configura PORTB
    LATB = 0;               //desliga todos as saídas
    TRISB = 0XFF;           //todos os pinos como entradas
    ANSELB = 0;             //pinos como digitais
    
    //configura PORTC
    LATC = 0;               //desliga todos as saídas
    TRISC = 0B11011111;     //todos os pinos como entradas
    ANSELB = 0;             //pinos como digitais
   
      
    while(1){
        
        if(TECLA == LOW){               //se botão pressionado
            
            if(ST_BT == NOPRESS){           //se não estava pressionado
                ST_BT = PRESS;              //sinaliza que o botão foi pressionado
                posicao++;                  //incrementa indexador dos LEDs
                if(posicao>=POSICAO_FINAL)posicao = POSICAO_INICIAL;  //se chegou no máximo reinicia
            } 
        }
        else{
            ST_BT = NOPRESS;
        }
        
        //atualiza leds
        switch(posicao){
                    
            case 0: 
                D4 = HIGH; //D4 = LIGADO
                D5 = LOW; //D5 = DESLIGADO
                D6 = LOW; //D6 = DESLIGADO
                D7 = LOW; //D7 = DESLIGADO
                break; 
                   
            case 1: 
                D4 = LOW; //D4 = DESLIGADO
                D5 = HIGH; //D5 = LIGADO
                D6 = LOW; //D6 = DESLIGADO
                D7 = LOW; //D7 = DESLIGADO
                break; 
                    
            case 2: 
                D4 = LOW; //D4 = DESLIGADO
                D5 = LOW; //D5 = DESLIGADO
                D6 = HIGH; //D6 = LIGADO
                D7 = LOW; //D7 = DESLIGADO
                break; 
                     
            case 3: 
                D4 = LOW; //D4 = DESLIGADO
                D5 = LOW; //D5 = DESLIGADO
                D6 = LOW; //D6 = DESLIGADO
                D7 = HIGH; //D7 = LIGADO
                break; 
        }
    }
}

 

Exemplo com o uso do MCC

Para exemplificar, vamos fazer a mesma aplicação utilizando o MPLAB Code Configurator. Para isso deve-se seguir os passos apresentados no artigo Crie projetos com a placa Curiosity: Iniciando com o MPLAB Code Configurator.

A configuração dos pinos deve ficar conforme apresentado na figura 11:

curiosity-pinos-de-i-o-CONFIG-MCC
Figura 11 – Configuração dos pinos usando o MCC

Foram gerados os aquivos pelo MCC, porém vamos verificar apenas como ficou a função para configuração dos pinos de I/O, no arquivo pin_manager.c:

void PIN_MANAGER_Initialize(void) {
    LATA = 0x00;
    TRISA = 0x19;
    ANSELA = 0x11;

    LATB = 0x00;
    TRISB = 0xF0;
    ANSELB = 0x30;
    WPUB = 0x00;

    LATC = 0x00;
    TRISC = 0xDF;
    ANSELC = 0xCF;
    WPUC = 0x00;

    OPTION_REGbits.nWPUEN = 0x01;
}

Note que foram configurados os registradores associados a cada pino, conforme as configurações feitas no MCC. A aplicação no loop principal ficará igual ao projeto feito sem o MCC, porém nesse caso foram utilizadas as macros de manipulação dos pinos:

#include "mcc_generated_files/mcc.h"

#define NOPRESS 0
#define PRESS 1
#define POSICAO_FINAL 4
#define POSICAO_INICIAL 0

//variáveis
unsigned char posicao = 0;    //variável auxiliar para posição dos leds
bit ST_BT;                    //flag para indicar o status do botão


/*
                         Main application
 */
void main(void) {
    // initialize the device
    SYSTEM_Initialize();

    // When using interrupts, you need to set the Global and Peripheral Interrupt Enable bits
    // Use the following macros to:

    // Enable the Global Interrupts
    //INTERRUPT_GlobalInterruptEnable();

    // Enable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptEnable();

    // Disable the Global Interrupts
    //INTERRUPT_GlobalInterruptDisable();

    // Disable the Peripheral Interrupts
    //INTERRUPT_PeripheralInterruptDisable();

    while (1) {
         if(TECLA_GetValue() == LOW){               //se botão pressionado
            
            if(ST_BT == NOPRESS){           //se não estava pressionado
                ST_BT = PRESS;              //sinaliza que o botão foi pressionado
                posicao++;                  //incrementa indexador dos LEDs
                if(posicao>=POSICAO_FINAL)posicao = POSICAO_INICIAL;  //se chegou no máximo reinicia
            } 
        }
        else{
            ST_BT = NOPRESS;
        }
        
        //atualiza leds
        switch(posicao){
                    
            case 0: 
                D4_SetHigh(); //D4 = LIGADO
                D5_SetLow(); //D5 = DESLIGADO
                D6_SetLow(); //D6 = DESLIGADO
                D7_SetLow(); //D7 = DESLIGADO
                break; 
                  
            case 1: 
                D4_SetLow(); //D4 = DESLIGADO
                D5_SetHigh(); //D5 = LIGADO
                D6_SetLow(); //D6 = DESLIGADO
                D7_SetLow(); //D7 = DESLIGADO
                break; 
                    
            case 2: 
                D4_SetLow(); //D4 = DESLIGADO
                D5_SetLow(); //D5 = DESLIGADO
                D6_SetHigh(); //D6 = LIGADO
                D7_SetLow(); //D7 = DESLIGADO
                break; 
                     
            case 3: 
                D4_SetLow(); //D4 = DESLIGADO
                D5_SetLow(); //D5 = DESLIGADO
                D6_SetLow(); //D6 = DESLIGADO
                D7_SetHigh(); //D7 = LIGADO
                break; 
        }
    }
}

O resultado é apresentado na Figura 12, onde a cada pressionamento da tecla é deslocado um LED:

curiosity-pinos-de-i-o-resultado
Figura 12 – Resultado do exemplo proposto

O artigo exibiu os detalhes para configuração e manipulação dos pinos utilizando o compilador XC8. Foram apresentados todos os registradores assim como um exemplo de aplicação.

Você pode acessar o exemplo completo no MPLAB XPress.

No próximo artigo vamos aprender a trabalhar com os Timers.

Caso tenha alguma dúvida ou sugestão, deixe seu comentário abaixo.

Crie projetos com a placa Curiosity

Curiosity – Iniciando com o MPLAB Code Configurator Curiosity – Explore o TIMER0
Licença Creative Commons Esta obra está licenciada com uma Licença Creative Commons Atribuição-CompartilhaIgual 4.0 Internacional.
Comentários:
Notificações
Notificar
1 Comentário
recentes
antigos mais votados
Inline Feedbacks
View all comments
Home » Hardware » Microcontroladores » Curiosity – Explore os pinos de I/O

EM DESTAQUE

WEBINARS

VEJA TAMBÉM

JUNTE-SE HOJE À COMUNIDADE EMBARCADOS

Talvez você goste: