Escolar Documentos
Profissional Documentos
Cultura Documentos
Microcontroladores PIC
2/111
8K words de ROM
358 bytes de RAM
256 bytes de E2PROM
3 Timers
1 Porta Serial Sncrona/Assncrona
8 Entradas Analgicas
2 Comparadores/ Sadas PWM
3/111
Famlias PIC
Na linha de produtos da Microchip encontramos diversas famlias de
microcontroladores de 8,16 e 32 bits, sendo as principais listadas abaixo:
PIC10
PIC12
PIC16
PIC18
4/111
PIC24/dsPIC
PIC32
Linguagens de Programao
Assembly
Uma linguagem de montagem ou assembly uma
notao legvel por humanos para o cdigo de mquina que
uma arquitetura especfica usa. A linguagem de mquina, que
um mero padro de bits, torna-se legvel pela substituio dos
valores em bruto por smbolos chamados mnemnicos.
Por exemplo, enquanto um computador sabe o que a
instruo-mquina IA-21 (10110000 01100001) faz, para os
programadores mais fcil recordar a representao
equivalente em intruses mnemnicas MOV AL, 61h. Tal
instruo ordena que o valor hexadecimal 61 (97, em decimal)
seja movido para um registrador chamado 'AL'.
As vantagens da programao de microcontroladores em assembly so a
velocidade e eficincia do cdigo gerado. Como desvantagens temos a difcil
manuteno devido a complexidade inerente a linguagem, alm da pouca
portabilidade devido ao grande comprometimento com um hardware especifico.
5/111
Linguagem C
C
uma
linguagem
de
programao estruturada e padronizada
criada na dcada de 1970 por Dennis
Ritchie e Ken Thompson para ser usada
no sistema operacional UNIX. Desde
ento se espalhou por muitos outros
sistemas operativos, e tornou-se uma
das linguagens de programao mais
usadas.
C tem como ponto-forte a sua
eficincia e a linguagem de
programao de preferncia para o
desenvolvimento
de
software
de
sistemas operacionais, apesar de tambm ser usada para desenvolver aplicaes.
Outra caracterstica importante de C sua proximidade a linguagem de mquina,
que permite que um projetista seja capaz de fazer algumas previses de como o
software ir se comportar ao executar.
A utilizao de C para a programao de microcontroladores PIC parece
uma escolha natural e realmente . Atualmente, a maioria dos microcontroladores
disponvel no mercado conta com compiladores de linguagem C para o
desenvolvimento de software. O uso de C permite a construo de programas e
aplicaes muito mais complexas do que seria vivel utilizando apenas assembly.
Lgica Booleana
Muitas operaes que o microcontrolador executa so lgicas. Para que
possamos entender e fazer uso dessas operaes, precisamos saber os princpios
de lgica booleana. O termo booleana vem do nome George Boole, matemtico
ingls, que foi o primeiro a defini-las como parte de um sistema de lgica em
meados do sculo XIX.
Lgica E
Suponhamos que voc seja uma pessoa que trabalha durante toda a
semana e no sbado e que portanto, seu nico dia de folga seja o domingo.
Suponhamos tambm que voc, como muitas outras pessoas, gosta de ir a praia
no domingo. Porm, para isso acontecer preciso haver sol correto? Sendo
assim, a situao descrita a seguinte:
Hoje Domingo?
no
no
sim
sim
Tem Sol?
no
sim
no
sim
Vamos a praia?
no
no
no
sim
6/111
B
R
F
F
V
F
F
F
V
V
R=AeB
Lgica OU
Imaginemos um sistema de alarme de uma sala que monitore duas portas
atravs de dois sensores S1 e S2:
Para o alarme ser acionado basta que qualquer um dos sensores seja
acionado, isso se descreve na situao abaixo:
Acionou S1?
no
no
sim
sim
Acionou S2?
no
sim
no
sim
Aciona Alarme?
no
sim
sim
sim
7/111
Lgica NO
No exemplo da lgica E usamos a expresso Hoje Domingo para indicar
o dia de folga da pessoa. Mas se quisssemos expressar de uma forma que
sempre fossemos obter a resposta se hoje o dia de folga da pessoa, poderamos
usar a expresso: No Trabalho Hoje?. Percebe-se que tratasse do contrario da
expresso Trabalho Hoje, portanto a tabela verdade da Lgica NO :
A
R
F
V
V
F
R = NO A
Lgica OU EXCLUSIVO
Imaginemos que ocorrera uma festa muito badalada na
cidade em que dois sujeitos foram convidados Joo e Jos.
Ambos so timas pessoas e ajudam a animar a festa. Se
nenhum dos dois comparecer, a festa ser muito chata, sem
animao. Porm se os dois se encontrarem brigaram a noite
inteira e estragam a festa dos outros. A situao acima pode
ser representada na tabela abaixo:
Joo foi festa?
no
no
sim
sim
A festa boa?
no
sim
sim
no
O fato de a festa ser boa depender de apenas um dos dois (Joo ou Jos)
estar presente, o que caracteriza uma lgica OU EXCLUSIVO. O nome dado a
lgica em ingls XOR (Exclusive Or). A tabela verdade da lgica encontra-se
abaixo:
A
B
R
F
F
F
F
V
V
V
F
V
V
V
F
R = A xor B
Variveis
Todos os programas criados para o microcontrolador manipulam com
dados, mais comumente nos referimos aos dados como variveis. Variveis so
8/111
Lgicas
Numricas
o Inteiras
o Reais
Caractere
o Simples
o Texto
Lgicas
As variveis lgicas so usadas para armazenar valores lgicos, verdadeiro
ou falso, ocupam no mnimo 1 bit de memria (depende do compilador) e podem
armazenar o resultado de uma equao booleana por exemplo.
Numricas Inteiras
As variveis inteiras podem guardar valores inteiros. Podem ter
representaes com ou sem sinal. As variveis inteiras em geral podem ocupar 1,
2, 4 ou 8 bytes da memria do microcontrolador (dependendo tambm do
compilador).
Numricas Reais
Variveis Reais so utilizadas para armazenar nmeros reais (com vrgula)
sendo por definio com sinal. A representao utilizando ponto flutuante
geralmente ocupa 4 bytes.
Caractere Simples
Contm o valor de um caractere especfico. Ocupam 1 byte na memria, se
esse for representando como caractere da tabela ASCII (acrnimo para American
Standard Code for Information Interchange, que em portugus significa "Cdigo
Padro Americano para o Intercmbio de Informao") uma codificao de
caracteres de 7 bits baseada no alfabeto ingls. Surgiu posteriormente uma
verso com 8 bits do ASCII que previa o suporte para os caracteres especiais. O
ASCII se tornou o mais padro dos sistemas de codificao de caracteres e seu
uso quase unanimidade nos compiladores.
Caractere Texto
So usados para representar palavras ou textos, nada mais que uma
cadeia de caracteres simples. Utilizam uma poro contgua da memria
9/111
reservada para esse fim. Essa cadeia ocupa tantos bytes quantos for o tamanho
do texto em uma determinada codificao (geralmente ASCII).
Bases Numricas
A seguir descrevemos as trs bases que os programas de microcontrolador
usam: binria, decimal e hexadecimal.
Base Decimal
A base decimal, e a base que utilizamos no dia-a-dia tm base 10 pois
contm 10 algarismos (0 a 9). No so necessrias mais explicaes sobre essa
base, j que efetuamos todos os clculos que conhecemos nessa base.
Base Binria
A base binria utilizada quando queremos representar um nmero bit a
bit. Numa analogia, uma varivel de um byte (8 bits) representada em base
binria, se assemelha a oito lmpadas de diferentes potncias dispostas da
seguinte forma:
Hexadecimal
0x21
0x2666
0x04D3
0x000724B2
importante observar que no caso do resto ser maior que 9 o dgito deve
ser convertido para hexadecimal. No caso do resto 11 acima, o seu
correspondente hexadecimal B. Para a converso de 0x01B1 hexadecimal para
decimal, a lgica semelhante a converso de binrio para decimal:
0 x 163 + 1 x 162 + B x 161 + 1 x 160
0 x 163 + 1 x 162 + 11 x 161 + 1 x 160
0 x 4096 + 1 x 256 + 11 x 16 + 1 x 1
256 + 176 + 1 = 433
Fluxogramas
Embora atualmente existam outras formas de representao de ciclo de
execuo, os fluxogramas so muito utilizados. Representam o ciclo de instrues
e tomada de deciso que devem ser tomados na soluo de um problema.
Constituem-se basicamente de diversos smbolos para cada operao, sendo os
mais comuns apresentados abaixo:
12/111
13/111
14/111
Aplicao Exemplo
Para exemplificar o ciclo de produo de um programa, vamos nos utilizar
de um exemplo de aplicao e mostrar cada etapa de sua implementao.
1) Definio do Problema
Um cliente lhe procura com um de seus produtos, solicitando que voc
desenvolva uma mquina que automatize o processo de fabricao. O produto
uma chapa de metal com um furo centralizado sem muita preciso:
2) Definio da Soluo
Aps o estudo para soluo voc chega ao esboo abaixo:
15/111
3) Fluxograma
Depois de definida a soluo convm fazermos o fluxograma que a expressa:
4) Codificao
5) Depurao
Tanto a codificao quanto a depurao dessa aplicao sero feitos nos
captulos posteriores quando tivermos os pr-requisitos necessrios.
16/111
17/111
19/111
20/111
Timers
O PIC16F877A contm em sua arquitetura trs timers nomeados TMR0,
TMR1 e TMR2. Sendo o TMR0 e TMR2 de 1 byte e o TMR1 de 2 bytes. Os timers
so geralmente utilizados quando se deseja fazer uma medio precisa de tempo,
mas tambm podem ser configurados como contadores ou servir de base para
outro perifrico como o mdulo PWM (Pulse Width Modulation - Modulao por
largura de pulso).
Para entender o funcionamento do timer, imaginemos que o este um
tanque que se pode encher de gua, sendo assim podemos considerar que as
capacidades desses tanques sejam 255 litros para o TMR0 e TMR2 e 65535 litros
para o TMR1. Imagine agora que o processador joga 1 litro de gua a cada
quatro ciclos de clock (200ns se o microcontrolador estiver rodando a 20 MHz) ou
seja, incrementa o valor do timer em um.
1
20000000
(4 x 8)
65535 x 1,6us
104ms
21/111
Porta Serial
Hoje em dia existe uma grande tendncia para que a comunicao entre
componentes eletrnicos seja serial. Isso denotado pela grande quantidade de
componentes que possuem interfaces seriais. Embora possa apresentar taxas de
transferncia inferiores a comunicao paralela, o menor uso de pinos e
conseqentemente uma economia de trilhas na placa do circuito impresso acaba
favorecendo o uso da comunicao serial.
Existem dois tipos de comunicao serial, a assncrona na qual no existe
um pino para sincronismo do tempo de cada bit numa transmisso; portanto,
fixo. E a sncrona que possui um pino que se alterna para indicar a transferncia
de um bit.
Destes dois tipos de serial a mais comumente utilizado a assncrona, esta
composta basicamente de dois pinos: TX (transmissor) e RX (receptor). Sendo
que o transmissor de um dispositivo ligado no receptor do outro e vice-versa. O
PIC16F877A possui uma porta serial universal (USART) que pode ser configurada
como assncrona ou sncrona. A porta serial se encontra nos pinos RC6 (TX) e
RC7 (RX) pinos 25 e 26 respectivamente do encapsulamento DIP.
Na serial assncrona cada byte transmitido bit a bit em uma freqncia
conhecida por ambos os dispositivos esta freqncia chamada de baudrate da
comunicao sendo que o inverso do valor do baudrate (perodo) representa o
tempo de um bit.
Como ambos os lados conhecem o baudrate da comunicao a
amostragem feita na metade desse meio perodo. A grosso modo, o transmissor
pega o byte a ser transmitido e amostra seus 8 bits no pino TX (quando
estudarmos a serial a fundo veremos que existem outros bits que so enviados
juntamente). O pino RX do receptor percebe cada um destes 8 bits e forma
novamente o byte do outro lado. Um diagrama bsico de uma comunicao
assncrona feita entre dois dispositivos visto abaixo. Nesta o Dispositivo A est
enviando um byte com valor 187 ou 0B10111011 em binrio para o Dispositivo B e
o perodo de um bit (P) representado pela seta vermelha:
22/111
VREF
=
1024
5V
1024
4,88 x 10-3V
= 4,88mV
24/111
Interrupes do PIC
Os microcontroladores PIC apresentam diversas interrupes, no caso do
16F877A so 15 fontes diferentes. As mais comumente utilizadas so
exemplificadas abaixo.
Interrupo Externa
O pino RB0 (pino 33 no CI encapsulamento DIP) dotado de um circuito
interno capaz de detectar e gerar uma interrupo na subida ou descida do pino.
Isso configurvel atravs de programa e dentre outras coisas poderia ser usado
para efetuar contagem de pulsos de um sensor de velocidade. Bastando que para
isso uma varivel seja incrementada a cada chamada da funo de tratamento da
interrupo externa.
Interrupo de Timers
O PIC16F877A contm trs timers: TMR0, TMR1 e TMR2 cada qual
podendo gerar uma interrupo. O Timer nada mais que um registrador que
incrementado em com um perodo igual da freqncia do microcontrolador.
Conforme j foi mencionado, um timer se assemelha muito a uma pessoa
enchendo um taque com um balde com um perodo entre cada arremesso
equivalente ao do timer.
26/111
27/111
Primeiro Programa C
A seguir fornecido um programa exemplo, de uma aplicao muito
simples que pisca com um perodo de 500ms os 8 leds ligados ao PORTD do
PIC16F877A da placa base da Cuscopic:
28/111
30/111
Descrio
Tamanho
int1
Varivel boleana
1 bit
int8
Inteira
1 byte
int16
Inteira
2 bytes
int32
Inteira
4 bytes
float
Ponto Flutuante
4 bytes
Intervalo
0
ou
1
0 a 255
ou
-128 a 127
0 a 65535
ou
-32768 a 32767
0 a 4294967295
ou
-2147483648 a 2147483647
-1.7E38 a 1.7E38
(preciso de 6 dgitos)
Equivalncia
int1
Int8
Utilizao
Outra nomenclatura para int1.
Varivel de 1 byte que representa um caractere
e no uma varivel inteira. Usada somente para
melhor adequao.
31/111
long
int16
Declarao de Variveis
Para serem usadas as variveis precisam ser declaradas, as declaraes
podem ser feitas da seguinte forma:
tipo nome-da-variavel;
ou:
tipo nome-da-variavel1, nome-da-variavel2, ...;
Onde tipo o tipo da varivel e os nomes-da-variavelx so os nomes das
variveis separados por vrgulas. Opcionalmente na declarao da varivel ela
pode ser inicializada com um valor, caso contrrio o valor inicial da varivel
desconhecido:
tipo nome-da-variavel = valor-inicial;
ou:
tipo nome-da-variavel1 = v-inicial1, nome-da-variavel2 = v-inicial2, ...;
Por padro as variveis so sem sinal com exceo do tipo float que por
definio tem sinal. No caso de desejarmos utilizar variveis com sinal a sua
declarao deve ser precedida com o prefixo signed:
signed tipo nome-da-variavel;
ou:
signed tipo nome-da-variavel1, nome-da-variavel2, ...;
Existem casos que se deseja declarar uma varivel que representa um
conjunto com um tamanho determinado como um texto. Isso comumente
chamado de array ou vetor. Para isso devemos determinar o seu tamanho entre
colchetes; para que dessa forma o compilador aloque no uma mas n posies de
memria com o tipo especificado.
tipo nome-da-variavel [tamanho-do-array] = {valor-inicial1,valor-inicial2,...};
32/111
Nomenclatura de variveis
E recomendado na nomenclatura de variveis o uso de prefixos que
especificam o seu tipo. Isso auxilia o programador a identificar, em qualquer parte
do programa, o tipo da varivel sem ter de retornar e olhar a sua declarao. Os
prefixos para as principais variveis so exemplificados abaixo:
Tipo
int1
int8
int16
int32
signed int1
signed int8
signed int16
signed int32
float
char
Prefixo
i1_
i8_
i16_
i32_
si1_
si8_
si16_
si32_
f
c
Exemplo de declarao
int1 i1_Variavel;
int8 i8_Variavel;
int16 i16_Variavel;
int32 i32Variavel;
signed int1 i1_Variavel;
signed int8 i8_Variavel;
signed int16 i16_Variavel;
signed int32 i32Variavel;
float fVariavel;
char cVariavel;
Constante Numrica
10
0B10010111
0xAB
27.35
Significado
Constante Inteira em base Decimal
Constante Inteira em base Binria
Constante Inteira em base Hexadecimal
Constante Ponto Flutuante
Valor ASCII
65
90
61
33/111
Caractere Representado
Caractere de mudana de Linha (LF)
Caractere de retorno do Carro (CR)
Caractere de Tabulao (TAB)
Caractere de barra Invertida
Caractere Apstrofo
Caractere Aspas
Caractere Nulo
Significado
Cadeia que armazena a, b, c, d, e e \0.
Cadeia vazia que armazena apenas \0
Tamanho
6 bytes
1 byte
Declarao de Constantes
Alm das constantes que j esto definidas na linguagem C. possvel
declarar outras constantes como o nmero pi, nmero de Euler etc. Para isso
usamos a diretiva #define conforme exemplificado abaixo:
#define nome-da-constante valor-da-constante
conveniente observar que o nome da constante no pode ser o de uma
palavra reservada da linguagem C (como a palavra main, por exemplo) e que
exista pelo menos um espao entre a palavra e o nome da constante e dessa
ultima antes do valor da constante. Outro ponto importante e que semelhante as
variveis aconselhvel que as constantes tenham como prefixo a letra
k(minscula) seguida pelo nome da constante escrito todo em letras maisculas.
Isso se justifica para que o programador possa identificar que o que est sendo
referenciado uma constante em qualquer ponto do programa.
#define kEXEMPLO_DE_CONSTANTE_COM_VALOR_DEZ 10
Operadores
Operadores Aritmticos
Os operadores aritmticos so os seguintes: + (adio), - (subtrao), *
(multiplicao) e / (diviso). No caso de diviso entre nmeros inteiros, o resultado
34/111
Tem o valor
7
1
3
2
3
0
Operador de atribuio
O operador de atribuio (=) copia o valor do lado direito para a varivel, ou
endereo, do lado esquerdo. Alm disso, o operador = tambm retorna este valor
como resultado, isso significa que, se fizermos x = y = 0, ser processada
inicialmente a operao y = 0, atribuindo o valor 0 varivel y. Esta expresso
fornece o resultado 0, que atribudo varivel x. No final do processamento,
ambas as variveis tero o valor 0.
Expresso
i=3
i=3+4
i=k=4
Operao
Coloca o valor 3 em i
O valor 7 colocado em i
O valor 4 colocado em k; o valor da
atribuio (4) ento colocado em i
Explicao
A varivel de dois bytes i16_Soma recebe o
valor da varivel de um byte i8_Termo aps
i16_Soma = (int16) i8_Termo
esta ser convertida para uma varivel de
dois bytes.
A varivel de dois bytes i16_Var recebe a
varivel de quatro bytes i32_Resultado aps
i16_Var = (int16) i32_Resultado
esta ser convertida para uma varivel de
dois bytes.
Atribuies entre variveis de tipos diferentes pode resultar em erro de
estouro de limite, ou perda de informao. Por exemplo: uma varivel de quatro
bytes com o valor 70000(0x00011170) atribuda a uma varivel de dois bytes.
Neste caso apenas os valor dos dois bytes menos significativos sero repassados
e a varivel de dois bytes receber o valor 4464(0x1170).
35/111
Operadores relacionais
Os operadores relacionais em C so: == (igual a), != (diferente de), > (maior
que), < (menor que), >= (maior ou igual a) e <= (menor ou igual a). O resultado de
dois valores conectados por um operador relacional ser zero (0) para falso ou um
(1) para verdadeiro.
Expresso
5<3
3<5
5 == 5
3 == 5
5 <= 5
Resultado
0
1
1
0
1
Resultado
1
1
1
0
1 se i for maior que 5 e menor ou igual a 7.
0, qualquer outro caso
Resultado
0
1
1 se i no for maior que 5. 0, se i for maior que 5.
Valor
3
0x0F
0xFF
0x3C
0x0E
0x5A
Expresso binria
00000001 | 00000010
11111111 & 00001111
00110101 | 11001100
00001111 << 2
00011100 >> 1
~10100101
Valor binrio
00000011
00001111
11111111
00111100
00001110
01011010
Atribuies reduzidas
A linguagem C oferece muitos operadores de atribuio que so reduo de
outros operadores. Eles tomam a forma de op=, onde op pode ser +, -, *, /, %, <<,
>>, &, ^, |. A expresso f op= g anloga a f = f op g. Atribuies reduzidas so
somente um atalho para que o programador tenha o cdigo mais sucinto
(menor):
Expresso
a += 2
i <<= 1
s /= (7 + 2)
Equivale a
a=a+2
i = i << 1
s = s / (7 + 2)
Operadores pr e ps-fixados
Os operadores pr e ps-fixados incrementam (++) ou decrementam (--)
uma varivel. Uma operao prefixada realizada antes que o valor da varivel
seja utilizado. Uma operao ps-fixada efetuada aps a utilizao da varivel.
Por exemplo, para uma varivel i inteira com valor 5:
Expresso
5 + (i++)
5 + (i--)
5 + (++i)
5 + (--i)
Valor de i utilizado
na avaliao
5
5
6
4
Valor da expresso
Valor final de i
10
10
11
9
6
4
6
4
Precedncia de operadores
Os operadores tm uma ordem de precedncia. Isto , sem parnteses,
certas operaes so efetuadas antes de outras com menor precedncia. Para
operadores com precedncia igual, a associatividade da esquerda para direita.
Para se ter certeza da interpretao, as expresses que se deseja interpretar
primeiro devem ser agrupadas entre parnteses. Caso no haja parnteses a
ordem de execuo das operaes bsicas :
37/111
1)
2)
3)
4)
*
/
+
-
38/111
39/111
Os bits dos registradores PORTx refletem o valor atribudo nos pinos de seu
porto quando estes esto configurados como sada. Quando configurado como
entrada, a leitura do registrador reflete o valor lgico de cada pino do porto.
Operao
PORTx = 0xFF
PORTx = 0x00
i8_ PORTx = PORTx
Resultado
Coloca todos os pinos do PORTx em nvel lgico 1
Coloca todos os pinos do PORTx em nvel lgico 0
L o valor do PORTx e o coloca na varivel i8_ PORTx
Operao
Operao em Binrio
Resultado
0B11001100
PORTx |= set_bit0
0B11001101
Operao
Operao em Binrio
Resultado
0B00110111
0B00100111
Operao
Operao em Binrio
Resultado
0B11110110
PORTx ^= set_bit7
0B01110110
40/111
Expresso
Resultado
0B10010000
0B10010000
0B10010000
0B10010000
Descrio
Testa se o bit 0
do PORTx est
em nvel lgico 0.
Resultou em 1
(verdadeiro)
Testa se o bit 0
do PORTx est
em nvel lgico 1
Resultou em 0
(falso)
Testa se o bit 7
do PORTx est
em nvel lgico 0.
Resultou em 0
(falso)
Testa se o bit 7
do PORTx est
em nvel lgico 1
Resultou em 1
(verdadeiro)
41/111
42/111
43/111
44/111
break;
// Caso no PORTD tiver a senha 2
case 59:
// Liga o PORTC por 2 segundos
PORTC = 0XFF;
delay_ms(2000);
break;
// Caso no PORTD tiver a senha 3
case 129:
// Liga o PORTC por 3 segundos
PORTC = 0XFF;
delay_ms(3000);
break;
// Caso padro
default:
// Desliga o PORTC
PORTC = 0;
break;
}
}
}
45/111
46/111
{
// Valor inicial do contador recebe 4
i8_ContInicial = 4;
}
// Espera soltar RDO e RD1
// Faa
// {} = nada
// Enquanto
// o bit0 do PORTD estiver ligado
// ou
// o bit1 do PORTD estiver ligado
do
{}
while(((PORTD & set_bit0) != 0) || ((PORTD & set_bit1) != 0));
// Contador recebe o valor inicial
i8_Cont = i8_ContInicial;
// Lao while {}
while(i8_Cont <= 3)
{
// Pisca RC0
PORTC |= SET_BIT0;
delay_ms(500);
PORTC &= CLEAR_BIT0;
delay_ms(500);
// Incrementa contador
i8_Cont++;
}
// Contador recebe o valor inicial
i8_Cont = i8_ContInicial;
// Lao do {} while
do
{
// Pisca RC0
PORTC |= SET_BIT1;
delay_ms(500);
PORTC &= CLEAR_BIT1;
delay_ms(500);
// Incrementa contador
i8_Cont++;
}
while(i8_Cont <= 3);
}
}
47/111
48/111
49/111
//
//
//
//
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
50/111
// Lao principal
while(TRUE)
{
// Se a senha que estiver no PORTD estiver correta
if(testa_senha(PORTD))
{
// Dependendo do valor do PORTD
switch(PORTD)
{
// Caso no PORTD tiver a senha 1
case kSENHA1:
// Liga o PORTC por 1 segundo
liga_portc(1);
break;
// Caso no PORTD tiver a senha 2
case kSENHA2:
// Liga o PORTC por 2 segundos
liga_portc(2);
break;
// Caso no PORTD tiver a senha 3
case kSENHA3:
// Liga o PORTC por 3 segundos
liga_portc(3);
break;
// Caso padro
default:
// Desliga o PORTC
PORTC = 0;
break;
}
// Espera liberar as teclas
do {} while(!teclas_liberadas());
}
}
}
// ======================================================================
#separate
// Piscar o PORTC 3 vezes
void pisca_portc(void)
{
// Usada no lao for que faz o PORTC piscar
int8 i8_i;
51/111
52/111
// Seno
else
{
// Retorna que no/falso (false), as senha passada no correta
return(false);
}
}
// ======================================================================
53/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
54/111
os portos
0B00000000;
0B00000000;
0B00000000;
// Inicializa o display
inic_display();
// Lao de repetio
while(true)
{
// Reflete no PORTC o que est lendo do PORTD
PORTC = PORTD;
// Conforme o que for pressionado no PORTD
switch(PORTD)
{
// Se for DB0
case 0B00000001:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("1 BYTE:
");
// Para i8_i de 0 a 254 de 1 em 1
for(i8_i=0; i8_i<0xFF; i8_i++)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%u %3u %03u %c %X ",
i8_i,i8_i,i8_i,i8_i,i8_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB1
case 0B00000010:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("1 BYTE SINAL:
");
// Para i8_i de 0 a 254 de 1 em 1
for(i8_i=0; i8_i<0xFF; i8_i++)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%d %03d %c %X
",
55/111
i8_i,i8_i,i8_i,i8_i,i8_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB2
case 0B00000100:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("2 BYTES:
");
// Para i16_i de 0 a 60000 de 1000 em 1000
for(i16_i=0; i16_i<=60000; i16_i+=1000)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%lu %05lu %lX
",i16_i,i16_i,i16_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB3
case 0B00001000:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("2 BYTES SINAL: ");
// Para i16_i de 0 a 60000 de 1000 em 1000
for(i16_i=0; i16_i<=60000; i16_i+=1000)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%ld %lX
",i16_i,i16_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB4
case 0B00010000:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("4 BYTES:
");
// Para i32_i de 0 a 1000000000 de 10000000 em 10000000
for(i32_i=0; i32_i<=1000000000; i32_i+=10000000)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%lu
",i32_i);
delay_ms(kTEMPO_ENTRE);
}
56/111
break;
// Se for DB5
case 0B00100000:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("4 BYTES SINAL: ");
// Para i32_i de 0 a 1000000000 de 10000000 em 10000000
for(i32_i=0; i32_i<=1000000000; i32_i+=10000000)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%ld
",i32_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB6
case 0B01000000:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("4 BYTES FLOAT: ");
// Para f_i de 0 a 20 de 0.01 em 0.01
for(f_i=0; f_i<20; f_i+=0.01)
{
// Mostra a varivel por um tempo
end_display(2,1);
printf(mostra,"%f %01.3f
",f_i,f_i);
delay_ms(kTEMPO_ENTRE);
}
break;
// Se for DB7
case 0B10000000:
// Sinaliza o que esta mostrando
end_display(1,1);
mostra("1 BIT:
");
// Varivel recebe falso
i1_i = false;
// Mostra a varivel por 10x o tempo normal
end_display(2,1);
printf(mostra,"%d %u
",i1_i,i1_i);
delay_ms(10*kTEMPO_ENTRE);
// Varivel recebe verdadeiro
i1_i = true;
57/111
58/111
Captulo 10 Timers
Timer 0 como contador
/*
Programa demonstrando TMR0 operando como contador
*/
// Biblioteca CCS do PIC16F877A
#include<16f877A.h>
// Definio dos Registradores do PIC16F877A
#include<16F877A-sfrs.h>
// Definies de configuraes do PIC
#fuses HS,NOWDT,PUT,PROTECT,NOCPD,NOBROWNOUT,NOLVP
//
//
//
//
//
//
//
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
59/111
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00010000;
TRISB = 0B00000000;
TRISC = 0B00000000;
TRISD = 0B00000000;
// Inicializa os portos
PORTA = 0B00000000;
PORTB = 0B00000000;
PORTC = 0B00000000;
PORTD = 0B00000000;
// Incremento TMR pelo RA4, na subida, prescaler para TMR0,
// prescaler 1:2 (Datasheet pgina 25)
// Bit 07 - RBPU: PORTB Pull-up Enable bit
// Bit 06 - INTEDG: Interrupt Edge Select bit
// Bit 05 - T0CS: TMR0 Clock Source Select bit
// Bit 04 - T0SE: TMR0 Source Edge Select bit
// Bit 03 - PSA: Prescaler Assignment bit
// Bit 02 - \
// Bit 01 - | PS2:PS0: Prescaler Rate Select bits
// Bit 00 - /
OPTION_REG = 0B00100000;
// Coloca o valor inicial no TMR0 (Datasheet pgina 55)
TMR0 = 0xF6;
// Habilita interrupes, interrupes de perifricos
// e TMR0 (Datasheet pgina 26)
// Bit 07 - GIE: Global Interrupt Enable bit
// Bit 06 - PEIE: Peripheral Interrupt Enable bit
// Bit 05 - TMR0IE: TMR0 Overflow Interrupt Enable bit
// Bit 04 - INTE: RB0/INT External Interrupt Enable bit
// Bit 03 - RBIE: RB Port Change Interrupt Enable bit
// Bit 02 - TMR0IF: TMR0 Overflow Interrupt Flag bit
// Bit 01 - INTF: RB0/INT External Interrupt Flag bit
// Bit 00 - RBIF: RB Port Change Interrupt Flag bit
INTCON = 0B11100000;
// Inicializa o display
inic_display();
// Lao de repetio
while(true)
{
// Mostra o PORTA, varivel, TMR0 e INTCON
end_display(1,1);
printf(mostra,"PORTA:%X VAR:%X ",PORTA,i8_Var);
end_display(2,1);
printf(mostra,"TMR0:%X INTC:%X ",TMR0,INTCON);
60/111
// Pisca o RC0
PORTC ^= set_bit0;
// Intervalo de 0,5s
delay_ms(500);
}
}
// ======================================================================
#int_timer0
// Interrupo de overflow do TMR0
void t0_int(void)
{
// Incrementa o valor da varivel
i8_Var++;
}
// ======================================================================
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
61/111
// Int16 ================================================================
// Int32 ================================================================
// Float ================================================================
// Prottipos de funes ================================================
// Prottipos de interrupes ===========================================
#int_timer1
// Interrupo de overflow do TMR1
void t1_int(void);
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00000000;
TRISB = 0B00000000;
TRISC = 0B00000000;
TRISD = 0B00000000;
// Inicializa os portos
PORTA = 0B00000000;
PORTB = 0B00000000;
PORTC = 0B00000000;
PORTD = 0B00000000;
// Prescaler do TMR1 8, clock FOSC/4,
// liga o timer (Datasheet pgina 59)
// Bit 07 - Unimplemented: Read as 0
// Bit 06 - Unimplemented: Read as 0
// Bit 05 - \ T1CKPS1:T1CKPS0: Timer1 In. Clock Prescaler Select bits
// Bit 04 - /
// Bit 03 - T1OSCEN: Timer1 Oscillator Enable Control bit
// Bit 02 - T1SYNC: Timer1 Ext. Clock In. Synchronization Cont. bit
// Bit 01 - TMR1CS: Timer1 Clock Source Select bit
// Bit 00 - TMR1ON: Timer1 On bit
T1CON = 0B00110001;
// Clculo e carregamento do tempo para interrupo do TMR1
// TMR1 = 65536 - ((TEMPOINT1 * FOSC ) / (4 * PRESCALER))
// TMR1 = 65536 - ((10e-3 * 20000000 ) / (4 * 8))
// TMR1 = 65536 - 6250
// TMR1 = 59286
// TMR1 = 0xE796
TMR1H = 0xE7;
TMR1L = 0x96;
//
//
//
//
62/111
// Bit
// Bit
// Bit
// Bit
// Bit
// Bit
INTCON
63/111
1s
>= 10)
contador de 1s
= 0;
64/111
// Zera o contador de 5s
i8_Cont5s = 0;
// Pisca o RC5 (5s)
PORTC ^= set_bit5;
}
}
}
}
// ======================================================================
65/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
66/111
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00000000;
TRISB = 0B00000000;
TRISC = 0B00000000;
TRISD = 0B11111111;
TRISE = 0B00000000;
// Inicializa os portos
PORTA = 0B00000000;
PORTB = 0B00000000;
PORTC = 0B00000000;
PORTD = 0B00000000;
PORTE = 0B00000000;
// Liga o TMR2, Prescaler 1:1 (Datasheet pgina 63)
// Bit 07 - Unimplemented: Read as 0
// Bit 06 - \
// Bit 05 - \ TOUTPS3:TOUTPS0: Timer2 Output Postscale Select bits
// Bit 04 - /
// Bit 03 - /
// Bit 02 - TMR2ON: Timer2 On bit
// Bit 01 - \ T2CKPS1:T2CKPS0: Timer2 Clock Prescale Select bits
// Bit 00 - /
T2CON = 0B00000100;
// Habilita o mdulo pwm (Datasheet pgina 66)
// Bit 07 - Unimplemented: Read as 0
// Bit 06 - Unimplemented: Read as 0
// Bit 05 - \ CCPxX:CCPxY: PWM Least Significant bits
// Bit 04 - /
// Bit 03 - \
// Bit 02 - \ CCPxM3:CCPxM0: CCPx Mode Select bits
// Bit 01 - /
// Bit 00 - /
CCP1CON = 0B00001111;
// Configura a freqncia para 19,53kHz
// PR2 = (1 / (Freqncia PWM * TOSC * Presaler TMR2 * 4)) - 1
// PR2 = (1 / (19530 * (1/2000000) * 1 * 4)) - 1
// PR2 = (1 / (19530 * 0,00000005 * 1 * 4)) - 1
// PR2 = (1 / 0,003906) - 1
// PR2 = 256,01 - 1
// PR2 = 256 - 1
PR2 = 255;
// Carrega o valor zero no PWM
carrega_pwm(0);
// Inicializa o display
inic_display();
67/111
68/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
69/111
#separate
// Efetua a leitura do canal analgica passado
int16 le_canal_analogica(int8 i8_Canal);
// Prottipos de interrupes ===========================================
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00000001;
TRISB = 0B00000000;
TRISC = 0B00000000;
TRISD = 0B00000000;
TRISE = 0B00000000;
// Zera
PORTA =
PORTB =
PORTC =
PORTD =
PORTE =
os portos
0B00000000;
0B00000000;
0B00000000;
0B00000000;
0B00000000;
// Inicializa o display
inic_display();
// Clock analgica FOSC/64, liga o A/D (Datasheet pgina 129)
// Bit 07 - \ ADCS1:ADCS0: A/D Conversion Clock Select bits
// Bit 06 - /
// Bit 05 - \
// Bit 04 - | CHS2:CHS0: Analog Channel Select bits
// Bit 03 - /
// Bit 02 - GO/DONE: A/D Conversion Status bit
// Bit 01 - Unimplemented: Read as 0
// Bit 00 - ADON: A/D On bit
ADCON0 = 0B10000001;
// Justificado a direita, FOSC/64,
// apenas AN0 analgica (Datasheet pgina 130)
// Bit 07 - ADFM: A/D Result Format Select bit
// Bit 06 - ADCS2: A/D Conversion Clock Select bit
// Bit 05 - Unimplemented: Read as 0
// Bit 04 - Unimplemented: Read as 0
// Bit 03 - Unimplemented: Read as 0
// Bit 02 - \
// Bit 01 - | PCFG3:PCFG0: A/D Port Configuration Control bits
// Bit 00 - /
ADCON1 = 0B11001110;
// Lao de repetio
while(true)
{
// L o canal 0
i16_ValorAD = le_canal_analogica(0);
70/111
",i16_ValorAD);
71/111
72/111
Captulo 13 E2PROM
Utilizando E2PROM - Electrically-Erasable Programmable Read-Only Memory
// Biblioteca CCS do PIC16F877A
#include<16f877A.h>
// Definio dos Registradores do PIC16F877A
#include<16F877A-sfrs.h>
// Definies de configuraes do PIC
#fuses HS,NOWDT,PUT,PROTECT,NOCPD,NOBROWNOUT,NOLVP
//
//
//
//
//
//
//
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
73/111
os portos
0B00000000;
0B00000000;
0B00000000;
0B00000000;
0B00000000;
// Inicializa o display
inic_display();
// L a varivel da eeprom
i8_Variavel = le_int8_e2prom(kENDERECO_E2PROM_VARIAVEL);
// Lao de repetio
while(true)
{
// Se pressionar RD1 incrementa varivel a
if((PORTD & set_bit1) != 0) i8_Variavel++;
// Se pressionar RD0 decrementa varivel a
if((PORTD & set_bit0) != 0) i8_Variavel--;
// Mostra as variveis no display
end_display(1,1);
printf(mostra,"VARIAVEL:%u
",i8_ i8_Variavel);
// Guarda o byte na E2prom
grava_int8_e2prom(kENDERECO_E2PROM_VARIAVEL, i8_Variavel);
// Enquanto alguma tecla estiver pressionada
do {} while(PORTD != 0);
// Enquanto no pressionar nenhuma tecla
do {} while(PORTD == 0);
}
}
// ======================================================================
#separate
void grava_int8_e2prom(int8 i8_Endereco, int8 i8_Dado)
{
74/111
75/111
76/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
77/111
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00000000;
TRISB = 0B00000000;
TRISC = 0B10000000;
TRISD = 0B00000000;
TRISE = 0B00000000;
// Zera
PORTA =
PORTB =
PORTC =
PORTD =
PORTE =
os portos
0B00000000;
0B00000000;
0B00000000;
0B00000000;
0B00000000;
78/111
// Lao de repetio
while(true)
{
// Espera receber um byte
do {} while((PIR1 & set_bit5) == 0);
// Limpa flag de recepo
PIR1 &= clear_bit5;
// Recebe o byte
i8_Byte = RCREG;
// Notifica o que recebeu
end_display(2,1);
printf(mostra,"D:%03u H:%X C:%c
",i8_Byte,i8_Byte,i8_Byte);
79/111
//
//
//
//
//
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
Power Up Time
Protege o cdigo contra leitura
Memria EEPROM desprotegida contra leitura
Sem reset por BROWNOUT
Sem programao em baixa tenso
80/111
os portos
0B00000000;
0B00000000;
0B00000000;
0B00000000;
0B00000000;
81/111
82/111
",i8_Byte,i8_Byte,i8_Byte);
}
}
// ======================================================================
#int_rda
// Tratamento da interrupo por recepo de dado da USART
void rx_int(void)
{
// Recebe o byte
i8_Byte = RCREG;
delay_ms(1000);
}
// ======================================================================
#int_timer1
// Interrupo de overflow do TMR1
void t1_int(void)
83/111
{
// Reprograma o timer
TMR1H = i8_TMR1H;
TMR1L = i8_TMR1L;
// Incrementa o contador de 500ms
i8_Cont500ms++;
// Se passou 500ms
if(i8_Cont500ms >= 5)
{
// Reinicia o contador
i8_Cont500ms = 0;
// Determina que passou 500ms
i1_Passou500ms = true;
}
}
// ======================================================================
84/111
Captulo 15 Watchdog
Utilizando o Watchdog
/*
Programa demonstrando o Watchdog operando
resetando caso algo trave o microcontrolador
*/
// Biblioteca CCS do PIC16F877A
#include<16f877A.h>
// Definio dos Registradores do PIC16F877A
#include<16F877A-sfrs.h>
// Definies de configuraes do PIC
#fuses HS,WDT,PUT,PROTECT,NOCPD,NOBROWNOUT,NOLVP
//
//
//
//
//
//
//
HS
WDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
85/111
86/111
HS
WDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
87/111
// Zera os portos
PORTC = 0B00000000;
// Prescaler para WDT, prescaler 1:256
// Bit 07 - RBPU: PORTB Pull-up Enable bit
// Bit 06 - INTEDG: Interrupt Edge Select bit
// Bit 05 - T0CS: TMR0 Clock Source Select bit
// Bit 04 - T0SE: TMR0 Source Edge Select bit
// Bit 03 - PSA: Prescaler Assignment bit
// Bit 02 - \
// Bit 01 - | PS2:PS0: Prescaler Rate Select bits
// Bit 00 - /
OPTION_REG = 0B00001111;
// Lao de repetio
while(true)
{
#asm
// Coloca o microcontrolador para dormir
SLEEP
#endasm
// Pisca todo o PORTC
PORTC = ~PORTC;
}
}
// ======================================================================
88/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
89/111
// Int16 ================================================================
int16 i16_TMR1
= 0; // Usado para calculo do valor do TMR1
int16 i16_ContSinalizaEvento = 0; // Conta tempo de sinalizao de evento
// Int32 ================================================================
// Float ================================================================
// Prottipos de funes ================================================
#separate
// Programa o tempo de sinalizao do evento em ms
void sinaliza_evento(int16 i16_Tempo);
// ======================================================================
#separate
// Retorna o estado atual ou o de cancelamento e confirmao se
// pressionar as teclas retorna tambm aps o timeout programado
// o estado de timeout
int8 confirma_cancela(int8 i8_EstadoCancela, int8 i8_EstadoAtual,
int8 i8_EstadoConfirma, int8 i8_EstadoTimeout);
// Prottipos de interrupes ===========================================
#int_timer1
// Interrupo de overflow do TMR1
void t1_int(void);
// ======================================================================
// Funo principal do programa
void main()
{
// Configura o sentido dos portos
TRISA = 0B00000000;
TRISB = 0B00000000;
TRISC = 0B00000000;
TRISD = 0B00000000;
TRISE = 0B00000000;
// Zera
PORTA =
PORTB =
PORTC =
PORTD =
PORTE =
//
//
//
//
//
//
//
//
os portos
0B00000000;
0B00000000;
0B00000000;
0B00000000;
0B00000000;
90/111
91/111
{
// Determina que no esta mais sinalizando
i1_SinalizandoEvento = false;
}
}
// Se passou um segundo
if(i1_Passou1Segundo)
{
// Determina que j tratou os eventos de 1 segundo
i1_Passou1Segundo = false;
// Decrementa para timeout confirma/cancela
if(i8_TimeOutConfirmaCancela > 0) i8_TimeOutConfirmaCancela--;
// Togla RC0
PORTC ^= set_bit0;
}
// Se no estiver sinalizando um evento
if(!i1_SinalizandoEvento)
{
// Conforme o estado da mquina de estado
switch(i8_Estado)
{
// Mensagem 1
case 0:
// Mostra a mensagem
end_display(1,1);
mostra(" ESTE PROGRAMA ");
end_display(2,1);
mostra(" VEM DEMONSTRAR ");
// Sinaliza por um tempo
sinaliza_evento(2000);
// Passa para o prximo estado
i8_Estado = 10;
break;
// Mensagem 2
case 10:
// Mostra a mensagem
end_display(1,1);
mostra("A UTILIZACAO DE ");
end_display(2,1);
mostra(" MAQ. DE ESTADOS");
// Sinaliza por um tempo
sinaliza_evento(3000);
// Passa para o prximo estado
i8_Estado = 20;
92/111
break;
// Mensagem 3
case 20:
// Mostra a mensagem
end_display(1,1);
mostra(" ASSOCIADA A ");
end_display(2,1);
mostra("TEMPORIZACAO DE");
// Sinaliza por um tempo
sinaliza_evento(2000);
// Passa para o prximo estado
i8_Estado = 30;
break;
// Mensagem 4
case 30:
// Mostra a mensagem
end_display(1,1);
mostra(" EVENTOS SEM ");
end_display(2,1);
mostra(" USO DE DELAYS! ");
// Sinaliza por um tempo
sinaliza_evento(4000);
// Passa para o prximo estado
i8_Estado = 40;
break;
// Prepara a deciso de confirma/cancela
case 40:
// Notifica a escolha
end_display(1,1);
mostra("DESEJA VER AS ");
end_display(2,1);
mostra("MSGS NOVAMENTE?");
// Programa o timeout de confirma/cancela
i8_TimeOutConfirmaCancela = 15;
// Passa para o prximo estado
i8_Estado = 50;
break;
// Escolhe se deseja ver novamente a mensagem
case 50:
93/111
94/111
#separate
// Retorna o estado atual ou o de cancelamento e confirmao se
// pressionar as teclas retorna tambm aps o timeout programado
// o estado de timeout
int8 confirma_cancela(int8 i8_EstadoCancela, int8 i8_EstadoAtual,
int8 i8_EstadoConfirma, int8 i8_EstadoTimeout)
{
// Se pressiona alguma tecla
if(i1_TeclaNova)
{
// Determina que tratou a tecla apertada
i1_TeclaNova = false;
// Conforme o valor de teclas
switch(i16_Teclas)
{
// Se for confirma
case kCONFIRMA:
// Retorna o estado de confirmao
return(i8_EstadoConfirma);
break;
// Se for cancela
case kCANCELA:
// Retorna o estado de cancelamento
return(i8_EstadoCancela);
break;
}
}
// Se ocorreu timeout
if(i8_TimeOutConfirmaCancela == 0)
{
// retorna o estado de timeout
return(i8_EstadoTimeout);
}
// Se chegou aqui retorna o estado atual
return(i8_EstadoAtual);
}
// ======================================================================
#int_timer1
// Interrupo de overflow do TMR1
void t1_int(void)
{
// Reprograma o timer
TMR1H = i8_TMR1H;
TMR1L = i8_TMR1L;
// Efetua a leitura do teclado
ler_teclas();
95/111
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
96/111
97/111
PORTB
PORTC
PORTD
PORTE
=
=
=
=
0B00000000;
0B00000000;
0B00000000;
0B00000000;
98/111
printf(mostra,"ESTADO:%u
",i8_Estado);
// Se passou 100ms
if(i1_Passou100ms)
{
// Determina que j tratou os eventos de 100ms
i1_Passou100ms = false;
// Coloca o deslocamento atual do PORTC
PORTC = i8_DeslocaPORTC[i8_IndDeslPORTC];
// Incrementa e avalia o limite do ndice
i8_IndDeslPORTC++;
if(i8_IndDeslPORTC >= 3) i8_IndDeslPORTC = 0;
}
// Se passou um segundo
if(i1_Passou1Segundo)
{
// Determina que j tratou os eventos de 1 segundo
i1_Passou1Segundo = false;
// Se estiver temporizando a minuteira
if(i8_TempMinuteira > 0)
{
// Decrementa um segundo
i8_TempMinuteira--;
}
}
// Conforme o estado
switch(i8_Estado)
{
// Espera pressionar a tecla
case kESPERA_PRESSIONAR_TECLA:
// Se pressionou a tecla
if((PORTD & set_bit0) != 0)
{
// Passa para o prximo estado
i8_Estado = kLIGA_RELE;
}
break;
// Liga o Rel
case kLIGA_RELE:
// Liga Rel
PORTE |= set_bit0;
// Passa para o prximo estado
i8_Estado = kESPERA_SOLTAR_TECLA;
break;
99/111
100/111
break;
}
}
}
//
=======================================================================
#int_timer1
// Interrupo de overflow do TMR1
void t1_int(void)
{
// Reprograma o timer
TMR1H = i8_TMR1H;
TMR1L = i8_TMR1L;
// Incrementa contador de 100ms
i8_Cont100ms++;
// Se passou 100ms
if(i8_Cont100ms >= 10)
{
// Reinicia contador
i8_Cont100ms = 0;
// Notifica que passou 100ms
i1_Passou100ms = true;
// Incrementa contador de segundo
i8_Cont1Segundo++;
// Se passou um segundo
if(i8_Cont1Segundo >= 10)
{
// Reinicia contador
i8_Cont1Segundo = 0;
// Notifica que passou um segundo
i1_Passou1Segundo = true;
}
}
}
// ======================================================================
101/111
Captulo 17 Ponteiros
Exemplo de ponteiros
/*
Programa que demonstra o uso de ponteiros
*/
// Biblioteca CCS do PIC16F877A
#include<16f877A.h>
// Definio dos Registradores do PIC16F877A
#include<16F877A-sfrs.h>
// Definies de configuraes do PIC
#fuses HS,NOWDT,PUT,PROTECT,NOCPD,NOBROWNOUT,NOLVP
//
//
//
//
//
//
//
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
102/111
os portos
0B00000000;
0B00000000;
0B00000000;
// Inicializa o display
inic_display();
// Lao de repetio
while(true)
{
// Mostra variveis no display
end_display(1,1);
printf(mostra,"VAR: %lX
",i32_Variavel);
end_display(2,1);
mostra("
");
// Enquanto no pressionar nenhuma tecla
do {} while(PORTD == 0);
// Conforme o valor do PORTD
switch(PORTD)
{
// RD0
case 0B00000001:
// Mostra o endereo da varivel
end_display(1,1);
mostra("ENDERECO DA VAR:");
end_display(2,1);
printf(mostra,"%X
",&i32_Variavel);
break;
// RD1
case 0B00000010:
// Modifica o primeiro byte
*(&i32_Variavel) = 0;
// Notifica o que foi feito
end_display(1,1);
mostra("ZEROU O PRIMEIRO");
end_display(2,1);
mostra("BYTE DA VARIAVEL");
break;
103/111
// RD2
case 0B00000100:
// Modifica o terceiro byte
*(&i32_Variavel + 2) = 0;
// Notifica o que foi feito
end_display(1,1);
mostra("ZEROU O TERCEIRO");
end_display(2,1);
mostra("BYTE DA VARIAVEL");
break;
// RD3
case 0B00001000:
// Mostra o segundo byte da varivel
end_display(1,1);
mostra("SEGUNDO BYTE:
");
end_display(2,1);
printf(mostra,"%X
",*(&i32_Variavel+1));
break;
// RD4
case 0B00010000:
// Mostra o quarto byte da varivel
end_display(1,1);
mostra("QUARTO BYTE:
");
end_display(2,1);
printf(mostra,"%X
",*(&i32_Variavel+3));
break;
}
// Enquanto alguma tecla estiver pressionada
do {} while(PORTD != 0);
}
}
// ======================================================================
104/111
Captulo 18 Structs
Exemplo de Structs
/*
Programa que demonstra a utilizao de structs
*/
// Biblioteca CCS do PIC16F877A
#include<16f877A.h>
// Definio dos Registradores do PIC16F877A
#include<16F877A-sfrs.h>
// Definies de configuraes do PIC
#fuses HS,NOWDT,PUT,PROTECT,NOCPD,NOBROWNOUT,NOLVP
//
//
//
//
//
//
//
HS
NOWDT
PUT
PROTECT
NOCPD
NOBROWNOUT
NOLVP
->
->
->
->
->
->
->
struct
i8_Hora; // Hora
i8_Minuto; // Minuto
i8_Segundo; // Dados da mensagem cam
105/111
106/111
PORTC = 0B00000000;
PORTD = 0B00000000;
// Prescaler do TMR1 8, clock (FOSC/4), liga o timer
// Bit 07 - Unimplemented: Read as 0
// Bit 06 - Unimplemented: Read as 0
// Bit 05 - \ T1CKPS1:T1CKPS0: Timer1 Input Clock Prescale Select bits
// Bit 04 - /
// Bit 03 - T1OSCEN: Timer1 Oscillator Enable Control bit
// Bit 02 - T1SYNC: Timer1 Ext. Clock In. Synchronization Control bit
// Bit 01 - TMR1CS: Timer1 Clock Source Select bit
// Bit 00 - TMR1ON: Timer1 On bit
T1CON = 0B00110001;
// Clculo do Tempo de Interrupo do TMR1:
i16_TMR1 = (65536-((kTEMPO_INT_TMR1*kFOSC)/(4*kPRESCALER_TMR1)));
// Guarda os valores de carga do TMR1
i8_TMR1H = (int8)(i16_TMR1 >> 8);
i8_TMR1L = (int8)i16_TMR1;
// Carrega o TMR1
TMR1H = i8_TMR1H;
TMR1L = i8_TMR1L;
// Habilita interrupes, interrupes de perifricos
// Bit 07 - GIE: Global Interrupt Enable bit
// Bit 06 - PEIE: Peripheral Interrupt Enable bit
// Bit 05 - TMR0IE: TMR0 Overflow Interrupt Enable bit
// Bit 04 - INTE: RB0/INT External Interrupt Enable bit
// Bit 03 - RBIE: RB Port Change Interrupt Enable bit
// Bit 02 - TMR0IF: TMR0 Overflow Interrupt Flag bit
// Bit 01 - INTF: RB0/INT External Interrupt Flag bit
// Bit 00 - RBIF: RB Port Change Interrupt Flag bit
INTCON = 0B11000000;
// Habilita interrupo pelo TMR1
// Bit 07 - PSPIE: Parallel Slave Port Read/Write Int. Enable bit(1)
// Bit 06 - ADIE: A/D Converter Interrupt Enable bit
// Bit 05 - RCIE: USART Receive Interrupt Enable bit
// Bit 04 - TXIE: USART Transmit Interrupt Enable bit
// Bit 03 - SSPIE: Synchronous Serial Port Interrupt Enable bit
// Bit 02 - CCP1IE: CCP1 Interrupt Enable bit
// Bit 01 - TMR2IE: TMR2 to PR2 Match Interrupt Enable bit
// Bit 00 - TMR1IE: TMR1 Overflow Interrupt Enable bit
PIE1 = 0B00000001;
// "Acerta" o relgio
sHorario.sData.i8_Dia = 29;
sHorario.sData.i8_Mes = 8;
sHorario.sData.i16_Ano = 2009;
sHorario.sHora.i8_Hora = 8;
sHorario.sHora.i8_Minuto = 40;
sHorario.sHora.i8_Segundo = 10;
// Inicializa o display
inic_display();
107/111
// Lao principal
while(true)
{
// Se passou 1 segundo
if(i1_Passou1s)
{
// Tratou eventos de 1 segundo
i1_Passou1s = false;
// Chama a lgica do relgio
relogio(sHorario);
}
// Mostra o horario
mostra_horario(sHorario);
}
}
// ======================================================================
#separate
// Mostra o horrio no display
void mostra_horario(horario &sHorario)
{
// Dia, ms e ano
int8 i8_Dia,i8_Mes;
int16 i16_Ano;
// Pega dia, ms e ano da data
i8_Dia = sHorario.sData.i8_Dia;
i8_Mes = sHorario.sData.i8_Mes;
i16_Ano = sHorario.sData.i16_Ano;
// Mostra a data no display
end_display(1,1);
printf(mostra,"
%02u/%02u/%04lu
",i8_Dia,i8_Mes,i16_Ano);
108/111
}
}
// ======================================================================
#separate
// Lgica do relgio (deve ser chamada a cada 1 segundo)
void relogio(horario &sHorario)
{
// Usada para calcular o limite do dia
int8 i8_LimiteDia;
// Incrementa o segundo
sHorario.sHora.i8_Segundo++;
// Avalia o limite do segundo
if(sHorario.sHora.i8_Segundo >= 60)
{
// Reinicia a varivel do segundo
sHorario.sHora.i8_Segundo = 0;
// Incrementa a varivel de minuto
sHorario.sHora.i8_Minuto++;
// Avalia o limite de minuto
if(sHorario.sHora.i8_Minuto >= 60)
{
// Reinicia a varivel de minuto
sHorario.sHora.i8_Minuto = 0;
// Incrementa a varivel de hora
sHorario.sHora.i8_Hora++;
// Avalia o limite de hora
if(sHorario.sHora.i8_Hora >= 24)
{
// Reinicia a varivel de hora
sHorario.sHora.i8_Hora = 0;
// Incrementa a varivel de dia
sHorario.sData.i8_Dia++;
// Se o ms for fevereiro
if(sHorario.sData.i8_Mes == 2)
{
// Se o ano for bissexto
if((sHorario.sData.i16_Ano % 4) == 0)
{
// Limite do dia 29
i8_LimiteDia = 29;
}
// Seno
else
{
// Limite do dia 28
i8_LimiteDia = 28;
}
109/111
}
// Seno se o ms for de 30 dias
else if((sHorario.sData.i8_Mes ==
(sHorario.sData.i8_Mes ==
(sHorario.sData.i8_Mes ==
(sHorario.sData.i8_Mes ==
{
// Limite do dia 30
i8_LimiteDia = 30;
}
// Seno o ms de 31 dias
else
{
// Limite do dia 31
i8_LimiteDia = 31;
}
4) ||
6) ||
9) ||
11))
110/111
{
// Reinicia contador
i8_Contador500ms = 0;
// Pisca 500ms
i1_Pisca500ms = ~i1_Pisca500ms;
// Incrementa contador de 1s
i8_Contador1s++;
// Se passou 1s
if(i8_Contador1s >= 2)
{
// Reinicia contador
i8_Contador1s = 0;
// Indica que passou 1 segundo
i1_Passou1s = true;
}
}
}
// ======================================================================
111/111