Autor Tema: Proyecto de encendido de varios canales LEDs con su dimmeador por canal  (Leído 3244 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Arkaedus

  • PIC10
  • *
  • Mensajes: 25
Hola a todos.

Me gustaría intercambiair un proyecto que ando haciendo y de paso a ver si me peuden echar una manita con el.

Puesto que tengo un problema.

El PIC que uso es el 16F876 pero no se si habría alguno mejor pues me gustaría hacer PWM se que hay modulos externos que pueden hacer PWM pero nunca los usé. Tambien querría preguntar si hay algun PIC que peuda tener mas de 0-255 en PWM pues me gustaria tener mas posiciones de PWM para que la iluminacion suba de manera mas suave y no se note.

Yo simulo en Proteus 8 y cuando lleva un poco de tiempo en marcha en la LCD me salen signos de interrogación por muy poco de tiempo. He buscado el error pero no lo veo. Estoy empezando en este mundo.

El programa que uso para hacer el codigo en C es el PCWHD, ya que intenté el XC8 pero no me aclaro con el. Si alguien me peude echar una amno sobre comos eria el codigo en XC8 le estaría agradecido. pero lo que más em interesa es eliminar ese error de lectura o escritura en la pantalla LCD donde salen interrogaciones.

Paso el codigo y diseño en Proteus.

Muchas gracias de antemano
« Última modificación: 08 de Mayo de 2015, 23:09:20 por Arkaedus »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #1 en: 08 de Mayo de 2015, 10:29:29 »
El PWM de este micro soporta hasta 10bits de resolucion, 255 pasos aun asi me parecen BASTANTES como para que demasiado notable. Lo que tenes que tener en cuenta es que depende de la seleccion de frecuencia del PWM puede o no llegar a cumplir con esa "resolucion" de 8 bits/10 bits. Incluso el datasheet trae la formula para calcularlo.

Tu programa parece que no utiliza el PWM por HW. Lo estas haciendo por soft?.

Tambien me parece que deberias separar en archivos las cosas, por ejemplo hacer un archivo para todas las funciones del LCD, entonces adjuntas la cabecera en tu main.c y ya tenes todas las funciones disponibles.
Se hace un poco mas ordenado trabajar y leer el codigo, esto es un consejo si lo queres lo tomas , sino seguis con tu forma de trabajo.

Por ejemplo, todas las definiciones de linea del LCD + prototipos de funciones lo pones en un archivo que se llame lcd.h y y las funciones en un archivo lcd.c
luego en tu archivo c principal pones un include lcd.h; y listo ya tenes todo funcionando igual.

Por el tema del error del LCD, no se, es DEMASIADO codigo, pero podrias probar quitando algunas funciones y solo dejando algunas y ver si ocurre lo mismo,

Desconectado Joseph90

  • PIC12
  • **
  • Mensajes: 89
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #2 en: 08 de Mayo de 2015, 13:52:27 »
Coincido con KILLERJC 255 es una resolución más que suficiente para variar la intensidad de un led, con una resolución mayor  no lograrías ver ningún cambio.
Con respecto al LCD si no encuentras el error te recomiendo que  pruebes en otra versión del Proteus anterior (alguna variante del Proteus 7), pues al menos yo no me fio de ninguna versión en concreto y siempre si tengo algún error y ya he hecho y revisado todo lo posible pruebo con otra versión el mismo esquema.....
Saludos.......   
El problema del hombre no está en la boma atómica, sino en su corazón. Albert Einstein.

Desconectado Arkaedus

  • PIC10
  • *
  • Mensajes: 25
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #3 en: 01 de Julio de 2015, 10:53:09 »
Al final quiero intentar hacer el dimeado mediante PWM por software.

Este es el proyecto tal cual lo tengo:



Los drivers vienen con una entrada PWM que en estado alto (5V) enciende el LED y en estado bajo (0V) lo apaga, vamos como veiene siendo la salida alta y baja del PWM por eso les he metido 5V directos para que se peudan encender de momento lso LEDs y ver el funcionamiento del proyecto.

Este es el codigo que empleo:

DS1302
Código: [Seleccionar]
//////////////////////////////////////////////////////////////////////////
////                               DS1302.C                           ////
////                     Driver for Real Time Clock                   ////
////                                                                  ////
////  rtc_init()                                   Call after power up////
////                                                                  ////
////  rtc_set_datetime(day,mth,year,dow,hour,min)  Set the date/time  ////
////                                                                  ////
////  rtc_get_date(day,mth,year,dow)               Get the date       ////
////                                                                  ////
////  rtc_get_time(hr,min,sec)                     Get the time       ////
////                                                                  ////
////  rtc_write_nvr(address,data)                  Write to NVR       ////
////                                                                  ////
////  data = rtc_read_nvr(address)                 Read from NVR      ////
////                                                                  ////
////  get_bcd(data)                              Convert data to BCD  ////
////                                                                  ////
////  rm_bcd(data)                               Convert data to int  ////
////                                                                  ////
//////////////////////////////////////////////////////////////////////////
////        (C) Copyright 1996,2003 Custom Computer Services          ////
//// This source code may only be used by licensed users of the CCS C ////
//// compiler.  This source code may only be distributed to other     ////
//// licensed users of the CCS C compiler.  No other use, reproduction////
//// or distribution is permitted without written permission.         ////
//// Derivative programs created using this software in object code   ////
//// form are not restricted in any way.                              ////
//////////////////////////////////////////////////////////////////////////

#ifndef RTC_SCLK

#define RTC_SCLK PIN_E1
#define RTC_IO   PIN_E0
#define RTC_RST  PIN_E2

#endif

void write_ds1302_byte(BYTE cmd) {
   BYTE i;

   for(i=0;i<=7;++i) {
      output_bit(RTC_IO, shift_right(&cmd,1,0) );
      output_high(RTC_SCLK);
      output_low(RTC_SCLK);
   }
}

void write_ds1302(BYTE cmd, BYTE data) {

   output_high(RTC_RST);
   write_ds1302_byte(cmd);
   write_ds1302_byte(data);
   output_low(RTC_RST);
}

BYTE read_ds1302(BYTE cmd) {
   BYTE i,data;

   output_high(RTC_RST);
   write_ds1302_byte(cmd);
  
   input(RTC_IO);
   delay_us(1);
        
   for(i=0;i<=7;++i) {
      shift_right(&data,1,input(RTC_IO));
      output_high(RTC_SCLK);
      delay_us(2);
      output_low(RTC_SCLK);
      delay_us(2);
   }
   output_low(RTC_RST);

   return(data);
}

void rtc_init() {
   BYTE x;
   output_low(RTC_RST);
   delay_us(2);
   output_low(RTC_SCLK);
   write_ds1302(0x8e,0);
   write_ds1302(0x90,0xa4);
   x=read_ds1302(0x81);
   if((x & 0x80)!=0)
     write_ds1302(0x80,0);
}



void rtc_set_datetime(BYTE day, BYTE mth, BYTE year, BYTE dow, BYTE hr, BYTE min) {

   write_ds1302(0x86,day);
   write_ds1302(0x88,mth);
   write_ds1302(0x8c,year);
   write_ds1302(0x8a,dow);
   write_ds1302(0x84,hr);
   write_ds1302(0x82,min);
   write_ds1302(0x80,(0));
}

void rtc_get_date(BYTE& day, BYTE& mth, BYTE& year, BYTE& dow) {
   day = read_ds1302(0x87);
   mth = read_ds1302(0x89);
   year = read_ds1302(0x8d);
   dow = read_ds1302(0x8b);
}

void rtc_get_time(BYTE& hr, BYTE& min, BYTE& sec) {
   hr = read_ds1302(0x85);
   min = read_ds1302(0x83);
   sec = read_ds1302(0x81);
}

void rtc_write_nvr(BYTE address, BYTE data) {
   write_ds1302(address|0xc0,data);
}

BYTE rtc_read_nvr(BYTE address) {
    return(read_ds1302(address|0xc1));
}


Con esta funcion imprimo los valores en pantalla que nos ofrece el DS1302:
Código: [Seleccionar]
//-----------------------------------------------------------------------------
void lcd_print_2num_bcd_lcd1(int num_bcd)
{
   lcd_putc1((num_bcd >> 4)    + 0x30);      //DECENAS
   lcd_putc1((num_bcd &  0x0F) + 0x30);      //UNIDADES
}
//-----------------------------------------------------------------------------

PANTALLA DE CONFIGURACION DE ENCENDIDO DE LOS LEDS
Código: [Seleccionar]
//PANTALLA DE CONFIGURACION
         case 1:    
        
    
            switch (config_cursor_actual)
            {
               //CURSOR EN DIA DE LA SEMANA            
               case 0:
                  if (puls_up_fs && comprobar_datos_config())
                  {
                     if (++config_dia_actual == 8) config_dia_actual = 1;
                  }
                  if (puls_down_fs && comprobar_datos_config())
                  {
                     if (--config_dia_actual == 0) config_dia_actual = 7;                    
                  }
               //-------------------------                  
                  break;                  
                
               //CURSOR EN DECENAS HORA INICIO                  
               case 1:
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_INC, 1);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_DEC, 1);
                  }
               //-------------------------
                  break;
                  
               //CURSOR EN UNIDADES HORA INICIO              
               case 2:    
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_INC, 0);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_inicio[config_dia_actual],
                              LIMIT_HORAS_DEC, 0);
                  }              
               //-------------------------
                  break;
                  
               //CURSOR EN DECENAS MINUTOS INICIO                  
               case 3:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_INC, 1))
                     {
                        inc_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_DEC, 1))
                     {
                        dec_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }
               //-------------------------
                  break;
                  
               //CURSOR EN UNIDADES MINUTOS INICIO                  
               case 4:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_INC, 0))
                     {
                        inc_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_inicio[config_dia_actual],
                                  LIMIT_MINS_DEC, 0))
                     {
                        dec_2bcd(&config_hora_inicio[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }        
               //-------------------------
                  break;
              
            
            
             //CURSOR EN DECENAS HORA FIN                
               case 5:
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_INC, 1);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_DEC, 1);
                  }
               //-------------------------
                  break;
                  
               //CURSOR EN UNIDADES HORA FIN              
               case 6:    
                  if (puls_up_fs)
                  {
                     inc_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_INC, 0);
                  }
                  if (puls_down_fs)
                  {
                     dec_2bcd(&config_hora_fin[config_dia_actual],
                              LIMIT_HORAS_DEC, 0);
                  }              
               //-------------------------
                  break;
                  
               //CURSOR EN DECENAS MINUTOS FIN                  
               case 7:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_INC, 1))
                     {
                        inc_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_DEC, 1))
                     {
                        dec_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }
               //-------------------------
                  break;
                  
               //CURSOR EN UNIDADES MINUTOS FIN                  
               case 8:
                  if (puls_up_fs){
                     if (inc_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_INC, 0))
                     {
                        inc_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_INC, 0);
                     }
                  }
                  if (puls_down_fs){
                     if (dec_2bcd(&config_minuto_fin[config_dia_actual],
                                  LIMIT_MINS_DEC, 0))
                     {
                        dec_2bcd(&config_hora_fin[config_dia_actual],
                                 LIMIT_HORAS_DEC, 0);
                     }
                  }        
               //-------------------------
                  break;

