Microcontroladores PICjwilson/pdf/5_Micro_Parte_5_(PIC...Introdução O principal microcontrolador...

197
Microcontroladores PIC Prática MSc. Gustavo Souto de Sá e Souza Revisado por José Wilson Nerys

Transcript of Microcontroladores PICjwilson/pdf/5_Micro_Parte_5_(PIC...Introdução O principal microcontrolador...

Microcontroladores PICPrá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 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

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 WatchdogTimer. 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çãoInverte 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çãoRotaciona 1 passo

para a esquerda

PORTD=0? LATD = 1nã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çãoRotaciona 1 passo

para a esquerda

PORTD=0? LATD = 1nã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çãoRotaciona para a

esquerda

LED aceso

na borda

esquerda

?

Rotaciona para a

direita

LED aceso

na borda

direita?

não

não

sim

sim

EXEMPLO – 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ÇÃODigamos 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çãoAdiciona 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 – LCDchar 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çãoAdiciona 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çãoAguarda

interrupção

Interrupção

ativada?Inverte sinal do LED

nãosim

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çãoInicia 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çãoInicia 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 + LCDsetupADC();

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çãoLê 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 Vdd

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

}

void main(void) {

OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz

EXEMPLO – ADC + LCD + DOIS CANAISTRISD = 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 CANAISfloat 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 canais

ADCON0bits.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 2Inicio

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 2TMR2 = 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?

simInicia 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; // 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

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çãoInicia conversão AD no

pino AN0

Atualiza valor do “duty

cycle” do PWM baseado

no valor de tensão lido no

pino AN0nã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 + LCDchar 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 + LCDvoid 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 deslocamentoTRMT = 1 TSR vazio

TRMT = 0 TSR cheio

Dado transmitido no 9º

bit. Pode ser endereço,

dado ou paridade

SERIAL EUSART

Habilita porta serialSPEN = 1 configura os

pinos RX/DT e TX/CK como

porta serialSPEN = 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 bitsBRG16 = 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”

Modo assí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íncrona1. 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íncrona1. 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

}

SERIALvoid 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ãosim

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 uma interrupçã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

}

}

}

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

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 #4 – 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 #5 – PISCAR LED

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

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

LATDbits.LATD0 = !LATDbits.LATD0; // Pisca LED na porta D0

}

}

Fim de Código

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 #7 – INTERRUPÇÃO

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.