Buscar

APOSTILA PRATICA MPLAB X8

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 3, do total de 197 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 6, do total de 197 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes
Você viu 9, do total de 197 páginas

Faça como milhares de estudantes: teste grátis o Passei Direto

Esse e outros conteúdos desbloqueados

16 milhões de materiais de várias disciplinas

Impressão de materiais

Agora você pode testar o

Passei Direto grátis

Você também pode ser Premium ajudando estudantes

Prévia do material em texto

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:
 if: 
if (variavel == 10) {
// executa se condição for verdadeira
} else {
// executa se condição for falsa
}
Condição
Linguagem C – compilador XC8
Loops:
While: 
while (variavel != 0) {
// código em loop
}
Linguagem C – compilador XC8
Loops:
While: 
while (variavel != 0) {
// código em loop
}
Condição (executa enquanto for 1)
Linguagem C – compilador XC8
Loops:
 for: 
for (variavel = 1; variavel < 100; variavel++) 
{
// código em loop
}
Linguagem C – compilador XC8
Loops:
 for: 
for (variavel = 1; variavel < 100; variavel++) 
{
// código em loop
}
Valor inicial
Linguagem C – compilador XC8
Loops:
 for: 
for (variavel = 1; variavel < 100; variavel++) 
{
// código em loop
}
Condição (executa enquanto for 1)
Linguagem C – compilador XC8
Loops:
 for: 
