Nothing Special   »   [go: up one dir, main page]

Micro Parte 5 (PIC) Pratica

Fazer download em pptx, pdf ou txt
Fazer download em pptx, pdf ou txt
Você está na página 1de 197

Microcontroladores PIC

Prática

MSc. Gustavo Souto de Sá e Souza


Revisado por José Wilson Nerys
Introdução
O principal microcontrolador utilizado nesse estudo é o PIC18F4550, cujas
características principais são:
 Fontes de clock possíveis:
Cristal externo (4 modos);
Clock externo (2 modos. Até 48 MHz);
Oscilador interno (8 frequências diferentes: de 31 kHz a 8 MHz)
 Memórias: 32 K de memória Flash; 2 K de SRAM e 256 bytes de EEPROM
 35 pinos de entrada/saída
 Conversor Analógico/Digital de 10 bits, 13 entradas multiplexadas

Obs.: É importante lembrar que as informações contidas aqui podem variar para outras famílias PIC ou até
mesmo para outros chips da mesma família.
Introdução
O principal microcontrolador utilizado nesse estudo é o PIC18F4550, cujas
características principais são:

 3 interrupções externas
 Capacidade de corrente nos pinos de I/O: 25 mA
 4 módulos temporizadores (Timer 0 a Timer 3)
 Até 2 módulos de Captura/Comparação/PWM (CCP)
 Unidade interna de USB (transceiver)
 Programação via canal serial com 2 pinos
 Canal serial universal melhorado (EUSART)
 Canal I2C (vários transdutores usam esse canal para a transferência de dados.
Exemplos: giroscópio e barômetro)
PIC18F4550
Linguagem C – compilador XC8

Inicialização da variável “variavel”:


 Bit ou boolean: bit variavel;
 Valor inteiro: int variavel;
 Valor inteiro com sinal (positivo ou negativo): signed int variavel;
 Caractere: char variavel;
 String (conjunto de, digamos, 10 caracteres): char variavel[10];
 Valor flutuante: float variavel;
Linguagem C – compilador XC8

Definição de variável:
 Decimal: variavel = 100;
 Binário: variavel = 0b1100100;
 Hexadecimal: variavel = 0x64;
 Caractere: variavel = “d”;
Linguagem C – compilador XC8
Operações:
 Definição de variável: variavel = 255;
 Soma: variavel = 15 + b;
 Subtração: variavel = 15 - b;
 Multiplicação: variavel = 15 * b;
 Divisão: variavel = 15 / b;
 Rotação de N bits para esquerda: variavel = variavel <<
N;
 Rotação de N bits para a direita: variavel = variavel >>
N;
Linguagem C – compilador XC8
Operações:
 Operação E: variavel = variavel & 55;
 Operação OU: variavel = variavel | 55;
 Operação NÃO (inverte apenas 1 bit): variavel = !
variavel;
 Incrementar em 1: variavel++;
 Decrementar em 1: variavel--;
Linguagem C – compilador XC8
Condições (retornam 1 se verdadeiro, 0 se falso):
 Verificar se é igual: (variavel == b);
 Verificar se é diferente: (variavel != b);
 Verificar se é maior: (variavel > b);
 Verificar se é menor: (variavel < b);
 Verificar se é maior ou igual: (variavel >= b);
 Verificar se é menor ou igual: (variavel <= b);
 Condição E: (variavel <= b && variavel != 0);
 Condição OU: (variavel <= b || variavel != 0);
Linguagem C – compilador XC8

Definições:
 Define “_constante” como 5: #define _constante 5
 Define “PINO_DO_LED” como LATD1: #define PINO_DO_LED LATD1

Inclusões de bibliotecas:
 Inclui biblioteca do compilador: #include <stdlib.h>
 Inclui biblioteca da pasta local: #include “lcd.h”
Linguagem C – compilador XC8

Se:
 if:
if (variavel == 10) {
// executa se condição for verdadeira
} else {
// executa se condição for falsa
}
Linguagem C – compilador XC8

Se: Condição
 if:
if (variavel == 10) {
// executa se condição for verdadeira
} else {
// executa se condição for falsa
}
Linguagem C – compilador XC8

Loops:
 While:
while (variavel != 0) {
// código em loop
}
Linguagem C – compilador XC8

Condição (executa enquanto for 1)


Loops:
 While:
while (variavel != 0) {
// código em loop
}
Linguagem C – compilador XC8

Loops:
 for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Valor inicial
Loops:
 for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Condição (executa enquanto for 1)
Loops:
 for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Incremento
Loops:
 for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8

Loops:
 break:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
if (variavel < 0) {
break;
}
}
Linguagem C – compilador XC8
Loops:
 break:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
if (variavel < 0) {
break;
}
} Finaliza e sai do loop aqui
Linguagem C – compilador XC8

Funções:
 Principal:
void main (void) {
// Código principal do programa vem aqui
}
Linguagem C – compilador XC8

Funções:
 Interrupção:
void interrupt int_func (void) {
// Código da interrupção
}
Linguagem C – compilador XC8

Funções:
 Interrupção de baixa prioridade:
void interrupt low_priority int_low_funcao
(void) {
// Código da interrupção de baixa
prioridade
}
Linguagem C – compilador XC8

Funções:
 Secundárias:
void LigaTimer (void) {
TMR0ON = 1;
}
Linguagem C – compilador XC8

Funções:
 Secundárias com valores de entrada e saída:
int SomaDez (int valor_de_entrada) {
valor_de_entrada = valor_de_entrada + 10;
return valor_de_entrada;
}
Linguagem C – compilador XC8

Chamando Funções:
LigaTimer();

variavel = SomaDez(variavel);
Linguagem C – compilador XC8
Função de atraso por milissegundo:
__delay_ms(tempo_em_milissegundos);

!!! Requer que a velocidade do oscilador seja definido antes, por meio da linha
#define _XTAL_FREQ 1000000 (para um oscilador de 1 MHz)

Também requer a library xc.h incluída por meio da linha:


#include <xc.h>
Pode causar erro se o valor de entrada for muito grande, relativo à velocidade do
oscilador.
Linguagem C – compilador XC8

Comentando o código:
TRISA = 0; // A parte comentada vem depois de
// duas barras
/* Ou você pode comentar
todo um trecho do código
usando asterisco e barra
*/
ok++;
Linguagem C – compilador XC8
sprintf: imprime e manipula strings e caracteres. Requer que a biblioteca “stdio.h”
seja incluída.

#include <stdio.h>
char linha1[16];

sprintf(linha1, “Hello, world!”);

// Grava o texto ‘Hello, world!’ na variável linha1


Linguagem C – compilador XC8

char linha1[16];
contador = 15;

sprintf(linha1, “Contagem: %i”, contador);

// Grava o texto ‘Contagem: 15’ na variável linha1


// %i imprime um número inteiro
Linguagem C – compilador XC8

char linha1[16];
contador = 15;
sprintf(linha1, “Contagem: %3.2i”, contador);

// Grava o texto ‘Contagem: 15.00’ na variável linha1


// %X.Yi imprime um número inteiro com X casas fixas
// antes do separador decimal e Y fixas casas depois
Linguagem C – compilador XC8

char linha1[16];
temperatura = 37.52;

sprintf(linha1, “Graus: %2.2f”, temperatura);

// Grava o texto ‘Graus: 37.52’ na variável linha1


// %f imprime um número de ponto flutuante
Linguagem C – compilador XC8

char linha1[16];
caractere_U = 0x55;

sprintf(linha1, “Letra U: %c”, caractere_U);

// Grava o texto ‘Letra U: U’ na variável linha1


// %c imprime um caractere correspondente à tabela
// ASCII
Linguagem C – compilador XC8
Definindo bits de Configuração:

O símbolo “#” precedido da configuração desejada é uma diretiva de programa, que


indica ao Compilador a ação a ser tomada antes da execução do código do programa.
As 3 principais diretivas utilizadas nos exemplos são:
#include - inclui bibliotecas padrões e
do usuário

#define - define constantes e


variáveis antes da execução do programa

#pragma config - define configurações em uma área


específica da memória flash, fora do código do programa
principal
Linguagem C – compilador XC8
Bits de Configuração essenciais (incluídos com #pragma config):

 FOSC: // Frequência do oscilador


Define a origem do oscilador principal do microcontrolador.
Mais usados:

#pragma config FOSC = INTIO; (oscilador interno)


#pragma config FOSC = XT; (cristal externo)
#pragma config FOSC = HS; (cristal externo rápido – High
Speed)
Linguagem C – compilador XC8

Bits de Configuração essenciais:


 WDT: // No PIC18F4550

Watchdog Timer Enable. Habilita o reset automático do Watchdog Timer. Caso o


comando ClrWdt() não seja executado num dado número de instruções, o
microcontrolador será ressetado:

#pragma config WDT = OFF; // desabilita watchdog


timer
#pragma config WDTPS = 32768;
Linguagem C – compilador XC8

Bits de Configuração essenciais:


 MCLRE:

Master Clear Enable. Habilita ou desabilita o pino de reset no microcontrolador.

#pragma config MCLRE = OFF;


Linguagem C – compilador XC8

Bits de Configuração não tão essenciais (podem ficar no valor padrão):


 PWRT:
Aguarda um tempo depois de ligar para iniciar o programa. Habilitá-lo evita
instabilidade no programa devido a oscilações na alimentação e oscilador:
#pragma config PWRT = ON;
Linguagem C – compilador XC8

Bits de Configuração não tão essenciais (podem ficar no valor padrão):


 BOREN:
Brown-out reset enable. Habilita o reset automático em caso de baixa tensão de
alimentação:
#pragma config BOREN = SBORDIS;
Linguagem C – compilador XC8
Bits de Configuração essenciais:
 PBADEN:

Habilita ou desabilita o conversor Analógico-Digital na porta B. Caso for utilizar


interrupção na porta B ou usá-la como entrada/saída digital, este deve estar
desabilitado. Por padrão é habilitado:

