Micro Parte 5 (PIC) Pratica
Micro Parte 5 (PIC) Pratica
Micro Parte 5 (PIC) Pratica
Prática
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
Definição de variável:
Decimal: variavel = 100;
Binário: variavel = 0b1100100;
Hexadecimal: variavel = 0x64;
Caractere: variavel = “d”;
Linguagem C – compilador XC8
Operações:
Definição de variável: variavel = 255;
Soma: variavel = 15 + b;
Subtração: variavel = 15 - b;
Multiplicação: variavel = 15 * b;
Divisão: variavel = 15 / b;
Rotação de N bits para esquerda: variavel = variavel <<
N;
Rotação de N bits para a direita: variavel = variavel >>
N;
Linguagem C – compilador XC8
Operações:
Operação E: variavel = variavel & 55;
Operação OU: variavel = variavel | 55;
Operação NÃO (inverte apenas 1 bit): variavel = !
variavel;
Incrementar em 1: variavel++;
Decrementar em 1: variavel--;
Linguagem C – compilador XC8
Condições (retornam 1 se verdadeiro, 0 se falso):
Verificar se é igual: (variavel == b);
Verificar se é diferente: (variavel != b);
Verificar se é maior: (variavel > b);
Verificar se é menor: (variavel < b);
Verificar se é maior ou igual: (variavel >= b);
Verificar se é menor ou igual: (variavel <= b);
Condição E: (variavel <= b && variavel != 0);
Condição OU: (variavel <= b || variavel != 0);
Linguagem C – compilador XC8
Definições:
Define “_constante” como 5: #define _constante 5
Define “PINO_DO_LED” como LATD1: #define PINO_DO_LED LATD1
Inclusões de bibliotecas:
Inclui biblioteca do compilador: #include <stdlib.h>
Inclui biblioteca da pasta local: #include “lcd.h”
Linguagem C – compilador XC8
Se:
if:
if (variavel == 10) {
// executa se condição for verdadeira
} else {
// executa se condição for falsa
}
Linguagem C – compilador XC8
Se: Condição
if:
if (variavel == 10) {
// executa se condição for verdadeira
} else {
// executa se condição for falsa
}
Linguagem C – compilador XC8
Loops:
While:
while (variavel != 0) {
// código em loop
}
Linguagem C – compilador XC8
Loops:
for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Valor inicial
Loops:
for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Condição (executa enquanto for 1)
Loops:
for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Incremento
Loops:
for:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
}
Linguagem C – compilador XC8
Loops:
break:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
if (variavel < 0) {
break;
}
}
Linguagem C – compilador XC8
Loops:
break:
for (variavel = 1; variavel < 100; variavel++)
{
// código em loop
if (variavel < 0) {
break;
}
} Finaliza e sai do loop aqui
Linguagem C – compilador XC8
Funções:
Principal:
void main (void) {
// Código principal do programa vem aqui
}
Linguagem C – compilador XC8
Funções:
Interrupção:
void interrupt int_func (void) {
// Código da interrupção
}
Linguagem C – compilador XC8
Funções:
Interrupção de baixa prioridade:
void interrupt low_priority int_low_funcao
(void) {
// Código da interrupção de baixa
prioridade
}
Linguagem C – compilador XC8
Funções:
Secundárias:
void LigaTimer (void) {
TMR0ON = 1;
}
Linguagem C – compilador XC8
Funções:
Secundárias com valores de entrada e saída:
int SomaDez (int valor_de_entrada) {
valor_de_entrada = valor_de_entrada + 10;
return valor_de_entrada;
}
Linguagem C – compilador XC8
Chamando Funções:
LigaTimer();
variavel = SomaDez(variavel);
Linguagem C – compilador XC8
Função de atraso por milissegundo:
__delay_ms(tempo_em_milissegundos);
!!! Requer que a velocidade do oscilador seja definido antes, por meio da linha
#define _XTAL_FREQ 1000000 (para um oscilador de 1 MHz)
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];
char linha1[16];
contador = 15;
char linha1[16];
contador = 15;
sprintf(linha1, “Contagem: %3.2i”, contador);
char linha1[16];
temperatura = 37.52;
char linha1[16];
caractere_U = 0x55;
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:
Inicio
void main(void) {
OSCCON = 0b01100000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
Fim de Código
EXEMPLO – PISCAR LED (VERSÃO 2)
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#define Led LATDbits.LATD0
void main(void) {
Fim de Código
EXEMPLO – PISCAR LED – 1 SEGUNDO blink1s.c
Inicio
#include <xc.h>
void main(void) {
OSCCON = 0b01100000; // Define velocidade do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
EXEMPLO – PISCAR LED – 1 SEGUNDO
Fim de Código
EXEMPLO 1 DE ROTAÇÃO DE LEDS
Inicio
não sim
PORTD=0? LATD = 1
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
#pragma config FOSC = HS // Cristal oscilador externo (clock externo)
#pragma config WDT= OFF // Watchdog Timer desligado
#pragma config MCLRE = ON // Define pino 1 como Reset
if (PORTD == 0)
{
LATD = 1;
SuperDelay(500);
} Fim de Código
}
EXEMPLO 2 DE ROTAÇÃO DE LEDS
Inicio
não sim
PORTD=0? LATD = 1
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
void main(void) {
Fim de Código
EXEMPLO 3 – ROTACIONAR LED ledRotate.c
Inicio
void main(void) {
TRISA = 0b00000000; // Habilita porta A como saída
LATA = 1; // Liga o primeiro pino da porta A
while(1) { // Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com estilo
pra esquerda
__delay_ms(100); // Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); // Atraso de 100 ms
}
}
} Fim de Código
EXEMPLO – ROTACIONAR LED - EXPLICAÇÃO
Digamos que LATA = 0b00000001
LATA >> 1 retorna o seguinte valor: 0b00000000, pois rotacionou o “1” para a direita e ele
caiu fora dos 8 bits. O oitavo bit é preenchido com 0.
LATA << 7 retorna o seguinte valor: 0b10000000, pois rotacionou o “1” um total de sete bits
para a esquerda e ele ficou no lugar do oitavo bit. Os 7 primeiros bits são preenchidos com
0.
Fazendo a operação OU entre ambos, temos (LATA >> 1 | LATA << 7) = 0b10000000; Continuemos
com LATA = 0b10000000
LATA >> 1 retorna o seguinte valor: 0b01000000, pois rotacionou o “1” para a direita e ele
caiu no lugar do sétimo bit. O oitavo bit é preenchido com 0.
LATA << 7 retorna o seguinte valor: 0b00000000, pois rotacionou o “1” um total de sete bits
para a esquerda e ele saiu do espaço dos bits. Os 7 primeiros bits são preenchidos com 0.
Fazendo a operação OU entre ambos, temos (LATA >> 1 | LATA << 7) = 0b01000000;
Display LCD
EXEMPLO – LCD lcd.h lcd.c
Inicio
#include <xc.h>
Conexão da Porta D no
#define RS LATD2 // < Pinos do LCD
LCD #define EN LATD3
Os pinos D0, D1, D2 e #define D4 LATD4
D3 do LCD são #define D5 LATD5
conectados ao Terra #define D6 LATD6
#define D7 LATD7 // Pinos do LCD >
void main(void) {
TRISD = 0; // Define porta D
inteira como saída
while(1) {
sprintf(linha2, "Contador: %i ",contador); // Grava texto em linha2
contador ++;
// Incrementa contador
Lcd_Set_Cursor(2,1); Fim de Código // Posiciona o cursor na linha 2,
EXEMPLO – LCD + CONTADOR FLOAT lcdFloat.c
Inicio
lcd.h
Adiciona 0.01 em
Configuração
contador
#include "lcd.h"
#include <stdio.h>
EXEMPLO – LCD + CONTADOR FLOAT
char linha1[16]; // Variável linha1 com
16 caracteres
char linha2[16]; // Variável linha2 com
16 caracteres
float contador = 0.0; // Variável contador com
valor inicial 0.0
void main(void) {
TRISD = 0; // Define
porta D inteira como saída
Lcd_Init(); // Inicia o
LCD
sprintf(linha1, "Hello world! "); // Grava texto em linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na
linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD
while(1) {
Fim de%3.2f",contador);
sprintf(linha2, "Contador: Código // Grava texto em linha2
Interrupções
Linguagem C – compilador XC8
Registradores importantes - interrupção:
GIE: bit que habilita a interrupção global:
GIE = 1; // Habilita interrupção
PBIE: bit que habilita a interrupção de periféricos (timer2, adc):
PEIE = 1; // Habilita interrupção de periféricos
INTXIE: bit que habilita a interrupção externa X (X = 0, 1 ou 2):
INT0IE = 1; // Habilita interrupção externa 0
INT1IE = 1; // Habilita interrupção externa 1
INT2IE = 1; // Habilita interrupção externa 2
Linguagem C – compilador XC8
Registradores importantes - interrupção:
ADIF: bit que habilita a interrupção do conversor AD:
Inicio
não
Interrupção sim
Inverte sinal do LED
ativada?
EXEMPLO – INTERRUPÇÃO (INT0) interrupcao_INT0.c
#include <xc.h>
void setupInt(void) {
GIE = 1; // Habilita interrupção global
INT0IE = 1; // Habilita Interrupção da INT0
INT0F = 0; // Zera a Flag de interrupção da INT0
INTEDG0 = 1; // Interrupção por borda crescente.
}
Para usar a interrupção INT0 (Pino RB0, da porta B), deve-se desabilitar o conversor AD dessa porta
EXEMPLO – INTERRUPÇÃO (INT0)
void interrupt interrupcao(void) { // Função de interrupção
if (INT0F) { // Caso a flag
da INT0 esteja habilitada
LATAbits.LA0 = !LATAbits.LA0; // Inverte o sinal no pino A0
INT0F = 0; // Desabilita
a flag da INT0
}
}
void main(void) {
TRISA = 0x00; // Porta A com
todos pinos de saída
TRISB = 0x01; // Somente
pino B1 como entrada (INT0)
setupInt(); // Função de
inicializar Interrupção
while(1) { // Loop
infinito
}
}
Fim de Código
Conversor
Analógico/Digital
(10 bits)
Características do Conversor Analógico Digital (ADC):
10 bits
13 entradas multiplexadas
Registradores importantes:
Registrador Função
ADRESH Byte superior do resultado
ADRESL Byte inferior do resultado
ADCON0 Registrador de controle 0 – escolha de canais, liga/desliga/inicia conversão
ADCON1 Registrador de controle 1 – tensão de referência / configuração dos pinos de entrada como
analógico ou digital
ADCON2 Registrador de controle 2 – configura a fonte de clock e a taxa de aquisição
Linguagem C – compilador XC8
Registradores importantes – ADC (PIC18F4550):
DIGITAL
Inicio
DIGITAL
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
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
Fim de Código
EXEMPLO – ADC + LCD lcd.h adc_lcd.c
Inicio
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada
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
adc_lcd_2ch.c
Lê tensão no pino A1 e
guarda
EXEMPLO – ADC + LCD + DOIS CANAIS
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
void setupADC(void) {
TRISA = 0b00000011; // Habilita pinos A0 e A1 como entrada
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
Fim de Código
EXEMPLO – ADC + LCD + 4 CANAIS
Início
Atualiza LCD
(chama rotina que lê
Configuração
tensão nos pinos A0 a
lcd.h
A4 automaticamente)
adc_lcd_4ch.c
EXEMPLO – ADC + LCD + 4 CANAIS
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
void setupADC(void) {
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
Fim de Código
EXEMPLO – ADC + LCD + 8 CANAIS + INT
Inicio
lcd.h adc_lcd_8ch.c
Atualiza LCD
Configuração com as variáveis tensão[0] a
(x = 0) tensão[7];
Inicia leitura do pino ANx
não
Atualiza variável
tensão[x] com o xé
Leitura
valor da tensão no maior
finalizada? sim
não pino Ax; que 7?
Incrementa x
sim
x=0
EXEMPLO – ADC + LCD + 8 CANAIS + INT
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
adc_lcd_8ch.c
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
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
Fim de Código
TEMPORIZADORES/
CONTADORES
Timer 0 configurado para 8 bits (T08BIT =
1) ou 16 bits (T08BIT = 0)
Inicio
Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 50 ms)
void setupInt(void) {
GIE = 1; // Habilita interrupção global
TMR0IE = 1; // interrupção do Timer 0
}
void setupTmr0() {
T08BIT = 0; // Modo 16 bits
T0CS = 0; // Source do clock (operando como temporizador, e não como contador
PSA = 1; // Desabilita Prescaler
TMR0H = 0x3C; // Começa a contar de 15535
TMR0L = 0xAF; // até 65535 (conta 50 mil vezes)
TMR0ON = 1; // Liga o timer
}
EXEMPLO – TEMPORIZADOR 0
void interrupt interrupcao(void) { // Função de interrupção
if (TMR0IF) { // Caso a flag do
temporizador esteja ativa
LATDbits.LD0 = !LATDbits.LD0; // Inverte pino D0
TMR0H = 0x3C; // Começa a contar de 15535
TMR0L = 0xAF; // até 65535 (conta 50 mil
vezes)
TMR0IF = 0; // Flag do timer 0 em 0
}
}
void main(void) {
TRISD = 0x00; // Porta D como saída
setupInt(); // Função de habilitar
interrupção
setupTmr0(); // Função de configurar timer
0
while(1) { // Loop infinito
}
}
// O código acima inverte o sinal do pino D0 a cada 50000 us, via temporizador 0.
Fim de Código
EXEMPLO – TEMPORIZADOR 0 + PRESCALER
Inicio
interrupcao_TMR0Pre.c
Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 1s)
Interrupção
Inverte sinal do LED
ativada? sim
não
EXEMPLO – TEMPORIZADOR 0 + interrupcao_TMR0Pre.c
PRESCALER
#define _XTAL_FREQ 4000000 // Oscilador a 4 MHz. O número de instruções
por
// segundo é de 1
milhão. O tempo para executar uma
#include <xc.h> // instrução (e do tick do timer) é de
1 us.
void setupInt(void) {
GIE = 1; // Habilita interrupção global
TMR0IE = 1; // interrupção do Timer 0
}
void setupTmr0() {
T08BIT = 0; // Modo 16 bits
T0CS = 0; // Fonte do clock = interna
PSA = 0; // Habilita Prescaler
EXEMPLO – TEMPORIZADOR 0 + PRESCALER PIC16F4550
TMR0H = 0x85; // Começa a contar de 34285
TMR0L = 0xED; // até 65535 (conta 31250 vezes)
TMR0ON = 1; // Liga o timer
}
Inicio
Configuração
(temporizador
configurado para Aguarda interrupção
gerar interrupção a
cada 10 ms)
Interrupção
Inverte sinal do LED
ativada? sim
não
EXEMPLO – TEMPORIZADOR 2 interrupcao_TMR2.c
void setupInt(void) {
GIE = 1; // Habilita interrupção global
PEIE = 1; // Timer 2 exige interrupção de periféricos habilitada
TMR2IE = 1; // interrupção do Timer 2
}
void setupTmr2() {
T2CKPS0 = 1; // Prescaler x 4
T2CKPS1 = 0; //
T2OUTPS0 = 0; // Postscaler x 10
T2OUTPS1 = 1; //
T2OUTPS2 = 0; // Conta 250 (PR2, abaixo) x 4 (prescaler) x 10 (postscaler)
vezes
EXEMPLO – TEMPORIZADOR 2
TMR2 = 0x00; // Começa a contar de 0
PR2 = 249; // até 249 (conta 250 vezes + recarga automatica)
TMR2ON = 1; // Liga o timer
}
void main(void) {
setupInt(); // Função de habilitar
interrupção
setupTmr2(); // Função de configurar
timer 0
TRISD = 0x00; // Porta D como saída
while(1) { // Loop infinito
}
} // O código acima inverte o valorFim
do de Código
pino D0 a cada 10 ms usando o Timer 2.
EXEMPLO – ADC + LCD + TIMER lcd.h adc_lcd_tmr.c
Inicio
Configuração
Atualiza LCD com o valor da
(configura timer para
variável “tensão” e
interromper a cada 10
“contador”
ms)
não sim
Interrupção do Inicia leitura no
timer? conversor AD
EXEMPLO – ADC + LCD + TIMER lcd.h adc_lcd_tmr.c
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
void setupTmr3() {
T3CKPS0 = 0; // Prescaler
T3CKPS1 = 0; // Prescaler
TMR3CS = 0; // Clock origina do clock interno
void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 entrada
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
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:
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
Quando TMR2 é igual a PR2, os três eventos seguintes ocorrem no próximo ciclo
crescente:
TMR2 é zerado
Inicio
Configuração
(configura
. . . É, não faz nada.
temporizador e
PWM)
EXEMPLO – PWM pwm.c
#include <xc.h>
void setupTmr2() {
TMR2 = 0x00; // Começa a contar de 0
PR2 = 249; // até 250 (conta 250 vezes + recarga automatica)
}
void main(void) {
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
setupPWM();
while(1) {
}
}
Fim de Código
EXEMPLO – PWM + ADC pwm_adc.c
Inicio
#include <xc.h>
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
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
A tensão de referência do AD é
fundamental porque a tensão
máxima de saída do LM35 é Converte leitura do AD em
Acabou a
1,5 V, para uma temperatura de temperatura
não conversão? sim
150ºC Mostra valor no LCD
LM35 + LCD
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include "lcd.h"
void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada
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
Bit de seleção da polaridade dos dados recebidos Bit que habilita o registrador de baud rate de 16 bits
Modo assíncrono: BRG16 = 1 gerador de baud rate de 16 bits habilitado
RXDTP = 1 dado de RX invertido
Modo síncrono:
RXDTP =1 dado recebido é invertido Bit que habilita auto-detecção de baud
rate
SERIAL – Baud Rate O valor de “n” na fórmula
de cálculo do baud rate
corresponde ao par:
SPBRGH:SPBRG
Carregando o valor
desejado nesses
registradores, o PIC
automaticamente calcula a
taxa de
transmissão/recepção
SERIAL – Baud Rate – alguns valores de SPBRGH:SPBRG para
algumas taxas de transmissão/recepção
Modo assíncrono de 8 bits de baixo baud
rate
0 0
0 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.
0 0
0 1
Inicio
Configuração;
Envia texto pra Aguarda interrupção
porta serial;
não sim
Interrupção da Envia texto para a porta serial
recepção serial? com caractere digitado;
EXEMPLO - SERIAL serial.c
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
#define _XTAL_FREQ 4000000 // Oscilador interno de 4 MHz
#include <xc.h>
char caracter;
bit flag_interrupcao = 0;
SERIAL
void inicializa_RS232(long velocidade,int modo)
{
RCSTA = 0X90; // Habilita porta serial, recepção de 8 bits em modo continuo,
assíncrono.
int valor;
if (modo == 1) { // modo = 1, modo alta velocidade
(BRGH = 1)
TXSTA = 0X24; // modo assíncrono,
transmissão 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-16)/16); // valor para gerar o baud
rate
}
else { //modo = 0 ,modo
baixa velocidade (BRGH = 0)
TXSTA = 0X20; //modo assincrono,trasmissao 8 bits.
valor =(int)(((_XTAL_FREQ/velocidade)-64)/64);
//calculo do
valor do gerador de baud rate
}
SPBRG = valor; esse registrador, carregado com o “valor” calculado, define o baud
CSRC TX9 TXEN SYNC SENDB BRGH TRMT TX9D
rate TXSTA:
RCIE = 1; 0 0 1 0 0//habilita
1 interrupção
0 de0
SERIAL
void escreve(char valor)
{
TXIF = 0; // limpa flag que sinaliza envio
completo.
TXREG = valor; // Envia caractere desejado à porta
serial
while(TXIF ==0); // espera caractere ser enviado
}
Inicio
Configuração;
Organiza posição do
Envia texto pra
Aguarda interrupção caractere na segunda linha do
porta serial e
LCD
LCD;
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
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 main(void)
{
OSCCON = 0b01100000; // Oscilador interno a 4 MHz
TRISB = 0X02; // configura portB B1 (pino RX) como
entrada
PORTB = 0; // limpar as portas que estão configuradas
como saidas
inicializa_RS232(9600,1); // modo de alta velocidade
GIE = 1; // GIE: Global Interrupt Enable bit
EXEMPLO – SERIAL + LCD
while (1) {
if(flag_interrupcao == 1) { // Tem dados
para ler
imprime(" \n\rCaractere digitado: ");
escreve(caracter);
if (posicao == 16) {
posicao = 1;
} else {
posicao++;
}
flag_interrupcao = 0;
}
}
//loop infinito
Fim de Código
EXEMPLO – SERIAL + ADC serial_adc.c
Inicio
Configuração;
Inicia leitura da tensão no
Envia texto pra
pino AN0
porta serial;
#include <xc.h>
#include <stdio.h>
#include <string.h> //para usar funçoes de string deve se adicionar este header
#include <stdlib.h>
char caracter;
bit flag_interrupcao = 0;
char linha[22];
int contador;
float tensao;
void setupADC(void) {
TRISA = 0b00000001; // Habilita pino A0 como entrada
ADCON0bits.ADON = 1; // Liga o AD
}
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
while (1) {
ADCON0bits.GO = 1;
// Inicia leitura do ADC
while(ADCON0bits.NOT_DONE) { // Aguarda
leitura do ADC
}
contador = (ADRESH * 0x100) + ADRESL; // Transfere valor
para variável
tensao = ((5 * contador) * 0.0009765625); // Calcula tensão real
sprintf(linha, "\b\b\b\b\b%1.3f", tensao); // Grava texto em linha1
imprime(linha); Fim de Código
PROGRAMAS COM BUGS #1 – ROTAÇÃO DE LEDS
Comportamento esperado:
Os LEDs rotacionem no estilo
“bate-e-volta”.
Sintoma:
Ao iniciar o programa, os LEDs
começam a rotacionar corretamente,
mas depois de várias rotações, ele
volta a rotacionar do primeiro LED.
PROGRAMAS COM BUGS #1 – ROTAÇÃO DE LEDS
#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz
#include <xc.h>
#pragma config FOSC = INTIO67 // Oscilador interno
#pragma config WDTEN = ON // Watchdog Timer ligado
#pragma config MCLRE = OFF // Master Clear desabilitado
void main(void) {
TRISA = 0b00000000; // Habilita porta A como saída
LATA = 1; // Liga o primeiro pino da porta A
while(1) {
// Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com
estilo pra esquerda
__delay_ms(100); //
Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); //
Atraso de 100 ms Fim de Código
PROGRAMAS COM BUGS #2 – ROTAÇÃO DE LEDS
Comportamento esperado:
Os LEDs rotacionem no estilo
“bate-e-volta”.
Sintoma:
Ao iniciar o programa, nada
acontece.
PROGRAMAS COM BUGS #2 – ROTAÇÃO DE LEDS
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
void main(void) {
LATA = 1; // Liga o primeiro pino da porta A
while(1) {
// Inicia loop infinito
while(LATA != 0b00000001) {
LATA = (LATA >> 1 | LATA << 7); // Rotacionando com
estilo pra esquerda
__delay_ms(100); //
Atraso de 100 ms
}
while(LATA != 0b10000000) {
LATA = (LATA << 1 | LATA >> 7); // Rotacionando com
estilo pra direita
__delay_ms(100); //
Atraso de 100 ms
} Fim de Código
PROGRAMAS COM BUGS #4 – PISCAR LED
Comportamento esperado:
Piscar um LED na porta D0 a cada
100 ms.
Sintoma:
O LED pisca, mas o osciloscópio
mostra que ele pisca a cada 25 ms.
PROGRAMAS COM BUGS #4 – PISCAR LED
#define _XTAL_FREQ 1000000 // Oscilador de 1 MHz
#include <xc.h>
void main(void) {
OSCCON = 0b01010000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
Fim de Código
PROGRAMAS COM BUGS #5 – PISCAR LED
Comportamento esperado:
Piscar um LED na porta D0 a
cada 100 ms.
Sintoma:
O LED fica ligado o tempo
todo.
PROGRAMAS COM BUGS #5 – PISCAR LED
#define _XTAL_FREQ 4000000 // Oscilador de 4 MHz
#include <xc.h>
void main(void) {
OSCCON = 0x01010000; // Define frequência do oscilador para 4MHz
TRISD = 0b00000000; // Habilita porta D como saída
Fim de Código
PROGRAMAS COM BUGS #6 – LCD
Comportamento esperado:
Escrever “Hello, world!” e um contador
na tela do LCD. A cada contagem, o
LED da porta D0 deve piscar.
Sintoma:
Ao iniciar o programa, o LCD não
mostra nada escrito. Apesar disso, o
LED pisca.
PROGRAMAS COM BUGS #6 – LCD
#define _XTAL_FREQ 1000000
#include <xc.h>
#include "lcd.h"
#include <stdio.h>
PROGRAMAS COM BUGS #6 – LCD
char linha1[16]; // Variável linha1 com
16 caracteres
char linha2[16]; // Variável linha2 com
16 caracteres
int contador = 0; // Variável contador
com valor inicial 0
void main(void) {
Lcd_Init(); // Inicia o
LCD, ligado na porta D
TRISD = 0; // Define
porta D inteira como saída
sprintf(linha1, "Hello world! "); // Grava texto em linha1
Lcd_Set_Cursor(1,1); // Posiciona o cursor na
linha 1, caractere 1
Lcd_Write_String(linha1); // Escreve texto de linha1 no
LCD
while(1) {
sprintf(linha2, "Contador: %i ",contador); // Grava texto em
linha2 Fim de Código
PROGRAMAS COM BUGS #7 –
INTERRUPÇÃO
Comportamento esperado:
O LED deve acender ou apagar a cada
pressionar do botão ligado à porta B0 (ou
INT0)
Sintoma:
Nada acontece ao pressionar o botão.
PROGRAMAS COM BUGS #7 – INTERRUPÇÃO
#include <xc.h>
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 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
5. Ler o datasheet.