sábado, 3 de junho de 2017

Programa Relógio com ajuste RTC

Sugestão de implementação

Tecla # Entra e sai do ajuste do relogio
Tecla 2 (^) rola o menu de opções para cima
 Tecla 8 (v) rola o menu de opções para baixo
 Tecla 4 (<) Ajusta a opção corrente do menu por decremento
 Tecla 6 (>) Ajusta a opção corrente do menu por incremento

 Opções do menu e ajustes possíveis:
 1 - Dia corrente (SUN, MON, TUE, WED, THU, FRI, SAT)
 2 - Data (1 a 31)
 3 - Mês (1 a 12)
 4 - Ano (2000 a 2099)
 5 - Hora (0 a 23)
 6 - Minutos (0 a 59)



Sugestão de variáveis a ser utilizadas

Leitura, gravação e apresentação do lcd

  • sec
  • min
  • hour
  • day
  • date
  • month
  • year

Ajuste dos parâmetros


  • min_aj
  • hour_aj
  • day_aj
  • date_aj
  • month_aj
  • year_aj

Controle e fluxo de programa

tec            // valor do código ASCII da tecla pressionada
fl_tec        // flag que indica que uma tecla foi pressionada, valores 1 (uma tecla foi pressionada) ou 0
menu        //  indica a opção corrente que será mostrada no LCD e pode ser alterada
fl_menu    //  indica que está no modo de ajuste, valores 0 ou 1, serve para manter um while () que
                     executa o ajuste do menu



Funções para modificar os dados RTC - > ajuste


// devolve a dezena em decimal do numero
unsigned char UpperCh(unsigned char ch)
{
unsigned char temp;
  temp = ch >> 4;
  return(temp);
}
// devolve a unidade em decimal do numero
unsigned char LowerCh(unsigned char ch)
{
unsigned char temp;
  temp = ch & 0x0F; //Making the Upper 4-bits
  return(temp);
}


Exemplo de uso:

unsignde char min;        // variável usada para ler os minutos do RTC
unsigned char min_aj;   // variável para fazer o ajuste dos minutos

min_aj = UpperCh(min)*10 + LowerCh(min);




Funções para modificar os dados Ajuste -> RTC


// converte para o formato RTC
unsigned char ch_to_rtc (unsigned char ch){
    unsigned char dezena,unidade,saida;
    dezena = ch/10; // dezena
    unidade= ch - dezena*10; // unidade
    saida = (dezena<<4)|(unidade);
    // temp = ((ch/10)<<4) && (ch - (ch/10)); // não sei se funciona de uma vez só???
    return saida;
}

Exemplo de uso:

unsignde char min;        // variável usada para ler os minutos do RTC
unsigned char min_aj;   // variável para fazer o ajuste dos minutos

min = ch_to_rtc(min_aj);



Programa com funções a completar

/*
 *
 * Programa que mostra caledário e relógio no LCD
 * Teclado matricila por conversor AD com Interrupção
 * Programa de ajuste do relógio
 *
 * Tecla # Entra e sai do ajuste do relogio
 * Tecla 8 (^) rola o menu de opções para cima
 * Tecla 2 (v) rola o menu de opções para baixo
 * Tecla 4 (<) Ajusta a opção corrente do menu por decremento
 * Tecla 6 (>) Ajusta a opção corrente do menu por incremento
 *
 * Opções do menu e ajustes possíveis:
 * 1 - Dia corrente (SUN, MON, TUE, WED, THU, FRI, SAT)
 * 2 - Data (1 a 31)
 * 3 - Mes (1 a 12)
 * 4 - Ano (2000 a 2099)
 * 5 - Hora (0 a 23)
 * 6 - Minutos (0 a 59)
 *
 */


#define _XTAL_FREQ 48000000

#include <xc.h>
#include <stdio.h>
#include "C:\h\config_PIC18F4550.h"
#include "c:\h\biblioteca_lcd_2x162_48M_XC.h"

// prototipos de funções para leitura e escrita do rtc i2c
void i2c_init();
void i2c_start(void);
void i2c_restart(void);
void i2c_stop(void);
void i2c_wait(void);
void i2c_send(unsigned char dat);
unsigned char i2c_read(void);
unsigned char rtc1307_read(unsigned char address); //RTC DS1307 Read Function