He definido los limites de hora y minuto en el principio del programa así:

#define LIMIT_HORAS_INC      0x24
#define LIMIT_MINS_INC       0x60

#define LIMIT_HORAS_DEC      0x23
#define LIMIT_MINS_DEC       0x59

Gracias a este codigo ajuso la hora y minuto del encendido y del apagado de los LEDs de los dos canales de dia.

Todo esto es mostrado en pantalla gracais a este código:
Código: [Seleccionar]
//PANTALLA DE CONFIGURACION            
         case 1:

            //ENCABEZADO
            lcd_gotoxy (1,1);
            printf (lcd_putc1 "< PANTALLA PARA PROGRAMAR EL ENCENDIDO >");
            
            //DIA
            lcd_gotoxy(1,2);
            printf(lcd_putc1,"Encender el ");
            lcd_gotoxy(13,2);
            lcd_print_nom_dia_sem(config_dia_actual);
            lcd_gotoxy(16,2);
            printf(lcd_putc1," de ");
            
            //INICIO
            lcd_gotoxy(20,2);
            lcd_print_2num_bcd_lcd1(config_hora_inicio[config_dia_actual]);
            lcd_gotoxy(22,2);
            printf(lcd_putc1,":");
            lcd_gotoxy(23,2);
            lcd_print_2num_bcd_lcd1(config_minuto_inicio[config_dia_actual]);
            lcd_gotoxy(25,2);
            printf(lcd_putc1," a ");
            
            //FIN
            lcd_gotoxy(28,2);
            lcd_print_2num_bcd_lcd1(config_hora_fin[config_dia_actual]);
            lcd_gotoxy(30,2);
            printf(lcd_putc1,":");
            lcd_gotoxy(31,2);
            lcd_print_2num_bcd_lcd1(config_minuto_fin[config_dia_actual]);
            lcd_gotoxy(33,2);
            printf(lcd_putc1,"   ");

            break;

