sexta-feira, 21 de março de 2014

Gerando multiplos pwm com timer0(sem utilizar o modulo CCP) - MPLAB XC8

         Há momentos em que precisamos de vários sinais de pwm mas sem precisar recorrer a microcontroladores mais complexos, uma ideia simples é usar as interrupções do timer para gerar quantos pwm forem possíveis.  
         Neste exemplo vou demostrar como criar 3 pwm que podem por exemplo acionar leds RGB,como eu não tinha nenhum led aqui RBG peguei 3 leds de alto brilho (azul,verde,vermelho) coloquei todos juntos e para dar um efeito mais homogêneo encostei eles em uma barra da cola de silicone(dessa de cola quente), o resultado fica próximo ao de um led RGB.
        Para a montagem física coloquei 3 valores diferente de resistor devido as diferença de brilho de cada led(isso depende da potencia de cada led), o circuito funciona com 5V. O microcontrolador usado é o PIC16F648 mas o código pode ser usado também no PIC16F628.
        A ideia é criar uma variável("tamanho_periodo") que irá controlar a largura do pulso em todas as três saídas ,e mais três variáveis que fará a variação da largura do pulso("larg_pwm1","larg_pwm2" e"larg_pwm2") em cada pino.Veja que neste exemplo limitei a largura máxima em 20 incrementos(mas isso pode ser alterado) .
      Veja a demontração:
      

O esquemático:




O código fonte :


/*
 *                                              Gerando pwm sem usar o modulo CCP - MPlab XC8
 *
 * Compilador : MPlabXC8
 * Microcontrolador: 16F648A
 * Autor: aguivone
 * Versão: 1
 * Data :  21 de março de 2014
 */
#include <stdio.h>
#include <string.h> 
#include <stdlib.h>

#include <xc.h>
////////////////////////defines/////////////////////////////////////////////////////////////////////////////////////////
#define PWM1                    PORTBbits.RB5
#define PWM2                    PORTBbits.RB6
#define PWM3                    PORTBbits.RB7

/////////////////////////////////////////////////////////configuraçôes//////////////////////////////////////////////////

#pragma config FOSC = INTOSCIO  // Oscillator Selection bits (INTOSC oscillator: I/O function on RA6/OSC2/CLKOUT pin, I/O function on RA7/OSC1/CLKIN)
#pragma config WDTE = OFF       // Watchdog Timer Enable bit (WDT disabled)
#pragma config PWRTE = ON       // Power-up Timer Enable bit (PWRT enabled)
#pragma config MCLRE = OFF      // RA5/MCLR/VPP Pin Function Select bit (RA5/MCLR/VPP pin function is digital input, MCLR internally tied to VDD)
#pragma config BOREN = OFF      // Brown-out Detect Enable bit (BOD disabled)
#pragma config LVP = OFF        // Low-Voltage Programming Enable bit (RB4/PGM pin has PGM function, low-voltage programming enabled)
#pragma config CPD = OFF        // Data EE Memory Code Protection bit (Data memory code protection off)
#pragma config CP = OFF         // Flash Program Memory Code Protection bit (Code protection off)


/////////////////////////////////////variaveis utilizadas///////////////////////////////////////////////////////////////////
int larg_pwm1 = 5; //a largura de pulso é limitada ao valor maximo do periodo(no caso 20)
int larg_pwm2 = 5;
int larg_pwm3 = 5;
int tamanho_periodo = 20; //incrementos máximos
int temporizador = 0;
unsigned long tempo_mudar = 0;
int cor = 0;
///////////////////////////////////////////////////interrupção//////////////////////////////////////////////////////////////

void interrupt interrupcao(void)//vetor de interrupção
{
    if (T0IF) {//interrupção do timer0 - estoura quando atinge 255(0XFF)
        temporizador++;
        if (temporizador >= larg_pwm1)
        {PWM1 = 0;}
        if (temporizador >= larg_pwm2)
        {PWM2 = 0;}
        if (temporizador >= larg_pwm3)
        {PWM3 = 0;}
        if (temporizador >= tamanho_periodo) {
            //fim de periodo todos vão para nivel alto
            // o periodo é de 2,49ms aprox. 401hz
            PWM1 = 1;
            PWM2 = 1;
            PWM3 = 1;
            temporizador = 0;
            tempo_mudar++;
            if (tempo_mudar >= 40)
            {
                //100ms = 40;
                //(tempo = valor em ms/2,49)
                tempo_mudar = 0;
                switch (cor) {
                    case 0:
                    {
                        if (larg_pwm1 >= tamanho_periodo) {
                            larg_pwm1 = 5;
                            cor++;
                        } else {
                            larg_pwm1++;
                        }
                    }
                    break;
                    case 1:
                    {
                        if (larg_pwm2 >= tamanho_periodo) {
                            larg_pwm2 = 5;
                            cor++;
                        } else {
                            larg_pwm2++;
                        }
                    }
                    break;
                    case 2:
                    {
                        if (larg_pwm3 >= tamanho_periodo) {
                            larg_pwm3 = 5;
                            cor++;
                        } else {
                            larg_pwm3++;
                        }
                    }
                    break;
                    case 3:
                    {
                        if (larg_pwm1 >= tamanho_periodo) {
                            larg_pwm1 = 5;
                            larg_pwm2 = 5;
                            cor++;
                        } else {
                            larg_pwm1++;
                            larg_pwm2++;
                        }
                    }
                    break;
                    case 4:
                    {
                        if (larg_pwm1 >= tamanho_periodo) {
                            larg_pwm1 = 5;
                            larg_pwm3 = 5;
                            cor++;
                        } else {
                            larg_pwm1++;
                            larg_pwm3++;
                        }
                    }
                    break;
                    case 5:
                    {
                        if (larg_pwm3 >= tamanho_periodo) {
                            larg_pwm3 = 5;
                            larg_pwm2 = 5;
                            cor++;
                        } else {
                            larg_pwm3++;
                            larg_pwm2++;
                        }
                    }
                    break;
                    case 6:
                    {
                        if (larg_pwm1 >= tamanho_periodo) {
                            larg_pwm1 = 5;
                            larg_pwm2 = 5;
                            larg_pwm3 = 5;
                            cor = 0;
                        } else {
                            larg_pwm1++;
                            larg_pwm2++;
                            larg_pwm3++;
                        }
                    }
                    break;
                }

            }
        }
        TMR0 = 250; //reinicia timer com o valor calculado
        T0IF = 0;
    }
}

void inicializa_timer0()
{
    OPTION_REG = 0; //timer0 com prescaler dividido por 2
    T0IE = 1; //habilita interrupção do timer0
    TMR0 = 250; //zera registrador de contagem
    PEIE = 1; //habilita interrupção de perifericos do pic
    GIE = 1; //GIE: Global Interrupt Enable bit
}
//////////////////////////////////////////////////////Rotina principal///////////////////////////////////////////////////////////////

void main(void)
{
    TRISB = 0; //configura como saida
    TRISA = 0X00; //configura portA como saida
    PORTB = 0; // limpar as portas que estão configuradas como saidas
    inicializa_timer0();
    CMCON = 7; // desliga todos os comparadores
    for (;;) {//faz nada
              }//loop infinito
}