// protipos de funções para o main e funcionamento do teclado matriacial
void inicia_regs(void);
void interrupt ISR_alta_prioridade(void);
void config_int(void);
void config_int2 (void);
void config_AD(void);
int conv_AD(void);
void delay_ms(int i);
void atraso_meios(unsigned char meio_segundos);
unsigned char UpperCh(unsigned char ch);
unsigned char LowerCh(unsigned char ch);
unsigned char ch_to_rtc (unsigned char ch);
void grava_rtc (void);
void mostra_rtc_lcd(void);
void mostra_menu(void);

void trata_tecla_4(void);
void trata_tecla_6(void);
void trata_tecla_8(void);
void trata_tecla_2(void);

unsigned char fl_tec = 0, tec = 0;
/* fl_tec: flag que indica que chegou uma tecla
 * tec: valor asc da tecla recebida
 */
unsigned char sec,min,hour,day,date,month,year, menu=1;
unsigned char min_aj,hour_aj,day_aj,date_aj,month_aj,year_aj;
unsigned char buffer[17];

void main(void) {
    unsigned char fl_menu = 0;
    inicia_regs();
    config_int();
    config_int2(); // configura as interrupções
    config_AD(); // configura e inicializa o conversor AD
    i2c_init(); //To Generate the Clock of 100Khz
    // trata o LCD
    lcd_inicia(0x28, 0x0f, 0x06); // incializa o LCD com 4 linhas
    lcd_LD_cursor(0); // Desliga o cursor
    lcd_posicao(1, 1);
    imprime_string_lcd("   Calendario   ");
    lcd_posicao(2, 1);
    imprime_string_lcd("  Relogio - RTC ");
    atraso_meios(2);
    while (1) {
        lcd_posicao(2, 1);
        imprime_string_lcd("Set-RTC press #");
        mostra_rtc_lcd();
        if (fl_tec) {
            fl_tec = 0;
            if (tec == 35) {// tecla # entra no mneu
                fl_menu = 1;
             
                // converte os dados para numero para ajuste
                //                sec_aj = UpperCh(sec)*10 + LowerCh(sec);
                min_aj = UpperCh(min)*10 + LowerCh(min);
                hour_aj = UpperCh(hour)*10 + LowerCh(hour);
                day_aj = day;
                date_aj = UpperCh(date)*10 + LowerCh(date);
                month_aj = UpperCh(month)*10 + LowerCh(month);
                year_aj = UpperCh(year)*10 + LowerCh(year);
                mostra_menu();
                // fim da conversão
            }
        }
        while (fl_menu) {
            if (fl_tec) {
                fl_tec = 0;
                if (tec == 35) { // tecla # sai do menu
                    fl_menu = 0;
                    tec = 0; // destrava o while do menu
                    grava_rtc(); // grava os dados no rtc
                }
                trata_tecla_8();
                trata_tecla_2();
                trata_tecla_4();
                trata_tecla_6();
                mostra_menu();
            }
        }
    }
}


// funções para leitura e escrita do rtc i2c
// copiar as funções do programa de exemplo
// void i2c_init(){}
// void i2c_start(void){}
// void i2c_restart(void){}
// void i2c_stop(void){}
// void i2c_wait(void){}
// void i2c_send(unsigned char dat){}
//unsigned char i2c_read(void){}

unsigned char rtc1307_read(unsigned char address)
{
unsigned char temp;
i2c_start();
i2c_send(0xD0);
i2c_send(address);
i2c_restart();
i2c_send(0xD1);
temp = i2c_read();
//i2c_stop(); this line is Removed Because it is already included in i2c_read function
return temp;
}
// fim das funções para leitura e escrita do rtc i2c


// funções para o main e funcionamento do teclado materiacial
// função de configuração do conversor A/D
// void config_AD(void) {}
// função que efeuta uma conversão A/D e retorna um inteiro com o valor convertido
// int conv_AD(void) {}
// função que inicia os registradores I/O
// void inicia_regs(void) {} 
// função de interrupção de alta prioridade
// função que lê o teclado na INT2 - Ver prog cofre
// void interrupt ISR_alta_prioridade(void) {}
// função de configuração geral de interrupções
// void config_int(void) {}
// configura a interrupção exarna INT2
// void config_int2(void) {}
// função que gera atraso em mlisegundos
// void delay_ms(int i){}
//função de atraso de multiplos de 0,5s
// void atraso_meios(unsigned char meio_segundos)
// devolve a dezena em decimal do numero
unsigned char UpperCh(unsigned char ch)
{
unsigned char temp;
  temp = ch >> 4;
  return(temp);
}
// devolve a unidade em decimal do numero
unsigned char LowerCh(unsigned char ch)
{
unsigned char temp;
  temp = ch & 0x0F; //Making the Upper 4-bits
  return(temp);
}
// converte para o formato RTC
unsigned char ch_to_rtc (unsigned char ch){
    unsigned char dezena,unidade,saida;
    dezena = ch/10; // dezena
    unidade= ch - dezena*10; // unidade
    saida = (dezena<<4)|(unidade);
    // temp = ((ch/10)<<4) && (ch - (ch/10)); // não sei se funciona de uma vez só???
    return saida;
}
// grava os dados no RTC

