Escolar Documentos
Profissional Documentos
Cultura Documentos
A evolução da tecnologia:
Os primeiros computadores:
Com domínio da manipulação da
tensão e da corrente elétrica, os dipositivos de
cálculo anteriormente mecânicos passaram a ser
elétricos, o que facilitava o projeto, a construção e
reduzia o tamanho dos sistemas, mesmo assim
os primeiros computadores eram gigantescos e
ocupavam prédios inteiros devido aos
componentes utilizados na época (vávulas). Um
bom exemplo era o ENIAC utilizado para
realização de cálculos balísticos na década de 40.
· Telefonia
· Atomóveis
· Aviação
· Diversão
· Eletrodomésticos
· Calculadoras
· Máquinas
· Informática
· Sistemas bancários
· Segurança
· Celulares
· Sist. Hospitalares
etc..
Microprocessadores e Microcontroladores:
Vimos até agora que microprocessadores e microcontroladores são o fruto de muitos anos de
avanço técnico, são utilizados para controlar diversos tipos de sistemas e máquinas, e que a grande
vantagem de seu uso é a possibilidade de alteração e atualização rápida e simples, bastando para isso a
criação de um novo programa.
Mas quais as diferenças entre microprocessadores e microcontroladores, em que casos eles são
utilizados?
Embora muitos confundam as duas nomenclaturas e as utilizem até como sinônimos, eles são
dispositivos com conceitos e funções distintas, pelos seguintes aspéctos:
Microprocessador:
Microcontrolador:
Os microcontroladores por sua vez têm como alvo o controle autônomo de sistemas, dessa forma
geramlente procura-se que eles sejam baratos e pequenos, para atingir esse objetivo, é inserido no mesmo
encapsulamento, além da CPU, diversos Periféricos Internos, isso reduz muito o espaço físico na PCI (placa
de circuito impresso), barateando o projeto e tornando atualizações e modificações um processo muito mais
simples e rápido; hoje dependendo da aplicação é possível se escolher o microcontrolador mais adequado
observando a lista de periféricos internos que ele possui.
Periféricos Internos: São sub-circuitos presentes na mesma pastilha de silício da CPU, hoje podemos
encontrar incorporado aos microcontroladores uma grande lista de periféricos internos:
Vamos pensar em uma tarefa bem simples e apresentar cada um dos passos que devem ser
executadas para a realização da mesma.
Materiais necessários:
três laranjas
faca
espremedor
coador
copo
colher
açúcar
Sequência de procedimentos:
Com esse simples exemplo foi possível verificar que mesmo as atividades mais simples passam por
várias etapas até sua conclusão, e quando estivermos criando nossos programas para os microcontroladores
deveremos pensar em todas as etapas da tarefa. Um bom modo para essa análise é a criação de um
fluxograma, mas isso discutiremos um pouco mais para frente.
Porém existe um detalhe importantíssimo que não levamos em consideração até agora: que idioma
ou linguagem usaremos para transmitir as informações da tarefa ao microcontrolador?
MNEMÔNICOS: Pequenas palavras, geralmente baseadas no idioma inglês, que representam cada uma da
instruções ou códigos da linguagem Assembly
Compilador: É um software que pode ser considerado como um tradutor, ele pega os mnemônicos da
linguagem e os transforma nos respectivos códigos de máquina (hexadecimal ou binário)
Após a compilação de nosso programa, o arquivo gerado (binário ou hexadecimal) é gravado dentro do
microcontrolador, e sendo assim o mesmo já pode começar a executar os comandos do programa passoa a
passo.
Curiosidade:
Editor e compilador (IDE): Software onde escreveremos o programa e irá traduzir os comandos da
linguagem (assembly, C, BASIC, PAscal, etc) para o código de máquinas (hexadecimal ou binário)
Software para simulação e teste da lógica do programa
Hardware de gravação do microcontrolador ou Kit de desenvolvimento
O Mercado de Microcontroladores
Existe uma grande disponibilidade de fabricantes de microcontroladores, onde cada um desenvolve seus
componentes com determinadas características. Entretando, caso venhamos compará-los, descobriremos
que sua estrutura básica interna de funcionamento são semelhantes. Quando projetamos determinado
circuito com microcontrolador, devemos selecionar o modelo de microcontrolador mais adequado, levando em
consideração, as facilidades de compra, obtenção continua deste chip e multiplicidade de fornecedores para
projetos industriais.
... etc.
Introdução a programação
1. 0 Kit PICgenios I
1.1 Controle de display LCD
1.2 Varredura de displays de 7 segmentos
1.3 Varredura de teclado matricial
1.4 Acionamento de leds
1.5 canal de comunicação serial RS232 e RS485
1.6 Conversores A/D
1.7 Canal PWM
Um pouco de História
A liguagem C foi criada por Dennis Ritchie e Ken Thompson no Laboratório Bell em 1972. C é uma linguagem profissional e é
aceita e utilizada na criação de sistemas operacionais, tais como Unix, Windows e Linux.
A linguagem de programação C tornou-se rapidamente uma das mais importantes e populares, principalmente por ser muito
poderosa, portátil e flexível. Essa flexibilidade tem seus incovenientes de permitir que se criem programas desorganizados e de
difícil compreensão. É uma linguagem de programação genérica desenvolvida para ser tão eficiente e rápido quanto o assembly
e tão estruturada e lógica quanto as linguagens de alto nível (PASCAL, JAVA, etc).
C foi desenhada para que usuários possa planejar programas mais estruturados e modulares. O resultado é um programa mais
legível e documentado. Os programas em C tendem a ser bastante compactos e de execução rápida.
A linguagem C habitualmente pe denominada general purpose, pois sua aplicação não se destina a uma área específica,
diferente de outras linguagem como COBOL, PASCAL, FORTRAN, entre outras, e esta é uma das grandes vantagens, pois
adapta-se ao desenvolvimento de qualquer projeto. A linguagem C é utilizada para construção de compiladores de outras
linguagens.
Vamos descrever algums pontos importantes com relação as características do C:
Rapidez - possui performance semelhante as obtidas pelo assembly, pois permite acesso a memória e manipulações de bits,
utilizando linguagem de alto nível.
Simples - possui sintaxe simples, e números de comandos reduzidos, facilitando o aprendizado da linguagem.
Portável - a linguagem C é padronizada (ANSI) no qual define padrões para os compiladores. Podemos transportar nossos
programas para outras plataformas e compila-los sem alteração no código.
Popular - internacionalmente conhecida e amplamente utilizada por programadores.
Modular - permite a separação do código em módulos distintos e independentes, podendo estes serem utilizados em varíos
programas.
Alto Nível - o C é considerado linguagem de alto nível, quando comparada com a linguage Assembly.
Bibliotecas Poderosas - possui diversas bibliotecas e permite a criação de novas pelo programador.
Evolução - o C deu origem a novas linguagens de programação, como por exemplo o C++.
Devido a sua qualidade, portabilidade, eficiência e controle , o C, podemos dizer, é a linguagem mais utilizada por
programadores de microcontroladores. Atualmente, a maioria dos microcontroladores existentes no mercado contam com
compiladores de linguagem C para o desenvolvimento de programas.
Quanto estamos tratando de programas para microcontroladores, devemos tomar certos cuidados com relação a escolha da
linguagem de programação e do compilador a ser utilizada , pois a capacidade de memória de armazenamento do programa é
extremamente reduzida, comparando com PC.
O papel do Compilador
A única maneira de se comunicar com o microcontrolador é através da linguagem de máquina, ou melhor dizendo, através de
códigos de máquinas. Por tanto os programas em C devem necessariamente serem interpretados e compilados a fim de termos
como resultado os comandos de máquinas a serem gravados na memória de programa do microcontrolador.
Existem no mercado diversos compiladores de programas em C para microcontroladores PIC, tais como: HI-TECH PICC, C18,
C30, CCS, SDCC, WIZ-C, mikroC, CC5, PICmicro C, entre outros.
Em nosso curso iremos utilizar a IDE MikroC desenvolvido pela empresa Mikroelektronika (www.mikroe.com), no qual permite
editar, compilar e simular programas em C para microcontroladores PIC da familia 12, 16 e 18.
Iremos utilizar o mikroc devido a sua eficiência e flexibilidade. Além disso, este compilador possui uma extensa biblioteca de
funções prontas para controle de diversas periféricos conectados ao nosso microcontrolador PIC.
Aos escrevermos e compilarmos um programa em nosso compilador, caso o programa não tenha erros de sintaxe, ou algum
outro erro cometido pelo programador, teremos como resultado a criação do arquivo de máquina hexadecimal (extensão .hex).
Este arquivo .hex é conhecido como código de máquina, e será este o arquivo a ser gravado na memória do microcontrolador.
Descreveremos abaixo as etapas passo a passo para editar, compilar, simular e gravar um programa no microcontrolador PIC.
Estudaremos com mais detalhes nas unidades seguintes do nosso curso os processos de edição,
compilação e gravação de programas.
Descreveremos agora algumas dos exemplos de programas e aplicações práticas que serão estudados em nosso curso:
Através deste Kit podemos desenvolver os mais variados tipos de programas, tais como:
Controle de displays LCD alfanumérico 16X2 (16 colunas por 2 linhas ) no modo 4 e 8 bits. Os displays LCD são
utilizados nas grandes maioria dos projetos eletrônicos hoje em dia.
4 displays de 7 segmentos acionados por varredura.
Matriz de teclado com 12 teclas.
7 teclas de acesso direto ao pino, sendo que 3 teclas dessas simulam a interrupções externa INT0, INT1 e INT2 do PIC.
16 leds para controle lógico visual.
2 relés NA/NF para acionamento de cargas externas de 10A / 220V.
RTC - relógio de tempo real com bateria. Através desse relógio o programador poderá programar temporizadores,
acionamentos programados, calendarios, entre outras aplicações.
Canal Serial RS232: canal para comunicação serial com PC ou outras máquinas
Canal Serial RS232 Emulada: o programador pode emular uma serial via software e então trabalhar com duas seriais
RS232 no seu projeto.
Canal USB 2.0 para implementações em projetos que necessitem comunicação USB (necessário usar PIC18F4550)
Canal PS/2: permite ligar ao microcontrolador teclado de PC ou mouse para otimizar o projeto eletrônico.
Aquecedor via PWM. O aluno poderá controlar o canal PWM do PIC simulando na placa.
Sensor de temperatura LM35: o aluno poderá realizar ensaios práticos com este sensor de temperatura.
Acionamento de Buzzer. Em alguns projetos é indispensável a utilização de um alarme sonoro.
Acesso a todas as portas de expansão do microcontrolador PIC, que nos permite ligar outros dispositivos externos ao Kit.
Ventoinha acionada por PWM. É importante pois o aluno poderá controlar por PWM a velocidade de giro da ventoinha.
Contadores de Pulsos. Através desse circuito poderemos saber a velocidade de giro da ventoinha. (contador RPM).
Memória serial E2PROM via I2C 24C04. Este tipo de memória são muito utilizada em diversos equipamento e máquinas.
2 trimpots para simulação e programação do canal A/D do PIC (Analógico 1 , e Analógico 2).
Canal de comunicação RS485: Protocolo muito utilizado em redes industriais e em PLC's.
Chave Load/Run para gravação ISP (gravação no próprio circuito).
Microcontrolador PIC18F452 DIP com 32Kbyte de Flash;
Canal de gravação ICSP: Conector para modo debugger e ICD2.
Regulador de tensão.
Chave Dip seletora de funções.
Suporte para displays LCD Gráficos 128 x 64 controlador KS107/108.
Suporte para displays LCD Gráficos 128 x 64 controlador T6963C.
Suporta os PIC18F4xxxx, PIC18F2XX0 e os PIC16F873/876 de 28 pinos.
Sei que você deve estar pensando, nossa quanto dispositivo conectado ao microcontrolador. É verdade, mas esses
microcontroladores podem realizar muitas outras funções... em outras palavras, esse PIC é 10!
Durante nosso treinamento iremos realizar diversas experiências práticas utilizando os recursos da linguagem C junto com
as funções da IDE mikroC.
Vamos detalhar um pouco cada experiência e conhecer um pouco mais sobre o que vamos estudar daqui por diante.
Veremos abaixo algumas das aplicações práticas que iremos realizar durante nosso treinamento:
Iremos no decorer das unidades programar o PIC para controlar e escrever mensagens publicitária nos display LCD 16X2
alfanumérico:
Os displays LCD são amplamente utilizados em diversos equipamentos e aparelhos. No decorrer dos estudos iremos explorar
as funções do mikroC em linguagem C para controle de displays LCD. Estudaremos passo a passo como escrever mensagens
de textos nos modos 4 e 8 bits.
Equipamentos domésticos
Equipamentos industriais Equipamentos de
Informática CLPs e controladores Equipamentos portáteis
industriais
Os diplays de 7 segmentos são largamente utilizados em equipamentos como: balança, painéis de máquinas industriais,
equipamentos médicos, eletrodomésticos entre outros. Podemos controlar os displays de 7 segmentos através de conversores
BCD, como por exemplo o 74HC247 (decodificador BCD) ou desenvolver códigos BCD pelo microcontrolar. Em nosso caso, os
displays estão sendo acionados por varredura.
Para acionar os displays de 7 segmentos, iremos utilizar o sistema de varredura, que permite através de um barramento de
dados de 8 bits e mais 4 pinos de acionamento, "escrever" o valor correspondente ao dado que deve ser mostrado no visor.
O sistema de varredura de teclado matricial permite que o microcontrolador leia muitas teclas ligada ao seus pinos. O teclado
matricial é muito utilizado para economizar pinos físicos do microcontrolador. Equipamentos de diversos tipos usam o teclado
matricial para inserir dados ao microcontrolador.
Aplicações reais com teclados matriciais:
Acionamento de Leds
Os leds são utilizados praticamente em quase todas as aplicações eletrônicas. Através dos leds podemos visualizar o status de
uma máquina, "desenhar" mensagens de textos, iluminar objetos, criar animações visuais, entre outras aplicações.
Iremos estudar os recursos de programação em C para controle das portas de saída disponíveis no microcontroladores PIC
utilizando os leds como barramento de dados visual.
Os leds são utilizados em diversos equipamento no mercado para as mais variadas aplicações. Muitas das aplicações é o
microcontrolador responsável pelo controle desses leds.
É de grande importância que os equipamentos eletrônicos tenham um canal de comunicação com o meio externo. Através de
um canal de comunicação é possível monitorar o estado do equipamento assim como enviar e receber informações em tempo
real. Iremos aprender a utilizar o canal de comunicação serial do microcontrolador PIC realizando comunicações de envio e
recepção de dados com o PC.
Aplicações reais com Comunicação Serial RS232 e RS485
Supervisórios Industriais
Comunicação com computadores PC
Comunicação com outras máquinas
A aplicação básica do microcontrolador PIC trabalhando com o conversor A/D abaixo é simples, mas possui um grande
conteúdo educativo para nós neste momento. No exemplo abaixo utilizamos dois simples trimpots para variarmos o valor de
tensão no pino A/D do PIC. Este exemplo na verdade representa inumeras aplicações práticas de equipamentos do mercado,
tais como: aparelhos de medição, leitores de sensores de temperatura, atuadores, entre outros. Criaremos programas para
controle e leitores de tensão nas unidades seguintes.
Veremos também como ler e interpretar valores analógicos vindo de sensores de temperatua (LM35) utilizando os recurso da
linguagem C.
Aplicações reais com os conversores A/D do PIC
Iremos simular programas de controle de largura de pulsos. Através do canal PWM disponível no PIC,
podemos controlar diversos equipamentos, tais como: inversores de frequência, estabilizadores, fonte
chaveada, controle de velocidade de motores DC, entre outras.
Nem nossos laboratório, iremos controlar a velocidade de giro de uma ventoinha e controlar o
aquecimento de uma caraga resistiva via PWM.
Informações importantes
Outros exemplos de programas também serão tratados e comentados em nosso curso, mas ficarão como
sendo material complementar ao aluno.
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2008. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem
prévio aviso. Maiores informações: suporte@microgenios.com.br
As características gerais da família PIC
1.0 A família PIC
1.1 Desempenho da família PIC
1.2 Tipo de memórias de programa
A família PIC
O PIC possui uma arquitetura interna do tipo Havard. A diferença entre essa
arquitetura e as tradicionais, do tipo Von-Neumann, é que ela possui um
barramento para o programa e outro para os dados, diferente da arquitetura
tradicional em que um barramento é tanto de dados como de endereço.
Memória do PIC18F452
1.0 Tipos de Memórias
1.1 Memória de Programa
1.2 Memória de dados - EEPROM
1.3 Memória de dados - RAM
Osciladores
1.0 O clock
1.1 Osciladores: Cristal e Ressonador
1.2 Cristal de Oscilação RC
1.3 Modo HSPLL
1.4 Ciclos de Máquina
1.5 Reset
Bits configurations
1.0 Os bits de configuração
1.1 FOSC (frequêncy Oscilator)
1.2 OSCSEN (SYSTEM CLOCK SWITCH BIT)
1.3 PWRTEN (SYSTEM CLOCK SWITCH BIT)
1.4 BROWN-Out
1.5 BOREN
1.7 WDTEN - Watchdog Timer Enable (cão de guarda)
1.8 Watchdog Postscale Select Bit
1.9 CCP2MX
2.0 BKBUG (debug)
2.1 LVP (Low Voltagem Programming)
2.2 STVREN (Stack Full/Underflow Reset Enable Bit)
O PIC18F452
O PIC18F452 é um microcontrolador que possui memória do tipo FLASH, que nos representa uma grande facilidade em
desenvolvimentos de projetos e protótipos pois não requer apagá-lo através de luz-ultravioleta como as versões antigas que utilizavam
EEPROM.
O PIC18F452 é um microcontrolador com tecnologia CMOS (baixíssimo consumo) fabricado pela empresa Microchip Technology.
· microcontrolador de 40 pinos;
· memória de programa FLASH de 32K ( 16384 bytes words)
· memória de dados RAM de 1536 bytes;
· memória EEPROM de 256 byte;
· Processamento de até 10MIPS (milhões de instruções por sergundo)
· quatro temporizadores internos (um de 8 bits e 3 de 16 bits) (TIMER0, TIMER1, TIMER2, TIMER3)
· 2 canais capture/compare/PWM - módulo CCP
· Master synchronous Serial Port (MSSP) module.
· Unhaced Usart
· 8 canais A/D de 10 bits;
· Detector de baixa voltagem programável
· Permite até 100 000 ciclos de escrita e leitura na memória de programa Flash
· permite 1 000 000 ciclos de leitura e escrita na E2PROM
· Retenção de dados na Flash de 40 anos
· Watchdog timer com oscilador próprio e programável
· três pinos de interrrupção externa. INT0, INT1, INT2
Tipos de encapsulamentos:
As primeiras versões do PIC eram baseadas em encapsulamentos do tipo DIP40, hoje os dipositivos de 40 pinos ainda são muito comuns, porém de acordo com
a aplicação e os periféricos internos presentes no Chip eles podem ser encontrados em diversos encapsulamentos como:
DIP → Dual In-line Pin
PLCC → Leadless Chip Carrier.
TQFP
Nosso estudo será baseado em microcontroladores com o encapsulamento DIP (Dual In-line Pin), devido a facilidade de utilização e disponibilidade no mercado,
porém não há grandes dificuldades para se migrar para outros encapsulamentos, basta analisar um pouco o datasheet do microcontrolador.
O PIC18F452 possui no total de 33 pinos de I/O divididos entre as PORTA, PORTB, PORTC, PORTD e PORTE.
PORTA: encontramos 7 pinos físicos intitulados de RA0 a RA6 que podem ser utilizados como I/O de uso geral ou como conversor analógico/ digital A/D, (com
excessão de RA4), além de possuir também a função de detecção de baixa tensão (LVD), referência analógica do A/D e contador externo.
PORTB: encontramos 8 pinos intitulado de RB0 a RB7 configuráveis como I/O de uso geral. Nesse PORT podemos trabalhar com três interrupções externas,
módulo CCP e pinos de gravação e debugger.
PORTC: encontramos 8 pinos intitulados de RC0 a RC7 configuráveis como I/O de uso geral, saída do oscilador do timer, módulo CCP, Clock e data para os
modos SPI, I2C e UART.
PORTD: encontramos 8 pinos intitulado de RC0 a RC7 que pode ser configurado como I/O de uso geral ou ser configurado como PSP para ter saída TTL (por
exemplo: interfaciamento com microprocessadores ).
PORTE: podemos utilizá-lo como PORT de I/O de uso geral ou utilizar os pinos de WR e CS para acesso ao modo paralelo Slave Port (acesso a memória
externa por exemplo).
Pino
Função Tipo Descrição
(DIP)
1 /MCLR/VPP entrada - entrada Entrada do RESET externo. Pino de habilitação de alta voltagem ICSP
13 OSC1 /CLK1 entrada entrada do cristal oscilador / entrada do clock externo
14 OSC2 / CLK1/ RA6 saída - saída - I/O saída do cristal oscilador / entrada do clock exteno / entrada e saída de uso geral
2 RA0 / AN0 I/O - entrada entrada e saída de uso geral / entrada do conversor AD0
3 RA1 / AN1 I/O - entrada entrada e saída de uso geral / entrada do conversor AD1
entrada e saída de uso geral/ entrada do conversor AD2 / entrada de referência baixa
4 RA2 / AN2 /Vref- I/O - entrada - entrada
do A/D
entrada e saída de uso geral / entrada do conversor AD3 / entrada de referência Alta
5 RA3 / AN3 / Vref+ I/O - entrada - entrada
do A/D
6 RA4 / T0CKI I/O - entrada - entrada entrada e saída de uso geral / entrada de clock timer0
I/O - entrada - entrada - entrada e saída de uso geral / entrada do conversor AD4 / entrada de seleção SPI,
7 RA5/AN4/SS/LVDIN
entrada detector de baixa voltagem.
33 RB0 / INT0 I/O - entrada entrada e saída de uso geral / interrupção externa 0
34 RB1 / INT1 I/O - entrada entrada e saída de uso geral / interrupção externa 1
35 RB2 / INT2 I/O - entrada entrada e saída de uso geral / interrupção externa 2
36 RB3 / CCP2** I/O - I/O entrada e saída de uso geral / módulo CCP2 (multiplexado com RB3 )
37 RB4 I/O entrada e saída de uso geral / pino de interrupção por mudança de nível
entrada e saída de uso geral (interrupção por mudança de estado) / pino de habilitação
38 RB5/PGM I/O - I/O
ICSP baixa voltagem
entrada e saída de uso geral (interrupção por mudança de estado) / pino ICSP In-
39 RB6 / PGC I/O - I/O
Circuit Debugger
entrada e saída de uso geral (interrupção por mudança de estado) / pino ICSP In-
40 RB7 / PGD I/O - I/O
Circuit Debugger
15 RC0/T10S0/T1CKI I/O - saída - entrada entrada e saída de uso geral / saída do 2º oscilador /Contador externo Timer 1
RC1 / T10SI / entrada e saída de uso geral / entrada 2º oscilador / módulo CCP2 (multiplexado com
16 I/O - entrada -saída
CCP2** RB3 )
17 RC2/CCP1 I/O - I/O entrada e saída de uso geral / módulo CCP1
entrada e saída de uso geral / entrada e saída do clock serial para o modo SPI /
18 RC3/SCK/SCL I/O - I/O - I/O
entrada e saída do clock serial para o modo I2C
23 RC4/SDI/SDA I/O - entrada - I/O entrada e saída de uso geral / entrada de dados SPI / entrada e saída de dados I2C
24 RC5/SD0 I/O - saída entrada e saída de uso geral / saída de dados SPI
entrada e saída de uso geral / canal de transmissão UART / clock de sincronismo
25 RC6/TX/CK I/O - saída - I/O
UART
26 RC7/RX/DT I/O - entrada - I/O entrada e saída de uso geral / canal de recepção UART / clock de sincronismo UART
19 RD0/PSP0 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
20 RD1/PSP1 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
21 RD2/PSP2 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
22 RD3/PSP3 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
27 RD4/PSP4 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
28 RD5/PSP5 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
29 RD6/PSP6 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
30 RD7/PSP7 I/O - I/O entrada e saída de uso geral / porta de comunicação paralela
entrada e saída de uso geral / controle de leitura do port paralelo / entrada analógica
8 RE0/RD/AN5 I/O
AD5
entrada e saída de uso geral / controle de escrita do port paralelo / entrada analógica
9 RE1/WR/AN6 I/O
AD6
entrada e saída de uso geral / controle de seleção do port paralelo / entrada analógica
10 RE2/CS/AN7 I/O
AD7
12 ,
GND alimentação negativo
31
11, 32 VCC alimentação positivo
Tipos de Memórias
No PIC18F452 encontramos três tipos de memórias:
Como nós sabemos, memória de programa (ROM, EPROM, FLASH) é do tipo não volátil, ou seja, podemos desenergizar nosso sistema microcontrolado e ele
não perderá o programa gravado.
Nosso microcontrolador estudado possui internamente 32Kbyte de memória de programa e possui um barramento de programa de 16 bits. Além disso, existem 21
bits para endereçamento da memória de programa, o que permite que até 2 Mbyte sejam endereçados pelo microcontrolador da familia PIC18F.
Memória de Programa
A memória de programa utilizada em nosso microcontrolador é do tipo FLASH (sufixo "F") que permite ser gravada/apagada no minimo 1000 vezes. Este tipo de
memória utilizada é ideal para ser utilizada em desenvolvimento de projetos e até mesmo em produtos finais.
Memória de Programa FLASH do PIC18F442
Podemos perceber que a memória de programa do PIC18F452 inicia-se no endereço 0000h e atinge o valor máximo de 7FFFH, ou seja , 32767K byte
(32Kbyte).
Nota:
Não podemos confundir de forma alguma memória de programa e memória de dados. Sabemos que memória de programa é
onde nosso programa estará gravado, enquanto memória de dados é onde os valores de nossas variáveis serão salvas
temporariamente.
O endereço inicial 0000h é chamado de vetor de reset. A instrução de programa que estiver nesse endereço de memória será a primeira a ser
executada pelo processador do PIC. Sempre que energizarmos ou resetarmos o microcontrolador, o contador de programa PC apontará sempre para este
primeiro endereço da memória.
Em seguida temos os endereços 0008h e 0018h. Estes endereços são chamados de vetores de interrupção. (veremos mais adiante em nosso curso
sobre esses vetores de interrupção).
Em seguida temos os endereços 0008h e 0018h. Estes endereços são chamados de vetores de interrupção. (veremos mais adiante em nosso curso sobre esses
vetores de interrupção).
/Este programa tem por função alterar o estado dos 8 pinos do PORTB do PIC em intervalos de 1 segundo.
void main() {
TRISB = 0; // configura o portB como saída
PORTB = 0x00; // coloca zero em todos os pinos do portB
do {
PORTB = 0xFF; // coloca um em todos os pinos do portB
Delay_ms(1000); // delay de 1 segundo (1000 ms)
PORTB = 0x00; // Coloca zero em todos os pinos do portB
Delay_ms(1000); // delay de 1 segundo
} while(1);
Ao compilarmos o programa acima com o mikroC teremos como resultado o seguinte código de máquina (descrito somente algumas linhas do código gerado;
A partir da imagem acima, podemos verificar os valores que serão gravados na memória de programa após gravação do programa exemplo acima. Esses valores
são úteis para o programador experiente, pois permite visualizar e acompanhar a execução por completo da compilação dos arquivos.
Nota: Os códigos em assembly visualizado na figura acima foi gerado pelo compilador mikroC após a compilação de um
programa escrito em C.
A memória de dados RAM é dividida em dois grupos: os chamados GPR (Registradores de Propósito Geral) e os SFR ( Registradores de Funções Especiais).
Os GFR tem a função de armazenar dados de uso geral que utilizamos e criamos durante a execução do nosso programa. Podemos guardar nesse região da
memória RAM dados voláteis de variáveis, tabelas, constantes, entre outras.
Os SFR's é a parte principal do microcontrolador, é nesta área da memória RAM que estão armazenados todo o setup de funcionamento do PIC. Apartir desses
registradores podemos configurar o modo de trabalho dos timers/counters, USART, conversores analógicos digitais, etc.
O PIC18F452 em estudo possui internamente 1536 bytes de memória de dados RAM.
O banco de memória RAM da família 18F é dividido em 16 bancos que contém 256 bytes de memória. Os 6 primeiros bancos são a região dos GPR's, e o último
banco são dos SFR's. Acompanhe a figura abaixo:
Os SFR´s são registradores de funções especiais responsáveis pela configuração dos modos de trabalhos do PIC. Através da
configuração desses registradores especiais, podemos também monitorar o status do microcontrolador em determinados momentos e
situações. Estudaremos a função desses registradores quando estivermos trabalhando com projetos, pois dessa maneira ficará mais
claro seu funcionamento e aplicações.
O Clock
Todo microcontrolador requer um circuito de oscilação pois é quem dá o sinal de "partida" e "sincronismo" para qualquer atividade interna da chip. A freqüência de
operação de oscilação é um dos agentes que determinam a velocidade de execução das instruções do microcontrolador.
1. LP low-power cristal
2. XT cristal ou ressonador
3. HS High-Speed cristal (cristal de alta velocidade) ou ressonador
4. HS + PLL High-Speed cristal ou ressonador com PLL habilitada
5. RC Resistor / Capacitor externo
6. RCIO Resistor / Capacitor externo com pino de I/O
7. EC Clock externo
8. ECIO Clock exteno com pino de I/O
Nota: Quando projetamos um dispositivo, a regra é colocar o oscilador tão perto quanto possível do microcontrolador, de modo a evitar
qualquer interferência nas linhas que ligam o oscilador ao microcontrolador.
Note que existe dois capacitores ligados em paralelo com o cristal. O valor desses capacitores variam de acordo com a frêquencia do
cristal utilizado. Abaixo segue uma tabela apresentando os valores dos capacitores:
Ressonador cerâmico
cristal de quartzo
Os ressonadores cerâmicos são comercializados em dois tipos: com dois terminais e com três terminais. Os mais utilizados são os ressonadores com três
terminais pois não precisam de capacitores externos. O ressonador com dois terminais obedecem a ligação da figura 01, enquanto no de três o pino central deve
ser aterrado. segue abaixo o esquema de ligação do ressonador com três terminais:
Os ressonadores cerâmicos é uma segunda opção. Não é tão barato quanto um RC mas é bem mais estável e preciso.
Nota: Antes de gravarmos um programa no microcontrolador PIC devemos "queimar" os fusivel de configuração informando qual o tipo
de oscilador estamos utilizando em nosso hardware.
Nos projetos do nosso curso iremos utilizar cristal de quartzo de 4MHz pois garantimos maior precisão nas rotinas de tempo nas execuções das instruções.
Circuito de Oscilação RC
Este é o tipo de oscilador mais simples que existe e também o mais barato, mas, por outro lado, é o menos preciso, variando muito a tensão de trabalho,
temperatura e tolerâncias. O circuito RC deve ser ligado conforme a figura abaixo:
Modo HSPLL
HSPLL é na verdade um modo em que podemos multiplicar o valor da freqüência de entrada do cristal oscilador por 4. É ideal para ambientes em que o
dispositivo não pode gerar EMI (interferência Eletromagnética). Este modo deve ser habilitado nos "fusíveis de configurações" no momento em que formos gravar
o chip.
Por exemplo:
Caso venhamos conectar ao PIC um cristal de 10 MHz entre os pinos OSC1 e OSC2 e ativarmos o modo HSPLL no momento em que gravarmos o chip, o PIC
passa a operar a 40 MHz, executando as instruções internas em 10MHz (10 MIPS - milhões de instruções por segundo), pois a frequência real de operação do
seu microcontrolador é: Fosc / 4.
Para representar os bits de configuração de nosso microcontrolador, iremos utilizar um software gratuito de gravação de microcontroladores PIC disponível na
internet, chamado WinPIC800. (www.winpic800.com).
Nota: No programa Winpic800 podemos definir o tipo de oscilador utilizado no PIC através do seguinte setup:
Internamente no microcontrolador, encontramos 8 registradores de 16bits, divididos em duas partes: Byte alto e Byte Baixo, e são
responsáveis pela configuração geral do PIC. Esta região de memória não é acessivel durante a execução do programa, mas somente
podemos configura-lá no momento da gravação do chip.
Apresentamos a seguir uma tabela com a descrição de todos os bits de configuração do PIC18F452:
No WinPIC800, programa de gravação de microcontroladores PIC utilizado no kit PICGenios da Microgenios, podemos visualizar e
configurar os bits de configuração antes de gravarmos o programa no PIC.
A melhor maneira de configurar os bits de configuração é no momento de criação do programa no compilador, pois uma vez
configurado esses bits, não precisaremos reconfigura-los a cada compilação de nos programa.
Através dessa opção podemos configurar o tipo de clock com o qual o microcontrolador irá operar. As fontes de clock que podem ser
selecionadas são:
Oscilador externo RC, com RA6 configurado como pino de saida de clock;
Oscilador do tipo EC, utilizando o pino RA6 como saida de clock (Fosc/4);
Através desse bit de configuração, podemos selecionar o modo de acionamento do oscilador do PIC. Caso venhamos a selecionar este
bit, a frequência de oscilação passa a ser gerada internamente pelo TIMER1, caso contrário, o oscilador selecionado é FOSC.
Obs: Caso desejemos utilizar o oscilador interno do PIC, devemos selecionar este bit de configuração e configurar o TIMER1 para
trabalhar como oscilador para o clock (basta habilitar o T1OSCSEN do TIMER1), caso não venhamos a programar o TIMER1
corretamente, automaticamente o bit de configuração do OSCSEN será desabilitado.
A través desse bit, podemos configurar o modo POWER para o acionamento do PIC, quando este bit estiver acionado o modo POWER-UP TIMER estará
habilitado. O temporizadore de power-up pode seu utilizado para fazer com que o chip permaneça em reset por aproximadamente 72ms após o chip ter sido
ligado. E deve ser utilizado para garantir a estabilização da fonte de energia no projeto.
BROWN-OUT voltage
O detector de brown-out é utilizado para provocar o reset da CPU no caso de a tensão de alimentação cair abaixo de um determinado
limite. Uma vez que a tensão retorne ao seu valor nominal, o circuito de reset é liberado e o programa é reiniciado.
No PIC18F452 podemos selecionar 4 tipos de tensões para o BROWN-OUT: 2.0V, 2.7V, 4.2V ou 4.5V.
BROWN-OUT detect
Podemos habilitar ou desabilitar o detector de brown-out, basta selecionar o bit de configuração caso desejemos habilitar o brown-out.
WDTEN - Watchdog Timer Enable (cão de guarda)
O watchdog timer ou cão de guarda é um sistema interno ao microcontrolador que evita que o programa pare em um determinado
ponto. Imagine que você desenvolveu uma aplicação e que por um erro de software em certo momento o seu programa pára (entra em
loop infinito). Caso o watchdog dog não seja resetado em tempos em tempos ele irá "estourar", ou seja, chegará ao final da sua
contagem fazendo com que o microcontrolador resete e reinicie todo o processo.
Para habilitar o Watchdog marque o bit WDTEN. (basta deixar em ON).
Watchdog Postscale Select Bit
O tempo minimo para estouro do watchdog é de 18 ms, porém podemos estender esse tempo através do postscale. Com essa função
podemos multiplicar o tempo mínimo de 18 ms com os seguintes multiplicadores do prescaler: 1:1; 1:2, 1:4, 1:8, 1:16, 1:32, 1:64, 1:128.
CCP2 MX
Podemos através desse bit definir se queremos multiplexar o módulo CCP2 com o pino RC1 (CCP2MX = 0) com o pino RB3 (CCP2MX
= 1)
BKBUG (debug)
Através desse bit , podemos habilitar o modo DEBUGGER no PIC. Nesse modo é possivel emular um programa no próprio projeto
eletrônico. Emular consiste no processo de junto com o computador, testar passo a passo o funcionamento do programa que está
rodando no microcontrolador. Se esta opção estiver ativa, os pinos de gravação RB6 e RB7 deixam de funcionar como I/O's; caso
contrário, o funcionamento desses pinos fica normal. Faz necessários a utilização de equipamentos de debugação fornecidos pela
Microchip, ou outras empresas para realizar esta operação.
LVP (Low Voltagem Programming)
Quando o PIC é gravado, é acionado uma tensão de 12Vcc no pino MCLR. Se a opção LVP estiver ativa, para gravar o PIC basta ter
nivel lógico 1 no pino RA5. Esta opção é ideal para aplicações em campo onde é dificil encontrar tensões de 12V disponível em
determinados equipamentos.
O PIC18F452 possui internamente 31 endereços de pilha. Quando habilitamos esse bit STVREN, toda vez que ultrapassarmos o limete
da pilha (ocorrer overflow) o microcontrolador será resetado.
Caso este bit esteja habilitado, protege contra leitura a memória de programa de 0x0200 a 0x1FFF.
Caso este bit esteja habilitado, protege contra leitura a memória de programa de 0x2000 a 0x3FFF.
Caso este bit esteja habilitado, protege contra leitura a memória de programa de 0x4000 a 0x5FFF.
Caso este bit esteja habilitado, protege contra leitura a memória de programa de 0x6000 a 0x7FFF.
Caso este bit esteja habilitado, protege contra leitura os 256 bytes da memória EEPROM (memória não volátil).
Caso este bit esteja habilitado, protege contra leitura a região de memória Boot (área da memória de programa) 0x0000 até 0x0FF0.
Caso este bit esteja habilitado, protege a memória de programa contra escrtita por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra escrtita por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra escrtita por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra escrtita por tabela no endereço especificado.
Caso este bit esteja habilitado, protege contra escrita os 256 bytes da memória EEPROM (memória não volátil).
Caso este bit esteja habilitado, protege contra escrtita por tabela a área de boot.
Config Write Protect
Caso este bit esteja habilitado, protege contra escrita a área de configuração do microcontrolador.
Caso este bit esteja habilitado, protege a memória de programa contra leitura por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra leitura por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra leitura por tabela no endereço especificado.
Caso este bit esteja habilitado, protege a memória de programa contra leitura por tabela no endereço especificado.
Ciclos de máquina
A contagem de tempo não é medida diretamente pela freqüência de oscilação do cristal e sim através do que chamamos de CICLO DE MÁQUINA.
Internamente no microcontroladores PIC a freqüência do cristal é dividida por 4, o que nos resulta que a freqüência real de trabalho é:
Para exemplificar vamos supor que temos conectado ao microcontrolador um cristal de quartzo de 8MHz. Qual é a freqüência real de execução das instruções do nosso
microcontrolador?
Sabemos que a freqüência do cristal utilizado é de 4 MHz, e que cada instrução leva exatamente 1 ciclo de máquina para ser executada; Basta dividir o valor do
cristal por 4 para sabermos o valor real de trabalho do PIC.
Concluimos então que nosso microcontrolador PIC com cristal de 8MHz esta trabalhando efetivamente a 2MHz, ou seja , cada instrução de programa leva 0,5 us
para ser executada.
Nota: Temos que lembrar que nosso microcontrolador em estudo pode operar com cristal oscilador de até 40MHz, disso nos resulta em 10MHz a
freqüência máxima de trabalho permitida por esse chip.
Reset
Sempre que ligamos ou energizamos nosso circuito microcontrolado é interessante que o PIC seja resetado, para isso é necessária a inserção de um circuito
eletrônico bem simples, mas capaz de realizar esse procedimento que costumamos chamar de POWER ON RESET.
Além disso é interessante que exista um botão para que o usuário possa reiniciar o sistema sempre que for necessário (reset manual), a seguir indicamos um
exemplo de circuito para o reset.
figura 01
Os PORTB, PORTC e PORTD possuem 8 pinos de I/O cada, enquanto o PORTE possue 3 pinos de I/O e
PORTA 6 pinos de I/O.
Cada porta de I/O possui dois registradores que controlam suas funções: um registrador PORT e um
registrador TRIS.
Os registradores PORT (PORTA, PORTB, PORTC, PORTD, PORTE) que são posições na RAM que
contêm os dados das portas paralelas (I/O's) do microcontrolador. Qualquer escrita realizada em um
desses registros automaticamente altera todo o conteúdo presente na saída do chip.
O registrador TRIS é utilizado para configurar cada pino da respectiva porta como entrada ou saída.
Assim, cada bit do registrador corresponde a um pino da porta. Se o bit estiver em 1 (um), o pino
correspondente esta configurado como entrada de dados, e se estiver em 0 (zero) configuramos este
pino como saída de dados.
As portas de comunicação paralela do PIC são utilizadas para efetuar diversas tarefas:
PORTA
A primeira porta a ser estudada é a PORTA. Além das funções de entrada e saída de dados encontramos
também diversas outras funções multiplexadas aos pinos da PORTA:
Registrador PORTA
Figura 02
O resistrador PORTA esta localizado na memória RAM do PIC e possui o endereço (0XF80). Este registrador
irá acessar os pinos da PORTA da seguinte maneira:
Toda a porta de I/O possui internamente um latch de saída para cada pino. Dessa forma, uma escrita no
registrador PORTA irá na realidade escrever em cada latch do PORTA.
Nota: O registrador PORTA é o "espelho" dos pinos da PORTA do PIC, para lermos ou
escrevermos nesse registrador estamos na verdade atuando sobre os pinos do port
respectivamente. Não podemos esquecer que o registrador TRISA também afeta a
leitura e escrita no port.
Além de operar como I/O de uso geral, o PORTA, pode ser configurado como entrada analógica. Para
isso, faz necessário que o programador venha a programar os pinos do PORTA como entrada
analógica, através do registrador ADCON1.
Nota: após o reset do seu microcontrolador, os pinos do PORTA e PORTE vem configurados como A/D
(entrada analógica), caso queiramos acionar por exemplo um relê com um pino deste PORT,
precisamos configurar adequamente este pino como I/O através do registrador ADCON1.
Conhecendo o registrador ADCON1:
X pode ser 0 ou 1
Figura 03
O registrador ADCON1 é responsável por determinar quais os pinos do PORTA e PORTE (com excessão
de RA4) serão entrada analógica ou digital. Repare que na tabela (figura 03) para configurarmos todos os
pinos do PORTA como entrada digital, ou seja, como I/O de uso geral, basta carregar o valor ADCON1 =
0B00000111; ou ADCON1 = 0B00000110;
Exemplo de programa:
void main() {
adcon1 = 0b00000111; // configura pinos do PORTA e PORTE como I/O digital
trisa.f0 = 0; //configura pino RA0 como saida
porta.F0 = 1; // envia nivél lógico 1 no pino RA0
}
Podemos definir determinadas tensões externas de referência para nosso conversor analógico / digital,
através dos pinos RA2 (AN2) e RA3 (AN3). Podemos também programar nossa referência de tensão do
conversor A/D como sendo VSS e VDD, ou seja, a própria tensão de alimentação do chip. Neste caso, os
pinos RA2 e RA3 poderão ser utilizados como entrada analógica, ou como I/O de uso geral.
Registrador TRISA
O registrador TRISA é utilizado para o controle da direção de atuação de cada pino de I/O do PORTA.
Através desse registradores definimos e configuramos o modo de trabalho do pino do
microcontrolador como entrada ou saída de dados.
Se o bit do registrador TRISA estiver em nível lógico 1, o pino correspondente a este bit do PORTA estará
configurado como entrada.
Se o bit do registrador TRISA estiver em nível lógico 0, o pino correspondente a este bit do PORTA estará
configurado como saída.
void main() {
trisa = 0b00000000; //configura todos os pinos do PORTA como saida
trisb = 0b00001111; //configura somente os pinos de RB7 a RB4 do PORTB como saida
trisa.f0 = 0; //configura pino RA0 como saida
trise.f2 = 1; //configura pino RE2 como entrada de dados
trisc.f1 = 1; //configura pino RC1 como entrada de dados
}
Exemplo:
Com base no circuito eletrônico abaixo, vamos configurar os registradores de direção de pinos:
void main() {
adcon1 = 0b00000110; //configura pinos do PORTA e PORTE como I/O digital
trisa.f0 = 0; //configura RA0 do PORTA como saida
trisa.f2 = 0; //configura RA2 do PORTA como saida
trisa.f4 = 0; //configura RA4 do PORTA como saida
porta = 0b00010101; //ascende somente todos os leds.
No circuito acima, os pinos RA0, RA2, RA4 dO PORTA são responsáveis pelo acionamento dos leds.
Devemos configurar o PORTA como saída, pois nosso objetivo é "escrever" no port, ou seja, enviar "0"
ou "1" lógico nos pinos do PORTA correspondente.
Os pinos RB0, RB3 e RB7 do PORTB tem a função de "ler" os estados das teclas, quando as teclas
estão soltas temos nível lógico 1 nos pinos, quando a tecla é pressionada, o estado do pino é alterado
para nível 0. Devemos configurar o PORTB como entrada, pois iremos "ler" o estados dos pinos, ou
seja, o estados das teclas.
Seguindo o mesmo raciocínio lógico, vamos programar o PIC abaixo de forma que todos os leds pisquem a
cada segundo.
void main(){
trisd = 0; //configura todos os pinos do PORTC como saida
portd = 0; //inicia programa com portd em zero
while(1){ //laço de repetição
portd = 0; //apaga todos os leds
delay_ms(1000); //delay de 1 segundo
portd = 0b11111111; //envia nível lógico 1 em todos os pinos do PORTD
delay_ms(1000); //delay de 1 segundo
}
}
Exercício:
Com base na tabela (figura 03), programa os pinos RA0, RA1 e RA3 como entrada analógica, as demais
entradas analógicas deverão ser programadas como I/O digital.
void main(){
adcon1 = 0b00000100; //configura pinos RA0, RA1, RA3 do PORTA entrada analógica
}
Para ler o LATCH de saída do microcontrolador ao invés do pino utilizamos o registrador LATA,
referente ao PORTA, ou LATB, referente ao PORTB. O latch de saída encontra-se antes do buffer de
saída do pino, e por esse motivo podemos ler seu estado.
PORTB
O PORTB, tal qual o PORTA, implementa diversas outras funções multiplexadas aos seus pinos, acompanhe:
PORTC
O PORTC, tal qual o PORTA, implementa diversas outras funções multiplexadas aos seus pinos, acompanhe:
PORTD
O PORTD, tal qual o PORTA, PORTB e PORTC implementa diversas outras funções multiplexadas aos seus
pinos, acompanhe:
Assim como nas outras portas, o PORTD possui dois registradores que definem o modo de
trabalho dos seus pinos de I/O: são eles: PORTD e TRISD.
Tanto o registrador PORTD quanto o registrador TRISD estão localizados na memória RAM
do PIC e pertencem aos SFR'S (Registradores de Funções Especiais).
O registrador TRISD tem a função de programar os pinos do PIC para serem entradas ou
saídas.
O registrador PORTD é o "espelho" dos pinos do PORTD do PIC, para lermos ou
escrevermos nesse registrador estamos na verdade atuando sobre os pinos do port
respectivamente. Não podemos esquecer que o registrador TRISD também afeta a leitura
e escrita no port.
As funções especiais de cada pino serão vistas quando estudarmos suas aplicações reais
através dos projetos que vamos desenvolver durante nosso curso.
PORTE
O PORTE, tal qual as outras portas, implementa diversas outras funções multiplexadas aos seus pinos,
acompanhe:
Assim como nas outras portas, o PORTE possui dois registradores que definem o modo de trabalho
dos seus pinos de I/O: são eles: PORTE e TRISE.
Tanto o registrador PORTE quanto o registrador TRISE estão localizados na memória RAM do PIC e
pertencem aos SFR'S (Registradores de Funções Especiais).
O registrador TRISE tem a função de programar os pinos do PIC para serem entradas ou saídas.
O registrador PORTE é o "espelho" dos pinos do PORTE do PIC, para lermos ou escrevermos nesse
registrador estamos na verdade atuando sobre os pinos do port respectivamente. Não podemos
esquecer que o registrador TRISE também afeta a leitura e escrita no port.
As funções especiais de cada pino serão vistas quando estudarmos suas aplicações reais através dos
projetos que vamos desenvolver durante nosso curso.
1.0 Exercício 1
1.1 Exercício 2
1.2 Exercício 3
1.3 Exercício 4
EXERCÍCIO 1:
Figura 01
Nossa missão neste exercício é programar o PORTB para ascender todo os leds.
Resposta:
Para ascender os leds, devemos programar o PORTB como saida, pois nosso intuito é "colocar" nivel lógico 1 (um) nos pinos
RB0 a RB7 para acendermos os leds. Logo precisaremos programar os registradores TRIS e PORT.
OBS: todas as vezes que tivermos que ler ou escrever um determinado dado nos pinos do PIC, devemos definir sua "direção"
através do registrador TRIS.
Quando o registrador TRIS for igual a 0 (zero) estaremos programando o PORT como saída.
Quando o registraor TRIS for igual a 1 (um), estaremos programando o PORT como entrada.
EXERCÍCIO 2:
Aproveitando o mesmo circuito eletrônico do exercício anterior (figura 01), programe o PORTB somente para acender
os leds alternadamente.
Resposta:
TRISB = 0b10101010; //configura os pinos RB0, RB2, RB4, RB6 do PORTB como saída. Neste exemplo acionamos
somente os pinos pares do PORTB como saída
PORTB = 0b10101010; //envia nível lógico 1 nos pinos do PORTB cujos estão acionados em 1
EXERCÍCIO 3:
O exercício seguinte é parecido com os anteriores, sua particularidade é que os leds estão agora conectados na PORTA do
PIC. Como sabemos a PORTA possui diversas funções, entre elas a de conversão analógico / digital (A/D). A PORTA e o
PORTE após reset (por default) vem configurado todos seus pinos como A/D (com excessão do pino RA4, que não é entrada
A/D). Para acionarmos nossos leds, conforme nosso exemplo seguinte, devemos programar além do TRIS (registrador de
definição de sentido do PORT) e do PORT ( registrador "espelho" dos pinos do PIC) o registrador: ADCON1.
O registrador ADCON1 é um registrador de funções especiais SFR's cujo endereço na memória RAM é 0xFC1h. Este
registrador possui diversas funções especiais que serão estudadas mais adiante em nosso curso.
Caso queremos utilizar todos os pinos da PORTA como I/O de uso geral, devemos programar o registrador ADCON1 com o
valor 6 (seis).
Pergunta:
Conforme circuito abaixo, programe a PORTA do PIC como saída para que acenda todos os leds;
Figura 02
Resposta:
obs: a emissão do registrador ADCON1 nos programas, acarreta o não acionamento adequado do PORTA e
consequentemente provoca o mal funcionamento do programa.
O pino RA4 do PIC é dreno aberto, isto implica que devemos conectar resitor de pull-up quando formos trabalhar este pino
como I/O de uso geral.
O PORTE também possui a função de conversores analógicos / digitais (A/D) também. Devemos configurar o ADCON1 para
trabalharmos o PORTE como I/O de uso geral.
EXERCÍCIO 04:
Neste próximo exercício resolvido desejamos acender os leds conectado a PORTA e ler as teclas conectadas no PORTD. Programe somente os
registradores resposáveis para execução dessa tarefa:
Circuito eletrônico:
Figura 03
Resposta:
Tirando como referência os exercícios anteriores, podemos acionar os leds e ler os estados das teclas configurando os
seguintes registradores;
Dica: para lermos os estados das teclas conectado ao PORTD, conforme figura 03, podemos utilizar o comando de atribuição
de igualdade:
A = PORTD;
Sendo:
Através dessa instrução a variável A passa a ter no momento da execução do comando o estado do PORTD. Agora basta
analizar o byte lido e tomar as decisões necessárias no programa;
1.0 Introdução
1.1 Conhecendo o mikroC
1.2 Criação de um projeto no mikroC
1.3 Conhecendo o ambiente mikroC
1.4 Code Editor (editor de código)
1.5 Code Assistant (assistente de código)
1.6 Parameter Assistant (assistente de parâmetro)
1.7 Auto Correct (correção automática)
1.8 Comment / Uncomment (Comentar / não comentar)
1.9 Goto Line (vá para linha)
2.0 Messages Window (janela de mensagens)
2.1 Procedures List (Lista de procedimentos)
2.2 Project Setup
2.3 Ferramentas Integradas
Introdução
O mikroC é um compilador desenvolvido e comercializado pela empresa MikroElektronika (www.mikroe.com). Ele se consiste um sistema
integrado de desenvolvimento (IDE) para os sistema operacional Windows e suporta toda a linha de microcontroladores PIC (séries PIC12,
PIC14, PIC16, PIC18) e existe outras versões para dsPIC (dsPIC30, dsPIC33 e PIC24). Os PICs da série 14 e 17, além dos microcontroladores
da UBICOM/SCENIX (SX), não são suportados por esta versão do compilador.
Integrado ao compilador mikroC, temos diversas ferramentas que nos auxiliam no desenvolvimento de aplicações, tais como: emuladores de
Terminal Serial, ferramentas para LCD gráficos e displays de 7 segmentos, EEPROM, etc. Temos também a opção de utilizar o debugador de
código na própria IDE.
O mikroC não é um software gratuito, e é comercializado pelo seu fabricante por poucos dólares. A versão demo que iremos utilizar no
desenvolvimento do nosso curso possui limite de geração de código de 2 kbyte de programa. Ultrapassando esse limite, é necessário adquirir a
versão completa (full).
O mikroC possui diversas bibliotecas de funções prontas para o tratamento dos mais variados dispositivos. Acompanhe:
ADC Library
CAN Library
CANSPI Library
Compact Flash Library
EEPROM Library
Ethernet Library
SPI Ethernet Library
Flash Memory Library
Graphic LCD Library
T6963C Graphic LCD Library
I²C Library
Keypad Library
LCD Library
LCD Custom Library
LCD8 Library
Manchester Code Library
Multi Media Card Library
OneWire Library
PS/2 Library
PWM Library
RS-485 Library
Software I²C Library
Software SPI Library
Software UART Library
Sound Library
SPI Library
USART Library
USB HID Library
Util Library
SPI Graphic LCD Library
Port Expander Library
SPI LCD Library
SPI LCD8 Library
SPI T6963C Graphic LCD Library
Outras bibliotecas
Conversions Library
Trigonometry Library
sprint Library
Setjmp Library
Time Library
Conhecendo o mikroC
Vamos conhecer nosso compilador mikroC
Após a instalação do compilador, é visualizado um ícone na área de trabalho denominado mikroC. Clique duas vezes nesse ícone que o
programa começa a ser carregado e apresenta a seguinte tela:
A primeira vez que instalamos o MikroC em nosso computador, sua interface é apresentado com background de cor preta. Podemos alterar esta
configuração acessando o menu Tools > options > Colors > Scheme.
Nosso compilador trabalha com a concepção de criação de projeto. Necessáriamente devemos criar um projeto para cada aplicação que venhamos a desenvolver.
A concepção de criação de projeto no mikroC é importante para que possamos incluir vários arquivos-fontes e configurações ao nosso projeto.
Abra o mikroC e vá ao menu Project > New Project. A tela seguinte aparece:
Figura 02 - criação de um projeto no mikroC
>> No campo Device podemos selecionar o modelo do microcontrolador PIC que utilizaremos em
nosso projeto.
Após ter configurado todos os parâmentros e campos, basta clicar no botão ok para salvar seu projeto. Pronto, nosso projeto está
pronto e podemos inserir os códigos do programa no editor.
Conhecendo o ambiente mikroC
Figura 03
O compilador mikroC permite o desenvolvimento rápido de aplicações complexas graças aos recursos do editor avançado Code Editor. Além disso, é permitido utilizar as
bibliotecas incluídas na linguagem para aumentar a velocidade e a facilidade de desenvolvimento dos projetos como comunicação serial, displays, aquisição de dados,
memória, etc.
Após a compilação de nosso programa, o mikroC também gera arquivos LIST, código em assembly e arquivo .HEX. Integrado ao compilador, temos um debugador para
testes do programa no ambiente.
Code Editor (editor de código)
O editor de código do compilador mikroC oferece grandes auxílios no desenvolvimentos de projetos. Alguns aspectos desse editor são:
Sintaxe ajustável
Assistentes de parâmetros
Código modelo
Autocorreção para tipos comuns
Função para saltos de linhas.
Assistentes de códigos
O Assistente de código é uma excelente ferramenta disponível no mikroC, pois o programador não precisa editar todo o código e ainda por cima analisa o formato da
constução do comando;
Figura 04
Para acioná-lo, digite as primeiras letras e pressione CTRL + SPACE que aparecerá uma janela informando os comandos associados às letras digitadas.
O compilador mikroC possui a opção de correção automática, corrigindo erros de sintaxe cometido pelo programador. Para corrigir os palavras é necessário que você
adicione as palavras corretas e erradas através do menu Tools > Preferences > Auto Correct. As palavras erradas serão substituídas pelas palavras corretas desde que estejam
registradas no menu > Auto Correct.
Através dessa função você poderá facilmente adicionar linhas ou blocos de comentários no seu programa. Basta clicar com o mouse no ícone Comment / Uncomment do
Code Toolbar.
Figura 05
Figura 06
Para visualizar a lista de todos os procedimentos utilizados pelo compilador, selecione View > Procedures List pelo menu ou prossione
CTRL + L no teclado.
Project Setup
Em Project Setup podemos alterar as configurações dos projetos criado no mikroC. Para acessá-lo pressione Project > Edit Project.
Ferramentas Integradas
O compilador MikroC possui diversas ferramentas que nos auxiliarão no desenvolvimento de nosso projeto. Dentre as ferramentas, encontramos
terminais seriais, terminais de comunicação USB, Ethernet, LCD alfanumérico e Gráfico, Bootloader, display de 7 segmentos, dentre outros.
Para ter acesso a esses painéis, acesse o menu Tools.
Figura 07
Vamos conhecer cadas uma das ferramentas do MikroC:
MikroBootLoader
Alguns modelos de microcontroladores PIC possui internamente uma região em sua memória de programa denominada Boot. Nesta
região podemos gravar um pequeno programa chamado BootLoader, no qual permite, via um software de PC, gravar o microcontrolador
via PC RS232 < > USART do PIC. A empresa Mikroelektronika disponibilizou o programa de Boot para diversos componentes da família
PIC16F e PIC18F, que podem ser encontrados na pasta:
c:\...\MikroeleKtronica\Mikro_c\Examples\EasyPic5\extra_examples\Bootloader
Figura 09 - MikroBootLoader
O sistema de Bootloader são altamente utilizados em equipamentos que permitem atualização de versões do programa do microcontrolador, tais
como CLP.
Nota: Existe vários programas de bootloader para microcontroladores PIC na internet. Digite bootloader PIC no google (www.google.com.br)
para conhecer um pouco melhor sobre o tema.
USART Terminal
O mikroC possui uma excelente ferramenta para recepção e envio de dados seriais via RS232, o Comunication Terminal (terminal de
comunicação). Para acessá-lo, clique no menu Tools > USART Terminal ou no ícone terminal que fica na Toolbar.
Para configurá-lo é muito fácil e simples; basta escolher a porta de comunicação serial através do Settings Com Port, definir a
velocidade de comunicação em Settings Baud, os bits de dados e a paridade. Após este procedimento, clique em Connect COM para que
a porta seja aberta. Todos os caracteres recebidos e enviados serão mostrados na caixa de texto maior da janela. Para enviar algum
dado, basta digitá-lo na caixa de texto ao lado do botão send e pressionar send.
Sua utilização é muito simples, permite que utilizemos LCD's gráficos com controladores T6963C e com Drives KS0108. Basta clicar no
botão Load BMP Picture para carregar a imagem BMP.
Após termos desenhado nosso caracterer, podemos clicar no botão GENERATE, para que apareça uma tela com nosso código (subrotina) pronto
para inserirmos em nosso programa principal.
Outras Ferramentas:
Debugger
É possível debugar o programa compilado através do próprio mikroC. O uso do debugador é muito importante para certos aplicativos,
pois evita a necessidade de gravar um programa em uma placa de teste. Para ativar o Debugador, vá em Run > Start Debugger.
Através do debugador você poderá testar o funcionamento lógico do seu programa, podendo visualizar todos os registradores, variáveis, funções
entre outras.
Janelas de estatísticas
Após a compilação do programa, é possivel ter acesso à janela de estatísticas que nos informa o tamanho do código gerado, tamanho das
rotinas, posições ocupadas pelas variáveis, memória de programa e dados, etc. Para visualizá-la, clique em View > View Statistics.
Note que a janela de estatísticas é composta por seis abas. A primeira informa o tamanho de RAM e ROM usadas pelo programa.
Informa com maiores detalhes os endereços, tamanho Informa todos os endereços das variáveis na RAM, os
das rotinas compiladas do projeto. SFR's e os GPRS.
4º. Clique no botão ok do painel New Project para salvar as configurações do projeto.
A tela seguinte irá aparecer, edite seu programa no Code Editor (painel de edição).
TRISD = 0x00;
PORTD= 0xff;
while (1);
}
5º. Salve seu programa através do ícone salvar na barra de ferramentas do mikroC e pressione o
ícone Build Project ou pressione as teclas de atalho CTRL + F9 para compilar seu
programa;
6º. Seu programa será compilado e seu resultado poderá ser visualizado através da Janela de
mensagens:
Pronto, seu projeto foi criado e compilado com sucesso; O compilador mikroC gerou na
compilação o arquivo .HEX, é este arquivo que deverá ser gravado no microcontrolador PIC.
Arquivo meu_programa.hex gerado pelo mikroC na compilação do nosso projeto
:1000000004EF00F0FFFFFFFF956AFF0E836EFFD73E
:10001000FFD7FFFFFFFFFFFFFFFFFFFFFFFFFFFF18
:020000040030CA
:0E000000FFFAFFFEFFFFFBFFFFFFFFFFFFFF0A
:00000001FF
Introdução a Linguagem C
Até este pondo do curso, estudamos vários tópicos fundamentais para o desenvolvimento do nosso curso, conhecemos a história dos microcontroladores,
estudamos os recursos e estruturas de hardware do PIC18F452 e aprendermos a compilar e editar um programa no compilador mikroC.
Chegou o momento de aprendermos a programar em linguagem C os microcontroladores PIC. Antes de estudarmos os conceitos da linguagem, devemos saber
que a linguagem C trata-se de uma linguagem complexa e de difícil assimilação para programadores inexperientes. Procuraremos abordar o conteúdo e
estrutura da linguagem baseando-se em exemplos de programas, pois dessa forma, ficará muito mais claro para o aluno entender a linguagem.
//Primeiro Programa
void main()
{
trisb = 0; //define portb como saída
portb = 0; //coloca nível lógico 0 em todos os pinos do portb
while(1)
{
portb.f0 = 1; //seta pino RB0
Delay_ms(1000); //aguarda 1000 ms (milisegundos)
portb.f0 = 0; //resseta pino RB0
Delay_ms(1000); // aguarda 1 segundo
}
}
//Primeiro Programa
É chamada de comentário. Os comentários são importantes para documentar o programa. Podemos adicionar comentários em nosso programa de duas
maneiras:
Através de comentários de linhas simples: quando queremos comentar apenas uma linha de programa, iniciamos os comentários com os caracaters " // " (igual a
linha do programa anterior). Esses tipo de comentário não faz parte da padronização ANSI original, mas atualmente é encontrado em vários compiladores.
Através de comentários de múltiplas linhas: podemos comentar linhas ou blocos de código de programa utilizando a seqüência de caracteres "/* " para iniciar o
comentário e a seqüência "*/" para terminar o comentário.
void main()
A declaração main()especifica o nome da função. A função main(), na linguagem C, é sempre a primeira a ser executada e deve ser a única no
programa. O programa termina quando for encerrada a execução da função main().
Uma função, em C, nada mais é do que um conjunto de instruções que pode ser executada a partir de qualquer ponto do programa. Utilizamos o sinal
de abertura de chave "{" para iniciar uma função e o sinal de fechamento de chave "}" para finalizar a função. Todas as instruções devem estar dentro
das chaves que iniciam e terminam a função e são executadas na ordem em que as escrevemos
No caso deste programa exemplo, ela não recebe nenhum parâmetro e também não retorna parâmetro nenhum. Isto fica explícito através da palavra-
chave void escrita na frente do programa.
As funções e as suas características serão apresentadas em detalhes mais adiante em nosso curso;
Como estudamos nas unidades anteriores, o comando trisb define o sentido de acionamento do PORTB do PIC. Neste exemplo, trisb = 0, logo o PORTB
foi programado como saída.
O comando portb = 0 coloca nivél lógico 0 em RB0 a RB7. As instruções C são sempre encerradas por um ponto-e-vírgula ( ; ). O ponto-e-vírgula é
parte da instrução e não um simples separador e devemos ao final de cada instrução colocar o acréscimo de um ponto-vírgula “;”.
while(1)
Este é um comando de controle utilizado na repetição de um determinado bloco de instrução. O bloco de instrução será executado repetidamente
enquanto o condição for verdadeira, ou seja, for diferente de zero. No nosso exemplo, o valor 1 utilizado no comando while garante que a condição seja
sempre verdadeira. Estudaremos mais sobre o comando while mais adiante no curso;
Como não temos nenhum comando que interrompa o laço while, os blocos de comandos apresentados serão executados indefinitamente até que o
processador seja desligado ou reiniciado.
A operação portb.f0 = 1 faz com que o pino RB0 do PORTB seja colocado em nivel lógico 1; Para se referir a um pino das portas do PIC, PORTA,
PORTB, PORTC, PORTD, PORTE, devemos apresentar o nome do porta, mais o ponto ".", mais a inicial "f" e o número do pino correspondente.
Exemplo:
A linha de programa seguinte, Delay_ms(1000), é uma função interna do compilador mikroC utilizada para gerar atrasos em escala de milissegundos. No
nosso exemplo, o comando irá gerar atraso de 1000 milessegundos, ou seja, 1 segundo.
A operação portb.f0 = 0 faz com que o pino RB0 do PORTB seja colocado em nível lógico 0;
Desta forma, ao programarmos o PIC com o programa exemplo, o pino RB0 ficará mudando de estado lógico 1 e 0 a cada 1 segundo,
Coloque em prática este pequeno projeto. Copie e compile este programa exemplo no compilador mikroC, isso lhe ajudará nos seus estudos.
Acomanhe:
//Segundo Programa
void main()
{
trisb = 0; //define portb como saida
portb = 0; //coloca nível lógico 0 em todos os pinos do portb
while(1)
{
portb = 255; //seta todos os pinos do portb
portd = 255; //seta todos os pinos do portd
Delay_ms(100); //aguarda 1000 ms (milisegundos)
portb = 0; //resseta todos os pinos do portb
portd = 0; //resseta todos os pinos do portd
Delay_ms(100); //aguarda 1000 ms (milisegundos)
}
}
O programa acima tem por objetivo piscar infinitamente o portb e portd do PIC em intervalos de 100 milissegundos. Suas caracteristicas são parecidas com a
do programa anterior, sua única diferença esta no tratamento das portas;
Podemos representar um valor numérico de diversas formas. Para exemplificar, vamos supor o que desejamos carregar o valor 187 no registrador PORTB no
PIC utilizando o mikroC, acompanhe:
Representação decimal:
Para representarmos um número em decimal basta colocar seu valor sem nenhuma abreviatura, conforme o linha abaixo:
ATENÇÃO: NUNCA DEVEMOS REPRESENTAR UM NÚMERO DECIMAL INICIANDO COM 0 (ZERO), POIS O MIKROC INTERPRETARÁ O NÚMERO COMO OCTAL.
EX:
portb = 25 (25 é representado em decimal)
é diferente de
portb = 025 (025 é representado em octal)
Representação Hexadecimal:
Para representar um número em hexadecimal devemos colocar o prefixo 0x (ou 0X) antes do número hexadecimal. (0 a F)
Representação binária:
Para representarmos um número em binário devemos colocar o prefixo 0b (ou 0B) antes do número em binário.
Observe que na representação binária de um número, o bit mais significativo fica ao lado do prefixo 0b. Não confunda de forma alguma a construção e as
representações de um número binário, caso contrário seu programa não funcionará corretamente.
Representação octal:
O sistema octal não é um sistema muito difundido nos dias atuais. Apesar do compilador mikroC suportar esse tipo de representação numérica, somente
devemos utilizá-la quando for realmente necessário.
Para representar um número octal é necessário colocar o prefixo 0 (zero) antes do valor numérico octal.
Atenção: Não confundir números decimais com octais. Números Octais são precedidos com 0, ex: 0140 é um número octal. Números decimais não é
Exercícios 01:
RB0 = 0
RB1 = 1
BR2 = 1
RB3 = 0
RB4 = 0
RB5 = 1
RB6 = 0
RB7 = 0
Qual o valor numérico que devemos colocar na instrução abaixo para representar os estados dos pinos do PORTB. Obedeça as representações numéricas
solicitadas:
Representação decimal:
portb = X; ?
Representação binária:
portb = X; ?
Representação hexadecimal:
portb = X; ?
Representação octal:
portb = X; ?
Diferente do pradrão ANSI C, No mikroC podemos utilizar caracteres maiúsculos e minúsculos no programa (case insensitive). Acompanhe:
Vejamos:
Representação decimal:
portb = 38;
Representação binária:
portb = 0b00100110;
Representação hexadecimal:
portb = 0x26;
Representação octal:
portb = 046;
Estrutura de um programa em C
Todo programa escrito em C consiste em uma ou mais funções, tendo como poarticularidade
deste fato a possibilidade de construir programas modulares e estruturados. O programa
principal escrito em C é uma função. O C é uma linguagem estremamente estruturada e exige
do programador domínio adequado de tal conceito. Veja a seguir, o menor programa possível
de ser escrito em C:
main( )
em que:
A função main() é a principal instrução a ser considerada em um programa escrito na linguagem C e deve estar
presente em algum lugar do programa, pois é ela que marca o ponto de inicialização do processo de execução do
programa.
A seguir veremos um modelo de escrita de um programa em C, com todas as definições e comentários.
Acompanhe:
[<tipo>] nome_da_funcao([<parâmetros>])
[<declaração de parâmentros>]
/*
Este trecho é reservado para o corpo da função_nome, com a declaração de suas variáveis locais, seus comandos
e funções de trabalho. Esta função pode ser chamada de sub-rotina do programa.
*/
void main([<parâmetros>])
{
/*
Este trecho é reservado para o corpo da função, com a declaração de suas variáveis locais, seus comandos e
funções de trabalho. Aqui estão os primeiros comandos que serão executados no programa.
*/
Toda a informação situada entre colchetes "[" e "]" indica informações que podem ou não estar presentes em um
programa.
O programador poderá inserir ou não o comentários em seu programa. Por convenção, é importante colocarmos
sempre os cabeçalhos nos programas, pois é a apresentação do programa.
Neste trecho do programas podemos declarar todo o cabeçalho do nosso programa assim como definir variáveis
globais que poderão ser utilizadas em todas as funções do nosso programa.
Exemplo de cabeçalho:
#include "minhas_funcoes.h" // incluimos em nosso programa as bibliotecas de funções que estão no arquivo
minhas_funcoes.h.
int a ; //definimos a variável a como inteiro e como sendo global
int b; //definimos a variável b como inteiro e como sendo global
[<tipo>] nome_da_funcao([<parâmetros>])
[<declaração de parâmentros>]
/*
Este trecho é reservado para o corpo da nome_da_funcao, com a declaração de suas variáveis locais, seus
comandos e funções de trabalho. Esta função pode ser chamada de sub-rotina do programa.
*/
}
Este último bloco trata-se de uma função que carrega o nome nome_da_funcao. Seu tipo pode ou não ser
explicitado. Caso não seja, qualquer função será do tipo int por default.
Esta função não faz parte da função main() e deverá ser chamada em algum momento pelas função main() ou por
outra função para seja executados seus comandos. Podemos no momento da chamada da função enviar
parâmetros (estudaremos mais sobre as funções a seguir).
No final da função, encontramos o comando return, cujo objetivo é retornar a função que a chamou um valor de
retorno da função.
Não é obrigatório o uso do comando return, caso não precisemos retornar nenhum valor na função.
void funcao(void) {
portb = ~portb;
return;
}
void main([<parâmetros>])
{
/*
Este trecho é reservado para o corpo da função, com a declaração de suas variáveis locais, seus comandos e
funções de trabalho. Aqui estão os primeiros comandos que serão executados no programa.
*/
A função main() será a primeira a ser executada pelo processador. Junto a função main(), temos o modificador de
tipo void que tem a função de declarar que a função main() não deve retornar nenhum valor.
A manipulação de programas em linguagem C para microcontroladores é diferente de trabalharmos com
programas para PC's, pois nos computadores PC's existem o sistema operacional que receberá o retorno da função
main(). Nos microcontroladores, como não possuimos um sistema operacional rodando em paralelo com o
programa, não podemos retornar nenhum valor na função main(). Para este caso, devemos sempre iniciar a
função main() com o modificador de tipo nulo void.
void main() {
PORTB = 0;
TRISB = 0;
PORTB = ~PORTB;
Delay_ms(1000);
}
INFORMAÇÕES IMPORTANTISSIMAS:
AS FUNÇÕES DE SUBROTINAS DEVEM SER COLOCADAS ANTES DA FUNÇÃO MAIN(), CASO
CONTRÁRIO OCORRERÁ ERRO DE COMPILAÇÃO DO PROGRAMA. ISSO OCORRE PORQUE não
podemos usar uma função sem declará-la previamente. PARA COLOCARMOS FUNÇÕES
ABAIXO DA FUNÇÃO MAIN() FAZ NECESSÁRIO UTILIZAR OS PROTÓTIPOS DE FUNÇÕES, CUJO
OBJETIVO É MOSTRAR AO COMPILADOR O TIPO, NOME E PARÂMETROS DA FUNÇÃO DAS
SUBROTINAS.
Exercício 01:
Vamos análisar um exemplo de programa em linguagem C disponível no próprio compilador mikroC como
exemplo. Em princípio, não quero que você entenda o funcionamento do programa, mas quero que você
identifique os principais blocos de funções desse programa. Vejamos:
/*
* Project name:
PWM_Test_01 (PWM library Demonstration)
* Copyright:
(c) MikroElektronika, 2005.
* Test configuration:
MCU: P18F8520
Dev.Board: BIGPIC3
Oscillator: HS, 10.0 MHz
Ext. Modules: -
SW: mikroC v5.00
* NOTES:
None.
*/
unsigned short j, oj;
void InitMain() {
PORTB = 0;
TRISB = 0;
ADCON1 |= 0x0F;
PORTA = 255;
TRISA = 255;
PORTC = 0x00;
TRISC = 0;
Pwm_Init(5000);
}//~
void main() {
initMain();
j = 127;
oj = 0;
Pwm_Start();
while (1) {
if (Button(&PORTA, 0,1,1))
j++ ;
if (Button(&PORTA, 1,1,1))
j-- ;
if (oj != j) {
Pwm_Change_Duty(j);
oj = j;
PORTB = oj;
}
Delay_ms(200);
}
}//~!
Resposta:
/*
* Project name:
PWM_Test_01 (PWM library Demonstration)
* Copyright:
(c) MikroElektronika, 2005.
* Test configuration:
MCU: P18F8520
Dev.Board: BIGPIC3
Oscillator: HS, 10.0 MHz
Ext. Modules: -
SW: mikroC v5.00
* NOTES:
None.
*/
Este bloco do programa são comentários e são resposável pela parte "documental do programa". No momento da
compilação, esses textos serão descartados pelo compilador.
Neste trecho do programas é definido o cabeçalho do programa, e nele foi declarado as variável globais do
programa.
void InitMain() {
PORTB = 0;
TRISB = 0;
ADCON1 |= 0x0F;
PORTA = 255;
TRISA = 255;
PORTC = 0x00;
TRISC = 0;
Pwm_Init(5000);
}//~
Esta função é uma subrotina do programa, e foi chamada pelo programador de InitMain();
j = 127;
oj = 0;
Pwm_Start();
while (1) {
if (Button(&PORTA, 0,1,1))
j++ ;
if (Button(&PORTA, 1,1,1))
j-- ;
if (oj != j) {
Pwm_Change_Duty(j);
oj = j;
PORTB = oj;
}
Delay_ms(200);
}
}//~!
Apesar do função main() ser a última na ordem de escrita do programa, ela será a primeira função a ser executada
pelo processador.
Dicas:
Protótipos de Funções
Não podemos usar uma função sem declará-la previamente. Trata-se duma instrução
geralmente colocada no início do programa ou do arquivo, obrigatoriamente antecedendo
a definição e a chamada da função. O protótipo informa ao compilador o tipo que a função
retorna, o nome da função, bem como os parâmetros que ela recebe. Eis um exemplo:
void minha_rotina (); //protótipo de função, esta linha de programa deve ser colocada no
topo do programa , junto com as declarações;
//....
void main()
{
// aqui esta meu programa principal
}
Os indetificadores
A linguagem C define identificadores como sendo nomes usados para se fazer referência a
entidades do programa (variáveis, funções, rótulos, etc.) definidas pelo programador. Em
C, um identificador é composto de um ou mais caracteres, sendo que, para identificadores
internos, os 31 primeiros são significativos. O primeiro caractere deve ser uma letra ou
um sublinha (_) e os caracteres subseqüentes devem ser letras, números ou sublinhas.
Eis aqui alguns exemplos de identificadores corretos e incorretos:
Isto quer dizer que se duas variáveis têm em comum os 31 primeiros caracteres e diferem
apenas a partir do trigésimo segundo, o compilador C não será capaz de distingui-Ias. Por
exemplo, esses dois identificadores são iguais:
isto_e_um_exemplo_de_um_nome_longo
isto_e_um_exemplo_de_um_nome_longo_tambem
Tipos de dados
TAMANHO
TIPO INTERVALO
EM BITS
char 8 0 a 255
int 8 0 a 255
3.4E-38 a
float 32
3.4E+38
nenhum
void 0
valor
O tipo char é utilizado para representação de caracteres ASCII de 8 bits. Cada variável do
tipo char pode representar um caractere ASCII. O tipo int é utilizado para representar
números inteiros de 8 bits (0 a 255). Estes tipos de dados são amplamente usados em
programação C.
O tipo char e int representam números inteiros e não podem ser utilizados para
representar números frácionários. Para isso, deve ser utilizado o tipo float, também
chamado de ponto flutuante.
O tipo float deve ser evitado ao máximo e restrito apenas às operações que
realmente necessitarem de um tipo de dados como este.
Modificadores de Tipo
Podemos utilizar comandos especiais do C para obter outros tipos de dados. Esses
comandos especiais são chamados de modificadores de tipo e são os seguintes:
O modificador de tipo signed pode ser utilizado para modificar um tipo base de dados
para que ele possa representar um número positivo ou negativo;
O modificador short é utilizado para definir uma variável com tamanho menor que o tipo
modificado, ou seja, uma versão reduzida do tipo especificado.
O modificador long é utilizado para ampliar a magnitude de representação do tipo
especificado.
TIPO TAMANHO RANGER
(unsigned )
8 -bit 0 à 255
char
signed char 8 -bit -128 à +127
(signed)
8 - bit -128 à +127
short (int)
unsigned
8 - bit 0 à 255
short (int)
(signed) int 16 - bit -32768 à 32767
unsigned
16 - bit 0 à 65535
int
(signed) -2147483648 à
32 - bit
long int 2147483647
unsigned
32 - bit 0 à 4294967295
long int
+/-
1.17549435082E-
float 32 - bit
38 à +/-
6.80564774407E38
+/-
1.17549435082E-
double 32 - bit
38 à +/-
6.80564774407E38
+/-
1.17549435082E-
long double 32 - bit
38 à +/-
6.80564774407E38
void nulo sem valor
Obs: tipos de float, double e long double são considerados do mesmo tipo no
mikroC.
Declaração de variáveis
Definir uma variável é criá-la na memória (alocá-la), dar a ela um nome e especificar o
tipo de dado que nela vai armazenar.
<tipo> nome_da_variavel;
O tipo deve ser um tipo de dado válido em C tais como: char, int, float, com ou sem seus
modificadores, unsigned, signed, short e long. E nome_da_variavel é o nome da
variável adotada pelo programador.
int soma ;
unsigned char i,j,k ;
float salário;
unsigned int idade;
short int y;
long caminho, estado;
unsigned valor;
Outro aspecto importante da declaração das variáveis é o local onde são declaradas.
Basicamente, uma variável pode ser declarada em dois pontos distintos do programa:
Variáveis globais:
No corpo principal do programa: variáveis declaradas no corpo principal do programa são
variáveis globais que podem se acessadas por qualquer função do programa. Essas variáveis
estão fora de qualquer função do programa, inclusive a função main().
Exemplo:
contador = contador + 10
Repare que as variáveis "contador" e "a" forma definidas fora de qualquer função do programa,
essas variáveis serão tratadas como variáveis globais e seus dados poderão ser manipulados
por qualquer função do programa;
Repare no programa exemplo acima que as variáveis "contador" e "a" estão sendo manipuladas
no corpo da função main() e na função subrotina(). Este tipo de manipulação de variáveis
somente é possível se declararmos como sendo do tipo GLOBAIS, ou seja, necessáriamente
devemos defini-las no corpo do programa (fora de qualquer função do programa, inslusive a
função main()).
Variáveis locais:
Ao contrário das variáveis globais, uma variável local somente existe dentro da função em que
foi declarada. Isto significa que uma variável local somente existe enquanto a função esta
sendo executada. No momento que ocorre o retorno da função, as variáveis locais são
descartadas;
Repare que a variável "contador" foi declarada (criada) dentro da função main(), as variável
locais somente terá validade dentro da função que a declarou, neste caso, "contador" somente
poderá ser manipulada no programa dentro da função main().
Acompanhe mais um exemplo de variável local:
Repare no programa exemplo acima que temos duas funções, a função main() e a função
subrotina(). Dentro de cada uma dessas funções foram criada uma variável chamada "tempo"
do tipo int, essas variáveis são locais e somente tem validade dentro da função que a declarou,
ou seja, a variável "tempo" da função subrotina() NÃO tem nenhuma ligação com a variável
"tempo" da função main(), pois são variáveis locais;
Repare que a variável "tempo" foi declarada unicamente dentro da função main() e que seus
dados estão sendo manipuladas por outra função chamada subrotina(). Ao compilarmos este
programa, certamente o compilador apresentará um erro de compilação nos informando que a
variável "tempo" não foi definida. Esse é um erro comum que muitos programadores
inexperientes cometem na linguagem C, pois esquecem que uma variável local somente tem
validade dentro da função que a declarou.
Podemos declarar variáveis como parâmetros formais de uma função, que são também tratadas
como variáveis locais. Iremos estudar esse tipo de variável quando estivermos falando de
funções em nosso curso;
1.0 Exercício 1
1.1 Exercício 2
1.2 Exercício 3
1.3 Exercício 4
1.4 Exercício 5
1.5 Exercício 6
1.6 Exercício 7
Analise a figura abaixo e descreva como foi configurado os bits configurations (fusiveis) do PIC.
Comente somente os bits que estão ativos no painel de controle:
Resposta:
O bit HS esta selecionado no nosso painel (figura acima), isso comprova que
nosso microcontrolador PIC será acionado por oscilador exteno do tipo cristal ou
ressonador (pois bit OSCSEN não esta habilitado).
O bit BOREN esta acionado e programado para provocar reset no PIC quando a
tensão cair abaixo de 2.0V (verifique o valor da tensão selecionado).
O watchdog esta ativado (WDTEN ativo) com prescaler de 1:128, o que nos
resulta tempo de 2304us para ocorrer o reset.
EXERCÍCIO 2:
Pergunta:
Faça uma análise apurada dos estados dos bits de configuração do PIC descrevendo
as funções de cada bit que esteja ativado:
Resposta:
EXERCÍCIO 3:
Pergunta:
/*
* Project name:
Seg2Cif_Static (Usage of 7Seg displays)
* Copyright:
(c) Mikroelektronika, 2005.
* Description:
This code demonstrates how to display a static number on two 7-
segment
displays (common cathode), in multiplex mode. Both displays are
connected
to PORTB (RB0..RB7, segment A to RB0, segment B to RB1, etc), with
refresh
via pins of porta (RA0,RA1).
This code also demonstrates how to use interrupts.
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPIC3
Oscillator: HS, 08.0000 MHz
Ext. Modules: -
SW: mikroC v6.0
* Notes:
None.
*/
void interrupt() {
if (v==0) {
PORTB = por2; // send mask for digit 3 to portb
PORTA = 1; // turn on 1st 7 seg., turn off 2nd
v = 1;
} else {
PORTB = por1; // send mask for digit 8 to portb
PORTA = 2; // turn on 2nd 7 seg., turn off 1st
v = 0;
}
TMR0 = 0; // clear TMRO
INTCON = 0x20; // clear TMR0IF and set TMR0IE
}//~
void main() {
trisC = 0;
OPTION_REG = 0x80; // pull up resistors
PORTA = 0; // clear porta (make sure both displays are
off)
TRISA = 0; // designate porta pins as output
PORTB = 0; // clear portb (make sure LEDs are off)
TRISB = 0; // designate portb pins as input
TMR0 = 0; // clear TMRO
por1 = 0x7F; // mask for 8 (7 seg. display)
por2 = 0x4F; // mask for 3 (7 seg display)
portC = 2;
INTCON = 0xA0; // enable T0IE
// wait for interrupt
}//~!
Resposta:
/*
* Project name:
Seg2Cif_Static (Usage of 7Seg displays)
* Copyright:
(c) Mikroelektronika, 2005.
* Description:
This code demonstrates how to display a static number on two 7-
segment
displays (common cathode), in multiplex mode. Both displays are
connected
to PORTB (RB0..RB7, segment A to RB0, segment B to RB1, etc), with
refresh
via pins of porta (RA0,RA1).
This code also demonstrates how to use interrupts.
* Test configuration:
MCU: PIC16F877A
Dev.Board: EasyPIC3
Oscillator: HS, 08.0000 MHz
Ext. Modules: -
SW: mikroC v6.0
* Notes:
None.
*/
void interrupt() {
if (v==0) {
PORTB = por2; // send mask for digit 3 to portb
PORTA = 1; // turn on 1st 7 seg., turn off 2nd
v = 1;
} else {
PORTB = por1; // send mask for digit 8 to portb
PORTA = 2; // turn on 2nd 7 seg., turn off 1st
v = 0;
}
TMR0 = 0; // clear TMRO
INTCON = 0x20; // clear TMR0IF and set TMR0IE
}//~
Esta é a única função de sub-rotina do nosso programa exemplo e é chamada de interrupt(), A função
interrupt() é do tipo void, que representa que esta função não possui retorno.
void main() {
trisC = 0;
OPTION_REG = 0x80; // pull up resistors
PORTA = 0; // clear porta (make sure both displays are
off)
TRISA = 0; // designate porta pins as output
PORTB = 0; // clear portb (make sure LEDs are off)
TRISB = 0; // designate portb pins as input
TMR0 = 0; // clear TMRO
por1 = 0x7F; // mask for 8 (7 seg. display)
por2 = 0x4F; // mask for 3 (7 seg display)
portC = 2;
INTCON = 0xA0; // enable T0IE
// wait for interrupt
}//~!
Esta é a função main() do programa , esta é a primeira função que será executada pelo
processador do PIC.
EXERCÍCIO 4:
Pergunta:
Suponhamos que temos precisamos criar uma variável no programa que assumirá valores de 0 a 100
durante toda a execução do programa, utilizaremos o compilador mikroC. Qual o tipo de variável
que devemos declarar em nosso programa para armazenar o valor apresentado?
Obs: Procure definir o tipo de variável mais adequado pois sabemos que se ttratando de
microcontroladores nossos recursos de memória são limitados
Resposta:
Sabemos que no mikroC basicamente temos os tipos de dados: char, int, float, double e void.
No mikroC os tipos float e double são interpretados como sendo do mesmo tipo, ou seja, ambos tem os
mesmos tamanhos.
O tipo de dados que se enquadra para o ranger de 0 a 100 são: unsigned char, short int, unsigned int e
long int.
Mas conforme o anunciado precisamos criar uma variável mais adequada, pois assim otimizaremos o
consumo de memória de dados em nosso microcontrolador;
O tipo que mais adequado é unsigned char. (0 a 255) ou o unsigned short int (0 a 255).
EXERCÍCIO 5:
Pergunta:
Resposta:
EXERCÍCIO 6:
Pergunta:
No programa seguinte, descubra quais são as variáveis local e quais são as variáveis
globais: Defina a diferença entre variáveis local e global:
//programa exemplo
char contador;
int limite;
void funcao(void)
{
int a;
limite = a + contador;
portb = limite;
void funcao2(void)
{
signed char b;
portd = b;
}
void main()
{
int c;
trisb = 0;
portb = 0;
trisd = 0;
portd = 0;
funcao() ;
funcao2();
Resposta:
Variável Local:
int a;
signed char b;
int c;
Variável Global:
char contador;
int limite;
EXERCÍCIO 7:
Pergunta:
Tipos de Operadores
A linguagem C faz uso de diversos operadores. Podemos classifica-los em algumas categoria
principais: artméticos, relacionais, lógicos, lógicos bit a bit , outros.
Os operadores Aritméticos:
operador ação
+ adição
subtração ou menos
-
unário
* Multiplicação
/ Divisão
Resto da divisão
%
inteira
++ incremento
-- Decremento
Adição e Subtração
c = a + b;
d = d + b;
c = c - a;
a = d - a + c;
Multiplicação e Divisão
c = a * b;
d = d * d;
c = c / a;
a = (d * a) / c;
O operador %
O operador % é utilizado para retornar o resto de uma operação de divisão inteira. Vejamos
um exemplo:
C = C + 1;
é diferente de
variavel _a = ++ variavel_b;
Vejamos um exemplo:
int a, b, c;
a = 0;
b = a ++;
c = ++ a;
Neste caso, após a execução dos três comandos, o valor de "a" será igual a 2, o valor da
variável "b" será igual a 0 e o valor da variável "c" será igual a 2.
Operadores Relacionais;
Os operadores relacionais servem para comparar expressões. São muito utilizado para
comparar condições de controle do fluxo de execução de programas.
Operação
operador
realizada
> maior que
>= maior ou igual a
< menor que
<= menor ou igual a
== igual a
!= diferente de
Estes operadores serão muito utilizado para construir expressões condicionais, como veremos
mais adiante em nosso curso.
Operação
operador
realizada
&& AND (E)
|| OR (OU)
! NOT (NÃO)
Com esses operadores podemos relacionar diversas condições diferentes em um mesmo teste
lógico.
if (c>0 || a==0) b = a; // condição verdadeira de teste: se a variável "c" for maior que 0 ou a for
igual a 0 então "b" é igual a variável "a".
if (!a) b = c; // condição verdadeira de teste: se a variável "a" for igual a 0, a variável "b"
assumirá o valor da variável "c". Note que estamos utilizando o operador de negação "!" NOT,
por esse motivo a variável "a" assumirá o valor verdadeiro, já que possui valor 0.
Os operadores Bit a Bit são utilizados para realizar operações lógicas entre elementos ou
variáveis.
Operação
operador
realizada
& AND (E)
| OR (OU)
XOR (OU
^
exclusiva)
NOT
~ (complemento de
um)
deslocamento à
>>
direita
deslocamento à
<<
esquerda
O operador lógico AND realiza operação separadamente para cada bit dos operandos.
Utilizamos muito este o operando AND como "máscara" de um byte, para habilitar ou
desabilitar somente os bits que desejamos. Veja um exemplo:
int a, b;
a = 125;
b = 28;
a = a & b;
O Operador OR (|)
O operador OR é muito similar ao operador AND, sua operação também é realizada para cada
bit do operando. Exemplo:
int a, b;
a = 125;
b = 28;
a = a | b;
O operador XOR são muito utilizado em funções de comparação de valores, pois em uma
operação lógica, o resultado somente será verdadeiro (nível lógico 1) se um e somente um
deles for verdadeiro ( nível 1). Exemplo:
int a, b;
a = 125;
b = 28;
a = a ^ b;
O operador NOT inverte o estado de cada bit do operando em uma operação. Exemplo:
int a, b, c;
a = 1;
b = 1;
b = ~a
c = ~b
O operador >> desloca para a direita os bits de uma variável um determinado número de vezes.
exemplo:
int a, b, c;
a = 10;
b = 10;
b = a >> 1;
c = b << 5;
No exemplo acima, os valores dos bits da variável "a" foram deslocados 2 vezes para a direita,
enquanto os bits da variável b foram deslocados 5 vezes para a esquerda.
Estruturas de Controle
As estruturas de controle são usadas nos programas em lugares em que necessitamos
que a máquina faça repetidas operações ou necessite de tomadas de decisão.
O comando IF (SE)
O IF (SE, em português) é uma estrutura de tomada de decisão baseada no resultado lógico de um teste. Sua
forma geral é:
if (condição) comando;
ou
Em C, qualquer número diferente de zero é tido como verdadeiro. O que significa que uma condição em C só é
falsa, quando os resultados dos operadores que aplicados for zero (0). Qualquer outro valor, mesmo negativo, é
considerado como verdadeiro ou não zero.
No comando If, caso a condição seja verdadeira (diferente de zero), o comando, ou blocos de comandos serão
executados, caso contrário, quando a condição for falsa (0 zero) o comando será ignorado.
Exemplo:
void main() {
char a = 10;
char b = 0 ;
if (a) b--;
}
A variável "a" foi atribuida o valor 10, que é diferente de zero (0). Consequentemente, a o comando if será
executado e a condição de decremento da variável b será executado; ( if (a) b--; ).
também é possível executar outro comando ou bloco de comandos no caso da condição ser avaliada como falsa,
para isso utilizamos os recursos do comando if - else.
if (expressão)
comando 1
else
comando 2
Exemplo:
if (x > 5)
z = 10;
else
z = 20;
A linha de comando if (x > 5) tem por função verificar se acondição x>5 é verdadeira, caso seja verdadeira, a
linha de programa z = 10 será executada. Caso a condição do comando IF seja falsa, ou seja, se "x" for menor que
5, então a linha de comando z = 20 será executada.
Todos os operadores do C podem ser incluidos no teste de uma condição, expressões válidas da linguagem C
podem ser avaliadas para a geração de um resultado booleano na estrutura if. As expressões seguintes são válidas
e seus resultados dependerão do valor de suas variáveis. Exemplo:
if (a > b) b = a; // se a expressão a > b for verdadeira, a variável "b" assume o valor da "a"
if (b < a) b = 10; // se a expressão a < b for verdadeira, a variável "b" assume o valor 10
if (a != b) b = 55; // se a expressão a !=b (diferente) for verdadeira, a variável "b" assume o valor 55
if ( (a + b) > (b + d) ) b++; // se a expressão (a + b) > (b + d) for verdadeira, a variável "b" será incrementada em
uma unidade.
Observações importantes:
O operador de atribuição de igualdade em C (=) é diferente do operador relacional de igualdade (==). Para testar a
condição de uma variável qualquer, utilizamos o operador relacional de igualdade (==). Acompanhe:
if (a == b) c = 10;
é diferente de
if (a = b) c = 10;
A condição (a == b) faz uma comparação entre as duas variáveis, caso a condição seja verdadeira, a variável "C"
assumirá o valor 10;
O comando If seguinte, possui uma expressão de atribuição de igualdade (a = b). O compilador ao compilar este
comando, irá primeiramente atribuir a variável "a" o valor contido em "b", e depois disso, verificará se acondição
não é zero, caso seja verdadeiro o resultado (diferente de zero), a variável "c" assumirá o valor 10;
No comando IF para adicionarmos blocos de programas, faz necessário o uso dos simbolos abre- chaves ({)
efecha-chaves (}).
Exemplo:
if (portb == portc)
{ //blocos de comandos
a++;
portb.f0 = 1;
d = c + e;
}
Podemos criar arranjos (nesting) de comandos através da estrutura if, else, if. Os arranjos são criados bastando
colocar estruturas if aninhadas com outras estruturas if.
Seu formato geral é:
Exemplo:
void main() {
Exemplo:
void main() {
{
sinal--;
contador = 15;
}
else
if (contador == sinal) sinal = 0;
}
A estrutura if é uma das mais utilizadas para tomada de decisões lógicas. Iremos utilizá-la em vários programas
que desenvolveremos durante nosso curso.
O comando Switch
O comando switch é uma forma mais clara e elegante de tomar decisão dentro de um programa em C. Diferente
do comando if, a estrutura switch não aceita expressão para a tomada de decisão, mas só aceita constante.
switch (variável)
{
case constante1:
declaração1A;
declaração1B;
declaração1N;
break;
case constante2:
declaração2A;
declaração2B;
declaração2N;
break;
default;
declaração_default;
}
O valor da variável no comando switch é comparada contra as constantes especificadas pela cláusula case. Caso a
variável e a constante possuam valores iguais, os comandos seguinte a cláusula case serão executados. Caso não
tenha nennhuma constante com o mesmo valor da variável, então os comandos especificados pela cláusula default
serão executados.
Acomanhe o exemplo:
void main() {
switch(contador)
{
case 2: sinal++;
break;
case 1: sinal = 2;
break;
default: sinal = 0;
}
}
No exemplo de acima, a variável contador será comparada às constantes 2, 1 e 10. Como a variável contador
possui o valor 10, consequentemente o comando que será executado no exemplo acima é case 10:
contador--; (decrementa a variável contador).
A cláusula Break possui a função de encerrar uma sequencia de comandos de
uma cláusula case.
A cláusula default é o último comando switch.
Introdução
Os laços de repetição servem para repetir uma ou mais vezes determinada instrução ou blocos de instruções.
Existem basicamente três tipos de estruturas de repetição na linguagem C:
for
While
Do - While
A estrutura for basicamente é utilizada para laços finitos de contagem, normalemtne utilizando uma variável de
controle da contagem.
A estrutura while basicamente é utilizado para repetição de um determinado conjunto de instrução enquanto uma
condição for verdadeira.
O comando do - while é similar à estrutura while, diferenciando apenas o momento que é analisada a condição.
O comando For
O laço for é utilizado quando necessitamos de um ciclo de repetições controlado, pois em sua
declaração podemos inicializar e incrementar ou decrementar a variável de controle. Antes de
serem executados os comandos do laço For-next, primeiramente é avaliada a condição do teste.
Caso seja verdadeira, são executados os comandos do laço. A cada ciclo que é executado o
faço for, a variável de controle será incrementada ou decrementada no valor programado no
incremento.
ou
em que:
inicialização: expressão válida utilizada normalemtne para inicialização da variável de controle
do laço for.
condição: condição para que decide pela continuidade ou não do laço de repetição, enquanto
esta condição foi verdadeira , o laço for permanecerá em execução.
incremento: valor incrementado em a cada repetição do laço for.
Exemplo:
int contador;
for (contador = 0 ; contador = 10 ; contador ++ ) portb = contador;
Exemplo:
int v, d;
for (v = 0 ; v = d ; v++)
{
Comando A
Comando B
}
O grande benifício do laço for é sua flexibilidade, pois aceita qualquer expressão válida em C, mesmo que essas
expressões não tenham relacionamento com o laço de repetição diretamente.
Um exemplo simples de aplicação do laço for é a criação de pequenos tempos de atrasos (delays).
int atraso;
for (atraso = 0 ; atraso < 1000 ; atraso++);
O laço for acima faz com que o processamento fique incrementando constantemente a variável atraso em 1 até
que esta variável seja igual ao valor 1000;
No exemplo acima a variável n será incrementada 100 vezes, desde que o pino RB0 permaneça em estado lógico
alto. Se o pino RB0 em algum momento do laço cair para nivel lógico baixo, o loop será imediatamente
encerrado.
Programa Exemplo:
Aproveitando que estamos estudando as estruturas do laço de repetição for, vamos elaborar um program que pisca
um led conectado ao pino RD0 do PIC utilizando os recursos do laço for.
O programa seguinte vai contar até 100.000. Para acomodar um número dessa grandeza poderiamos ter utilizado
uma variável long, mas optamos pela variável int para que você entenda a construção de dois laços for
encadeados. Para contar até 100,000 é necessário termos uma variável que conte até 100 e outra até 1000 (100 *
1000 = 100.000).
//**********************************************************
// programa de perda de tempo utilizando o laço de repetição for.
//**********************************************************
void main() {
trisd = 0;
while(1) {
atraso(); //chama rotina de perda de tempo
portd = ~portd; // inverte os estados do portd do PIC
}
}
O comando While
Muitos dos programadores iniciantes não sabem do que iremos comentar agora.
void main() {
while (1) // condição a ser testada. Neste exemplo a condição sempre será verdadeira (1);
{
declaração 1;
declaração 2;
declaração n;
}
}
void main() {
int a = 25;
while (a = 5)
{
a++;
portb = a;
}
}
Repare que no exemplo acima o valor a condição do laço while é falsa, neste cado os comandos do laço não serão
executados no programa até que a condição seja verdadeira, ou seja, até que a = 5.
O comando do - while
O comando do -while forma uma estrutura de repetição diferente dos comandos while e for estudado
anteriormente. Sua diferença fundamental com relação as outras tradicionais laços de loop while e for esta no fato
da avaliação da condição de teste ser no final do laço de repetição, contrário dos outros laços que estudamos, que
testam as condições no início de cada ciclo.
formato geral:
ou
do
{
comando 1;
comando 2;
} while (condição de teste);
Na estrutura do-while a condição de teste é efetuada somente na parte final do loop. Isso faz
com que as instruções contidas no interior do laço do - while sejam executadas ao menos uma
vez. Caso a condição teste seja atendida, o laço de repetição é finalizado, caso contrário o
bloco que está na estrutura seria novamente executado até que a condição teste seja atendida.
Exemplo:
void main() {
int a = 0; //declara a variável a como inteiro com o valor 0
do
{
a++; //incrementa a variável a em uma unidade
portd = ~portd; //inverte os estados do portd
}
while(a > 100); // enquanto a < 100 permanece no loop do-while;
}
Break
O comando break, na linguagem C, é utilizado para interromper (quebrar) qualquer laço de
repetição instantaneamente. No momento da execução do loop, ao encontrar o comando break,
o laço de repetição é finalizado.
Exemplo:
void main() {
int a = 0;
do
{
a++; //incrementa a variável A em uma unidade
break; //interrompe a execução do laço de repetição do-while
portd = ~portd; //inverte os estados dos portd
}
while(a < 100); //enquanto a variável a for menor que 100 a rotina do-while será executada.
}
Continue
O comando continue reinicia novamente o teste da condição do laço de repetição. Toda a vez
que no laço for encontrado o comando continue, os comandos seguintes não serão executados
no laço.
Exemplo:
void main() {
int a = 0;
do
{
a++; //incrementa a variável A em uma unidade
continue; //iretorna para o inicio do laço de repetição
portd = ~portd; //inverte os estados dos portd
}
while(a < 100); //enquanto a variável a for menor que 100 a rotina do-while será executada.
}
No exemplo de programa acima, os comandos abaixo de continue não serão executados, pois,
toda a vez que for executado o comando continue, automaticamente o programa será
redirecionado para o cabeçalho do laço de repetição independente de qualquer estado de
variáveis.
O comando continue é valido para os laços do-while, while, for e case.
Introdução
É um dispositivo indispensável na maioria dos projetos, pois permite adicionar dados ao Mc. Acompanhe o
esquema de um teclado:
O resistor utilizado chama-se pull-up, pois garante o nível lógico 1 na entrada do Mc quando a chave estiver
aberta. Quando pressionamos a tecla, alteramos o nível lógico do pino do Mc, ou seja, se por exemplo: o pino
RB0, RB4 e RB7 estiver em nível lógico 1, ao pressionarmos a tecla S1 o pino vai para nível 0. ( apesar do portb
do PIC possuir resistores de pull-up interno convencionamos a utilização também de resistores externos)
Quando tivermos no projeto teclas conectadas ao Mc, devemos tomar cuidado com o efeito mecânico Debouncing
ao pressionarmos essas teclas.
Debouncing: o efeito mecânico de rebatimento que a tecla sofre logo após ser pressionada é chamado "boucing",
o qual provoca a leitura falsa da tecla, isto é, o rebatimento faz com que a tecla seja lida mais de uma vez. A rotina
de debouncing nada mais é do que um pequeno intervalo de tempo entre o momento em que a tecla é solta e a
nova leitura do teclado. Esse intervalo permite que o fenômeno do rebatimento termine naturalmente, evitando
assim a leitura falsa dela. Tempo aproximado de 25 ms.
No mikroC podemos manipular teclados através de uma simples função intitulada button. Acompanhe:
A Função Button
A função button tem como sintaxe:
onde:
&port = port onde esta ligado a tecla, pode ser PORTA, PORTB, PORTC, PORTD
ou PORTE.
pin = é o pino onde esta ligado a tecla no PIC, pode ser de 0 a 7.
timer = tempo de debounce em escala de milisegundos.
estado_de_ativação = determina se a tecla vai ser ativada em nível 0 ou em
1.
Exemplo:
Apartir da configuração da função button acima, descobrimos que a tecla que será lida está conectada ao portb,
pino RB0, delay de debounce de 10 milisegundos e é acionada em nível lógico 0 (zero).
Primeiro Programa:
Conectado ao PIC temos uma tecla ( push- button) e um led. Repare que o led é ligado com nivel lógico 1.
figura 01
Desejamos que toda vez que pressionarmos e soltermos a tecla S1, o led 1 deverá alterar seu estado lógico, ou
seja, se o led estiver acesso, ao pressionar e soltar a tecla S1, o led será apagado, e ao pressionar a tecla
novamente, o led será acesso. Devemos programar delay para correção de debounce de 20 milisegundos.
Para realizar essa tarefa, iremos fazer um programa bem simples utilizando a função button, acomanhe:
void main()
{
trisd.f0 = 0; //configura pino RD0 como saida (leds)
trisb.f0 = 1; //configura pino RB0 (tecla) como entrada
do {
if (Button(&PORTB, 0, 20, 0)) //se a tecla S1 estiver pressionada o comando if será
executado
{
delay_ms(200); //delay de 200 milisegundos
portd.f0 = ~pord.f0; //inverte o estado do led
}
} while(1);
}
No programa acima configuramos o pino RD0 como saída, pois tráta-se de um led.
Criamos um laço de repetição através do comando do-while, cujo objetivo é fazer com que o microcontrolador
sempre esteja executando os comandos do laço.
Caso a tecla S1 seja pressionada, ao executar a função button, teremos como retorno valor 1 (verdadeiro), e caso
não venhamos a pressionar a tecla, a função button nos retornará o valor 0. Apartir disso concluímos que a
condição IF somente será verdadeira caso o retorno da função button for verdadeiro, que neste caso, ocorrerá
quando a tecla for pressionada.
O programa apresentado acima possui um problema, pois caso deixamos a tecla pressionada, a condição IF sempre
será verdadeira e então seus comandos serão executados, fazendo com que o led acenda e apague enquanto a tecla
estiver pressionada.
Para corrigir o problema do programa anterior, vamos elaborar um novo programa que acenda e apague o led 1 da
figura 01 para cada toque que dermos no teclado, ou seja, temos que pressior e soltar a tecla para executar a
inversão do estado do led, se deixarmos a tecla pressionada, o estado lógico do led somente mudará um vez. O
tempo de debouncing programado deverá ser de 20 milisegundos.
Programa:
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led.
*/
#define led1 portd.f0 //a diretiva define atribui ao pino RD0 o nome led1.
void main() {
trisd.f0 = 0; //configura o pino RD0 como saida, pois iremos ligar/desligar o
led.
trisb.f0 = 1; //configura pino RB0 (tecla) como entrada
do {
if (Button(&PORTB, 0, 20, 0)) estado_antigo = 1; //se a tecla fo pressionada, a
variável estado_antigo = 1.
if (estado_antigo == 1 && Button(&PORTB, 0, 20, 1)) { //verifica se a tecla foi solta
led1 = ~led1; //inverte o estado do led 1.
estado_antigo = 0; //inverte o valor da variável estado_antigo para o próximo
acionamento.
}
} while(1);
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led.
*/
Até este ponto do curso não estudamos a utilização da diretiva define. Esta diretiva tem por função atribuir a uma
constante ou registrador um novo nome. Veja o comando:
#define led1 portd.f0 //a diretiva define atribui ao pino RD0 o nome led1.
A diretiva #define atribui o nome led1 ao pino RD0 do PIC, partir deste ponto do programa, toda vez que
utilizarmos o nome led1, o compilador sabe que se refere ao pino portd.f0 (RD0), e substituirá na compilação este
novo nome pelo endereço fisico de memória do pino RB0.
Exemplo:
#define display1 portd.f0 //a diretiva define atribui ao pino RD0 o nome led1.
#define led2 portd.f1 //a diretiva define atribui ao pino RD0 o nome led1.
void main() {
trisd = 0; //configura o pino RD0 como saida, pois iremos ligar/desligar o led.
display1 = 0;
led2 = 1;
}
Definimos uma variável do tipo int chamada estado_antigo. Esta variável tem por função fazer com que o led seja
ligado/desligado somente com um unico toque na tecla, evitando que ao deixarmos a tecla pressionada os
comandos if sejam sempre executados.
void main() {
Como já estudamos anteriormente, o registrador TRIS do PIC, tem por função informar a
direção (leitura ou escrita) dos pinos da porta. Neste programa temos uma tecla conectado
ao pino RB0, e para lermos essa tecla é necessário configurar este pino como entrada. A
função button se encarrega de configurar esses registradores de sentido para nós.
Conectado ao pino RD0, temos um led. Para acionar este led, faz necessário enviar nível
lógico 1 a este pino, então devemos configurar este pino como sáida.
Lembre-se que devemos sempre manter o microcontrolador executando alguma rotina, mesmo que essa rotina
seja um comando sem saida (while(1);). Devemos criar um programa que "amarre" o microcontrolador a sempre
executar suas funções. No nosso programa exemplo utilizamos os recursos do laço de repetição do - while.
do {
if (Button(&PORTB, 0, 20, 0)) estado_antigo = 1; //se a tecla fo pressionada, a
variável estado_antigo = 1.
if (estado_antigo && Button(&PORTB, 0, 20, 1)) { //verifica se a tecla foi solta
led1 = ~led1; //inverte o estado do led 1.
estado_antigo = 0; //inverte o valor da variável estado_antigo para o próximo
acionamento.
}
} while(1);
Repare que a condição de teste do laço de repetição do-while será sempre verdadeira (while(1)).
Os comandos seguintes tem por objetivo ler o estado da tecla S1, conectada ao pino RB0 do PIC, e ligar ou apagar
o led 1 conectado ao pino RD0.
Para lermos a tecla, utilizamos a função do mikroC: Button, em conjunto com o comando de tomada de decisão
IF.
Vejamos:
Sabemos que o comando if somente será executado se a condição de teste for verdadeira, neste caso, a variável
estado_antigo somente será executada se a função button for verdadeira, para isso é necessário que a tecla seja
pressionada.
Outro comando:
Nesta linha de programa efetuamos uma operação AND (E) entre a variável estado_antigo e o retorno da função
Button, cujo objetivo é verificar se a tecla foi solta ou não. Repare que nesta segunda função Button o estado
lógico de acionamento da tecla passa a ser 1 (Button(&PORTB, 0, 20, 1)), contrário da função Button da linha
anterior, essa alteração indica que somente teremos a condição de retorno verdadeira (1), caso a tecla não esteja
pressionada.
Os comandos seguintes somente serão executados se a condição if for verdadeira, e para isso faz necessário que a
variável estado_antigo seja igual a 1 e que o retorno da função Button seja verdadeira, ou seja, a tecla tem que
estar solta.
Leituras de 4 teclas:
Nosso próximo passo é elaborar um programa para lermos 4 teclas conectado ao PIC, conforme figura abaixo:
Figura 03
Perceba no esquema eletrônico acima que nossos teclados não possuem mais resistores de pull-up externo
(compare com o circuito eletrônicos da figura 01), neste caso devemos acionar os resistores de pull-up interno
disponivel no PORTB do PIC através do bit RBPU do registrador INTCON2.
No PORTB do PIC18f442, por default, o circuito de pull-up interno vem desativado (após reset). Esses resistores
de pull-up são automaticamente ativados quando programamos o PORTB como saida (trisb = 0), para outros
casos, devemos nós mesmos ativá-los.
O registrador bit RBPU é ativado com nível lógico 0 (zero), e destivado com nível lógico 1 (um).
Nosso programa:
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de 4 tecla para ligar/desligar um led.
*/
#define led1 portd.f0 //a diretiva define atribui ao pino RD0 o nome led1.
void main() {
trisd = 0; //configura o pino RD0 como saida, pois iremos ligar/desligar o led.
portd = 0;
intcon2.rbpu = 0; //habilita os resistores internos de pull-up do PORTB do PIC
trisb.f0 = 1; //configura pino RB0 (tecla) como entrada
trisb.f1 = 1; //configura pino RB1 (tecla) como entrada
trisb.f2 = 1; //configura pino RB2 (tecla) como entrada
trisb.f3 = 1; //configura pino RB3 (tecla) como entrada
do {
if (Button(&PORTB, 0, 20, 0)) //lê tecla 1
portd = 0b00000001;
else if (Button(&PORTB, 1, 20, 0)) //lê tecla 2
portd = 0b00000010;
else if (Button(&PORTB, 2, 20, 0)) //lê tecla 3
portd =0b00000011;
else if (Button(&PORTB, 3, 20, 0)) //lê tecla 4
portd =0b00000100;
Delay_ms(200); //delay de 200 milisegundos
} while(1);
}
1.3 Exercício 4
1.4 Exercício 5
1.5 Exercício 6
1.6 Exercício 7
1.6 Exercício 8
Introdução
Apartir de agora iremos colcolar em prática tudo que estudamos nesta unidade do curso através de exercícios;
Exercício 1:
Qual é a diferença entre o operador = e o operador ==?
Resposta:
Exercício 2:
a = 25 & 12;
Resposta:
25 = 000011001
&
12 = 000001100
________________
00001000
A=8
Exercício 3:
Comparando os laços de repetição, do-while e while, descreva suas principais diferenças com relação a avaliação da
condição de teste:
Resposta:
O laço do-while avalia a condição de teste somente no final, após ter executado todos os comandos do laço. Como garantia
temos que o laço será executado ao menos uma vez no programa.
O laço while analisa a avaliação de teste no início do programa, caso a condição seja verdadeira, os comandos dos seu laço
serão executados, caso falso, o laço de repetição while é finalizado.
Exercício 4:
O programa seguinte tem como objetivo piscar um led conectado ao pino RB5 do PIC em intervalos de 1 segundo. Ao
compilar esse programa, o programador percebeu que o programa não funcionou. Analise o programa abaixo e aponte o erro
cometido pelo programador inesperiênte: Refaça o programa com as correções necessárias para seu perfeito funcionamento.
void main()
{
trisb = 0;
portb.f5 = 1;
Delay_ms(1000); // 1 second delay
portb.f5 = 0;
Delay_ms(1000); // 1 second delay
}
Resposta:
O erro cometido no programa acima, se deve ao fato de não existir uma rotina de loop que faça com que o processamento do programa volte a se
repetir.
Para corrigir este erro, colocamos o comando de repetição while em nosso programa com a condição verdadeira.
void main()
{
trisb = 0;
while(1){ // condição sempre verdadeira
portb.f5 = 1;
Delay_ms(1000); // 1 second delay
portb.f5 = 0;
Delay_ms(1000); // 1 second delay
}
}
Exercício 5:
Analise
x = 0;
if (x = 1) portb = 0;
ou
x = 1;
if (x ==0) portb = 0;
Resposta:
Exercício 6:
Faça um programa que monitore o acionamento de uma tecla conectado ao port RB1 do PIC, conforme esquema abaixo. A
cada acionamento da tecla todos os leds do portd deverão alterar seu estado anterior (ligado/desligado). Para realizar este
programa , utilize os recursos do comando if para detectar o acionamento das teclas. Não iremos considerer neste programa o
efeito debouncing.
Programa:
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar todos os leds do portd
*/
void main() {
trisd = 0;
portd = 0;
intcon2.rbpu = 0;
//habilita os resistores internos de pull-up do PORTB do PIC
while(1){
if (tecla1 == 0){ //se tecla1 for pressionada então....
portd = ~portd; //inverte os estados dos leds do portd
Delay_ms(200); //delay de 200 milisegundos
}
}
}
Repare no video que ao pressionarmos a tecla1, os leds são acionados e desacionados diversas vezes, isso representa que
enquanto a tecla estiver pressionada (nivel 0) a condição if será verdadeira e seus comandos serão executados.
Para resolver esse problema, podemos utilizar diversos artificios em C, mas no nosso estudo vamos utilizar a função button
do mikroC.
Exercício 7:
Faça o mesmo exercício anterior só que agora utilizando a função button do mikroC para leituras da tecla. Utilize delay de
25ms para correção do debouncing.
Programa:
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar todos os leds do portd
*/
void main() {
trisd = 0;
portd = 0;
intcon2.rbpu = 0;
//habilita os resistores internos de pull-up do PORTB do PIC
while(1){
if (button(&portb, 0, 25, 0)){ //se tecla1 for pressionada a condição será verdadeira.
portd = ~portd; //inverte os estados dos leds do portd
Delay_ms(200); //delay de 200 milisegundos
}
}
}
Observe que a função button no momento que é executada, configura o port como entrada (trisb = 255) . Por esse motivo,
não é obrigatório configurarmo o registrador TRISB.F0.
Exercício 8:
Faça um programa utilizando os recursos da função button para ler 3 teclas conectada aos pinos RB0, RB1, RA5. Cada tecla
deve ser programada para funcionarem somente com toque, ou seja, é necessário pressionar e soltar a tecla para cada
acionamento.
Programa:
/*
Programa de leitura de tecla.
Curso: Microcontroladores PIC programação em C
Este programa tem por objetivo ler o estado de uma tecla para ligar/desligar um led.
*/
while(1){
Introdução
Agora que já conhecemos os recursos fundamentais da linguagem C, estamos prontos para criar nossos programas para controle de equipamentos. Estudaremos as
principais funções e ferramentas para manipular displays LCD. Para implementar nossos projetos é interessante a utilização de um display, capaz de tornar mais
simples a visualização de informações e a interação com nosso equipamento, escolhemos para tratar nesta obra de um display de utilização muito comum em
sistemas microcontrolados, suas características são as seguintes:
Um display LCD desse tipo, possui embutido em seu circuito um outro microcontrolador, e para podermos utilizá-lo temos que entender um pouco de seus
comandos e funções. Dessa forma, da mesma maneira com que trabalhamos com o PIC, para utilizar um display LCD temos que seguir uma sequência de
procedimentos.
Hardware e Pinagem
Existem modelos diferentes, com localização diferente da pinagem, porém a numeração e função dos pinos geralmente é a mesma, nos kits didáticos e
profissionais Microgenios é utilizado o LCD apresentado em seguida:
CGROM: Memória não volátil onde estão gravados os códigos para escrita dos caracteres, isso é muito útil, pois apenas
enviamos o código ASCII do caracter e esse já é escrito no display.
DDRAM: É uma área de memória volátil, onde escrevemos o que queremos que apareça no display, cada endereço dessa
memória equivale a um endereço de caracter dos display, podemos fazer a seguinte analogia para facilitar, cada caracter do
display é como uma “janela” que exibe o conteúdo que escrevemos na DDRAM.
CGRAM: É uma pequena área de memória onde podemos “desenhar” caracteres diferentes (apenas 8 caracteres). Ela é muito
utilizada quando precisamos criar caracteres que não são comuns a todas as línguas como por exemplo o caracter “ç” do
português.
Abaixo está o endereço em hexadecimal de cada caracter no display LCD 16 x 2, assim fica mais fácil a movimentação do cursor
e das letras a serem escritas:
A seguir o código que devemos enviar para o LCD a fim de obtermos um determinado caracter:
Endereços e Instruções
Agora conhecemos a pinagem desse LCD, vamos conhecer seu modo de funcionamento e saber um pouco mais das instruções e
dados que precisaremos utilizar.
É interessante atentarmos para a seguinte característica, a via de dados e instruções é a mesma, dessa forma a sinalização, que
indica se o Byte que chega no display é dado ou instrução é proveninte do sinal encontrado no pino 4 (RS):
RS = 0 -> Instrução
RS = 1 -> Dado
Outra característica importante é que precisamos pulsar (de 1 para 0) o sinal Enable (pino 6) para que a informação que chega
aos terminais do LCD seja interpretada pelo controlador do display.
Em nosso estudo manteremos o pino 5 (R/W) em zero, pois apenas escreveremos no LCD. Podemos ligar este pino do LCD no
PIC também.
Para utilizarmos esse novo dispositivo em nossos projetos, devemos seguir alguns passos:
1º Inicializar o LCD: Primeiramente criar uma rotina em nosso programa, que envie para o display uma sequência de informações
que determinará o modo com o qual trabalharemos, com por exemplo:
O mikroC automaticamente carrega as rotinas de inicilização do LCD na compilação de um programa. O programador não precisa se
preocupar em inicilizar o LCD desde que o hardware do dispositivo esteja configurado no programa corretamente no modo 4 ou 8 bits;
(veremos com detalhes mais adiante).
Tabelas de Instruções
Na seqüência disponibilizamos as tabelas de instruções para esse tipo display, como nosso objetivo não é o estudo do
display propriamente dito, aconselhamos aos interessados nesse dispositivo que procurem bibliografias dedicadas a eles
para um maior detalhamento das funções.
Abaixo está o endereço em hexadecimal de cada caracter no display LCD 16 x 2, assim fica mais fácil a movimentação do cursor
e das letras a serem escritas:(ENDEREÇOS EM HEXADECIMAL)
80 81 82 83 84 85 86 87 88 89 8A 8B 8C 8D 8E 8F
C0 C1 C2 C3 C4 C5 C6 C7 C8 C9CACB CC CD CE CF
Inicialização do LCD
Toda vez que alimentarmos o LCD, devemos executar um procedimento de inicialização, o qual consiste em enviar comandos que
configuram o modo de operação para execução de um dado programa: fixação das condições de utilização, fixação do modo de controle
ativo/inativo do display e limpeza da tela.
No mikroC não precisamos nos preocupar em programar todos os comandos de inicialização do LCD, pois, através de simples funções,
o compilador se encarrega de programá-lo para nós. Por esse motivo devemos informar ao sistema o “tipo” de LCD que estamos
utilizando por meio de linhas de comando. A seguir, vamos conhecer e estudar as instruções de controle de LCD usadas no mikroC.
modo 8 bits
modo 4 bits
no modo 8 bits.
no modo 4 bits - somente um port de controle/dados
no modo 4 bits - com dois ports para controle e dados do LCD
No modo 8 bits, todos os pinos do barramento de dados do LCD são utilizados, conforme figura abaixo:
Repare que todos os 8 pinos do barramento de dados do LCD (D0 a D7) estão ligados no microcontrolador PIC, neste modo, estamos
enviando as instruções e comandos para o LCD em 8 bits.
O compilador mikroC possui diversas bibliotecas de funções prontas para trabalharmos com displays LCD. Para exemplificar, vamos
apresentar um programa em C que utiliza os recursos das funções de controle de LCD do compilador mikroC, acompanhe:
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_8bits.c
Este programa tem por objetivo escrever a mensagem "Microgenios" na primeira
linha do LCD e na segunda "Kit PICGENIOS".
**************************************************************************
*/
void main()
{
trisd = 0; //configura todos os pinos do portd como saída
trise = 0; //configura todos os pinos do porte como saida
ADCON1 = 0x06; //configura todos os pinos de A/D como I/O de uso geral
Os comandos seguintes controlam o display LCD no modo 8 bits. Vamos estudar cada um dos comandos:
O comando lcd8_config ( ):
O comando lcd8_config determina quais são os pinos do barramento de dados e de controle do LCD que estão ligados ao PIC, assim
como também inicializa o LCD.
Sintaxe:
lcd8_config(&port_controle, &port_dados, RS, EN, RW, D7, D6, D5, D4, D3, D2, D1, D0 );
Onde:
A função lcd8_config acima, determina os PORTs e os pinos que participam do controle do LCD:
PORTE
PORTD
Repare que o pino R/W do LCD foi aterrado. No comando Lcd8_config informamos que o pino RW era RE0 do PIC.
O comando lcd8_cmd(comandos_LCD):
No mikroC podemos configurar o LCD de diversas formas diferentes. Através da função lcd8_cmd(), podemos determinar diversas
"tarefas" que o LCD deverá executar. Acompanhe:
Sintaxe:
Lcd8_cmd(comandos_LCD);
onde:
Comandos Descrição
LCD_FIRST_ROW Move cursor para primeira linha do LCD
LCD_SECOND_ROW Move cursor para segunda linha do LCD
LCD_THIRD_ROW Move cursor para a terceira linha do LCD
LCD_FOURTH_ROW Move cursor para a quarta linha do LCD
LCD_CLEAR Apaga display
LCD_RETURN_HOME Retorna cursor para a primeira coluna da primeira linha do LCD
LCD_CURSOR_OFF Desliga cursor
LCD_UNDERLINE_ON Salta cursor para a linha inferior
LCD_BLINK_CURSOR_ON Ativa o modo piscante do cursor
LCD_MOVE_CURSOR_LEFT Move cursor para a esquerda sem movimentar os textos
LCD_MOVE_CURSOR_RIGHT Move cursor para a direita sem movimentar os textos
LCD_TURN_ON Liga cursor
LCD_TURN_OFF Apaga todo o visor do LCD, sem perder os dados no visor
LCD_SHIFT_LEFT Movimenta textos do LCD para a esquerda
LCD_SHIFT_RIGHT Movimenta textos do LCD para a direita
No exemplo utilizamos o seguinte comando para apagar o display LCD:
Este e os demais comandos que estudaremos somente podem ser utilizados após a execução do comando lcd8_config().
E agora escrevemos a mensagem "Microgenios" na coordenada informada pela função lcd8_out no LCD.
Os números 1, 1 da função acima, informa que a mensagem "Microgenios" será escrita na primeira linha da primeira coluna do LCD. o
Primeiro numero informa a linha do LCD e o segundo número informa a coluna do LCD.
Os displays LCD são constituidos de linhas e colunas conforme podemos ver na figura abaixo:
Podemos escrever um dado em qualquer posição do LCD. basta informar a linha e a coluna para inicio do texto.
No caso de desejarmos escrever uma mensagem "ligado" na quarta linha, décima coluna do LCD 20 x 4, basta escrever o seguinte
comando:
Vamos escrever agora outro programa que escreve uma mensagem no display lcd 16 x 4:
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_8bits_01.c
Este programa tem por objetivo escrever a mensagem "Maquina: ligado" na primeira
linha do LCD e na segunda linha "Prog: ligado".
**************************************************************************
*/
void main()
{
trisd = 0; //configura todos os pinos do portd como saída
trise = 0; //configura todos os pinos do porte como saida
ADCON1 = 0x06; //configura todos os pinos de A/D como I/O de uso geral
Neste exemplo repare que utilizamos a mesma configuração de hardware do LCD anterior. Repare que agora temos um comando novo
em nosso programa, o comando lcd8_out_cp, cuja função é escrever no lcd uma string ou variável na corrente posição do cursor.
Repare que o comando lcd8_out(1,1,"Maquina: "); deixa o cursor posicionada na sétima coluna da primeira linha do lcd. O
próximo comando que vem em seguida no programa é lcd8_out_cp(texto), que escreve na posição do cursor do lcd o valor da
variável "texto", que neste caso é a string "ligado".
Ma qu i n a : L i g a d o
P r og : L i g a do
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits_00.c
Este programa tem por objetivo escrever a mensagem "teste LCD" na primeira
linha do LCD. Programa no modo 4 bits
**************************************************************************
*/
void main() {
TRISD = 0; // programa portD como saida
Lcd_Config(&PORTD,1,3,2,7,6,5,4); //configura e inicializa LCD
Lcd_Cmd(Lcd_CLEAR); // apaga display
Lcd_Cmd(Lcd_CURSOR_OFF); // desliga cursor
Lcd_Out(1, 1, "teste LCD"); // escreve texto "teste LCD" na primeira linha, primeira coluna do LCD
while(1);
}
O programa acima tem a função de escrever na primeira linha do display lcd o texto "teste LCD". Repare na imagem acima que
utilizamos somente um port do PIC para controle e envio de dados para o LCD.
Os comandos seguintes controlam o display LCD no modo 4 bits. Vamos estudar cada um dos comandos:
O comando lcd_config ( ):
O comando lcd_config( ) determina quais são os pinos do barramento de dados e de controle do LCD que estão ligados ao PIC, assim
como também inicializa o LCD.
Sintaxe:
Onde:
A função lcd_config acima, determina o PORT e os pinos que participam do controle do LCD:
PORTD
PORTD
PODEMOS ATERRAR O PINO R/W DO LCD, POIS AS FUNÇÕES DE CONTROLE DE LCD DO MIKROC NÃO UTILIZA ESTE PINO
SIMPLESMENTE DEIXAM ESTE PINO EM NIVEL LÓGICO 0. CASO VENHAMOS A ATERRAR O PINO RW, ECONOMIZAREMOS 1 PINO DE
I/O DO PIC.
Os demais comandos do programa estudamos anteriormente, em caso de dúvida leia novamente o conteúdo do tópico lcd modo 8 bits.
Este é mais um dos modos 4 bits de trabalharmos com LCD. Neste novo modo podemos ter um port de controle e outro port do PIC para
dados. Veja o esquema abaixo:
Repare que para controlar o display LCD utilizamos dois ports do PIC, o PORTA para controle, e o PORTD como dados.
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits_01.c
Este programa tem por objetivo escrever a mensagem "Programa LCD" na primeira
linha do LCD. Programa no modo 4 bits
**************************************************************************
*/
void main() {
while(1);
}
Os comandos seguintes controlam o display LCD no modo 4 bits. Vamos estudar cada um dos comandos:
O comando lcd_custom_config ( ):
O comando lcd_custom_config( ) determina quais são os pinos do barramento de dados e de controle do LCD que estão ligados ao PIC,
assim como também inicializa o LCD.
Sintaxe:
Onde:
A função lcd_custom_Config acima, determina os PORTs e os pinos que participam do controle e envio de dados para o LCD:
PORTA
PORTD
Aprendendo Programando:
Apartir de agora, iremos desenvolver alguns exemplos de programas utilizando display LCD alfanuméricos.
1º Programa:
Vamos elaborar um programa utilizando os recursos das funções de display LCD do MikroC para que funcione da seguinte maneira:
Microcontrolador: PIC18F4x2
Cristal: 8MHz
Acompanhe o harware:
figura 01 - Esquema elétrico
void main() {
unsigned char inc = 0; //declara variavel chamada "inc" como char
lcd8_config(&porte, &portd,2,1,4,7,6,5,4,3,2,1,0); //
lcd8_cmd(lcd_clear); //apaga display LCD
lcd8_cmd(lcd_cursor_off); //desliga cursor
lcd8_out(1,1,"Microgenios"); //escreve no display LCD
lcd8_out(2,1,"KIT PICGENIOS"); //escreve no display LCD
}
Obs: repare neste programa que o pino R/W do display LCD foi aterrado, e na função lcd8_config foi declarado como sendo pino
RE4. O pino R/W normalmente não é utilizado nas maioria das aplicações, neste caso, como a função lcd8_config necessita de
algum parâmetro, informamos um valor qualquer, neste caso foi um pino inexistente no chip. (lembre-se que todos os ports do PIC são
composto por 8 bits, neste caso a posição de memória RE4 existe, porém não tem aplicação para este chip).
Regras do C: Se na declaração de uma função declararmos "n" parametros, necessáriamente deveremos enviar todos os "n"
parâmetros na chamada desta função.
2º Programa:
Nosso segundo programa, tem como objetivo escrever no display LCD o valor numérico 100 armazenado em uma variável do tipo char,
chamada "contador". Utilizaremos o mesmo esquema eletrônico apresentado do exemplo 01.
Acompanhe:
/*********************** Animação de Display LCD ************************
Centro de Tecnologia Microgenios
Programa: Animação LCD
Compilador: MikroC
Cristal: 8Mhz
Microcontrolador: PIC18F452
Objetivo: enviar para o display LCD o valor da variável contador
*************************************************************************/
void main() {
unsigned char contador = 100; //declara variável char contador e atribui o valor 100
unsigned char texto[10]; //cria vetor (array) do tipo char com 11 elementos (os indice começam do 0)
lcd8_config(&porte, &portd,2,1,4,7,6,5,4,3,2,1,0); //
lcd8_cmd(lcd_clear); //apaga display LCD
lcd8_cmd(lcd_cursor_off); //desliga cursor
}
O programa deste exercício possui muitas informações importantes, dentre elas, a utilização de Arrays, ou como neste caso é chamado,
vetor.
Para que possamos enviar o valor numérico presente em uma variável qualquer, a principio precisamos converter cada um de seus
algorismo em caracterer, pois a função de display LCD do MikroC somente opera com caracteres e string.
Um erro comum (acredito que você já tentou), é utilizar as funções dessa forma:
Se você pensou que iria aparecer no display LCD o valor da variável contador no display LCD você se enganou.
Seu display LCD somente pode operar com caracterer, ou seja, char. Lembre-se que o barramento do LCD é de 8 bits, no qual permite o
envio de valores de 0 a 255 no máximo.
Cada caracterer no padrão ASCII é do comprimento de um char, neste caso você já começa a pensar...
É exatamente isso, temos que enviar caracter por caracter, caso nossa intensão seja escrever uma mensagem no visor do LCD.
Nosso compilador possui algumas bibliotecas que irão nos ajudar e muito na elaboração do nosso programa. Utilizamos uma função
chamada bytetostr no programa, que tem por objetivo converter o valor numérico de uma variável para String e armazenar em uma
Tabela (vetor).
" Professor, estou com uma dúvida !! . Afinal qual é a diferença entre um caractere e uma string???
Na linguagem C diferenciamos um caractere de uma string através das aspas simples ' e aspas duplas ". Exemplo:
Caractere:
todo caractere ASCII possui um valor numérica (consulte o menu Tools > ASC Chart do MikroC)
String:
Não exite uma representação numérica para uma string, pois está é composta por caractere + 1 caractere de terminação, chamado "Null", cujo valor é Zero.
então teremos:
"A" ---> é igual a: --- > 'A' (caractere) + "\0" (caractere de terminação de string null)
Pense e responda:
Qual é o número que representa seu nome?
resp:
Não existe um número que represente seu nome, e isso acontece em qualquer string.
3º Programa:
Este Terceiro programa tem por objetivo mostrar utilizar os recursos da memória CGRAM do display LCD. Neste exemplo, aparecerá
um pequeno "cavalinho" andando no display LCD alfanumérico.
Teste este programa no seu kit PICgenios e veja o resultado:
//1º caracterer************
const char character1[] = { 32 , 32 , 32 , 32 , 3 , 7 , 14 , 14};
const char character2[] = { 32 , 32 , 32 , 32 , 15 , 31 , 31 , 31};
const char character3[] = { 32 , 32 , 32 , 32 , 3 , 31 , 31 , 31};
const char character4[] = { 32 , 1 , 31 , 31 , 31 , 27 , 19 , 16};
const char character5[] = { 12 , 24 , 16 , 1 , 1 , 1 , 32 , 32};
const char character6[] = { 31 , 31 , 30 , 23 , 32 , 32 , 16 , 32};
const char character7[] = { 31 , 31 , 1 , 1 , 1 , 1 , 32 , 32};
const char character8[] = { 28 , 28 , 4 , 4 , 8 , 32 , 32 , 32};
void escreve(char pos_row, char pos_char, char pos_row1, char pos_char1,char num) {
char i;
if (num == 1){
LCD8_Cmd(64);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character1[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character2[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character3[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character4[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character5[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character6[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character7[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character8[i]);
LCD8_Cmd(LCD_RETURN_HOME);
lcd8_chr(pos_row, pos_char, 0);
LCD8_Chr_cp(1);
LCD8_Chr_cp(2);
LCD8_Chr_cp(3);
lcd8_chr(pos_row1, pos_char1, 4);
LCD8_Chr_cp(5);
LCD8_Chr_cp(6);
LCD8_Chr_cp(7);
}
if (num == 2){
LCD8_Cmd(64);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character1a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character2a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character3a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character4a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character5a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character6a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character7a[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character8a[i]);
LCD8_Cmd(LCD_RETURN_HOME);
lcd8_chr(pos_row, pos_char, 0);
LCD8_Chr_cp(1);
LCD8_Chr_cp(2);
LCD8_Chr_cp(3);
lcd8_chr(pos_row1, pos_char1, 4);
LCD8_Chr_cp(5);
LCD8_Chr_cp(6);
LCD8_Chr_cp(7);
}
if (num == 3){
LCD8_Cmd(64);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character1b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character2b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character3b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character4b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character5b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character6b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character7b[i]);
for (i = 0; i<=7; i++) LCD8_Chr_Cp(character8b[i]);
LCD8_Cmd(LCD_RETURN_HOME);
lcd8_chr(pos_row, pos_char, 0);
LCD8_Chr_cp(1);
LCD8_Chr_cp(2);
LCD8_Chr_cp(3);
lcd8_chr(pos_row1, pos_char1, 4);
LCD8_Chr_cp(5);
LCD8_Chr_cp(6);
LCD8_Chr_cp(7);
}
void main() {
unsigned char texto[10];
lcd8_config(&porte, &portd,2,1,4,7,6,5,4,3,2,1,0); //
lcd8_cmd(lcd_clear); //apaga display LCD
lcd8_cmd(lcd_cursor_off); //desliga cursor
while(1){
escreve (1,1,2,1,3);
delay_ms(100);
escreve (1,1,2,1,2);
delay_ms(100);
escreve (1,1,2,1,1);
delay_ms(100);
}
}
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2008. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem prévio aviso. Maiores
informações: suporte@microgenios.com.br
Conversor A/D do PIC
1.0 Introdução
Introdução
O PIC18F452 possui internamente 8 canais de A/D com resolução de 10 bits cada. Comu m conversor A/D com
resolução de 10 bits e tensão de referência de 5V, podemos obter um valor de 4,8876.. mV, pois 5V/ (2E10 - 1) =
4,8876... mV.
Os conversores A/D dos PICs utilizam uma técnica de aproximação sucessivas, normalmente com resolução de 10 bits,
com clock selecionável pelo usuário e múltiplas entradas multiplexadas.
Canais AD multiplexados
Os conversores A/D do nosso microcontrolador estão ligados nos pinos RA0 (AN0), RA1 (AN1), RA2 (AN2), RA3
(AN3), RA5 (AN4), RE0 (AN5), RE1 (AN6), RE7 (AN7). Os registradores que participam da configuração do conversor
A/D são: ADCON0 e ADCON1.
Nosso A/D possui resolução de 10 bits (8 + 2 bits), onde os valores das conversões são armazenados nos registradores
ADRESH e ADRESL.
Registrador ADCON0:
ADCON0:
ADCS1 ADCS0 CHS2 CHS1 CHS0 GO/DONE ----- ADON
Registrador ADCON1:
ADCON1:
ADFM ADCS2 ------ ----- PCFG3 PCFG2 PCFG1 PCFG0
O bit de ADFM tem a função de organizar o resultado da conversão A/D, de forma que o os valores convertidos sejam
justificados a direita ou a esquerda nos registradores ADRESH e ADRESL. Caso venhamos configurar ADFM = 1,
organizamos o valor da conversão a direita, ou seja, os oitos bits menos significativo será armazendo em ADRESL, e os 2
bits mais significativo serão armazenados em ADRESH.
Caso ADFM = 0, justificaremos a esquerda os valores de conversão, desta forma os oitos bits mais significativos ficarão
em ADRESH e os 2 menos significativo ficará em ADRESL.
Através dos bits PCFG3, PCFG2, PCFG1, PCFG0 informamos quais os pinos que serão A/D ou I/O digital.
ADCON1 = 0 ; //programamos todos os pinos RA0, RA1 , RA2 , RA3, RA5, RE0, RE1, RE2 como A/D
ADCON1 = 6 ; //programamos todos os pinos RA0, RA1 , RA2 , RA3, RA5, RE0, RE1, RE2 como I/O de uso geral
ADCON1 = 14 ; //programamos os pinos RA1 , RA2 , RA3, RA5, RE0, RE1, RE2 como I/O de uso geral e somente RA0
como AD (referência VDD).
ADCON1 = 4 ; //programamos os pinos RA2 , RA5, RE0, RE1, RE2 como I/O de uso geral e RA0, RA1 e RA3 como
AD (referência VDD).
Nosso módulo possui um conversor com resolução máxima de 10 bits, ou seja, 1024 divisões (0 a 1023 divisões).
Podemos configurar e determinar tensões de referência externa para nosso conversor A/D através dos pinos AN3 e AN2,
ou selecionar a tensão interna do chip (vcc e gnd) como referência.
onde:
obs: 1023 é o valor máximo de conversão do A/D, lembrando que o valor é de 0 a 1023.
Analize o esquema elétrônico seguinte:
figura 01
Analizando o esquema eletrônico apresentado, vamos encontrar o valor analógico convertido para digital:
Digamos que o valor da tensão Vin no momento de leitura do AN0 seja de 2V.
Nossa Fórmula:
Rad = ( Vin - Vref-) * 1023 / (Vref+ - Vref-)
logo:
Rad = (2 - 1) *1023 / (3 - 1)
Rad = 1 * 1023 / 2
Rad = 511
sintaxe:
Adc_Read(canal_ AD);
onde:
Canal_AD: canal do conversor AD do PIC que desejamos ler. O número do canal AD depende do tipo de PIC usado.
Exemplo:
int leitura_ad;
leitura_ad = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res
A função adc_read salva o valor da conversão AD (canal 0 - pino RA0) na variável leitura_ad.
Lembre-se que o valor da resolução do AD do PIC18F452 é de 10 bits, e por esse motivo devemos utilizar uma variável
do tipo inteiro para armazenar o valor do A/D.
O registrador ADCON1 é responsável por configurar o modo de trabalho dos pinos com A/D. Através dos bits PCFG3,
PCFG2, PCFG1, PCFG0 configuramos o pino como A/D ou como I/O de uso geral.
Exemplo de programa:
Acompanhe o exemplo simples onde utilizamos um potenciometro a entrada RA0 e um display LCD 16x2 para
visualizarmos o valor da conversão do AD.
Exemplo de programa:
/****************************************************************************
Centro de Tecnologia Microgenios
Programa: Diplay_7_seg_01
Placa: KIT PICGENIOS
Objetivo: este programa tem por função ler o canal AD0 e escrever no lcd
o valor de conversão
*******************************************************************************
*/
char texto[16];
int temp_res = 0;
void main() {
trisd = 0; //define portd como saida
trise = 0; //define porte como saida
trisa.f0 = 1; //define pinos RA0 como entrada
ADCON1 = 0B00001110; //configura pino RA0 como entrada analógica e os demais com I/O digital
do
{
temp_res = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res
Delay_10us; //delay de 10 microsegundos
wordToStr(temp_res, texto); //converte valor da conversão do ad0 para string
lcd8_out(1,11,texto); //escreve no lcd o valor da conversão do ad0
}while (1);
Detalhes do programa:
char texto[16];
int temp_res = 0;
Depois iniciamos a função main() e definimos o sentido dos ports que participam do controle do LCD: Repare que
programamos o registrador ADCON1 com o valor 2, pois o porte do PIC é utilizado como I/O para controlar o LCD.
temp_res = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res
A função abaixo tem pertence ao compilador mikroC e tem por objetivo converter o valor de uma variável numérica do
tipo word em string. Esta conversão é necessária pois iremos escrever o valor numérico da variável temp_res, resultado da
conversão AN0, e escrever no LCD. A variável que assimilará o valor convertido em string é chamada de "texto".
Esquema elétrico:
Programa:
/****************************************************************************
Centro de Tecnologia Microgenios
Programa: Diplay_7_seg_01
Placa: KIT PICGENIOS
Objetivo: este programa tem por função ler o canal AD0 e AD1 e escrever no lcd
o valor de conversão
*******************************************************************************
*/
char texto[16];
int leitura_an0 = 0;
int leitura_an1 = 0;
void main() {
trise = 0; //define portb como saida
trisd = 0; //define portd como saida
ADCON1 = 0b00000100; //habilita canal A/D 0 e A/D1 do PIC
trisa = 0b00001111; //define pinos como entrada
do
{
leitura_an0 = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável leitura_an0
wordToStr(leitura_an0, texto); //converte valor da conversão do ad0 para string
lcd8_out(1,11,texto); //escreve no lcd o valor da conversão do ad0
leitura_an1 = Adc_read(1); //lê canal ad1 do PIC e salva valor na variável leitura_an1
leitura_an1 = leitura_an1 / 2.048; //ajusta a escala de conversão do sensor de temperatura
wordToStr(leitura_an1, texto); //converte valor da conversão do ad1 para string
lcd8_out(2,11,texto); //escreve no lcd o valor da conversão do ad1
}while (1);
}
O o sensor de temperatura utilizado em nosso projeto é o LM35 fabricado pela empresa National Semicondutores. Este
circuito integrado é um sensor de temperatura linear cujo valor de saida de tensão é diretamente proporcional à
temperatura. Sua escala já é calibrada em graus celsius com saida de 10mV / ºC no ranger minimá de - 55 ºC a +150 ºC.
A resolução do A/D de nosso microcontrolador é de 10 bits e em nosso programa utilizamos a tensão de referencia interna
do A/D (5V).
Resolução do PIC:
5V (1024 - 1) = 4,8876 mV
Logo teremos
10 / 4,8876 = 2,048
Em nosso programa arrendondamos o valor 2.046 para 2 para que nosso programa não ultrapasse o valor limite demo do
compilador (2Kbyte).
leitura_an1 = adc_read(1); //lê canal ad1 do PIC e salva valor na variável leitura_an1
leitura_an1 = leitura_an1 / 2.048; //ajusta a escala de leitura do sensor lm35.
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2007. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem prévio aviso.
Maiores informações: suporte@microgenios.com.br
Canal PWM do PIC
Introdução
Os controles de potência, inversores de freqüência, conversores para servomotor, fonte chaveadas e muitos outros circuitos utilizam a tecnologia do
PWM (Pulse Width Modulation) ou Modulação de Largura de Pulso como base de seu funcionamento.
Inversores de Freqüência
PWM é a abreviação de Pulse Width Modulation ou Modulação de Largura de Pulso. Para que se entenda como funciona esta tecnologia no controle de
potência, partimos de um circuito imaginário formado por um interruptor de ação muito rápida e uma carga que deve ser controlada, conforme a
figura abaixo:
Quando o interruptor está aberto não há corrente na lâmpada e a potência aplicada é nula. No instante em que o interruptor é fechado, a carga
recebe a tensão total da fonte e a potência aplicada é máxima.
Como fazer para obter uma potência intermediária, digamos 50%, aplicada à carga? Uma idéia é fazermos com que a chave seja aberta e fechada
rapidamente de modo a ficar 50% do tempo aberta e 50% fechada. Isso significa que, em média, teremos metade do tempo com corrente e metade
do tempo sem corrente.
A potência média e, portanto, a própria tensão média aplicada à carga é neste caso 50% da tensão de entrada.
Veja que o interruptor fechado pode definir uma largura de pulso pelo tempo em que ele fica nesta condição, e um intervalo entre pulsos pelo tempo
em que ele fica aberto. Os dois tempos juntos definem o período e, portanto, uma freqüência de controle. A relação entre o tempo em que temos o
pulso e a duração de um ciclo completo de operação do interruptor nos define ainda o ciclo ativo.
Variando-se a largura do pulso e também o intervalo de modo a termos ciclos ativos diferentes, podemos controlar a potência média aplicada a uma
carga. Assim, quando a largura do pulso varia de zero até o máximo, a potência também varia na mesma proporção (duty cycle), conforme está
indicado na figura abaixo:
Este princípio é usado justamente no controle PWM: modulamos (variamos) a largura do pulso de modo a controlar o ciclo ativo do sinal aplicado a
uma carga e, com isso, a potência aplicada a ela.
O microcontrolador PIC18F442 possui internamente 2 módulos CCP (capture/Compare/PWM Module), CCP1 e CCP2. Podemos manipular com grande
facilidade as instruções para geração de sinal PWM no mikroC. Acompanhe:
Pwm_Init
Pwm_Change_Duty
Pwm_Start
Pwm_Stop
//Sintaxe
Pwm_Init(valor_da_freqüência)
onde:
Exemplo:
A través da função Pwm_Change_Duty() podemos controlar o duty cycle do sinal PWM. O valor do duty cycle varia de 0 a 255, onde "0" é igual a 0%, "127" igual a 50% e "255" igual a
100%.
Sintaxe:
Pwm_Change_Duty(valor_duty_cycle)
onde:
valor_duty_cycle: valor do tipo char (0 à 255) que determina a porcentagem do duty cycle PWM.
Exemplo:
No caso de configurarmos o duty conforme a figura acima, devemos carregar o seguinte valor para:
Duty de 10%
Pwm_Change_Duty(25); // carrega valor 26 pois : (10% * 255) / 100 = 25,5 , como somente podemos colocar valores inteiros entre 0 a 255, o valor será arrendondado para 25
Duty de 50%
Pwm_Change_Duty(127); // carrega valor 127 pois : (50% * 255) / 100 = 127,50 , como somente podemos colocar valores inteiros entre 0 a 255, o valor será arrendondado para 127
Duty de 90%
Pwm_Change_Duty(229); // carrega valor 229 pois : (90% * 255) / 100 = 229,50 , como somente podemos colocar valores inteiros entre 0 a 255, o valor será arrendondado para 229
Através da função Pwm_Start(), damos início a geração do sinal PWM no PIC, e através da função Pwm_Stop() finalizamos a geração do sinal Pwm.
Sintaxe:
Nem todos os PIC possuem um segundo módulo CCP2, para os PIC que possuem este segundo módulo ou mais módulos, basta acrescentar o número 1 ou 2 nas funções para informar o
módulo que está sendo programado:
Exemplo:
Pwm1_Init
Pwm1_Change_Duty
Pwm1_Start
Pwm1_Stop
As funções acima faz referência ao módulo CCP2 do PIC e possue configuração identica a função do módulo CCP1 estudado acima.
Exemplo de programa:
Para entendermos melhor o funcionamento da função Pwm do mikroC, vamos estudar um exemplo de programa simples, acomanhe:
Programa:
void main() {
Pwm_init(5000);
Pwm_Change_Duty(127);
Pwm_Start();
while(1);
}
No programa acima configuramos o módulo CCP1 do PIC para trabalhar como PWM com freqüência de 5Khz e duty cycle de 50%, conforme gráfico abaixo:
No qual:
Segundo Programa
Programa:
void main() {
Pwm1_init(5000);
Pwm1_Change_Duty(127);
Pwm1_Start();
while(1);
}
repare que o programa acima tem a mesma função do programa anterior, a única diferença é que colocamos o número 1 nas funções para indicar que estamos trabalhando com o segundo
módulo CCP do PIC, ou seja, o módulo CCP2.
Vamos elaborar um programa em C cuja finalidade é carregar na função Pwm_change_duty() o valor lido do conversor AN0 do PIC, ou seja, iremos ler constantemente o valor do AD AN0
do PIC, tratar o valor númerico da conversão para que fique na escala de 0 a 255, pois esta é a escala de 0% a 100% de duty do PWM. A saída PWM do PIC controlará a velocidade de
rotação de uma ventoinha.
Esquema:
Programa:
/****************************************************************************
Centro de Tecnologia Microgenios
Programa: Leitura_AD_e_PWM
Placa: KIT PICGENIOS
Objetivo: Controlar uma ventoinha via PWM através da entrada AD0.
*/
void main() {
do // rotina de loop
{
a = Adc_Read(0); //lê canal ad0 e salva em temp_res
a = (a * 0.24); //converte valor para o duty cycle
Pwm_Change_Duty(a); //envia o valor lido de "a" para o módulo CCP1 pwm
Delay_10us; //aguarda 10us
}
while (1);
O programa exemplo foi compilado no mikroC e simulado no programa de simulação PROTEUS (www.labcenter.co.uk).
Os Timers/Counters
Os timers são ferramentas internas dos microcontroladores em geral que servem para contagem de tempo, eventos,
temporização entre outras funções.
TIMER0
TIMER1
TIMER2
TIMER3
TIMER0
O valor do prescaler pode ser configurado a partir dos bits T0PS2, T0PS1 e T0PS0 do registrador T0CON (TIMER0
CONTROL REGISTER);
O prescaler passa a ser uma importantíssima ferramentas do timer, pois através dele conseguimos gerar tempos
muito maiores.
Quando o TIMER0 é configurado para operar no modo de 8 bits, podemos efetuar contagens de 0 a 255 (limite
da capacidade para 8 bits). Quando a contagem chega até seu valor máximo de 255, o próximo pulso acarretaria o que
chamamos de "estouro de contagem", fazendo com que o valor de contagem de início novamente a partir do 0 (zero).
No caso anterior, caso tenhamos a interrupção do TIMER0 habilitada, no momento que ocorre o "estouro de
contagem", seria gerado um pedido de interrupção do TIMER0.
No modo 16 bits do TIMER0, seu funcionamento é igual ao modo de 8 bits, porém neste cado a faixa de
contagem é de 0 a 65535.
Os valores de iniciais de temporização/contagem devem ser carregados nos registradores especiais intitulado de
TMR0L (TIMER0 Module Low Byte Register) e TMR0H (TIMER0 Module Hight Byte Register);
Quando programamos os timers para atuarem como temporizadores, estamos considerando que os pulsos que
incrementam os registradores de contagem são proveniente do valor do oscilador / 4, ou seja, caso estivermos utilizando
um cristal de 4MHz, iremos incrementar em uma unidade os registradores de contagem a cada 1 us, pois 4Mhz/4 =
1MHz = 1us (microsegundos).
Dica:
Repare que a unidade resultante da divisão da Frequencia do oscilador / 4 (ciclo de máquina) esta em MHz ( unidade
de frequência), neste caso para sabermos o tempo (periodo), basta dividir 1 / seu valor.
Ex: 1 / (Fosc / 4 )
TMR0L é um registrador de contagem de 8 bits que possui a função de armazenar a parte baixa do valor de contagem
programada do TIMER0.
TMR0H é um registrador de contagem de 8 bits que possui a função de armazenar a parte alta do valor de contagem
programada do TIMER0.
Os registradores TMR0L e TMR0H juntos formam um único registrador de 16 bits, que nos permite uma contagem máxima de
0 a 65535.
INTCON é um registrador de 8 bits responsável pela configuração do modo de operação do TIMER0. Podemos definir através
desse registrador o valor do prescaler que desejamos acionar, o modo de operação de contagem de 8 ou 16 bits, seleção da fonte
de clock (interna ou externa) para o timer, seleção de disparo do timer através de borda de subida ou borda de descida do clock
externo no pino RA4/T0CK1.
Faça download do diagrama esquemático do TIMER0 disponível na informações complementar dessa unidade.
1 1 1 1:256
1 1 0 1:128
1 0 1 1:64
1 0 0 1:32
0 1 1 1:16
0 1 0 1:8
0 0 1 1:4
0 0 0 1:2
Configuração do Prescaler:
Como sabemos, através do prescaler conseguimos tempos maiores com os timers, para entendermos melhor sua
utilização acompanhe o exemplo abaixo:
Digamos que o ciclo de máquina no PIC sejá de 1us e o TIMER0 esteja configurado no modo 8 bits (contagem de
0 a 255) e sem o presacaler. O TIMER0 ira "estourar" sua contagem em 256us.
Agora digamos que para o mesmo anunciado anterior, configuramos e acionamos o prescaler para 1:2. Nosso
intervalo de "estouro" do TIMER0 não mais será 256us mas sim 512us.
Se ao invés de prescaler de 1:2 utilizarmos prescaler 1:32, o tempo agora será de 256us x 32 = 8192us.
Em que:
Ciclo de máquina: é o valor da relação entre: 1 / (Fosc / 4 ), onde Fosc é justamente a frequeência do cristal.
Obs: modo PLL desabilitado, iremos estudar esta função mais adiante.
Prescaler : é o fator de divisão programado. Podemos considerar como sendo um "redutor" de frequencia.
Modo 8/16bits: é o modo de contagem programado no TIMER0, para 8 bits o valor é 256, e para 16 bits, o valor será
de 65535.
Valor de contagem: é o valor de carregagem no registrador de contagem TMR0H eTMR0L.
Exemplo:
Precisamos ligar e desligar um relé a cada segundo ( um segundo ligado e um segundo desligado), estamos utilizamdo
um cristal de 8Mhz, utilizaremos para isso os recursos do Temporizador Timer0, acompanhe:
T0CON = 0B10000110; //configura timer modo 16 bits, com prescaler 1:128, fonte de clock interno
TMR0L = 0XF6; //carrega valores de contagem C2F6 equivale a
TMR0H = 0XC2; //carrega valores de contagem
obs: o valor 49910 surgio da conversão do valor em hexadecimal F6C2 para decimal
O registrador INTCON
O registrador INTCON possui diversar funções, entre elas a de habilitar algumas interrupções do PIC (veremos mais
adiante no nosso curso) e de armazenar os bits de estatus de estouro do TIMER0:
Iremos estudar todos esses bits mais adiante em nosso curso, pois eles tratam das configurações das interrupções, e
neste momento não é importante conhecer alguns deles. Vamos apresentar somente os bits que são utilizados nos TIMERS.
INTCON. GIEH = bit de acionamento da "chave geral das interrupções" e habilitação das interrupções de alta prioridade
0 - liga a chave geral das interrupções
1 - desliga a chave geral das interrupções
INTCON. GIEL = bit de habilitação das interrupções de baixa prioridade
0 - TIMER0 não ocorreu estouro de contagem (overflow)
1 - TIMER0 ocorreu estouro de contagem (overflow). Este bit deve ser apagado por software.
Conhecemos os registradores responsáveis pela configuração do TIMER0 do PIC, agora vamos configurá-los:
Vamos nos recordar da fórmula do TIMER0:
Exemplo 1 :
Se tivermos conectado ao nosso PIC um cristal de 8 MHz e o TIMER0 seja programado como temporizador, com prescaler de
1:4, modo 8 bits e contagem inicial em TMR0L = 0, teremos então:
Exemplo 2 :
Se tivermos conectado ao nosso PIC um cristal de 8 MHz e o TIMER0 seja programado como temporizador, com prescaler de
1:256, modo 16 bits e contagem inicial em TMR0L = 0 e TMR0H = 0, teremos então:
vamos supor que desejamos que um led conectado ao pino RB0 do PIC pisque em intervalos de 1 segundo (ligado e
desligado) utilizando os recursos de temporização do TIMER0.
Cristal: 8Mhz
PIC18F452
TIMER0 / MODO 16BITS
tempo de estouro do TIMER0 = ciclo de máquina x prescaler x (modo 8/16 bits - valor de contagem do TIMER0)
logo:
1 000 0000 = 0,5 * 16 * (65536 - X)
x = 59464
Concluimos que o valor de carregagem em TMR0L e TMR0H deverá ser de 59464, ou seja, TMR0L = 0X48; , TMR0H =
0XE8; (valores 59464 convertido em hexadecimal é igual a E848)
T0CON = 0b10000011; //configura temporizador 16 bits, com prescaler ativado em 1:16, clock interno
TMR0L = 0x48; //carrega valores de contagem em TMR0L - registrador baixo de contagem
TMR0H = 0xE8; //carrega valores de contagem em TMR0H - registrador alto de contagem
O programa abaixo tem por função configurar o modo de trabalho do TIMER0. Repare que o registrador T0CON foi
configurado da seguinte forma:
O programa seguinte tem por objetivo alterar os estados dos leds conectados ao PORTB em intervalos de 1 segundo.
Hardware:
Cristal: 8 Mhz
Microcontrolador: PIC18f452
Temporizador: Timer0
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER0 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb em
intervalo de 1 segundo (ligado e desligado) utilizando o TIMER0 do PIC.
Modo programado: 16 bits, prescaler 1:128
***********************************************************************/
do {
if (intcon.tmr0if == 1) { //se o flag de estouro do TIMER0 for igual a 1, então
PORTB = ~PORTB; // inverte o estado do portb
TMR0L = 0xF7;
TMR0H = 0XC2;
Iintcon.tmr0if = 0; // apaga flag de entouro do TIMER0
//para uma nova contagem
}
} while(1); // loop
}
tempo de estouro do TIMER0 = ciclo de máquina x prescaler x (modo 8/16 bits - valor de contagem do TIMER0)
tempo de estouro = 0,5 * 128 * (65536 - 49911)
Tempo de estouro = 1.000,000 us ou 1 segundo
Repare que nosso TIMER0 já foi configurado e iniciou a contagem dos pulsos de ciclo de máquina. Agora precisamos
monitorar o bit de estouro do TIMER0, pois não sabemos a que momento o estouro vai ocorrer, o que sabemos é que vai levar 1
segundos para ocorrer o estouro, ou seja, o bit TMR0IF vai para 1. Para isso, utilizaremos o comando de tomada de decisão IF,
que terá a seguinte função:
Se o bit de estouro intcon.tmr0if for igual a 1, representa que o TIMER0 estourou, e os comandos do bloco IF são
executados. Toda a vez que o TIMER0 estura, ou seja, o timer chega até 1 segundos, é invertido o estado do portb e reiniciado a
contagem do TIMER0.
Neste novo exemplo de programa, vamos programar o TIMER0 do PIC para trabalhar como contador de pulsos
externos. Neste modo, os pulsos externos, são aplicados no pino RA0/T0CK1 do PIC. Devemos contar apenas 10 pulsos
externos, que neste caso, configuraremos o TIMER0 do PIC no modo 8 bits com prescaler 1:1, e os pulsos serão lidos por borda
de descida. Ao completar a contagem de 10 pulsos, o led conectado ao pino RB7 do PIC deverá acender para sinalizar o fim da
contagem.
Esquema elétrico:
Para realizar o seguinte desafio é necessário configurar os seguintes registradores do TIMER0:
Programa:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o contador T0CK1 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb a cada
10 pulsos gerados no pino contador RA4/T0CK1 do PIC.
***********************************************************************/
Repare que o nos comandos abaixo que o registrador T0CON foi configurado como contador de pulsos externos, modo
de operação do TIMER0 de 8 bits, com prescaler 1:1.
O registrador de contagem TMR0L é o registrador onde será armazenado os valores de contagem dos pulsos externos,
e neste caso ele foi pré configurado com o valor 246, devido a necessidade de contarmos apenas 10 pulsos. Devemos lembrar
que os registradores de contagem do TIMER0 são incrementados em 1 unidade e contam para cima, neste caso, como
desejamos programar o TIMER0 para que a cada 10 pulsos no pino RA0/T0CK1 seja gerado um estouro, devemos carregar em
TMR0L o valor da diferença entre o valor máximo de contagem para o modo 8 bits, que é 256, pelo valor da quantidade de
pulsos a ser contado, que neste cado é 10. Então teremos:
256 - 10 = 246
O TIMER1:
Realizamos nas unidades passadas um estudo não muito aprofundado sobre as funções e características dos TIMERS
do PIC. Agora chegou o momento de estudarmos mais profundamente os recursos e a programação dos registradores e modos
de trabalho desses temporizadores e contadores.
O TIMER1 pode operar como temporizador ou como contador de 16 bits, suas características são muito parecida com a
do TIMER0.
Dizemos que o timer está operando como temporizador quando a referência do clock de incremento da contagem é
realizada pelo clock interno do PIC, e dizemos que o timer esta operando como contador quando a referência do clock de
incremento da contagem é proveniente de um clock externo ao PIC. (pulso aplicado no pino RB6/T1OSO/T1CK1).
P1R1: é um registrador onde é armazenado os bits de status das interrupções e estouro dos timers.
P1E1: é um registrador de 8 bits onde é habilitado as interrupções do PIC.
TMR1L é um registrador de contagem de 8 bits que possui a função de armazenar a parte baixa do valor de contagem
programada do TIMER0.
TMR1H é um registrador de contagem de 8 bits que possui a função de armazenar a parte alta do valor de contagem
programada do TIMER0.
Os registradores TMROL e TMR0H juntos formam um único registrador de 16 bits, que nos permite uma contagem
máxima de 0 a 65535.
T1CON é um registrador de 8 bits responsável pela configuração do modo de operação do TIMER1. Podemos definir
através desse registrador o valor do prescaler que desejamos acionar, o modo de operação de contagem de 8 ou 16 bits, seleção
da fonte de clock (interna ou externa) para o timer, seleção de disparo do timer através de borda de subida ou borda de descida
do clock externo no pino RB6/T10S0/T1CK1.
1 1 1:8
1 0 1:4
0 1 1:2
0 0 1:1
T1OSCEN: Habilitação do oscilador externo de baixa frequeência nos pinos T1OSO e T1OSI
0 - Oscilador desligado
1 - Oscilador Ligado
T1SYNC: Controle do sincronismo interno. Caso TMR1CS = 0, esse bit é descartado
0 - Sincronismo ligado
1 - Sincronismo desligado
TMR1CS: Bit de seleção de clock;
0 - A base de clock para o TIMER1 é interna (Fosc/4);
1 - Clock externo no pino RC0/T1CK1;
A figura 01 apresenta o diagrama de funcionamento do TIMER1 operando com o oscilador de baixa frequência.
Figura 01
Exemplo de programa:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER1 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb em
intervalo de 0,5 segundo (ligado e desligado) utilizando o TIMER1 do PIC.
Modo programado: 8 bits, prescaler 1:16
***********************************************************************/
void main() //função principal do programa
{
TRISB = 0; //define portb como saida
T1CON = 0B10110001; //liga TIMER1, prescaler 1:8, modo 16bits.
PIR1.TMR1IF = 0; //apaga flag de estouro do TIMER1
do {
if (PIR1.TMR1IF == 1) //se flag estiver em 1, representa que houve o estouro do timer1
{
PORTB = ~PORTB; //inverte o valor do portb
TMR1L = 0; //recarrega valor de contagem baixa do timer1
TMR1H = 0; //recarrega valor de contagem alta do timer1
PIR1.TMR1IF = 0; //resseta flag de estouro do timer1 para uma nova contagem.
}
} while (1);
}
O TIMER2 :
O TIMER2 é um timer de 8 bits com recarga automática. Esse TIMER tem um registrador de configuração, um de
contagem e outro de comparação. Ele possui um registrador de contagem de 8 bits ( 0 a 255) chamado TMR2.
Diferentemente dos outros timers, o TIMER2 possui um prescale e um postscaler. Os registradores especiais responsável pela
configuração do TIMER2 são:
Dizemos que o TIMER2 é um timer com recarga automática pois quando o valor carregado em PR2 é igual ao de
contagem TMR2, o valor de TMR2 é zerado e inicia-se uma nova contagem, ou melhor dizendo, temporização.
Através do registrador T2CON, podemos configurar o modo de operação do TIMER2, tais como: valor do prescale e
postcale e ligar ou desligar o timer2.
Faça download do diagrama esquemático do TIMER3 disponível na informações complementar dessa unidade.
O funcionamento do postcale é muito semelhante ao prescaler, sua diferença básica está na contagem. Em vez
de contar pulsos de ciclos de máquina, o postcale conta n comparações do TIMER2 com PR2. Após n comparações, o flag
de estouro do TIMER2 é sinalizado com nível lógico 1.
0 - TIMER2 desligado
1 - TIMER 2 ligado
0 0 1:1
0 1 1:4
1 x 1:16
X pode ser 1 ou 0
Para exemplificar, vamos estudar um programa que tem como função piscar um led conectado ao pino RB0 do PIC em
intervalos de 1 segundo (ligado e desligado). Neste exemplo iremos utilizar o TIMER2 com ajuste de prescale e postcale para
entendermos o funcionamento.
Esquema elétrico:
Programa:
Para calcularmos o tempo de estouro do TIMER2 utilizamos as seguintes contas (observe que estamos utilizando um cristal
externo de 4MHz):
Exemplo de Programa:
/***************************************************************************
Microgenios soluções eletrônica Ltda
Programa: Pisca Pisca utilizando o TIMER2
Compilador: MikroC
Objetivo: Este programa tem por objetivo piscar o led conectado ao pino RB0 do PIC em intervalos de 1
segundo (ligado / desligado) APROXIMADAMENTE.
***************************************************************************/
while (1)
{
if (pir1.tmr2if == 1) //se o TIMER2 estourar os comandos serão executados
{
i++; //foi criado a variável i para que somente depois de
//15 estouros do TIMER2, a subrotina de inversão do
//estado do led seja chamada.
//a variável i é incrementada em um unidade a cada
//estouro do TIMER2
if (i > 15) //caso i seja maior que 15, então chama subrotina de
{
inverte_led(); //inversão dos leds
i = 0; //zera novamente i para uma nova contagem
}
PIR1.TMR2IF = 0; //apaga o bit de sinalização de estouro do TIMER2
//para inciar uma nova contagem
}
}
}
O TIMER3 :
O TIMER3 é um temporizador e contador de 16 bits. Possui internamente dois registradores de 8 bits, TMR3L e
TMR3H, que juntos formam um registrador de 16 bits (contagem de 0 a 65535).
Os registradores relacionados com o TIMER3 são:
Através do registrador T3CON, podemos configurar o modo de operação do TIMER3, tais como: valor do prescale ,
ligar ou desligar o TIMER3, seleção de clock interno ou externo (contador) e fonte do timer para o módulo CCP do PIC.
Faça download do diagrama esquemático do TIMER3 disponível na informações complementar dessa unidade.
0 - Sincronismo ligado
1 - Sincronismo desligado
0 - TIMER3 desligado
1 - TIMER3 ligado
Para este exemplo, vamos programar o TIMER3 no modo 16 bits (contagem de 0 a 65535), prescaler de 1:8, clock
interno, cristal de 4Mhz e modo HSPLL desativado (multiplicador do oscilador), termos então:
Tempo de estouro do TIMER0 = valor de contagem do TIMER0 x PRESCALER X tempo de ciclo de máquina
T3CON = 0b10110001; //programa TIMER3 com prescaler 1:8, modo 16 bits, clock interno
TMR3l = 0; //inicia contagem a partir do 0
TMR3H = 0; //inicia contagem no modo 16 bits
O programa abaixo tem por função configurar o modo de trabalho do TIMER3. Repare que o registrador T3CON foi
configurado da seguinte forma:
Os registradores de contagem dos pulsos dos clocks internos do PIC são inicializados a partir do zero.
O TIMER0:
Realizamos nas unidades passada um estudo não muito aprofundado sobre as funções e caracteristicas dos TIMERS do PIC. Agora chegou o
momento de estudarmos mais profundamente os recursos e a programação dos registradores e modos de trabalho desses temporizadores e
contadores.
O TIMER0 pode operar como temporizador ou como contador. Esse periférico do PIC pode operar em dois modos:
Dizemos que o timer esta operando como temporizador quando a referencia do clock de incremento da contagem é realizada pelo clock interno do
PIC, e dizemos que o timer esta operando como contador quando a referencia do clock de incrremento da contagem é proveniente de um clock
externo ao PIC. (pulso aplicado no pino T0CK1
TMR0L é um registrador de contagem de 8 bits que possui a função de armazenar a parte baixa do valor de contagem programada do TIMER0.
TMR0H é um registrador de contagem de 8 bits que possui a função de armazenar a parte alta do valor de contagem programada do TIMER0.
Os registradores TMROL e TMR0H juntos formam um único registrador de 16 bits, que nos permite uma contagem máxima de 0 a 65535.
INTCON é um registrador de 8 bits responsável pela configuração do modo de operação do TIMER0. Podemos definir através desse registrador o
valor do prescaler que desejamos acionar, o modo de operação de contagem de 8 ou 16 bits, seleção da fonte de clock (interna ou externa) para o
timer, seleção de disparo do timer através de borda de subida ou borda de descida do clock externo no pino RA4/T0CK1.
ESTUDE O MATERIAL DA SEGUNDA UNIDADE DO CURSO PARA OBTER MAIORES INFORMAÇÕES SOBRE OS MODOS DE
TRABALHO DOS TIMERS.
Exemplo 01:
Vamos programar o TIMER0 para funcionar como temporizador programado para "estourar" sua contagem em 3 segundos. A cada estouro do
TIMER0 será alterado os estados dos leds ligado ao PORTD, e uma nova contagem de 3 segundo é reiniciada.
Configurações:
Cristal: 8 Mhz
Microcontrolador: PIC18F452
Vamos programar nosso TIMER0 passo a passo: Acompanhe a numeração da figura seguinte:
Numeração Função
1 Cristal externo
Chave seletora de função: define se o timer0 irá operar como
2
temporizador ou contador
PSA : Chave seletora que habilita ou desabilita a utilização do prescaler
3
(podemos considerar prescaler como um "redutor" de tempo)
4 Escala de ajuste do prescaler
Chave seletora do modo de contagem do TIMER0: formato 8 bits ou
5
formato 16 bits
Registradores de contagem TMR0L e TMR0H (dois registradores de 8
6
bits, formando 16 bits)
Bit de sinalização de estouro do TIMER0 (muita atenção no uso desse
7
bit)
8 Chave liga desliga do Timer0
void main(){
//************ configuração do Leds ************************
trisd = 0; //define portd como saida
portd = 0; //estado incial dos leds apagado
tmr0h = ?? ;
tmr0l = ??;
intcon.tmr0if = 0; //numero7: apaga flag de estouro do timer0, pois é fundamental para a sinalização do estouro
t0con.tmr0on = 1; //numero8: liga timer0
while(1){
if (intcon.tmr0if == 1){
portd = ~portd; //inverte o estado do portd
tmr0l = ??;
tmr0h = ?? ;
intcon.tmr0if = 0; //apaga flag de estouro do timer0 para uma nova contagem de tempo
}
}
}
tempo de estouro = ciclo de máquina * prescaler * (modo 8/16 bits - valor de contagem inicial em TMR0L e TMR0H)
logo teremos: (lembre-se que nosso objetivo é gerar um pisca pisca com tempo de 3 segundos, para isso converteremos 3 segundos para escala de
microsegundo: 3000000)
Logo teremos:
O valor 18661 é justamente o valor que devemos carregar em TMR0L e TMR0H. Para realizarmos com facilidade esta operação matemática, basta
simplesmente converter este valor decimal para hexadecima:
TMR0L = 0XE5;
TMR0H = 0X48;
Com certeza você deverá estar pensando da onde surgio o valor 1:128 do prescaler no exercício?? Na formula de temporização do Timer0, é mais
fácil encontrarmos o valor de carregagem nos registradores de contagem TMR0H e TMR0L do que o valor do prescaler, pois lembre-se que temos
algumas poucas opções de valores de prescaler, que já são pré-definidas no hardware do PIC. No exercício adotamos um valor alto do prescaler,
pois nossa temporização de 3 segundos é considerado um tempo alto para quem trabalha em escalas de us segundos.
pronto, nosso programa final esta pronto, basta compilarmos e visualizarmos seu funcionamento no kit de desenvolvimento.
Programa Final:
void main(){
//************ configuração do Leds ************************
trisd = 0; //define portd como saida
portd = 0; //estado incial dos leds apagado
intcon.tmr0if = 0; //numero7: apaga flag de estouro do timer0, pois é fundamental para a sinalização do estouro
t0con.tmr0on = 1; //numero8: liga timer0
while(1){
Exemplo 02:
Neste novo exemplo, iremos realizar um programa que irá ler os estados de 2 teclas ligada ao PIC a cada 20ms. Enquando nosso timer0 permanece
incrementando sua contagem, ficaremos alternando o estado de um led para simbolizar o funcionamento do programa.
Nosso hardware:
Configurações:
Cristal: 8 Mhz
Microcontrolador: PIC18F452
Esboço do programa:
Logo: (lembre-se que nosso tempo desejado agora é de 20ms, ou seja, 20 000us
portanto:
O valor 63036 é justamente o valor que devemos carregar em TMR0L e TMR0H. Para realizarmos com facilidade esta operação matemática, basta
simplesmente converter este valor decimal para hexadecima:
TMR0L = 0X3C;
TMR0H = 0XF6;
Programa:
void varredura_teclas(){
void main(){
//************ configuração do Leds ************************
trisb.f0 = 1; //define portb.rb0 como entrada
trisb.f1 = 1; //define portb.rb1 como entrada
trisb.f6 = 0; //define portb.rb6 como saída
trisb.f7 = 0; //define portb.rb7 como saída
portb.f6 = 0; //apaga led rb6
portb.f7 = 0; //apaga led rb7
intcon.tmr0if = 0; //numero7: apaga flag de estouro do timer0, pois é fundamental para a sinalização do estouro
t0con.tmr0on = 1; //numero8: liga timer0
while(1){
if (intcon.tmr0if == 1) varredura_teclas();
}
}
Obs: Podemos substituir o seguinte trecho do nosso programa por uma simples linha de código:
por:
t0con = 0b10000011;
Desafio: Faça você mesmo um programa de varredura de teclado operando o timer0 com tempo de varredura de 80ms.
Exercício 01
Vamos gerar um pisca pisca com intervalo de 1 segundo ligado e 1 segundo desligado:
Nosso hardware:
Cristal: 8 Mhz
Microcontrolador: PIC18F452
portanto:
O valor 49911 é justamente o valor que devemos carregar em TMR0L e TMR0H. Para realizarmos com facilidade esta
operação matemática, basta simplesmente converter este valor decimal para hexadecima:
TMR0L = 0XF7;
TMR0H = 0XC2;
Programa:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER0 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb em
intervalo de 1 segundo (ligado e desligado) utilizando o TIMER0 do PIC.
Modo programado: 16 bits, prescaler 1:128
cristal 8mhz
kitpicgenios pic18f
***********************************************************************/
do {
if (intcon.tmr0if == 1) { //se o flag de estouro do TIMER0 for igual a 1, então
PORTD = ~PORTD; // inverte o estado do portD
TMR0L = 0xF7; //parte baixa do valor de contagem
TMR0H = 0xC2; //parte balta do valor de contagem
intcon.tmr0if = 0; // apaga flag de entouro do TIMER0
//para uma nova contagem
}
} while(1); // loop
}
Nosso hardware:
Cristal: 8 Mhz
Microcontrolador: PIC18F452
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER0 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb em
intervalo de 1 minuto (ligado e desligado) utilizando o TIMER0 do PIC.
Modo programado: 16 bits, prescaler 1:128
cristal: 8mhz
kit picgenios pic18f
***********************************************************************/
do {
if (intcon.tmr0if == 1) { //se o flag de estouro do TIMER0 for igual a 1, então
a++; //incrementa uma unidade em "a"
if (a == 30){ //somente quando a variável "a" for igual a 30 o portb será invertido
PORTB = ~PORTB; // inverte o estado do portb
a = 0;
} //zera a para uma nova temporização
portanto:
O valor 49911 é justamente o valor que devemos carregar em TMR0L e TMR0H. Para realizarmos com facilidade esta
operação matemática, basta simplesmente converter este valor decimal para hexadecima:
TMR0L = 0XF7;
TMR0H = 0XC2;
Agora basta repetir o ciclo por 60 vezes para que altere os estados dos leds:
if (intcon.tmr0if == 1) { //se o flag de estouro do TIMER0 for igual a 1, então
a++; //incrementa uma unidade em "a"
if (a == 60){ //somente quando a variável "a" for igual a 30 o portb será invertido
PORTB = ~PORTB; // inverte o estado do portb
a = 0;
} //zera a para uma nova temporização
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER0 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do portb em
intervalo de 1 HORA (ligado e desligado) utilizando o TIMER0 do PIC.
Modo programado: 16 bits, prescaler 1:256
cristal: 8mhz
***********************************************************************/
do {
if (intcon.tmr0if == 1) { //se o flag de estouro do TIMER0 for igual a 1, então
a++; //incrementa uma unidade em "a"
intcon.tmr0if = 0; //apaga flag de estouro do timer0 para uma nova contagem
TMR0L = 0xdc; //carrega valor de contagem do timer0
TMR0H = 0x0B; //carrega valor de contagem do timer0
if (a == 450){ //somente quando a variável "a" for igual a 450 o portb será invertido
PORTB = ~PORTB; // inverte o estado do portb
a = 0;
} //zera a para uma nova temporização
}
} while(1); // loop
}
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2007. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem prévio aviso.
Maiores informações: suporte@microgenios.com.br
Exercícios resolvidos
1.0 Exercício 01
1.1 Exercício 02
1.2 Exercício 03
1.3 Exercício 04
1.4 Exercício 05
1.5 Exercício 06
1.6 Exercício 07
Ma q u i n a L i g a d a
Esquema elétrico:
/****************************************************************************
Centro de Tecnologia Microgenios
Programa: acionamento LCD modo 8 bits
*******************************************************************************
*/
void main() {
Lcd8_Config(&PORTC,&PORTB,2,1,0,7,6,5,4,3,2,1,0); //inicializa lcd modo 8 bits
Lcd8_Cmd(Lcd_Clear); //apaga lcd
Lcd8_Cmd(LCD_CURSOR_OFF); //desliga cursor do lcd
Lcd8_Out(1, 1, "Maquina Ligada"); //escreve mansagem na linha 1, coluna 1 do lcd
while (1);
}
Ma q u i n a
L i g a d a
/****************************************************************************
Centro de Tecnologia Microgenios
Programa: acionamento LCD modo 8 bits
*******************************************************************************
*/
void main() {
Lcd8_Config(&PORTC,&PORTB,2,1,0,7,6,5,4,3,2,1,0); //inicializa lcd modo 8 bits
Lcd8_Cmd(Lcd_Clear); //apaga lcd
Lcd8_Cmd(LCD_CURSOR_OFF); //desliga cursor do lcd
Lcd8_Out(1, 1, "Maquina"); //escreve mansagem na linha 1, coluna 1 do lcd
Lcd8_Out(2, 9, "Ligada"); //escreve mansagem na linha 9, coluna 2 do lcd
while (1);
}
P R OG R AMA C A O EM C
PARA P I C 1 8 F
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits
Perceba que neste modo 4 bits, somente 1 port do PIC controla todo o diaplay LCD
**************************************************************************
*/
void main() {
while(1);
}
Simulação no PROTEUS:
# # # LCD 1 6 X 2 # # #
A L F A N UME R I C O
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits
Perceba que neste outro modo 4 bits, 2 ports do PIC participam para controle do LCD
**************************************************************************
*/
void main() {
while(1);
}
Simulação no PROTEUS:
Exercício 05:
O programa seguinte tem por objetivo incrementar uma variável chamada contador enquanto a tecla RB0 (S1) estiver pressionada e decrementar esta mesma variável
quando a tecla RB1 (S2) estiver pressionada. O valor deverá ser monitorado através do display LCD 16x2, programado no modo 8 bits.
Dados do projeto:
Esquema elétrico:
Programa:
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_8bits_01.c
Este programa tem por objetivo escrever no LCD o valor de incremento e decremento da variável contador.
Cristal: 8Mhz
Kit PICgenios PIC18F
Compilador MikroC
**************************************************************************
*/
while(1){
}while(1);
}
ByteToStr
ShortToStr
WordToStr
IntToStr
LongToStr
FloatToStr
Substitua os códigos acima por uma das funções acima e veja o resultado.
Exercício 06:
Nosso próximo programa exemplo, tem por objetivo modificar o programa anterior (Exercício 05) de forma que o incremento do teclado
somente ocorra quando o operador pressionar e soltar a tecla.
Repare no programa anterior que enquanto estivermos pressionando a tecla, a variável contador será incrementada ou decrementada
(dependendo da tecla pressionada).
Dados do projeto:
Esquema elétrico:
Programa:
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits_01.c
Este programa tem por objetivo escrever o valor da variável contador no LCD
Tecla RB0 incrementará 1 unidade em contador.
Tecla RB1 decrementará 1 unidade em contador.
Cursor desligado
***************************************************************************/
while(1){
// *************** bloco de programa para incremento **********************************
if (button(&portb, 0, 30, 0)) estado_antigo1 =1; // se tecla RB0 for pressionada altera o valor da variável
if (button(&portb, 0, 30, 1)&& estado_antigo1){ //se tecla RB0 estiver solta e estado_antigo == 1 então...
contador++; //incrementa contador
shortToStr(contador, texto); //converte valor da variável contador para string e salva em Texto
Delay_ms(200);
Lcd_custom_Out(2, 12,texto); // escreve variável texto na 2º linha, 12º coluna do LCD
Lcd_Custom_Chr_CP('%'); //escreve na possição do cursor o simbolo de % Porcentagem
estado_antigo1 = 0; //zera variável estado_antigo1
}
else
// *************** bloco de programa para decremento **********************************
if (button(&portb, 1, 30, 0)) estado_antigo =1;
if (button(&portb, 1, 30, 1)&& estado_antigo){
contador--;
shortToStr(contador, texto); //converte valor da conversão do ad0 para string
Delay_ms(200);
Lcd_custom_Out(2, 12,texto); // escreve variável texto na 2º linha, 10º coluna do LCD
Lcd_Custom_Chr_CP('%');
estado_antigo = 0;
}
}
while(1);
}
Exercício 07:
Vamos programar agora nosso display LCD sem auxilio de nenhuma função pronta do MikroC. Em alguns momentos, iremos nos deparar
com situaçoes em que nosso display LCD não estão conectados diretamente aos pinos físicos do LCD, para esses casos, temos que nos
recorrer a programação um pouco mais trabalhosa. Acompanhe:
Dados do projeto:
LCD modo 8 bits
Microcontrolador PIC18F452
Kit PICgenios PIC18F - Módulo Profissional
Cristal: 8MHz
O programa tem por objetivo escrever duas simples mensagem no display LCD no modo 8 bits, conforme esquema do exercício 05.
Nosso Programa:
//Programa principal
void main ()
{
trisd = 0; //define portd como saida
trise = 0; //define porte como saída
adcon1 = 6;//configura todos os pinos que são A/D como I/O digital
trisb.f0 = 1; //configura pino RB0 como entrada de dados
trisb.f1 = 1; //configura pino RB1 como entrada de dados
//inicializa display
initlcd();
1.0 O TIMER1
O TIMER1:
Realizamos nas unidades passadas um estudo não muito aprofundado sobre as funções e características dos TIMERS do PIC. Agora
chegou o momento de estudarmos mais profundamente os recursos e a programação dos registradores e modos de trabalho desses
temporizadores e contadores.
Diferente do TIMER0, o TIMER1 somente pode operar no formato 16bits ( contagem de 0 a 65535) e possui menor ranger em seu
prescaler. podendo operar como temporizador ou como contador de 16 bits.
Não se esqueça: Dizemos que o timer está operando como temporizador quando a referência do clock de incremento da contagem é
realizada pelo clock interno do PIC, e dizemos que o timer esta operando como contador quando a referência do clock de incremento
da contagem é proveniente de um clock externo ao PIC. (pulso aplicado no pino RB6/T1OSO/T1CK1 no caso de operarmos com
timer1).
P1R1: é um registrador onde é armazenado os bits de status das interrupções e estouro dos timers.
P1E1: é um registrador de 8 bits onde é habilitado as interrupções do PIC.
TMR1L é um registrador de contagem de 8 bits que possui a função de armazenar a parte baixa do valor de contagem programada do
TIMER0.
TMR1H é um registrador de contagem de 8 bits que possui a função de armazenar a parte alta do valor de contagem programada do
TIMER0. Os registradores TMROL e TMR0H juntos formam um único registrador de 16 bits, que nos permite uma contagem máxima de
0 a 65535.
T1CON é um registrador de 8 bits responsável pela configuração do modo de operação do TIMER1. Podemos definir através desse
registrador o valor do prescaler que desejamos acionar, o modo de operação de contagem de 8 ou 16 bits, seleção da fonte de clock
(interna ou externa) para o timer, seleção de disparo do timer através de borda de subida ou borda de descida do clock externo no pino
RB6/T10S0/T1CK1.
Exemplo 01:
Para exemplificar a utilização do TIMER1 do PIC vamos analizar um simples exemplo de programa cujo objetivo é piscar 8 leds
conectados ao PORTD do PIC utilizando o TIMER1 como temporizador:
Hardware:
Descrição:
Microcontrolador: PIC18F452
Cristal: 8 MHz
Compilador: MikroC ver8.0
Programa:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Programa: Pisca Pisca utilizando o TIMER1 do PIC
Objetivo: Este programa tem por objetivo piscar os leds do PORTD em
intervalo de 0,5 segundo (ligado e desligado) utilizando o TIMER1 do PIC.
Modo programado: 8 bits, prescaler 1:16
***********************************************************************/
do {
if (PIR1.TMR1IF == 1) //se flag estiver em 1, representa que houve o estouro do timer1
{
PORTD = ~PORTD; //inverte o valor do portD
TMR1L = 0; //recarrega valor de contagem baixa do timer1
TMR1H = 0; //recarrega valor de contagem alta do timer1
PIR1.TMR1IF = 0; //resseta flag de estouro do timer1 para uma nova contagem.
}
} while (1);
}
O programa acima configura o TIMER1 para operar em 16 bits com prescaler 1:8, clock interno. A cada estouro do TIMER1, o estado dos
pinos do PORTD são invertido.
Sabendo que nosso microcontrolador esta trabalhando com um cristal externo de 8MHz, vamos calcular o tempo de estouro do TIMER1:
Configuração do TIMER1:
logo o tempo de estouro do TIMER1 do nosso exemplo de programa é de aproximadamente 262 milisegundos, o que nos
representa um pisca pisca em intervalos de 262 milisegundos, ligado/desligado.
Exemplo 02:
Agora que ja estamos entendendo o funcionamento dos TIMERS/COUNTERS, vamos elaborar um outro programa um pouco mais
complexo, acompanhe:
Objetivo: Quando pressionarmos a tecla ligada em RB0 (conforme hardware seguinte), o led ligado em RD0 deverá piscar 5 vezes a cada
150ms. Ao pressionarmos a tecla ligada em RB1, o led ligado em RD1 deverá piscar 4 vezes em intervalos também de 150 ms (ligado e
desligado). Para determinar a temporização deveremos utilizar o TIMER1 como temporizador.
Obs: A tecla deverá ser pressionada e solta para que o evento ocorra, ou seja, o evento deverá realmente ocorrer na passagem de nível 1
para 0.
Hardware:
Descrição:
Microcontrolador: PIC18F452
Cristal: 8 MHz
Compilador: MikroC ver8.0
Programa:
/**************************************************************************
centro de tecnologia microgenios
Kit PICgenios PIC18F
MicroICD zif
Compilador MikroC
Cristal 8MHZ
**************************************************************************
*/
void main() {
while(1){
}
while(1);
}
Clique aqui para baixar o programa acima:
Configuração do TIMER1:
Tempo de estouro:
logo:
devemos converter o valor 28036 para hexadecimal para simplificarmos nosso entendimento na locação do valor em TMR1L e TMR1H.
então:
TMR1L = 0X84;
TMR1H = 0X6D;
1º Neste pequeno trecho do programa, configuramos os pinos das teclas como entrada e os pinos dos leds como saida e declaramos as
variáveis utilizadas em nosso programa:
*******************************************************************
void main() {
char estatus = 0b00000011; //declara variavel estatus
char i; //declara variável i
trisb.rb0 = 1; //define pino RB0 como saida, pois trata-se de uma tecla
trisb.rb1 = 1; //define pino RB1 como saida, pois trata-se de uma tecla
2º O segundo bloco de programa, tem por objetivo varrer a tecla RB0. Caso essa tecla seja pressionada, iniciaremos um bloco de repetição
for e programaremos o TIMER1 para "estourar" a cada 262 ms.
***********************************************************************************
if (portb.f0 == 0 && estatus.f0 == 1 ){ //verifica se tecla RB0 foi pressionada
3º O bloco de program seguinte possui a mesma funcionalidade que o trecho de programa anterior, a única diferença esta no fato de
trabalharmos com a tecla RB1.
****************************************************************************
if (portb.f1 == 0 && estatus.f1 == 1 ){
**************************************************************************************
Exemplo 03:
Vamos imaginar agora uma situação real. Imagine que trabalhamos em uma empresa de embalagens, e em um determinado dia, seu
superior lhe fornece a seguinte missão:
Automatizar uma pequena esteira de produção, de forma que cada vez que uma embalagem passa por um sensor conectado a esteira de
produção é somado 1 unidade. Veja a animação seguinte:
Quando 30 caixas passarem por um sensor de presença (sensor infravermelho), a esteira de produção deverá ser desligada e uma
mensagem no display LCD deverá aparecer informando o operador para separar o lote de caixas, em seguinda, basta pressionar uma tecla
para que o processo continua do ponto onde parou.
Para realizar este projeto, devemos utilizar o modo contador de pulsos externos do TIMER1.
Hardware:
Descrição:
Microcontrolador: PIC18F452
Cristal: 8 MHz
Compilador: MikroC ver8.0
Programa:
/**************************************************************************
centro de tecnologia microgenios
programa exemplo: lcd_modo_4bits_01.c
este programa tem por objetivo mostrar no display lcd
cursor desligado
***************************************************************************/
#define esteira portb.f0
#define tecla_restart portb.f1
char texto[6];
void main() {
if (tmr1l < 10) esteira = 1; //se o valor do registrador de contagem do timer1 < 10
else //liga a esteira, caso contrário desliga a esteira
esteira = 0;
}
}
Clique aqui para baixar o programa acima:
1.0 Introdução
O que é Interrupção?
As interrupções são um evento externo ou interno que obriga o Microcontrolador a suspender suas atividades temporariamente,
para atender a esse evento que a interrompeu. Em resumo é uma ocorrência que faz o microprocessador parar sua rotina e desviar
para outro ponto do software, em que se localiza o serviço de interrupção que foi gerado pela ocorrência.
Para ligarmos as interrupções no microcontrolador, é necessário selecionar as interrupções desejadas no registrados SFR's
chamado IE (Interrupt Enable), bastando colocar o valor 1 para habilitar e 0 para desabilitar as interrupções que se deseja acionar.
Quando uma interrupção é acionada, o programa realiza uma instrução idêntica a CALL (chamada de sub-rotina), onde ocorre um
salto incondicional até a rotina da interrupção chamada. Nesse ponto do programa serão executados os comandos da interrupção
referente. Após o término do programa de interrupção o Mc volta a executar o programa principal do ponto seguinte em que parou
antes da chamada da interrupção.
Interrupção do TIMER0
Interrupção do TIMER1
Interrupção do TIMER2
Interrupção do TIMER3
Interrupção por mudança de estado (pinos RB4, RB5, RB6, RB7)
Interrupção externa INT0
Interrupção externa INT1
Interrupção externa INT2
Interrupção na conversão AD
Interrupção na recepção serial
Interrupção na transmissão serial
Interrupção do módulo CCP
Interrupção de escrita na EEPROM/FLASH
Interrupção por queda de tensão.
As prioridades de interrupção funcionam da seguinte maneira: Caso venhamos programar interrupções de alta e baixa
prioridade em nosso programa, e por um determinado momento seja solicitado ao mesmo tempo as duas interrupções,
a interrupção de alta prioridade será atendida primeiro. Ao término da execução da rotina de interrupção de alta
prioridade, automaticamente a rotina de baixa prioridade começa o seu tratamento. Quando uma rotina de baixa
prioridade estiver sendo executada e ocorrer uma interrupção de alta prioridade, a interrupção de alta prioridade será
atendida priomeiro, e ao seu término, a interrupção de baixa prioridade continuará a sua execução do ponto seguinte
onde parou.
Prioridades de Interrupção
Vamos supor que temos duas interrupções no Mc sendo solicitadas simultaneamente. Qual interrupção o Mc solicitará
primeiro? É por este motivo que devemos definir as prioridades das interrupções quando formos solicitá-las. No PIC18F
existe dois níveis de interrupção pré-estabelecida, alta prioridade e baixa prioridade:
Exemplo:
Caso o programador habilite no programa as interrupções externas Int1 e Serial, eu pergunto a você, qual dessas duas
interrupções será atendida primeiro, caso venham a serem solicitadas ao mesmo tempo?
Nos SFR's do PIC existe um registrador chamado IP (Interrupt Priority), cuja função é definir as interrupções que
vão ser atendidas primeiro, bastando colocar o valor 1 na interrupção desejada para maior prioridade e 0 para a menor
prioridade. Para interrupção com o mesmo nível de prioridade, o programador deverá informar por código qual a
interrupção que deverá ser atendida primeiro.
O registrador IE
As interrupções do nosso microcontrolador é parecido com a instalação elétrica de sua residência, acompanhe:
figura 01
Repare que para ascender a lampada de sua residência, é necessário que o interruptor esteja acionado (IE) e a chave
geral esteja acionada (GIEH).
Nos microcontroladores a interrupção funciona da mesma forma:
Existe um bit de habilitação ou desabilitação da interrupção do periférico chamado IE (interrupt enable) e um outro bit
de habilitação geral das interrupções chamado GIEH (interrupção geral)
O registrador GIEH
Como podemos visualizar na figura 01 (figura anterior), o bit GIEH é responsável por habilita e desabilitar todas as
interrupções do nosso microcontrolador.
O registrador GIEL
O bit GIEL é responsável em habilitar/desabilitar as interrupções de baixa prioridade do PIC.
O registrador IP
O bit intitulado "IP" é responsável por definir a prioridade das interrupções de cadas periférico, quando colocamos nível
lógico 1, habilitamos alta prioridade, caso seja 0, definimos como baixa prioridade.
O registrador IF
Todos os periféricos do nosso microcontrolador possuem um bit de sinalização de estado, neste caso denominado IF. A
interrupção do periférico somente ocorre quando este bit é setado durante a execução do programa.
O registrador RCON.IPEN
O registrador RCON.IPEN é responsável por definir os níveis de prioridade de interrupção do PIC. Nosso microcontrolador
da família PIC18 possuem recursos adcionais em comparação com os PIC16, quando configuramos este registrador
RCON.IPEN = 1; habilitamos o modo de alta e baixa prioridade de interrupção do PIC, presente na família PIC18F, e quando
definimos RCON.IPEN = 0;, desabilitamos este modo e herdamos as características do PIC16F com somente um nível de
prioridade de interrupção.
Exemplo:
RCON.IPEN = 0; // habilitamos o modo de alta e baixa prioridade de interrupção do PIC, presenta na família PIC18F
RCON.IPEN = 1; // desabilitamos o modo de alta e baixa prioridade de interrupção do PIC (herança da família PIC16F)
*************************************************************************************
1º repare que a interrupção geral INTCON.GIEH esta habilitada, a interrupção de baixa prioridade também esta habilitada, e
foi definido os dois níveis de prioridades (alta e baixa) atravé do registrador RCON.IPEN.
OBS: o registrador INTCON.GIEH possui mais de uma função, além de ser o responsável por habilitar/desabilitar todas
as interrupções (chave geral), é também responsável por habilitar as interrupções de alta prioridade no PIC. Você
encontrará no manual ou em exemplos de programas nomeclaturas a este registrador desta forma: INTCON.GIE. Na
verdade tanto faz escrever INTCON.GIEH ou INTCON.GIE que o compilador entenderá como sendo o mesmo bit. Isso é
válido também para o registrador INTCON.GIEL, que pode ser encontrado como INTCON.PEIE.
Nosso compilador possui duas funções reservadas para tratamento das rotinas de interrupção de alta prioridade e de baixa
prioridade, que são:
}
e
void interrupt_low(){ //função de tratamento de interrupção de baixa prioridade
Para entendermos melhor o funcionamento das interrupções, vamos analizar e estudar com detalhes a interrupção do
TIMER0, acompanhe:
Interrupção do TIMER0:
No programa abaixo estamos utilizando os recursos da interrupção do TIMER0 para inverter o estado lógico do PORTB. Cada interrupção
do TIMER0 ocorrerá a 3 segundos. Nosso objetivo neste programa é inverter o estado dos leds conectados ao PORTB a cada interrupção
do TIMER0, ou seja, a cada 3 segundos (ligado - desligado). O TIMER0 foi configurado no modo 16 bits, com prescaler 1:128 e o valor
contagem inicial do registrador de contagem é de 18661 (analise o cálculo do tempo de estouro do TIMER0 seguinte). Esta configuração
nos garante um delay de 3 segundos para que o PORTB seja invertido.
Hardware:
Características:
Cristal: 8Mhz
Microcontrolador: PIC18F452
Tempo de estouro do TIMER0 = ciclo de máquina * prescaler * (Modo 16 bits - valor do registrador TMR0L e TMR0H)
3.000.000 us = 0,5 * 128 * (65536 - x ) logo
x = 18661
O Programa:
/**************************************************************************************************
centro de tecnologia microgenios
programa: inversão lógica do portb
objetivo: este programa tem por objetivo alterar o estado lógico do portb do pic em intervalos de
1 segundos. utilizaremos o timer0 para geração do delay, no modo 16 bits, com prescaler 1:2 com
base no cristal de 8mhz.
**************************************************************************************************/
t0con = 0b10000110; // modo 16 bits, com prescaler 1:128, timer0 ligado e como temporizador
tmr0l = 0xe5; //valor inicial de contagem
tmr0h = 0x48; //valor inicial de contagem
intcon.tmr0if = 0; //apaga flag de estouro do timer0
intcon.gieh = 1; //habilita chave geral das interrupções
intcon.tmr0ie = 1; //habilita interrupção do timer0
rcon.ipen = 1; //define caracteristicas pi18f (2 níveis de prioridade de interrupção)
intcon2.tmr0ip = 1; //define interrupção do timer0 como alta prioridade
Diferente dos outros programas estudados até aqui, o programa acima utiliza o recurso das interrupções do microcontrolador PIC
utilizando o TIMER0. Repare que no programa acima, não precisamos ficar monitorar o bit sinalizador de estouro do TIMER0, pois,
quando este bit for setado, ou seja, quando o TIMER0 estourar, automaticamente o programa em execução é interrompido e desviado para
a rotina de interrupção. Após o término do tratamento das rotinas de interrupção, o programa retorna para o ponto seguinte de onde parou
anteriormente.
RCON
INTCON
INTCON2
INTCON3
PIR1, PIR2
PIE1 , PIE2
IPR1, IPR2
A função do registrador RCON na interrrupção é definir se será utilizado as prioridades altas e baixas das interrupções (0x08 e
0x18) ou no modo normal, compativel com a familia PIC16 em que somente há um vetor de interrupção.
O bit do registrador RCON responsável pela seleção de habilitação do modo de interrupção chama-se: IPEN.
Os registradores INTCON, INTCON2 e INTCON3 definem a habilitação das interrupções de baixa e alta prioridade, além de
definir se algumas interrupções externas serão utilizadas.
Os registradores P1R1 e P1R2 são responsáveis em armazenar os estados das interrupções. Quando uma interrupção foi
programada, é através dos bits desse registrador que poderemos monitorar o estado da interrupção (acionada ou não acionada).
Através dos registradores IPR1 e IPR2 definimos as prioridades altas e baixas das interrupções, caso esse sistema seja utilizado.
Resumidamente, cada interrupção é constituido de três bits que determinam a sua forma de funcionamento:
1 - bit para habilitar a interrupção desejada (interrupção do TIMER0, interrupção Int0, serial, etc), cuja indicação é chamada "IE",
exemplo: intcon.tmr0ie = 1;
1 - bit para monitor o estado da interrupção, também chamado de Flag, cuja indicação é chamada: "IF", exemplo: intcon.tmr0if =
0;
1 - bit de definição de prioridade de interrupção (alta ou baixa prioridade), cuja indicação é chamada: "IP", exemplo:
intcon2.tmr0ip = 1;
bit Evento
INTCON.GIE/GIEH
Habilitação geral das interrupções
(BIT <7>) = 1
INTCON.PEIE/GIEL
Habilitação Interrupção dos periféricos
(BIT<6>) = 1
INTCON.TMR0IE (BIT
Habilitação Interrupção doTIMER0
<5>) = 1
INTCON.INT0IE (BIT
Habilitação Interrupção INT0 externa
<4>) = 1
INTCON.RBIE
Habilitação Interrupção por mudança de estado
(BIT<3>) = 1
INTCON.TMR0IF
Flag de estouro do TIMER0
(BIT<2>) = 1
INTCON.INT0IF (BIT
Flag de interrupção externa INT0
<1>) = 1
INTCON.RBIF
Flag de interrupção por mudança de estado
(BIT<0>) = 1
No registrador INTCON, os registradores marcados em amarelo na tabela acima são bits de sinalização de interrupção.
bit Evento
INTCON2.RBPU (BIT <7>)
Habilita resistores de pull-up do portb
=0
INTCON2.RBPU (BIT <7>)
desabilita resistores de pull-up do portb
=1
INTCON2.TMR0IP (BIT
Alta prioridade da Interrupção do TIMER0
<2>) = 1
INTCON2.TMR0IP
Baixa prioridade da Interrupção do TIMER0
(BIT<2>) = 0
bit Evento
INTCON3.INT2IP (INTCON3 <7>) = 1 Alta prioridade na Interrupção externa INT2
INTCON3.INT2IP (INTCON3 <7>) = 0 Baixa prioridade na Interrupção externa INT2
INTCON3.INT1IP (INTCON3 <6>) = 1 Alta prioridade na Interrupção externa INT1
INTCON3.INT1IP (INTCON3 <6>) = 0 Baixa prioridade na Interrupção externa INT1
INTCON3.INT2IE (INTCON3 <4>) = 1 Habilita interrupção externa INT2
INTCON3.INT2IE (INTCON3 <4>) = 0 desabilita interrupção externa INT2
INTCON3.INT1IE (INTCON3 <3>) = 1 Habilita interrupção externa INT1
INTCON3.INT1IE (INTCON3 <3>) = 0 desabilita interrupção externa INT1
INTCON3.INT2IF (INTCON3 <1>) = 1 Bit de sinalização de Interrupção INT2
INTCON3.INT2IF (INTCON3 <1>) = 0 Bit de sinalização de Interrupção INT2
INTCON3.INT1IF (INTCON3 <0>) = 1 Bit de sinalização de Interrupção INT1
INTCON3.INT1IE (INTCON3 <0>) = 0 Bit de sinalização de Interrupção INT1
bit Evento
IPR1.PSPIP (BIT < 7 >) = 1 Alta prioridade na interrupção paralela
IPR1.PSPIP (BIT < 7 >) = 0 Baixa prioridade na interrupção paralela
IPR1.ADIP (BIT < 6 >) = 1 Alta prioridade na interrupção conversão AD
Baixa prioridade na interrupção conversão
IPR1.ADIP (BIT < 6 >) = 0
AD
Alta prioridade na interrupção de recepção
IPR1.RCIP (BIT < 5 >) = 1
serial
Baixa prioridade na interrupção de recepção
IPR1.RCIP (BIT < 5 >) = 0
serial
Alta prioridade na interrupção de
IPR1.TXIP (BIT < 4 >) = 1
transmissão serial
Baixa prioridade na interrupção de
IPR1.TXIP (BIT < 4 >) = 0
transmissão serial
IPR1.SSPIP (BIT < 3 >) = 1 Alta prioridade na interrupção MSSP
IPR1.SSPIP (BIT < 3 >) = 0 Baixa prioridade na interrupção MSSP
Alta prioridade na interrupção do módulo
IPR1.CCPIP (BIT < 2 >) = 1
CCP
Baixa prioridade na interrupção do módulo
IPR1.CCPIP (BIT < 2 >) = 0
CCP
IPR1.TMR2IP (BIT < 1 >) =
Alta prioridade na interrupção do TIMER2
1
IPR1.TMR2IP (BIT < 1 >) =
Baixa prioridade na interrupção do TIMER2
0
IPR1.TMR1IP (BIT < 0 >) =
Alta prioridade na interrupção do TIMER1
1
IPR1.TMR1IP (BIT < 0 >) =
Baixa prioridade na interrupção do TIMER1
0
bit Evento
IPR2.EEIP (BIT < 4 >) = 1 Alta prioridade na interrupção EEPROM
IPR2.EEIP (BIT < 4 >) = 0 Baixa prioridade na interrupção EPROM
Alta prioridade na interrupção por colisão no
IPR2.BCLIP (BIT < 3 >) = 1
barramento
Baixa prioridade na interrupção por colisão
IPR2.BCLIP (BIT < 3 >) = 0
no barramento
Alta prioridade na interrupção por queda de
IPR2.LVDIP (BIT < 2 >) = 1
tensão
Baixa prioridade na interrupção por queda de
IPR2.LVDIP (BIT < 2 >) = 0
tensão
IPR2.TMR3IP (BIT < 1 >) =
Alta prioridade na interrupção do TIMER3
1
IPR1.TMR3IP (BIT < 1 >) =
Baixa prioridade na interrupção do TIMER3
0
IPR1.CCP2IP (BIT < 0 >) = 1 Alta prioridade na interrupção CCP2IP
IPR1.CCP2IP (BIT < 0 >) = 0 Baixa prioridade na interrupção CCP2IP
No mikroC o tratamento das interrupções de mesma prioridades devem ser obedecidas e tratadas por ordem de tratamento através de laços
de tomada de decisão, como o exemplo seguinte:
void interrupt() {
if (intcon.tmr0if==1) { //testa se a interrupção chamada é do timer0
portb = ~portb; //inverte o estado do portb
tmr0 = 96;
intcon.tmr0f = 0;
}
else if (intcon.rbif==1) //caso contrário, verifica se a interrupção é por mudança de estado
portd = ~portd; //inverte o estado do portd
intcon.rbif = 0;
}
}
A interrupção do TIMER0 e do módulo RB (interrupção por mudança de estado) foram habilitadas com a mesma prioridade. No código,
a interrupção do TIMER0 possui maior prioridade na execução da interrupção que a interrupção por mudança de estado, pois o análise do
flag de sinalização do TIMER0 é realizado primeiro, e somente se, a condição for falsa, é que será testada a interrupção RB.
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2007. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem prévio aviso. Maiores informações:
suporte@microgenios.com.br
As Interrupções do PIC18Fxx2
Interrupção TIMER1:
***************** registradores de configuração geral das interrupções (válido para todas as interrupções do PIC)
*************************
INTCON.GIEH: habilita a chave geral das interrupções e habilita as interrupções de alta prioridade
INTCON.GIEL: habilita as interrupções de baixa prioridade
RCON.IPEN: herança da família PIC18F ou PIC16F (dois níveis de prioridade de interrupção ou somente um nível)
Para aprendermos a programar a interrupção do TIMER1, vamos desenvolver passo a passo um programa:
Nosso programa terá a função de ler o canal analógico AN0 (trimpot R2 conectado ao pino RA0) e mostrar seu valor no LCD, e a cada 2
segundos o estado do relé Q2 deverá ser alterado (ligado e desligado). Para realizarmos a temporização de 2 segundos utilizaremos o TIMER1
e sua interrupção. A cada interrupção será incrementada uma variável, e seu valor poderá ser visualizado no LCD.
Esquema elétrico:
Hardware:
Cristal: 8Mhz
Microcontrolador: PIC18F452
Tempo de estouro do TIMER0 = ciclo de máquina * prescaler * (Modo 16 bits - valor do registrador TMR0L e TMR0H)
200.000 us = 0,5 * 8 * (65536 - x ) logo
x = 15536
Primeiro devemos configurar o modo de operação do TIMER1. Para exemplificarmos, vamos configurar o TIMER1 em 16 bits com prescaler
1:8, clock interno e timer1 ligado.
T1CON = 0b10110001;
Segundo: devemos carregar os registradores de contagem do TIMER1: (vamos supor que desejamos carregar o valor 0 nesses registradores)
TMR1L = 0xB0;
TMR1H = 0x3C;
INTCON.GIEH = 1;
/**************************************************************************
centro de tecnologia microgenios
kit picgenios pic18f
***************************************************************************/
char contador = 0;
void main() {
char texto[10];
int leitura_ad0 = 0;
adcon1 = 0b00001110; // programa pinos de ra0 como a/d e os demais como i/o de uso geral
trise = 0; // programa porte como saida
trisd = 0; // programa portd como saida
trisb.f0 = 0; //define pino como saida
trisa.f0 = 1; //pino como entrada (ad)
while(1){
leitura_ad0 = adc_read(0);
wordtostr(leitura_ad0, texto); //converte valor da variável contador no lcd
lcd_custom_out(1, 10,texto); // escreve variável texto na 2º linha, 10º coluna do lcd
lcd_custom_chr_cp('%'); //escreve a string "qt" na corrente posição do cursor
}
}
1.0 Introdução
1.0 Exercício 01
1.1 Exercício 02
1.2 Exercício 03
Introdução:
Um dos grandes recursos dos temporizadores do PIC é a capacidade de gerar contagens de tempos precisos. Conforme estudamos nesta unidade,
descobrimos que é possível gerar interrupções com nossos temporizadores, e, mais legal ainda é que, essas interruções não afetam diretamente o
desenvolvimento do programa principal, ou seja, as interrupções dos temporizadores somente ocorrerão quando o tempo programado "estourar", durante este
intervalo de tempo podemos desenvolver diversas outras atividades com nosso microcontrolador.
A utilização das interrupções dos temporizadores é muito importante, pois através deles podemos desenvolver diversas atividades em paralelo com a
programação dos temporizadores:
Acompanhe um rascunho de um programa:
Repare na imagem acima que o programa de tratamento das interrupções dos timers ocorrem em paralelo com nosso programa principal. A principio, este
fato não causou grandes impacto para você acredito. Analise agora a proxima imagem:
Repare na figura acima que nosso programa agora assumiu várias funções. A rotina de interrupção do TIMER0 tem por objetivo lêr as teclas de um teclado,
acionar/desacionar leds e desligar relés, enquanto a rotina de interrupção do TIMER1 tem por objetivo lêr o canal A/D, escrever um dado na memória e
comparar valores no programa. Todas essas rotinas são realizadas no momento em que cada timer gera sua interrupção, ou seja, após o "estouro" da
contagem. Repare que nosso programa principal esta livre para executar suas rotinas.
Esta técnica de programação é muito utilizada pelos programadores, pois dessa forma criamos blocos de programas trabalhando em paralelo com o
programa principal.
Bom, agora que já aprendemos a importancia das interrupções, vamos desenvolver alguns exercícios sobre os temporizadores:
Programando as interrupções do TIMER0:
Exercício 01:
Vamos elabora um programa exemplo cuja finalidade será acionar e desacionar um led em intervalos de 0.5 segundos. Para realizar esta tarefa, vamos
utilizar o TIMER0 do PIC:
Programa:
/****************************************************************************
centro de tecnologia microgenios
programa: pisca_pisca por interrupção do timer0
placa: kit picgenios
cristal: 8 mhz
objetivo: piscar os leds do portd em intervalos de 1 segundo utilizando as
interrupções do timer0 do pic
****************************************************************************/
t0con = 0b10000101; //configura o timer0 no modo 16 bits com prescaler 1:64, timer como temporizador
tmr0l = 0xee; //parte menos significativa do resultdado da conta (65536 - 34285)
tmr0h = 0x85; //parte mais significativa do resultado da conta (65536 - 34285)
/*calculo matemático:
tempo de estouro = (65536 - valor de carregagem nos timers) x prescaler x ciclo de máquina
*/
Observação: Neste exemplo de programa estamos utilizando cristal de 8 MHz, diferente dos outros programas que desenvolvemos até este ponto do nosso
curso.
Ciclo de máquina = Fosc / 4 logo -> 8 Mhz / 4 = 2Mhz portanto -> 0.5 us.
Exercício 02:
Aproveitando os recursos do programa de interrupção do TIMER0 acima, vamos elaborar outro programa cuja função será incrementar uma variável do tipo
inteiro (int) a cada estouro do TIMER0 e enviar para o display lcd seu valor. Repare que agora os leds encontra-se no portB do PIC.
Esquema elétrico
Programa:
/****************************************************************************
centro de tecnologia microgenios
programa: pisca_pisca por interrupção do timer0
placa: kit picgenios
cristal: 8 mhz
objetivo: piscar os leds do portd em intervalos de 1 segundo utilizando as
interrupções do timer0 do pic. cada interrupção incrementará em 1 unidade a
variável contador e enviará o valor para o display lcd.
****************************************************************************/
char contador = 0; //define variável contador como inteiro
char texto[10]; //cria matris com 10 elementos do tipo char
/*calculo matemático:
tempo de estouro = (65536 - valor de carregagem nos timers) x prescaler x ciclo de máquina
*/
Exercício 03:
Vamos programar agora as interrupções do TIMER0 e TIMER1. A rotina de interrupção do TIMER1 terá por objetivo inverter os estados dos leds conectado
ao portb em intervalos de 1 segundos e a rotina de interrupção do TIMER1 terá objetivo inverter os estados dos leds conectados ao portd do PIC em
intervalos de 50 milisegundos.
Programa:
/****************************************************************************
centro de tecnologia microgenios
programa: pisca_pisca por interrupção do timer0 e timer1
placa: kit picgenios
cristal: 8 mhz
objetivo: piscar os leds do portb em intervalos de 1 segundo utilizando as
interrupções do timer0 do pic. a interrupção do timer1 terá como função
inverter os estado do portd em intervalos de 50 ms. timer0 terá maior prioridade
do que timer1.
****************************************************************************/
adcon1 = 6;
trisa.ra5 = 1;
trisc.f0 = 0;
portc.f0 = 0;
//configura timer0
t0con = 0b10000101; //configura o timer0 no modo 16 bits com prescaler 1:64, temporizador
tmr0l = 0xee; //parte menos significativa do resultdado da conta (65536 - 34285)
tmr0h = 0x85; //parte mais significativa do resultado da conta (65536 - 34285)
//configura timer1
t1con = 0b10010001; //configura timer1 como 16 bits, prescaler 1:2, timer1 ligado
tmr1l = 0xb0; //inicial contagem timer1
tmr1h = 0x3c; //carrega contagem timer1
while(1);
tempo de estouro = (65536 - valor de carregagem nos timers) x prescaler x (ciclo de máquina
logo: 31250 x 64 x 0.5 = 1000000 us ou 1 segundo.
######################################################################
tempo de estouro = (65536 - valor de carregagem nos timers) x prescaler x ciclo de máquina
*******************************************************************************/
No programa anterior acionamos a interrupção do TIMER0 e a interrupção do TIMER1. Repare que as rotinas de tratamento das interrupções são
responsáveis pela inversão do PORTB e PORTD. O acionamento das interrupções trabalham em paralelo com nosso programa principal, que neste caso, sua
única função era executar o laço de repetição do - while ().
1.0 O TIMER2
O TIMER2 :
O TIMER2 somente pode operar como TEMPORIZADOR (contagem baseada no ciclo de máquina). Diferente de outros temporizadores,
TIMER2 possui postcaler, que ao invés de contar pulsos do ciclo que máquina, conta n comparações do TMR2 com PR2. Após n comparações,
o flag de estouro do TIMER2 é sinalizado com nível lógico 1.
Perceba que na fórmula de tempo de estouro do TIMER2 o valor de PR2+1 é utilizado porque a contagem sempre começa do 0 (zero).
Exemplo: Calcule o tempo de estouro do TIMER2 sabendo que o valor do prescaler configurado é de 1:16, postscale:1:10, cristal utilizado
8Mhz, e PR2 = 200.:
logo teremos:
T2CON = 0B01001111;
PR2 = 200
Exemplo de programa:
Descrição de Hardware:
Microcontrolador: PIC18F452
Cristal: 8MHz
Esquema eletrônico:
Objetivo: Faça um programa para controle de uma forno elétrico. A cada 10 segundos o relé deverá pemanecer ligado e durante 20 segundos
deverá permanecer desligado. O display LCD 16x2 deverá apresentar em seu visor o valor de 0 a 100% lido de um sensor de temperatura,
conectado a entrada analógica AN0.
Obs: para simular o sensor de temperatura estamos utilizando um trimpot de 10K, conforme esquema eletrônico apresentado.
Programa:
/******************************************************************************
Centro de Tecnologia Microgenios
Proprama: Interrupção TIMER2
Objetivo: ligar relé a cada 10 segundos e desliga-lo a cada 5 segundos
Ler o sensor de temperatura em AN0 e mostrar valor no LCD
*******************************************************************************/
{
rele = ~rele; //inverte o estado do relé
estado = 0;
contador = 0;
}
PIR1.TMR2IF = 0; // resseta bit sinalizador de estouro do TIMER2 para uma nova interrupção
}
void main() {
char contador = 0;
char texto[10];
int leitura_ad0;
while(1)
{
leitura_ad0 = adc_read(0) * (100.0 /1023.0); //le canal AN0 e salva em leitura_ad0
wordToStr(leitura_ad0, texto); //converte o valor lido no AN0 em string
Lcd_custom_Out(2,7,texto); //envia para o lcd o valor string da conversão ad0
delay_us(10); //delay de 10us
}
As Interrupção externa
O microcontrolador PIC18F452 possui 3 pinos de interrupção externa, podendo ser acionadas por mudança de nível lógico 1 para 0
(borda de descida), ou de 0 para 1 (borda de subida).
As interrupção externas são independentes entre si, e estão multiplexadas com os pinos RB0 (INT0), RB1 (INT1) e RB2 (INT2). Para
que as interrupções externas funcionem, são necessário configurar e habilitar sua função no PIC. vamos estudar um pouco sobre cada
interrupção externa:
Obs: a interrupção externa INT0, por hardware, é de alta prioridade, não sendo possível defini-lá como baixa prioridade.
Diagrama de hardware:
Programa exemplo:
Para exemplificar o funcionamento da interrpção externa INT0, vamos criar um programa cuja função é acionar a interrupção externa
INT0 a cada pulso proveniente de um sensor inflavermelho. A interrupção será disparada por borda de descida. A cada disparo da
interrupção INT0, iremos incrementar uma unidade um uma variável chamada "contador" e enviar o valor dessa variável no portd.
Esquema elétrico:
Programa:
/******************************************************************************
Centro de Tecnologia Microgenios
Proprama: Interrupção TIMER1
Objetivo: incrementar uma unidade no portb a cada interrupção externa INT0
*******************************************************************************/
Rcon.ipen = 1; //define como dois niveis de prioridade de interrupção presente nos PIC18F
while(1); //fica em loop infinito aguardando o acionamento da interrupção por mudança de estado.
O funcionamento da interrupção externa INT1 é igual a da interrupção INT0, sua única diferença esta no fato dos registradores de
configuração serem outros:
Diagrama de hardware:
Exemplo de programa:
/******************************************************************************
centro de tecnologia microgenios
proprama: interrupção timer1
objetivo: incrementar uma unidade no portd a cada interrupção externa int1
*******************************************************************************/
while(1); //fica em loop infinito aguardando o acionamento da interrupção por mudança de estado.
/******************************************************************************
centro de tecnologia microgenios
proprama: interrupção timer1
objetivo: incrementar uma unidade no portd a cada interrupção externa int2
*******************************************************************************/
while(1); //fica em loop infinito aguardando o acionamento da interrupção por mudança de estado.
}
Centro de Tecnologia Microgenios - Curso de Microcontroladores PIC - Programação em C
Microgenios © 1998 - 2007. Todos os direitos reservados. É proibido cópia parcial ou integral desse material sem prévio aviso. Maiores
informações: suporte@microgenios.com.br
Técnicas avançadas da linguagem C
1.0 Protótipos de funções
1.1 Ponteiros
Introdução
Agora que já estudamos muitos tópicos de grande importância em nosso curso, vamos explorar mais dois itens da linguagem C, tais como:
Protótipos de funções
Ponteiros
Protótipos de funções:
Para melhor entendermos o conceito de protótipos de funções da linguagem C, vamos estudar um simples exemplo de programa em C,
acompanhe:
/******************************************************************************
Centro de Tecnologia Microgenios
Proprama exemplo
Objetivo: apresentar o conceito: protótipo de função
*******************************************************************************/
Repare que a função principal do programa, ou seja, a função main() encontra-se no final do nosso programa enquanto as demais funções
encontra-se no início. Com certeza você estará se perguntando: porque o programa é construido dessa maneira? porque não colocamos a função
main() no início do programa e as demais subrotinas (funções) no final do programa?.
Em um programa em C, não devemos chamar uma função antes do compilador saber que esta função existe. Por esse motivo, no momento da
compilação, faz necessário que as funções (subrotinas) do programa sejam colocadas no início do programa, para que o compilador a
reconheça.
O programa abaixo é o mesmo comentado anteriormente, sua única diferença esta no fato de invertermos a posição da
função main() para o início do programa.
/******************************************************************************
Centro de Tecnologia Microgenios
Proprama exemplo
Objetivo: apresentar o conceito: protótipo de função
*******************************************************************************/
//********************** função main() *****************************************
void main() {
trisb = 0;
aciona_led();
gera_delay();
while(1);
}
//************************** subrotina aciona led ******************************
void aciona_led(){
portb = 1;
}
Ao tentarmos compilar o programa acima no mikroC, será apresentado o seguinte erro de compilação:
Este erro se deve ao fato de do pré-compilador do mikroC, no momento da compilação, encontrar o comando de chamada de função
aciona_led();
e gera_delay(); antes de encontar a subrotina void aciona_led()e void gera_delay().
Para corrigirmos este problema, podemos utilizar os protótipos de funções no topo do nosso programa, cujo objetivo é informar ao pré-
compilador do mikroC quais são as funções de subrotinas do nosso programa, dessa maneira podemos colocar essas funções antes ou depois da
função main(), ou então espalhada em módulos ou outros arquivos linkados com nosso programa.
Para exemplificarmos os protótipos de funções, vamos corrigir nosso programa utilizando esse recurso:
/******************************************************************************
Centro de Tecnologia Microgenios
Proprama exemplo
Objetivo: apresentar o conceito: protótipo de função
*******************************************************************************/
Repare que o protótipo de função se constitui na declaração da própria função que vamos utilizar no programa, sem o bloco de comandos que
esta função irão executar.
Os protótipos de funções são de grande utilidade, uma vez que eles ajudam, evitando cometermos erros na codificação dos programas,
escrevendo códigos com parâmetros inadequados para uma função.
Ponteiro
Os ponteiros são tipos de dados muito utilizado na linguagem C, podemos utilizar seus recursos em aplicações complexas e de alta flexibilidade.
Resumidamente podemos dizer que um ponteiro nada mais é do que uma variável utilizada para guardar o endereço de outra variável, dizemos
que um ponteiro é um apontador de outra variável.
Para definirmos uma variável do tipo ponteiro, utilizamos o simbolo ' * ' (asterisco). Acompanhe o exemplo abaixo:
int *teste
char *soma
O primeiro declara uma variável teste do tipo int como ponteiro, e o segundo declara uma variável soma do tipo char
como ponteiro.
Em C os ponteiros também tem tipos, pois ao declararmos como ponteiros, devemos informar seu tipo de variável que
irá apontar.
Repare que os dois ponteiros criados acima não foram inicializados, isso significa que eles podem estar apontando para
qualquer endereço da memória. Para não cometermos nenhum erro na utilização de ponteiros, sempre é recomendado no
momento da criação de um ponteiro inicializa-los.
A linguagem C nos oferece o apontador (&), que é responsável por indicar a posição específica de uma variável na
memória.
variavel_soma = &teste;
int *endereco_soma;
int contador;
contador = 120;
endereco_soma = &contador;
*endereco_soma = 50;
Definimos uma variável ponteiro do tipo int chamada endereço_soma e uma variável do tipo int chamada contador. Na
linha de programa seguinte, é atribuido a variável contador o valor 120. Em seguida na variável ponteiro endereco_soma é
atribuido o ENDEREÇO de memória da variável contador. Dizemos agora que a a variável endereco_soma aponta para
a variável contador. Em seguida, atribui-se o valor 50 ao endereço apontado pela variável endereco_soma. Como
resultado, a variável contador passará a armazenar o valor 50.
Acompanhe o exemplo:
No código acima declaramos uma variável do tipo int chamada soma e a inicializamos com o valor 100; declaramos
também um ponteiro do tipo int chamado apontador. A expressão, &soma, atribui ao ponteiro o endereço da variável
soma. O ponteiro apontador, passa a apontar para a variável soma. Apartir de agora, podemos alterar o valor da variável
soma através do ponteiro apontador. Quando atribuimos ao ponteiro apontador o endereço da variável soma, significa
dizer que a variável apontador é a própria variável soma. Podemos então alterar o valor da variável soma através do
ponteiro apontador. Para isso, fariamos da seguinte maneira:
*apontador = 20;
Introdução
Como sabemos, nosso microcontrolador possui internamente um canal USART. Através desse canal serial
podemos nos comunicar serialmente com diversos dispositivos e equipamentos, entre eles o PC.
O compilador mikroC possui internamente funções que nos permite manipular com grande facilidade o canal
serial do PIC, vamos conhecer um pouco sobre o canal serial do PIC e seus registradores de configuração e seus
modos de trabalho.
Devemos nos lembrar que estamos estudando em particular o microcontrolador PIC18F442, mas as funções do
compilador mikroC não se restringe somente a este tipo de microcontrolador, mas praticamente todos os PICs que
possuem internamente um ou mais canais USART.
O canal USART do PIC18F442 é um canal de recepção e transmissão de dados (RX e TX) que pode ser
configurado como full duplex (pode receber e enviar dados ao mesmo tempo) para comunicação com PC´s por
exemplo, também conhecido como modo assincrono, ou half duplex, que pode ser utilizado como canal de
comunicação de dados entre A/D ou D/A, seriais EEPROM, etc, chamado de modo sincrono.
Os pinos multiplexados com o canal USART são RC6 (TX/CK) e RC7 (RX/DT)
Exemplo de aplicação: Modo full duplex - assincrono:
Modos de Comunicaçâo
Há duas maneiras para comunicação serial : modo síncrono e modo assíncrono. Modo
Síncrono — é necessário sincronismo entre os dois sistemas em comunicação. O
sincronismo é gerado por um grupo de bits, chamado de bits de sincronismo. Os bits são
recebidos pelo receptor que ajusta seu clock interno para receber o conjunto de bits
referentes aos dados. É possível receber qualquer quantidade de dados, de acordo com o
previsto no projeto. Após receber o último bit de dado, o transmissor envia um conjunto
de bits denominado bits de parada, que ao ser detectado pelo receptor informam-no que
acabaram os bits de dados.
Observe na figura que o stop bit é reconhecido pela transição de 1 para 0. Neste instante
o clock interno do sistema inicia uma varredura da linha de tempos em tempos para
detectar o nível da mesma. Ao receber o sétimo bit o sistema fica esperando o stop bit,
que é a transição de 0 para 1, ou a permanência em nível 1, se já estava em 1. Neste
ponto o sistema entra em repouso aguardando um novo start bit. Os sinais de
temporização e controles utilizados são gerados pelo hardware, especialmente
desenvolvido para este tipo de comunicação. Neste caso, deve-se garantir que os
sistemas transmissor e receptor operem com a mesma taxa de comunicação.
Canais de Comunicação
Canal half-duplex —ou semi-duplex, é o que possui elementos que tanto recebem como
transmitem os dados. As duas operações, recebimento e transmissão, não podem ser
feitas ao mesmo tempo. Temos então, uma comunicação nos dois sentidos mas não
simultâneos. O walkie-talkie é um exemplo deste tipo de comunicação.
Padrão RS 232
MAX 232
Introdução
Como sabemos, nosso microcontrolador possui internamente um canal USART. Através desse canal serial podemos nos comunicar serialmente com
diversos dispositivos e equipamentos, entre eles o PC.
O compilador mikroC possui funções de tratamento de comunicação serial, que vem a facilitar e acelerar o tempo no desenvolvimento de programas.
Basicamente possuimos 4 funções no mikroC para manipulação da USART do PIC, que são:
Usart_Init ; configura e inicializa os registradores do canal USART do PIC, assim como define o valor de
BAUDRATE (velocidade da comunicação) de trabalho do PIC.
Usart_Data_Ready ; esta função é utilizado para sabermos se algum byte chegou no buffer serial do PIC. Utilizamos esta
função antes de utilizarmos a função Usart_Read().
Usart_Read ; função que lê o valor armazenado no buffer serial do PIC. Toda vez que um dado chegar serialmente
no PIC, este byte será armazenado em um BUFFER interno no PIC, através dessa função do mikroC podemos lêr este dado
recebido.
Usart_Write ; esta função envia pela serial o valor do tipo BYTE programado pelo programador. É utilizado para
enviar um determinado byte pelo canal serial do PIC durante a execução do programa.
O programa seguinte tem como função enviar o caracterer " A " pelo canal serial do PIC com a taxa de velocidade de 9600 bps (bits por segundo).
Acompanhe o esquema elétrico abaixo:
Comunicação serial
Programa exemplo:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Objetivo: Este programa tem por objetivo enviar pela serial rs232 do kit o
caractere "A".
Baudrate 9600, N, 8, 1
*/
void main() {
USART_init(9600); //inicializa serial.
USART_Write('A'); //envia o caractere "A" pela serial do kit
while(1);
}
O programa acima tem unicamente a função de enviar por uma única vez o caractere 'A' pelo canal serial RS232 com velocidade de 9600 bps.
Programa detalhado:
O comando USART_init(9600)tem por função inicializar e determinar a velocidade de comunicação do canal serial do PIC, neste caso configuramos
para operar em 9600 bps, mas poderiamos, sem problema algum, configurar outras taxas de transferências, tais como:
110, 220, 300, 600, 1200, 2400, 4800, 9600, 14400, 19200, 38400, 56000, 57600, etc.
O comando USART_Write('A')tem a função de enviar pelo canal serial do PIC o caractere 'A'. Para utilizar esta função temos algumas restrições:
A função USART_Write() envia somente 1 byte pela serial quando ela é executada.
Exemplo:
USART_Write("MICROGENIOS") ; //A função de escrita na serial NÃO suporta envio de String dessa maneira.
USART_Write("A"); //Repare que o caracterer é precedido com aspas duplas, na linguagem C este
caratere é tratado como string. Neste caso, o caratere A é composto por 'A' + \0 por ser tratar de uma
string. Para enviar um caracterer necessário utilizarmos aspas simples: Ex: 'A'.
Para operar com a função USART_Write(), o modo mais "elegante", ou talvez, o modo "mais usual", é a utilização de ponteiros. Aprendemos nas lições
anteriores como manipular uma variável ponteiro.
Os ponteiros resumidamente podemos dizer que nada mais é do que uma variável utilizada para guardar o endereço de outra variável, dizemos que um
ponteiro é um apontador de outra variável.
Para exemplificar um programa de comunicação serial com ponteiros, vamos desenvolver um simples programa, que possui como objetivo, enviar a string
"microgenios" através da serial do PIC.
Programa:
/*********************************************************************
Centro de tecnologia Microgenios
Placa: Kit PICGenios
Baudrate 2400, N, 8, 1
**********************************************************************/
void main() {
do {
USART_Write(*i); //envia o caractere pela serial do kit
*i++; //incrementa contador e endereço apontado pelo ponteiro
delay_ms(100); //aguarda 100ms
} while (*i != '\0'); //verifica se ponteiro é igual a NULL
Analizando o programa acima, percebemos que foi definida uma variável ponteiro do tipo char chamada i. Quando definimos uma variável como ponteiro,
na verdade estamos apontando para um determinado endereço de memória do PIC. No comando unsigned char *i = "microgenios" definimos
a variável i ponteiro e do tipo char não sinalizada e a inicilizamos com a cadeia de caractere "microgenios". Para entendermos melhor como será armazenado
nossa cadeia de caracteres, analize a tabela abaixo:
endereço na memória 00h 01h 02h 03h 04h 05h 06h 07h 08h 09h 10h 11h 12h 13h 14h 15h 16h
dado na memória (caractere) m i c r o g e n i o s \0
Repare que possuimos na primeira linha da tabelas os endereços da memória onde nossa variável estará armazenada, e na segunda linha de programa, temos
os dados de nossa string armazenado seguenciamente na memória.
Quando declaramos um parâmetro entre aspas (ex: "microgenios"), o compilador sabe que essa forma é para declaração de strings e automaticamente inclui
em seu final o terminador ('\0' - NULL).
Podemos incrementar ou decrementar um ponteiro. Quando efetuamos este tipo de operação temos que ter em mente que o ponteiro vai apontar para o
proximo valor correspondente ao seu tipo de dado definido. Se, por exemplo, definimos uma variável ponteiro do tipo char, a cada incremento, estaremos
apontando para o próximo endereço de memória de um byte, e se incrementarmos uma variável ponteiro declarada do tipo long, fará com que o ponteiro
aponte para o próximo long, que é um tipo de dados de quatro bytes.
Com base no que vimos até agora, podemos conluir que a função USART_Write(*i) no programa exemplo, tem como objetivo enviar pelo canal serial
do PIC o dado apontado pelo apontador i. Repare que a cada envio de um caractere apontado pelo apontador i, este mesmo apontado é incrementado em 1
unidade, como o ponteiro i foi definido como byte, a cada incremento, i aponta para a próxima posição de memória que armazena um outro caractere.
Sempre antes de lermos o buffer serial do PIC através da função Usart_Read (), precisamos saber se existe algum byte lá, e para
isso, realizamos uma condição de teste com a função Usart_Data_Ready() no comando de tomada de decisão IF.
char rtx;
...
if (Usart_Data_Ready() == 1 ) { //verifica se existe algum byte para ler no buffer serial do PIC
rtx = Usart_Read(); //le o byte que chegou pela serial e a salva na variável rtx.
}
Repare no programa que utilizamos o comando IF para testarmos o retorno da função Usart_Data_Ready(). A função
Usart_Data_Ready() tem como retorno zero (0) quando o buffer serial do PIC encontra-se vazio e tem retorno igual a 1 (um)
quando temos no buffer do PIC algum byte armazenado.
Para exemplificarmos, vamos elaborar um programa de comunicação serial, cuja finalidade é ascender ou apagar um led
conectado em RD0 de acordo com o byte recebido pela serial do PIC. Quando o byte recebido for o caractere " a " o led deverá
ascender ou quando o byte for recebido for " b " o led deverá apagar. De início, vamos considerar o led no estado apagado.
Programa:
/************************************************************************
Centro de Tecnologia Microgenios
Programação C para microcontroladores PIC
Autor: Fernando Simplicio
Objetivo: este programa tem por objetivo ascender o led quando o pic recebir o
caractere ' a ' pela serial, e apagar este mesmo led quando receber o byte ' b '
pela serial.
Velocidade: 9600, 8, 1, N
KitPICgenios
Cristal: 4MHz
**************************************************************************/
void main() {
unsigned short int dt;
do {
if (Usart_Data_Ready()) { //verifica se algum byte chegou no buffer serial
dt = Usart_Read(); //lê o byte do buffer e salva na variável dt
Usart_Write(dt); //envia pela serial o valor do byte recebido
//Também conhecido como eco, normalmente
//reenviamos o byte recebido como confirmação do
//recebimento para o transmissor
}
switch(dt) {
case 'a': //caso o byte recebido seja o caracterer ' a ', então..
PORTD.F0 = 1; //acende o led
break; //finaliza a condição switch
case 'b': //caso o byte recebido seja o caracterer ' b ', então..
PORTD.F0 = 0; //apaga o led
break; //finaliza a condição switch
}
} while(1);
}
1.0 Introdução
Vamos apresentar um exemplo de programa, em que utilizaremos os recursos dos comandos de comunicação seriais do mikroC, para fazer a comunicação entre
o PIC e um PC (padrão IBM). Utilizaremos o HiperTerminal do Windows para transmitir e receber dados seriais entre ambos.
Primeiramente devemos nos certificar se o HiperTerminal do Windows está instalado no computador PC (IBM). O HiperTerminal é fabricado pela empresa
Hilgraeve e pode ser encontrado no site do fabricante (http://www.hilgraeve.com).
Para habilitar o HiperTerminal no Windows (98SE e XP), entre na pasta "arquivos de sistemas>instalar/remover programas> componentes/instalação do
windows>comunicação", e com o mouse habilite o ícone chamado HiperTerminal.
Configuração do HiperTerminal
1) Abra o HiperTerminal .
2) Nomeie a nova conexão de ProgSerial (adotaremos este nome somente para facilitar a
compreensão do exercício).
Figura 17.1
4) Nesta tela informamos a porta de comunicação serial que vamos utilizar para transmitir e Figura 17.3
receber dados.
Bits de parada = 8
Paridade = nenhum
Bits de parada = 1
Figura 17.4
O HiperTerminal está pronto e configurado para receber e enviar dados pela serial do PC. Não se esqueça de que devemos programar o Figura
microcontrolador com a mesma taxa de comunicação programada no HiperTerminal para não ocorrerem erros de comunicação. 17.5
Monte os circuitos conforme a figura 17.6 em um proto board, ou utilize o KITPICGENIOS (kit de desenvolvimento) comentado no início do nosso curso
para realização deste exercício.
Hardware
Figura 17.6
Precisamos do cabo serial para ligar o microcontrolador PIC (circuito da figura) no PC. A porta serial do PC é a antiga porta de conexão do
mouse/COM1/COM2.
Esquema elétrico do cabo serial para ser ligado na porta serial COM1 do PC.
Figura 17.7
Esquema elétrico do cabo serial para ser ligado na porta COM2 do PC.
Figura 17.8
Após a montagem dos circuitos eletrônicos, montagem e conexão do cabo serial no microcontrolador e no PC através da porta serial, vamos partir para o
terceiro e último passo do exercício, o programa de comunicação serial.
NOTA Para fazer o exemplo de programa seguinte, certifique-se que o HiperTerminal do windows esteja aberto e configurado, que os cabos de
comunicação serial RS232 estejam montados corretamente e conectado ao hardware conforme figura 17.6.
Neste painel devemos configurar a porta de comunicação do PC (COM1, COM2 ...), determinar o baudrate programado, o stop bit, paridades, e clicar no botão
Connect para iniciar a recepção ou transmissão de dados pela serial:
Para exemplificar a utilização do USART Terminal do mikroC, vamos elaborar um programa cuja finalidade é transmitir para o compilador mikroC uma
seguencia de três textos infinitamente. A velocidade da comunicação deverá ser a 2400 bps.
Programa:
/*********************************************************************
Centro de tecnologia Microgenios
Objetivo: este programa tem por objetivo enviar pela serial do PIC três textos.
Placa: Kit PICGenios
Baudrate 2400, N, 8, 1
Cristal = 4MHz
**********************************************************************/
void texto_i(){
do {
usart_write(*i); //envia pela serial o caracterer apostado pelo ponteiro
*i++; //incrementa contador e endereço apontado pelo ponteiro
} while (*i != '\0'); //verifica se ponteiro é igual a NULL
void texto_j(){
do {
usart_write(*j); //envia pela serial o caracterer apostado pelo ponteiro
*j++; //incrementa contador e endereço apontado pelo ponteiro
} while (*j != '\0'); //verifica se ponteiro é igual a NULL
void texto_h(){
do {
usart_write(*h); //envia pela serial o caracterer apostado pelo ponteiro
*h++; //incrementa contador e endereço apontado pelo ponteiro
} while (*h != '\0'); //verifica se ponteiro é igual a NULL
void main() {
while(1);
I2C
Esse novo barramento foi batizado pela empresa Holandesa (Philips) como
Inter IC ou I2C e possibilita a utilização de grande quantidade de
componentes padronizados, os quais podem realizar diversas funções,
além de possibilitar a troca eficaz de informações entre eles. Esse novo
barramento obteve uma grande aceitação do mercado, tornando-se um
dos mais utilizados e isso foi determinate para a crianção da versão 2.0,
lançada em 1998.
O barramento I2C
As linhas SDA como SCL são bidirecionais e devem ser ligadas ao positivo da alimentação
através de uma fonte de corrente ou de um resistor pull-up, para garantir que ambas as
linhas permaneçam em nível alto, quando o barramento está livre.
Uma das vantagens do padrão I2C é que ele não fixa a velocidade de transmissão
(freqüência), pois ela será determinada pelo circuito MASTER (transmissão do SCL).
Uma transição de nível alto para baixo na linha SDA, enquanto a linha SCL está no nível
alto, é o indicativo da situação de START. Já uma transição do nível baixo para o nível alto
da linha SDA enquanto a linha SCL se mantém no nível alto, define uma condição STOP.
Sempre o mestre é o resposável pela geração dessas condições. Após uma condição de
START o barramento é considerado ocupado, e apenas volta a ficar livre algum tempo
depois da condição de STOP.
Caso o dispositivo que está recebendo o sinal, por algum motivo, não puder trabalhar os
dados recebidos, ele pode alterar a linha SCL, colocando-a no nível baixo, e assim forçar o
mestre a entrar num estado de espera. Dessa forma, fomente quando a linha estiver
novamente livre a transferência dos dados pode continuar.
Após o escrita/leitura de um byte no barramento, o dispositivo receptor gera um bit de
reconhecimento (acknowledge). O sinal de reconhecimento permite a fluência da
transferência dos dados. Assim, por exemplo, após a condição de Start e o
endereçamento estarem concluídos, o estágio (escravo) selecionado deve fornecer o sinal
de reconhecimento (ACK).
A linha SDA do receptor é colocada em nível baixo durante o pulso de clock de modo que
ele permaneça estável no nível baixo durante o período alto do pulso de clock.
Endereçamento-padrão
O formato básico de um comando I2C é constituído por 7 bits de endereço, utilizando para
especificar o dispositivo escravo a ser acessado, seguido por um bit indicador de
leitura/escrita.
Formato da Transmissão
2) Em seguida é enviado o endereço físico do escravo ligado ao barramento I2C. O bit LSB
desse endereço (R/W) informa se queremos ler ou escrever na memória.
Memória 24Cxx
A série 24Cxx EEPROM de baixo custo, baixo consumo e tamanho reduzido (oito
pinos) é excelente para aplicação em desenvolvimentos compactos. Utiliza
tecnologia I2C (permite leitura/escrita com duas vias SDA e SCL).
Tipos de memória serial EEPROM: 24C01, 24C02, 24C04, 24C08, 24C16, 24C32,
24C64, 24C128, 24C256, 24C512 fabricado por: ATMEL, STM, etc.
Pinagem:
Endereçamento
Os pinos A0, A1 e A2 definem o endereço físico da 24CXX no barramento I2C, que permite ligar até oito
memórias dessas no barramento.
Para podermos ler ou escrever dados nessas memórias, é necessário sabermos seu endereço no
barramento I2C. O endereço é definido da seguinte maneira:
O endereço é formado por 1 byte subdividido em três partes:
Gravação
Para gravarmos dados (byte) na EEPROM 24CXX, temos de seguir estes processos:
No processo de escrita, os bits de reconhecimento de dados ACK são gerados pelo receptor (memória).
Leitura
No processo de leitura, os bits de reconhecimento de dados ACK são gerados pelo mestre (receptor).
Receita de Bolo
É muito fácil de gravar dados em um memória da série 24Cxx em programas feitos com auxilio do
mikroC. Acompanhe essa receita de bolo:Invertemos o diagrama de gravação de dados na qual mostra
todas as etapas para gravar a memória 24Cxx, e colocamos para cada estado do diagrama a linha de
programa correspondente em BASIC.
Este diagrama de comunicação I2C é padrão e utilizados em muitos dispositivos I2C. Apesar de
estarmos se tratando do processo de gravação para a serie de memória 24Cxx, este bloco de comandos
são válidos para quase todos outros componentes I2C.Por exemplo: conversores A/D e D/A I2C, como o
PCF8591N; RTC - PCF8583N, DS1307, entre outros.
Programa de Leitura I2C.
O processo de leitura de já em um pouco mais trabalhoso e confuso para muitos programadores que
utilizam o assembly ou o C. Em BASIC o processo é muito fácil de ser programado, acomanhe:
Introdução
Aprendemos nesta unidade um pouco sobre a comunicação serial RS232. Agora iremos colocar em prática o que estudamos
até agora através dos execícios resolvidos abaixo:
Exercício 01:
Vamos elaborar um simples programa, que cujo objetivo, seja ler o canal AD0 do PIC, converter esse valor em string e
transmiti-lo pelo canal serial do PIC a uma velocidade de 9600 bps.
Programa:
/*************************************************************************
Microgenios Soluções eletrônica Ltda
Prog: le_ad0_envia_serial
Autor: Fernando Simplicio
KitPIcgenios
cristal: 8MHz
**************************************************************************/
do{
}
//*****************************programa principal ******************************
void main(){
while(1){
temp_res0 = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res0
intToStr(temp_res0, texto); //converte valor da conversão do ad0 para string
delay_ms(10);
TX_AD(); //chama função de envio do val
}
}
Descrição do programa:
Não fique muito assustado caso não tenha compreendido o funcionamento de todos os comandos do programa anterior, veremos
agora algumas de suas particularidades:
No comando acima defimos uma variável matriz do tipo char não sinalizada. Repare que não informamos no comando texto[] o
número de elementos da matriz, neste caso, por regra da linguagem C, somos obrigados a inicilizar esta matriz. No comando acima
termos então a seguinte construção:
O comando a seguir configura os pinos do PIC como A/D e define a velocidade de baudrate na comunicação serial.
void main(){
o bloco seguinte tem por objetivo, ler o canal AD0 do PIC, converter o valor lido em string e chamar a subrotina de transmissão
desse valor pela serial do PIC.
while(1){
temp_res0 = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res0
intToStr(temp_res0, texto); //converte valor da conversão do ad0 para string
delay_ms(10);
TX_AD(); //chama função de envio do val
agora só nos resta entender o funcionamento da subrotina de transmissão serial. A função de tratamento da transmissão e recepção
serial no mikroC somente permite que enviamos um bytes de dados por vez, isso implica que devemos tratar nossas variáveis ou
strings antes de utilizar estas funções.
Acompanhe o raciocínio:
Através dos comandos abaixo, o valor lido no AD0 é atribuido a variável temp_res0, e após isso, convertemos o valor dessa
variável em string e atribuimos esse novo valor na variável texto, através do comando: intToStr(temp_res0, texto).
Como sabemos, a variável texto é do tipo matriz, isso significa que essa variável aloca seus dados sequênciais na memória, byte a
byte.
Imaginemos agora, para entendermos melhor, que o valor lido no AD0 do PIC seja o valor 652, Teremos como resultado presente
na variável texto após a execução do comando intToStr(temp_res0, texto) o seguinte resultado:
texto[0] = "6"
texto[1] = "5"
texto[2] = "2"
texto[3] = "\0" <-- caractere de terminação de string NULL (\0)
A partir desse raciocício, criamos uma subrotina que tem por objetivo enviar do PIC cada caracterer presente na variável matriz
texto de forma a "reconstruir" novamente o valor lido no canal AD0.
do{
Usart_Write(texto[x]); //envia pela serial o caracterer apostado pelo ponteiro
x++; //incrementa variável x, cujo obetivo é alterar o indice da matriz.
}
while (texto[x] != '\0'); //verifica se ponteiro é igual a NULL
Copie e compile o programa deste exercício no mikroC, grave no microcontrolador PIC e teste seu funcionamento utilizando o
hyperterminal do windows para visualizar os dados enviado através do canal serial do PIC.
Exercício 02:
Para aprimorar ainda mais nossos conhecimentos, vamos implementar ao nosso programa anterior um display LCD 16X2 e mais um
trimpot ligado ao AD1, de forma que todos os caracteres envias pela serial do PIC, também seja mostrado no LCD.
Esquema elétrico:
Programa:
/*************************************************************************
Microgenios Soluções eletrônica Ltda
Prog: le_ad0_AD1_envia_serial
Autor: Fernando Simplicio
KitPIcgenios
cristal: 8MHz
**************************************************************************/
int temp_res0 = 0;
int temp_res1 = 0;
do{
do{
Usart_Init(9600);
adcon1 = 2;
do{
temp_res0 = Adc_Read(0); //le canal ad0 do PIC e salva valor na variável temp_res0
temp_res1 = Adc_Read(1); //lê canal ad1 do PIC e salva valor na variável temp_res1
while(1);
}
Existe uma série muito grande de chips RTC no mercado, em nosso curso utilizaremos o DS1307 fabricado pela DALLAS semicondutores.
DS1307
O chip DS1307 é um relógio de tempo real completo, que nos pemite programar segundo, minutos, horas, dias, mês e anos. Podemos
programar individualmente cada um dessas opções individualmente a qualquer momento em nosso programa via comunicação I2C. Este
relógio pode operar no formato de 12 ou 24 horas e AM/PM.
Características do relógio:
Contador de segundos, minutos, horas, dias, dias da semana, mês e anos com contagem pré programada pela Dallas até 2100, isso
representa que o próprio chip opera normalmente a contagem nos meses de 31 dias e 28 dias (fevereiro), incluindo também os dias
da semana (segunda feira, terça feira, quarta feira ...).
Entrada para bateria externa de 3.0V.
Protocolo I2C de fácil manipulação.
Consumo menor que 500nA da bateria (chip operando).
Temperatura de operação na faixa de -40ºC a +85ºC.
Tensão de operação: 5V DC
Frequência de Trabalho: 100KHz.
Pinagens do DS1307:
DS1307
Pinagens Descrição
1 X1 pino de entrada do cristal oscilador de 32.768khz.
2 X2 pino de entrada do cristal oscilador de 32.768khz.
pino de entrada da tensão da bateria de backup. (bateria de 3V
3 Vbat
de lithium é requerida).
4 GND GND
5 SDA Entrada e saida serial DATA na comunicaçãos I2C
6 SCL Entrada do clock SCL na comunicação I2C
pino de saida de clock (1Hz, 4KHz, 8KHz, 32KHz) quando bit
7 SWQ/OUT
SQWE for igual a 1.
8 Vcc Alimentação 5V do chip
Nosso relógio possui internamento registradores especiais cuja função é de configurar o modo de trabalho dos temporizadores. Através
desse registradores podemos configurar os segundos, minutos, hora, dia da semana, mês e ano, assim como definir o modo de operação
do calendário, de 12 ou 24 horas, AM/PM.
Através da descrição acima, já é possivel entender como devemos configurar nosso Relógio.
Vamos analizar agora o gráfico que nos ensina a programar o DS1307 via I2C utilizando o mikroC.
Todos os dados de leitura e escrita que manipularmos no DS1307 devem necessáriamente estar no formato BCD.
(caso tenha dúvida com relação ao formato BCD leia novamente o material complementar da primeira unidade).
O relógio DS1307 enquadra-se na categoria em que seu endereço no barramento I2C é 1101000X.
Bom, agora que já aprendemos a escrever no relógio I2C, faz necessário lermos as informações que estão sendo processadas pelo nosso relógio.
Para isso devemos compreender o funcionamento do protocolo I2C no processo de leitura, acompanhe:
Vamos elaborar um programa no mikroC que leia os dados dos registradores do relógio DS1307.
programa:
Repare que alguns dos comandos possuem um o indicativo numérico 1 (I2C_Rd(1)), isso nos representa que iremos ler mais dados no
barramento I2C. Agora o último comando ano = I2C_Rd(0) utilizamos o indicador numérico 0 (zero) para informar ao DS1307 que não iremos
mais ler nenhum byte.
Agora chegou o momento de elaborarmos nosso primeiro programa utilizando os recursos do mikroC para programarmos o relógio DS1307.
Vamos elaborar um programa que escreva o seguinte horário no DS1307, e apartir disso, leremos o valor corrente das horas no DS1307 e
escreveremos esses valores no visor do LCD 16X2.:
Esquema elétrico:
Programa:
/*******************************************************************************
Microgenios Soluções Eletrônica Ltda
Programa Exemplo: RTC
Autor: Fernando Simplicio
Objetivo: programar e ler o relógio DS1307 utilizando comunicação I2C.
Cristal: 8Mhz.
******************************************************************************/
void programa_i2c(){
I2C_Init(100000); // iniciliza I2C com frequencia de 100KHz
I2C_Start(); //inicializa a comunicação I2c
I2C_Wr(0xD0); //endereço fixo para a categoria do DS1307: 1101000X, onde x = 0 é para gravação, e X = 1 para leitura.
I2C_Wr(0); //endereço onde iremos começar a programação do relógio, neste caso é o endereço dos segundos.
I2C_Wr(0x25); //inicializa a contagem dos segundos apartir de 25.
I2C_Wr(0x44); //inicializa a contagem apartir de 44 minutos.
I2C_Wr(0x08); //inicializa a contagem dos hora apartir das 08:00hs (formato 24 horas).
I2C_Stop(); //condição de finalização da comunicação I2C
}
void display_lcd() {
BCD(1,1,horas); //chama subrotina de conversão da variável horas para BCD
LCD_custom_Chr_Cp(':'); //escreve no display LCD
BCD(1,4,minuto); //chama subrotina de conversão da variável minuto para BCD
LCD_custom_Chr_Cp(':'); //escreve no display LCD
BCD(1,7,segundo); //chama subrotina de conversão da variável segundo para BCD
}
programa_i2c();
Aproveitando o esquema eletrico do programa anterior, vamos elaborar um novo programa cuja finalizade seja prograr no DS1307 o seguinte
calendário:
Programa:
Obs: o programa abaixo consome 2204 byte de memória de programa do PIC. Neste caso, este programa não será possivel ser compilado
na versão demo do mikroC.
/*******************************************************************************
Microgenios Soluções Eletrônica Ltda
Programa Exemplo: RTC
Autor: Fernando Simplicio
Objetivo: programar e ler o relógio DS1307 utilizando comunicação I2C.
Cristal: 8Mhz.
******************************************************************************/
void display_lcd() {
lcd_custom_cmd(lcd_clear); //apaga lcd
BCD(1,1,horas); //chama subrotina de conversão da variável horas para BCD
LCD_custom_Chr_Cp(':'); //escreve no display LCD
BCD(1,4,minuto); //chama subrotina de conversão da variável minuto para BCD
LCD_custom_Chr_Cp(':'); //escreve no display LCD
BCD(1,7,segundo); //chama subrotina de conversão da variável segundo para BCD
encontra_dia_semana(); //chama subrotina onde será encontrado o dia da semana
LCD_custom_out(1,10,texto); //escreve no display LCD
BCD(2,1,dia); //chama subrotina de conversão da variável horas para BCD
LCD_custom_Chr_Cp('/'); //escreve no display LCD
BCD(2,4,mes); //chama subrotina de conversão da variável horas para BCD
LCD_custom_out(2,6,"/20"); //escreve no display LCD
BCD(2,9,anos); //chama subrotina de conversão da variável horas para BCD
}
programa_i2c();
Introdução
Chegamos a última unidade de nosso curso. Nesta nova unidade estudaremos vários estudos de casos reais.
Bom, vamos estudar agora os recursos e técnicas de programação para leitura de teclados matriciais:
Os teclados Matriciais
Os teclados matriciais são muito utilizados nos dias de hoje, pois é através deles que podemos utilizar em nossa aplicações um número
grande de botões sem comprometer muitos pinos do microcontrolador. O teclado matricial, também conhecido como matriz de botões, se
consiste em um arranjo conhecido como teclado matriz C x L (C corresponde a coluna, e L corresponde a linha).
Em uma matriz de teclado C x L, o que determina o número de pinos necessário para varrer o teclado é determinado pela soma do número
de linhas mais numero de colunas do teclado utilizado. Na figura anterior utilizaremos 7 pinos do microcontrolador para lermos as teclas.
Na figura abaixo apresentamos o teclado 3 x 4 do KIT PICGENIOS da Microgenios.
O Funcionamento:
Por exemplo:
Vamos supor que colocamos nivel lógico 0 na primeira coluna (pino RB0) enquanto as outras colunas RB1, RB2 e RB3 permanecem em
nível lógico 1. Após isso, realizamos uma leitura nas linhas (RB4, RB5, RB6 e RB7). Se todas as teclas estiverem soltas, todas as linhas
estarão com nível lógico 1. Se alguma linha estiver em nível lógico 0 enquanto a coluna estiver ressetada, representa que a tecla no
cruzamento C x L esta pressionada.
Somente uma coluna devem ser colocada em nível lógico 0 de cada vez, enquanto as demais colunas devem permanecer em nível lógico 1.
Esquema elétrico:
Programa:
/***************************************************************************
CENTRO DE TECNOLOGIA MICROGENIOS
ESTE PROGRAMA TEM POR OBJETIVO ESCREVER NO LCD O VALOR NUMÉRICO DE CADA
TECLA DO TECLADO MATRICIAL.
*****************************************************************************
*/
void main() {
do
{
var2 = portd;
if (var2.f0 == 0) lcd("<---");
else if (var2.f1 == 0) lcd("7");
else if (var2.f2 == 0) lcd("4");
else if (var2.f3 == 0) lcd("1");
var2 = portd;
if (var2.f0 == 0) lcd("0");
else if (var2.f1 == 0) lcd("8");
else if (var2.f2 == 0) lcd("5");
else if (var2.f3 == 0) lcd("2");
//------------------------------------------------------------------------
var2 = portd;
if (var2.f0 == 0) lcd("-->");
else if (var2.f1 == 0) lcd("9");
else if (var2.f2 == 0) lcd("6");
else if (var2.f3 == 0) lcd("3");
delay_ms(100);
}
while(1);
}
Clique aqui para fazer download do programa:
Introdução
Os teclados de PCs é uma ótima ferramenta para implementações e inserção de dados em equipamentos de diversos tipos.
Devido ao seu custo baixo, funcionalide, praticidade e eficiência, os teclados de PC's vem cada vez mais sendo utilizados
pelos projetistas eletrônicos.
O teclado e seu host estão conectados através de 4 fios (entenda-se “host” como o dispositivo que se comunica com o teclado
trocando informações com ele, que no caso de um PC é o próprio PC).
A conexão entre um teclado e o PC é realizada através de um conector DIN de 5 pinos em 180º ou através de um conector do
tipo PS/2 (mini-din de 6 pinos). Em ambos os casos uma linha transmite o sinal do clock, outra dos dados e os demais a
alimentação +5V e GND.
A comunicação entre o teclado e o host é em série com bit inicial, oito bits de dados, paridade ímpar e bit de parada. É bi-
direcional, o teclado informa ao host a atividade das teclas e o host envia os comandos para sua configuração, acendimento
de luzes (CapsLock, NumLock, etc) re-inicialização, re-envio, etc. Isto faz que o sinal de dados possa ser usado por ambas as
partes, enquanto que o clock controla sempre o teclado.
O compilador mikroC possui funções pré-programada para tratamento de teclado PS/2. Através de simples comandos
podemos receber dados provenientes de um teclado e tratar essas informações para determinados fins. Os comandos de
tratamento do teclado PS/2 no mikroC são:
Ps2_Init
Ps2_Config
Ps2_Key_Read
A função Ps2_Init tem por objetivo inicializar o PORT para trabalhar com o teclado PS/2. Esta função normalmente é
utilizada quando desejamos utilizar os pinos pré-programados do port para comunicação SDA e SCL entre teclado e PIC.
sintaxe:
Ps2_Init(&PORT);
Exemplo:
Ps2_Init(&PORTD);
A função Ps2_Config tem por objetivo inicializar e configurar os pinos do PIC que participarão da comunicação com o
teclado PS/2.
sintaxe:
onde:
PORT_do_PIC = PORTA, PORB, PORTC, PORTD ou PORTE.
pino_de_clock = RX0 a RX7 (x referece ao PORT_DO_PIC . Ex: RA0)
pino_de_data = RX0 a RX7 (x referece ao PORT_DO_PIC . Ex: RA0)
Exemplo:
Ps2_Config( &PORTB, 4, 5); //configura os pinos RB4 (clock) e RB5 (data) do PORTB
para manipulação do teclado PS/2.
Ps2_Key_Read
Afunção Ps2_Key_Read tem por objetivo identificar se alguma tecla foi pressionada, receber o valor da tecla pressionada e
identificar se as teclas de funções especiais, tais como ESC, Enter, estão pressionadas. caso alguma tecla tenha sido
pressionada a função seus parametros retornará nivel 1, caso contrário, ou seja, caso nenhuma tecla tenha sido pressionada,
retorna nivel 0.
sintaxe:
onde:
&valor_da_tecla = retorna o valor da tecla pressionada no teclado PS/2.
&tecla_especial = verifica se alguma tecla especial foi pressionada.
&bit_status = verifica se alguma tecla foi pressionada. Caso verdadeira, retorna 1, caso falso,
retorna 0.
Exemplo:
Segue abaixo a tabela com os valores de retorno para cada tecla pressionada no teclado PS/2:
Key Value returned
F1 1
F2 2
F3 3
F4 4
F5 5
F6 6
F7 7
F8 8
F9 9
F10 10
F11 11
F12 12
Enter 13
Page Up 14
Page Down 15
Backspace 16
Insert 17
Delete 18
Windows 19
Ctrl 20
Shift 21
Alt 22
Print Screen 23
Pause 24
Caps Lock 25
End 26
Home 27
Scroll Lock 28
Num Lock 29
Left Arrow 30
Right Arrow 31
Up Arrow 32
Down Arrow 33
Escape 34
Tab 35
Observação 01: Para que possamos utilizar as funções de tratamento de teclados PS/2 no mikroC,
necessáriamente devemos utilizar em nosso projeto cristal oscilador igual ou maior que 6 MHz, caso contrário
nosso programa não funcionará corretamente.
Observação 02: Quando estivermos manipulando os comandos de tratamento de teclado PS/2 no mikro,
devemos necessáriamente desligar todas as interrupções do PIC.
Para entendermos melhor o funcionamento das funções de tratamento de teclados PS/2 no mikroC, vamos elaborar um
exemplo de programa simples, cuja função seja rebecer o valor lido de uma tecla qualquer do teclado e atribuir este valor ao
PORTD.
Esquema elétrico:
Programa:
/***************************************************************************
Centro de Tecnologia Microgenios
Programa: Ps/2_teclado_lcd
Compilador: mikroC 6.02
Kit: Kit PICGenios
Obejtivo: Este programa tem por objetivo ler um teclado de computador PS/2 e
enviar o valor de cada tecla para o portA do PIC.
*/
while (1){
if (Ps2_Key_Read(&valor_da_tecla, &tecla_especial, &bit_status)) {
if ((bit_status ==1) && valor_da_tecla) {
PORTA = valor_da_tecla; //escreve valor da tecla pressionada no lcd
}
}
}
}
Os comandos abaixo tem por função configurar os pinos RD2 como clock e RD3 como DATA, para tratamento do teclado
PS2.
A condição de tomada de decião IF abaixo é necessário para sabermos se alguma tecla do PC foi
pressionada. Neste caso a função será verdadeira quando o retorno da função Ps2_Key_Read for
diferente de zero.
O segundo teste de tomada de decisão IF realiza uma operação lógica AND entre os parâmetros bit_status e valor_da_tecla da
função, Ps2_Key_Read.
if ((bit_status ==1) && valor_da_tecla)
caso a condição If anterior seja verdadeira, é atribuida ao PORTA o valor recebido do teclado PS/2.
Vamos agora elaborar um exemplo de programa um pouco mais sofisticado. Neste novo exemplo de programa utilizaremos o
display LCD como terminal de recepção dos dados lidos no teclado PS2.
Repare que estamos utilizando neste projeto cristal de 8 MHz, mas poderiamos utilizar qualquer outro cristal que não seja
menor do que 6MHz, caso contrário não poderiamos usufruir das funções de PS/2 do mikroC.
Nosso programa:
/***************************************************************************
Centro de Tecnologia Microgenios
Programa: Ps/2_teclado_lcd
Compilador: mikroC 6.02
Kit: Kit PICGenios
Obejtivo: Este programa tem por objetivo ler um teclado de computador PS/2 e
enviar o valor de cada tecla para o display LCD.
****************************************************************************/
unsigned short
keydata = 0, special = 0, down = 0; //variáveis necessário para usar a
//biblioteca PS2
void main() {
do {
if (Ps2_Key_Read(&keydata, &special, &down)) {
if (down && (keydata == 16)) {// tecla Backspace pressionada
Lcd_custom_Cmd(LCD_MOVE_CURSOR_LEFT);
}
else if (down && (keydata == 13)) {// tecla Enter pressionada
Lcd_custom_Cmd(LCD_RETURN_HOME);
}
else if (down && !special && keydata) {
Lcd_Custom_Chr_CP(keydata); //escreve valor da tecla pressionada no lcd
}
}
Delay_ms(10); // debounce
} while (1);
}
O programa acima lê o teclado Ps/2 e escreve no display LCD os valores dessas teclas, o mais importante é que o valor lido é
em ASCII, e neste caso podemos enviar diretamente para o LCD, até mesmo pela serial do PC.
Memória EEPROM
Definição:
EEPROM (Electric Eraseble and Programable Read Only Memory) Memória somente de leitura de apagamento
e programação elétrica, essa memória revolucionou esse tipo de sistema, pois possibilitava a programação e
reprogramação de maneira elétrica sem a necessidade da retirada do componente do circuito, porém demanda de
grande complexidade de projeto o que reduz sua capacidade e eleva seu preço é utilizada tanto como memória de
programa quanto como memória de dados substituindo assim EPROMs e RAMs.
Com o mikroC, podemos escrever e e ler dados nesta memória com grandes facilidades, através
dos comandos:
EEprom_Write(endereço, dado);
EEprom_Read(endereço);
Onde:
endereço = endereço da memória EEPROM do PIC onde será salvo os dados.
dado = informação que será salvo na memória do PIC.
Exemplo:
Exemplo de programa:
O programa seguinte tem por objetivo escrever uma mensagem na EEPROM, no endereço 0
(zero), e posteriormente ler esse mesmo endereço de memória na EEPROM e enviar os dados
lidos para o display LCD.
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits_01.c
Este programa tem por objetivo escrever a mensagem "Teste EEPROM" na EEPROM
do
PIC (endereço 0) e posteriormente ler essa mensagem salvo na memória e
enviar para a primeira linha do LCD.
Cristal : 8MHz
***************************************************************************/
void main() {
while(1);
}
O equipamento que iremos desenvolver é chamado de Prod-CNC. Este equipamento deverá automatizar
Inicialmente, nosso equipamento deverá contar o número de caixas que passam em uma esteira de
linha de produção. Os produtos que iremos contar estão embalados em caixas de papelão, conforme
podemos ver na animação abaixo:
Os Pulsos de contagem são gerados por um sensor fotoelétrico posicionado na lateral da esteira de
produção, cuja função é que detecta a passagem das caixas de papelão. Cada pulso enviado pelo
sensor, representa que passou 1 caixa na esteira, e nosso equipamento deverá "ler" esse sinal e
contar. Inicialmente nosso projeto somente contará o número de caixas que passam na esteira e
mostrará no display LCD do equipamento;
Figura -
Repare que os pulsos do sensor fotoelétrico chega até o contador externo RA4/T0CK1 do
microcontrolador PIC18F442. Sabemos que este pino tem a função de operar como I/O de uso geral,
conversor A/D ou como contador de pulsos externos. Neste caso, iremos programar este pino como
contador de pulsos externo, pois queremos contar os pulsos vindos do sensor da esteira de produção.
O programa:
/**************************************************************************
Centro de tecnologia Microgenios
Programa exemplo: LCD_modo_4bits_01.c
Este programa tem por objetivo contar os pulsos recebidos atráves do contador T1CK1 e enviar valor da
contagem para o lcd.
**************************************************************************
*/
char *texto[16];
unsigned short contador;
void main()
T1CON = 0B00000011; //liga TIMER1, prescaler 1:8, modo 8bits, contador externo
TMR1L = 0; //carrega valor de contagem baixa do TIMER1
do
{
contador = TMR1L + contador; //lê o valor do timer1 e soma a variável contador
TMR1L = 0; //zera contagem para receber novo pulso
wordToStr(contador, texto); //converte valor da conversão do ad0 para string
Lcd_custom_Out(2, 10,texto); // escreve variável texto na 2º linha, 10º coluna do LCD
Lcd_custom_Out(2, 1,"Numero: ");
delay_ms(50);
} while(1); // loop
}
char *texto[16];
unsigned short contador;
Os comandos abaixo inicializam e configura o modo de operação do LCD 16x2 do equipamento PROD-
CNC.
void main()
{
T1CON = 0B00000011; //liga TIMER1, prescaler 1:8, modo de leitura/escrita em 8bits, contador
externo
TMR1L = 0; //carrega valor de contagem baixa do TIMER1
Nosso programa fica em loop constante graças aos comandos do-while. Neste laço de repetição, o valor
da contagem dos pulsos recebidos externamente no pino RA4 armazenados em TMR1L, são convertidos
em STRING e enviados para o LCD.
Desta maneira, cada pulso recebido no pino de contagem externa RA4/T1CK1 incrementa em 1 unidade
a variável "contador", sendo esta variável convertida em string e enviada para o lcd.
do
{
contador = TMR1L + contador; //lê o valor do timer1 e soma a variável contador
TMR1L = 0; //zera contagem para receber novo pulso
wordToStr(contador, texto); //converte valor da conversão do ad0 para string
Lcd_custom_Out(2, 10,texto); // escreve variável texto "Programa LCD" na 2º linha, 10º coluna
do LCD
Lcd_custom_Out(2, 1,"Contagem: ");
delay_ms(50);
} while(1); // loop