#pragma config PBADEN = OFF;


Linguagem C – compilador XC8

Registradores essenciais:
 OSCCON: Byte que define a frequência do oscilador interno do
PIC18F45K20:
OSCCON=0b01110000; // Frequência: 16 MHz
OSCCON=0b01100000; // Frequência: 8 MHz
OSCCON=0b01010000; // Frequência: 4 MHz
OSCCON=0b00110000; // Frequência: 1 MHz
(padrão)
Linguagem C – compilador XC8
Registradores essenciais:
 OSCCON: Byte que define a frequência do oscilador interno do PIC18F4550:

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


IDLEN IRCF2 IRCF1 IRCF0 OSTS IOFS SCS1 SCS0
Bits de seleção da frequência

OSCCON=0b01110000; // Frequência: 8 MHz


OSCCON=0b01100000; // Frequência: 4 MHz
OSCCON=0b01010000; // Frequência: 2 MHz
OSCCON=0b01000000; // Frequência: 1 MHz (padrão)
OSCCON=0b00110000; // Frequência: 500 kHz
OSCCON=0b00100000; // Frequência: 250 kHz
Exemplos Gerais
EXEMPLO – PISCAR LED blink.c

Inicio

Configuração Inverte sinal do pino D0


Atrasa 100 ms
EXEMPLO – PISCAR LED blink.c

#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h> // Biblioteca do compilador xc8

#pragma config FOSC = INTOSC // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
OSCCON = 0b01100000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída

while(1) { // Inicia loop infinito


LATDbits.LATD0 = !LATDbits.LATD0; // Inverte sinal do pino D0
__delay_ms(100); // Atraso de 100 ms
}
}

Fim de Código
EXEMPLO – PISCAR LED (VERSÃO 2)
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#define Led LATDbits.LATD0

#include <xc.h> // Biblioteca do compilador xc8

#pragma config FOSC = HS // Oscilador externo


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {

TRISD = 0b00000000; // Habilita porta D como saída

while(1) { // Inicia loop infinito


Led = !Led; // Inverte sinal do pino Led
__delay_ms(100); // Atraso de 100 ms
}
}

Fim de Código
EXEMPLO – PISCAR LED – 1 SEGUNDO blink1s.c

Inicio

Configuração Inverte sinal do pino D0 Atrasa 100 vezes 10 ms


EXEMPLO – PISCAR LED – 1 SEGUNDO blink1s.c

#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void SuperDelay(long counter) { // Função com valor de


entrada “counter”
counter = counter / 10; // Divide o valor informado por 10
for (long i = 1; i <= counter; i++) { // E usa o resultado como base
__delay_ms(10); // Para repetir uma
contagem de 10 ms
}
}

void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
EXEMPLO – PISCAR LED – 1 SEGUNDO

while(1) { // Inicia loop infinito


LATDbits.LATD0 = !LATDbits.LATD0; // Inverte sinal do pino D0
SuperDelay(1000); // Atraso de 1 s
}

Fim de Código
EXEMPLO 1 DE ROTAÇÃO DE LEDS
Inicio

Rotaciona 1 passo para a


Configuração
esquerda

não sim
PORTD=0? LATD = 1
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
#pragma config FOSC = HS // Cristal oscilador externo (clock externo)
#pragma config WDT= OFF // Watchdog Timer desligado
#pragma config MCLRE = ON // Define pino 1 como Reset

void SuperDelay(long counter) { // Função com valor de


entrada ?counter?
counter = counter / 10; // Divide o valor informado por 10
for (long i = 1; i <= counter; i++) { // E usa o resultado como base
__delay_ms(10); // Para repetir uma
contagem de 10 ms
}
}
void main(void) {
TRISD = 0; // Habilita porta D como saída
LATD = 0b00000001; // Liga o Led do pino 0 da porta D
while(1)
{
LATD = LATD << 1; // Rotacionando para a esquerda
SuperDelay(500);

if (PORTD == 0)
{
LATD = 1;
SuperDelay(500);
} Fim de Código
}
EXEMPLO 2 DE ROTAÇÃO DE LEDS
Inicio

Rotaciona 1 passo para a


Configuração
esquerda

não sim
PORTD=0? LATD = 1
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#pragma config FOSC = HS // Cristal oscilador externo (clock externo)


#pragma config WDT= OFF // Watchdog Timer desligado
#pragma config MCLRE = ON // Define pino 1 como Reset

void SuperDelay(long counter) { // Função com valor de


entrada ?counter?
counter = counter / 10; // Divide o valor informado por 10
for (long i = 1; i <= counter; i++) { // E usa o resultado como
base
__delay_ms(10); // Para repetir uma
contagem de 10 ms
}

void main(void) {

TRISD = 0; // Habilita porta D como saída


LATD = 0b00000001; // Liga o primeiro pino da porta D
SuperDelay(500);
while(1)
{
while(LATD != 0b10000000)
{
LATD = LATD << 1; // Rotacionando para a esquerda
SuperDelay(500);
}
while(LATD != 1)
{
LATD = LATD >> 1; // Rotacionando para a direita
SuperDelay(500);
}
}
return;
}

Fim de Código
EXEMPLO 3 – ROTACIONAR LED ledRotate.c

Inicio

sim LED aceso não


Rotaciona para a
Configuração na borda
esquerda
direita?

não LED aceso sim


na borda Rotaciona para a direita
esquerda?
EXEMPLO – ROTACIONAR LED ledRotate.c

#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz


#include <xc.h>
#pragma config FOSC = INTIO // Oscilador interno
#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
TRISA = 0b00000000; // Habilita porta A como saída
LATA = 1; // Liga o primeiro pino da porta A
while(1) { // Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com estilo
pra esquerda
__delay_ms(100); // Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); // Atraso de 100 ms
}
}
} Fim de Código
EXEMPLO – ROTACIONAR LED - EXPLICAÇÃO
Digamos que LATA = 0b00000001

LATA >> 1 retorna o seguinte valor: 0b00000000, pois rotacionou o “1” para a direita e ele
caiu fora dos 8 bits. O oitavo bit é preenchido com 0.

LATA << 7 retorna o seguinte valor: 0b10000000, pois rotacionou o “1” um total de sete bits
para a esquerda e ele ficou no lugar do oitavo bit. Os 7 primeiros bits são preenchidos com
0.

Fazendo a operação OU entre ambos, temos (LATA >> 1 | LATA << 7) = 0b10000000; Continuemos
com LATA = 0b10000000

LATA >> 1 retorna o seguinte valor: 0b01000000, pois rotacionou o “1” para a direita e ele
caiu no lugar do sétimo bit. O oitavo bit é preenchido com 0.

LATA << 7 retorna o seguinte valor: 0b00000000, pois rotacionou o “1” um total de sete bits
para a esquerda e ele saiu do espaço dos bits. Os 7 primeiros bits são preenchidos com 0.

Fazendo a operação OU entre ambos, temos (LATA >> 1 | LATA << 7) = 0b01000000;
Display LCD
EXEMPLO – LCD lcd.h lcd.c

Inicio

Configuração Adiciona 1 em contador

Atualiza LCD com valor


de contador
EXEMPLO – LCD lcd.h lcd.c

#define _XTAL_FREQ 1000000

#include <xc.h>
Conexão da Porta D no
#define RS LATD2 // < Pinos do LCD
LCD #define EN LATD3
Os pinos D0, D1, D2 e #define D4 LATD4
D3 do LCD são #define D5 LATD5
conectados ao Terra #define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
Biblioteca local do LCD
#include "lcd.h"
#include <stdio.h>
EXEMPLO – LCD
char linha1[16]; // Variável linha1 com 16
caracteres
char linha2[16]; // Variável linha2 com 16
caracteres
int contador = 0; // Variável contador com
valor inicial 0