/* void grava_rtc(void) {
    // retorna os alores para gravação
    min = ch_to_rtc(min_aj);
    // fazer para hour, day, date, month, year
    // rotina de gravação

    // exemplo para gravação de um valor fixo
    // data quarta 31/dez/2014 23h 59min e 45 seg
 
//    i2c_start();
//    i2c_send(0xD0);
//    i2c_send(0x00);
//    i2c_send(0x45 | 0x80); //CH = 1 Stop oscillator
//    i2c_send(0x59); //Minute
//    i2c_send(0x23); //Hour
//    i2c_send(0x04); //4 - quarta
//    i2c_send(0x31); //31 data
//    i2c_send(0x12); //12 Dez
//    i2c_send(0x14); //2014
//    i2c_stop(); //Stop the I2C Protocol

    //Have to start the Clock again
//    i2c_start();
//    i2c_send(0xD0);
//    i2c_send(0x00);
//    i2c_send(0x00); //start Clock and set the second hand to Zero
//    i2c_stop();
    // fim do start
}

// mostra caledario - hora alternados na linha 1
void mostra_rtc_lcd(void){
    sec = rtc1307_read(0x00);
// ler min, hour, day, date, month, year
    lcd_posicao(1, 1);
    switch (day) {
        case 1: sprintf(buffer, "SUN %02x/%02x/20%02x", date, month, year);
            break;
        // fazer para os outros 6 dias da semana
    }
    imprime_buffer_lcd(buffer, 15);
    atraso_meios(1);
    // mostra a hora na na linha 1 e espera 1/2 segundo
}

void mostra_menu(void) {
    /*1 - Dia corrente (SUN, MON, TUE, WED, THU, FRI, SAT)
     * 2 - Data (1 a 31)
     * 3 - Mes (1 a 12)
     * 4 - Ano (2000 a 2099)
     * 5 - Hora (0 a 23)
     * 6 - Minutos (0 a 59) */
    //    lcd_limpa_tela();
 
    switch (menu) {
        case 1:
            switch (day_aj) {
                case 1: sprintf(buffer, "dia = SUNDAY   ");
                    break;
                // fazer os outros dias
            }
            break;
        case 2:
            sprintf(buffer, " Data = %2d    ", date_aj);
            break;
        // fazer para Mes, Ano, Hora, Minutos
    }
    lcd_posicao(1, 1);
    imprime_buffer_lcd(buffer, 15);
    lcd_posicao(2, 1);
    imprime_string_lcd("set < >  ch ^ v ");
}

void trata_tecla_4(void) {
    if (tec == 52) {// tecla 4 < decrementa a opção corrente
        switch (menu) {
            case 1: // decrementa dia
                day_aj--;
                if (day_aj == 0) {
                    day_aj = 7;
                }
                break;
            case 2: // decrementa data
                if (date_aj == 1) {
                    date_aj = 31;
                } else date_aj--;
                break;
            case 3: // decrementa  mês
                if (month_aj == 1) {
                    month_aj = 12;
                }
                month_aj--;
                break;
            case 4: // decrementa ano
                if (year_aj == 0) {
                    year_aj = 99;
                } else year_aj--;
                break;
            case 5: // decrementa hora
                if (hour_aj == 0) {
                    hour_aj = 23;
                } else hour_aj--;
                break;
            case 6: // decrementa minutos
                if (min_aj == 0) {
                    min_aj = 59;
                } else min_aj--;
                break;
        }
    }
}

void trata_tecla_6(void) {
// ver exemplo função trata_tecla_4
}

void trata_tecla_8(void) {
    if (tec == 56) {// tecla 8 ^ rola menu p/ cima
        if (menu < 6) {
            menu++;
        } else {
            menu = 1;
        }
    }
}