Estas son als funciones que ultilizo para incrementar y decrementar los valores de hora y minuto tanto de inicio como de fin:

Código: [Seleccionar]
//-----------------------------------------------------------------------------
short inc_2bcd(int* num_bcd, int bcd_limite = 0x9A, short digito = 0)
//Significado de los parametros:
//    num_bcd:    numero de 2 cifras en BCD que queremos incrementar
//    bcd_limite: valor una vez incrementado el numero BCD que se considera que
//                ha habido un desbordamiento, volviendo al valor 0. Los unicos
//                valores no BCD aceptables son desde 0x9A hasta 0xA0 que
//                equivalen a 100 BCD.
//    digito:     especifica si se ha de incrementar la cifra de las unidades(0)
//                o la de las decenas (1)
//
//Devuelve 1 si desborda por el limite
{
   switch (digito)
   {
      //Incrementar unidades
      case 0:
         *num_bcd +=1;              //Unidades + 1
         if ((*num_bcd & 0x0F) > 9) //Unidades > 9?
         {
            *num_bcd &= 0xF0;          //Unidades = 0
            *num_bcd += 0x10;          //Decenas + 1
         }
         if (*num_bcd >= bcd_limite)//Desbordamiento?
         {
            *num_bcd = 0x00;           //Numero BCD = 00
            return 1;                  //Devolver desbordamiento
         }
         break;
      //Incrementar decenas        
      case 1:
         *num_bcd += 0x10;          //Decenas + 1
         if (*num_bcd >= bcd_limite)//Desbordamiento?
         {
            *num_bcd &= 0x0F;          //Decenas = 0
            return 1;                  //Devolver desbordamiento
         }        
         break;
   }
   return 0;
}
//-----------------------------------------------------------------------------

short dec_2bcd(int* num_bcd, int bcd_limite = 0x99, short digito = 0)
//Significado de los parametros:
//    num_bcd:    numero de 2 cifras en BCD que queremos decrementar
//    bcd_limite: valor que tomará el numero BCD si se ha llegado a numeros
//                negativos (desbordamiento).
//    digito:     especifica si se ha de decrementar la cifra de las unidades(0)
//                o la de las decenas (1)
//
//Devuelve 1 si desborda por debajo de 0
{
   switch (digito)
   {
      //Decrementar unidades
      case 0:
         *num_bcd -= 1;                //Unidades - 1
        
         if (*num_bcd == 0xFF)           //Desbordamiento?
         {
            *num_bcd = bcd_limite;        //Numero BCD = limite
            return 1;                     //Devolver desbordamiento
         }

         if ((*num_bcd & 0x0F) == 0x0F)//Desbordamiento de Unidades?            
         {                                //Automaticamente -> Decenas - 1
            *num_bcd &= 0xF9;//0b11111001;//Unidades = 9          
         }
         break;
        
      //Decrementar decenas        
      case 1:
         *num_bcd -= 0x10;             //Decenas - 1

         if ((*num_bcd & 0xF0) == 0xF0)//Desbordamiento?
         {
            *num_bcd = (*num_bcd & 0x0F) | (bcd_limite & 0xF0); //Decenas = Decenas de limite
            if (*num_bcd > bcd_limite){   //Al restaurar las decenas, el numBCD es > limite?
               *num_bcd -= 0x10;               //Decenas - 1
            }
            return 1;                     //Devolver desbordamiento
         }      
         break;
   }
   return 0;
}

I esta son las funciones de la EEPROM donde leo y guardo los 4 valores del encendido para ada dia de la semana de Lunes a Domingo(2 para el inicio o encendido de los leds (hour_init, min_init) y otros dos para el apagado (hour_end, min_end)):
Código: [Seleccionar]
//-----------------------------------------------------------------------------
short cargar_eeprom() //Devuelve 0 si todo correcto / 1 si ha ocurrido algun error
{
   short temp_return;
   int *array;
   int i;
   int checksum_calc, checksum_leido;
  
   checksum_calc = 0x4A;  //Valor de inicio de la suma de comprobación de errores.  
  
   for (i = 0; i < 4; i++){
      switch(i)
      {
         case 0: array = &config_hora_inicio[0];   break;
         case 1: array = &config_minuto_inicio[0]; break;
         case 2: array = &config_hora_fin[0];      break;
         case 3: array = &config_minuto_fin[0];    break;
      }
      
      for (temp = 0; temp < 7; temp++){
         array[temp] = read_eeprom((i*7) + temp);
         if (array[temp] > 0x59) temp_return = 1;
        
         checksum_calc += array[temp];
      }
      
   }
  
   //Comprobación de errores
   checksum_leido = read_eeprom(0x1C /* =4*7 */);
  
   if (checksum_calc != checksum_leido){
      //Reset Data
      for (temp = 0; temp < 7; temp++){
         config_hora_inicio[temp]   = config_minuto_inicio[temp]  = 0x00;
         config_hora_fin[temp]      = config_minuto_fin[temp]     = 0x00;
      }
      return 1;
   }else return 0;
}
//-----------------------------------------------------------------------------
void guardar_eeprom()
{
   int *array;
   int i;
   int checksum;
  
   checksum = 0x4A;  //Valor de inicio de la suma de comprobación de errores.  
  
   for (i = 0; i < 4; i++){
      switch(i)
      {
         case 0: array = &config_hora_inicio[0];   break;
         case 1: array = &config_minuto_inicio[0]; break;
         case 2: array = &config_hora_fin[0];      break;
         case 3: array = &config_minuto_fin[0];    break;
      }

      for (temp = 0; temp < 7; temp++){
         write_eeprom((i*7) + temp, array[temp]);
        
         checksum += array[temp];
      }      
   }  
   write_eeprom((0x1C /* =4*7 */), checksum);
}
//-----------------------------------------------------------------------------;

Nunca he hecho un codigo PWM para PIC, asi que por eso pdio ayuda.

Encontre este tutorial:

Tutorial PWM con PIC C de CCS


Si yo queiro que la subida de 0 a 100% (0 a 255) sean 5 segundos como deberia hacerlo?

aqui creo que es donde se podria hacer eso