void main(void) {
TRISD = 0; // Define porta D
inteira como saída

Lcd_Init(); // Inicia o LCD


sprintf(linha1, "Hello world! "); // Grava texto em linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1,
caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD

while(1) {
sprintf(linha2, "Contador: %i ",contador); // Grava texto em linha2
contador ++;
// Incrementa contador
Lcd_Set_Cursor(2,1); Fim de Código // Posiciona o cursor na linha 2,
EXEMPLO – LCD + CONTADOR FLOAT lcdFloat.c

Inicio
lcd.h

Adiciona 0.01 em
Configuração
contador

Atualiza LCD com valor


de contador
EXEMPLO – LCD + CONTADOR FLOAT lcdFloat.c

#define _XTAL_FREQ 1000000


lcd.h
#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include "lcd.h"
#include <stdio.h>
EXEMPLO – LCD + CONTADOR FLOAT
char linha1[16]; // Variável linha1 com
16 caracteres
char linha2[16]; // Variável linha2 com
16 caracteres
float contador = 0.0; // Variável contador com
valor inicial 0.0

void main(void) {
TRISD = 0; // Define
porta D inteira como saída

Lcd_Init(); // Inicia o
LCD
sprintf(linha1, "Hello world! "); // Grava texto em linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na
linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD

while(1) {
Fim de%3.2f",contador);
sprintf(linha2, "Contador: Código // Grava texto em linha2
Interrupções
Linguagem C – compilador XC8
Registradores importantes - interrupção:
 GIE: bit que habilita a interrupção global:
GIE = 1; // Habilita interrupção
 PBIE: bit que habilita a interrupção de periféricos (timer2, adc):
PEIE = 1; // Habilita interrupção de periféricos
 INTXIE: bit que habilita a interrupção externa X (X = 0, 1 ou 2):
INT0IE = 1; // Habilita interrupção externa 0
INT1IE = 1; // Habilita interrupção externa 1
INT2IE = 1; // Habilita interrupção externa 2
Linguagem C – compilador XC8
Registradores importantes - interrupção:
 ADIF: bit que habilita a interrupção do conversor AD:

ADIF = 1; // Habilita interrupção do ADC


 TXIE: bit que habilita a interrupção de transmissão da serial:

TXIE = 1; // Habilita interrupção do TX da serial


 RCIE: bit que habilita a interrupção de recepção da serial:

RCIE = 1; // Habilita interrupção do RX da serial


Linguagem C – compilador XC8
Registradores importantes - interrupção:

 TMRXIE: bit que habilita a interrupção do timer X


(X pode ser 0, 1, 2 ou 3):

TMR0IE = 1; // Habilita interrupção do TMR0


TMR1IE = 1; // Habilita interrupção do TMR1
TMR2IE = 1; // Habilita interrupção do TMR2
TMR3IE = 1; // Habilita interrupção do TMR3
Linguagem C – compilador XC8
Registradores importantes – interrupção (flags):
 INTXIF: bit que sinaliza a flag da interrupção externa X (X=0, 1, 2):
INT0IF = 0; // Limpa a flag do INT0

 TMRXIF: bit que sinaliza a flag de interrupção do timer X (X=0, 1, 2, 3):


TMR3IF = 0; // Limpa a flag do TMR3

 ADIF: bit que sinaliza a flag de interrupção do ADC:


ADIF = 0; // Limpa a flag do ADC
EXEMPLO – INTERRUPÇÃO (INT0) interrupcao_INT0.c

Inicio

Configuração Aguarda interrupção

não
Interrupção sim
Inverte sinal do LED
ativada?
EXEMPLO – INTERRUPÇÃO (INT0) interrupcao_INT0.c

#define _XTAL_FREQ 1000000

#include <xc.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
#pragma config PBADEN = OFF // Conversor AD da porta B desligado

void setupInt(void) {
GIE = 1; // Habilita interrupção global
INT0IE = 1; // Habilita Interrupção da INT0
INT0F = 0; // Zera a Flag de interrupção da INT0
INTEDG0 = 1; // Interrupção por borda crescente.
}

Para usar a interrupção INT0 (Pino RB0, da porta B), deve-se desabilitar o conversor AD dessa porta
EXEMPLO – INTERRUPÇÃO (INT0)
void interrupt interrupcao(void) { // Função de interrupção
if (INT0F) { // Caso a flag
da INT0 esteja habilitada
LATAbits.LA0 = !LATAbits.LA0; // Inverte o sinal no pino A0
INT0F = 0; // Desabilita
a flag da INT0
}
}

void main(void) {
TRISA = 0x00; // Porta A com
todos pinos de saída
TRISB = 0x01; // Somente
pino B1 como entrada (INT0)
setupInt(); // Função de
inicializar Interrupção
while(1) { // Loop
infinito
}
}
Fim de Código
Conversor
Analógico/Digital

(10 bits)
Características do Conversor Analógico Digital (ADC):
10 bits
13 entradas multiplexadas
Registradores importantes:
Registrador Função
ADRESH Byte superior do resultado
ADRESL Byte inferior do resultado
ADCON0 Registrador de controle 0 – escolha de canais, liga/desliga/inicia conversão
ADCON1 Registrador de controle 1 – tensão de referência / configuração dos pinos de entrada como
analógico ou digital
ADCON2 Registrador de controle 2 – configura a fonte de clock e a taxa de aquisição
Linguagem C – compilador XC8
Registradores importantes – ADC (PIC18F4550):

ADCON0: Registrador de Controle do ADC


Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0
X X CHS3 CHS2 CHS1 CHS0 GO/DONE\ ADON
Status da Habilita
Bits de seleção do Canal Analógico
conversão ADC

ADCON0bits.CHS = 0b0000  Seleção do Canal AN0

ADCON0bits.CHS = 0b0001  Seleção do Canal AN1

ADCON0bits.ADON = 1  Liga o ADC

ADCON0bits.GO = 1  Inicia a conversão A/D


Linguagem C – compilador XC8

Registradores importantes – ADC :

 ADCON0bits.GO: bit que inicia a conversão analógica:


ADCON0bits.GO = 1; // Inicia a conversão AD

 ADCON0bits.DONE: flag que sinaliza o fim da conversão analógica:


while (!ADCON0bits.DONE) {
} // Aguarda finalização da conversão AD
Linguagem C – compilador XC8

Registradores importantes – ADC (PIC18F4550):

ADCON1: Registrador de Controle do ADC

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


X X VCFG1 VCFG0 PCFG3 PCFG2 PCFG1 PCFG0
Bits de
configuração da
tensão de referência

ADCON1bits.VCFG = 0b00;  Tensões de referência: Vss e Vdd


Linguagem C – compilador XC8
Registradores importantes – ADC (PIC18F4550):
ADCON2: Registrador de Controle do ADC

Bit 7 Bit 6 Bit 5 Bit 4 Bit 3 Bit 2 Bit 1 Bit 0


ADFM - ACQT2 ACQT1 ACQT0 ADCS2 ADCS1 ADCS0
Formato do Bits de seleção do Tempo de Aquisição Bits de seleção do Clock de
resultado de dados conversão

ADCON2bits.ADCS = 0b110  Clock do AD: Fosc/64

ADCON2bits.ACQT = 0b010  Tempo de aquisição: 4 TAD

ADCON2bits.ADFM = 0b1  Formato do resultado: justificado à direita


Linguagem C – compilador XC8
Registradores importantes – ADC :

 ADRESL: byte que guarda os 8 bits menos significativos da conversão


AD:

 ADRESH: byte que guarda os 8 bits mais significativos da conversão AD:

valor_convertido = (ADRESH * 0x0100) + ADRESL;


// guarda o valor da conversão AD na variável
// de 16 bits “valor_convertido”
EXEMPLO – CONVERSOR ANALÓGICO- adc.c

DIGITAL
Inicio

Inicia leitura da tensão


Configuração
no pino A0

não Finalizou sim Grava valor da leitura


leitura? nos bits da porta C e D
EXEMPLO – CONVERSOR ANALÓGICO- adc.c

DIGITAL
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
TRISC = 0b00000000; // Habilita porta C como saída

TRISA = 0x00000001; // Habilita pino A0 como entrada

ADCON2 = 0b10010110; // Tempo Aquisição: 4TAD; Clock:


Fosc/64
ADCON1 = 0b00000000; // Tensões de referência: Vss e Vdd

ADCON0bits.CHS = 0b0000; // Seleciona o canal AN0


EXEMPLO – CONVERSOR ANALÓGICO-DIGITAL

ADCON0bits.ADON = 1; // Habilita o conversor AD

while(1) { // Inicia loop infinito


ADCON0bits.GO = 1; // Inicia a conversão
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
LATD = ADRESL; // Transfere valor para porta D
LATC = ADRESH; // Transfere valor para porta C
__delay_ms(100); // Atraso de 100 ms
}

Fim de Código
EXEMPLO – ADC + LCD lcd.h adc_lcd.c

Inicio

Inicia leitura da tensão


Configuração
no pino A0

não sim Calcula tensão no pino e


Finalizou
exibe valor lido e tensão
leitura?
calculada no LCD
EXEMPLO – ADC + LCD lcd.h adc_lcd.c

#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include "lcd.h"
#include <stdio.h>

char linha1[16]; // Variável linha1 com 16


caracteres
char linha2[16]; // Variável linha2 com 16
EXEMPLO – ADC + LCD
int contador = 0; // Variável contador com valor
inicial 0
float tensao = 0.0; // Variável tensao com valor inicial
0.0

void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b010; // Tempo de aquisição: 4 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ADCON0bits.CHS = 0b0000; // Seleciona o canal AN0

ADCON0bits.ADON = 1; // Liga o AD
}

void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
EXEMPLO – ADC + LCD
setupADC();

Lcd_Init(); // Inicia o
LCD

while(1) { // Inicia loop infinito


ADCON0bits.GO = 1; // Inicia a conversão A/D
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor
para variável
tensao = ((5 * contador) * 0.0009765625); // Calcula tensão real
sprintf(linha1, "Conversor: %4i ", contador); // Grava texto em
linha1
sprintf(linha2, "Tensao: %1.2f ",tensao); // Grava texto em
linha2
Lcd_Set_Cursor(1,1); // Posiciona o cursor na
linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD
Lcd_Set_Cursor(2,1); // Posiciona o cursor na
linha 2, caractere 1
Fim de Código
EXEMPLO – ADC + LCD + DOIS CANAIS
Inicio

Lê tensão no pino A0 e Atualiza LCD com os


Configuração
guarda valores lidos lcd.h

adc_lcd_2ch.c

Lê tensão no pino A1 e
guarda
EXEMPLO – ADC + LCD + DOIS CANAIS
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD > lcd.h

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
adc_lcd_2ch.c
#include "lcd.h"
#include <stdio.h>

char linha1[16]; // Variável linha1


com 16 caracteres
char linha2[16]; // Variável linha2
EXEMPLO – ADC + LCD + DOIS CANAIS

int contador = 0; // Variável contador com


valor inicial 0
float tensao1 = 0.0; // Variável tensao com valor inicial 0.0
float tensao2 = 0.0; // Variável tensao com valor inicial 0.0

void setupADC(void) {
TRISA = 0b00000011; // Habilita pinos A0 e A1 como entrada

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b010; // Tempo de aquisição: 4 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ADCON0bits.ADON = 1; // Liga o circuito AD


}

void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
EXEMPLO – ADC + LCD + DOIS CANAIS
TRISD = 0b00000000; // Habilita porta D como saída

setupADC();
Lcd_Init(); // Inicia o
LCD

while(1) { // Inicia loop infinito


ADCON0bits.CHS = 0b0000; // Seleciona canal AN0
ADCON0bits.GO = 1; // Inicia a conversão
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor para variável
tensao1 = ((5 * contador)/1023.0); // Calcula tensão real

ADCON0bits.CHS = 0b0001; // Seleciona canal AN1


ADCON0bits.GO = 1; // Inicia a conversão
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor para
variável
tensao2 = ((5 * contador)/1.023.0); // Calcula tensão real
EXEMPLO – ADC + LCD + DOIS CANAIS

sprintf(linha1, "Tensao 1: %1.2f ",tensao1); // Grava texto em


linha1
sprintf(linha2, "Tensao 2: %1.2f ",tensao2); // Grava texto em
linha2

Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1,


caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD

Lcd_Set_Cursor(2,1); // Posiciona o cursor na linha 2,


caractere 1
Lcd_Write_String(linha2); // Escreve texto de linha2 no LCD
}

Fim de Código
EXEMPLO – ADC + LCD + 4 CANAIS

Início

Atualiza LCD
(chama rotina que lê
Configuração
tensão nos pinos A0 a
lcd.h
A4 automaticamente)

adc_lcd_4ch.c
EXEMPLO – ADC + LCD + 4 CANAIS
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >
lcd.h
#pragma config FOSC = INTIO // Oscilador interno
#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
adc_lcd_4ch.c
#include "lcd.h"
#include <stdio.h>

char linha1[16]; // Variável linha1


com 16 caracteres
char linha2[16]; // Variável linha2
EXEMPLO – ADC + LCD + 4 CANAIS
Seleção do clock do
AD

void setupADC(void) {

TRISA = 0b00001111; // Habilita pinos A0 a A3 como entrada

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b110; // Tempo de aquisição automático: 16 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ADCON0bits.ADON = 1; // Liga o circuito AD


}

float leTensao(int canal_adc) {


ADCON0bits.CHS = canal_adc; // Seleciona canal
ADCON0bits.GO = 1; // Inicia a conversão
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
int contador = (ADRESH * 0x100) + ADRESL; // Transfere valor para variável
EXEMPLO – ADC + LCD + 4 CANAIS
float tensao = ((5 * contador)/1023.0); // Calcula tensão real
return tensao;
}

void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
setupADC();
Lcd_Init(); // Inicia o LCD
while(1) { // Inicia loop infinito
sprintf(linha1, "T0: %1.1f T1: %1.1f", leTensao(0), leTensao(1)); //Grava texto em linha1
sprintf(linha2, "T2: %1.1f T3: %1.1f", leTensao(2), leTensao(3)); //Grava texto em linha2

Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1, caractere 1


Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD
Lcd_Set_Cursor(2,1); // Posiciona o cursor na linha 2, caractere
1
Lcd_Write_String(linha2); // Escreve texto de linha2 no LCD
}
}

Fim de Código
EXEMPLO – ADC + LCD + 8 CANAIS + INT
Inicio

lcd.h adc_lcd_8ch.c
Atualiza LCD
Configuração com as variáveis tensão[0] a
(x = 0) tensão[7];
Inicia leitura do pino ANx

não
Atualiza variável
tensão[x] com o xé
Leitura
valor da tensão no maior
finalizada? sim
não pino Ax; que 7?
Incrementa x
sim
x=0
EXEMPLO – ADC + LCD + 8 CANAIS + INT
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado lcd.h
#pragma config MCLRE = OFF // Master Clear desabilitado

#include "lcd.h"
#include <stdio.h>
adc_lcd_8ch.c

char linha1[16]; // Variável linha1 com 16


caracteres
char linha2[16]; // Variável linha2 com 16
caracteres
EXEMPLO – ADC + LCD + 8 CANAIS + INT
int canal = 0; // Variável que diz qual canal é lido
atualmente
float tensao[8]; // Vetor que guarda a tensão em cada um dos
canais
bit atualizado; // Flag que indica se todos canais já foram
lidos

void setupADC(void) {
TRISA = 0b00101111; // Habilita pinos A0 a A3 e A5 como entrada
TRISE = 0b00000111; // Habilita pinos E0 a E2 como entrada
// São os pinos relativos a AN0 a AN7

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b110; // Tempo de aquisição automático: 16 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ADCON0bits.ADON = 1; // Liga o circuito AD


EXEMPLO – ADC + LCD + 8 CANAIS + INT
void setupInterrupcao(void) {
GIE = 1; // Habilita interrupção global
PEIE = 1; // ADC exige interrupção de periféricos habilitada
ADIE = 1; // Liga interrupção pelo AD
}

void interrupt adc_interrupt(void) {


if (ADIF) {
int contador = (ADRESH * 0x100) + ADRESL; // Transfere valor para variável
tensao[canal] = ((5 * contador)/1023.0); // Calcula tensão real
if (canal == 7) { // Verificação para alternar
canal = 0; // o canal lido a cada interrupcao
ADCON0bits.CHS = canal; // Seleciona canal
atualizado = 1; // Marca a flag caso ja leu os 4 canais
} else {
canal++; // Atualiza o canal
ADCON0bits.CHS = canal; // Seleciona canal
ADCON0bits.GO = 1; // Inicia a conversão
}
ADIF = 0; // Desmarca flag da interrupção ADC
EXEMPLO – ADC + LCD + 8 CANAIS + INT
}
}

void main(void) {
OSCCON = 0b01010000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
Lcd_Init(); // Inicia o LCD
setupADC(); // Configura o ADC
setupInterrupcao(); // Configura a interrupção
atualizado = 0; // Marca a flag para atualizar os 8 canais
ADCON0bits.CHS = canal; // Seleciona canal
ADCON0bits.GO = 1; // Inicia a conversão

while(1) { // Inicia loop infinito


sprintf(linha1, "1:%1.0f 2:%1.0f 3:%1.0f 4:%1.0f",
tensao[0], tensao[1], tensao[2], tensao[3]); // Grava
texto em linha1
sprintf(linha2, "5:%1.0f 6:%1.0f 7:%1.0f 8:%1.0f",
tensao[4], tensao[5], tensao[6], tensao[7]); // Grava
texto em linha2
EXEMPLO – ADC + LCD + 8 CANAIS + INT

Lcd_Set_Cursor(1,1); // Posiciona o cursor na


linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD
Lcd_Set_Cursor(2,1); // Posiciona o cursor na
linha 2, caractere 1
Lcd_Write_String(linha2); // Escreve texto de linha2 no
LCD
atualizado = 0; // Marca a flag para atualizar os 4
canais
ADCON0bits.GO = 1; // Inicia a conversão
}
}

Fim de Código
TEMPORIZADORES/
CONTADORES
Timer 0 configurado para 8 bits (T08BIT =
1) ou 16 bits (T08BIT = 0)

Escolha entre temporizador (T0CS = 0) ou


contador (T0CS = 1)

No modo Contador, o Timer 0 incrementa


seu registrador interno na transição de 0 para
1 no pino RA4 (T0CKI), se T0SE = 0. Se
T0SE = 1, o incremento é na transição de 1
para 0
EXEMPLO – TEMPORIZADOR 0 interrupcao_TMR0.c

Inicio

Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 50 ms)

não Interrupção sim


Inverte sinal do LED
ativada?
EXEMPLO – TEMPORIZADOR 0 interrupcao_TMR0.c

#define _XTAL_FREQ 4000000 // Oscilador a 4 MHz. O número de instruções por


// segundo é de 1 milhão. O
tempo para executar uma
#include <xc.h> // instrução (e do tick do timer) é de 1 us.

#pragma config FOSC = HS // Oscilador externo


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void setupInt(void) {
GIE = 1; // Habilita interrupção global
TMR0IE = 1; // interrupção do Timer 0
}

void setupTmr0() {
T08BIT = 0; // Modo 16 bits
T0CS = 0; // Source do clock (operando como temporizador, e não como contador
PSA = 1; // Desabilita Prescaler
TMR0H = 0x3C; // Começa a contar de 15535
TMR0L = 0xAF; // até 65535 (conta 50 mil vezes)
TMR0ON = 1; // Liga o timer
}
EXEMPLO – TEMPORIZADOR 0
void interrupt interrupcao(void) { // Função de interrupção
if (TMR0IF) { // Caso a flag do
temporizador esteja ativa
LATDbits.LD0 = !LATDbits.LD0; // Inverte pino D0
TMR0H = 0x3C; // Começa a contar de 15535
TMR0L = 0xAF; // até 65535 (conta 50 mil
vezes)
TMR0IF = 0; // Flag do timer 0 em 0
}
}

void main(void) {
TRISD = 0x00; // Porta D como saída
setupInt(); // Função de habilitar
interrupção
setupTmr0(); // Função de configurar timer
0
while(1) { // Loop infinito
}
}
// O código acima inverte o sinal do pino D0 a cada 50000 us, via temporizador 0.
Fim de Código
EXEMPLO – TEMPORIZADOR 0 + PRESCALER
Inicio
interrupcao_TMR0Pre.c

Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 1s)

Interrupção
Inverte sinal do LED
ativada? sim
não
EXEMPLO – TEMPORIZADOR 0 + interrupcao_TMR0Pre.c
PRESCALER
#define _XTAL_FREQ 4000000 // Oscilador a 4 MHz. O número de instruções
por
// segundo é de 1
milhão. O tempo para executar uma
#include <xc.h> // instrução (e do tick do timer) é de
1 us.

#pragma config FOSC = HS // Oscilador externo


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void setupInt(void) {
GIE = 1; // Habilita interrupção global
TMR0IE = 1; // interrupção do Timer 0
}

void setupTmr0() {
T08BIT = 0; // Modo 16 bits
T0CS = 0; // Fonte do clock = interna
PSA = 0; // Habilita Prescaler
EXEMPLO – TEMPORIZADOR 0 + PRESCALER PIC16F4550
TMR0H = 0x85; // Começa a contar de 34285
TMR0L = 0xED; // até 65535 (conta 31250 vezes)
TMR0ON = 1; // Liga o timer
}

void interrupt interrupcao(void) { // Função de interrupção


if (TMR0IF) { // Caso a flag do
temporizador esteja ativa
LATDbits.LD0 = !LATDbits.LD0; // Inverte pino D0
TMR0H = 0x85; // Começa a contar de 34285
TMR0L = 0xED; // até 65535 (conta 31250 vezes)
TMR0IF = 0; // Flag do timer 0 em 0
}
}
void main(void) {
setupInt(); // Função de
habilitar interrupção
setupTmr0(); // Função de
configurar timer 0
TRISD = 0x00; // Porta D como saída
while(1) { // Loop infinito
}
}
// O código acima inverte o sinal doFim de Código
pino D0 a cada 1 s, via temporizador 0.
Temporizador 2
Em operação normal, o Timer 2 começa a contar de TMR2 = 0 e, a cada ciclo de contagem, compara os
valores de TMR2 e PR2. Quando os dois valores forem iguais, ele gera um sinal na saída do temporizador,
além de zerar o registrador TMR2 e setar a flag TMR2IF.
EXEMPLO – TEMPORIZADOR 2 interrupcao_TMR2.c

Inicio

Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 10 ms)

Interrupção
Inverte sinal do LED
ativada? sim
não
EXEMPLO – TEMPORIZADOR 2 interrupcao_TMR2.c

#define _XTAL_FREQ 4000000 // Oscilador a 4 MHz. O número de instruções por


// segundo é de 1 milhão.
O tempo para executar uma
#include <xc.h> // instrução (e do tick do timer) é de 1 us.
#pragma config FOSC = HS // Oscilador Externo
#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void setupInt(void) {
GIE = 1; // Habilita interrupção global
PEIE = 1; // Timer 2 exige interrupção de periféricos habilitada
TMR2IE = 1; // interrupção do Timer 2
}