void trata_tecla_2(void) {
// ver exemplo função trata_tecla_8
}





sexta-feira, 26 de maio de 2017

quarta-feira, 8 de fevereiro de 2017

Entendendo I2C



Fontes de consulta:







   

RTC - Real Time Clock


Exemplo: DS1307








Código de exemplo em linguagem C para uso do RCT DS1307 com PIC18F4550

/*
 * File:   I2C - Atv01 - Exemplo.c
 * Author: Pilger
 *
 * Created on 25 de Novembro de 2017, 13:58
 * 
 * Exemplo de ligação I2C com RTC DS1307
 * Caledário e horário no LCD
 * Start em 23/12/2014 as 23h 59min 45s 
 * Ver mudança em caledário e tempo
 */

#define _XTAL_FREQ 48000000

#include <xc.h>
#include <stdio.h>
#include "C:\h\config_PIC18F4550.h"
#include "c:\h\biblioteca_lcd_2x162_48M_XC.h"

//protóptipo de funções
// I2C
void i2c_init();
void i2c_start(void);
void i2c_restart(void);
void i2c_stop(void);
void i2c_wait(void);
void i2c_send(unsigned char dat);
unsigned char i2c_read(void);
// funções criadas

unsigned char rtc1307_read(unsigned char address); //RTC DS1307 Read Function
void delay_ms(int i);
void atrasos(unsigned char segundos);

// variáveis globais
unsigned char sec,min,hour,day,date,month,year;

void main()
{
    unsigned char buffer[16];
    // defionição direção pinos
TRISB = 0x0F;
TRISC = 0xFF;
TRISD = 0x00;
    // inicia LCD
    lcd_inicia(0x28, 0x0f, 0x06); // incializa o LCD com 4 linhas
    lcd_LD_cursor(0); // Desliga o cursortar instrução
    lcd_limpa_tela();
    lcd_posicao(1, 1);
    imprime_string_lcd("RTC DS1307 ");
    atrasos(2); // atraso de 2s
    lcd_limpa_tela();
i2c_init(); //To Generate the Clock of 100Khz
    // escreve data e hora inicial no DS1307
    // exemplo usado data 31/dez/2014 numero gravado: dia 4 (quarta) 31/12/14
    // exemplo usado tempo: 23h 59min e 45 seg
    // exemplo p/ mostrar a virada de hora, dia e mês e ano
    i2c_start();
i2c_send(0xD0);
i2c_send(0x00);
    i2c_send(0x45|0x80); //CH = 1 Stop oscillator
i2c_send(0x59); //Minute 
i2c_send(0x23); //Hour
i2c_send(0x04); //4 - quarta
i2c_send(0x31); //31 data
i2c_send(0x12); //12 Dez
i2c_send(0x14); //2014
i2c_stop(); //Stop the I2C Protocol
//Have to start the Clock again
i2c_start();
i2c_send(0xD0);
i2c_send(0x00);
i2c_send(0x45); //start Clock and set the second hand to Zero
i2c_stop();
while(1)
{
sec = rtc1307_read(0x00);
min = rtc1307_read(0x01);
hour = rtc1307_read(0x02);
        day = rtc1307_read (0x03);
date = rtc1307_read(0x04);
month = rtc1307_read(0x05);
year = rtc1307_read(0x06);
        // imprime dia, data, mês e ano
        lcd_posicao(1, 1);
        switch (day){
            case 1: sprintf(buffer, " SUN %02x/%02x/20%02x ", date,month,year);
            break;
            case 2: sprintf(buffer, " MON %02x/%02x/20%02x ", date,month,year);
            break;
            case 3: sprintf(buffer, " TUE %02x/%02x/20%02x ", date,month,year);
            break;
            case 4: sprintf(buffer, " WED %02x/%02x/20%02x ", date,month,year);
            break;
            case 5: sprintf(buffer, " THU %02x/%02x/20%02x ", date,month,year);
            break;
            case 6: sprintf(buffer, " FRI %02x/%02x/20%02x ", date,month,year);
            break;
            case 7: sprintf(buffer, " SAT %02x/%02x/20%02x ", date,month,year);
            break;
        }
        imprime_buffer_lcd(buffer, 16);
        // imprime hora
        lcd_posicao(2, 1);
        sprintf(buffer, " Hora: %02x:%02x.%02x ", hour,min,sec);
        imprime_buffer_lcd(buffer, 16);
       atrasos(1); // atraso de 1s
}
}