setup_timer_2(T2_DIV_BY_16, 255, 1);



La idea que tenia para poder hacer el PWM es esta (de alguna manera realizar estas operaciones):



Sabiendo que aqui hemos puesto que la duración del ciclo de dia son 12 horas, yo quiero que el PWM se ajuste segun lo que el usuario introduzca como valores de inicio y apagado.

horatotal=config_hora_fin[dow]-config_hora_inicio[dow];
minutototal=config_minuto_fin[dow]-config_minuto_inicio[dow];              aqui hay que tener en cuenta que si el minuto inicio es 30 y el de fin 00 convertir el 00 a 60para poder restar.


horarest=config_hora_fin[dow]-hora del ds1302;
minrest=config_minuto_fin[dow]-minuto del DS1302;    

Luego pasar todo esto a milisegundos asi por ejemplo:

milisegundostotal=(horatotal*3600*1000)+(mintotal*60*1000);   //3600 porque son los segundos que tiene una hora y 60 por los segundos por minuto y por 1000 poruqe un segundo son 1000 milisegundos
milisegundosrest=(horarest*3600*1000)+(minrest*60*1000);   //3600 porque son los segundos que tiene una hora y 60 por los segundos por minuto y por 1000 poruqe un segundo son 1000 milisegundos

y habria que comprobar con un if de la siguiente manera:

if(milisegundosrest<milisegundostotal){
milisegundosinicio=milisegundosrest;  //estto seria el incio del bucle como un j=milisegundosrest; como inicio del contador
milisegundosacontar=milisegundostotal-milisegundosrest;  //esto sera lo que cuente si mpieza en 30000 y acaba en 50000, contaria 20000, eta variable usaria para eso
}
else{
milisegundosinicio =0;  //esto es como un j=0, el inicio del contador
milisegundoacontar=milisegundostotal;
}


milisegundosinicio y milisegundosacontar los usaremos para poder hacer los diferentes PWM y, pero primero quiero que me confirmen si con 20MHz de cristal el ciclo son 1ms,  e ir comprobando la hora con el DS1302 para hacer los diferentes PWM


La cuestion es que no se hacer las restas con las variables que guardo en la eeprom (realmente ya no se si son Hex o binarias, creo que binarias, pero no estoy seguro, en cualquier caso no se hacer la resta en este formato, asi que aqui es donde necesito ayuda.



Todo esto evidentemente con mi PIC 18F8722


Espero no haberme enrollado mucho

Y como siempre antetodo gracias y espero su ayuda con esto de las matematicas en C :)

    
« Última modificación: 01 de Julio de 2015, 11:39:23 por Arkaedus »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #4 en: 01 de Julio de 2015, 18:06:11 »
Primero que nada, yo pienso que ese 7805 va a desaparecer de la faz del planeta tierra cuando conectes eso., de la salida de 12V a los 5V de salida hacen que caigan 7V en el 7805. Por otro lado no se con que vas a alimentar los leds, son 3W e imagino una caida de tension de 2 a 2.5V cada uno, asi que seguro que de la alimentacion de 12V, si llegas a sacarlo del regulador va a estallar tambien, ya que a este podes sacarle solo 1A caso extremo con muchisima disipacion/minima caida de tension.  Si los alimenta con los 24V ahi puede sobrevivir ambos tal ves, todo va a depende de cuanto consuma tu circuito, acordate que en tu 7812 caen 12V, asi que un poco de corriente y ya estarias cerca del limite de potencia.


Bue dejando eso a un lado... Y volviendo a la programacion


Citar
Nunca he hecho un codigo PWM para PIC, asi que por eso pdio ayuda.

aqui creo que es donde se podria hacer eso

setup_timer_2(T2_DIV_BY_16, 255, 1);

Tenes que entender como funciona el PWM, te voy a dar 2 opciones PWM por HW y por SW, fijate que hay un diagrama en el datasheet. Basicamente funciona de esta forma.
Se carga el registro del CCP con un valor, suponete 200.
Se carga el registro PR indicando el periodo, 100.
Se configura el timer para saber cada cuanto cuenta. ( Aunque esa funcion que pasaste hace 2 de estas)

Entonces el TMR2 comienza de 0,salida en 1, el TMR aumenta y esta comparandose continuamente con PR y CCPRxH/L , cuando es igual a PR, pone 0 la salida. Entonces sigue aumentando hasta que es igual a CCPRxH/L ahi es cuadno se completo nuestro periodo, entonces solo el modulo CCP pone a 1 la salida y pone a 0 el TMR, para comenzar todo de nuevo.

Si podes hacer uso de estas salidas de PWM es genial, ya que te ahorra mucho codigo y trabajo del micro.
Pero a veces es complicado hacer periodos de PWM mas grandes, entonces tenes que usar un PWM por soft,
El PWM por soft basicamente intenta imitar eso. Si por ejemplo yo quisiera un periodo de 20ms, entonces mi TMR deberia interrumpir cada 20ms/x ( donde x son los pasos) si son por ejemplo 8 bits, es decir 255 , lo cual te quedaria que deberia producir una interrupcion cada 20ms/255 = 78uS, cada ves que interrumpe sumas 1 a un contador, y comparas con tus periodos de cada PWM, en codigo algo asi:

Código: C
  1. Int_TMR {
  2.    uint8_t i;
  3.    if(pwm1>i){salida_pwm1=0;}else{salida_pwm1=1;}
  4.    if(pwm2>i){salida_pwm2=0;}else{salida_pwm2=1;}
  5.    if(pwm3>i){salida_pwm3=0;}else{salida_pwm3=1;}
  6.    i++;
  7. }
(observa que asumi que al ser de 8 bits va a pasar de 255 a 0, cuando sume 1 mas)

Cambiando los valores de pwm1 ,pwm2, pwm3 ya estarias cambiando el valor de cada uno.
Hay muchisimos ejemplos de PWM con CCS por internet.

Citar
Si yo queiro que la subida de 0 a 100% (0 a 255) sean 5 segundos como deberia hacerlo?

Bueno aqui entra tu manejo de las matematicas y usar un timer. basicamente deberias crear una recta. la ecuacion de la recta que pasa en 2 puntos


x1= tiempo inicial
x2= tiempo final
y1= valor inicial
y2= valor final

Supongamos entonces que vas de 0 a 255 (y1=0 y2=255), en 10 segundos ( x1=0 x2=10 )
pwm = 255/10 * (X-0) + 0
pwm = Ax + B

A y B son los valores que debes encontrar. En este ejemplo A= 255/10  y B=0