for (variavel = 1; variavel < 100; variavel++) 
{
// código em loop
}
Incremento
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
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 edo 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
Definindo bits de Configuração:
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
Inicio
Configuração
Inverte sinal do pino 
D0
Atrasa 100 ms
EXEMPLO – PISCAR LED
#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
Inicio
Configuração Inverte sinal do pino D0 Atrasa 100 vezes 10 ms
EXEMPLO – PISCAR LED – 1 SEGUNDO
#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
Configuração
Rotaciona 1 passo 
para a esquerda
PORTD=0? LATD = 1
não sim
#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); 
} 
}
return;
}
Fim de Código
EXEMPLO 2 DE ROTAÇÃO DE LEDS
Inicio
Configuração
Rotaciona 1 passo 
para a esquerda
PORTD=0? LATD = 1
não sim
#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); 
Fim de Código
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;
}
EXEMPLO 3 – ROTACIONAR LED
Inicio
Configuração
Rotaciona para a 
esquerda
LED aceso 
na borda 
esquerda
?
Rotaciona para a 
direita
LED aceso 
na borda 
direita?
não
não
sim
simEXEMPLO – ROTACIONAR LED
#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
Inicio
Configuração
Adiciona 1 em 
contador
Atualiza LCD com 
valor de contador
EXEMPLO – LCD
#define _XTAL_FREQ 1000000
#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>
Conexão da Porta D
no LCD
Os pinos D0, D1, D2 
e D3 do LCD são 
conectados ao Terra
Biblioteca local do 
LCD
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); // Posiciona o cursor na linha 2, caractere 1
Lcd_Write_String(linha2); // Escreve texto de linha2 no LCD
}
}
Fim de Código
EXEMPLO – LCD + CONTADOR FLOAT
Inicio
Configuração
Adiciona 0.01 em 
contador
Atualiza LCD com 
valor de contador
EXEMPLO – LCD + CONTADOR FLOAT
#define _XTAL_FREQ 1000000
#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) {
sprintf(linha2, "Contador: %3.2f",contador); // Grava texto em linha2
contador = contador + 0.01; // Incrementa contador em 0.01
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
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)
Inicio
Configuração
Aguarda 
interrupção
Interrupção 
ativada?
Inverte sinal do LED
não
sim
EXEMPLO – INTERRUPÇÃO (INT0)
#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
}
}
// O código acima inverte o sinal no pino A0 a cada pressionar de um botão ligado àINT0
Fim de Código
Conversor 
Analógico/Digital
(10 bits)
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
Características do Conversor Analógico Digital (ADC):
10 bits
13 entradas multiplexadas
Registradores importantes:
Linguagem C – compilador XC8
Registradores importantes – ADC (PIC18F4550):
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
Bits de seleção do Canal 
Analógico
Status da 
conversão
Habilita 
ADC
ADCON0: Registrador de Controle do 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):
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
ADCON1: Registrador de Controle do ADC
ADCON1bits.VCFG = 0b00;  Tensões de referência: Vss e Vdd
Linguagem C – compilador XC8
Registradores importantes – ADC (PIC18F4550):
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 
resultado
Bits de seleção do Tempo de 
Aquisição de dados
Bits de seleção do Clock de 
conversão
ADCON2: Registrador de Controle do ADC
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-
DIGITAL
Inicio
Configuração
Inicia leitura da 
tensão no pino A0
Finalizou 
leitura?
Grava valor da 
leitura nos bits da 
porta C e D
não sim
EXEMPLO – CONVERSOR ANALÓGICO-
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
Inicio
Configuração
Inicia leitura da 
tensão no pino A0
Finalizou 
leitura?
Calcula tensão no pino e 
exibe valor lido e tensão 
calculada no LCD
não sim
EXEMPLO – ADC + LCD
#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 caracteres
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
Lcd_Write_String(linha2); // Escreve texto de linha2 no LCD
}
}
Fim de Código
EXEMPLO – ADC + LCD + DOIS CANAIS
Inicio
Configuração
Lê tensão no pino 
A0 e guarda
Atualiza LCD com os 
valores lidos
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 >
#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 caracteres
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 VddADCON0bits.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
Configuração
Atualiza LCD
(chama rotina que 
lê tensão nos pinos 
A0 a A4 
automaticamente)
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 >
#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 caracteres
EXEMPLO – ADC + LCD + 4 CANAIS
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
Seleção do clock
do AD
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
Configuração
(x = 0)
Atualiza LCD
com as variáveis 
tensão[0] a tensão[7];
Inicia leitura do pino 
ANx
Leitura 
finalizada
?
Atualiza 
variável 
tensão[x] com 
o valor da 
tensão no pino 
Ax;
Incrementa x
não sim
x é 
maior 
que 7?
sim
x = 0
não
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
#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 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 canaisADCON0bits.GO = 1; // Inicia a conversão
}
}
Fim de Código
TEMPORIZADORES/
CONTADORES 
Escolha entre temporizador (T0CS = 0) 
ou contador (T0CS = 1)
Timer 0 configurado para 8 bits 
(T08BIT = 1) ou 16 bits (T08BIT = 0)
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
Inicio
Configuração
(temporizador 
configurado para 
gerar interrupção 
a cada 50 ms)
Aguarda 
interrupção
Interrupção 
ativada?
Inverte sinal do LED
não sim
EXEMPLO – TEMPORIZADOR 0
#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
Configuração
(temporizador 
configurado para 
gerar interrupção 
a cada 1s)
Aguarda 
interrupção
Interrupção 
ativada?
Inverte sinal do LED
não sim
EXEMPLO – TEMPORIZADOR 0 + 
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
T0CONbits.T0PS = 0b100; // Multiplicador Prescaler: 32 x 31.250us = 1 s
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 do pino D0 a cada 1 s, via temporizador 0.
Fim de Código
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
Inicio
Configuração
(temporizador 
configurado para 
gerar interrupção 
a cada 10 ms)
Aguarda 
interrupção
Interrupção 
ativada?
Inverte sinal do LED
não sim
EXEMPLO – TEMPORIZADOR 2
#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
T2OUTPS3 = 1; // totalizando 10000 vezes (~10 ms) por interrupção
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 valor do pino D0 a cada 10 ms usando o Timer 2.
Fim de Código
EXEMPLO – ADC + LCD + TIMER
Inicio
Configuração
(configura timer 
para interromper 
a cada 10 ms) 
Atualiza LCD com o 
valor da variável 
“tensão” e “contador”
Grava tensão do pino 
AN0 na variável “tensão”;
Incrementa “contador”;
não simInterrupção 
do conversor 
AD?
Interrupção 
do timer?
sim
Inicia leitura no 
conversor AD
não
EXEMPLO – ADC + LCD + TIMER
#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
int contador = 0; // Variável contador com valor inicial 0
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; // Limpaa 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
Inicio
Configuração
(configura 
temporizador 
e PWM)
. . . É, não faz nada.
EXEMPLO – PWM
#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
Inicio
Configuração
Inicia conversão AD no 
pino AN0
Atualiza valor do “duty
cycle” do PWM baseado 
no valor de tensão lido no 
pino AN0
não sim
Interrupção 
do conversor 
AD?
EXEMPLO – PWM + ADC
#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
do ADC e do 
LCD
Leitura do LM35
Inicia conversão AD no 
pino AN0
Converte leitura do AD 
em temperatura
Mostra valor no LCDnão sim
Acabou a 
conversão?
A tensão de referência 
do AD é fundamental 
porque a tensão máxima 
de saída do LM35 é 1,5 V, 
para uma temperatura 
de 150ºC
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
No modo síncrono:
1 – Master (clock interno)
0 – Slave (clock externo)
No modo assíncrono: 
irrelevante
TXEN = 1  habilita transmissão
TXEN = 0  desabilita transmissão
TX9 = 1  transmissão de 9 bits
TX9 = 0  transmissão de 8 bits
SYNC = 1  modo síncrono
SYNC = 0  modo assíncrono
Modo síncrono: bit irrelevante
Modo assíncrono:
SENDB = 1  envia bit de parada
SENDB = 0  transmissão completada
Modo síncrono: não utilizado
Modo assíncrono:
BRGH = 1  baud rate alto
BRGH = 0  baud rate baixo
Bit de status do registrador 
de deslocamento
TRMT = 1  TSR vazio
TRMT = 0  TSR cheio
Dado transmitido no 9º 
bit. Pode ser endereço, 
dado ou paridade
SERIAL EUSART
Habilita porta serial
SPEN = 1  configura os 
pinos RX/DT e TX/CK como 
porta serial
SPEN = 0  desabilita porta 
serial
Modo assíncrono  irrelevante
Modo síncrono: 
SREN =1  habilita recepção simples
SREN = 0  desabilita recepção simples
RX9 = 1  recepção de 9 bits
RX9 = 0  recepção de 8 bits
Habilita recepção contínua
Modo assíncrono:
CREN = 1  habilita
Modo síncrono:
CREN = 1  habilita modo 
contínuo, até CREN = 0
Habilita detecção de endereço
Modo 9 bits assíncrono: 
Habilita detecção de endereço e interrupção
Modo 8 bits assíncrono: Irrevante
Bit de erro de quadro (framing)
Bit de erro de ultrapassagem
Dado recebido no 9º bit. 
Pode ser endereço, dado 
ou paridade
SERIAL EUSART
Bit de status de rolagem na 
aquisição automática de 
baud rate
Bit de seleção da polaridade dos dados 
recebidos
Modo assíncrono:
RXDTP = 1  dado de RX invertido
Modo síncrono: 
RXDTP =1  dado recebido é invertido
RCIDL = 1  operação de 
recepção está ociosa
Bit de seleção da polidade dos 
dados transmitidos e do clock
Modo assíncrono:
TXCKP = 1  dado de TX invertido
Modo síncrono:
TXCKP = 1  clock invertido
Bit que habilita o registrador de baud rate de 16 bits
BRG16 = 1  gerador de baud rate de 16 bits 
habilitado
Bit que habilita auto-detecção
de baud rate
Bit que habilita a função “Wake-
up”
Modoassíncrono:
WUE = 1  EUSART continuará a 
leitura do pino RX
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
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)
Modo assíncrono de 8 bits de baixo 
baud rate 
Modo assíncrono de 8 bits de alto 
baud rate 
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 𝑛 =
𝐹𝑂𝑆𝐶/(𝐵𝑎𝑢𝑑_𝑟𝑎𝑡𝑒 𝑑𝑒𝑠𝑒𝑗𝑎𝑑𝑎)
64
− 1
0 1 𝑛 =
𝐹𝑂𝑆𝐶/(𝐵𝑎𝑢𝑑_𝑟𝑎𝑡𝑒 𝑑𝑒𝑠𝑒𝑗𝑎𝑑𝑎)
16
− 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 𝑛 =
𝐹𝑂𝑆𝐶/(𝐵𝑎𝑢𝑑_𝑟𝑎𝑡𝑒 𝑑𝑒𝑠𝑒𝑗𝑎𝑑𝑎)
64
− 1
0 1 𝑛 =
𝐹𝑂𝑆𝐶/(𝐵𝑎𝑢𝑑_𝑟𝑎𝑡𝑒 𝑑𝑒𝑠𝑒𝑗𝑎𝑑𝑎)
16
− 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
Inicio
Configuração;
Envia texto pra 
porta serial;
Aguarda interrupção
Envia texto para a porta 
serial com caractere 
digitado;
não simInterrupção 
da recepção 
serial?
EXEMPLO - SERIAL
#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
}
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 rate
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)
}
SPEN RX9 SREN CREN ADDEN FERR OERR RX9D
1 0 0 1 0 0 0 0
CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D
0 0 1 0 0 1 0 0
RCSTA:
TXSTA:
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;
}
} //loop infinito
}
Fim de Código
EXEMPLO – SERIAL + LCD
Inicio
Configuração;
Envia texto pra 
porta serial e 
LCD;
Aguarda interrupção
Envia texto para a porta 
serial e LCD com 
caractere digitado;não sim
Interrupção 
da recepção 
serial?
Organiza posição do 
caractere na segunda 
linha do LCD
EXEMPLO – SERIAL + LCD
#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, recepção de 
// 8 bits em modo continuo, assíncrono.
int valor;
if (modo == 1) { // modo = 1, modo alta velocidade
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 umainterrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
TXIF = 0; // limpa flag que sinaliza envio completo.
TXREG = valor; // Envia caractere à porta serial
while(TXIF ==0); // espera caractere ser enviado
}
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
PEIE = 1; // habilita interrupção de perifericos do pic
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
sprintf(linha1, "Ultima tecla: %c", caracter); // Grava texto em linha1
Lcd_Write_String(linha1); // Escreve texto de linha1 no LCD
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
Inicio
Configuração;
Envia texto pra 
porta serial;
Inicia leitura da tensão 
no pino AN0
Envia texto para a porta 
serial com tensão lida;
não sim
Finalizou a 
leitura?
EXEMPLO – SERIAL + ADC
#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 transmissão desligado
//(pois corre se o risco de ter uma interrupção escrita e leitura ao mesmo tempo)
}
void escreve(char valor)
{
TXIF = 0; // limpa flag que sinaliza envio completo.
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
ADCON2bits.ACQT = 0b110; // Clock do AD: Fosc/64
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);
SuperDelay(1000);
} //loop infinito
}
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
}
}
}

Mais conteúdos dessa disciplina