// função que gera atraso em mlisegundos
void delay_ms(int i){
    for ( int x = 0; x < i; x++ )     { 
    __delay_ms(1); 
    }
}

void atrasos(unsigned char segundos) { // função de atraso em segundo
    delay_ms (1000*segundos);
}

void i2c_init()
{
TRISBbits.TRISB0 = 1;   // SDA IN
TRISBbits.TRISB1 = 1;   // SCL IN 
SSPCON1=0b00101000; //Master mode
    /* <7> Sem colisão - WCOL=0
     * <6> sem Overflow na recepção SSPOV=0 
     * <5> Habilita porta serial e ativa pinos SDA E SCL - SSPEN=1
     * <4> não usado em modo mestre =0 
     * <3:0> ativa modo mestre - SSPM3:SSPM0 --> 1000 - I2C Master Mode */
SSPADD = 119;
    /* Clock = Fosc/4*(SSPADD+1)
     * para 100KHz:
     * SSPADD = [48M / 100K)/4]-1 = 119 */
    SSPSTAT = 0b10000000;
    /* <7> SMP=1 Slew rate control disabled for Standard Speed mode (100 kHz and 1 MHz) - controle de inclinação desativado = 1
     * <6> CKE=0 -Disable SMBus specific inputs - níveis de entrada conforme especificação i2c = 0
     * <5> D//A= 0 - Master Reservado
     * <4> P=0 Stop bit was not detected last
     * <3> S=0 Start bit was not detected last
     * <2> R//W= 0 Master: Transmit is not in progress
     * <1> UA=0 Address does not need to be updated
     * <0> BF=0 SSPBUF is empty */ 
}

void i2c_start(void)
{
SSPCON2bits.SEN = 1;
/* SSPCON2 <0> SEN: Start Condition Enable/Stretch Enable bit(2)
     * 1 = Initiate Start condition on SDA and SCL pins. Automatically cleared by hardware.
     * 0 = Start condition Idle */
while (SSPCON2bits.SEN == 1)
        continue; // Aguarda o bit voltar a 0 automaticamente por hardware
}

void i2c_restart(void)
{
SSPCON2bits.RSEN = 1;
/* SSPCON2 <1> RSEN: Repeated Start Condition Enable bit(2)
     * 1 = Initiate Repeated Start condition on SDA and SCL pins. Automatically cleared by hardware.
     * 0 = Repeated Start condition Idle */
while (SSPCON2bits.RSEN == 1) 
        continue; // Aguarda o bit voltar a 0 automaticamente  por hardware
}

void i2c_stop(void)
{
SSPCON2bits.PEN=1;
    /* SSPCON2 <2> PEN: Stop Condition Enable bit(2)
     * 1 = Initiate Stop condition on SDA and SCL pins. Automatically cleared by hardware.
     * 0 = Stop condition Idle */
while(SSPCON2bits.PEN==1)
        continue;  // Aguarda o bit voltar a 0 automaticamente  por hardware
}

void i2c_wait(void)
{
while( SSPSTATbits.R_W == 1)
continue;
if(SSPCON2bits.ACKSTAT == 1)
{
i2c_stop();
}
//If ACKSTAT bit is 0 Acknowledgment Received Successfully
//Otherwise Not
}

void i2c_send(unsigned char dat)
{
SSPBUF = dat;    /* Move data to SSPBUF */
    while(SSPSTATbits.BF);       /* wait till complete data is sent from buffer */
    i2c_wait();       /* wait for any pending transfer */
}

unsigned char i2c_read(void)
{
unsigned char temp;
    SSPCON2bits.RCEN = 1;        /* Enable data reception */
    while(SSPSTATbits.BF == 0)      /* wait for buffer full */
    continue;
    temp = SSPBUF;   /* Read serial buffer and store in temp register */
    i2c_wait();       /* wait to check any pending transfer */
    SSPCON2bits.ACKDT=1; //send not acknowledge
SSPCON2bits.ACKEN=1;
while(SSPCON2bits.ACKEN == 1) 
continue;
i2c_stop();
    return temp;     /* Return the read data from bus */
}

unsigned char rtc1307_read(unsigned char address)
{
unsigned char temp;
i2c_start();
i2c_send(0xD0);
i2c_send(address);
i2c_restart();
i2c_send(0xD1);
temp = i2c_read();
//i2c_stop(); this line is Removed Because it is already included in i2c_read function
return temp;
}

   