Ahora si yo utilizo un timer para actualizar mi valor de pwm cada 1 segundo tengo:
para cuando pasaron 0 segundos => pwm=0
1 seg => pwm=255/10 o 25
2 seg => pwm=255/5 o 51
3 seg => pwm=765/10 o 76

Se observa un poco grande los pasos no?, si se quisiera algo mas suave en el cambio del birillo de los leds, podramos actualizarlo cada 0.5s
0s    -> pwm=0
0.5s -> pwm=12
1s    -> pwm=25
1.5s -> pwm=38

etc, ahora hay pasos mas chiquitos.
Yo utilize un timer por que queria que los cambios esten espaciados uno de otro de forma igual, pero si tu programa por ejemplo no tiene nada que hacer podria hacerlo de ahi, y loso deberias calcular el valor de cada uno de los PWM y actualizar sin necesidad de un timer.

Una cosa mas, en la ecuacion x1 puede ser siempre 0, si es que haces X2=(tiempo final - tiempo inicial) , es decir la diferencia, aqui vas a tener que trabajar con float.

Esa formula te permite calcular cualquier pendiente, asi que cuando termine una pendiente, calculas la otra y no calculas los valroes de pendiente y ordenada, y luego para sacar el pwm simplemente usas la ecuacion de pwm = A*tiempo transcurrido + B

Cuando usar segundos/minutos/horas? eso va a depender de que tan rapido actualizes tus leds, si tus rampas duran minutos hasta horas, entonces tal ves te conviene hacerlo con una base de tiempo de minutos y actualizar cada 30seg o 15 segundos.
Ahora si tus rampas duran segundos podes utilizar tambien minutos para X, pero se hace mas facil usando segundos, hay valores mas grandes. Ej:

de (x1,y1) a (x2,y2)
de (0,10) a (1,255) si tomo x como minutos
y= 245x + 10

Si mi timer interrumpe cada 1 segundos para actualizar los pwm, entonces cada ves que entra mi timer deberia multiplicar la cantidad de entradas por 1/60 , por ejemplo para el segundo 5 deberia hacer esta operacion:
y= 245*(5/60) + 10

de (0,10) a (60,255) usando x como segundos
y= 49/12 * X + 10

La diferencia aca es que si interrumpe cada 1 segundo mi timer para el segundo 5 solo reemplazaria el valor de 5 en X (o 5ta ves que entra), entonces se vuelve mas facil el trabajo de llevar las cuentas aca.
y= 49/12 * (5) + 10

Lo que elijas depende de tu programa y lo que intentas hacer.

Finalmente seguro que me vas a decir que tu rampa peude NO comenzar desde 0.. entonces por ejemplo si tenes una ramap del segundo 23 al 58 , de 50 a 100 pwm , entonces quedaria asi:
x1=23 ; x2=58 ; y1=50 ; y2=100

Y te queda una recta de :

y =  10/7 * X + 120/7

Si lees del DS1302 solo tomas los segundos y lo reemplazas ahi por la X, entonces cuando sean 23segundos esa formula da 0, para 33 segundos te da 64 y asi hasta los 58 que da 100, pero actualizas a cada segundo :)
« Última modificación: 01 de Julio de 2015, 18:29:35 por KILLERJC »

Desconectado Arkaedus

  • PIC10
  • *
  • Mensajes: 25
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #5 en: 02 de Julio de 2015, 15:16:17 »
Hola, veamos la alimentacion del proyecto seian 24V y 5A.

Los LEDs vana  una tension de 3,8V por eso los pongo en series de 5 LEDs ya que 5*3,8V son 19V y necesito 2,5V de caida en el Driver de cada serie de LED por eso me salen 19V+2,5V=21,5V me quedan 2,5V que son disipados en el mosfet del driver, con un buen dsipador térmico de aletas y ayudado por los dos ventiladores que llevaria la lámpara creo que ira bien.

Pongo de nuevo la imagn con unos medidores de corriente:



Como puedes ver le estoy pidiendo muy poca corriente y en el Datasheet 78XX (donde XX = 05 o 12 o 24)datasheet para el de 5 y 12 V se le peude meter una tensión de hasta 35V de entrada y para el de 24V de hasta 40V de entrada.

No he usado nunca PWM ni timers, no te he entendido muy bien como usar lo del timer.

En el datasheet vi un diagrama y codigo de como hacer PWM pero esta en assembler algo que yo no tengo ni idea por eso lo hago el codigo C, que es lo que he estudiado.

Yo he estado mirando e informandome por internet sobre el PWM y he diseñado los PWM para los tres canales de luces para un tiempo determinado de 2 minutos y 40 segundos.
Usando delay_ms();

He estado haciendo un a simulacion en Poteus de los 3 PWM simulando un inicio del canal noche en encendido, apagarloy luego pasar al encendido de los dos canales del dia, para acabar apagandolos y encendiendo de nuevo el de noche según este diagrama:



Debido  a que yo quiero dividir el tiempo que esta encendido el ciclo de dia en 12 partes he optado a usar 120 segundos para el ciclo de dia ya que es multiplode 12. Pero lo suyo es que los delays se sstituyesen por una formula que me ayudase a hacer el PWM a lo largo dle ciclo de dia. Es decir si se progrma un encendido a als 10 y se apague a las 22 hay 12 horas de ciclo de dia y los PWM se adaptarian a esas 12 horas por si solos, y si se pone que de 12 a 22 seria un ciclo de 10 horas, los PWm se volverian a daptar a esas 10 horas cambiandose ellos. es porgramacion pero la cuestion es que no se como hacer lo de coger los datos de mi programa.

Que hago directamente la resta de config_hora_fin-config_hora_inicio??
Tengo que poder trabajar con este dato para pasarlo a segundos y luego poder hacer los PWm segun los segundos que deban de durar.

Este es el codigo de la simulacion de Proteus que hecho que si que van los PWM pero como he dicho con als funciones delay, que no me permiten hacer lo que quiero:

Código: [Seleccionar]
#include <18F8722.h>
#fuses HS, NOWDT, PUT, BROWNOUT, NOLVP
#use delay(clock=4000000)

void pwm();

int i,j,k;


