Vous êtes sur la page 1sur 122

Curso de

Linguagem C

Rinaldo Câmara Gonçalves


Labtools – Mosaico Didactic Division
Revisão 2
Sumário

SUMÁRIO .....................................................................................................................................................................3
RECURSOS BÁSICOS: EXEMPLO 1 BOTÃO E LED ............................................................................................5
RECURSOS DO LIVRO ..................................................................................................................................................5
LÓGICA DO EXEMPLO ...................................................................................................................................................5
ESQUEMA ELÉTRICO....................................................................................................................................................6
FLUXOGRAMA ..............................................................................................................................................................7
CÓDIGO ......................................................................................................................................................................8
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................10
ANOTAÇÕES ..............................................................................................................................................................11
RECURSOS BÁSICOS: EXEMPLO 2 PISCA – PISCA VARIÁVEL .....................................................................13
RECURSOS DO LIVRO ................................................................................................................................................13
LÓGICA DO EXEMPLO .................................................................................................................................................13
ESQUEMA ELÉTRICO..................................................................................................................................................14
FLUXOGRAMA ............................................................................................................................................................15
CÓDIGO ....................................................................................................................................................................16
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................18
ANOTAÇÕES ..............................................................................................................................................................19
RECURSOS BÁSICOS: EXEMPLO 3 CONTADOR HEXADECIMAL ..................................................................20
RECURSOS DO LIVRO ................................................................................................................................................20
LÓGICA DO EXEMPLO .................................................................................................................................................20
ESQUEMA ELÉTRICO..................................................................................................................................................21
FLUXOGRAMA ............................................................................................................................................................22
CÓDIGO ....................................................................................................................................................................25
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................28
ANOTAÇÕES ..............................................................................................................................................................29
RECURSOS AVANÇADOS: EXEMPLO 4 MAXIMIZAÇÃO DE PINOS DE I/O...................................................30
RECURSOS DO LIVRO ................................................................................................................................................30
LÓGICA DO EXEMPLO .................................................................................................................................................30
ESQUEMA ELÉTRICO..................................................................................................................................................31
FLUXOGRAMA ............................................................................................................................................................32
CÓDIGO ....................................................................................................................................................................36
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................40
ANOTAÇÕES ..............................................................................................................................................................41
RECURSOS AVANÇADOS: EXEMPLO 5 VARREDURA DE DISPLAY .............................................................42
RECURSOS DO LIVRO ................................................................................................................................................42
LÓGICA DO EXEMPLO .................................................................................................................................................42
ESQUEMA ELÉTRICO..................................................................................................................................................44
FLUXOGRAMA ............................................................................................................................................................45
CÓDIGO ....................................................................................................................................................................50
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................57
ANOTAÇÕES ..............................................................................................................................................................58
RECURSOS AVANÇADOS: EXEMPLO 6 CONTROLE DO LCD ............................................................................59
RECURSOS DO LIVRO ................................................................................................................................................59
LÓGICA DO EXEMPLO .................................................................................................................................................59
ESQUEMA ELÉTRICO..................................................................................................................................................60
FLUXOGRAMA ............................................................................................................................................................61
CÓDIGO ....................................................................................................................................................................68
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................76
ANOTAÇÕES ..............................................................................................................................................................77
RECURSOS AVANÇADOS: EXEMPLO 7 CONVERSOR ANALÓGICO DIGITAL..............................................78
RECURSOS DO LIVRO ................................................................................................................................................78
LÓGICA DO EXEMPLO .................................................................................................................................................78

Linguagem C para PIC 3


ESQUEMA ELÉTRICO..................................................................................................................................................79
FLUXOGRAMA ............................................................................................................................................................80
CÓDIGO ....................................................................................................................................................................82
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................86
ANOTAÇÕES ..............................................................................................................................................................87
RECURSOS AVANÇADOS: EXEMPLO 8 CONTROLE DO PWM E EEPROM INTERNA ..................................88
RECURSOS DO LIVRO ................................................................................................................................................88
LÓGICA DO EXEMPLO .................................................................................................................................................88
ESQUEMA ELÉTRICO..................................................................................................................................................89
FLUXOGRAMA ............................................................................................................................................................90
CÓDIGO ....................................................................................................................................................................93
EXERCÍCIOS PROPOSTOS ..........................................................................................................................................99
ANOTAÇÕES ............................................................................................................................................................100
RECURSOS AVANÇADOS: EXEMPLO 9 COLETOR DE DADOS ....................................................................101
RECURSOS DO LIVRO ..............................................................................................................................................101
LÓGICA DO EXEMPLO ...............................................................................................................................................101
ESQUEMA ELÉTRICO................................................................................................................................................102
FLUXOGRAMA ..........................................................................................................................................................103
CÓDIGO ..................................................................................................................................................................109
EXERCÍCIOS PROPOSTOS ........................................................................................................................................114
ANOTAÇÕES ............................................................................................................................................................115
RECURSOS AVANÇADOS: EXEMPLO 10 FUNÇÕES MATEMÁTICAS..............................................................116
RECURSOS DO LIVRO ..............................................................................................................................................116
LÓGICA DO EXEMPLO ...............................................................................................................................................116
ESQUEMA ELÉTRICO................................................................................................................................................117
FLUXOGRAMA ..........................................................................................................................................................118
CÓDIGO .................................................................................................................................................................119
EXERCÍCIOS PROPOSTOS ........................................................................................................................................121
ANOTAÇÕES ............................................................................................................................................................122

4 Linguagem C para PIC


Recursos Básicos: Exemplo 1 Botão e Led
1.1 - Recursos do Livro
Para o bom entendimento deste nosso primeiro exemplo são necessários os conhecimentos de
programação em linguagem C, comandos de controle de Fluxo (cap.7 do livro Programação em C),
declaração de variáveis, constantes e tipos de dados (cap.5 do livro Programação em C), diretivas
de configuração dos pinos de I/O (cap.10-pág.170, cap.11.5; 11.6-pág.202; 11.7 e cap.12.2-pág.
250 do livro Programação em C).
1.2 - Lógica do exemplo
Nosso exemplo será composto de um programa capaz de ler um botão e controlar um led. Com
o botão S1 pressionado o led L2 acende, com o botão S1 liberado o led L2 apaga.
Veremos os primeiros comandos para controle de fluxo de um programa e como ler uma entrada
e acionar uma saída, fundamental já que estamos trabalhando com um microcontrolador.
Neste exemplo você verá o comando WHILE, (Faça enquanto for verdadeiro) sendo utilizado
para o controle de fluxo de nossa rotina principal, forçando um loop infinito.
O comando IF ELSE, (Se verdadeiro {comando}, Se falso {comando}), realiza o teste do
botão e determina o caminho a ser seguido, se acende ou apaga o led. Caso o botão esteja
pressionado o teste determina que o led deve acender, caso contrário o led será apagado. Para o
teste do botão está sendo utilizado o operando “!” (NOT), para botão pressionado temos nível lógico
zero no pino de I/O, neste caso o teste com o comando IF será verdadeiro para botão pressionado
e falso para botão liberado.

Linguagem C para PIC 5


1.3 - Esquema Elétrico

+5V

RESET
+5V
10K MC1
1 32
MCLR VDD
2 31
RA0 VSS +5V
3 40
4
RA1 RB7
39 RB1
RA2 RB6
5
RA3 RB5
38 RB0
6 RA4 RB4 37
7 36
RA5 RB3 10K 330R
8 35
RE0 RB2
+5V 9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12
13
VSS RD6 29
28
S1 L2
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

6 Linguagem C para PIC


1.4 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
WATCHDOG, PRESCALER.

LIMPA WATCHDOG

NÃO BOTÃO S1 SIM


PRESS.?

APAGA LED L2 ACENDE LED L2

Linguagem C para PIC 7


1.5 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 1 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este software está preparado para demonstrar o controle dos pinos de I/O
// este primeiro programa demonstrará o estado de um botão por meio de um led.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição das variáveis internas do PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
//Este programa não utiliza nenhuma variável de usuário

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.
//Este programa não utiliza nenhuma constante de usuário

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.
//Este programa não utiliza nenhum flag de usuário

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta = 0x05


#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

8 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit botao = portb.0 // Estado do botão


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do Hardware.

#bit led = portb.1 // Led correspondente ao botão


// 1 -> Led ligado
// 0 -> Led desligado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Microcontrolador *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void main ()
{

setup_counters(RTCC_INTERNAL, WDT_2304MS);

set_tris_a(0b11111111); // configuração dos pinos de I/O


set_tris_b(0b11111101);
set_tris_c(0b11111111);
set_tris_d(0b11111111);
set_tris_e(0b00000111);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Loop principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

while(TRUE)
{
RESTART_WDT();
if(!botao) // testa botão
{
led = 1; // Se botão = 0, então led = 1
}
else led=0; // caso contrário, led = 0
}
// FIM DO PROGRAMA
}

1.6 -

Linguagem C para PIC 9


1.7 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Utilize as funções do Compilador para controlar o Led, OUTPUT_HIGH e OUTPUT_LOW.


2. Altere a lógica do programa para que o led acenda com o botão liberado e apague com o
botão pressionado.
3. Troque o pino de I/O que controla o botão, por exemplo, utilize o pino RB3.
4. Com o botão pressionado acenda o led 2 e apague o led 3, para o botão liberado apague o
led 2 e acenda o led 3.

10 Linguagem C para PIC


1.8 - Anotações

Linguagem C para PIC 11


Recursos Básicos: Exemplo 2 Pisca – Pisca Variável
1.9 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, funções do compilador para controle de atraso (cap.11.4 pág. 195 do livro
Programação em C), Operadores para criação de expressões lógicas e aritméticas (cap.6 do livro
Programação em C), diretivas de configuração para uso de função de atraso (cap.10, pág.169 do
livro Programação em C).
1.10 - Lógica do exemplo
A finalidade de nosso exemplo é demonstrar a inversão de portas e a utilização da função de
delay da Linguagem C.
Através dos botões S1 e S2, Up e Down é possível ajustar a freqüência de oscilação dos Leds 3
e 4 da placa McLab2.
As constantes min e max determinam os limites, máximos e mínimos de ajuste da freqüência de
oscilação.
Para a inversão das portas está sendo utilizado o operador lógico “~”, (NOT, complemento de 1),
com este operando estaremos invertendo bit a bit o conteúdo do registrador portb.
A função delay_ms gera um atraso de milisegundos usando o ciclo de máquina, ou seja, o
programa fica travado nesta função até o tempo desejado.
O camando For (inicialização, teste condicional, incremento) é utilizado para controle do laço
da rotina de delay, definindo a quantidades de vezes que o laço será executado, nesta rotina não
utilizaremos a opção de inicialização do comando For, sendo a mesma executada fora do laço.

Linguagem C para PIC 13


1.11 - Esquema Elétrico

+5V

RESET
+5V
10K MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
8 35
+5V RE0 RB2
9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

+5V +5V

10K 10K

RB0 RB1 RB2 RB3


S1 S2
330R 330R

L3 L4

14 Linguagem C para PIC


1.12 - Fluxograma
A
MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS, NÃO BOTÃO S1 SIM
WATCHDOG, PRESCALER. PRESS.?

INICIALIZA PORTB COM


SIM
0X0F TEMPO = MAX?

LIMPA WATCHDOG NÃO

INCREMENTA TEMPO

COMPLEMENTA PORTB

A
NÃO BOTÃO S2 SIM
PRESS.?

SIM
TEMPO = MIN?

NÃO

DECREMENTA TEMPO

CARREGA A VARIÁVEL
CONTADOR COM O VALOR
DA VARIÁVEL TEMPO

ROTINA DE DELAY

LAÇO FOR

NÃO
B CONTADOR ≠ 0

SIM

DELAY (10MS)

Linguagem C para PIC 15


1.13 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 2 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este software demonstrará a utilização da função de delay e a inversão de portas
//a frequência de oscilação dos leds é controlada pelos botões S1 (UP) e S2 (DOWN).

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição das variáveis internas do PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos
fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use delay(clock=4000000, RESTART_WDT) // diretiva para o uso da função delay

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
int contador = 0 ;
int tempo = 9;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.
//Este programa não utiliza constantes
#define max 255 // Limite de ajuste do tempo
#define min 10

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.
//Este programa não utiliza nenhum flag de usuário.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta = 0x05


#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08

16 Linguagem C para PIC


#byte porte = 0x09
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.
#bit botao_0 = portb.0 // Estado do botão_0
// 1 -> Liberado
// 0 -> Pressionado
#bit botao_1 = portb.1 // Estado do botão_1
// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Microcontrolador *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main ()
{

setup_counters(rtcc_internal,wdt_2304ms);

set_tris_a(0b11111111);
set_tris_b(0b11110011);
set_tris_c(0b11111111);
set_tris_d(0b11111111);
set_tris_e(0b00000111);

porta = 0x00;
portb = 0x0f; // carrega portb com valor inicial
portc = 0x00;
portd = 0x00;
porte = 0x00;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Loop principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
while(TRUE)
{
RESTART_WDT();

portb = ~portb; // complemanta o portb

if (!botao_0) // O botão_0 foi pressionado?


{
if (tempo != max) // sim, tempo é diferente de max?
{
tempo = tempo + 1; // não, incrementa tempo
}
} // botão_0 liberado, testa botão 1

if (!botao_1) // O botão 1 foi pressionado ?


{
if (tempo != min) // sim, tempo é diferente de min?
{
tempo = tempo - 1; // não, decrementa tempo
}
} // botão_1 liberado
contador = tempo; // carrega contador
for (;contador!=0; contador--) // contador é diferente de 0? se sim
// decrementa contador e executa o comando
delay_ms(10); // comando: delay de 10 milisegundos.
}

} // FIM DO PROGRAMA