Controlando PWM


Objetivo: 

Controlar  a velocidade de um motor DC a partir de um potenciômetro




Atividade 2


2.1 Tensão mínima de trabalho

  • Identificar a tensão mínima para dar partida ao motor utilizado
    • Ligar o motor escolhido ao programa trabalhado na atividade 1 e identificar qual o % de duty cycle necessário para vencer a inércia do motor
    • Baixar o % de duty cycle até o ponto de parada do motor



2.2 Lendo um potenciômetro

  • Ler um potenciômetro me uma entrada analógica do microcontrolador

2.3 Controlando a carga a partir do potenciômetro


  • Interligar a leitura do potenciômetro com o acionamento da saída PWM de forma que a escala do potenciômetro seja:
    • Mínimo: Motor desligado
    • Máximo: Velocidade máxima do motor






sexta-feira, 11 de novembro de 2016

Funções de tempo


 A medição de tempo é feita por contagem de ciclos de instrução (TCI), cujo valor, em segundos depende da frequência do oscilador de clock. O tempo correspondente ao ciclo de instrução (TCI), é dado pela equação:





Para uma frequência de 48MHz temos




xc.h

A bliblioteca xc.h disponibiliza alguma funções que permitem gerar atrasos.

É necessário "chamar" a biblioteca xc.h
#include <xc.h>

Para o correto funcionamento, uma vez que as funções são baseadas em ciclos de instrução do microcontrolador é necessário indicar a frequência em Hz de trabalho do microcontrolador
#define _XTAL_FREQ 48000000

Obs.: Nas funções e macros descritas a seguir o argumento a ser passado ("cycles" ou "x") não pode ser um valor elevado, pois o compilador "entende" que desta forma o programa poderia estar "travado" ou em loop infinito, então para obter tempos maiores, é necessário chamar várias vezes as funções ou realizar inteirações (laços de repetição como "for", "while").

 Fonte: Guia do Usuário do compilador XC8 - Microchip

_delay

Gera um atraso de um número de ciclos que é especificado como argumento "cycles"

Sintaxe:  void _delay(unsigned long cycles);

Uso: _delay(10);   // gera um atraso de 10 ciclos de instrução aproximadamente 833ns (10 x 83,3ns)


   

_delay3


Gera um atraso de 3 vezes o número de ciclos que é especificado como argumento "cycles"

Sintaxe:  void _delay3(unsigned char cycles);

Uso: _delay3(10); // atraso de 30 ciclos de instrução



__delayus


É uma macro baseada na função _delay e gera um atraso em us que é especificado no argumento "x"

Sintase: void __delay_us(x);

Uso: __delay_us(1);  // gera uma atraso de 1us



   __delayms


É uma macro baseada na função _delay e gera um atraso em ms que é especificado no argumento "x"

Sintase: void __delay_ms(x);

Uso: __delay_ms(1);  // gera uma atraso de 1ms   


Entendendo PWM



Datasheet capítulo 15 (PWM)

O que é PWM (MEC071)

Modulação por Largura de Pulso - UDESC

PULSE WIDTH MODULATION CONCEITOS E CIRCUITO-EXEMPLO

EletrônicaDigital PWM - Modulação Por Largura de Pulso - Mecaweb





Exemplo de funcionamento




Código de exemplo para acionamento das saídas 1 e 2



/*
 * File:   PWM_1_exemplo.c
 * Author: Pilger
 *
 * Created on 16 de Novembro de 2017, 08:35
 */

#define _XTAL_FREQ 48000000
#define TMR2PRESCALE 16

// relação de frequencia x prescaler para xtal de 48M
// para reslução de 1000 -> 2^10 = 1023
// ps   F pwm
// 1    48KHz
// 4    12KHz
// 16    3 KHz

#include <xc.h>
#include "C:\h\config_PIC18F4550.h"

//variáveis globais
long freq;

// protótipos de funções
void delay_ms(int i);
int PWM_Max_Duty(void);
void PWM1_Init(long fre);
void PWM2_Init(long fre);
void PWM1_Duty(unsigned int duty);
void PWM2_Duty(unsigned int duty);
void PWM1_Start(void);
void PWM1_Stop(void);
void PWM2_Start(void);
void PWM2_Stop(void);


