Escolar Documentos
Profissional Documentos
Cultura Documentos
Apostila Do Curso Básico de Microcontroladores
Apostila Do Curso Básico de Microcontroladores
de
Microcontroladores PIC
Fabricantes de Microcontroladores
Existem diversos fabricantes de Microcontroladores no mercado mundial. Cada um
possui suas especialidades como velocidade de operação, custo/benefício, periféricos, etc.
Dentre os principais fabricantes, podemos citar:
Atmel;
Dallas Semiconductor;
Intel;
Philips;
Microchip;
Hitachi;
Motorola;
Zilog.
Ciclo de Máquina
É também chamado de Ciclo de Instrução. Como indica o próprio nome, o Ciclo de
Máquina é o tempo gasto para efetuar uma instrução. Nos Microcontroladores PIC o Ciclo de
Máquina é de 4 Ciclos de Clock.
Para que o programa escrito no Microcontrolador seja executado é necessário que seja
conectado ao mesmo um Oscilador. O Oscilador é o componente que gerará pulsos de Clock
em um contador especial, denominado Contador de Programa. O Contador de Programa
Dentre o bloco Memórias, destaca-se: Memória de Programa, onde está gravado todo
o programa do usuário; Memória RAM, utilizada para a manipulação de valores,
armazenamento de resultados de operações matemáticas e booleanas, etc. (todas as variáveis
que são criadas pelo usuário são armazenadas na Memória RAM); dentre o bloco Memórias
temos os Registradores de Funções Especiais. Estes auxiliam na manipulação dos módulos
internos do Microcontrolador. Cada módulo de Comunicação, Timer, Conversor A/D, entre
outros, possui um ou mais registros de configurações.
O C é uma linguagem de alto nível com uma sintaxe bastante estruturada e flexível
tornando sua programação bastante simplificada;
O C compartilha recursos tanto de alto quanto de baixo nível, pois permite acesso e
programação direta do microprocessador. Com isto, rotinas cuja dependência do tempo
é crítica, podem ser facilmente implementadas usando instruções em “Assembly”. Por
esta razão o C é a linguagem preferida de boa parte dos programadores;
O C é uma linguagem estruturalmente simples e de grande portabilidade. O compilador
C gera códigos mais enxutos e velozes do que muitas outras linguagens;
Embora estruturalmente simples (poucas funções intrínsecas) o C não perde
funcionalidade, pois permite a inclusão de uma farta quantidade de rotinas do usuário.
Os fabricantes de compiladores fornecem uma ampla variedade de rotinas pré-
compiladas em bibliotecas.
Toda função deve ser iniciada por uma chave de abertura { e encerrada por uma chave
de fechamento };
Toda função é procedida de parênteses ( );
As linhas de código são sempre encerradas por um ponto e vírgula;
A formatação dos programas é completamente livre, mas temos por conveniência
manter a legibilidade;
Os comandos são executados na ordem em que foram escritos;
Os comentários devem ser delimitados por /* no início e */ no final.
Podem ser usados também os caracteres // para comentários de uma linha.
Variáveis
Todas as variáveis e constantes usadas no programa devem ser definidas com um
nome e um tipo. Os dados básicos podem ser de 8, 16 e 32 bits de comprimento, e devido as
características peculiares dos microcontroladores, variáveis de 1 bit também podem ser
definidas.
Para declararmos uma variável devemos seguir algumas regras. São elas:
Tipos de Variáveis
Variáveis de 1 bit: podem assumir apenas dois valores distrintos: “0” ou “1”. No CCS
este tipo de variável é nomeado por “int1” e “short”.
Variáveis de 8 bits sem sinal: podem armazenar valores inteiros que vão de “0” a “256”,
para o caso dos tipos “unsigned int”, “unsigned int8” e “byte”.
Variáveis de 8 bits com sinal: armazenam valores inteiros que vão de “-127” até “128”.
São os tipos: “signed int” e “signed int8”.
Variável de 8 bits padrão ASCII (manipulação de caracteres): “char”.
Variáveis de 16 bits: “long int”, “int16”.
Variável de 32 bits: “int32”.
Variável de 32 bits para valores fracionários: “float”.
Declarando Variáveis
A forma de declaração de variáveis é a seguinte:
Tipo_da_variável Nome_da_variável;
Inicializando Variáveis
Pode-se inicializar uma variável no momento de sua declaração, ou em qualquer
instante do programa.
Variáveis Locais: as variáveis locais tem “alcance” apenas dentro das rotinas ou
funções onde foram criadas. Isto significa que apenas a rotina ou função onde a
mesma foi criada poderá utilizá-la.
Exemplo: 0b10101010
Tipos de Operadores
Operador de Atribuição
A operação de atribuição é a operação mais simples do C. Consiste de atribuir valor de
uma expressão a uma variável. A sintaxe da operação de atribuição é a seguinte:
identificador = expressão;
Operadores Aritméticos
Existem cinco operadores aritméticos em C. Cada operador aritméticos está
relacionado ao uma operação aritmética elementar: adição, subtração, multiplicação e divisão.
Existe ainda um operador (%) chamado operador de módulo cujo significado é o resto da
divisão inteira. Os símbolos dos operadores aritméticos são:
Precedência de operadores
Quando mais de um operador se encontram em uma expressão aritmética as
operações são efetuadas uma de cada vez respeitando algumas regras de precedência. Estas
regras de precedência são as mesmas da matemática elementar.
Os operadores de multiplicação (*), divisão (/) e módulo (%) tem precedência sobre os
operadores de adição (+) e subtração (-). Entre operadores de mesma precedência as
operações são efetuadas da esquerda para a direita.
Operadores relacionais
Operadores relacionais verificam a relação de magnitude e igualdade entre dois
valores. São seis os operadores relacionais em C:
O resultado de uma expressão lógica é sempre um valor numérico que pode variar
entre dois valores: uma expressão avaliada como verdadeira recebe o valor 1 e uma expressão
lógica avaliada como falsa recebe o valor 0.
Operadores lógicos
São três os operadores lógicos de C: &&, || e !. Estes operadores possuem o mesmo
significado, respectivamente, dos operadores lógicos Booleanos AND, OR e NOT.
expressão_1 || expressão _2
! expressão
Operadores Incrementais
Em programação existem instruções muito comuns chamadas de incremento e
decremento. Uma instrução de incremento adiciona uma unidade ao conteúdo de uma variável.
Uma instrução de decremento subtrai uma unidade do conteúdo de uma variável.
Estruturas Relacionais
Decisão de um bloco (if...)
A estrutura de decisão de um bloco permite que se execute (ou não) um bloco de
instruções conforme o valor de uma condição seja verdadeiro ou falso. O fluxograma desta
estrutura é mostrado abaixo.
F bloco
if(condição)
bloco;
Se a condição for verdadeira o bloco será executado. Caso contrário, o bloco não é
executado.
condição?
bloco 1 bloco 2
if(condição)
bloco_1;
bloco_2;
O exemplo mostrado acima está incompleto. Não basta somente o trecho de código
mencionado acima para que o estudante possa verificar os resultados. O exemplo é apenas
ilustrativo para que o estudante tenha uma base de como utilizar a expressão de Decisão.
No código acima verificamos a utilização de uma função até aqui desconhecida. Ela
serve para imprimir textos. Esta função está detalhada em um capítulo relacionado à Funções
do CCS.
Condição
F
1?
V
Condição
F
2?
bloco 1
V
Condição
F
3?
bloco 2
...
V
bloco 3
...
if(condição_1)
Bloco_1;
else if(condição_2)
Bloco_2;
...
Else
Bloco_N;
Estrutura switch...case
A estrutura switch...case é uma estrutura de decisão que permite a execução de um
conjunto de instruções a partir de pontos diferentes conforme o resultado de uma expressão de
controle. O resultado desta expressão é comparado ao valor de cada um dos rótulos, e as
instruções são executadas a partir desde rótulo. A figura abaixo mostra o fluxograma lógico
desta estrutura.
expressão
rotulo 1
conjunto 1
rotulo 2
conjunto 2
...
rotulo N
conjunto N
rotulo D
conjunto D
switch(expressão)
...
default: conjunto_d;
O valor de “expressão” é avaliado e o fluxo lógico será desviado para o conjunto cujo
rótulo é igual ao resultado da expressão e todas as instruções abaixo deste rótulo serão
executadas. Caso o resultado da expressão seja diferente de todos os valores dos rótulos
então o “conjunto_d” é executado. Os rótulos devem ser expressões constantes inteiras
diferentes entre si. O rótulo default é opcional.
Estruturas de Repetição
Estrutura do...while
Esta é uma estrutura básica de repetição condicional. Permite a execução de um bloco
de instruções repetidamente. Sua sintaxe é a seguinte:
do
bloco
}while(condição);
Esta estrutura faz com que o bloco de instruções seja executado pelo menos uma vez.
Após a execução do bloco, a condição é avaliada. Se a condição é verdadeira o bloco será
executado novamente. Caso contrário a repetição é terminada. O fluxograma desta estrutura é
mostrado na figura:
condição? V
Estrutura while
A estrutura de repetição condicional while é semelhante a estrutura do...while. Sua
sintaxe é a seguinte:
while(condição)
bloco
Esta estrutura faz com que a condição seja avaliada em primeiro lugar. Se a condição é
verdadeira o bloco é executado uma vez e a condição é avaliada novamente. Caso a condição
seja falsa a repetição é terminada sem a execução do bloco. Observe que nesta estrutura, ao
contrário da estrutura do...while, pode ocorrer do bloco de instruções não ser executado
nenhuma vez. Para isto basta que a condição seja inicialmente falsa.
bloco
Estrutura for
A estrutura for é muito semelhante as estruturas de repetição vistas anteriormente,
entretanto costuma ser utilizada quando se quer um número determinado de ciclos. A
contagem dos ciclos é feita por uma variável chamada de contador. A estrutura for é, as vezes,
chamada de estrutura de repetição com contador. Sua sintaxe é a seguinte:
bloco
A instrução break.
Esta instrução serve para terminar a execução das instruções de um laço de repetição
(for, do...while, while) ou para terminar um conjunto switch...case.
Manipulação de Funções
Funções de Biblioteca
Uma função é um sub-programa (também chamado de rotina). Esta função recebe
informações, processa e retorna outra informação. Por exemplo: podemos ter uma função que
receba um valor numérico, calcule seu logaritmo decimal e retorne o valor obtido.
Para incluir uma biblioteca do compilador (que está na pasta include do compilador)
usa-se a diretiva:
O código mostrado abaixo é uma função definida pelo usuário para calcular a média
aritmética de dois números reais:
No exemplo acima definimos uma função do tipo “float” chamada “media” que recebe
dois argumentos tipo “float”: “a” e “b”. A média destes dois valores é calculada e armazenada
na variável “med” declarada dentro da função “media”. A função retorna, para o programa que
a chamou, um valor também do tipo “float”: o valor da variável “med”. Este retorno de valor é
feito pela instrução “return” que termina a execução da função e retorna o valor de “med” para
o programa que a chamou.
Definição de Funções
De modo formal, a sintaxe de uma função é a seguinte:
Bloco_de_instruções_da_função
O tipo de retorno da função especifica qual o tipo de dado retornado pela função,
podendo ser qualquer tipo de variável: “int”, “float”, etc. Se a função não retorna nenhum valor
para o programa que a chamou devemos definir o retorno como “void”, ou seja, um retorno
ausente.
Vale notar que existe apenas um valor de retorno para funções em C. Não podemos
fazer o retorno de dois ou mais valores. Porém isto não é uma limitação séria, pois o uso de
ponteiros contorna o problema.
A lista de argumentos da função especifica quais são os valores que a função recebe.
As variáveis da lista de argumentos são manipuladas normalmente no corpo da função.
A chamada de uma função termina com a instrução return que transfere o controle para
o programa que realizou a chamada da função. Esta instrução tem duas finalidades: determina
o fim lógico da rotina e o valor de retorno da função. O argumento de return será retornado
como valor da função.
Sintaxe:
[corpo de função]
{ ...
...
Sintaxe:
...
...
[corpo de função]
Em C, como em muitas outras linguagens, é permitido que o usuário crie uma função
em um arquivo e um programa que a chame em outro arquivo distinto. Esta facilidade permite a
criação de bibliotecas de usuário: um conjunto de arquivos contendo funções escritas pelo
usuário. Esta possibilidade é uma grande vantagem utilizada em larga escala por
programadores profissionais.
Sintaxe:
...
...
Declaração de Vetores
Em C, um vetor é um conjunto de variáveis de um mesmo tipo que possuem um nome
identificador e um índice de referência.
tipo nome[tam];
onde: “tipo” é o tipo dos elementos do vetor: “int”, “float”, “char”, etc. “nome” é o
identificador do vetor. “tam” é o tamanho do vetor, isto é, o número de elementos que o vetor
pode armazenar.
Inicialização de Vetores
Assim como podemos inicializar variáveis (por exemplo: int j = 3;), podemos inicializar
os vetores. A sintaxe para a inicialização dos elementos de um vetor é:
onde: “lista de valores” é uma lista de números, separada por vírgulas, dos valores de
cada elemento do vetor.
nome_da_função(nome_do_vetor)
...
Matrizes
Vetores podem ter mais de uma dimensão, isto é, mais de um índice de referência.
Podemos ter vetores de duas, três, ou mais dimensões, nestes casos, estes são chamados de
matrizes. Podemos entender um vetor de duas dimensões (por exemplo) associando-o aos
dados de uma tabela.
tipo nome[tam_1][tam_2]...[tam_N]={{lista},{lista},...{lista}};
...
Strings
String é uma das mais importantes formas de dados em C e é usada para armazenar e
manipular textos como palavras, nomes e sentenças. String é um vetor do tipo char terminado
pelo caracter NULL (\0), ou seja, string é uma série de caracteres armazenados em seqüência,
onde cada um ocupa um byte de memória, toda string é terminada por um byte de valor zero
(\0). Cada caracter é um elemento independente e pode ser acessado através de um índice.
Funções para utilização de diversos circuitos integrados como Relógio de Tempo Real,
Conversores D/A, Memórias Flash, Potenciômetros Digitais, Módulos de Comunicação
Ethernet, entre outros, também fazem parte do Pacote de Funções do CCS. Bibliotecas de
Funções Matemáticas também estão inclusas.
Compilando os Programas
Para compilar o programa, basta acessar a Aba “Compile”. Um conjunto de opções
será fornecido e, dentre elas, basta clicar no ícone denominado “Compile”.
Nesse processo, sabemos que vamos medir a temperatura de uma Estufa. Sendo
assim, precisamos escolher um Sensor de Temperatura que se enquadre no processo,
respeitando características de temperatura do ambiente a ser monitorado. Assim, escolhemos
um sensor analógico e utilizamos um Módulo Conversor A/D ou utilizamos um Sensor de
Temperatura Digital com comunicação SPI ou I2C, entre outros tipos. Como vamos medir
temperaturas relativamente baixas (próximas a 30 graus Celsius) podemos utilizar um sensor
de temperatura digital com comunicação “SPI”, o que é muito comum no mercado. Como não
se consegue uma grande variação da grandeza física Temperatura em um pequeno intervalo
de tempo, no nosso exemplo medir a temperatura de 5 em 5 segundos já nos é o suficiente.
Sendo assim, necessitamos de uma base de tempo que nos ajude a calcular este tempo de 5
segundos. Isso é realizado a partir de um Módulo Temporizador. A comunicação entre
Computador e MCU será realizada a partir de um Módulo RS232.
Após alguns projetos realizados, o estudante e/ou programador irá adquirir experiência
o bastante para dimensionar o melhor MCU para a sua aplicação. Graças à Flexibilidade da
Linguagem C, boa parte do programa poderá ser escrito antes mesmo de se ter certeza
absoluta de qual MCU será utilizado. Podemos escrever um programa voltado para o
PIC16F84A e, caso o mesmo não nos atenda em função do tamanho da Memória requerida
pelo nosso aplicativo, alteramos poucas linhas de código para mudarmos para o PIC16F877A,
por exemplo.
Vamos dar ênfase somente aos itens principais do CCS e que serão utilizados com
maior freqüência durante o curso. Tudo o que está relacionado neste tópico poderá ser
aplicado a qualquer Microcontrolador PIC. Assim, fica de encargo do estudante e/ou
programador desfrutar de todas as outras opções e ferramentas do programa em questão.
No canto superior direito da Tela Inicial, na aba “Project”, clique no ícone “PIC
Wizard”.
Logo em seguida abrirá uma tela com o nome “Salvar Como”. Nesta tela você indicará
o nome do Projeto e onde serão salvos os arquivos gerados pelo CCS.
Logo após indicar o diretório dos arquivos, abrirá uma nova janela como o nome “PIC
Wizard”. É nela em que fazemos as principais configurações do MCU. O “PIC Wizard” possui
ferramentas necessárias para efetuarmos boa parte das configurações do MCU.
Na opção “Oscilator Frequency” insira o valor do Cristal a ser utilizado. No caso do Kit
de Desenvolvimento utilizado deixaremos o valor default de 20.000.000Hz (20 Mega Hertz).
Para o nosso exemplo, vamos escolher a opção “High speed Osc (> 4mhz)” e marcar
a opção “Power Up Timer”.
Na aba “Code”, visualizamos o código em C gerado pelo “PIC Wizard”. Isto é bastante
útil, pois muitas vezes já temos um projeto em andamento e necessitamos alterar algumas das
configurações do MCU. Caso não saibamos qual é o código a ser inserido, basta recorrermos
ao “PIC Wizard” e copiarmos o código em questão.
Por default, a opção “Use RS232” está marcada (habilita o hardware de comunicação
RS232). Caso não se queira utilizar a porta serial RS232 do PIC esta opção deverá ser
desmarcada. O campo “Baud” indica a velocidade de transmissão e recepção de dados do
hardware. Existem diversas opções como: 9600, 19200, 38400 e 115200, entre outros. No
nosso caso utilizaremos o “Baud” de 115200. Através das opções “Transmit” e “Receive”,
selecionamos os pinos de transmissão (TX) e recepção (RX) de dados, respectivamente. Esses
são pinos específicos de comunicação do MCU. No caso do MCU em questão, os pinos de TX
e RX são os pinos RC6 e RC7, respectivamente. Logo, em “Transmit” deixaremos como “C6” e
em “Receive” o “C7”. No campo “Stream”, damos nome à porta de comunicação em questão.
Quando utilizamos em um projeto mais de uma porta de comunicação RS232 (existem MCUs
com 4 USART), esta opção é de extrema importância pois configura o canal de comunicação a
ser utilizado para se transmitir dados.
Por default, a opção “Use I2C” está desabilitada (hardware I2C desabilitado). A
princípio não utilizaremos o hardware I2C. Portanto, deixaremos esta opção desmarcada.
Ressalto novamente que para visualizar o código gerado basta clicar na aba “Code”.
Para realizarmos a leitura do nosso sensor de temperatura através da SPI temos que
configurá-la. Isso é feito a partir da opção “SPI and LCD”. Os parâmetros de configuração da
SPI são mostrados na tela logo após clicarmos na opção “SPI and LCD”. Feito isso, habilite a
opção “Hardware SPI#1” e selecione a opção “Master”. Isso habilitará o Hardware SPI do
MCU e o mesmo trabalhará como Mestre, ou seja, será responsável por comandar o processo
de comunicação SPI, que no nosso exemplo ocorre entre sensor de temperatura e MCU. As
opções “Spi Mode” e “Clock” são fundamentais para que a comunicação entre MCU funcione
corretamente. Como estamos apenas em um exemplo de como se criar um projeto não
trataremos esta informação neste instante. Isso será abordado em um tópico adiante
relacionado à Comunicação SPI.
Os Timers são configurados a partir da opção “Timers”. No campo “WDT” (Watch Dog)
marque a opção “Not used”. No campo “Timer 1” (timer de 16 bits) habilite a opção “Internal” e
selecione a resolução de “1.6us 104ms”. Nesta configuração, se contarmos até 50 obtemos
um intervalo de aproximadamente 5 segundos (50 * 104ms = 5200ms = 5,2s) para leitura do
sensor de temperatura citado no nosso exemplo. O Timer utilizado e a sua resolução são
escolhidos também em conseqüência do processo. Existem Timers de 8 bits e de 16 bits. A
melhor escolha deverá ser feita pelo programador, diante de cada aplicação.
#include “diretório_do_arquivo\nome_do_arquivo.h”.
Desta forma, se mudarmos o diretório do projeto uma série de erros poderá ocorrer,
pois pode ser que o arquivo não exista no diretório mencionado pela diretiva “#include”. Por
isso recomendamos substituir todo o texto que faz referência ao diretório do arquivo por um “.”
(ponto). Desta forma, se mudarmos o diretório de todo o projeto, não teremos nenhum tipo de
problema. Teremos, portanto:
#include “.\nome_do_arquivo.h”
Todo o procedimento de como se criar um novo projeto no CCS está listado e ilustrado
neste capítulo. E o mesmo procedimento poderá ser seguido a fim de se configurar qualquer
outro MCU da família PIC.
Diversas características dos módulos internos do PIC foram omitidas, pois este capítulo
visa apenas apresentar o assistente de configurações “PIC Wizard” e suas principais
ferramentas. Características exclusivas de cada módulo e exemplos de outros módulos
internos, que não foram mencionados neste capítulo e que são possíveis de serem
configurados pelo “PIC Wizard”, serão apresentados em tópicos posteriores.
É importante que o estudante e/ou programador saiba que cada MCU possui as suas
especialidades como, por exemplo, quantidade de Timers de 8 bits e Timers de 16 bits
disponíveis, número de entradas analógicas, tipos de comunicação, quantidade de
Entradas/Saídas, etc. Portanto, nem todos os módulos disponíveis num determinado MCU
serão possíveis de serem configurados a partir do “PIC Wizard”. Quando houver a
necessidade de se utilizar um módulo específico do MCU que não seja configurável pelo
assistente de configurações “PIC Wizard”, o estudante e/ou programador deverá recorrer aos
Tópicos de Ajuda do CCS.
Get_tris_x(VALOR): verifica a configuração dos pinos da Porta “x”. Para esta função,
temos o seguinte: “0” o pino está configurado como saída e “1” como entrada. O bit
menos significativo de “VALOR” representa o bit menos significativo da Porta X.
Input_state(PINO): verifica o nível lógico do pino. Esta função não muda a configuração
do pino. Se o pino em questão estiver configurado como saída digital, por exemplo, ele
permanecerá configurado como saída digital. Assim, a função retornará: “0” se a saída
está em nível baixo ou “1” se a saída estiver em nível alto.
É de extrema importância que o estudante tenha uma boa base teórica da Linguagem
C, abordada em outros tópicos, e que compreenda o que for abordado em cada seção, pois
tópicos futuros dependerão exclusivamente desses nossos primeiros e simples programas.
output_low(pino);
output_high(pino);
output_toggle(pino);
output_bit(pino,valor);
output_a(valor);
output_b(valor);
...
Input(pino);
Input_a();
Input_b();
...
Device: PIC16F877A
Fuses: High speed osc (>4MHz)
Oscilator Frequency: 20.000.000
Existe uma função que já inverte o valor do pino. Abaixo segue o código do loop infinito
com esta função:
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
while(true){
if(input(PIN_D0))
output_high(PIN_D4);
else
while(true){
output_bit(PIN_D4,input(PIN_D0));
}
Antes de incluir a biblioteca devemos definir os pinos do MCU para cada pino do
display LCD (RS, E, D4 ao D7) , incluir a biblioteca “visor.h”. Esta biblioteca deve ser inserida
na pasta do projeto a ser executado. Para se utilizar o display, deve-se executar as rotinas
lcd_ini() e liga_display() no programa principal.
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
lcd_ini();
delay_ms(10);
liga_display();
lcd_pos_xy(3,1);
printf(lcd_escreve,"Hello World");
pos_linha(2);
printf(lcd_escreve,"From PIC16F877A");
delay_ms(3000);
limpa_linha(1);
limpa_linha(2);
pos_linha(1);
printf(lcd_escreve,"Bootloader no");
pos_linha(2);
printf(lcd_escreve,"pino RD0");
while(true){}
}
Entradas Analógicas
O PIC16F877A possui 8 Canais Analógicos multiplexados em um único Conversor
Analógico/Digital de 10 bits. As tensões de referência do conversor podem ser externas,
através de pinos específicos, ou internas (própria alimentação do MCU). Para o caso de
referência externa, esta deve respeitar os limites da alimentação que, no nosso caso, estará
entre 0 e 5volts.
Set_adc_channel(canal);
Read_adc();
A0
Units 0-1023
Internal 2-6us
Código fonte:
#include ".\nome_do_projeto.h"
#include <bootloader.h>
void main()
{
int16 conversao;
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_ini();
delay_ms(10);
liga_display();
Interrupções
São rotinas especiais que interrompem a execução do programa para o tratamento de
determinados eventos. O programador não sabe o momento em que a interrupção irá ocorrer,
mas ele sabe o que a rotina realizará quando ela acontecer.
enable_interrupts(GLOBAL);
disable_interrupts(nome da interrupção);
disable_interrupts(GLOBAL);
clear_interrupt(nome da interrupção);
#include ".\exemplo_curso.h"
#include <bootloader.h>
int16 contador=0;
#int_EXT
EXT_isr()
{
contador++;
clear_interrupt(INT_EXT);
}
void main()
{
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
delay_ms(50);
lcd_ini();
delay_ms(10);
liga_display();
ext_int_edge( L_TO_H );
while(true){
pos_linha(1);
printf(lcd_escreve,"Contador:%04ld",contador);
}
}
#include ".\nome_do_projeto.h"
#include <bootloader.h>
#define X1 PIN_B1
#define X2 PIN_B2
#define X3 PIN_B3
#define Y1 PIN_B4
#define Y2 PIN_B5
#define Y3 PIN_B6
#define Y4 PIN_B7
#include ".\visor.h"
char tecla='N';
#int_RB
RB_isr()
{
output_high(X1);
output_low(X2);
output_low(X3);
if(input(Y1)){
tecla='1';
goto FIM;
}
if(input(Y2)){
tecla='4';
goto FIM;
}
if(input(Y3)){
tecla='7';
FIM:
output_high(X1);
output_high(X2);
output_high(X3);
delay_ms(50);
clear_interrupt(INT_RB);
delay_ms(50);
lcd_ini();
delay_ms(10);
liga_display();
output_high(X1);
output_high(X2);
output_high(X3);
pos_linha(1);
while(true){
if(tecla!='N'){
if(tecla=='#'){
limpa_display();
pos_linha(1);
}
else{
printf(lcd_escreve," %c",tecla);
}
tecla='N';
}
}
}
Timer 1:
Internal
Resolution 1.6us (overflow 104ms)
Timer 1 overflow
Código fonte:
#include ".\nome_do_projeto.h"
#include <bootloader.h>
void main()
{
int16 conversao;
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
lcd_ini();
delay_ms(10);
liga_display();
Comunicação Serial
Para se estabelecer comunicação entre Computador e Microcontrolador através da
interface RS232, devemos inserir um circuito de interface entre eles.
Putc(dado)
Getc()
Printf(mensagem);
Use RS-232
Baud 9600
Parity None
Transmit - C6
Receive - C7
Bits – 8
Código Fonte:
#include ".\nome_do_projeto.h"
#include <bootloader.h>
#int_RDA
RDA_isr()
{
int dado_recebido;
dado_recebido = getc();
if(dado_recebido == 'L') // acende o led D4 ao receber
output_high(led); // o dado 'L'
else if(dado_recebido == 'D')
output_low(led); // apaga o led ao receber o 'D'
}
void main()
{
int i=0;
setup_adc_ports(NO_ANALOGS);
setup_adc(ADC_OFF);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_1(T1_DISABLED);
setup_timer_2(T2_DISABLED,0,1);
setup_comparator(NC_NC_NC_NC);
setup_vref(FALSE);
enable_interrupts(INT_RDA);
enable_interrupts(GLOBAL);
EEPROM
O PIC16F877A possui uma memória não volátil de 256 bytes do tipo EEPROM , ou
seja, que após ser desligado os dados não são perdidos.
Write_eeprom(endereço,dado);
Read_eeprom(endereço);
A0
Units 0-1023
Internal 2-6us
#include ".\exemplo_curso.h"
#include <bootloader.h>
void main()
{
int16 valor;
setup_adc_ports(AN0);
setup_adc(ADC_CLOCK_INTERNAL);
setup_psp(PSP_DISABLED);
setup_spi(FALSE);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
delay_ms(50);
lcd_ini();
delay_ms(10);
liga_display();
set_adc_channel(POTENCIOMETRO);
while(true){
valor=read_adc();
if(input(GRAVAR)){
write_eeprom(8,valor/256);
write_eeprom(9,valor%256);
delay_ms(100);
}
pos_linha(1);
printf(lcd_escreve,"Atual:%04ld",valor);
pos_linha(2);
printf(lcd_escreve,"Gravado:%04ld",read_eeprom(8)*256+read_eeprom(9));
delay_ms(100);
}
}
Para acionar o LED basta colocar o pino conectado ao mesmo em nível lógico alto
(“1”). Para desligá-lo colocamos o pino em nível lógico baixo (“0”).
O circuito abaixo funciona bem com cargas de baixa potência. No entanto, cargas
indutivas, como motores e relés, introduzem uma grande quantidade de ruídos na linha de
alimentação. Por esta razão, utilizamos um Diodo em Anti-paralelo com a carga indutiva, afim
de minimizar os ruídos provenientes das tensões reversas geradas no desligamento da carga.
Entre os tipos de sensores resistivos podemos citar dois tipos comuns: Termistores
(sensores de temperatura) e os LDR’s (Resistor Dependente de Luz). Afim de simular um
Sensor do tipo Resistivo, é comum utilizarmos de um Potenciômetro Analógico.