Linguagem C para PIC 17


1.14 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:
1. Implemente a inversão de portas para que o led 3 e o led 4 pisquem alternadamente.
2. Utilize a forma reduzida para incrementar e decrementar a variável tempo.
3. Troque a função delay_ms por delay_us e ajuste as constantes para obter o mesmo ajuste de
freqüência.
4. Substitua o comando For pelo comando While.

18 Linguagem C para PIC


1.15 - Anotações

Linguagem C para PIC 19


Recursos Básicos: Exemplo 3 Contador Hexadecimal

1.16 - Recursos do Livro


Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos
exemplos anteriores e tabela de constante (cap.12.21 pág. 309 do livro Programação em C).
1.17 - Lógica do exemplo
Através dos botões S1 e S2 o contador será incrementado ou decrementado, e o seu valor
mostrado no display de sete segmentos ds4.
A finalidade de nosso exemplo é demonstrar a implementação de tabelas utilizando a memória
de programa, sendo está tabela uma matriz unidimensional, nossa tabela fará a conversão de BCD
para sete segmentos, realizando a função de um circuito decodificador.
Para o devido tratamento dos botões, neste exemplo foi implementada uma rotina de filtro para
cada botão evitando o problema de debouncing, além do filtro foi criado um flag, para cada botão,
que tem a função de indicar se a tecla está pressionada ou liberada. Desta forma para que o
contador seja incrementado ou decrementado o botão deve ser pressionado e depois liberado.
A variável contador será utilizada como indexador da tabela de constante, assim sendo para o
contador igual à zero, será retornado o código de sete segmentos para o número zero e assim por
diante.

20 Linguagem C para PIC


1.18 - Esquema Elétrico

220R
+5V DS4
a
+5V b a
c
d f g b
RESET e
10K f
MC1 g e c
Dp d
1 32 Dp
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7 220R
4
RA2 RB6
39 BC337
5 38
RA3 RB5 4,7K
6 RA4 RB4 37
7 36
RA5 RB3
8 35
+5V RE0 RB2
9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

+5V +5V

10K 10K

RB0 RB1

S1 S2

PIC16F877

Linguagem C para PIC 21


1.19 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
WATCHDOG, PRESCALER.

INICIALIZA PORTB COM


0X10

LIMPA WATCHDOG

22 Linguagem C para PIC


A

NÃO BOTÃO S1 SIM


PRESS.?

Re-carrrega o Filtro do Botão


Marca botão liberado SIM
O botão já estava
pressionado ?

C NÃO

NÃO
Filtro ≠ 0 ?

Marca Botão pressionado


SIM

Decrementa o Filtro

NÃO
Contador ≠ Max ?

SIM

Incrementa o contador
Consulta tabela de conversão e
atualiza o display

Linguagem C para PIC 23


C

NÃO BOTÃO S2 SIM


PRESS.?

Re-carrrega o Filtro do Botão


Marca botão liberado SIM
O Botão já estava
pressionado ?

B NÃO

NÃO
Filtro ≠ 0 ?

Marca Botão pressionado


SIM

Decrementa o Filtro

NÃO
Contador ≠ Min ?

SIM

Decrementa o contador
Consulta tabela de conversão e
atualiza o display

24 Linguagem C para PIC


1.20 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 3 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Contador hexadecimal que utiliza dois botões para incrementar e decrementar
// o valor da variável "contador". O contador está limitado pelas constantes min e max.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos
fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define t_filtro 400 // tamanho do filtro


#define min 0 // valor mínimo para o contador
#define max 15 // valor máximo para o contador

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.

int contador=min; // inicia contador com mínimo


long int filtro0=t_filtro; // inicia filtro do bot1
long int filtro1=t_filtro; // inicia filtro do bot2
int flags=0; // limpa os flags

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.
#bit bt_UP_press = flags.0
#bit bt_DOWN_press = flags.1

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

Linguagem C para PIC 25


#byte porta = 0x05
#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit botao_UP = portb.0 // Estado do botão UP


// 1 -> Liberado
// 0 -> Pressionado

#bit botao_DOWN = portb.1 // Estado do botão DOWN


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
// futuras alterações do hardware.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tabela de Valores *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
byte const tabela[16] = {
//PGFEDCBA ; POSIÇÃO RELATIVA AOS SEGMENTOS
0b00111111, // 0H - 0
0b00000110, // 1H - 1
0b01011011, // 2H - 2
0b01001111, // 3H - 3
0b01100110, // 4H - 4
0b01101101, // 5H - 5
0b01111101, // 6H - 6
0b00000111, // 7H - 7
0b01111111, // 8H - 8
0b01101111, // 9H - 9
0b01110111, // AH - A
0b01111100, // BH - B
0b00111001, // CH - C
0b01011110, // DH - D
0b01111001, // EH - E
0b01110001}; // FH - F

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Microcontrolador *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main()
{

setup_counters(rtcc_internal, wdt_2304ms);

set_tris_a(0b11111111);
set_tris_b(0b11101111);
set_tris_c(0b11111111);
set_tris_d(0b00000000);
set_tris_e(0b00000111);

porta = 0x00;
portb=(0b00010000); // seleciona display ds4
portc = 0x00;
portd = (tabela[contador]); // mostra no display valor inicial do contador
porte = 0x00;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

26 Linguagem C para PIC


* Loop principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
while(TRUE) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 0 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if (!botao_UP) // O botão UP está pressionado ?
{ // sim,
if (!(bt_UP_press)) // O botão UP já foi tratato ?
{ // não.
if (filtro0 !=0) // Fim do filtro do botão UP ?
{
filtro0--; // Não, então decrementa o filtro
}
else // Sim, Faz a ação do botão
{
bt_UP_press = 1; // Marca que o botão está pressionado
if (contador != max)
{
contador++; // incrementa o contador
portd = (tabela[contador]); // consulta tabela, atualiza
// display
}
}
}
}
else
{ // botão 0 liberado
filtro0 = t_filtro; // inicia o filtro do botão 0
bt_UP_press = 0; // marca que o botão foi liberado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 1 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if (!botao_DOWN) // testa botão DOWN
{ // botão DOWN pressionado
if (!(bt_DOWN_press)) // o botão DOWN já foi tratato ?
{ // não
if (filtro1 !=0) // Fim do filtro do botão DOWN ?
{
filtro1--; // não, então decrementa o filtro
}
else // SIM. Faz a ação do botão
{
bt_DOWN_press = 1; // marca que o botão está pressionado
if (contador != min)
{
contador--; // decrementa o contador
portd = (tabela[contador]);// consulta tabela, atualiza
// display
}
}
}
}
else
{ // botão 1 liberado
filtro1 = t_filtro; // inicia o filtro do botão 1
bt_DOWN_press = 0; // marca que o botão foi liberado
}
}
}

Linguagem C para PIC 27


1.21 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Modifique o programa para que o contador conte de 1 a 5.


2. Implemente um botão para reset do contador.
3. Altere a tabela para que as posições de A a F da tabela apaguem o display.
4. Mude a contagem do dsp4 para o display dsp3.

28 Linguagem C para PIC


1.22 - Anotações

Linguagem C para PIC 29


Recursos Avançados: Exemplo 4 Maximização de Pinos de I/O
1.23 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos
exemplos anteriores e mais, funções do compilador para controle de interrupção, tratamento
automático (cap.12 pág.254 do livro Programação em C), controle do processador (cap.11 pág.223
do livro Programação em C), manipulação de Timers (cap.11.8 pág.211 do livro Programação em
C), diretivas de configuração para uso de interrupções, #int_xxx e #priority (cap.10, pág.161 e
pág.166 do livro Programação em C).
1.24 - Lógica do exemplo
Nosso exemplo será composto de um programa capaz de ler quatro botões e tocar o buzzer com
uma freqüência diferente para cada combinação de botões. Para cada botão existe um led ligado
no mesmo pino, que será utilizado para indicar os botões pressionados no momento. Utilizaremos
os timers e duas interrupções para controlarmos a freqüência de leitura dos botões e a freqüência
do buzzer:
• Timer 0: controlará a freqüência de varredura dos botões;
• Timer 2: controlará a freqüência do som. O som será feito excitando o buzzer com uma
onda quadrada de freqüência variável. Variaremos esta freqüência alterando o valor de
PR2, que controla o estouro deste timer.
Desta forma, nosso programa principal será um loop infinito sem efeito algum. Somente
ficaremos esperando o acontecimento das interrupções.
Para a varredura dos botões ajustaremos a interrupção de TMR0 para aproximadamente 500Hz:

Ciclo de Máq. Prescale Conta TMR0 Auxiliar Período Freqüência


1 µs 8 256 - 2048 µs 488 Hz

Além disso, o sistema possui um filtro, regulado pela constante FILTRO_BOTAO, para evitar o
debounce da tecla. Este filtro garante que a tecla fique pressionada pelo tempo de FILTRO_BOTAO
x 2048µs.
Quanto à freqüência do buzzer, esta será controlada por TMR2. Calibramos os valores de pre e
postscale para que a freqüência da interrupção do TMR2 varie entre 100Hz e 2kHz, com a variação
de PR2 entre 16 e 240:

Ciclo de Máq. Prescale Postscale PR2 Período Freqüência


1 µs 16 1 16 256 µs 3906 Hz
1 µs 16 1 240 3840 µs 260 Hz

Para facilitar a implementação, a cada interrupção inverteremos o estado do pino de


acionamento do buzzer. Desta forma, a freqüência deste será equivalente à metade da freqüência
da interrupção do TMR2.
O Livro Conectando o PIC, possui um cápitulo dedicado a este assunto.

30 Linguagem C para PIC


1.25 - Esquema Elétrico

+5V

RESET
+5V
10K MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
BUZZER 8 35
+5V RE0 RB2
9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

+5V +5V +5V +5V

10K 10K 10K 10K


10K 10K 10K 10K
RB0 RB1 RB2 RB3
S1 S2 S3 S4
330R 330R 330R 330R

L1 L2 L3 L4

Linguagem C para PIC 31


1.26 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
WATCHDOG, PRESCALER.

LIGA AS INTERRUPÇÕES

LIMPA WATCHDOG

32 Linguagem C para PIC


INTERRUPÇÕES

NÃO SIM
INT DE TMR0?

Trata TMR2 Trata TMR0

TRATA TMR2

NÃO SAÍDA DO BUZZER SIM


ESTÁ LIGADA?

DESLIGA A SAÍDA DO
LIGA A SAÍDA DO BUZZER
BUZZER

FIM DA INTERRUPÇÃO

Linguagem C para PIC 33


TRATA TMR0

Convetre pinos dos botões em


entradas

Delay de 4 ciclos de máquina


para estabilização do port

Lê todos os botões e guarda


em variável temporária
(STATUS_BOTÕES)

Converte pinos dos botões em


saída

CHECA BOTÃO S1

NÃO
Reinicia Filtro Botão S1 PRESS ?

SIM
Limpa Flag de botão
pressionado (Status Leds)

Fim do Filtro ?
NÃO

SIM

Marca flag de botão


pressionado

CHECA BOTÃO S2

CHECA BOTÃO S3

CHECA BOTÃO S4

34 Linguagem C para PIC


AÇÃO DOS BOTÕES
A

Atualiza leds conforme botões


pressionados

NÃO Algum botão


pressionado ?

SIM

Consulta tabela conforme


conbinação de botões
Inicializa PER com 255 pressionados

Deliga interrupção de TMR2 Inicializa TMR2

Desliga a saída do Buzzer Liga Interrupção de TMR2

FIM DA INTERRUPÇÃO

Linguagem C para PIC 35


1.27 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 4 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este software está preparado para ler quatro botões e tocar o buzzer com
//duração variavel conforme a tecla pressionada, além de acender o led
//indicando a última tecla pressionada.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define t_filtro 20 // tamanho do filtro

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.

int status_botoes = 0; // armazena o estado lógico dos botões


int status_leds = 0; // atualiza leds conforme o botão pressionado
int per = 0; // limitador de contagem do Timer2

int filtro1 = t_filtro; // inicia filtro do botao1


int filtro2 = t_filtro; // inicia filtro do botao2
int filtro3 = t_filtro; // inicia filtro do botao3
int filtro4 = t_filtro; // inicia filtro do botao4

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta = 0x05


#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

36 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit botao1 = status_botoes.0 // Estado do botão 1


// 1 -> Liberado
// 0 -> Pressionado

#bit botao2 = status_botoes.1 // Estado do botão 2


// 1 -> Liberado
// 0 -> Pressionado

#bit botao3 = status_botoes.2// Estado do botão 3