void setupTmr2() {
T2CKPS0 = 1; // Prescaler x 4
T2CKPS1 = 0; //
T2OUTPS0 = 0; // Postscaler x 10
T2OUTPS1 = 1; //
T2OUTPS2 = 0; // Conta 250 (PR2, abaixo) x 4 (prescaler) x 10 (postscaler)
vezes
EXEMPLO – TEMPORIZADOR 2
TMR2 = 0x00; // Começa a contar de 0
PR2 = 249; // até 249 (conta 250 vezes + recarga automatica)
TMR2ON = 1; // Liga o timer
}

void interrupt interrupcao(void) { // Função de interrupção


if (TMR2IF) { // Caso a flag do
temporizador esteja ativa
LATAbits.LD0 = !LATAbits.LD0; // Inverte pino D0
TMR2IF = 0; // Flag do timer 2 em 0
}
}

void main(void) {
setupInt(); // Função de habilitar
interrupção
setupTmr2(); // Função de configurar
timer 0
TRISD = 0x00; // Porta D como saída
while(1) { // Loop infinito
}
} // O código acima inverte o valorFim
do de Código
pino D0 a cada 10 ms usando o Timer 2.
EXEMPLO – ADC + LCD + TIMER lcd.h adc_lcd_tmr.c

Inicio

