O objetivo deste artigo é explicar o funcionamento dos Configuration Bits do microcontrolador PIC16F877A. Para tanto, vamos fazer uso da IDE MPLAB-X versão 2.00, além do montador MPASM na versão 5.54 e compilador XC8 versão 1.31, além, é claro, do MPLAB IDE Versão 8.76. Todos esses ambientes podem ser encontrados gratuitamente no site da Microchip.
Um pouco sobre o microcontrolador PIC16F877A
Este microcontrolador é bastante popular aqui no Brasil. Apesar de não chegar perto da capacidade de qualquer ARM Cortex, este dispositivo de 8 bits costuma ser o primeiro (ou um dos primeiros) microcontroladores que muitos tem contato. Suas principais características são:
- Flash de 14,3KBytes (8KPalavras, uma vez que o tamanho da palavra é de 14 bits);
- RAM de 368Bytes;
- EEPROM de 256Bytes;
- 33 IOs;
- 8 Canais AD de 10 bits;
- Comunicação I2C, SPI e USART;
- 2 Timer de 8 bits e 1 timer de 16 bits;
- 2 Comparadores.
O que são Configuration Bits
Os microcontroladores Microchip possuem regiões de memória definidas para uso específico, contendo Bits de Configuração (Configuration Bits ou Fuse Bits). Esses bits determinam o funcionamento fundamental do dispositivo, como modo do oscilador, Watchdog Timer, modos de programação e proteção de código. A correta configuração desses bits definem o funcionamento do seu microcontrolador. Para tanto, vamos entender como fazer esse trabalho.
Quais os Configuration Bits do PIC16F877A
Os periféricos do dispositivo afetados pelos Configuration Bits são: Oscilador, Watchdog Timer, Power-up Timer, Brown-out Reset, ICSP e proteção de memória. Para este caso trata-se de apenas uma região de memória com apenas uma palavra (apesar do núcleo ser 8 bits, o tamanho da palavra é 14 bits).
Primeiramente, vamos entender com detalhes o que acontece no hardware com a mudança de cada bit desse controle. Cada periférico terá um comportamento diferente, dependendo de sua função no dispositivo.
- Configuration Bits: Oscillator Selection Bits (FOSC1:FOSC0)
Trata-se de dois bits que configuram o oscilador externo do microcontrolador. Ele define, basicamente, o tipo de oscilador (cristal, ressonador ou RC) e a velocidade de chaveamento. Os valores possíveis para teste registrador são:
| 00 = LP oscillator | (Low-Power Crystal) |
| 01 = XT oscillator | (Crystal/Resonator) |
| 10 = HS oscillator | (High-Speed Crystal/Resonator) |
| 11 = RC oscillator | (Resistor/Capacitor) |
|
A escolha entre esses modos tem mais a ver com a frequência do que com o tipo do oscilador em si. As configurações HS, XT e LP podem ser aplicadas tranquilamente para um cristal oscilador, e HS e XT também aceitam ressonadores.
Como na tabela ao lado, para valores de frequência é que vão definir qual será a configuração. A opção HS é para cristais ou ressonadores de 4MHz a 20MHz. Já para frequências entre 200KHz e 4MHz, deve-se utilizar a configuração XT. |


No entanto, quando falamos em LP, falamos de frequências muito baixas. Esse modo de trabalho mantém o microcontrolador em baixo consumo, ideal para situações de bateria ou economia de energia. As frequências são extremamente baixas, de 32KHz a 200KHz. Para esse caso não é possível trabalhar com ressonadores, apenas cristais.
Ao lado temos o esquema interno do circuito oscilador. Trata-se de uma porta inversora que gera um sinal na frequência do cristal ou ressonador.
Como opção de baixo consumo, o LP trabalha da mesma forma que o HS e XT. No entanto, com frequência de trabalho bem mais baixa, na faixa das dezenas ou centenas de KHz. Neste caso, o maior ganho é na potência consumida, uma vez que todo o circuito consome menos nessa frequência de operação.
|
Uma outra opção de configuração de oscilador é o RC. Trata-se de um circuito muito simples, contendo apenas um resistor e um capacitor. Neste caso, as velocidades são baixas como para a configuração LP. No entanto, enquanto o LP ganha em desempenho, o RC ganha em custo, uma vez que tratam-se de componentes mais baratos.
Outra desvantagem desse circuito é a precisão. Além dos valores de tolerância dos próprios componentes, essa montagem é bastante influenciada pela temperatura e umidade do ambiente. |