//========================
void main()
{


setup_timer_2(T2_DIV_BY_16, 255, 1);

setup_ccp3(CCP_PWM);
setup_ccp4(CCP_PWM);
setup_ccp5(CCP_PWM);

WHILE(1){
  
   //de 0 a 10 segundos
   i=255;
   j=0;
   k=0;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(10000);
  
   //de 10 a 20 segundos
   j=0;
   k=0;
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   for(i=255; i > 0; i--)
      {
      set_pwm3_duty(i);
      delay_ms(39);// sale de ->       (10segundos)-[(1/frecuencia reloj)*256 ciclos] /256 ciclos
      }
  
   //de 20 a 30 segundos
   i=0;
   set_pwm3_duty(0);
   for(j=0; j< 255; j++)
      {
      set_pwm4_duty(j);
      k=(j-178)*0.662338;
      if(j<178)
      {
      k=0;
      set_pwm5_duty(k);
      }
      else
      set_pwm5_duty(k);
      delay_ms(39);// sale de ->       (10segundos)-[(1/frecuencia reloj)*256 ciclos] /256 ciclos
      }
      
   //de 30 a 40 segundos
   i=0;
   j=255;
   k=51;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(10000);
  
   //de 40 segundos a 43 segundos
   i=0;
   set_pwm3_duty(i);
   for(j=255; j> 204; j--)
      {
      k=51+(255-j)*1.5098039;
      set_pwm4_duty(j);
      set_pwm5_duty(k);
      delay_ms(58);// sale de ->       (3segundos)-[(1/frecuencia reloj)*51 ciclos] /51 ciclos
      }
      
   //de 43 a 60 segundos
   i=0;
   j=204;
   k=128;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(17000);
  
   //de 60 a 63 segundos
   i=0;
   set_pwm3_duty(i);
   for(j=204; j> 51; j--)
      {
      k=128+(204-j)*0.830065;
      set_pwm4_duty(j);
      set_pwm5_duty(k);
      delay_ms(20);// sale de ->       (3segundos)-[(1/frecuencia reloj)*153 ciclos] /153 ciclos
      }

   //de 63 a 97 segundos
   i=0;
   j=51;
   k=255;
   set_pwm3_duty(0);
   set_pwm4_duty(51);
   set_pwm5_duty(255);
   delay_ms(34000);
  
   // de 97 a 100 segundos
   i=0;
   set_pwm3_duty(i);
   for(k=255; k> 128; k--)
      {
      j=51+(255-k)*1.204724;
      set_pwm5_duty(k);
      set_pwm4_duty(j);
      delay_ms(24);// sale de ->       (3segundos)-[(1/frecuencia reloj)*127 ciclos] /127 ciclos
      }
  
   //de 100 a 117 segundos
   i=0;
   j=204;
   k=128;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(17000);
  
  // de 117 a 120
  i=0;
  set_pwm3_duty(i);
  for(k=128; k> 51; k--)
      {
      j=204+(128-k)*0.662338;
      set_pwm5_duty(k);
      set_pwm4_duty(j);
      delay_ms(39);// sale de ->       (3segundos)-[(1/frecuencia reloj)*77 ciclos] /77 ciclos
      }
  
   //de 120 a 130 segundos
   i=0;
   j=255;
   k=51;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(10000);
  
  
  // de 130 a 140
  i=0;
  set_pwm3_duty(i);
  for(j=255; j> 0; j--)
      {
      k=51-(255-j)*0.662338;
      set_pwm4_duty(j);
      if(j>178)
      set_pwm5_duty(k);
      else
      {
      k=0;
      set_pwm5_duty(k);
      }
      delay_ms(39);// sale de ->       (10segundos)-[(1/frecuencia reloj)*256 ciclos] /256 ciclos
      }
      
   //de 140 a 150 segundos
   j=0;
   k=0;
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   for(i=0; i <255; i++)
      {
      set_pwm3_duty(i);
      delay_ms(39);// sale de ->       (10segundos)-[(1/frecuencia reloj)*256 ciclos] /256 ciclos
      }
  
   //de 150 a 160 segundos
   i=255;
   j=0;
   k=0;
   set_pwm3_duty(i);
   set_pwm4_duty(j);
   set_pwm5_duty(k);
   delay_ms(10000);
}
}


Tambien paso el archivo proteus y el del codigo para si quereis comprobar que funciona por si alguien alguna vez mira o busca algo sobre PWM y le puede servir.



Espero no ser tan pesado y a ver si puedo llegar a encontrar la solución a lo que deseo.

Muchas gracias KILLERJC y siento ser tan negado para esto pero poco a poco voy cogiendolo y aprendiendo. Los primeros pasos en los microcontroladores cuestan bastante jejeje

« Última modificación: 02 de Julio de 2015, 20:09:11 por Arkaedus »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #6 en: 02 de Julio de 2015, 20:33:04 »
Primero explico que es un timer de forma resumida, un timer es simplemente un modulo que cuenta pulsos, de reloj o externos , como el reloj ( cristal ) es conocida su frencuencia entonces uno puede calcular cuantos ciclos (pulsos) deberian entrar al timer para que se cumpla el tiempo necesario. Como los registros son limitados a 8/16/32bits, esto te lleva que cuando llegue por ejemplo el de 8bits a 0xFF cuando se agrega uno mas se produce un overflow y se esto activa la interrupcion. Eso es un timer, entonces si vos tenes un ciclo de 20ms de reloj ( para ser exagerado y ya dividido por 4 como hace microchip Tcy= fosc/4 ), si vos cargas al timer el valor de 250, va a contar 6 de esos y cuando llegue a los 6 se produce una interrupcion, entonces vos ya sabes que pasaron 6*20ms = 120ms.


Bueno ahora se me encendio la lamparita un poco mas. Por un momento pense que estabas queriendo hacer tu grafico de forma dinamica para que vos puedas modificarlo cuando quieras. Si tu grafico es fijo directamente podes calcular las constantes y ahcer masomenos lo que estaba haciendo yo. Tampoco se el periodo de tu PWM para saber si se va a hacer por SW o HW, si es por HW te ahorras muchisimo vuelvo a repetir

Podes hacer con delays cada una de las rampas pero si observas, esto te llevaria a hacer para cada una de estas una funcion distinta. Ademas los delays hacen que el micro se quede haciendo "nada" es decir no lo podes ocupar en otra cosa. Otra desventaja es que con el agregado de otras instruccion no vas a poder tener un cierto control del tiempo del mismo, ya que sino deberias estar contando instruccion por instruccion en ASM para saber cuanto tarda en ejecutarse y se cumpla como debe ser la rampa.
Ademas de eso necesitarias una seccion de codigo que pregunte que hora es y llame a la funcion exacta.

Es decir algo asi (brutamente pero espero que sirva para que te des cuenta y asumo que es por HW el PWM):