Configuração
Atualiza LCD com o valor da
(configura timer para
variável “tensão” e
interromper a cada 10
“contador”
ms)

não sim Grava tensão do pino AN0 na


Interrupção do
variável “tensão”;
conversor AD?
Incrementa “contador”;

não sim
Interrupção do Inicia leitura no
timer? conversor AD
EXEMPLO – ADC + LCD + TIMER lcd.h adc_lcd_tmr.c

#define _XTAL_FREQ 4000000

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include <xc.h>
#include "lcd.h"
#include <stdio.h>

char linha1[16]; // Variável linha1 com


16 caracteres
char linha2[16]; // Variável linha2 com
16 caracteres
EXEMPLO – ADC + LCD + TIMER

float tensao = 0.0; // Variável que guarda a tensão lida no conversor AD


long contagem = 10000; // Variável que define quantos us serão contados a cada conversão

void interrupt interrupcao() {


if (ADIF) {
int leitura_adc = (ADRESH * 0x100) + ADRESL; // Transfere valor para variável
tensao = ((5 * leitura_adc) * 0.0009765625); // Calcula tensão real
contador++;
// Incrementa contador
ADIF = 0; // Desmarca flag da interrupção ADC
}
if (TMR3IF) {
TMR3H = (0xFFFF - contagem) >> 8; // Cálculo do valor
inicial do TMR3
TMR3L = ((0xFFFF - contagem) & 0xFF); // Cálculo do valor inicial
do TMR3
LATDbits.LD0 = !LATDbits.LD0; // Inverte sinal no pino D0
TMR3IF = 0; // Limpa a Flag da interrupção
ADCON0bits.GO = 1; // Inicia conversao AD
}
EXEMPLO – ADC + LCD + TIMER

void setupTmr3() {
T3CKPS0 = 0; // Prescaler
T3CKPS1 = 0; // Prescaler
TMR3CS = 0; // Clock origina do clock interno

TMR3H = (0xFFFF - contagem) >> 8; // Cálculo do valor inicial do


TMR3
TMR3L = ((0xFFFF - contagem) & 0xFF); // Cálculo do valor inicial do
TMR3

TMR3ON = 1; // Liga o timer


}

void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 entrada

ADCON2bits.ADCS = 0b1111; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b110; // Tempo de aquisição automático: 16 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd
EXEMPLO – ADC + LCD + TIMER
ADCON0bits.CHS = 0b0000; // Seleciona canal AN0

ADCON0bits.ADON = 1; // Liga o circuito AD


}

void setupInt(void) {
GIE = 1; // Habilita interrupção global
PEIE = 1; // Habilita interrupção de periféricos
TMR3IE = 1; // Interrupção do timer 3
ADIE = 1; // Habilita interrupção do ADC
}

void main(void) {
OSCCON = 0b01010000; // Oscilador interno a 4 MHz
TRISA = 1; // A0 como entrada
TRISD = 0; // Define porta D
inteira como saída
setupADC(); // Configuração do ADC
setupInt(); // Configuração da Interrupção
EXEMPLO – ADC + LCD + TIMER

setupTmr3(); // Configuração do Timer 3


Lcd_Init(); // Inicia o
LCD

while(1) {
sprintf(linha1, "N: %i", contador); // Grava texto em
linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1,
caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD
sprintf(linha2, "Tensao: %3.2f", tensao); // Grava texto em
linha2
Lcd_Set_Cursor(2,1); // Posiciona o cursor na
linha 2, caractere 1
Lcd_Write_String(linha2); // Escreve texto de linha2 no
LCD
} Fim de Código
}
MÓDULOS DE CAPTURE/
COMPARE/PWM
(CCP)
Os módulos de Captura, Comparação e PWM contém:

 1 registrador de 16 bits que opera como registrador de captura

 1 registrador de 16 bits para comparação ou

 1 registrador Mestre/Escravo para o Duty cycle de PWM


Configuração do Módulo CCP:
 Cada módulo (Captura, Comparação e PWM) está associado a um registrador de
controle (genericamente, CCPxCON) e um registrador de dados (CCPRx)
 O registrador CCPRx é composto por dois registradores de 8 bits: CCPRxL, para o
byte inferior e CCPRxH, para o byte superior
 A Tabela a seguir mostra os temporizadores associados a cada modo
Modo de Captura:
 No modo de Captura, o par de registradores CCPRxH:CCPRxL captura o valor de 16
bits dos registradores do Timer 1 ou do Timer 3, quando ocorre um evento no pino
CCPx correspondente
 Um evento é definido como uma das seguintes ocorrências:

 Cada transição decrescente

 Cada transição crescente

 Cada 4ª transição crescente

 Cada 16ª transição crescente


Modo de Comparação:
 No modo de Comparação, o valor do registrador CCPRx é constantemente comparado
com os valores dos pares de registradores do Timer 1 ou do Timer 3
 Quando ocorre uma equivalência (igualdade), o pino CCPx pode ser:

 Levado ao nível lógico alto

 Levado ao nível lógico baixo

 Inverter o estado do pino (baixo para alto ou alto para baixo)

 Permanecer inalterado
Modo PWM
 No modo PWM (Modulação de Largura de
Pulso), o pino CCPx produz uma saída PWM
com resolução de até 10 bits.
 Uma vez que o pino CCP2 é multiplexado
com um latch de dados da Porta B ou da Porta
C, o bit TRIS apropriado deve ser zerado para
fazer o pino CCP2 um pino de saída.
Modo PWM (Período)
 O Período de PWM é definido através do registrador PR2

 O Período de PWM pode ser calculado usando a fórmula:

 A frequência de PWM é o inverso do período (1/PWM)

 Quando TMR2 é igual a PR2, os três eventos seguintes ocorrem no próximo ciclo
crescente:

 TMR2 é zerado

 O pino CCPx é setado (exceto se o duty cycle for 0%)

 O duty cycle do PWM é transferido de CCPRxL para CCPRxH


Modo PWM (Duty Cycle)
 O Duty Cycle do PWM é definido escrevendo-se no registrador CCPRxL e nos
bits 4 e 5 de CCPxCON.
 Uma resolução de até 10 bits está disponível

 O registrador CCPRxL contém dos 8 bits mais significativos e os dois bits (4 e 5


de CCPxCON) são os bits menos significativos
 O valor de 10 bits é representado por: CCPRxL:CCPxCON<5:4>

 O Duty Cycle pode ser calculado usando a expressão:


Modo PWM
(Passos para a Configuração do PWM)
 Os seguintes passos devem ser executados quando configurando o módulo CCPx
para operação no modo PWM:
o Definir o período de PWM escrevendo no registrador PR2

o Definir o duty cycle escrevendo no registrador CCPRxL e nos bits


CCPxCON<5:4>
o Definir o pino CCPx como saída, através da instrução TRIS

o Definir o valor de pré-escala de TMR2, e então habitar o Timer 2, escrevendo em


T2CON
o Configurar o módulo CCPx para operação no modo PWM
Linguagem C – compilador XC8

Registradores importantes – PWM:


 CCPR2L: byte que define o duty cycle do PWM2:

CCPR2L = 26; // Define PWM com duty-cycle de 10%


CCPR2L = 255; // Define PWM com duty-cycle de 100%
CCPR2L = 128; // Define PWM com duty-cycle de 50%
CCPR2L = 77; // Define PWM com um duty-cycle de
30%
EXEMPLO – PWM pwm.c