- Configuration Bits: Watchdog Timer Enable Bit (WDTE)
Este bit habilita o circuito de Watchdog Timer (WDT). Trata-se de um timer que roda livremente através de um oscilador RC integrado, não exigindo nenhum componente externo.Isso significa que este timer estará rodando mesmo que o clock principal esteja parado.
| 1 = WDT Enable |
| 0 = WDT Disable |
Em seu funcionamento normal, esse timer gera um sinal de reset quando o timer estoura (TimeOut). Caso o dispositivo esteja em Sleep Mode, o WDT causa um Wake-Up (acorda), acordando e voltando ao funcionamento normal. O TimeOut desse vomponente pode variar bastante, tendo seu valor nominal como TWDT=18mS, mas podendo variar de 7 a 33mS.
No entanto, cuidado. É preciso desenvolver o código considerando o uso do WDT. Periodicamente, em um tempo menor que 7mS (tempo mínimo no pior caso), você deve gerar uma instrução de CLRWDT. Dessa forma, o WDT será sempre reiniciado e o microcontrolador irá trabalhar normalmente. Se o seu código travar, o sistema não vai enviar o CLRWDT e o microcontrolador irá reiniciar.
- Configuration Bits: Power-up Timer Enable Bit (PWRTE)
Este bit habilita o Power-up Timer. Esse circuito é responsável por manter o núcleo em estado de reset por um período após o circuito ser ser alimentado (Power-up). Durante esse período, o dispositivo estará trabalhando com o RC interno, mantendo o estado de reset mesmo antes do circuito oscilador principal funcionar. No entanto, da mesa forma que o WDT, seu tempo varia bastante. Tem sem valor nominal como TPWRT=72mS, mas varia entre 28 e 132mS.
| 1 = PWRT disabled |
| 0 = PWRT enabled |
Este tipo de solução é bastante eficiente para fontes de alimentação menos elaborados, que demoram alguns milissegundos para atingir sua carga máxima. Fazendo uso do Power-up Timer, garantimos que a CPU apenas irá começar a funcionar com o circuito estabilizado.
- Configuration Bits: Brown-out Reset Enable Bit (BOREN)
Este bit habilita o circuito de Brown-out Reset. Este circuito é responsável por geral um sinal de Reset para a CPU quando a tensão de alimentação cai abaixo de um limite definido como VBOR=4,0V por um período superior a TBOR=100uS, Uma vez que Brown-out Reset ocorra, o circuito irá manter o sistema em Reset até que a tensão retorne a valores superiores a VBOR.
| 1 = BOR Enabled |
| 0 = BOR Disabled |
Embora a tensão de alimentação desse componente trabalhe em uma faixa bastante grande, de 2,0V a 5,5V, a tensão de VBOR é definida em seus 4,0V, podendo apenas variar entre 3,65V e 4,35V.
- Configuration Bits: Low-Voltage ICSP Enable Bit (LVP)
Assim como a maioria dos microcontroladores, este possui um sistema de gravação ICSP (In-Circuit Serial Programming), que permite programar o componente já integrado no seu circuito final. Para tanto, ele faz uso de dois pinos, um para clock (PGC) e outro para dados (PGD), além de alimentação e MCLR. No entanto, para que o circuito entre no processo de gravação sem maiores problemas, é necessário aplicar uma tensão (VPP ou VIHH) relativamente alta para circuitos digitais no pino de MCLR. Essa tensão pode variar entre VIHHmin=VDD+3,5V e VIHHmáx=13,5V. Caso esteja trabalhando com uma alimentação de 5V, a tensão mínima seria de VIHHmin=8,5V.
Em determinados circuitos, esse tipo de tensão aplicado ao MCLR pode vir a ser um problema. Por conta disso, é possível habilitar o Configuration Bit LVP, que permite a gravação do componente com a própria tensão de alimentação. Além disso, o pino PGM passa a ser utilizado para a indicação de ICSP,e faz parte do processo de gravação.
| 1 = LVP Enabled | Pino RB3/PGM como PGM. |
| 0 = LVP Disabled | Pino RB3 como IO, VPP no MCLR precisa ser utilizado para gravação. |
- Configuration Bits: Data EEPROM Memory Code Protection Bit (CPD)
Como dito anteriormente, este dispositivo possui uma memória EEPROM interna de dados. São 256Bytes de memória para uso geral do dispositivo. O Configuration Bit CPD protege essa região de memória contra leituras e gravações externas. Dessa forma, apenas com um código dentro do microcontrolador é possível ler ou escrever dados na EEPROM.
| 1 = Data EEPROM Code Protection Off |
| 0 = Data EEPROM Code Protected |
- Configuration Bits: Flash Program Memory Write Enable Bits (WRT1:WRT0)
Estes bits habilitam a escrita na memória Flash através do uso do EECON. Dessa forma, possível escrever dados diretamente na memória Flash pelo firmware do dispositivo. Além disso, é possível selecionar os setores que a gravação de dados estará habilitada, conforme a tabela abaixo.
| 11 = Write Protection Off | Toda a memória de programa pode ser escrita por EECON. |
| 10 = 0000h to 00FFh write-protected | De 0100h a 1FFFh podem ser escritos por EECON. |
| 01 = 0000h to 07FFh write-protected | De 0800h a 1FFFh podem ser escritos por EECON. |
| 00 = 0000h to 0FFFh write-protected | De 1000h a 1FFFh Podem ser escritos por EECON. |
-
Configuration Bits: In-Circuit Debugger Mode Bit (Debug)
Os pinos RB6/PGC e RB7/PGD podem ser utilizados tanto como IOs comuns, como pinos de gravação ICSP. O controle dessas funções é feita por esse bit que, quando habilitado, dedica os pinos ao processo de Debug. Quando desabilitado, permite o uso como entradas e saídas digitais.
| 1 = In-Circuit Debugger Disabled | RB6 e RB7 como pinos GPIO |
| 0 = In-Circuit Debugger Enabled | RB6 e RB7 são dedicados ao Debugger |
É importante indicar que Debug e Gravação são processos diferentes. Esses pinos são utilizados para o processo de gravação, e a alteração desse bit não vai impedir esse processo. O Debug é o uso de uma ferramenta como ICD3 ou RealICE que permite a execução e o acompanhamento de código, leitura de variáveis e execução passo-a-passo.
- Configuration Bits: Flash Program Memory Code Protection Bit (CP)
Este bit é responsável por habilitar a proteção de código. Uma vez habilitado, a memória Flash (memória de programa) estará protegida contra cópia e não poderá ser lida. É necessário verificar a integridade da gravação antes de habilitar esse bit, uma vez que é necessário a leitura para garantir a gravação. No entanto, é sempre possível apagar o componente e realizar uma nova gravação.
| 1 = Code Protection Off |
| 0 = All Program Memory Code-Protected |
Configurando pelo Código
Para os exemplos que se seguem, vamos imaginar que estamos trabalhando com um cristal de 20MHz (FOSC = HS) e que desejamos o Power-up Timer (PWRT = ON) para garantir todo o circuito esteja seguro quando o software iniciar. Também vamos imaginar que não utilizaremos o Watchdog Timer (WDTE = OFF), mas teremos o Brown-out Reset habilitado (BOREN =ON).
Manteremos o Low Voltage Programming desabilitado (LVP = OFF), uma vez que a maioria dos gravadores geram a tensão necessária para a gravação normal, e não teremos nenhum tipo de proteção para o código.
- Códigos em Assembly
Para esse caso, o software de montagem MPASM está preparado para a premissa __CONFIG, que se encontra definida no arquivo de cabeçalho p16f877a.inc do montador. Nesse arquivo também são definidos os valores para cada configuração (configuration bits), de maneira fácil de ser entendida. Seus valores possíveis são:
| _FOSC_LP | Oscilador LP |
| _FOSC_XT | Oscilador XT |
| _FOSC_HS | Oscilador HS |
| _FOSC_EXTRC | Oscilador RC |
| _WDTE_OFF | WDT Disabled |
| _WDTE_ON | WDT Enabled |
| _PWRTE_ON | PWRT Enabled |
| _PWRTE_OFF | PWRT Disabled |
| _BOREN_OFF | BOR Disabled |
| _BOREN_ON | BOR Enabled |
| _LVP_OFF | RB3/PGM como IO. VIHH em MCLR para gravação |
| _LVP_ON | RB3/PGM como PGM. Gravação em Low-Voltage |
| _CPD_ON | Data EEPROM Code-Protected |
| _CPD_OFF | Data EEPROM Code Protection Off |
| _WRT_HALF | 1000h a 1FFFh podem ser escritos |
| _WRT_1FOURTH | 0800h a 1FFFh podem ser escritos |
| _WRT_256 | 0100h a 1FFFh podem ser escritos |
| _WRT_OFF | Toda a memória pode ser escrita |
| _DEBUG_ON | In-Circuit Debugger Enabled |
| _DEBUG_OFF | In-Circuit Debugger Disabled |
| _CP_ON | Memória de programa protegida |
| _CP_OFF | Memória de programa não protegida |
A utilização desse código é bastante simples. Uma vez tendo incluído o arquivo de cabeçalho, a implementação do código é feita com a lógica AND para a separação das premissas de configuração.
; PIC16F877A Configuration Bits ' Settings #include "p16F877A.inc" ; CONFIG ; __config 0xFF72 __CONFIG _FOSC_HS & _WDTE_OFF & _PWRTE_ON & _BOREN_ON & _LVP_OFF & _CPD_OFF & _WRT_OFF & _CP_OFF
- Códigos em C
Um método comum de configuração desses bits é dentro do código através das diretivas de pré-processamento. Essas diretivas são instruções interpretadas por um pré-processador para preparar o código para o compilador. Elas são analisadas antes da efetiva compilação, e podem modificar como o código será compilado.
Existem diversas diretivas, algumas de decisão, outras de definição de constantes, ou mesmo macro de funções. No nosso caso, a diretiva de pré-processamento que nos interessa é o pragma, mas especificamente o pragma config. Nem todos os compiladores possuem essas diretivas, então estamos falando especificamente do compilador XC8 da Microchip. Para este caso, as opções são mais simples. Cada bit possui um nome específico, onde apenas se pode configurar como ON ou OFF. Apenas FOSC possui mais opções, conforme abaixo.
| FOSC | EXTRC, HS, XT, LP |
| WDTE | ON ou OFF |
| PWRTE | ON ou OFF |
| BOREN | ON ou OFF |
| LVP | ON ou OFF |
| CPD | ON ou OFF |
| WRT | ON ou OFF |
| CP | ON ou OFF |
Em nosso exemplo, a configuração seria conforme abaixo:
#include <xc.h> // CONFIG #pragma config FOSC = HS // Oscillator Selection bits (HS oscillator) #pragma config WDTE = OFF // Watchdog Timer Enable bit (WDT disabled) #pragma config PWRTE = ON // Power-up Timer Enable bit (PWRT enabled) #pragma config BOREN = ON // Brown-out Reset Enable bit (BOR enabled) #pragma config LVP = OFF // Low-Voltage (Single-Supply) In-Circuit Serial Programming Enable bit (RB3 is digital I/O, HV on MCLR must be used for programming) #pragma config CPD = OFF // Data EEPROM Memory Code Protection bit (Data EEPROM code protection off) #pragma config WRT = OFF // Flash Program Memory Write Enable bits (Write protection off; all program memory may be written to by EECON control) #pragma config CP = OFF // Flash Program Memory Code Protection bit (Code protection off)
Configuration Bits setados pela IDE MPLAB IDE 8
Embora a Microchip tenha descontinuado o ambiente de desenvolvimento MPLAB IDE 8, este ainda é muito utilizado e merece um espaço neste artigo. Neste caso, é possível fazer a configuração dos bits diretamente no ambiente, não havendo a necessidade de escrevê-lo em código. Essa configuração é acessível conforme o menu abaixo.
Nele existe um check-box chamado “Configuration Bits set in code“. Quando este está habilitado, o sistema irá considerar as configurações feitas em código, conforme vimos anteriormente. Com este check-box está desabilitado, o sistema irá aceitar a configuração dos bits conforme a imagem abaixo.
A configuração é a mesma e respeita exatamente as mesmas opções que já abordamos. A única diferença é que o ambiente lhe dá um menu de opções mais agradável ao desenvolvedor.
Gerando configuração pela IDE MPLAB-X
Diferentemente do MPLAB IDE 8, o MPLAB-X não permite configurar os configuration bits diretamente na IDE. Essas configurações precisam estar presentes no código.
No entanto, o ambiente possui uma ferramenta integrada bastante interessante. Ela permite a geração das configurações para serem incluídas no código. Além disso, o sistema é inteligente o suficiente para gerar em Assembly ou C de acordo com a configuração do seu projeto. O procedimento é idêntico para ambos os casos e começa com a seleção do menu correto.
Esse menu possui as mesmas opções vistas anteriormente, de maneira muito similar ao MPLAB IDE 8. Você faz as configurações com opções claras e bastante amigáveis. Após terminar suas configurações, basta pressionar o botão “Generate Source Code to Output“.
É importante saber que o código apresentado não foi incluído no seu programa, ele apenas foi apresentado. Basta o desenvolvedor copiar esse resultado e colar em seu código.

