Nos próximos blocos entramos na rotina principal do programa. Nela, configuraremos as funções dos periféricos do PIC16F628A. Vale salientar que os pontos principais sao as configurações dos timers 1 e 2, assim como a configuração das interrupções. Estas configurações serao abordadas mais adiante.
Repare que a execução das configurações iniciais e dos periféricos só é executada uma aºnica vez, durante a inicialização do PIC. Após a limpeza dos PORTs, entramos em um loop infinito, onde o microcontrolador executará as funções principais de nosso programa.
Neste loop infinito (iniciado na instrução while(true), as funções executadas envolvem:
• Limpar o contador do Watch Dog Timer
• Testar o contador de período para o LED vermelho e compará-lo ao valor especificado para o Duty Cicle do mesmo. Se este valor for igual ou maior ao especificado, entao o pino que controla este LED recebe o valor lógico “0â€, ou seja apaga o LED (atingiu o ponto B na figura 5).
• Testar, analogamente ao executado para o LED vermelho, os LEDs verde e azul (seguindo esta ordem).
• Testar se alguma das seis chaves está pressionada. O fluxo de teste destas chaves pode ser visto na figura 7, que será detalhado mais a frente.
Após estes passos, o programa retorna para o passo 1 acima descrito, reiniciando o ciclo.
O próximo fluxo que iremos analisar é o fluxo dos botaµes, que pode ser visualizado na figura 7.

Este fluxo pode parecer complicado a primeira vista, mas a sua implementação é muito simples. Basicamente as suas funções sao:
• Verificar se o botao está pressionado;
• Verificar se o botao já estava pressionado no ciclo anterior;
• Se o botao já estava pressionado, decrementar o contador para o filtro de debouncing;
• Se o contador do filtro estiver zerado, marcará um flag indicando que o botao já estava pressionado;
• No caso de ser um botao de incremento do Duty Cicle de um LED específico, a variável responsável (pwm_red, pwm_green ou pwm_blue) será incrementada em uma unidade, respeitando-se o valor máximo definido pela constante MAX. No nosso caso, esta constante foi definida com o valor “10†(LED com intensidade de carga máxima – Duty Cicle de 100%);
• Caso seja um botao de decremento do Duty Cicle, as variáveis pwm_red, pwm_green ou pwm_blue serao decrementadas em uma unidade, respeitando-se o valor mínimo definido pela constante MIN. No nosso exemplo, esta constante foi definida com o valor “0†(LED apagado – Duty Cicle de 0%);
• Após este passo, o programa segue seu fluxo normal.
Na definição do programa, temos também que definir as ações que as interrupções para o TIMER1 e para o TIMER2 irao executar. O fluxo de execução do TIMER1 pode ser visto na figura 8. Esta interrupção é bem simples. Aliás fica aqui uma “dicaâ€: Os códigos para as interrupções devem ser bem enxutos para evitar que uma interrupção ocorra enquanto estivermos dentro de outra interrupção. Se isto não for bem controlado, o seu programa poderá apresentar resultados imprevisíveis.

Basicamente, como podemos ver na figura 8, esta interrupção apenas incrementa uma unidade no contador do período de cada Duty Cicle. Estas variáveis foram definidas como contador_red, contador_green e contador_blue. Após este incremento, ele carrega o TIMER1 com o valor de 63535. Com isto, o TIMER1 irá “estourar†a cada exato 1 ms.
Mais adiante estudaremos mais sobre o TIMER1.
O aºltimo fluxo que analisaremos é o da interrupção do TIMER2, ilustrado na figura 9. Este é um pouco mais complexo que o da interrupção do TIMER1, mas também é muito simples de ser implementado.

Esta interrupção é responsável por gerar a frequaªncia do PWM para os LEDs, e as funções que esta executa nada mais é que verificar se o PWM ajustado para a cada LED é diferente de zero. Se esta condição for verdadeira, ele irá colocar a saída em nível lógico “1â€, e representa o ponto A que vimos na figura 5.
É igualmente importante que esta interrupção zere os contadores de todos os períodos para os LEDs, para garantir que as características do ciclo que estiver sendo executado sao as mesmas do mesmo do ciclo anterior.
Esta interrupção inclusive carrega o TIMER1 com o valor 63535 para que o TIMER1 também comece a marcar o período de 1 ms necessário para incrementar os contadores dos LEDs.
Feito isso, verificamos que com, estas configurações de TIMER1 e TIMER2 podemos ter os valores 0 ms, 1 ms, 2 ms, 3 ms, 4 ms, 5 ms, 6 ms, 7 ms, 8 ms, 9 ms e 10 ms para o PWM, representando Duty Cicles de 0%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90% e 100%, respectivamente.
O TIMER1
O TIMER1 é um módulo de 16 bits, composto por dois registradores de 8 bits cada (TMR1H e TMR1L). Além da função de leitura destes registradores, até podemos alterar os seus valores (possuem função de escrita). Isto será muito aºtil quando quisermos iniciar este timer com um valor pré-definido e nos permitirá configurar o timer para que a interrupção ocorra em intervalos pré-determinados por nós.
Ele é utilizado como base para o módulo “Capture e Compare†e pode operar em traªs modos distintos.
O primeiro modo é o de Temporizador Síncrono (Synchronous Timer). Neste modo, o TIMER1 é incrementado em cada ciclo de instrução (ciclo de máquina) que é dado pela fórmula fosc / 4, onde fosc é a frequaªncia do oscilador (interno ou externo) do PIC16F628A.
O segundo modo de operação deste Timer é o de Contador Síncrono (Synchronous Counter). Neste modo, o TIMER1 será incrementado a cada borda de subida do sinal aplicado ao pino T1CKI. Com esta configuração, durante o modo SLEEP, este Timer não será incrementado, mesmo se o sinal externo estiver presente.
O terceiro modo é o Contador Assíncrono (Asynchronous Counter). Neste modo, semelhante ao que acontece no contador Síncrono, o TIMER1 será incrementado a cada borda de subida do sinal aplicado ao pino T1CKI. A diferença entre os dois contadores está no fato de que, neste modo, o TIMER1 continua a ser incrementado independentemente do clock interno do PIC ou se ele estiver durante uma operação de SLEEP. Devido a estas características, durante o SLEEP, uma interrupção pode ser gerada “acordando†o microcontrolador para reiniciar as suas funções. Outra característica deste modo, é que, uma vez que ele não está sincronizado com o clock interno do PIC, ele pode ser usado como base para implementar um Real Time Clock (RTC). Operando como Contador Assíncrono, o TIMER1 não pode ser usado como base de tempo para as operações de Capture e Compare.
Para configurarmos o TIMER1, utilizando o compilador da CCS, precisamos declarar a função setup_timer_1(modo), onde modo pode ser:
• T1_DISABLED – Desabilita o TIMER1;
• T1_INTERNAL – Modo Temporizador Síncrono;
• TI_EXTERNAL – Modo Contador Assíncrono;
• T1_EXTERNAL_SYNC – Modo Contador Síncrono.
O modo que iremos utilizar em nosso projeto é o Temporizador Síncrono. Portanto, a sintaxe para configurar o TIMER1 é setup_timer_1(T1_INTERNAL).
Outra característica do TIMER1 é o prescale, que nada mais é que um divisor de frequaªncia para o timer. Podemos aplicar um prescale no TIMER1 de valor 1, 2, 4 ou 8. Isso significa que podemos dividir o tempo de incremento do TIMER1 por 1, 2, 4 ou 8. Para configurar o prescale do TIMER1, também utilizaremos a sintaxe é setup_timer_1(modo). Neste caso, modo pode ser:
• T1_DIV_BY_1 – Prescale de 1 (sem prescale);
• T1_DIV_BY_2 – Prescale de 2 (divide a frequaªncia do TIMER1 por 2);
• T1_DIV_BY_4 – Prescale de 4 (divide a frequaªncia do TIMER1 por 4);
• T1_DIV_BY_8 – Prescale de 8 (divide a frequaªncia do TIMER1 por 8).
Em nosso código, não utilizaremos o prescale, ou seja, o modo será T1_DIV_BY_1.
Entao, o código para as configurações do TIMER1, em nosso código, deverá ser:
• setup_timer_1(T1_INTERNAL);
• setup_timer_1(T1_DIV_BY_1);
• Podemos ainda definir de outra forma, um pouco mais resumida, utilizando o caractere “|†(conhecido como “pipeâ€) para separar os argumentos. O nosso código ficará entao da seguinte forma:
• setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
• Com esta configuração, e utilizando um oscilador de 8 MHz, o TIMER1 será incrementado a cada 0,5 μs e gerará uma interrupção a cada 32.767,5 μs, ou seja, teremos cerca de 32,77 ms entre duas interrupções do TIMER1.
• Se atribuirmos o valor inicial para o TIMER1 de 63535, a interrupção acontecerá exatamente em 1 ms.
O TIMER2
O TIMER2 é um timer de 8 bits que conta com um prescaler, um postscaler e um registrador de período (conhecido como PR2).
O prescaler é um divisor de frequaªncia que vai dividir a frequaªncia do clock interno (fosc / 4) por 1, 4 ou 16.
O postscaler é um contador para as interrupções. Ele conta quanto ciclos completos (de 0 a 255) precisam ser realizados para que uma interrupção seja gerada. Ele pode assumir os valores de 1 a 16.
O registrador de período PR2 é utilizado para iniciar um valor pré determinado para o TIMER2, permitindo uma maior flexibilidade e controle do tempo em que a interrupção deve acontecer.
A fonte de clock para este timer é o clock do microcontrolador, ou seja, é fosc / 4. Devido a isto, o TIMER2 é suspenso durante uma operação de SLEEP, voltando a operar assim que o controlador “acordaâ€.
É o TIMER2 que é utilizado como base para a frequaªncia do PWM para os microcontroladores que possuem esta função diretamente no hardware.
O PIC16F628A já possui um pino específico para o PWM (por hardware), mas como precisamos controlar traªs pinos, e a idéia de nosso projeto é fazer o PWM por software, não vamos utilizar o hardware interno do PIC16F628A.
Apenas para fins didáticos, vamos utilizar o TIMER2 também como base da frequaªncia de nosso PWM.
Para configurarmos o TIMER2 usando o compilador C da CCS, precisamos empregar o seguinte comando setup_timer_2(modo, período, postscale).
Para o comando acima, o parâmetro modo: pode ser:
• T2 _DISABLED – Desabilita o TIMER2;
• T2_DIV_BY_1 – TIMER2 ativado, com prescale de 1;
• T2_DIV_BY_4 – TIMER2 ativado, com prescale de 4;
• T2_DIV_BY_16 – TIMER2 ativado, com prescale de 16.
Podemos utilizar para o parâmetro período qualquer valor inteiro entre 0 e 255, o que vai determinar quando que o valor do clock será resetado (reinicializado).
Para o parâmetro postscale, podemos utilizar um naºmero, também inteiro, entre 1 e 16 que irá determinar quantos resets serao necessários para gerar uma interrupção
Como a nossa idéia é gerar uma interrupção a cada 10 ms para gerar uma frequaªncia de PWM de 100 Hz, vamos configurar o TIMER2 de acordo com a função abaixo:
setup_timer_2(T2_DIV_BY_16,78,16);
Seguindo estas configurações (prescale de 16, PR2 de 78 e postscale de 16) e utilizando o ressonador de 8 MHz, teremos que o ciclo de máquina (fosc/4) será de 0,5 μs, o TIMER2 será atualizado (incrementado) a cada 8 μs, o overflow ocorrerá a cada 632 μs e a interrupção acontecerá a cada 10 ms (aproximadamente).
Compilando o programa
Para compilar o programa, podemos utilizar o compilador CCS diretamente através da interface IDE, ou pelo próprio MPLAB (se possuir o plug-in de conexao, disponível no site da CCS). Veja mais informações no site da própria CCS, no link: http://www.ccsinfo.com , seção de Support/Downloads.
Após a compilação, basta gravar o arquivo HEX gerado no PIC16F628A, utilizando um bom programador para este microcontrolador.
Este é um programa muito leve, que ocupa apenas 15% do microcontrolador.
Teste e uso
O teste para este circuito é muito simples. Em primeiro lugar, verifique se todos os componentes, principalmente aqueles que possuem polaridade, estao soldados corretamente.
Observe também se o microcontrolador está inserido no soquete corretamente, pois a inversao dele pode provocar a sua queima, inutilizando-o permanentemente.
Outro ponto importante é verificar se não há curto-circuito entre as soldas ou mesmo se há alguma solda “fria†que pode provocar o mau funcionamento do circuito.
Feito isso, é só plugar uma fonte de alimentação, com tensao entre 7 V e 15 V, prestando atenção que o polo positivo é o pino central, pois se o circuito for ligado a uma fonte com os terminais invertidos, o regulador de tensao irá se queimar.
Basta agora pressionar os botaµes para aumentar ou diminuir a intensidade do vermelho, verde e/ou azul do LED, verificando a cor resultante.
Conclusao
Este circuito é muito simples, mas é muito interessante, pois a partir dele o leitor poderá realizar outros testes, como as alterações na frequaªncia do PWM, no passo para o Duty Cicle, no ressonador utilizado para permitir alterações no código (lembrando que o PIC16F628A suporta osciladores de até 20 MHz), criação de uma rotina automática para alternação das cores etc.
Ele pode ser utilizado como base para iluminação indireta em ambientes, “tuning†em carros e motos, “case mod†para o seu computador, alimentação de motores DC, base de estudo para o PWM, alimentação de circuitos “Peltier†entre diversas outras. Enfim, saiba que a sua mente e criatividade sao os limites!
Boa montagem e boa diversao!

*Originalmente publicado na revista Saber Eletra´nica Nº440
Se leu e não entedeu nada, explico que o autor tentou explicar como montar o programa para que seja feito a combinação entre as cores do leds, mas se preoculpou tanto em explicar os detalhes das interrupções que ficou meio confuso.
E no fim muitos iram procurar pelo exemplo para tentar entender e se encontrar no que foi dito, mas não encontrara mastigadinho com em outros projetos, assim se seu curso de microcontrolador, foi bem palestrado, saberá como escrever as funções e insterrupções que direcionam o PWM para as I/Os comuns, senão vai ficar um pouco por fora e não vai conseguir fazer o proposto.
Abraço.