Inicio

Configuração
(configura
. . . É, não faz nada.
temporizador e
PWM)
EXEMPLO – PWM pwm.c

#define _XTAL_FREQ 4000000

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include <xc.h>

void setupTmr2() {
TMR2 = 0x00; // Começa a contar de 0
PR2 = 249; // até 250 (conta 250 vezes + recarga automatica)
}

void setupPWM (void) {


TRISCbits.RC1 = 1; // "desliga" bit de saída
setupTmr2(); // Configura timer 2
CCP2CONbits.CCP2M = 0b1100; // Modo PWM ativo
CCPR2L = 128; // Duty cycle % do PWM (0 - 255), portanto 128 = 50%
EXEMPLO – PWM

TMR2IF = 0; // Limpa flag do TMR2


TMR2ON = 1; // Dispara o timer
TRISCbits.RC1 = 0; // "liga" bit de saída
}

void main(void) {
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
setupPWM();

while(1) {
}
}

// Gera um sinal PWM na saída do pino RC1

Fim de Código
EXEMPLO – PWM + ADC pwm_adc.c

Inicio

Inicia conversão AD no pino


Configuração
AN0

Atualiza valor do “duty cycle”


Interrupção do
do PWM baseado no valor de
não conversor AD? sim tensão lido no pino AN0
EXEMPLO – PWM + ADC pwm_adc.c

#define _XTAL_FREQ 4000000

#pragma config FOSC = HS // Oscilador externo High Speed


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include <xc.h>

long contagem = 0; // Variável auxiliar

void interrupt interrupcao() {


if (ADIF) {
contagem = (ADRESH * 0x100) + ADRESL; // Transfere a leitura do AD para a
contagem = contagem >> 2; // rotacional 2 posições à direita (divide por 4)
CCPR2L = contagem; // para ajustar aos aos 8 bits do PWM
ADIF = 0; // Desmarca flag da interrupção ADC
}
if (TMR2IF) { // Caso a flag do
temporizador esteja ativa,
TMR2IF = 0; // desmarca a mesma
EXEMPLO – PWM + ADC
}
}

void setupTmr2() {
TMR2 = 0x00; // Começa a contar de 0
PR2 = 249; // até 250 (conta 250 vezes + recarga automatica)
}

void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0entrada

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b010; // Tempo de aquisição: 4 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ADCON0bits.CHS = 0b0000; // Seleciona o canal AN0


ADCON0bits.ADON = 1; // Liga o AD
}
EXEMPLO – PWM + ADC
void setupInt(void) {
GIE = 1; // Habilita interrupção global
PEIE = 1; // Habilita interrupção de periféricos
TMR2IE = 1; // Interrupção do timer 2
ADIE = 1; // Habilita interrupção do ADC

void setupPWM (void) {


TRISCbits.RC1 = 1; // "desliga" bit de saída
setupTmr2(); // Configura timer 2
CCP2CONbits.CCP2M = 0b1100; // Modo PWM ativo
CCPR2L = 128; // Configura % do PWM (0 - 255)
TMR2IF = 0; // Limpa flag do TMR2
TMR2ON = 1; // Dispara o timer
EXEMPLO – PWM + ADC
TRISCbits.RC1 = 0; // "liga" bit de saída

void main(void) {
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
TRISD = 0; // Define porta D
inteira como saída
LATD = 1; // Acende o primeiro LED da porta D
setupADC(); // Configuração do ADC
setupInt(); // Configuração da Interrupção
setupPWM(); // Configuração do PWM

while(1) {
ADCON0bits.GO = 1; // Lê ADC, para recarregar valor no PWM
while (ADCON0bits.NOT_DONE) {
}
}
}
// Gera um sinal PWM na saída com ciclo variando de acordo com a tensão no pino A0
Fim de Código
TRANSDUTOR DE
TEMPERATURA + LCD
LM35 + LCD
Inicio

Configuração Leitura do LM35


do ADC e do Inicia conversão AD no pino
LCD AN0

A tensão de referência do AD é
fundamental porque a tensão
máxima de saída do LM35 é Converte leitura do AD em
Acabou a
1,5 V, para uma temperatura de temperatura
não conversão? sim
150ºC Mostra valor no LCD
LM35 + LCD
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "lcd.h"

#pragma config FOSC = HS // Oscilador externo


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
LM35 + LCD
char linha1[16]; // Variável linha1 com 16 caracteres
char linha2[16]; // Variável linha2 com 16 caracteres
long contador;
float temperatura;

void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada

ADCON2bits.ADCS = 0b110; // Clock do AD: Fosc/64


ADCON2bits.ACQT = 0b010; // Tempo de aquisição: 4 Tad
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b01; // Tensões de referência: Vss e Pino AN3

// ADCON0 = 0; // Seleciona o canal AN0


ADCON0bits.CHS = 0b0001; // Seleciona o canal AN1
ADCON0bits.ADON = 1; // Liga o AD
}

Com essa configuração, a tensão de referência positiva VREF+ para o AD está no pino AN3. Foi utilizada uma fonte de 1,5 V
nesse pino. Assim, a saída máxima do LM35 resulta na saída máxima do AD
LM35 + LCD
void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
setupADC();
Lcd_Init(); // Inicia o LCD

while(1) { // Inicia loop infinito


ADCON0bits.GO = 1; // Inicia a conversão A/D
while (!ADCON0bits.GODONE) { // Aguarda fim da conversão
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor para variável
temperatura = ((1.5 * 100 * contador)/1023.0); // Calcula temperatura

sprintf(linha1, "Leitura AD: %4i ", contador); // Grava texto em linha1


sprintf(linha2, "Temperat.: %3.1f ",temperatura); // Grava texto em linha2
Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD
Lcd_Set_Cursor(2,1); // Posiciona o cursor na linha 2, caractere 1
Lcd_Write_String(linha2); // Escreve texto de linha2 no LCD
}
return; LM35: 10mV/ºC  leitura do AD é convertida para tensão e dividida por 0,01 (multiplicada
} por 100)
COMUNICAÇÃO SERIAL
SERIAL EUSART

 O módulo de comunicação serial EUSART (Enhanced Universal Synchronous Asynchronous


Receiver Transmitter) do PIC18F4550 é um dos dois módulos de comunicação serial. Ele
pode ser configurado para operar nos seguintes modos:
 Asynchronous full duplex com
Auto reativação, com sinal de parada
Calibração automática da taxa baud rate
Transmissão de caracteres de parada de 12 bits

 Synchronous Master (half duplex) com polaridade de clock selecionável


 Synchronous Slave (half duplex) com polaridade de clock selecionável
SERIAL EUSART
 Os pinos do módulo EUSART são multiplexados com a Porta C. Para configurar os pinos
RC6/TX/CK e RC7/RX/DT/SDO como uma EUSART, é necessário:
Fazer SPEN = 1 (bit 7 do registrador RCSTA)
Definir os bits 6 e 7 da Porta C como entrada:
TRISCbits.RC6 = 1 e TRISCbits.RC7 = 1
Obs.: O controle do módulo EUSART fará a reconfiguração de entrada para saída
desses pinos, sempre que necessário.

 A operação do módulo EUSART é controlada através de 3 registradores


TXSTA – Transmit Status and Control
RCSTA – Receive Status and Control
BAUDCON – Controle de Baud Rate
SERIAL EUSART

Bit de seleção da fonte de clock SYNC = 1  modo síncrono


Bit de status do registrador de
No modo síncrono: SYNC = 0  modo assíncrono
deslocamento
1 – Master (clock interno) TRMT = 1  TSR vazio
0 – Slave (clock externo) Modo síncrono: bit irrelevante TRMT = 0  TSR cheio
No modo assíncrono: irrelevante Modo assíncrono:
SENDB = 1  envia bit de parada Dado transmitido no 9º bit.
SENDB = 0  transmissão completada Pode ser endereço, dado ou
paridade
TX9 = 1  transmissão de 9 bits Modo síncrono: não utilizado
TX9 = 0  transmissão de 8 bits Modo assíncrono:
BRGH = 1  baud rate alto
TXEN = 1  habilita transmissão BRGH = 0  baud rate baixo
TXEN = 0  desabilita transmissão
SERIAL EUSART

Habilita porta serial Habilita recepção contínua


SPEN = 1  configura os pinos Modo assíncrono: Bit de erro de ultrapassagem
RX/DT e TX/CK como porta CREN = 1  habilita
serial Modo síncrono: Dado recebido no 9º bit. Pode
SPEN = 0  desabilita porta CREN = 1  habilita modo ser endereço, dado ou paridade
serial contínuo, até CREN = 0
Habilita detecção de endereço
RX9 = 1  recepção de 9 bits Modo 9 bits assíncrono:
RX9 = 0  recepção de 8 bits Habilita detecção de endereço e interrupção
Modo 8 bits assíncrono: Irrevante
Modo assíncrono  irrelevante
Modo síncrono:
SREN =1  habilita recepção simples
SREN = 0  desabilita recepção simples Bit de erro de quadro (framing)
SERIAL EUSART

Bit de status de rolagem na Bit de seleção da polidade dos dados


aquisição automática de baud rate transmitidos e do clock Bit que habilita a função “Wake-up”
Modo assíncrono: Modo assíncrono:
TXCKP = 1  dado de TX invertido WUE = 1  EUSART continuará a
RCIDL = 1  operação de Modo síncrono: leitura do pino RX
recepção está ociosa TXCKP = 1  clock invertido

Bit de seleção da polaridade dos dados recebidos Bit que habilita o registrador de baud rate de 16 bits
Modo assíncrono: BRG16 = 1  gerador de baud rate de 16 bits habilitado
RXDTP = 1  dado de RX invertido
Modo síncrono:
RXDTP =1  dado recebido é invertido Bit que habilita auto-detecção de baud
rate
SERIAL – Baud Rate O valor de “n” na fórmula
de cálculo do baud rate
corresponde ao par:
SPBRGH:SPBRG

Carregando o valor
desejado nesses
registradores, o PIC
automaticamente calcula a
taxa de
transmissão/recepção
SERIAL – Baud Rate – alguns valores de SPBRGH:SPBRG para
algumas taxas de transmissão/recepção
Modo assíncrono de 8 bits de baixo baud
rate

Modo assíncrono de 8 bits de alto baud rate

O valor de “n” a ser carregado em SPBRG


é 6, para gerar baud rate de 9600 bps (valor
efetivo é 8.929 bps)

O valor de “n” a ser carregado em SPBRG é


25, para gerar baud rate de 9600 bps (valor
efetivo é 9.615 bps)
SERIAL – Passos para a transmissão serial assíncrona
1. Defina o valor de SPBRGH:SPBRG (chamado de “n” na fórmula usada). A fórmula a ser usada depende dos valores de
BRGH e BRG16. :

BRG16 BRGH Cálculo de n = SPBRGH:SPBRG

0 0

0 1

2. Habilite a comunicação serial assíncrona fazendo SYNC = 0 e SPEN = 1.

3. Se se deseja inverter o sinal do pino TX, faz-se TXCKP = 1

4. Se quiser usar interrupção da transmissão, fazer TXIE = 1. É necessário também fazer GIE = 1 e PEIE =1

5. Para a transmissão de 9 bits, deve-se fazer TX9=1. O 9º bit deve ser carregado em TX9D

6. Para habilitar a transmissão serial fazer TXEN = 1, que setará também o bit TXIF.

7. A transmissão de dados começa automaticamente quando o dado a ser transmitido é carregado em


TXREG.
SERIAL – Passos para a recepção serial assíncrona
1. Defina o valor de SPBRGH:SPBRG (chamado de “n” na fórmula usada). A fórmula a ser usada depende dos valores de
BRGH e BRG16. :

BRG16 BRGH Cálculo de n = SPBRGH:SPBRG

0 0

0 1

2. Habilite a comunicação serial assíncrona fazendo SYNC = 0 e SPEN = 1.


3. Se se deseja inverter o sinal do pino RX, faz-se RXDTP = 1
4. Se quiser usar interrupção da recepção, fazer RCIE = 1. É necessário também fazer GIE = 1 e PEIE =1
5. Para a recepção de 9 bits, deve-se fazer RX9=1. O 9º bit é recebido através do registrador RCSTA
6. Para habilitar a recepção serial fazer CREN = 1.
7. A flag RCIF será automaticamente setada quando a recepção estiver completa. Assim, se a
interrupção estiver habilitada (RCIE =1), desviará para a função de tratamento da interrupção.
8. O byte recebido via serial é carregado no registrado RCREG
EXEMPLO - SERIAL serial.c

Inicio

Configuração;
Envia texto pra Aguarda interrupção
porta serial;

não sim
Interrupção da Envia texto para a porta serial
recepção serial? com caractere digitado;
EXEMPLO - SERIAL serial.c

#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000 // Oscilador interno de 4 MHz

#include <xc.h>

#pragma config FOSC = HS // Oscilador externo


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

char caracter;
bit flag_interrupcao = 0;

void interrupt RS232(void) //vetor de interrupção


{
caracter = RCREG; // Lê caractere recebido do registrador
flag_interrupcao = 1; // Habilita variável indicando que houve
recepção
RCIF = 0; // Limpa flag de interrupção de
recepção
}
SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
RCSTA:
1 0 0 1 0 0 0 0

SERIAL
void inicializa_RS232(long velocidade,int modo)
{
RCSTA = 0X90; // Habilita porta serial, recepção de 8 bits em modo continuo,
assíncrono.
int valor;
if (modo == 1) { // modo = 1, modo alta velocidade
(BRGH = 1)
TXSTA = 0X24; // modo assíncrono,
transmissão 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-16)/16); // valor para gerar o baud
rate
}
else { //modo = 0 ,modo
baixa velocidade (BRGH = 0)
TXSTA = 0X20; //modo assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);
//calculo do
valor do gerador de baud rate
}
SPBRG = valor; esse registrador, carregado com o “valor” calculado, define o baud
CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D
rate TXSTA:
RCIE = 1; 0 0 1 0 0//habilita
1 interrupção
0 de0
SERIAL
void escreve(char valor)
{
TXIF = 0; // limpa flag que sinaliza envio
completo.
TXREG = valor; // Envia caractere desejado à porta
serial
while(TXIF ==0); // espera caractere ser enviado
}