Código: C
  1. main()
  2. {
  3.         preguntar_hora();
  4.         tiempo_actual=hora*60 + minutos;                        //Pienso actualizar los valroes del PWM a cada minuto, por eso no me preocupan los segundos
  5.         if(tiempo actual<seccion1) {rampa1();}                  // Ejemplo solo de 10 tramos
  6.         if(seccion1<tiempo actual<seccion2) {rampa2();}
  7.         if(seccion2<tiempo actual<seccion3) {rampa3();}
  8.         if(seccion3<tiempo actual<seccion4) {rampa4();}
  9.         if(seccion4<tiempo actual<seccion5) {rampa5();}
  10.         if(seccion5<tiempo actual<seccion6) {rampa6();}
  11.         if(seccion6<tiempo actual<seccion7) {rampa7();}
  12.         if(seccion7<tiempo actual<seccion8) {rampa8();}
  13.         if(tiempo actual>seccion9) {rampa9();}
  14. }
  15.  
  16. rampa1(){
  17.         int i;
  18.         for(i=0;i<200;i+=20)
  19.         {
  20.                 set_pwm_duty(i);
  21.                 delay_ms(10);       //Ejempo pero deberia ser mucho mayor
  22.         }
  23. }

Tendrias varias desventajas, no podrias actualizar tu LCD a cada segundo por que estaria metido ahi dentro haciendo sus delays, una ves que salga ahi podrias hacerlo.
La otra es que que si quisieras cambiar una rampa por algun motivo tendrias que volver a revisar TODO el codigo completo., modificar el codigo: agregando lineas, modificando los tiempos, verificando que sean correctos,etc

Por mi parte yo haria algo asi:
La unica referencia de tiempo que tenes es tu DS1307 con respecto a las horas del dia,horas/minutos/segundos. Asi que lo que vayas a hacer tienen que tener un comienzo fijado por esa hora, aunque lo pases a minutos por ejemplo, haces
Tiempo_actual = horas*60 + minuto *60

finalmente si no voy a cambiar las rampas y estas van a ser fijas, es decir que para cambiarlas necesitaria programar nuevamente el micro haria lo siguiente:

Crear un array con los valores a usar, de forma ordenada, estos valores pueden ser (los unicos que se me ocurrieron):

Opcion 1: Tiempo_inicial , Tiempo_final , PWM_inicial , PWM_final.
Opcion 2: Tiempo_inicial , A , B   ( de y=Ax+B )
Opcion 3: Tiempo, Valor_PWM

Ordenados por tiempo_inicial de menor a mayor, para no estar revisandolo 1 por 1.

Cada uno con ventaja y desventajas.
Opcion 1 tiene la ventaja de ocupar menos espacio en memoria ya que necesitarias 16+16+8+8 = 48bits o 6bytes por cada cambio (8bytes si ponemos todos de 16bits) , pero tiene la desventaja que cada ves que cambies la rampa deba calcularse nuevamente los coeficientes, esto no es tanto ya que serian 2/3ms cada ves que cambia la rampa o pendiente. Basicamente no es mucho

Opcion 2 tiene la ventaja de que no necesitas hacer el calculo en el micro, ya calculaste todo afuera y solo pusiste los coeficientes, este tiene una desventaja y que es que los float ocupan mucho mas espacio que los anteriores, si no me equivoco usa 32bits, asi que tendrias 10bytes(16+32+32 o en bytes 2+4+4) por cada cambio.

La opcion 3 es la que menos espacio ocupa 16+8 o 3bytes (4bytes si creas todo de 16bits) por cada cambio. funcionaria de la misma forma que la opcion 1, es decir necesitas calcular las cosas, aunque no hice un codigo para este, es muy similar a la opcion 2 su aplicacion

Ejemplo en codigo:

Opcion 2:
Código: C
  1. const float myarray[50][3] = {{T1,A1,B2,},{T2,A2,B2},....{Tn,An,Bn}}
  2.  
  3. main()
  4. {
  5.         preguntar_hora();
  6.         tiempo_actual=hora*60 + minutos;
  7.         j=buscar_indice();                      //Aca busco la rampa que deberia usar, o sea que par de 3 valroes deberia usar inicialmente
  8.         while(1)
  9.         {
  10.                 preguntar_hora();
  11.                 tiempo_actual=hora*60 + minutos;
  12.                 if(tiempo_actual>=myarray[j+1][0])              //Pregunto para saber si ya llego a la proxima rampa o constante
  13.                 {
  14.                         j++;                                    // Si llego aumento el indice, de esa forma comienza con la proximo cambio o se mantiene constante
  15.                 }
  16.                 valor_pwm= myarray[j][1] * Tiempo_actual + myarray[j][2];
  17.                 set_pwm_value(valor_pwm);
  18.         }
  19. }

Opcion1:
Código: C
  1. const float myarray[50][3] = {{Ti1,Tf1,PWMi1,PWMf1},{Ti2,Tf2,PWMi2,PWMf2},....{Tin,Tfn,PWMin,PWMfn}}
  2.  
  3. main()
  4. {
  5.         float A,B;
  6.         preguntar_hora();
  7.         tiempo_actual=hora*60 + minutos;
  8.         j=buscar_indice();                      //Aca busco la rampa que deberia usar, o sea que par de 3 valroes deberia usar inicialmente
  9.         A=calculo_de_A(Tij,Tfj,PWMij,PWMfj);
  10.         B=calculo_de_B(Tij,Tfj,PWMij,PWMfj);
  11.         while(1)
  12.         {
  13.                 preguntar_hora();
  14.                 tiempo_actual=hora*60 + minutos;
  15.                 if(tiempo_actual>=myarray[j][1])                        //Pregunto para saber si ya llego a la proxima rampa o constante lo comparo con Tf (tiempo final)
  16.                 {
  17.                         j++;                                    // Si llego aumento el indice, y calculo de nuevo los coeficientes para cada uno de los PWM
  18.                         A=calculo_de_A(Tij,Tfj,PWMij,PWMfj);
  19.                         B=calculo_de_B(Tij,Tfj,PWMij,PWMfj);
  20.                 }
  21.                 valor_pwm= A * Tiempo_actual + B;
  22.                 set_pwm_value(valor_pwm);      
  23.         }
  24. }