// 1 -> Liberado
// 0 -> Pressionado

#bit botao4 = status_botoes.3 // Estado do botão 4


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO E
//FUTURAS ALTERAÇÕES DO HARDWARE.

#bit botao1_press = status_leds.0


#bit botao2_press = status_leds.1
#bit botao3_press = status_leds.2
#bit botao4_press = status_leds.3

#bit buzzer = porta.5

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tabela de Valores *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
byte const tabela[16] = {255,16,32,48,64,80,96,112,128,144,160,176,192,208,224,240};

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configuração do Microcontrolador *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// A rotina principal simplesmente limpa o WDT, pois toda a lógica do
// programa é tratada dentro das interrupções.
void main()
{
setup_adc_ports (no_analogs);
setup_counters(rtcc_internal , rtcc_div_8);
setup_timer_2 (t2_div_by_16,per,1);

set_tris_a(0b11011111);
set_tris_b(0b11110000);
set_tris_c(0b11111111);
set_tris_d(0b11111111);
set_tris_e(0b00000111);

porta=(0b00000000);
portb=(0b00000000);
portc=(0b00000000);
portd=(0b00000000);
porte=(0b00000000);

enable_interrupts(GLOBAL);
enable_interrupts(INT_RTCC);
#priority timer0,timer2 // prioridade para a int de trm0

Linguagem C para PIC 37


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
while(TRUE) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer
}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina de Tratamento de interrupção de TMR0 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Esta interrupção ocorrerá a cada 2048us.
// O filtro dos botões tem duração de 40ms (2048us x 20) e são decrementados a cada
// interrupção.
// Esta interrupção é responsável por converter os pinos dos botões em entrada, salvar
// a condição dos botões em variável temporária e converter os pinos em saída
// novamente.

#int_rtcc
void trata_int_tmr0()
{
set_tris_b(0b00001111); // configura os pinos como entrada para
// testar os botões
delay_cycles(4); // aguarda 4 ciclos de máquina para a
// estabilização do portb
status_botoes = portb; // lê o status dos botoes, salva em variável
// temporária
set_tris_b(0b00000000); // configura os pinos como saída para
// controle dos leds

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 1 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao1) // testa botão 1