void imprime(const char frase[])


{
char indice = 0; // índice da cadeia de
caracteres
char tamanho = strlen(frase); // tamanho total da cadeia a ser impressa
while(indice < tamanho ) { // verifica se todos foram impressos
escreve(frase[indice]); // Chama rotina que escreve o
caractere
indice++; // incrementa índice
}
}
SERIAL
void main(void)
{
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
TRISB = 0X02; // configura portB B1 (pino RX) como
entrada
PORTB = 0; // limpar as portas que estão configuradas
como saidas
inicializa_RS232(9600,1); // modo de alta velocidade
GIE = 1; // GIE: Global Interrupt Enable bit
PEIE = 1; // habilita interrupção de
periféricos do pic
imprime("Usando a serial MPLAB X XC8 \n\r");
imprime(“Digite algo: \n\r");
while (1) {
if(flag_interrupcao == 1) { //tem dados
para ler
imprime(" \n\rCaractere digitado :");
escreve(caracter);
flag_interrupcao = 0;
}
} Fim de Código
EXEMPLO – SERIAL + LCD lcd.h serial_lcd.c

Inicio

Configuração;
Organiza posição do
Envia texto pra
Aguarda interrupção caractere na segunda linha do
porta serial e
LCD
LCD;

Interrupção da Envia texto para a porta serial


não recepção serial? e LCD com caractere digitado;
sim
EXEMPLO – SERIAL + LCD lcd.h serial_lcd.c

#define _XTAL_FREQ 4000000 // Oscilador interno de 4 MHz

#include <xc.h>

#define RS LATD2 // < Pinos do LCD


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD >

#include "lcd.h"
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado
EXEMPLO – SERIAL + LCD

char caracter;
char linha1[16]; // Variável linha1 com 16
caracteres
char linha2[16]; // Variável linha2 com 16
caracteres
bit flag_interrupcao = 0;

void interrupt RS232(void) //vetor de interrupção


{
caracter = RCREG; // Lê caractere recebido do registrador
flag_interrupcao = 1; // Habilita variável indicando que houve
recepção
RCIF = 0; // Limpa flag de interrupção de
recepção
}

void inicializa_RS232(long velocidade,int modo)


{
RCSTA = 0X90; // Habilita porta serial,
EXEMPLO – SERIAL + LCD
TXSTA = 0X24; // modo assíncrono,
transmissão 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-16)/16); // Cálculo do
baud rate
} else { //modo
= 0 ,modo baixa velocidade
TXSTA = 0X20; //modo
assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);

//calculo do valor do gerador de baud rate


}
SPBRG = valor;
RCIE = 1; //habilita interrupção de recepção
TXIE = 0; //deixa interrupção de transmissão
desligado
//(pois corre-se o risco de ter uma interrupção escrita e leitura ao mesmo
tempo)
}

void escreve(char valor)


EXEMPLO – SERIAL + LCD
void imprime(const char frase[])
{
char indice = 0; // índice da cadeia de
caracteres
char tamanho = strlen(frase); // tamanho total da cadeia a ser impressa
while(indice < tamanho ) { // verifica se todos foram impressos
escreve(frase[indice]); // Chama rotina que escreve o caractere
indice++; // incrementa índice
}
}

void main(void)
{
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
TRISB = 0X02; // configura portB B1 (pino RX) como
entrada
PORTB = 0; // limpar as portas que estão configuradas
como saidas
inicializa_RS232(9600,1); // modo de alta velocidade
GIE = 1; // GIE: Global Interrupt Enable bit
EXEMPLO – SERIAL + LCD

TRISD = 0x00; // configura portD como saída


Lcd_Init(); // Inicia o LCD
int posicao = 1; // Variável que guarda posição do caractere no LCD

imprime("Usando a serial MPLAB X XC8 \n\r"); // Envia texto para a


serial
imprime("Digite algo: \n\r");

Lcd_Set_Cursor(1,1); // Posiciona o cursor na


linha 1, caractere 1
sprintf(linha1, "Digite algo:"); // Grava texto em linha1
Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD

while (1) {
if(flag_interrupcao == 1) { // Tem dados
para ler
imprime(" \n\rCaractere digitado: ");
escreve(caracter);

Lcd_Set_Cursor(1,1); // Posiciona o cursor na linha 1,


caractere 1
EXEMPLO – SERIAL + LCD

Lcd_Set_Cursor(2,posicao); // Posiciona o cursor na linha 2, ultima


posicao
sprintf(linha1, "%c", caracter); // Grava texto em linha2
Lcd_Write_String(linha1); // Escreve texto de linha2 no
LCD

if (posicao == 16) {
posicao = 1;
} else {
posicao++;
}

flag_interrupcao = 0;
}
}
//loop infinito

Fim de Código
EXEMPLO – SERIAL + ADC serial_adc.c

Inicio

Configuração;
Inicia leitura da tensão no
Envia texto pra
pino AN0
porta serial;

Finalizou a Envia texto para a porta serial


leitura? sim com tensão lida;
não
EXEMPLO – SERIAL + ADC serial_adc.c

#define _XTAL_FREQ 4000000 // Oscilador interno de 4 MHz

#include <xc.h>
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

char caracter;
bit flag_interrupcao = 0;
char linha[22];
int contador;
float tensao;

void inicializa_RS232(long velocidade,int modo)


{
RCSTA = 0X90; // Habilita porta serial, recepção de
EXEMPLO – SERIAL + ADC
// 8 bits em modo
continuo, assíncrono.
int valor;
if (modo == 1) { // modo = 1, modo alta
velocidade
TXSTA = 0X24; // modo assíncrono,
transmissão 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-16)/16); // Cálculo do
baud rate
} else { //modo
= 0 ,modo baixa velocidade
TXSTA = 0X20; //modo
assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);

