COMO LER OS PINOS DE I/O's DO PIC16F628A – CHAVES


Até agora todas as experiências usaram os pinos de I/O como saída. Mas que tal ver agora como utilizá-los como entrada. Nessa experiência um grupo de pinos será utilizado como saída e outro como entrada. Para isso feche os jumpers: JP2 e JP3. Crie um projeto e insira no arquivo main.c a listagem abaixo. Compile e grave o microcontrolador.

Listagem main.c

//******************************************************************************
// Projeto Teclas para placa PE-PIC16F628A
// Desenvolvido por: Eng. Márcio José Soares
//
// V1.0 - 06/09/2022
//
// Compilador: XC8 v2.45
// IDE : MPLABX 6.0 Linux
// Plataforma: placa PE-PIC16F628A com PIC16F648A
// Gravador : PICKIT3
//
// Pinos utilizados:
// RA0 : S4
// RA1 : S3
// RA2 : S2
// RA3 : S1
// RB4 : LED5
// RB5 : LED3
// RB6 : LED2
// RB7 : LED1
//
//******************************************************************************

//******************************************************************************
// Bits de configuração
#pragma config FOSC = INTOSCIO // Bits de seleção do oscilador (Oscilador interno: RA6 e RA7 como I/O)
#pragma config WDTE = OFF // WDT disabilitado
#pragma config PWRTE = ON // Power-up Timer disabilitado
#pragma config MCLRE = ON // MCLR = I/O RA5
#pragma config BOREN = OFF // Brown-out Detect BOD disabilitado
#pragma config LVP = OFF // Low-Voltage Programming desabilitado - I/O RB4
#pragma config CPD = OFF // Data EE Memory Code Protection desabilitado
#pragma config CP = OFF // Flash Program Memory Code Protection desabilitado

//******************************************************************************
// Se nenhuma freqüência foi definida, assume 4MHz
// Esta definição é exigida para calibrar as funções __delay_us() e __delay_ms()
#define _XTAL_FREQ 4000000

//******************************************************************************
// Inclui arquivos
#include <xc.h>
#include <pic16f648a.h>

//******************************************************************************
// Definições importantes do módulo
#define TRUE 1
#define LEDS PORTB
#define TECLAS PORTA
#define TEMPO 500

//******************************************************************************
// Função para temporizar x ms
//
// Entradas - tempo em ms
// Saídas - nenhuma
//******************************************************************************
void mdelay_ms(unsigned long tempo){

while(tempo--)
__delay_ms(1);
}

//******************************************************************************
// Função para ler as teclas
//
// Entradas - nenhuma
// Saídas - valor da tecla ou 0 se sem tecla
//******************************************************************************
uint8_t get_teclas(void){

uint8_t ret = 0;

switch(TECLAS & 0x0F){ //lê port A e limpa MSB
case 0x0E: //se tecla S4 pressionada
ret = 0x02; //divisor
break;
case 0x0D: //se tecla S3 pressionada
ret = 0x03;
break;
case 0x0B: //se tecla S2 pressionada
ret = 0x04;
break;
case 0x07: //se tecla S1 pressionada
ret = 0x05;
break;
}

return ret;
}

//******************************************************************************
// Função principal
//
// Entradas - nenhuma
// Saídas - nenhuma
//******************************************************************************
void main(void) {

uint8_t i, j;

PORTA = 0; // zera ports
PORTB = 0;

INTCON = 0x00; // Todas as ints desligadas
CMCON = 0x07; // desliga comparadores

TRISA = 0xFF; // Configura PORT A - entrada
TRISB = 0x00; // Configura PORT B - saída

LEDS = 0; // limpa port

while(TRUE){

for(i=0;i<4;i++){
LEDS = ((0x10 << i) & 0xF0); // faz shift left e limpa LSB
j = get_teclas(); // lê teclas
if(j) // se tem teclas, tem divisor
mdelay_ms(TEMPO/j); // temporiza com divisor
else
__delay_ms(TEMPO); // senão usa tempo default
}

for(i=0;i<4;i++){
LEDS = ((0x80 >> i) & 0xF0); // faz shift rigth e limpa LSB
j = get_teclas(); // lê teclas ...
if(j) //
mdelay_ms(TEMPO/j); //
else
__delay_ms(TEMPO); // ...senão ...
}

}

return;
}

Esse programa ganhou algumas coisas a mais que os anteriores não tinham. A primeira delas são as sub-rotinas (funções) para temporização e leitura das teclas. O uso de sub-rotinas permite um melhor entendimento do programa. Note que sub-rotina “get_teclas()” lê a PORTA completa, limpa a mesma mantendo apenas o LSB intacto e em seguida o valor resultante é testado. As teclas estão ligadas a RA0 até RA3 e estes pinos possuem um resistor de pull-up que mantêm o estado do pino, quando a tecla não está pressionada, em 5VDC (nível lógico High). Porém ao ser pressionada, a tecla leva GND ao pino de I/O correspondente (nível lógico LOW) e é este o nível que será detectado (pino em LOW). Veja o que acontece dentro do switch:

quando:

0x0E → 0000 1110b → tecla S4 pressionada – retorno da função, valor 2H ou 2d

0x0D → 0000 1101b → tecla S3 pressionada – retorno da função, valor 3H ou 3d

0x0B → 0000 1011b → tecla S2 pressionada – retorno da função, valor 4H ou 4d

0x07 → 0000 0111b → tecla S1 pressionada – retorno da função, valor 5H ou 5d

Você deve ter percebido que no laço while esse programa se parece bastante com o programa sequencial de leds, com uma diferença. Antes de alterar os LEDs, as teclas são lidas. Se uma delas estiver pressionada um valor é retornado. Se o valor retornado é maior que “zero” o tempo para troca de estado é alterado dividindo TEMPO pelo valor retornado (apenas a parte inteira, não importando o resto da divisão). Isso é feito em uma segunda sub-rotina “mdelay_ms(tempo)”. Essa rotina vai aguardar o resultado da divisão. Note que se não houver tecla pressionada o tempo aguardado será o default e para isso usamos a função “__delay_ms()” fornecida pelo próprio compilador.

Mas porque usar duas funções para a mesma tarefa?! Simples, a função “__delay_ms()” não aceita variáveis na passagem do parâmetro tempo. A função mdelay_ms(tempo) aceita, usando a função do compilador com parâmetro fixo!

Você percebeu que ao pressionar uma tecla a velocidade do vai e vem aumenta ou diminui?!



Desafio:

  1. Que tal alterar a velocidade do vai e vem?!?


Dica: você pode modificar a definição TEMPO para mais ou para menos e/ou também os valores utilizados na divisão (retorno de get_teclas). Lembre-se que microcontroladores não “gostam” de divisão por zero! Cuidado ok!



Copyright deste conteúdo reservado para Márcio José Soares e protegido pela Lei de Direitos Autorais LEI N° 9.610, de 19 de Fevereiro de 1998. É estritamente proibida a reprodução total ou parcial do conteúdo desta página em outros pontos da internet, livros ou outros tipos de publicações comerciais ou não, sem a prévia autorização por escrito do autor.