{ // botão 1 está pressionado ?
filtro1--; // Sim, então decrementa o filtro
if (filtro1 == 0) // acabou o filtro do botão 1 ?
{
botao1_press = 1; // marca que o botão está pressionado
}
}
else
{ // botão 1 liberado
filtro1 = t_filtro; // inicia o filtro do botão 1
botao1_press = 0; // marca que o botão foi liberado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 2 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao2) // testa botão 2


{ // botão 2 está pressionado ?
filtro2--; // Sim, então decrementa o filtro
if (filtro2 == 0) // fim do filtro do botão 2 ?
{
botao2_press = 1; // marca que o botão está pressionado
}
}
else
{ // botão 2 liberado
filtro2 = t_filtro; // inicia o filtro do botão 2
botao2_press = 0; // marca que o botão foi liberado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 3 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if (!botao3) // testa botão 3
{ // botão 3 está pressionado ?

38 Linguagem C para PIC


filtro3--; // Sim, então decrementa o filtro
if (filtro3 == 0) // fim do filtro do botão 3 ?
{
botao3_press = 1; // marca que o botão está pressionado
}
}
else
{ // botão 3 liberado
filtro3 = t_filtro; // inicia o filtro do botão 3
botao3_press = 0; // marca que o botão foi liberado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão 4 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
if (!botao4) // testa botão 4
{ // botão 4 está pressionado ?
filtro4--; // Sim, então decrementa o filtro
if (filtro4 == 0) // fim do filtro do botão 4 ?
{
botao4_press = 1; // marca que o botão está pressionado
}
}
else
{ // botão 4 liberado
filtro4 = t_filtro; // inicia o filtro do botão 4
botao4_press = 0; // marca que o botão foi liberado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Atualiza Leds conforme botões pressionados *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
portb = status_leds; // atualiza os leds

if (status_leds == 0)
{
per = 0xff;
setup_timer_2 (t2_div_by_16,per,1);
disable_interrupts (INT_TIMER2);
buzzer = 0;
}
else
{
per = (tabela[status_leds]);// consulta tabela e inicializa timer2.
setup_timer_2 (t2_div_by_16,per,1);
enable_interrupts (INT_TIMER2); // habilita interrupção de timer2.
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina de Tratamento de interrupção de TMR2 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Está interrupção só irá ocorrer quando alguma tecla estiver pressionada,
// o periodo de ocorrência depende do botão ou da conbinação de botões pressionados,
// ela irá inverter o pino de I/O do buzzer a cada interrupção.
#int_timer2
void trata_int_tmr2()
{
if (buzzer != 0) // o buzzer está ligado ?
{
buzzer = 0; // sim, então desliga
}
else
{
buzzer = 1; // não, então liga
}
}

Linguagem C para PIC 39


1.28 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Utilize as funções disponíveis do Compilador para inverter o estado do buzzer.


2. Modifique o controle dos leds, os botões pares controlam os leds impares e os botões
impares controlam os leds pares, conforme a tabela abaixo.
Botão 1 Botão 2 Botão 3 Botão 4
Led 2 Led 1 Led 4 Led3

40 Linguagem C para PIC


1.29 - Anotações

Linguagem C para PIC 41


Recursos Avançados: Exemplo 5 Varredura de Display
1.30 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos nos
exemplos anteriores e mais, funções do compilador para controle de interrupção, tratamento manual
(cap.12 pág.254 do livro Programação em C), controle do processador (cap.11 pág.223 do livro
Programação em C), manipulação de Timers (cap.11.8 pág.211 do livro Programação em C),
introdução de código em assembly no programa em C (cap.10, pág.151 do livro Programação em
C),retorno de valores em funções assembly (cap.9, pág.147 do livro Programação em C), diretivas
de configuração para uso de interrupções, #int_global e #priority (cap.10, pág.162 e pág.166 do livro
Programação em C).
1.31 - Lógica do exemplo
O exemplo desenvolvido para esta aula faz muito mais que simplesmente implementar a
varredura dos displays. Trata-se de um contador regressivo de segundos, ou seja, um temporizador
capaz de contar até 9.999 segundos.
Para isso, utilizaremos os displays para indicar o valor atual do temporizador. A primeira tecla
(S1) não possui nenhuma função. Por outro lado, o led relacionado a ela (L1) será utilizado para
indicar o estado do temporizador:

L1 Descrição
Aceso Temporizador em contagem regressiva
Apagado Temporizador paralisado

Os demais botões apresentam as funções de controle do temporizador:

Botão Descrição
S2 Incrementa o valor inicial em 1 segundo
S3 Decrementa o valor inicial em 1 segundo
S4 Inicia e paralisa o temporizador

Os botões de incremento e decremento operam de forma rotativa, isto é, comutam


automaticamente entre 0000 e 9999. Outra característica destes botões é que eles executam suas
funções repetidamente quando mantidos pressionados e só funcionam quando o temporizador está
paralisado. Ao atingir o valor zero (0000) o temporizador é automaticamente paralisado, desligando-
se o led indicativo (L1).
Para o sistema de varredura foram criadas 4 variáveis para armazenamento dos dígitos
mostrados nos respectivos displays: UNIDADE, DEZENA, CENTENA e MILHAR. Estas variáveis
representam o valor atual do temporizador e são incrementadas e decrementadas através dos
botões.
Na verdade, os botões alteram diretamente o valor da unidade. A lógica do sistema compara
este valor com os limites (0 e 9) para alterar ou não os demais dígitos.
A freqüência de varredura é controlada pela interrupção de Timer0. Ajustamos seus parâmetros
para que a comutação entre displays (tempo da interrupção) seja de aproximadamente 4kHz:

Ciclo de Máq. Prescale Conta TMR0 Auxiliar Período Freqüência


1 µs 1 256 - 256 µs 3900 Hz

42 Linguagem C para PIC


A freqüência de varredura será a freqüência de comutação dividida pelo número de displays, que
no nosso caso será de aproximadamente 1kHz.
Dentro do tratamento da interrupção de TMR0 é desligado o display atual, carregado o valor do
dígito correspondente ao display e ligado o display seguinte.
Quanto à contagem dos segundos, utilizamos a interrupção de Timer1 para esta finalidade. Veja
os ajustes dos parâmetros para esta interrupção:

Ciclo de Máq. Prescale Conta TMR1 Auxiliar Período Freqüência


1 µs 8 62500 2 1.000.000 µs 1 Hz

Para isso, configuramos o prescale de TMR1 em 1:8 e iniciamos o contador com o valor total
menos o desejado para a contagem (65.536 – 62.500). Desta maneira a interrupção acontecerá a
cada 0,5 segundo. Para podermos contar 1 segundo foi criado uma variável auxiliar denominada
DIVISOR_TMR1.
Cada vez que o sistema entrar na interrupção de TMR1 e o contador auxiliar (DIVISOR_TMR1)
terminar, o tempo é decrementado, começando pela unidade e chegando até a milhar, se for
necessário. Quando o tempo termina (0000) tanto o led quanto o TMR1 são desligado.
Neste exemplo está sendo utilizado o tratamento Manual de interrupções, neste modo nós
devemos providenciar todo o código necessário para o tratamento da interrupção, tais como: salvar
contexto, restaurar contexto, limpar os flags de indicação de interrupção e criar os registradores
para as rotinas de salvar e restaurar contexto. A prioridade de tratamento da interrupção depende
da seqüência de teste dos flags de int, que também é de responsabilidade do programador.
Para este tipo de tratamento estamos utilizando a diretiva #int global.

Linguagem C para PIC 43


1.32 - Esquema Elétrico
220R

DS1 DS2 DS3 DS4


a
b a a a a
c
d f g b f g b f g b f g b
e
f
g e c e c e c e c
Dp d d d d
Dp Dp Dp Dp

220R Comum 1 Comum 2 Comum 3 Comum 4

BC337 BC337 BC337 BC337

+5V

+5V 4,7K 4,7K 4,7K 4,7K

RESET
10K
MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
8 35
+5V RE0 RB2
9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

+5V +5V +5V


RB0

330R 10K 10K 10K

RB1 RB2 RB3

S2 S3 S4
L1

44 Linguagem C para PIC


1.33 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
WATCHDOG, PRESCALER.

Configura Timer1

Liga as interrupções

Limpa WATCHDOG

SIM
BOTÃO UP PRESS.? Trata Botão UP

NÃO

BOTÃO DOWN SIM


Trata Botão Down
PRESS.?

NÃO

BOTÃO Start/Stop SIM


Trata Botão Start/Stop
PRESS.?

NÃO

Recarrega Filtro e turbo das


teclas

Linguagem C para PIC 45


INTERRUPÇÕES

NÃO SIM
INT DE TMR0?

SWITCH CASE

Recarrega Timer1
Incrementa ponteiro de seleção
de Display, desliga display do
Atualiza Display da SIM milhar, consulta tabela de
Unidade? conversão para sete
segmentos, liga display da
decrementa contador de int. unidade

NÃO

Incrementa ponteiro de seleção


de Display, desliga display da
NÃO Atualiza Display da SIM unidade, consulta tabela de
Passou 1 segundo ?
Dezena? conversão para sete
segmentos, liga display da
dezena

SIM NÃO

Recarrega contador de int. Incrementa ponteiro de seleção


de Display, desliga display da
Atualiza Display da SIM dezena, consulta tabela de
Centena? conversão para sete
segmentos, liga display da
centena
Decrementa Timer
NÃO

Zera ponteiro de seleção de


Display, desliga display da
Atualiza Display do SIM centena, consulta tabela de
NÃO milhar? conversão para sete
Timer Chegou a zero? segmentos, liga display do
milhar

NÃO
SIM

Desliga led de indicação de


timer operando
FIM DA INTERRUPÇÃO

Desabilita interrupção de
Timer1

FIM DA INTERRUPÇÃO

46 Linguagem C para PIC


Trata Botão UP Trata Botão DOWN

SIM SIM
Timer Ligado ? Timer Ligado ?

NÃO NÃO

Decrementa Filtro Decrementa Filtro

NÃO NÃO
Fim do Filtro ? Fim do Filtro ?

SIM SIM

Decrementa Turbo Decrementa Turbo

Fim do Temporizador NÃO Fim do Temporizador NÃO


para Turbo do Botão? para Turbo do Botão?

SIM SIM

Recarrega temporizador para Recarrega temporizador para


Turbo Turbo

Incrementa Timer Decrementa Timer

A A

Linguagem C para PIC 47


Trata botão Start/Stop

SIM
Ação já foi executada ?

NÃO

NÃO
Filtro terminou ?

SIM

NÃO
Timer ligado ?

SIM

SIM
Timer é igual a zero ? Apaga led de indicação de
Timer ligado

NÃO
Desabilita interrupção de
Timer1
Acende Led de indicação de
Timer ligado

Carrega Timer1 A

Carrega contador de
interrupções

Habilita interrupção de Timer 1

48 Linguagem C para PIC


Incrementa Timer Decrementa Timer

Incrementa unidade Decrementa unidade

NÃO NÃO
Unidade = 10 ? Unidade = 0XFF ?

SIM SIM

Zera unidade Unidade = 9


Incrementa dezena Decrementa dezena

NÃO NÃO
Dezena = 10 ? Dezena = 0XFF ?

SIM SIM

Zera dezena Dezena = 9


Incrementa centena Decrementa centena

NÃO NÃO
centena = 10 ? centena = 0XFF ?

SIM SIM

Zera centena Centena = 9


Incrementa milhar Decrementa milhar

NÃO NÃO
Milhar = 10 ? Milhar = 0XFF ?

SIM SIM

Zera milhar Milhar = 9

Return Return

Linguagem C para PIC 49


1.34 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 5 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este exemplo foi preparado para demonstrar o funcionamento do TIMER de
// 16 bits do PIC (TMR1), da varredura de displays e do tratamento manual de int.
// Consiste num temporizador de segundos. dois botões foram utilizados para
// programar o tempo da contagem. Um outro botão foi utilizado para disparar
// o contador. O temporizador consegue contar até 9999 segundos, de forma que
// os 4 displays de 7 segmentos foram necessários. A contagem é regressiva.
// um led indica que o temporizador está operando. Quando o sistema chega
// a 0000 (ZERO) o led é desligado automaticamente.
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define t_filtro 250 // tamanho do filtro


#define turbo_tecla 60
#define delta_timer1 (65536 - 62500)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.

int display = 0 ; // atualiza os displays


int contador = 2; // contador de interrupções de timer1
int filtro = t_filtro; // inicia filtro dos botões
int turbo = 1; // inicia turbo das teclas
int unidade = 9; // variável unidade do timer de 1 seg
int dezena = 9; // variável dezena do timer de 1 seg
int centena = 9; // variável centena do timer de 1 seg
int milhar = 9; // variável milhar do timer de 1 seg

static int W_TEMP; // variáveis para salvar contexto


static int STATUS_TEMP;
static int FSR_TEMP;
static INT PCLATH_TEMP;

50 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08
#byte porte=0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição de SFR's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#bit tmr1if = 0x0c.0 // tmr1if é o bit 0 do sfr pir1
#bit t0if = 0x0b.2 // t0if é o bit 2 do sfr intcon
#bit tmr1ie = 0x8c.0 // tmr1ie é o bit 0 do fsr pie1
#byte status = 0x03 // define endereço do reg de status
#byte fsr = 0x04 // define endereço do reg de fsr
#byte pclath = 0x0a // define endereço do reg de pclath

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit bt_up = portb.1 // Estado do botão up


// 1 -> Liberado
// 0 -> Pressionado

#bit bt_down = portb.2 // Estado do botão down


// 1 -> Liberado
// 0 -> Pressionado

#bit bt_start_stop = portb.3 // Estado do botão start_stop


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO E
//FUTURAS ALTERAÇÕES DO HARDWARE.

#bit estado_timer = portb.0 // led de estado do timer


// 1 -> timer contando
// 0 -> timer parado

#bit disp0 = portb.4 // seleção do display unidade (0)


#bit disp1 = portb.5 // seleção do display dezena (1)
#bit disp2 = portb.6 // seleção do display centena (2)
#bit disp3 = portb.7 // seleção do display milhar (3)

Linguagem C para PIC 51


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tabela de Valores *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
byte const converte[11] = { //PGFEDCBA POSIÇÃO RELATIVA AOS SEGMENTOS
0b00111111, // 0H - 0
0b00000110, // 1H - 1
0b01011011, // 2H - 2
0b01001111, // 3H - 3
0b01100110, // 4H - 4
0b01101101, // 5H - 5
0b01111101, // 6H - 6
0b00000111, // 7H - 7
0b01111111, // 8H - 8
0b01101111, // 9H - 9
0b00000000}; // blank

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de decremento do Timer *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
decrementa_timer()
{
unidade --;
if (unidade == 0xff)
{
unidade = 9;
dezena --;
}
if (dezena == 0xff)
{
dezena = 9;
centena --;
}
if (centena == 0xff)
{
centena = 9;
milhar --;
}
if (milhar == 0xff)
{
milhar = 9;
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de incremento do Timer *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
incrementa_timer()
{
unidade ++;
if (unidade == 10)
{
unidade = 0;
dezena ++;
}
if (dezena == 10)
{
dezena = 0;
centena ++;
}
if (centena == 10)
{
centena = 0;
milhar ++;
}
if (milhar == 10)
{
milhar = 0;
}
}

52 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de tratamento de interrupção de Timer1 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Esta interrupção ocorrerá a cada 0,5 segundos, a rotina de tratamento é executada a
// cada 2 interrupções (contador).
#inline
trata_tmr1()
{
set_timer1(delta_timer1); // carraga timer1
tmr1if = 0; // limpa flag de interrupção
contador --; // decrementa contador de interrupções
if (contador == 0)
{
set_timer1(delta_timer1); // carraga timer1
contador = 2; // carrega contador de int
decrementa_timer();
if((unidade==0)&&(dezena==0)&&(centena==0)&&(milhar==0))// timer está zerado?
{
estado_timer = 0; // sim, apaga o led e
tmr1ie = 0; // desliga tratamento de interrupção de timer1
}
}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina de Tratamento de interrupção de TMR0 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Esta interrupção ocorrerá a cada 256us.
#inline
trata_tmr0()
{
t0if = 0;
switch(display) // início da varredura dos display´s
{
case 0:
display++; // incrementa a variável de varredura
disp3 = 0; // desliga o display 3
portd = (converte[unidade]); // atualiza o portd
disp0 = 1; // liga o display 0
break; // sai

case 1:
display++; // incrementa a variável de varredura
disp0 = 0; // desliga o display 0
portd = (converte[dezena]); // atualiza o portd
disp1 = 1; // liga o display 1
break; // sai

case 2:
display++; // incrementa a variável de varredura
disp1 = 0; // desliga o display 1
portd = (converte[centena]); // atualiza o portd
disp2 = 1; // liga o display 2
break; // sai

case 3:
display = 0; // inicia a variável de varredura
disp2 = 0; // desliga o display 2
portd = (converte[milhar]); // atualiza o portd
disp3 = 1; // liga o display 3
break; // sai
}
}

Linguagem C para PIC 53


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para salvar contexto *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
salva_contexto()
{
#asm
MOVWF W_TEMP // SALVA REGISTRADOR DE TRABALHO E
SWAPF STATUS,W // DE STATUS DURANTE O TRATAMENTO
MOVWF STATUS_TEMP // DA INTERRUPÇÃO.
MOVF FSR,W
MOVWF FSR_TEMP // SALVA REGISTRADOR FSR
MOVF PCLATH,W
MOVWF PCLATH_TEMP // SALVA REGISTRADOR PCLATH
CLRF PCLATH // LIMPA REGISTRADOR PCLATH, SELECIONA PAGINA 0
CLRF STATUS // LIMPA REGISTRADOR STATUS
#endasm
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para restaurar contexto *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
restaura_contexto()
{
#asm
MOVF PCLATH_TEMP,W
MOVWF PCLATH // RECUPERA REG. PCLATH (PAGINAÇÃO)
MOVF FSR_TEMP,W
MOVWF FSR // RECUPERA REG. FSR (END. INDIRETO)
SWAPF STATUS_TEMP,W
MOVWF STATUS // RECUPERA REG. STATUS
SWAPF W_TEMP,F
SWAPF W_TEMP,W // RECUPERA REG. WORK
#endasm
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configuração do Microcontrolador *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main()
{
setup_adc_ports (no_analogs);
setup_counters(rtcc_internal, wdt_2304ms);
setup_timer_1 (t1_internal | t1_div_by_8);

set_tris_a(0b11111111);
set_tris_b(0b00001110);
set_tris_c(0b11111111);
set_tris_d(0b00000000);
set_tris_e(0b00000111);

porta=(0b00000000);
portb=(0b00000000);
portc=(0b00000000);
portd=(0b00000000);
porte=(0b00000000);

enable_interrupts(INT_RTCC );
enable_interrupts(GLOBAL);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Loop principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
loop:

while(TRUE) // rotina principal


{
RESTART_WDT(); // incia o watch-dog timer

54 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão de incremento (UP) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!bt_up) // testa botão up


{
goto trata_up;// desvia para a rotina de incremento do timer
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão de decremento (down) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!bt_down) // testa botão down


{
goto trata_dowm;// desvia para a rotina de decremento do timer
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão de Start / Stop *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!bt_start_stop) // testa botão start_stop


{
goto trata_start_stop; // desvia para a rotina para ligar ou
// desligar o timer
}
filtro = t_filtro;
turbo = 1;
}

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

trata_up:
if (estado_timer == 0) // o timer está parado?
{
filtro --; // decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{
turbo --; // decrementa o turbo da tecla
if (turbo == 0) // sim, fim do turbo do botão ?
{
turbo = turbo_tecla; // carrega o turbo
incrementa_timer(); // incrementa o timer
}
}
}
goto loop;

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

trata_dowm:
if (estado_timer == 0) // o timer está parado?
{
filtro --; // decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{
turbo --; // decrementa o turbo da tecla
if (turbo == 0) // sim, fim do turbo do botão ?
{
turbo = turbo_tecla; // carrega o turbo
decrementa_timer(); // decrementa o timer
}
}
}
goto loop;

Linguagem C para PIC 55


//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

trata_start_stop:
if (filtro != 0) // o timer está parado?
{
filtro --; // decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{
if (estado_timer != 0) // sim, o timer está ligado ?
{
estado_timer = 0; // indica timer parado
tmr1ie = 0; // desliga o tratamento de interrupção de timer1
}
else
{
if((unidade!=0)||(dezena!=0)||(centena!=0)||(milhar != 0))
// timer está zerado?
{
estado_timer = 1;// não, indica que o timer está contando
contador = 2; // carrega contador auxiliar
set_timer1(delta_timer1); // carrega timer 1
tmr1if = 0; // limpa flag de int tmr1
tmr1ie = 1; // liga o tratamento de interrupção de timer1
}
}
}
}
goto loop;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de Tratamento de interrupções *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Todo o tratamento de interrupção é feito manualmente.
// As funções salva contexto e restaura contexto foram feitas em assembler
// Observe que a prioridade das interrupções é realizada através do comando IF
// e a ordem do teste determina a prioridade no tratamento da interrupção.

#int_global
Void trata_int()
{
salva_contexto();// salva os registradores antes do tratamento da int

if (t0if) // É int de tmr0 ?


{
trata_tmr0(); // sim, trata tmr0
}

else // não,
{
if (tmr1if) // É int de tmr1 ?
{
trata_tmr1(); // sim, trata tmr1
}

} // não.

restaura_contexto(); // restaura contexto e sai da int.


}

56 Linguagem C para PIC


1.35 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Mude a rotina para que o temporizador conte de forma crescente e desligue quando chegar a
zero.
2. Altere a rotina de temporização para que o timer seja decrementado a cada 1 minuto.
3. Mude a rotina do timer para que ele funcione como um cronômetro com um botão de start e
um de reset.

Linguagem C para PIC 57


1.36 - Anotações

58 Linguagem C para PIC


Recursos Avançados: Exemplo 6 Controle do LCD
1.37 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, controle do LCD (cap.12.7.2 pág. 310 do livro Programação em C).
1.38 - Lógica do exemplo
Este exemplo foi criado para demonstrar a inicialização de LCD de 2 linhas por 16 caracteres
utilizando 8 vias de dados, e como enviar dados e comandos para o LCD.
O exemplo controla o acionamento de leds e do ventilador através de um MENU, tecla S1, de
escolha de opções, onde será possível escolher as opções de ligar ou desligar através da tecla
ENTER, tecla S2.
A escolha das telas será controlada pelo comando SWITCH do compilador C.
Após o programa ser carregado a seguinte tela será visualizada no display:

S e l e c i o n e T a r e f a
P r e s s M e n u

Quando a tecla S1 é pressionada a mensagem é trocada indicando as opções de controle,


pressionando a tecla menu é possível escolher entre controle de leds e controle do ventilador. O
controle selecionado é indicado por uma seta .

 c t r d o s l e d s
c t r d o v e n t

Uma vez que a tela de controle foi escolhida, pressione a tecla enter para entrar na tela de
controle, de acordo com a tela selecionada poderemos visualizar as seguintes telas:

c t r d o s l e d s
O N > O F F

V e n t i l a d o r
O N > O F F

Na tela de controle, deve se pressionar enter para escolher a opção desejada, ON ou OFF,
quando a tecla for pressionada o símbolo “>” será deslocado para a condição desejada.

Linguagem C para PIC 59


1.39 - Esquema Elétrico
+5V

7
DB0 VDD 2 10K
8
DB1 VO 3
9 VSS 1
1 DB2
0
1 DB3
1
1 DB4
4
2
1 DB5 RS RS
6
13 DB6 EN
5
4 DB7 R/W
EN
LCD

+5V

10K
RESET +5V
MC1
3
1
MCLR VDD 2
3
2 RA0 VSS 1
4
3 0
RA1 RB7 3
4
RA2 RB6 9
3
5
RA3 RB5 8
3
6 RA4 RB4 7
3
7
RA5 RB3 6
3
RS 8 RE0 RB2 5
+5V EN 9
3
RE1 RB1 4
10 33
1 RE2 RB0 3
1 VDD RD7 0
1 2
2 VSS RD6 9
1 2
3 OSC1 RD5 8
1 2
1 OSC2
4 RD4 7
2
1 RC0
5 RD3 2
2
4MHz 6 RC1
1 RD2 1
2
7 RC2 RD1 0
1 1
2 RC3
8 RD0 9
2
3 RC4 RC7 6
2 2
4 RC5 RC6 5

16F877
A

RB2 RB3

+5V +5V

330R 330R

10K 10K

+Vcc RB0 RB1 L3 L4

S1 S2
MINI VENTILADOR

1N4148

BC337
4,7K

60 Linguagem C para PIC


1.40 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
W ATCHDOG, PRESCALER.

Configura Timer0

Inicializa LCD

Tela principal

Habilita as interrupções

Limpa W ATCHDOG

SIM
Escreve tela principal ? Tela principal

NÃO

SIM
BOTÃO MENUPRESS.? Trata Botão Menu

NÃO

BOTÃO ENTER SIM


Trata Botão ENTER
PRESS.?

NÃO

Recarrega Filtro dos Botões

Linguagem C para PIC 61


INT ERRUPÇÕ ES

Declara Variáveis locais

Incrementa contador de
interrupções

Temp1 = 40
SIM

NÃO
Zera contador de interrupções

SW IT CH CASE

Verifica se o led 1 está aceso


Se sim:
SIM Pisca o Led 2 a cada 1
Controle do Led2
segundo.
Se não:
Apaga o led 2.

NÃO

Incrementa contador de time -


SIM out, após 5 segundos, limpa o
Controle do T ime - out da
flag "f_tela_principal", para
tela principal
liberar atualização da tela
principal.

NÃO

FIM DA INT ERRUPÇÃO

62 Linguagem C para PIC


Trata Botão MENU

SIM
Ação já foi executada ?

NÃO

Decrementa Filtro

SIM NÃO
Fim do Filtro ?

SIM NÃO
Contador de Tela < 2

Posiciona a seta na linha 0, Posiciona a seta na linha 1,


coluna 0 do LCD coluna 0 do LCD

Linguagem C para PIC 63


Trata Botão ENTER

SIM
Ação já foi executada ?

NÃO

Decrementa Filtro

SIM NÃO
Fim do Filtro ?

Carrega a tela de seleção de


tarefa:
Controle dos Leds ou Controle
do Ventilador

Re-inicia time-out

64 Linguagem C para PIC


Linguagem C para PIC 65
Seleção da Tela de Menu

Switch Case

SIM
Tela 1 do Menu ?

Posiciona a seta na linha 0


NÃO coluna 0

SIM
Tela 2 do Menu

Posiciona a seta na linha 1


NÃO coluna 0

Return

Beep

Fim do loop do Beep ? SIM


(conta beep)

NÃO Return

Liga Beep
Delay

Desliga Beep
Delay

Decrementa conta beep

66 Linguagem C para PIC


Seleção da Tela de Enter

Switch Case

SIM
Tela 1 do Enter ?

Carrega a tela de controle de


leds.
NÃO
Carrega contador para tela 3

SIM
Tela 2 do Enter

Carrega a tela de controle do


NÃO Ventilador
Carrega contador para tela 4

SIM
Tela 3 do Enter

Indica estado dos leds On ou


NÃO Off emite beep.

SIM
Tela 4 do Enter

Indica estado do ventilador On


NÃO ou Off emite beep

Return A

Linguagem C para PIC 67


1.41 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Básicos de programação *
* Exemplo 6 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este exemplo foi elaborado para explicar o funcionamento do módulo de LCD.
// Foi criada uma rotina para escrever comandos e uma para escrever caracteres,
// existe também uma rotina de inicialização necessária para a correta configuração
// do LCD. Os botões S1 e S2 são respectivamente botão Menu e Enter, o botão Menu
// seleciona a tarefa que desejamos executar (controle de Leds ou do Ventilador),
// o botão Enter seleciona a tarefa e funciona como controle de liga/desliga
// para a tarefa selecionada.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// O arquivo de definições do pic utilizado deve ser referenciado para que
//os nomes definidos pela Microchip possam ser utilizados, sem a necessidade
//de redigitação.

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define t_filtro 500 // tamanho do filtro

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
long int filtro = t_filtro; // inicia filtro dos botões
int flags1 = 0; // registrador de flags
int contador_tela = 0; // contador para seleção de tela
int time_out = 0; // registrador para contagem de tempo de time-out
int contador,temp1,temp2; // variaveis para a rotina de int de Timer0

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)

68 Linguagem C para PIC


#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta = 0x05


#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.

#bit f_tela_principal = flags1.0

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit menu = portb.0 // Estado do botão menu


// 1 -> Liberado
// 0 -> Pressionado

#bit enter = portb.1 // Estado do botão enter


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO E
//FUTURAS ALTERAÇÕES DO HARDWARE.

#bit rs = porte.0 // via do lcd que sinaliza recepção de dados ou comando


#bit enable = porte.1 // enable do lcd
#bit led1 = portb.2 // led s3
#bit led2 = portb.3 // led s4
#bit ventilador = portc.1 // controle do ventilador
#bit buzzer = porta.5 // controle do buzzer

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina que envia um COMANDO para o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void comando_lcd(int caracter)


{
rs = 0; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1 ; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable
delay_us(40); // espera mínimo 40 microsegundos
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina que envia um DADO a ser escrito no LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void escreve_lcd(int caracter)


{
rs = 1; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable
delay_us(40); // espera mínimo 40 microsegundos
}

Linguagem C para PIC 69


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para limpar o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void limpa_lcd()
{
comando_lcd(0x01); // limpa lcd
delay_ms (2);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Inicialização do Display de LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void inicializa_lcd()
{
comando_lcd(0x30); // envia comando para inicializar display
delay_ms(4); // espera 4 milisengundos

comando_lcd(0x30); // envia comando para inicializar display


delay_us(100); // espera 100 microsengundos

comando_lcd(0x30); // envia comando para inicializar display


comando_lcd(0x38); // configura LCD, 8 bits, matriz de 7x5, 2 linhas

limpa_lcd(); // limpa lcd

comando_lcd(0x0c); // display sem cursor


comando_lcd(0x06); // desloca cursor para a direita

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de Bip´s *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void bip(long int tempo, long int periodo)

{
long int conta_bip; // define variável local
conta_bip = tempo / periodo; // contabiliza quantas vezes terá
// que fazer o loop de bip´s
while (conta_bip) // faça o loop até acabar o conta_bip
{
buzzer = 1; // liga o buzzer
delay_ms(periodo/2); // conta tempo para o período escolhido

buzzer = 0; // desliga o buzzer


delay_ms(periodo/2); // conta tempo para o período excolhido

conta_bip--; // decrementa o conta_bip


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tela Principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tela_principal()
{
comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0
printf (escreve_lcd, "Seleciona Tarefa"); // imprime mensagem no lcd
comando_lcd(0xC0); // posiciona o cursor na linha 1, coluna 2
printf (escreve_lcd, " Press Menu "); // imprime mensagem no lcd
f_tela_principal = 1; // indica que a tecla foi atualizada
time_out = 0; // re-inicia contagem do tempo de time-out
}

70 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tela Menu *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tela_menu()
{
limpa_lcd();
comando_lcd(0x82); // posiciona o cursor na linha 0, coluna 2
printf (escreve_lcd, "ctr dos leds"); // imprime mensagem no lcd

comando_lcd(0xc2); // posiciona o cursor na linha 1, coluna 2


printf (escreve_lcd, "ctr do vent"); // imprime mensagem no lcd
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Seleção de tela após pressionar a tecla enter *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tela_ctr_led()
{
limpa_lcd();
comando_lcd(0x82); // posiciona o cursor na linha 0, coluna 2
printf (escreve_lcd, "ctr dos leds"); // imprime mensagem no lcd

comando_lcd(0xc4); // posiciona o cursor na linha 1, coluna 4


printf (escreve_lcd, "ON OFF"); // imprime mensagem no lcd

if (!led1)
{
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(' '); // envia simbolo "espaço" para o lcd
}
else
{
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(' '); // envia simbolo "espaço" para o lcd
}
}

void tela_ctr_ventilador()
{
limpa_lcd();
comando_lcd(0x83); // posiciona o cursor na linha 0, coluna 3
printf (escreve_lcd, "Ventilador"); // imprime mensagem no lcd

comando_lcd(0xc4); // posiciona o cursor na linha 1, coluna 4


printf (escreve_lcd, "ON OFF"); // imprime mensagem no lcd

if (!ventilador)
{
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(' '); // envia simbolo "espaço" para o lcd
}
else
{
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(' '); // envia simbolo " " para o lcd
}
}

Linguagem C para PIC 71


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Seleção das telas de Menu *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void sel_tela_menu()
{

switch(contador_tela)

case 1:
tela_menu();
comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0
escreve_lcd(0x7e); // envia simbolo "seta" para o lcd
break; // retorna

case 2:
tela_menu();
comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
escreve_lcd(0x7e); // envia simbolo "seta" para o lcd
break; // retorna da função
}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Seleção das telas após pressionar Enter *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void sel_tela_enter()
{

switch(contador_tela)

case 1:
tela_ctr_led();
contador_tela = 3;
break; // retorna da função

case 2:
tela_ctr_ventilador();
contador_tela = 4;
break; // retorna da função

case 3:
if (!led1)
{
led1 = 1; // acende o led
bip(50,2);
comando_lcd(0xc3);// posiciona o cursor na linha 1, coluna 3
escreve_lcd(0x3e);// envia simbolo "maior" para o lcd
comando_lcd(0xc7);// posiciona o cursor na linha 1, coluna 7
escreve_lcd(' ');// envia simbolo "espaço" para o lcd

else
{
led1 = 0; // apaga o led
comando_lcd(0xc7);// posiciona o cursor na linha 1, coluna 7
escreve_lcd(0x3e);// envia simbolo "maior" para o lcd
comando_lcd(0xc3);// posiciona o cursor na linha 1, coluna 3
escreve_lcd(' ');// envia simbolo "espaço" para o lcd
bip(50,2);
delay_ms(250);
bip(50,2);
}
break; // retorna da função

72 Linguagem C para PIC


case 4:

if (!ventilador)
{
bip(750,2);
ventilador = 1; // liga o ventilador
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(' '); // envia simbolo "espaço" para o lcd
}

else
{
bip(1000,2);
ventilador = 0; // desliga o ventilador
comando_lcd(0xc7); // posiciona o cursor na linha 1, coluna 7
escreve_lcd(0x3e); // envia simbolo "maior" para o lcd
comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3
escreve_lcd(' '); // envia simbolo "espaço" para o lcd
}
break; // retorna da função

}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Pic *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void main()
{
setup_adc_ports (no_analogs);
setup_counters (rtcc_internal, WDT_2304MS);

set_tris_a(0b11011111); // configuração da direção dos pinos de I/O


set_tris_b(0b11110011);
set_tris_c(0b11111101);
set_tris_d(0b00000000);
set_tris_e(0b00000100);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

inicializa_lcd(); // configura o lcd


tela_principal(); // imprime a tela principal no LCD

enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
loop:
while(TRUE) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Verifica se algum botão foi pressionado *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!f_tela_principal)
{
tela_principal();
}

Linguagem C para PIC 73


//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

if (!menu) // testa botão 1


{
goto trata_menu;// desvia para a rotina de incremento do timer
}

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

if (!enter) // testa botão 2


{
goto trata_enter;// desvia para a rotina de incremento do timer
}

//* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

filtro = t_filtro; // recarga da variável filtro


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão S1 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
trata_menu:
//ligar time - out
if (filtro != 0) // Ação já foi executada?
{
filtro --; // não, decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{ // sim, executa tarefa
if (contador_tela < 2) // De selecionar a próxima tarefa?
{
contador_tela ++;// sim, incrementa contador de seleção de tarefa
sel_tela_menu(); // seleciona a tela de menu
time_out = 0; // re-inicia contagem do tempo de time-out
}
else // não,
{
contador_tela = 1;// Volta para a primeira tela do menu
sel_tela_menu(); // carrega a tela de menu
time_out = 0; // re-inicia contagem do tempo de time-out
}
}
}
goto loop; // sim, volta para o loop principal

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão S2 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
trata_enter:
if (filtro != 0) // Ação já foi executada?
{
filtro --; // não, decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{
sel_tela_enter(); // sim, carrega a tela de seleção de tarefa
time_out = 0; // re-inicia contagem do tempo de time-out
}
}
goto loop;
}

74 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina de Tratamento de interrupção de TMR0 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Esta interrupção ocorrerá a cada 256us.
// A variável auxiliar temp1 será utilizada para contar 40 interrupções,
// totalizando 10ms. O comando switch será executado a cada 10ms.
#int_rtcc
void trata_int_tmr0()
{
temp1 ++;

if (temp1 == 40) // já passou 10ms?


{
temp1 = 0; // sim, zera contador de interrupção

switch(contador) // seleciona tarefa


{
case 0: // controle do led2
temp2 ++;
if (temp2 == 50) // passou 1 segundo?
{
temp2 = 0; // sim, zera contador de interrupção

if (led1) // O led1 está ligado


{
if (!led2) // sim, o led2 está ligado?
{
led2 = 1; // não, liga o led2
}
else
{
led2 = 0; // sim, desliga o led2
}
} // não, então não controla o led2
else
{
led2 = 0;// não, mantém o led2 desligado
}
}
contador ++; // incrementa contador de tarefa
break; // fim de execução de execução da tarefa

case 1: // time_out = 10ms * 250 * 2


time_out ++;
if (time_out == 250) // já passou 5 segundos?
{
time_out = 0; // sim, zera time_out
contador_tela = 0; // zera contador de tela
f_tela_principal = 0; // libera atual.tela principal
}
contador ++; // incrementa contador de tarefa
break; // fim de execução de execução da tarefa

default:
contador = 0;
}
} // não, sai da int.
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fim do Programa *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

Linguagem C para PIC 75


1.42 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Mude a rotina para que seja controlado o buzzer no lugar do led 2.


2. Crie mais um nível no Menu para controlar o buzzer.

76 Linguagem C para PIC


1.43 - Anotações

Linguagem C para PIC 77


Recursos Avançados: Exemplo 7 Conversor Analógico Digital
1.44 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, funções do compilador para controle do conversor analógico digital (cap.11-pág
206 do livro Programação em C).
1.45 - Lógica do exemplo
Este exemplo foi elaborado para explicar as funções do CCS para o módulo de conversão
analógico digital interno do PIC. É convertido o valor analógico presente no pino RA1 do
microcontrolador, sendo que este valor pode ser alterado através do potenciômetro P2 da placa
MCLAB2 este valor é ajustado entre 0 e 5V e mostrado no LCD.
Neste exemplo foi utilizado variável do tipo float para armazenar o resultado da conversão A/D.
Para que possamos visualizar o valor de 0 à 5V no LCD, foi feita uma segunda conversão o valor
digital foi convertido para “Volts” realizando uma regra de 3.

Valor máximo da
resolução do AD (10 bits)

Valor a ser mostrado no


(5V * ADRES) / 1023 = "n" Volts
display

Tensão de Referência Valor de tensão medido

78 Linguagem C para PIC


1.46 - Esquema Elétrico

+5V

- 4,7K 330R
P2 + RA1
10K
LM358 +5V

1uF

7
DB0 VDD 2 10K
8
DB1 VO 3
9 VSS 1
DB2
10
DB3
11
DB4 RS
12 4
DB5 RS
13 6
DB6 EN EN
14 5
DB7 R/W

LCD

+5V

RESET 10K
+5V
MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
RS 8 RE0 RB2
35
+5V EN 9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

Linguagem C para PIC 79


1.47 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
WATCHDOG, PRESCALER.

Configura AD:
RA0,RA1 e RA3 como entradas analógicas.
adc = 10 bits
Tensão de Refêrencia interna (VDD e VSS)
Frequencia de conversão = fosc / 32
Selecionado Canal 1
Módulo ligado

Inicializa LCD

Prepara Tela principal

80 Linguagem C para PIC


A

LIMPA WATCHDOG

Inicia e lê o resultado da
conversão

Multiplica valor da conversão


por 5

Divide resultado da
multiplicação por 1023

Envia resultado para o display

Linguagem C para PIC 81


1.48 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Avançados de programação *
* Exemplo 7 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este exemplo foi elaborado para explicar o funcionamento do módulo de
// conversão analógico digital interno do PIC. É convertido o valor analógico
// presente no pino RA2 do microcontrolador, sendo que este valor pode ser
// alterado através do potenciômetro P2 da placa MCLAB2. O valor da conversão
// A/D é ajustado numa escala de 0 à 5V e mostrado no LCD.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* DEFINIÇÃO DAS VARIÁVEIS INTERNAS DO PIC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// O arquivo de definições do pic utilizado deve ser referenciado para que
//os nomes definidos pela Microchip possam ser utilizados, sem a necessidade
//de redigitação.

#include <16f877A.h> // microcontrolador utilizado


#device adc=10 // configura AD para retornar valor em 10 bits

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
float conversao = 0; // armazena o resultado da conversão AD

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *

82 Linguagem C para PIC


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta = 0x05


#byte portb = 0x06
#byte portc = 0x07
#byte portd = 0x08
#byte porte = 0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit rs = porte.0 // via do lcd que sinaliza recepção de dados ou comando


#bit enable = porte.1 // enable do lcd

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina que envia um COMANDO para o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void comando_lcd(int caracter)


{
rs = 0; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1 ; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina que envia um DADO a ser escrito no LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void escreve_lcd(int caracter)


{
rs = 1; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para limpar o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void limpa_lcd()
{
comando_lcd(0x01); // limpa lcd
delay_ms (2);
}

Linguagem C para PIC 83


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Inicialização do Display de LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void inicializa_lcd()
{
comando_lcd(0x30); // envia comando para inicializar display
delay_ms(4); // espera 4 milisengundos
comando_lcd(0x30); // envia comando para inicializar display
delay_us(100); // espera 100 microsengundos
comando_lcd(0x30); // envia comando para inicializar display
comando_lcd(0x38); // liga o display, sem cursor e sem blink
limpa_lcd(); // limpa lcd
comando_lcd(0x0c); // display sem cursor
comando_lcd(0x06); // desloca cursor para a direita
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tela Principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void tela_principal()
{
comando_lcd(0x83); // posiciona o cursor na linha 0, coluna 3
printf (escreve_lcd, "Voltimetro"); // imprime mensagem no lcd
comando_lcd(0xcd); // posiciona o cursor na linha 1, coluna 14
printf (escreve_lcd, " V"); // imprime mensagem no lcd
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Pic *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main()
{
setup_adc_ports (RA0_RA1_RA3_analog);
setup_adc (adc_clock_div_32);
setup_counters (rtcc_internal, WDT_2304MS);
set_adc_channel (1); // seleciona o canal 1 do AD

set_tris_a(0b11111111); // configuração da direção dos pinos de I/O


set_tris_b(0b11111111);
set_tris_c(0b11111111);
set_tris_d(0b00000000);
set_tris_e(0b00000100);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

inicializa_lcd(); // configura o lcd


tela_principal(); // imprime a tela principal no LCD

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
loop:
while(TRUE) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer
conversao = read_adc(); // inicia conversão AD
conversao = (conversao * 5); // faz regra de 3 para converter o valor,
conversao = (conversao / 1023); // das unidades de AD em Volts.
comando_lcd(0xC2); // posiciona o cursor na linha 1, coluna 2
printf (escreve_lcd,"%1.9f", conversao);// envia dados para o display de LCD
// 1 número inteiro e 9 casas decimais.

84 Linguagem C para PIC


}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fim do Programa *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

Linguagem C para PIC 85


1.49 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Mude a configuração do A/D para que ele retorne apenas os 8 bits mais significativos.
2. Altere a função de escrita no LCD para que ela imprima apenas 3 casas depois da virgula.
3. Mude a configuração do A/D para que ele realize as conversões com a Fosc/8.

86 Linguagem C para PIC


1.50 - Anotações

Linguagem C para PIC 87


Recursos Avançados: Exemplo 8 Controle do PWM e EEPROM
Interna
1.51 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, funções do compilador para controle do PWM (cap.11.9 pág.218 do livro
Programação em C), funções do compilador para operação com EEPROM (cap.11.10 pág.219 do
livro Programação em C), diretiva #ROM (cap.10, pág.167 do livro Programação em C) e função de
manipulação de registradores make8 e make16 (cap.11, pág.200 e 201 do livro Programação em
C).
1.52 - Lógica do exemplo
Este exemplo foi elaborado para explicar o funcionamento do módulo de PWM e da escrita da
EEPROM interna do microcontrolador. Um ventilador terá a sua velocidade controlada através do
PWM, o valor ajustado poderá ser salvo na memória EEPROM e restaurado através dos botões.
A velocidade do ventilador é medida em rotações por segundo, através do timer1(usado como
contador) e mostrada no LCD.
Através do botão S1, o PWM é incrementado e decrementado pelo botão S2. Realizando a
operação nestes botões será visualizado no LCD o incremento e o decremento em porcentagem(%)
e a rotação do ventilador em rps (rotações por segundo).
O botão S4 salva o valor de ajuste em EEPROM e o botão S3 restaura o valor salvo atualizando
o PWM.
Para que possamos utilizar o PWM do PIC não podemos esquecer de configurar a freqüência do
PWM no Timer2.

T = [(PR2 + 1) * 4] * Tosc * Prescaler TMR2

A função set_pwm_duty(valor), determina o período do pulso do PWM, ou seja, o tempo em


que a saída do PWM permanecerá em nível lógico 1. Este valor pode chegar a 1023, enquanto o
período do PWM pode chegar a 1024, com PR2 igual a 255.
Por está razão dependendo da freqüência do PWM não será possível alcançar os 100% de Duty
Cyle.
DC = (valor / T), 1023 / 1024 = 0,9990

Então antes de utilizar o PWM, estude o funcionamento do Módulo CCP para um melhor
aproveitamento.
Este conhecimento pode ser adquirido através do livro Conectando o PIC.

88 Linguagem C para PIC


1.53 - Esquema Elétrico
+5V

7 VDD 2 10K
DB0
8
DB1 VO 3
9 VSS 1
DB2
10
DB3
11
DB4
4
12
DB5 RS RS
13 6
DB6 EN
14 5
DB7 R/W
EN
LCD

+5V

10K
RESET
+5V
MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
RS 8 RE0 RB2
35
+5V EN 9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
TACOMETRO 23
RC4 RC7
26
24 25
RC5 RC6

16F877A
+5V +5V +5V +5V

10K 10K 10K 10K

RB0 RB1 RB2 RB3

S1 S2 S3 S4

+Vcc
MINI VENTILADOR

1N4148

+5V
+5V

BC337
4,7K

150R 10K

1K
SIR381583F RPT38PT3F
TACOMETRO

BC337
1K

Linguagem C para PIC 89


1.54 - Fluxograma

M A IN

C O N FIG U R AÇ Õ E S IN IC IAIS
T R IS , P O R T AS ,
W A T C H D O G , P R E SC A LE R .

C onfigura T im er0

Inic ializa LC D

T ela princ ipal

H abilita as interrupç ões

Lim pa W AT C H D O G

S IM
E sc reve tela princ ipal ? T ela principal

NÃO

S IM
B O T Ã O U P P R ES S.? T rata B otão U P

N ÃO

BO T ÃO D O W N S IM
T rata B otão D O W N
P R ES S .?

N ÃO

N ÃO
G rava D ados em SIM
S alva dados em EE PR O M
E E PR O M ?

N ÃO

R estaura D ados da SIM


Lê E EP R O M
E E PR O M ?

N ÃO
A tualiza P wm

90 Linguagem C para PIC


Trata Botão UP Trata Botão DOWN

SIM SIM
Ação já foi executada ? Ação já foi executada ?

NÃO NÃO

Decrementa Filtro Decrementa Filtro

NÃO NÃO
Fim do Filtro ? Fim do Filtro ?

SIM SIM

Decrementa Turbo Decrementa Turbo

Fim do Turbo ? Fim do Turbo ?

Re-carrega variavel do Turbo Re-carrega variavel do Turbo

Incrementa PWM do Decrementa PWM do


ventilador ventilador
Atualiza a tela principal Atualiza a tela principal

A A

Linguagem C para PIC 91


INTERRUPÇÕES

Contador de interrupções é SIM


igual a zero ?
(Temp1 = 0)

NÃO

Decrementa contador de Carrega variável rotação com o


interrupções valor do Timer1

Divide variável rotação por 7


(número de palhetas do
ventilador) habilita atualização
do LCD

FIM DA INTERRUPÇÃO

92 Linguagem C para PIC


1.55 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Avançados de programação *
* Exemplo 8 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este exemplo foi elaborado para explicar o funcionamento do módulo de
// PWM e da escrita da EEPROM interna do microcontrolador. Um ventilador terá
// a sua velocidade controlada através do PWM, o valor ajustado poderá ser
// salva na memória EEPROM e restaurado através dos botões.
// A velocidade do ventilador é medida em rotações por segundo, através do
// timer1 e mostrada no lcd.

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Inicializa EEPROM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#rom 0x2100 = {0x03,0xe8} // carrega eeprom com valor inicial, inicia PWM com 97%

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define t_filtro 200 // tamanho do filtro


#define turbo_tecla 5 // turbo dos botões

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
float duty_cycle = 0; // armazena o resultado da conversão AD
long int duty_cycle1 = 0; // armazena o resultado da conversão AD
long int periodo_pulso = 0; //
long int rotacao = 0; // rps do ventilador
int end = 0; // variável para endereçamento da eeprom
int flags1 = 0; // flags
int filtro = t_filtro; // inicia filtro dos botões
int temp1 = 125; // variável aux para int de tmr0
int turbo = 1; // inicia turbo das teclas
int dado; // variável de dados para eeprom

Linguagem C para PIC 93


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08
#byte porte=0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.

#bit atualiza_lcd = flags1.0

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit botao1 = portb.0 // Estado do botão 2


// 1 -> Liberado
// 0 -> Pressionado

#bit botao2 = portb.1 // Estado do botão 3


// 1 -> Liberado
// 0 -> Pressionado

#bit botao3 = portb.2 // Estado do botão 4


// 1 -> Liberado
// 0 -> Pressionado

#bit botao4 = portb.3 // Estado do botão 4


// 1 -> Liberado
// 0 -> Pressionado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

#bit rs = porte.0 // via do lcd que sinaliza recepção de dados ou comando


#bit enable = porte.1 // enable do lcd
#bit ventilador = portc.1 // pino de I/O para controle do ventilador (PWM)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função que envia um COMANDO para o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void comando_lcd(int caracter)


{
rs = 0; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1 ; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

94 Linguagem C para PIC


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função que envia um DADO a ser escrito no LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void escreve_lcd(int caracter)


{
rs = 1; // seleciona o envio de um caracter
portd = caracter; // carrega o portd com o caracter
enable = 1; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para limpar o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void limpa_lcd()
{
comando_lcd(0x01); // limpa lcd
delay_ms (2);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de inicialização do Display de LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void inicializa_lcd()
{
comando_lcd(0x30); // envia comando para inicializar display
delay_ms(4); // espera 4 milisengundos

comando_lcd(0x30); // envia comando para inicializar display


delay_us(100); // espera 100 microsengundos

comando_lcd(0x30); // envia comando para inicializar display

comando_lcd(0x38); // liga o display, sem cursor e sem blink

limpa_lcd(); // limpa lcd

comando_lcd(0x0c); // display sem cursor

comando_lcd(0x06); // desloca cursor para a direita

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para imprimir a Tela Principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tela_principal()
{
comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0
printf (escreve_lcd, "Duty cycle RPS"); // imprime mensagem no lcd

comando_lcd(0xc3); // posiciona o cursor na linha 1, coluna 3


printf (escreve_lcd,"%" "3Lu%%", duty_cycle1); // envia dados para o display de
LCD

comando_lcd(0xcb); // posiciona o cursor na linha 1, coluna 11


printf (escreve_lcd,"%" "3Lu", rotacao); // envia dados para o display de LCD

Linguagem C para PIC 95


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Salva Dados na EEPROM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// salva dado na eeprom no endereço indicado através da variável "end",
// o dado a ser salvo é passado para a Função através da variável "dado".

void salva_dados()
{
write_eeprom (end,dado);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Lê Dados na EEPROM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// lê o dado na eeprom no endereço indicado através da variável "end",
// o dado lido é carregado na variável "dado".

le_dados(end)
{
dado = read_eeprom (end);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Atualiza PWM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void atualiza_pwm()
{
set_pwm2_duty(periodo_pulso); // atualiza duty cicle do PWM
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Pic *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void main()
{

setup_adc_ports (no_analogs); // desliga as entradas analógicas


setup_counters (rtcc_internal, rtcc_div_64);// tmr0 clock interno, ps: 1:64
setup_timer_1 (t1_external_sync | t1_div_by_1);// tmr1 clock externo, ps: 1:1
setup_timer_2 (t2_div_by_16,255,1);// tmr2 ps=1:16, pr2=255 e postscale: 1:1
setup_ccp2(ccp_pwm); // modo PWM ligado
set_pwm2_duty(periodo_pulso); // ajusta duty cycle em 0.

set_tris_a(0b11111111); // configuração da direção dos pinos de I/O


set_tris_b(0b11111111);
set_tris_c(0b11111101);
set_tris_d(0b00000000);
set_tris_e(0b00000100);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

inicializa_lcd(); // configura o lcd


tela_principal(); // imprime a tela principal no LCD

enable_interrupts(INT_RTCC);
enable_interrupts(GLOBAL);

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
loop:
while(TRUE) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer
if (atualiza_lcd != 0)

96 Linguagem C para PIC


{
duty_cycle = periodo_pulso; // carrega valor da rotação medida
duty_cycle = (duty_cycle / 1024); // efetua cálculo do duty cycle
duty_cycle = (duty_cycle * 100); // converte para porcentagem (%)
duty_cycle1 = (long int) duty_cycle;
// carrega os 16 bits menos significativos da parte inteira
// do resultado da converão

tela_principal(); // imprime a tela principal no LCD


atualiza_lcd = 0; // indica LCD atualizado
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão de incremento (UP) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao1) // testa botão 1


{
goto trata_up; // desvia para a rotina de incremento do PWM
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão de decremento (down) *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao2) // testa botão 2


{
goto trata_dowm; // desvia para a rotina de decremento do PWM
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão ler dados da EEPROM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao3) // testa botão 3


{
le_dados(1); // lê byte_low da eeprom
periodo_pulso = dado; // carrega valor lido em variável de 16 bits

le_dados(0); // lê byte_high da eeprom


periodo_pulso = make16(dado, periodo_pulso); // recompõe o dado de 16 bits

atualiza_pwm(); // Função para atualizar o PWM


atualiza_lcd = 1; // habilita atualização do LCD
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento do Botão salvar dados na EEPROM *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

if (!botao4) // testa botão 4


{
end = 0; // endereço do byte_high
dado = make8(periodo_pulso,1); // retorna byte_high
salva_dados(); // salva byte_high

end = 1; // endereço do byte_low


dado = make8(periodo_pulso,0); // retorna byte_low
salva_dados(); // salva byte_low
}

filtro = t_filtro; // carrega filtro dos botões


turbo = 1;

} // fecha while

//* * * * * * * * * * * Incrementa duty cycle do PWM * * * * * * * * * *


trata_up:
{
filtro --; // decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{

Linguagem C para PIC 97


turbo --; // decrementa o turbo da tecla
filtro = t_filtro;
if (turbo == 0) // sim, fim do turbo do botão ?
{
turbo = turbo_tecla;
if (periodo_pulso < 1023)
// limita incremento do periodo do pulso em 1023
{
periodo_pulso ++;
atualiza_pwm(); // Função para atualizar o PWM
atualiza_lcd = 1; // habilita atualização do LCD
}
}
}
}
goto loop;

//* * * * * * * * * * * Decrementa duty cycle do PWM * * * * * * * * * *


trata_dowm:
{
filtro --; // decrementa o filtro
if (filtro == 0) // fim do filtro do botão?
{
turbo --; // decrementa o turbo da tecla
filtro = t_filtro;
if (turbo == 0) // sim, fim do turbo do botão ?
{
turbo = turbo_tecla;
if (periodo_pulso != 0)
// limita decremento do periodo do pulso em 0
{
periodo_pulso --;
atualiza_pwm(); // Função para atualizar o PWM
atualiza_lcd = 1; // habilita atualização do LCD
}
}
}
}
goto loop;
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina de Tratamento de interrupção de TMR0 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Esta interrupção ocorrerá a cada 8ms.
// A variável auxiliar temp1 será utilizada para contar 125 interrupções,
// totalizando 1 segundo. Quando isto ocorrer, a variável rotação será carregada
// com o valor de rotações por segundo do ventilador.

#int_rtcc
void trata_int_tmr0(void)
{
set_rtcc(256-125);
if (temp1 == 0 ) // ja passou 1 segundo?
{ // Sim,
rotacao = get_timer1(); // le valor do timer 1
set_timer1 (0); // zera timer 1
rotacao = (rotacao / 7);
// divide por 7 (quantidade de palhetas do ventilador)
atualiza_lcd = 1; // habilita atualização do LCD
temp1 = 125; // re-inicia temp1
}
else // Não,
{
temp1 --; // decrementa temp1
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fim do Programa *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

98 Linguagem C para PIC


1.56 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Mude a freqüência do PWM para que possamos ajustar o Duty cycle de 0 a 100%.
2. Ative os dois PWM`s um para o ventilador e outro para a resistência.

Linguagem C para PIC 99


1.57 - Anotações

100 Linguagem C para PIC


Recursos Avançados: Exemplo 9 Coletor de Dados
1.58 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, funções do compilador para controle de comunicação serial I2C (cap.11.14 pág
240 do livro Programação em C), funções do compilador para controle de comunicação serial
RS232 (cap.11.13 pág 230 do livro Programação em C), diretiva de configuração #use i2c e #use
RS232 (cap.10, pág.171 e 172 do livro Programação em C).
1.59 - Lógica do exemplo
Este exemplo foi elaborado para explicar as funções de I2C do compilador CCS e comunicação
serial com a USART. Neste exemplo iremos coletar dados do A/D e armazenar estes dados na
EEPROM externa (24c04), estes dados serão enviados ao PC para a visualização dos mesmos.
O PC controlará as funções do coletor de dados.
Quando for recebido o dado 0x55 o PIC inicia a coleta de dados, ao final da coleta e enviado
para o PC o comando 0x0b, para a liberação da transmissão de dados.
Após o fim da coleta de dados o PIC aguarda o comando 0xaa, recebendo este dado, ele inicia a
transmissão de dados para o PC plotar os dados na tela. Ao final da transmissão ele aguarda novo
comando de inicio de coleta de dados.

Linguagem C para PIC 101


1.60 - Esquema Elétrico

+5V

- 4,7K 330R RA1


P2 +
10K

+5V
1uF

7
DB0 VDD 2 10K
8
DB1 VO 3
9 VSS 1
DB2
10
DB3
+5V 11
DB4 RS
12 4
DB5 RS
13 6
DB6 EN EN
14 5
DB7 R/W
RESET
+5V
10K MC1 LCD
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
8 35
+5V RE0 RB2
RS 9 34
+5V RE1 RB1
EN 10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
10K 10K 16 21
1 A0 VCC
8 RC1 RD2
2 7
4MHz 17 20
A1 WP RC2 RD1
3 A2 6 18 19
SCL RC3 RD0
4 GND 5 23 26
SDA RC4 RC7
24 25
RC5 RC6
24C04
16F877A

+5V

1uF
1uF

1 C1+
3 C1 -
1uF
4 C2+ +C 2
5 C2 - -C 6
12
1K
13 T1IN T1OUT
14 R1OUT R1IN 11
8 9 +5V
T2IN T2OUT
7 R2OUT R2IN 10
15 16
GND VCC 1uF
3 2 5
MAX-232

CONECTOR
DB9 FEMEA

102 Linguagem C para PIC


1.61 - Fluxograma

MAIN

CONFIGURAÇÕES INICIAIS
TRIS, PORTAS,
W ATCHDOG, PRESCALER.

Configuração: AD, rs232 e I2C

Inicializa LCD

Tela principal

Habilita as interrupções

Limpa W ATCHDOG

Verifica se chegou comando


pela USART

SIM
Inicia coleta de dados ? Coleta Dados

NÃO

SIM
Deve transmitir dados
TX Dados para o PC
para o PC ?

NÃO

SIM Cancela coleta de dados


Para a coleta de Dados ? Transmite para o PC comando
de fim de coleta de dados

NÃO

Linguagem C para PIC 103


Recebe comando do PC

NÃO
Chegou comando do
PC ?

SIM

SIM Recebeu o comando de


inicio de Coleta de Dados
?

Tarefa = coleta de dados


NÃO

SIM Recebeu o comando de


transmissão de dados
para o PC ?

Tarefa = transmite dados para o


PC NÃO

SIM Recebeu o comando de


parar coleta de dados ?

NÃO
Tarefa = para coleta de dados

104 Linguagem C para PIC


Coleta Dados

Escreve no LCD:
"Coletando Dados"

Lê Dados do AD
Salva em EEPROM Serial

NÃO
Fim da Coleta de Dados ?

SIM

Aguarda novo comando do PC

Envia para o PC comando de


Fim de Coleta de Dados

Escreve no LCD:
"Pronto para TX"

Return

Linguagem C para PIC 105


Transmite dados para o PC

Escreve no LCD:
"TX para o PC"

Lê memória EEPROM Serial


Transmite para o PC

NÃO Fim da transmissão de


Dados ?

SIM

Escreve no LCD:
"Fim da Trans..."

Aguarda novo comando do PC


delay de 5 segundos

Escreve no LCD:
"Press Inicio"
delay de 1 segundo

Return

106 Linguagem C para PIC


Linguagem C para PIC 107
Escreve na memória Lê dados da memória
EEPROM Serial EEPROM Serial

Envia Start bit Envia Start bit

Envia Controle Envia Controle

Envia endereço low Envia endereço low

Envia Dado Envia Start bit

Envia Stop bit Envia Controle

Recebe dados da memória


delay 10ms
salva em variável dado

Return Envia Stop bit

delay 10ms

Return

108 Linguagem C para PIC


1.62 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Avançados de programação *
* Exemplo 9 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este exemplo foi elaborado para explicar as funcões de I2C do compilador
// CCS. Neste exemplo iremos coletar dados do AD e armazenar estes dados na
// EEPROM externa (24c04), estes dados serão enviados ao PC para a
// visualização dos mesmos. O PC controlará as funções do coletor de dados.

#include <16f877A.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos


fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configuração do Módulo I2C *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use i2c(master,sda=pin_c4, scl=pin_c3, SLOW, RESTART_WDT, FORCE_HW)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configuração da USART *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use rs232 (baud=9600, xmit = pin_c6, rcv = pin_c7)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

#define ctrl_le 0b10100001// byte de controle da memória p/ leitura


#define ctrl_escr 0b10100000// byte de controle da memória p/ escrita

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constante internas do tipo Enumeração *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
enum selecao_de_tarefa
{
aguarda_comando, coleta_de_dados, transmite_para_pc, parar_coleta
}tarefa;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

Linguagem C para PIC 109


* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.
static int flags1 = 0; // flags
static int dado = 0;
static int end_low = 0;
static int tx_pc;
static int comando = 0;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08
#byte porte=0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.
#bit atualiza_lcd = flags1.0

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As saídas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.
#bit rs = porte.0 // via do lcd que sinaliza recepção de dados ou comando
#bit enable = porte.1 // enable do lcd

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para escrita na EEPROM externa I2C *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
escr_mem_serial ()
{
i2c_start(); // Condição de início
i2c_write(ctrl_escr); // Envia o byte de controle de leitura
i2c_write(end_low); // Envia endereço baixo
i2c_write(dado); // Escreve dado na E²PROM
i2c_stop(); // Condição de parada
delay_ms(10); // espera a gravação estar completa
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para leitura na EEPROM externa I2C *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
le_mem_serial ()
{
i2c_start(); // Condição de início
i2c_write(ctrl_escr); // Envia o byte de controle de leitura
i2c_write(end_low); // Envia endereço baixo
i2c_start(); // Nova condição de início
i2c_write(ctrl_le); // Envia o byte de controle de leitura
dado = i2c_read(0); // lê o dado armazenado na E²PROM
i2c_stop(); // Condição de parada
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *

110 Linguagem C para PIC


* Função que envia um COMANDO para o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void comando_lcd(int caracter)


{
rs = 0; // seleciona o envio de um comando
portd = caracter; // carrega o portd com o caracter
enable = 1 ; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função que envia um DADO a ser escrito no LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void escreve_lcd(int caracter)


{
rs = 1; // seleciona o envio de um caracter
portd = caracter; // carrega o portd com o caracter
enable = 1; // gera pulso no enable
delay_us(1); // espera 1 microsegundo
enable = 0; // desce o pino de enable

delay_us(40); // espera mínimo 40 microsegundos


}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para limpar o LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void limpa_lcd()
{
comando_lcd(0x01); // limpa lcd
delay_ms (2);
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função de inicialização do Display de LCD *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void inicializa_lcd()
{
comando_lcd(0x30); // envia comando para inicializar display
delay_ms(4); // espera 4 milisengundos
comando_lcd(0x30); // envia comando para inicializar display
delay_us(100); // espera 100 microsengundos
comando_lcd(0x30); // envia comando para inicializar display
comando_lcd(0x38); // liga o display, sem cursor e sem blink
limpa_lcd(); // limpa lcd
comando_lcd(0x0c); // display sem cursor
comando_lcd(0x06); // desloca cursor para a direita
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Função para imprimir a Tela Principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void tela_principal()
{
limpa_lcd()
comando_lcd(0x80); // posiciona o cursor na linha 0, coluna 0
printf (escreve_lcd, "Coletor de dados"); // imprime mensagem no lcd
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina para coleta de dados *

Linguagem C para PIC 111


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
coleta_dados()
{
comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
printf (escreve_lcd, "Coletando Dados"); // imprime mensagem no lcd
do
{
dado = read_adc(); // le resuldado do AD
escr_mem_serial (); // salva em eeprom
end_low += 1; // incrementa endereço, seleciona nova posição
delay_ms(10); // delay de 10 ms
}while (end_low != 0); // fim da coleta ?

tarefa = aguarda_comando; // aguarda comando do PC


comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
printf (escreve_lcd, " Pronto para TX "); // imprime mensagem no lcd
tx_pc = 11; // indica para o pc fim da coleta de dados
printf ("%x\r\n",tx_pc);// envia ao PC o comando de fim da coleta de dados
delay_ms(2000); // delay de 2 segundos
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina para transmitir dados para o PC *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
tx_dados_pc()
{
comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
printf (escreve_lcd, " TX para o PC "); // imprime mensagem no lcd
do
{
le_mem_serial (); // le dados da eeprom
printf ("%x\r\n",dado); // envia ao PC o valor da eeprom externa
end_low +=1; // incrementa endereço, seleciona nova posição
delay_ms(100); // delay de 100 ms
}while (end_low != 0); // fim da transmissão de dados

tarefa = aguarda_comando; // aguarda comando do PC


comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
printf (escreve_lcd, " Fim da Trans..."); // imprime mensagem no lcd
delay_ms(3000); // delay de 3 segundos
comando_lcd(0xc0); // posiciona o cursor na linha 1, coluna 0
printf (escreve_lcd, " "); // imprime mensagem no lcd
delay_ms(1000); // delay de 1 segundo
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Tratamento de recepção serial *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void recebe_comando()
{
if (kbhit())
{
comando = getc();
if (comando == 0x55) // recebeu o camando de coleta de dados ?
{
tarefa = coleta_de_dados; // sim, libera coleta de dados
}
if (comando == 0xaa) // recebeu o camando de transmissão de dados ?
{
tarefa = transmite_para_pc; // sim, transmite dados para o PC
}
if (comando == 0x7f) // recebeu o camando para cancelar coleta de dados ?
{
tarefa = parar_coleta; // sim, cancela coleta de dados
}
}
}

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Pic *

112 Linguagem C para PIC


* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void main()
{
setup_adc_ports (RA0_RA1_RA3_analog);
setup_adc (adc_clock_div_8);
set_adc_channel (1);
setup_counters (rtcc_internal, WDT_2304MS);

set_tris_a(0b11111111); // configuração da direção dos pinos de I/O


set_tris_b(0b11111111);
set_tris_c(0b10110111);
set_tris_d(0b00000000);
set_tris_e(0b00000100);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

inicializa_lcd(); // configura o lcd


tela_principal(); // imprime a tela principal no LCD

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
loop:
while(true) // rotina principal
{
RESTART_WDT(); // incia o watch-dog timer
recebe_comando();
if (tarefa == coleta_de_dados) // inicia coleta de dados ?
{
end_low = 0; // sim, carrega endereço inicial
coleta_dados(); // executa função de coleta de dados
}
if (tarefa == transmite_para_pc)// inicia transmissão de dados para o PC ?
{
end_low = 0; // sim, carrega endereço inicial
tx_dados_pc(); // executa função de transmissão de dados
}
if (tarefa == parar_coleta) // cancela coleta de dados ?
{
end_low = 0; // sim, carrega endereço inicial
tarefa = aguarda_comando; // espera envio de comando do PC
tx_pc = 11; // fim da coleta de dados
tx_dados_pc(); // envia comando para o PC
}
}
}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fim do Programa *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

Linguagem C para PIC 113


1.63 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Mude a rotina de coleta de dados para que seja armazenado na EEPROM um valor de 0 à
5V e não um valor de 0 a 255. Implemente a regra de três necessária.
2. Altere a configuração do A/D para que ele retorne os 10 bits do resultado da conversão e
salve este dado na EEPROM.

114 Linguagem C para PIC


1.64 - Anotações

Linguagem C para PIC 115


Recursos Avançados: Exemplo 10 Funções Matemáticas
1.65 - Recursos do Livro
Para o bom entendimento deste exemplo são necessários os conhecimentos adquiridos no
exemplo 1 e mais, funções matemáticas do compilador (cap.11.1 pág 175 do livro Programação em
C).
1.66 - Lógica do exemplo
A elaboração deste exemplo foi pensando na demonstração das funções matemáticas, nele
veremos o microcontrolador realizando o calculo do seno de 0 a 2π, um software para PC foi
elaborado para coletar os cálculos realizas e plotar os cálculos na tela do PC. Outras funções
podem ser visualizadas, bastando para isso alterar a função matemática de nosso programa.

116 Linguagem C para PIC


1.67 - Esquema Elétrico

+5V

RESET 10K
+5V
MC1
1 32
MCLR VDD
2 31
RA0 VSS
3 40
RA1 RB7
4 39
RA2 RB6
5 38
RA3 RB5
6 RA4 RB4 37
7 36
RA5 RB3
RS 8 RE0 RB2
35
+5V EN 9 34
RE1 RB1
10 33
RE2 RB0
11 30
VDD RD7
12 29
VSS RD6
13 28
OSC1 RD5
14 27
OSC2 RD4
15 22
RC0 RD3
16 21
4MHz RC1 RD2
17 20
RC2 RD1
18 19
RC3 RD0
23 26
RC4 RC7
24 25
RC5 RC6

16F877A

+5V

1uF
1uF

1 C1+
3 C1 -
1uF
4 C2+ +C 2
5 C2 - -C 6
12
1K
13 T1IN T1OUT
14 R1OUT R1IN 11
8 9 +5V
T2IN T2OUT
7 R2OUT R2IN 10
15
GND VCC 16 1uF
3 2 5
MAX-232

CONECTOR
DB9 FEMEA

Linguagem C para PIC 117


1.68 - Fluxograma
MAIN

CO NFIG URAÇÕ ES INICIAIS


TRIS, PO RTAS,
W ATCHDO G , PRESCALER.

Inicializa a variável
X=0

NÃO
X < (2 * PI)

SIM

LIMPA W ATCHDO G

Y = seno (x)

Envia o valor de X para o PC

Envia o valor de Y para o PC

Incrementa a variável X
X = x + 0,01

118 Linguagem C para PIC


1.69 - Código
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Programação em C - Recursos Avançados de programação *
* Exemplo 10 *
* *
* CENTRO DE CAPACITAÇÃO - LABTOOLS *
* *
* TEL: (0XX11) 4992-8775 SITE: www.labtools.com.br *
* E-MAIL: cursos@labtools.com.br *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* VERSÃO : 1.0 *
* DATA : 05/06/2003 *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Descrição geral *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// Este software foi desenvolvido para mostrar a implementação de funções
// matemáticas, como exemplo estamos calculando o seno e enviando para o
// PC os valores de "x" e "y" para serem plotados.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição dos I/O's e opções de configuração *
* das funções para periféricos *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#include <16f877A.h> // microcontrolador utilizado


#device adc=10

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Carrega bibliteca Matemática *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include <math.h> // microcontrolador utilizado

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações para gravação *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#fuses xt,wdt,noprotect,put,brownout,nolvp,nocpd,nowrt // configuração dos
fusíveis

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definições para uso de Rotinas de Delay *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use delay(clock=4000000, RESTART_WDT)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configuração da Usart *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use rs232(baud=9600,xmit=pin_c6,rcv=pin_c7)

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização das variáveis *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//Neste bloco estão definidas as variáveis globais do programa.

float y;
float x;

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Constantes internas *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de constantes facilita a programação e a manutenção.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Declaração dos flags de software *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
//A definição de flags ajuda na programação e economiza memória RAM.
//Este programa não utiliza nenhum flag de usuário

Linguagem C para PIC 119


/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Definição e inicialização dos port's *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

#use fast_io(a)
#use fast_io(b)
#use fast_io(c)
#use fast_io(d)
#use fast_io(e)

#byte porta=0x05
#byte portb=0x06
#byte portc=0x07
#byte portd=0x08
#byte porte=0x09

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* ENTRADAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// As entradas devem ser associadas a nomes para facilitar a programação e
//futuras alterações do hardware.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* SAÍDAS *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// AS SAÍDAS DEVEM SER ASSOCIADAS A NOMES PARA FACILITAR A PROGRAMAÇÃO E
//FUTURAS ALTERAÇÕES DO HARDWARE.

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Configurações do Pic *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

void main()
{
setup_adc_ports (no_analogs); // desliga as entradas analógicas
setup_counters (rtcc_internal, wdt_2304ms);// tmr0 clock interno, ps: 1:64

set_tris_a(0b11111111); // configuração da direção dos pinos de I/O


set_tris_b(0b11111111);
set_tris_c(0b11111111);
set_tris_d(0b11111111);
set_tris_e(0b00000111);

porta=0x00; // limpa porta


portb=0x00; // limpa portb
portc=0x00; // limpa portc
portd=0x00; // limpa portd
porte=0x00; // limpa porte

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Rotina principal *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
while(TRUE)
{
x=0;
while(x < 2*PI)
{
restart_wdt(); // limpa wdt
y = sin (x); // calculo da função
printf ("X=%1.3f",x); // envia ao PC o valor de x
printf (" ");
printf ("Y=%1.3f\r\n",y); // envia ao PC o valor de y
x = x + 0.01; // incrementa x
}
}

}
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* Fim do Programa *
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */

120 Linguagem C para PIC


1.70 -
1.71 - Exercícios Propostos
Agora que o exemplo já foi estudado e esclarecido, aproveite para gerar novos problemas e
soluções, seguindo os exercícios propostos:

1. Altere a função matemática para que o PIC calcule o co-seno.


2. Altere a função matemática para que o PIC calcule o log de um número.

Linguagem C para PIC 121


1.72 - Anotações

122 Linguagem C para PIC