Trabalhando com o microcontrolador PIC 16F877
       A partir desta aula irei dar informações importantes sobre as ferramentas necessárias para se programar um microcontrolador PIC 16F877. O objetivo aqui não é ensinar sobre os detalhes dos microcontroladores, pois seria necessário escrever um outro módulo para falar sobre o assunto. O que irei ensinar são noções básicas sobre as ferramentas necessárias para se programar e gravar um microcontrolador PIC, usando a linguagem C.
       A linguagem nativa de programação de microcontroladores é o Assembly, pois seus comandos de programação estão associados diretamente a endereços de memória e registradores do microcontrolador. Por esse motivo, um programa escrito em Assembly será compacto e, assim, será executado mais rapidamente.  Há algumas desvantagens em se programar todo um código em Assembly, como a demora na programação (pois, temos que programar endereço por endereço de memória), dificuldade em se dar manutenção no código futuramente, pois a programação é baseada em saltos GOTOs, as rotinas ficam todas "amarradas"; não é um código portável (por exemplo, se for preciso migrar para um outro modelo de microcontrolador, é preciso criar um novo programa a partir do zero, pois a maioria das rotinas estão associadas a endereços físicos de memória,do modelo do microcontrolador anterior.
       Antigamente os microcontrolaores tinham pouco espaço de memória para armazenar programas e, portanto, era necessário economizá-la ao máximo, para que se pudesse armazenar o código do programa. Nessa condição o compilador Assembler era de suma importância para gerar um código pequeno. Mas, com a evolução da microeletrônica, hoje em dia, os microcontroladores dispõem de uma quantidade muito maior de memória de programa. Agora, com os microcontroladores podendo armazenar mais códigos de programa, é muito mais produtivo e seguro, programar usando uma linguagem de alto nível como o C, que é portável, rápida, compacta e eficiente, sem falar na facilidade em se dar manutenção no código futuramente.
       O Assembly nunca deve ser desprezado, pois, quando necessitarmos de uma rotina que precise de toda a velocidade que o hardware dispõe para melhorar a eficiência de uma rotina, poderemos criar esta em Assembly e chamá-la a partir da linguagem C.
       Para o desenvolvimento de nossos projetos iremos usar o PIC 16F877, pois este tem 33 I/O (entradas/saídas), e vários periféricos como: USART, EEPROM, Timers, PWM, A/Ds, PSP, comunicação síncrona e assíncrona. Assim, poderemos controlar relês, LEDs, sensores A/C, comunicação serial, I2C, Paralela, etc., usando um único modelo de microcontrolador para desenvolvermos todos os projetos propostos neste curso. Quem desejar poderá criar os projetos usando outros microcontroladores e compiladores disponíveis no mercado.

       Neste tópico do curso iremos usar as seguintes ferramentas para programar o microcontrolador PIC 16F877:
O ambiente MPLAB IDE da MICROCHIP versão 7.21 ou superior;
O compilador PCW C Compiler IDE da CCS versão Trial 30 dias;
Uma gravador serial que dê suporte ao PIC 16F877 e grave a partir do MPLAB (PICStart Plus).

Obs.:  Os programas dessa aula foram gravados no PIC 16F877, usando o gravador McFlash da Mosaico (www.mosaico-eng.com.br).
       ANTES de começarmos a programar, vamos conhecer algumas características do microcontrolador PIC 16F877, como, as portas disponíveis, o nome e o número de cada pino, o tamanho da memória de programa entre outras.
       Quem deseja se aprofundar na programação de microcontroladores PIC usando a linguagem C, pode aprender muito através do livro "Microcontroladores PIC - Programação em C" escrito pelo autor Fábio Pereira - Editora Érica. Todos os programas exemplos desse livro foram escritos com base nos compiladores da CCS, onde há uma biblioteca de funções para facilitar a programação.
       Nesta aula são apresentados vários circuitos exemplos e seus respectivos programas fonte. Já na próxima aula iremos aprender a usar o compilador da CCS e o MPLAB para efetuar a gravação no PIC 16F877.

Características básicas do PIC 16F877:

- 33 pinos de I/O;
- 8k de memória de programa FLASH;
- 368 bytes de memória RAM;
- 256 bytes de memória EEPROM;
- Velocidade máxima de trabalho 20Mhz;
- Watchdog timer (WDT);
- 3 Timers;
- 8 canais A/D de 10 bits;
- 1 USART síncrona/assíncrona;
- Porta Paralela escrava (PSP);
- Porta serial síncrona SSP, SPI e I2C;

Entre outras.
Figura 1 - Pinagem do PIC 16F877
       A figura acima mostra todos os pinos do PIC 16F877, com seus respectivos nomes/funções. Os pinos (RA0 a RA5) estão associados a porta 'A'. (RE0, RE1 e RE2) a porta "E". (RC0 a RC7) a porta "C". (RD0 a RD7) a porta "D". E por último, os pinos (RB0 a RB7) associados a porta "B". Cada um destes pinos pode ser usado como entrada ou saída e são definidos na programação. Observe que a maioria dos pinos teem mais de uma função. Como exemplo veja o pino 10 que teem as funções de entrada/saída digital (RE2) e de selecionar um chip SPI (CS); ou a função de um canal A/D (AN7).
Figura 2 - Simples diagrama interno do PIC16F877
       Como um simples exemplo didático da estrutura interna do microcontrolador PIC 16F877, é possível observar na figura acima, que ele é composto de vários módulos como: uma unidade lógica e de controle, memórias RAM e ROM, Portas de entradas e saídas e também vários periféricos de grande utilidade para a implementação de muitos projetos interessantes. Grosso modo, um microcontrolador tem várias características de um microcomputador. Sendo assim, em alguns projetos, não necessitamos de um computador para executar determinadas funções, pois o microcontrolador dispõe do que é preciso para o projeto funcionar.
       Se desejarmos obter uma informação processada pelo microcontrolador de forma visual, poderemos conectar a ele um display LCD, LEDS ou mesmo conectar a um microcomputador através de uma de suas portas: Serial, Paralela, USB etc.
Descrição de algumas funções do compilador CCS usadas aqui em nossos exemplos:
 Função set_timer0()
Altera o conteúdo interno do timer0. Esta função aceita como parâmetro uma variável ou uma constante de 8 bits.
Exemplo:
set_timer0(131); //inicializa o valor do timer0 em 131.

 Função get_timer0()
Obtém o valor interno do timer0. Ela retona um valor de 8 bits.
Exemplo:
int8 valor;
valor = get_timer0();

 Função set_tris_d()
Escrita e leitura na porta D. Ou seja, define se um ou vários pinos são entradas ou saídas na porta D.
Um bit '1' indica que o respectivo pino associado a uma porta será usado como entrada (Input). E um bit '0', saída (Output). O parâmetro pode ser passado à função set_tris_d() também no sistema de numeração binário usando a constante 0b.
Exemplo:
set_tris_d(0b01000001); //Os pinos RD6 e RD0 são definidos como entradas e os demais como saídas.
ou em hexadecimal:
set_tris_d(0x41);

 Função setup_timer_0()
Configura o prescaler do timer0. O parâmetro passado é uma constante predeterminada usada para dividir o sinal de contagem por um prescaler (divisor de freqüência).
Exemplo:
setup_timer_0
(RTCC_INTERNAL | RTCC_DIV_64);
 //Informa que o timer0() usa interrupção interna, e que a freqüência é dividida por 64 (prescaler).

 Função enable_interrupts()
Usada para habilitar uma interrupção.
Exemplos:

enable_interrupts( GLOBAL ); //Habilita o sistema de interrupção geral. enable_interrupts( int_timer0 ); //Habilita interrupção do timer0().
enable_interrupts( int_rda ); //Habilita interrupção para leitura de caracter pela USART. 
ou 

enable_interrupts
(GLOBAL | int_timer0 | int_rda);
 //Ou todas através do operador OR ' |'.

 Função input()
Lê o estado de um pino de uma determinada porta.
Exemplo:
boolean estado;
estado = input(pin_d2); //Lê o estado do pino RD2 da porta D.
Se o valor da variável estado for '0' (false), isso indica que o nível lógico do pino RD2 é baixo (low). Se for '1' (true), o nível lógico no pino RD2 éalto (high).

 Função output_bit()
Liga ou desliga um determinado pino.
Essa função aceita dois parâmetros: o primeiro é o pino e o segundo é se ele será ligado ou desligado.
Exemplos:
output_bit(pin_d0, 1); //Põe pino RD0 em nível alto (high). Pode-se usar a constante true em vez de '1'. output_bit(pin_d0, 0); //Põe pino RD0 em nível baixo (low). Pode-se usar a constante false em vez de ' 0'.

 Função output_high()
Liga (põe em nível alto) um determinado pino.
Exemplos:
output_high(pin_d2); //Põe o pino RD2 da porta D em nível Alto.
É o mesmo que usar:
output_bit(pin_d2, true);

 Função output_low()
Desiga (põe em nível baixo) um determinado pino.
Exemplos:
output_low(pin_d2); //Põe o pino RD2 da porta D em nível Baixo.
É o mesmo que usar:
output_bit(pin_d2, false); 


 Função delay_ms()
Retarda o processamento do programa em milisegundos.
Exemplos:
delay_ms(15); //Aguarda 15 milisegundos.
delay_ms(1000); //Aguarda 1 segundo.

 Função getc()
Aguarda e chegada de um caracter na porta serial (USART).
Exemplo:
char valor;
valor = getch(); //Espera a chegada de um caracter na Serial e armazena-o na variável valor.

 Função printf()
Envia um ou mais caracteres formatados, pela porta serial (USART). Usa os mesmos caracteres padrão de formatação da função printf() ANSI.
Exemplos:
printf("Curso USB/Serial.\r\n"); //Envia uma sting constante.
printf("%d", 85); //Envia um número decimal.

int valor = 0x3F;
printf("%X", valor); //Envia um número hexadecimal.

char *texto = "Teste de transmissão.\r\n";
printf("%s", texto); //Envia uma string a partir de uma variável

Diretivas

#int_rda
Usada para definir uma função de interrupção para leitura dos caracteres que chegam no buffer da porta serial.

#include <16F877.h>
inclui o arquivo cabeçalho usado para se trabalhar com o PIC 16F877. Esse arquivo contém várias constantes e definições úteis.

#use delay(CLOCK=4000000)
Define o valor do relógio do PIC. Este valor tem que ser idêntico ao da freqüência do cristal ou resonador externo. Para usar as funções delay_us(), delay_ms(), delay_cycles() é necessário definir #use delay().

#fuses XT, PUT, NOWDT, NOBROWNOUT, NOLVP
Esta diretiva define quais fusíveis interno do PIC são configurados. Os parâmetros são armazenados no arquivo .HEX e são usados somente na hora da gravação.

Veja o significado de alguns fusíveis:

 Tipo de osciladores:

 LP - Low Power (oscilador < 200Khz);
 RC - Oscilador Resistor/Capacitor;
 XT - Oscilador a cristal <= 4Mhz;
 HS - High Speed (alta velocidade) > 4Mhz.


Outros fusíveis:
PUT ---> (Power Up Timer). Temporizador de power up ligado;
NOPUT ---> (No Power Up Timer). Temporizador de power up desligado;
WDT ---> (Watch Dog Timer) habilitado. O programa é resetado se por algum motivo, travar;
NOWDT ---> (No Watch Dog Timer) desabilitado. Se travar, o programa não é resetado;
BROWNOUT ---> Reset por queda de tensão habilitado. Sempre que a alimentação cai a um valor mínimo;
NOBROWNOUT ---> Reset por queda de tensão desabilitado. O PIC não é resetado;
LVP ---> Programação em baixa tensão habilitada;
NOLVP ---> Programação em baixa tensão desabilitada;
PROTECT ---> Protege todo o código do programa contra leitura;
NOPROTECT ---> Desabilita a proteção do código do programa contra leitura.
Obs.: Nem todos os modelos de PIC aceitam todas as constantes de fusíveis.

#use rs232(BAUD=9600, PARITY=N, BITS=8, XMIT=pin_c6, RCV=pin_c7) 

Configura os parâmetros da comunicação serial.

BAUD ---> Velocidade da transmissão (depende da freqüência do cristal).
PARITY ---> Paridade (N=nenhuma, E=par, O=ímpar);
BITS ---> Bits de dados (5, 6, 7, 8 ou 9);
XMIT ---> Especifica o pino que irá transmitir os dados ( no 16F877 o pin_c6 é fixo usando o USART);
RCV ---> Especifica o pino que irá receber os dados ( no 16F877 o pin_c7 é fixo usando o USART);

Obs.: É possível escolher outros pinos para XMIT e RCV, porém, todo o processo de transmissão e recepção de dados ficará por conta do software.

Definindo a direção dos pinos de I/O
       No PIC, os pinos de I/O podem ser definidos tanto como entradas como saídas, sendo assim, através de um único pino, podemos envia ou receber um sinal, para isso, é preciso definir a direção do pino através da função set_tris_X(). No nosso exemplo abaixo estamos usando a porta D. Se desejarmos definir todos os pinos da porta D como entradas, usamos a função set_tris_d(0b11111111). Para definirmos todos os pinos da porta D como saídas, usamos set_tris_d(0b00000000) com todos os bits zeros. Os bits estão associados aos pinos (RD7 a RD0) da direita para a esquerda, ou seja, bit mais significativo igual a RD7, e menos significativo igual a RD0.
Figura 3 - Direção dos pinos da porta D

Diagrama Elétrico do Microcontrolador

0 comentários:

Postar um comentário