//calculo do valor do gerador de baud rate


}
SPBRG = valor;
RCIE = 1;
//habilita interrupção de recepção
TXIE = 0; //deixa interrupção de
EXEMPLO – SERIAL + ADC
TXREG = valor; // Envia caractere à
porta serial
while(TXIF ==0); // espera caractere ser
enviado
}

void imprime(const char frase[])


{
char indice = 0; // índice da cadeia de
caracteres
char tamanho = strlen(frase); // tamanho total da cadeia a ser impressa
while(indice < tamanho ) { // verifica se todos foram impressos
escreve(frase[indice]); // Chama rotina que escreve o caractere
indice++; // incrementa índice
}
}

void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada

ADCON2bits.ADCS = 0b111; // Tempo de aquisição: 4 Tad


EXEMPLO – SERIAL + ADC
ADCON2bits.ADFM = 0b1; // Formato: à direita
ADCON1bits.VCFG = 0b00; // Tensões de referência: Vss e Vdd

ANSEL = 0x00000001; // Seleciona o canal AN0

ADCON0bits.ADON = 1; // Liga o AD
}

void SuperDelay(long counter) { // Função com valor de


entrada “counter”
counter = counter / 10; // Divide o valor informado por 10
for (long i = 1; i <= counter; i++) { // E usa o resultado como base
__delay_ms(10); // Para repetir uma
contagem de 10 ms
}
}

void main(void)
{
OSCCON = 0b01010000; // Oscilador interno a 4 MHz
EXEMPLO – SERIAL + ADC
TRISB = 0X02; // configura portB B1 (pino RX) como
entrada
PORTB = 0; // limpar as portas que estão configuradas
como saidas
inicializa_RS232(9600,1); // modo de alta velocidade
setupADC(); // Configuração do AD

sprintf(linha, "Tensão lida: 0.000"); // Grava texto em


linha1
imprime(linha);

while (1) {
ADCON0bits.GO = 1;
// Inicia leitura do ADC
while(ADCON0bits.NOT_DONE) { // Aguarda
leitura do ADC
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor
para variável
tensao = ((5 * contador) * 0.0009765625); // Calcula tensão real
sprintf(linha, "\b\b\b\b\b%1.3f", tensao); // Grava texto em linha1
imprime(linha); Fim de Código
PROGRAMAS COM BUGS #1 – ROTAÇÃO DE LEDS

Comportamento esperado:
Os LEDs rotacionem no estilo
“bate-e-volta”.

Sintoma:
Ao iniciar o programa, os LEDs
começam a rotacionar corretamente,
mas depois de várias rotações, ele
volta a rotacionar do primeiro LED.
PROGRAMAS COM BUGS #1 – ROTAÇÃO DE LEDS
#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz
#include <xc.h>
#pragma config FOSC = INTIO67 // Oscilador interno
#pragma config WDTEN = ON // Watchdog Timer ligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
TRISA = 0b00000000; // Habilita porta A como saída
LATA = 1; // Liga o primeiro pino da porta A
while(1) {
// Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com
estilo pra esquerda
__delay_ms(100); //
Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); //
Atraso de 100 ms Fim de Código
PROGRAMAS COM BUGS #2 – ROTAÇÃO DE LEDS

Comportamento esperado:
Os LEDs rotacionem no estilo
“bate-e-volta”.

Sintoma:
Ao iniciar o programa, nada
acontece.
PROGRAMAS COM BUGS #2 – ROTAÇÃO DE LEDS

#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz


#include <xc.h>
#pragma config FOSC = INTIO67 // Oscilador interno
#pragma config WDTEN = ON // Watchdog Timer ligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
TRISA = 0b00000000; // Habilita porta A como saída
LATA = 1; // Liga o primeiro pino da porta A
while(1) {
// Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com
estilo pra esquerda
__delay_ms(100); //
Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); //
Atraso de 100 ms Fim de Código
PROGRAMAS COM BUGS #3 – ROTAÇÃO DE LEDS

Comportamento esperado:
Os LEDs rotacionem no estilo
“bate-e-volta”.

Sintoma:
Ao iniciar o programa, nada
acontece. A tensão nos pinos
de saída dos LEDs não
mostram nenhum valor bem
definido.
PROGRAMAS COM BUGS #3 – ROTAÇÃO DE LEDS

#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz


#include <xc.h>
#pragma config FOSC = INTIO67 // Oscilador interno
#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
LATA = 1; // Liga o primeiro pino da porta A
while(1) {
// Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com
estilo pra esquerda
__delay_ms(100); //
Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); //
Atraso de 100 ms
} Fim de Código
PROGRAMAS COM BUGS #4 – PISCAR LED

Comportamento esperado:
Piscar um LED na porta D0 a cada
100 ms.

Sintoma:
O LED pisca, mas o osciloscópio
mostra que ele pisca a cada 25 ms.
PROGRAMAS COM BUGS #4 – PISCAR LED
#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz

#include <xc.h>

#pragma config FOSC = INTIO // Oscilador interno


#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
OSCCON = 0b01010000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída

while(1) { // Inicia loop infinito


LATDbits.LATD0 = !LATDbits.LATD0; // Inverte sinal do pino D0
__delay_ms(100); // Atraso de 100 ms
}

Fim de Código
PROGRAMAS COM BUGS #5 – PISCAR LED

Comportamento esperado:
Piscar um LED na porta D0 a
cada 100 ms.

Sintoma:
O LED fica ligado o tempo
todo.
PROGRAMAS COM BUGS #5 – PISCAR LED
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz

#include <xc.h>

#pragma config FOSC = INTIO67 // Oscilador interno


#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void main(void) {
OSCCON = 0x01010000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída

while(1) { // Inicia loop infinito


LATDbits.LATD0 = !LATDbits.LATD0; // Inverte sinal do pino D0
__delay_ms(100); // Atraso de 100 ms
}

Fim de Código
PROGRAMAS COM BUGS #6 – LCD

Comportamento esperado:
Escrever “Hello, world!” e um contador
na tela do LCD. A cada contagem, o
LED da porta D0 deve piscar.

Sintoma:
Ao iniciar o programa, o LCD não
mostra nada escrito. Apesar disso, o
LED pisca.
PROGRAMAS COM BUGS #6 – LCD
#define _XTAL_FREQ 1000000

#include <xc.h>

#define RS LATD2 // < Pinos do LCD ligados na porta D


#define EN LATD3
#define D4 LATD4
#define D5 LATD5
#define D6 LATD6
#define D7 LATD7 // Pinos do LCD ligados na porta D >

#pragma config FOSC = INTIO67 // Oscilador interno


#pragma config WDTEN = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

#include "lcd.h"
#include <stdio.h>
PROGRAMAS COM BUGS #6 – LCD
char linha1[16]; // Variável linha1 com
16 caracteres
char linha2[16]; // Variável linha2 com
16 caracteres
int contador = 0; // Variável contador
com valor inicial 0

void main(void) {
Lcd_Init(); // Inicia o
LCD, ligado na porta D

TRISD = 0; // Define
porta D inteira como saída
sprintf(linha1, "Hello world! "); // Grava texto em linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na
linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD

while(1) {
sprintf(linha2, "Contador: %i ",contador); // Grava texto em
linha2 Fim de Código
PROGRAMAS COM BUGS #7 –
INTERRUPÇÃO

Comportamento esperado:
O LED deve acender ou apagar a cada
pressionar do botão ligado à porta B0 (ou
INT0)

Sintoma:
Nada acontece ao pressionar o botão.
PROGRAMAS COM BUGS #7 – INTERRUPÇÃO

#define _XTAL_FREQ 1000000

#include <xc.h>

#pragma config FOSC = INTIO67 // Oscilador interno


#pragma config WDT = OFF // Watchdog Timer desligado
#pragma config MCLRE = OFF // Master Clear desabilitado

void setupInt(void) {
GIE = 1; // Habilita interrupção global
INT0IE = 1; // Habilita Interrupção da INT 0
INT0F = 0; // Limpa Flag de interrupção da INT 0
INTEDG0 = 1; // Interrupção por borda crescente.
}
PROGRAMAS COM BUGS #7 – INTERRUPÇÃO

void interrupt interrupcao(void) { // Função de interrupção


if (INT0F) { // Caso a flag
da INT0 esteja habilitada
LATAbits.LA0 = !LATAbits.LA0; // Inverte o sinal no pino A0
INT0F = 0; // Desabilita
a flag da INT0
}
}

void main(void) {
TRISA = 0x00; // Porta A com
todos pinos de saída
TRISB = 0x01; // Somente
pino B1 como entrada (INT0)
setupInt(); // Função de
inicializar Interrupção
while(1) { // Loop
infinito
}
} Fim de Código
PROGRAMAS COM BUGS

Checklist contra a maioria dos bugs:

1. Verificar os bits de configuração:


• MCLRE – impede qualquer funcionamento;
• FOSC – impede qualquer funcionamento;
• WDTEN – causa resets inesperados pouco depois de ligado;
• PBADEN – impede leitura digital na porta B

2. Verificar se as portas estão definidas corretamente como entrada ou saída na sequência


correta:
• Impede leitura ou saída nas portas e funcionamento de periféricos.

3. Verificar velocidade do oscilador ou cristal (definição da frequência em OSCCON) e se está


condizente com a definição de _XTAL_FREQ:
• Causa função __delay_ms gerar atrasos diferentes do esperado;
PROGRAMAS COM BUGS

Checklist contra a maioria dos bugs:

4. Verificar se definições de variáveis ou registradores estão corretas:


Usar 0x10101010 é bem diferente de usar 0b10101010;

5. Ler o datasheet.

Você também pode gostar