Conclusão
Embora os configuration bits do PIC16F877A sejam bastante específicos, mesmo dentro da linha dos microcontroladores PIC, pudemos observar com detalhes a função individual de cada bit, além de analisar cada uma de suas opções.
Também observamos como fazer a configuração dos configuration bits em código, tanto para a linguagem C quando para Assembly. Pudemos observar como trabalhar com as ferramentas presentes nos ambientes, sejam eles novos ou legados.
Agradecimentos
Gostaria de agradecer ao Josué Furtoso, por toda a ajuda, paciência e inspiração.
Referências
Flash Memory Programming Specification














sabe como insserir o arqquivo 18f87k22_g.lkkr num projeto pro mpllab x?
Queria mais detalhes sobre a programação desse pic. Possuo um módulo/gravador com socket ZIF e só conheço um pouco do ambiente MPLABX, queria saber como posso gravar meu primeiro firmware nele.
Francesco, quando você mostra a configuração em C eu não consigo identificar a configuração do:_DEBUG_ONIn-Circuit Debugger Enabled_DEBUG_OFFIn-Circuit Debugger Disabled
Poderia esclarecer? Obrigado!
Olá Gabriel, Gostei do seu comentário, realmente parece que os headers do PIC16F877A não possuem a configuração para o DEBUG_ON. Verifiquei o seguinte: Para o MPASM (eu sei, assembly) ele possui o p16f877a.inc que contém o _DEBUG_ON para a configuração. No entanto, verificando o p16f877a.h do XC8, não encontrei a mesma coisa. O que você pode fazer é a configuração manual, pois o valor para esse bit é 37FF de uma mascara de 3FFF. o que indica que trata-se do bit 11. Vou fazer a atualização do MPLAB e do XC8 para ver se houve alguma modificação nas novas versões.… Leia mais »
Muito bom, Francesco!
Olá Vagner,
Obrigado pelo retorno.
Cara, excelente! Desbravar o datasheet de um microcontrolador não é tão simples, essa ajudazinha nos primeiros passos é sempre bem vinda!
Se eu fosse compilar sem o XC8 (qualquer outro compilador que não possui a diretiva pragma) como eu declararia cada fuse bit?
boa noite, estou tentando fazer o codigo do pic 16f877A //GERADOR DE FUNÇÕES #include #use delay (clock=20000000) #fuses HS, NOWDT, PUT, BROWNOUT, NOLVP #define LCD_DB4 PIN_D4 #define LCD_DB5 PIN_D5 #define LCD_DB6 PIN_D6 #define LCD_DB7 PIN_D7 #define LCD_E PIN_E1 #define LCD_RS PIN_E0 #include “lcd.c” int8 k=1, ct_p = 0; int16 freq, per, temp; float freq_k; int1 flag=0; int16 x=0,y=0; #int_ccp1 //Interrupção Captura do CCP1 void capture_isr() { ++ct_p; per = get_timer1(); set_timer1(0); } atualiza_lcd() { switch (x)//seleção da forma de onda { case 0:lcd_putc(“f ONDA SENOIDAL”); output_high(pin_b3); output_low(pin_b4); break; case 1:lcd_putc(“f ONDA QUADRADA”); output_high(pin_b4); output_low(pin_b3); break; case 2:lcd_putc(“f ONDA TRIANGULAR”); output_high(pin_b3);… Leia mais »
Olá Aldanisio, Fiz alguma correções de sintaxe e o código compilou com sucesso. Não testei a lógica do programa. Por favor compare o código a seguir com o seu para verificar as diferenças. https://pastebin.com/VdZpPd6a