void main(){
  unsigned int i=0,j=0;
  PWM1_Init(3000);
  PWM2_Init(3000);
  TRISD = 0xFF;
  TRISC = 0;
  PWM1_Duty(0);
  PWM2_Duty(0);
  PWM1_Start();
  PWM2_Start();
  while (1)  {
    if(PORTDbits.RD0 == 0 && i<1000){
        while(PORTDbits.RD0==0);  
      i=i+100;
    }
    if(PORTDbits.RD1 == 0 && i>0){
        while(PORTDbits.RD1==0);
      i=i-100;
    }
    if(PORTDbits.RD2 == 0 && j<1000){
        while(PORTDbits.RD2==0);
      j=j+100;
    }
    if(PORTDbits.RD3 == 0 && j>0){
      while(PORTDbits.RD3==0);
        j=j-100;
    }
    PWM1_Duty(i);
    PWM2_Duty(j);
    delay_ms(10); // 10ms  
  }
}

// função que gera atraso em mlisegundos
void delay_ms(int i){
    for ( int x = 0; x < i; x++ )     { 
    __delay_ms(1); 
    }
}

int PWM_Max_Duty(void){
  return(_XTAL_FREQ/(freq*TMR2PRESCALE);
}

void PWM1_Init(long fre){
  PR2 = (_XTAL_FREQ/(fre*4*TMR2PRESCALE)) - 1;
  freq = fre;
}

void PWM2_Init(long fre){
  PR2 = (_XTAL_FREQ/(fre*4*TMR2PRESCALE)) - 1;
  freq = fre;
}

void PWM1_Duty(unsigned int duty){
  if(duty<1024) {
    duty = ((float)duty/1023)*PWM_Max_Duty();
    CCP1CONbits.DC1B1 = duty & 2;
    CCP1CONbits.DC1B0 = duty & 1;
    CCPR1L = duty>>2;
  }
}

void PWM2_Duty(unsigned int duty){
  if(duty<1024) {
    duty = ((float)duty/1023)*PWM_Max_Duty();
    CCP2CONbits.DC2B1 = duty & 2;
    CCP2CONbits.DC2B0 = duty & 1;
    CCPR2L = duty>>2;
  }
}

void PWM1_Start(void) {
    CCP1CONbits.CCP1M3 = 1;
    CCP1CONbits.CCP1M2 = 1;
  #if TMR2PRESCALE == 1
      T2CONbits.T2OUTPS0 = 0;
      T2CONbits.T2OUTPS1 = 0 ;
  #elif TMR2PRESCALE == 4
      T2CONbits.T2OUTPS0 = 1;
      T2CONbits.T2OUTPS1 = 0 ;
  #elif TMR2PRESCALE == 16
      T2CONbits.T2OUTPS0 = 1;
      T2CONbits.T2OUTPS1 = 1 ;
  #endif
  T2CONbits.TMR2ON = 1;
  TRISCbits.TRISC2 = 0;
}

void PWM1_Stop(void) {
    CCP1CONbits.CCP1M3 = 0;
    CCP1CONbits.CCP1M2 = 0;
}

void PWM2_Start(void){
    CCP2CONbits.CCP2M3 = 1;
    CCP2CONbits.CCP2M2 = 1;
  #if TMR2PRESCALE == 1
      T2CONbits.T2OUTPS0 = 0;
      T2CONbits.T2OUTPS1 = 0;
  #elif TMR2PRESCALE == 4
      T2CONbits.T2OUTPS0 = 1;
      T2CONbits.T2OUTPS1 = 0;    
  #elif TMR2PRESCALE == 16
      T2CONbits.T2OUTPS0 = 1;
      T2CONbits.T2OUTPS1 = 1;
  #endif
  T2CONbits.TMR2ON = 1;
  TRISCbits.TRISC1 = 0;
}

void PWM2_Stop(void){
    CCP2CONbits.CCP2M3 = 0;
    CCP2CONbits.CCP2M2 = 0;
}




Atividade 1


1.1 Entendendo o PWM 

  • Criar um projeto e compilar o exemplo
  • Observar no simulador
  • Colocar no hardware
  • Ligar um led na saída e observar
  • Ligar um osciloscópio e analisar a saída

1.2 Adicionando recursos de informação 

  • Modificar o programa para
  • Adicionar o módulo LCD e indicar o percentual de PWM em cada sinal
  • Modificar o incremento e decremento para saltos de 1%

1.3 Ligando uma carga 



  • Ligar uma carga em uma das saídas, um motor DC de 12V (pode ser uma ventoinha de fonte de computador)