Lo cual necesitaria un array para cada unos de los PWM (warm,white,noche), y si se usa la opcion uno, el calculo de Ay B para cada uno de los PWM, basicamente es repetir ese if y el set_pwm para cada uno de los otras salidas.
Todo esto es con el PWM hecho por HW.
Si es por software entonces se tiene que usar una interrupcion para el timer y nada mas.. en ves de actualizar el duty en el programa principal, solo actualizaria una variable, esa variable luego influye en la rutina de interrupcion del timer. Y quedaria algo asi:

Código: C
  1. const float myarray[50][3] = {{Ti1,Tf1,PWMi1,PWMf1},{Ti2,Tf2,PWMi2,PWMf2},....{Tin,Tfn,PWMin,PWMfn}}
  2. uint8_t vueltas;
  3.  
  4. main()
  5. {
  6.         float A,B;
  7.         preguntar_hora();
  8.         tiempo_actual=hora*60 + minutos;
  9.         j=buscar_indice();                      //Aca busco la rampa que deberia usar, o sea que par de 3 valroes deberia usar inicialmente
  10.         A=calculo_de_A(Tij,Tfj,PWMij,PWMfj);
  11.         B=calculo_de_B(Tij,Tfj,PWMij,PWMfj);
  12.         while(1)
  13.         {
  14.                 preguntar_hora();
  15.                 tiempo_actual=hora*60 + minutos;
  16.                 if(tiempo_actual>=myarray[j][1])                //Pregunto para saber si ya llego a la proxima rampa o constante,
  17.                 {
  18.                         j++;                                    // Si llego aumento el indice, y calculo de nuevo los coeficientes para cada uno de los PWM
  19.                         A=calculo_de_A(Tij,Tfj,PWMij,PWMfj);
  20.                         B=calculo_de_B(Tij,Tfj,PWMij,PWMfj);
  21.                 }
  22.                 valor_pwm1= A * Tiempo_actual + B;
  23.         }
  24. }
  25.  
  26. int_timer()
  27. {
  28.         if(valor_pwm1>vueltas){salida_pwm1=1;}else{salida_pwm1=0;}
  29.         if(valor_pwm2>vueltas){salida_pwm2=1;}else{salida_pwm2=0;}
  30.         if(valor_pwm3>vueltas){salida_pwm3=1;}else{salida_pwm3=0;}
  31.         vueltas++;
  32. }


Segun tu grafico tendrias 12 puntos para White, 12 para Warm y 4 para noche, usando la opcion 3 seria guardar 112bytes
« Última modificación: 02 de Julio de 2015, 20:49:51 por KILLERJC »

Desconectado Arkaedus

  • PIC10
  • *
  • Mensajes: 25
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #7 en: 03 de Julio de 2015, 05:26:02 »
Muy currada la respueta, pero ahora etngo que ir asimilandola jejeje.

Pues el PIC que uso es el 18F8722

Segun el datsheet tiene para 128KB code, 3936B para data y 1KB EEPROM  y con el compilador PIC C de CCS cuando compilo (a falat solod e introducirle el PWM al proyecto) me dice que estoy usando solo un 2% de RAM y un 9% de ROM.

Es de suponer que por espacio y datos debería ser posible meter el PWM. La idea que tenia es hacerla por codigo o sea software, cuando me hablas de hardware es por usar algun componente fisico no?

Necesito que se actualice la pantalla LD cada segundo almenos por el DS_1307 que marca los segundos cmabiantes en la pantalla y que el PIC pueda hacer varias cosas a la vez pro eso pedí ayuda proque sabía que con los delays no podrío hacerlo.

Voy a intentar hacer algo con lo que me explicastes y si tengo alguna duda te comento.

Un saludo.

« Última modificación: 03 de Julio de 2015, 08:01:13 por Arkaedus »

Desconectado Arkaedus

  • PIC10
  • *
  • Mensajes: 25
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #8 en: 03 de Julio de 2015, 09:01:05 »
Hola vale voy a empezar y vamos a ir solventando los problemas poco a pcoo:

PRIMER PROBLEMA:

He hecho lo siguiente:

  • declaro la variable para almacenar el resultado de la resta

int horastotalesdia;
int config_hora_inicio[7];
int config_minuto_inicio[7];

int config_hora_fin[7];
int config_minuto_fin[7];

  • hago las restas y lo muestro por pantalla

if(config_hora_fin[dow]>config_hora_inicio[dow])
horastotalesdia=config_hora_fin[dow]-config_hora_inicio[dow];       
   
else
horastotalesdia=0;

      lcd_gotoxy(1,4);
      printf(lcd_putc2,"%02x" horastotalesdia);
               
[/list]

Vale pues si hora de inicio es 02 y hora de fin es 07 me sale en pantalla bien el 05, pero claro estoy imprimiendo en entero en Hexadecimal, para poder multiplicar estas 5 horas por 3600 segundos que tiene cada hora y que el resultado en pantalla y real sea 18000 para poder hacer calculos. Se deberia pasar el entero en hexadecimal a entero, creo yo.¿Como puedo hacer esto?

Esto es lo primero que quiero resolver pues asi puedo obtener los segundos totales que esta el ciclo de dia encendido y a aprtir de ahi programar mis rampas.

Un saludo

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re: Proyecto de encendido de varios canales LEDs con su dimmeador por canal
« Respuesta #9 en: 03 de Julio de 2015, 14:01:35 »
Mmm... Para vos hay diferencia entre 0x5 y 5, y tambien 18000 y 0x4650
Te parecen distinto, pero son los mismos numeros, lo que si vos trabajas con el sistema decimal y los uC y uP con sistema binario. Pero ambos son el mismo numero. distinto es si haces 0x18000 (98304 pasado directamente) pero puede ser interpretado como un numero BCD (0 a 9), es decir cada byte representa un caracter del sistema decimal, tambien como no supera los 9 es decir mas de 4 bits, se puede achichar mas lo que ocupa esa "representacion" directa al sistema decimal

Con lo cual no hay ninguna necesidad de pasar a entero nada.. Si haces

a=0x5;
b=0x3C    //60 decma
c=a*b      // 300

es lo mismo que hacer:

a=5;
b=60;
c=a*b;    // 300

No hay diferencia, asi que no hay niguna conversion de entero decimal a entero hexa o viceversa, lo que si vas a necesitar una variable mas grande, ya que 300 y 18000 solo entran en variables de 16bits ( 2^16=65536 ), nada mas.
Y cuando hagas el printf hacelo como decimal. el compilador y printf se van a encargar de pasar de esa representacion binaria(hexa) que posee el uC a decimal BCD y finalmente a ASCII para enviarlo al LCD.