TODOPIC
Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: alanitotkd en 08 de Junio de 2011, 23:28:45
-
hola que tal necesito ayuda para poder hacer funcionar todo eso LCD_I2C_2 displays de 7 segmentos y comunicacion serial con el 16f876
de echo ya tengo el programa hecho pero no tengo ninguna interrupcion, todo corrido.
lo cual no soy muy bueno en interrupciones necesito que me envie datos serialmente y multiplexee los displays sin problema .. a y ke el I2C de un Ds1307 se muestre en el LCD
haber si me pueden ayudar a estructurar mi programa para que funcione ..
Help ...
Les dejo mi codigo ..
#include <LCD.c>
#byte portc = 0x07
#define ds_seconds 0x00
#define ds_minutes 0x01
#define ds_hours 0x02
#define ds_day 0x03
#define ds_date 0x04
#define ds_month 0x05
#define ds_year 0x06
#define ds_control 0x07
#define MULT1 PIN_C1
#define MULT2 PIN_C3
int16 time,lm35,retardo=250;
int8 data,unidad,decena;
//Dato en registro ds, a mandar o leer
int seconds,minutes,hours,day,date,month,year,control;
void ds1307(void);
void multiplex(void);
void main()
{
set_tris_c(0x00);
SETUP_ADC_PORTS(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_2(T2_DIV_BY_4,249,1); // Timer2 a ikhz
setup_ccp1(CCP_PWM);
set_adc_channel(0);
seconds= 0x00;
minutes= 0x30;
hours = 0x17;
day = 0x04;
date = 0x08;
month = 0x06;
year = 0x11;
control= 0x00;
delay_ms(retardo);
i2c_start();
i2c_write(0xd0);
i2c_write(ds_seconds);
i2c_write(seconds);
i2c_write(minutes);
i2c_write(hours);
i2c_write(day);
i2c_write(date);
i2c_write(month);
i2c_write(year);
i2c_write(control);
i2c_stop();
lcd_init();
lcd_putc("\f");
lcd_putc("Temp: \n");
lcd_gotoxy(13,1);
lcd_putc("oC");
while(TRUE)
{
delay_ms(retardo);
i2c_start();
i2c_write(0xd0);
i2c_write(ds_seconds);
i2c_stop();
i2c_start();
i2c_write(0xd1);
seconds = i2c_read();
minutes = i2c_read();
hours = i2c_read();
day = i2c_read();
date = i2c_read();
month = i2c_read();
year = i2c_read(0);
i2c_stop();
time = read_adc();
lm35 = time/10.23;
time = time*0.97752;
set_pwm1_duty(time);
set_timer2(0);
//delay_ms(200);
data = lm35;
unidad = data%10;
decena = data/10;
printf("%Lu",lm35);
multiplex();
lcd_gotoxy(7,1);
printf(lcd_putc," ");
printf(lcd_putc,"%Lu",lm35);
lcd_gotoxy(1,2);
printf(lcd_putc,"%2x-%2x-20%2x %2x:%2x:",date,month,year,hours,minutes); //xxx.x °C
}
}
void multiplex(void)
{
portc=decena*16;
output_high(MULT1);
delay_ms(15);
output_low (MULT1);
delay_ms(15);
portc=unidad*16;
output_high(MULT2);
delay_ms(15);
output_low(MULT2);
delay_ms(15);
}
espero alguien me pueda ayudar .
saludos
-
Hola, exactamente que es lo que le quieres cambiar a tu programa, si la comunicacion serie solo la vas a usar para enviar datos y no para recibir no necesitarias interrupcion para rs232.
talvez podrias usar interrupciones de timer para multiplexar tus displays o para hacer la impresion en la lcd.
no se si entendi bien lo que quieres, ppero si no corrigeme y vere en que puedo ayudarte
-
claro es lo que quiero ... poder multiplexar los diaplay's y mandar imprimir al LCD con interrupciones ya que si corro el programa asi como esta ... la vrd imprime los display's y espera a que retorne el ciclo para volver a hacerlo
igual con el LCD... y el I2C del reloj .. tardan mucho en ejecutarse..
-
puedes usar el timer0 para que te genere una interrupcion y hagas el corrimiento de tus displays.
para usar la interrupcion necesitas primero configurar el timer para que te de el tiempo de desbordamiento que quieras(supongo que sabes esto, si no me dices y te digo como)
para activar la interrupcion necesitas poner
enable_interrupts(int_timer0);
enable_interrupts(global);
y declarar la funcion de interrupcion respectiva que en este caso seria
#int_timer0
void mux()
{
..... aca pones lo quieres que haga en la interrupcion
}
-
creo que ya lo agregue como me dijiste ... solo que quisiera que me ayudaras un poco por ke que el multiplexeo esta bien pero
no me agrada mucho lo que veo creo ke estoy haciendo algo mal ... te adjunto mi archivo y la simulacion ...
-
te falto agregar el .h, no me deja compilar.
el multiplexeo no creo que se vea en la simulacion como se veria realmente, creo que tendrias que probarlo fisicamente para que veas si se prenden bien los displays
-
hola seguimos viendo que onda... mira te adjunto con el .h
creo ke tengo un error en la funcion bcd()
me aparecen 2 warnings....
y en la interrucion del timer 0
puse delay's no importa ?
-
algunos comentarios.
el warning que te da por bcd es porque lo estas declaranto como variable, pero lo abajo lo pones como funcion, si es funcion no necesitas declararlo arriba solo pon
int bcd()
{
...
return valor
}
y pusiste la interrupcion pero la estas usando mal, la idea de la interrupcion era para que quitaras los delays, es decir, entra una vez a la interrupcion y prendes el display 1, y cuando vuelva a entrar apagas el display 1 y prendes el 2, y asi los vas alternando
-
entonces seria algo parecido como ...
int flag;
flag = 0;
#int_timer0
void mux()
{
flag ++;
switch(flag)
{
case 1:
portc=decena*16;
output_high(MULT1);
break;
case 2:
output_low (MULT1);
break;
case 3:
portc=unidad*16;
output_high(MULT2);
break;
case 4:
output_low(MULT2);
break;
}
if (flag ==4)
flag = 0;
}
o como ... ? es ke no entiendo muy bien eso ...
-
si, mas o menos asi, podria ser asi:
int1 flag
#int_timer0
void mux()
{
if(flag)//si vas a prender el display 1
{
output_low(display2); apagas el display 2
//sacas el valor para el display 1
ouput_high(display 1); prendes el display 1
flag=false
}
else
{
output_low(display 1); apagas el display 1
//sacas el valor para el display 2
ouput_high(display 2); prendes el display 2
flag=true
}
}
espero se entienda, no necesitas 4 estados, porque tienes 2 estados en los que estan apagados los 2 displays, solo necesitas alternar entre uno y otro y en hardware no se vera que parpadean
-
ok correcto ...
lo estoy haciendo de esa manera ... al simularlo el PWM varia a lo loco ... y no esta en el valor que debe ser ... no se si te paso lo mismo en mi simulacion??
varia el ancho del pulso ... dsenfrenadamente .... ke podra ser . ???
#include "FINAL_UC1.h"
#include <LCD.c>
#byte portc = 0x07
//Registros DS1307
#define ds_seconds 0x00
#define ds_minutes 0x01
#define ds_hours 0x02
#define ds_day 0x03
#define ds_date 0x04
#define ds_month 0x05
#define ds_year 0x06
#define ds_control 0x07
#define MULT1 PIN_C1
#define MULT2 PIN_C3
//#use standard_io (C)
int16 time,lm35,retardo=250;
int8 data,unidad,decena;
//Dato en registro ds, a mandar o leer
int seconds,minutes,hours,day,date,month,year,control;
int8 bcd();
void ds1307(void);
void multiplex(void);
int1 flag;
#int_timer0
void mux()
{
if(flag)//si vas a prender el display 1
{
output_low(MULT2); //apagas el display 2
portc=decena*16; //sacas el valor para el display 1
output_high(MULT1); //prendes el display 1
flag=false;
}
else
{
output_low(MULT1); // apagas el display 1
portc=unidad*16; //sacas el valor para el display 2
output_high(MULT2); //prendes el display 2
flag=true;
}
}
void main()
{
set_tris_c(0x00);
SETUP_ADC_PORTS(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_2(T2_DIV_BY_4,249,1); // Timer2 a ikhz
setup_ccp1(CCP_PWM);
enable_interrupts(int_timer0);
enable_interrupts(global);
set_adc_channel(0);
seconds= 0x00;
minutes= 0x30;
hours = 0x17; //modo 24 hrs
day = 0x04; //1 es domingo
date = 0x08;
month = 0x06;
year = 0x11;
control= 0x00; //OUT=0 SQWE=0 RS0-1=0 no hay onda cuadrada
delay_ms(retardo); //Usuario lee
//Establece fecha y hora
i2c_start(); //Inicia I2C
i2c_write(0xd0); //Direcciona DS1307 write
i2c_write(ds_seconds); //Indica que empiece en registro ds_seconds
//Aquí establece fecha y hora respecto a la puesta arriba
i2c_write(seconds);
i2c_write(minutes);
i2c_write(hours);
i2c_write(day);
i2c_write(date);
i2c_write(month);
i2c_write(year);
i2c_write(control);
i2c_stop(); //Ya puso la hora y fecha
//El RTC ya está marcando el tiempo y fecha
//Rutina LCD
lcd_init();
lcd_putc("\f"); //Limpia LCD
lcd_putc("Temp: \n");
lcd_gotoxy(13,1);
lcd_putc("oC");
while(TRUE)
{
time = read_adc();
printf("%Ld",time);
lm35 = time/10.23;
data = lm35;
data=bcd();
set_pwm1_duty(time);
set_timer2(0);
delay_ms(200);
delay_ms(retardo); //Usuario lee
i2c_start(); //Inicia I2C
i2c_write(0xd0); //Direcciona DS1307 write
i2c_write(ds_seconds); //Indica que ponga registro en ds_seconds
i2c_stop();
i2c_start();
i2c_write(0xd1); //Lee DS1307
seconds = i2c_read();
minutes = i2c_read();
hours = i2c_read();
day = i2c_read();
date = i2c_read();
month = i2c_read();
year = i2c_read(0);
i2c_stop();
lcd_gotoxy(7,1);
printf(lcd_putc,"%Lu",lm35); //xxx.x °C
lcd_gotoxy(1,2);
printf(lcd_putc,"%2x-%2x-20%2x %2x:%2x:",date,month,year,hours,minutes); //xxx.x °C
}
}
int bcd()
{
unidad = data%10;
decena = data/10;
}
-
me parece raro que te haga eso, solo lo estas tomando de tu ADC, cada cuando necesitas hacer tu muestreo y enviar tus datos por i2c?
tal vez lo estes muestreando muy rapido, tal vez podrias usar la interrupcion por timer 1 para hacer una lectura en cada interrupcion y luego enviar tus datos por i2c.
si quieres ver paso por paso que esta pasando con tu programa, o porque varia asi el pwm puedes vero en proteus, al tu pic cargale el archivo .cof en lugar del .hex, y cuando pongas pausa te abrira la linea de codigo de tu programa y podras ver las variables y saber linea a linea que hace tu programa
-
No es que tiene que mostrar el reloj en tiempo real del ds1307 y a la ves tomar la lectura del ADC de un lm35 acondicionado. el valor del adc de 10 bits se va a enviar al pwm y multiplexar el% de modulacion por los displays. mandar el adc tambien por serial y la hora con fecha y temperatura mostrarlas en un LCD
esta medio raro ...
-
si quieres mostrar en tiempo real, porque no haces un muestreo cada segundo, puede configurar el timer 1 para que te de la interrupcion cada segundo y en ese momento tendrias un segundo antes del siguiente muestreo para actualizar tus datos y enviar por i2c
-
me parece muy bueno eso ... nad mas ke no se usar esa interrupcion... si me puedes ayudar con eso ...
eso es lo que keria hacer ...
-
es parecido a la interrupcion por timer0
pones stup_timer1()//aca configuras para que dure exactamente 1 segundo.(si quieres dime que oscilador usas y te ayudo con la configuracion)
y activas la interrupcion
enable_interrupts(int_timer1);
y creas la funcion
#int_timer1
void int_t1()
{
//aca puedes activar una bandera para que en cuanto regrese al main haga la actualizacion de datos, ya que lo ideal es no hacer muchas operaciones dentro de la interrupcion
}
una duda, usas un cristal interno o uno externo?
-
es con un cristal de 4 Mhz eso es lo ke me pides ?
-
si, eso.
puedes configurarlo asi;
setup_timer1(t1_internal|t1_div_by_8);
con esto el timer se generara una interrupcion cada 524ms pero si le das un valor inicial al timer de 3036, entonces tendras una interrupcion cada 500 ms.
entonces cada interrupcion harias esto:
#int_timer1
void int_t1()
{
set_timer1(3036);//con esto incializa el timer para que te vuelva a generar la interrupcion en medio segundo.
//si quieres puedes dejarlo cada medio segundo, es decir, 2 muestras por segundo, o poner un contador, y que cada 2 interrupciones se active una bandera para actualizar los datos
}
espero te sirva.
-
hola como doy lata con eso ... pero sii me estoy quemando los ojos para que salga... podrias ver mi codigo es que la salia PWM no sale como deberia...
haber si habilite bn el timer 1
#include "FINAL_UC1.h"
#include <LCD.c>
#byte portc = 0x07
//Registros DS1307
#define ds_seconds 0x00
#define ds_minutes 0x01
#define ds_hours 0x02
#define ds_day 0x03
#define ds_date 0x04
#define ds_month 0x05
#define ds_year 0x06
#define ds_control 0x07
#define MULT1 PIN_C1
#define MULT2 PIN_C3
//#use standard_io (C)
int16 time,lm35,retardo=250;
int8 data,unidad,decena;
//Dato en registro ds, a mandar o leer
int seconds,minutes,hours,day,date,month,year,control;
int8 bcd();
void ds1307(void);
void multiplex(void);
int1 flag,flag2;
#int_timer0
void mux()
{
if(flag)//si vas a prender el display 1
{
output_low(MULT2); //apagas el display 2
portc=decena*16; //sacas el valor para el display 1
output_high(MULT1); //prendes el display 1
flag=false;
}
else
{
output_low(MULT1); // apagas el display 1
portc=unidad*16; //sacas el valor para el display 2
output_high(MULT2); //prendes el display 2
flag=true;
}
}
#int_timer1
void int_t1()
{
if(flag2)
flag2=false;
else
flag2 = true;
set_timer1(3036);//con esto incializa el timer para que te vuelva a generar la interrupcion en medio segundo.
//si quieres puedes dejarlo cada medio segundo, es decir, 2 muestras por segundo, o poner un contador, y que cada 2 interrupciones se active una bandera para actualizar los datos
}
void main()
{
set_tris_c(0x00);
SETUP_ADC_PORTS(AN0_AN1_AN3);
setup_adc(ADC_CLOCK_INTERNAL);
setup_timer_1(t1_internal|t1_div_by_8);
setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
setup_timer_2(T2_DIV_BY_4,249,1); // Timer2 a ikhz
setup_ccp1(CCP_PWM);
enable_interrupts(int_timer0);
enable_interrupts(int_timer1);
enable_interrupts(global);
set_adc_channel(0);
seconds= 0x00;
minutes= 0x30;
hours = 0x17; //modo 24 hrs
day = 0x04; //1 es domingo
date = 0x08;
month = 0x06;
year = 0x11;
control= 0x00; //OUT=0 SQWE=0 RS0-1=0 no hay onda cuadrada
delay_ms(retardo); //Usuario lee
//Establece fecha y hora
i2c_start(); //Inicia I2C
i2c_write(0xd0); //Direcciona DS1307 write
i2c_write(ds_seconds); //Indica que empiece en registro ds_seconds
//Aquí establece fecha y hora respecto a la puesta arriba
i2c_write(seconds);
i2c_write(minutes);
i2c_write(hours);
i2c_write(day);
i2c_write(date);
i2c_write(month);
i2c_write(year);
i2c_write(control);
i2c_stop(); //Ya puso la hora y fecha
//El RTC ya está marcando el tiempo y fecha
//Rutina LCD
lcd_init();
lcd_putc("\f"); //Limpia LCD
lcd_putc("Temp: \n");
lcd_gotoxy(13,1);
lcd_putc("oC");
while(TRUE)
{
time = read_adc();
time*=0.9775;
printf("%Ld",time);
lm35 = time/10.23;
data = lm35;
data=bcd();
set_pwm1_duty(time);
set_timer2(0);
delay_ms(200);
while(flag2)
{
delay_ms(retardo); //Usuario lee
i2c_start(); //Inicia I2C
i2c_write(0xd0); //Direcciona DS1307 write
i2c_write(ds_seconds); //Indica que ponga registro en ds_seconds
i2c_stop();
i2c_start();
i2c_write(0xd1); //Lee DS1307
seconds = i2c_read();
minutes = i2c_read();
hours = i2c_read();
day = i2c_read();
date = i2c_read();
month = i2c_read();
year = i2c_read(0);
i2c_stop();
}
lcd_gotoxy(7,1);
printf(lcd_putc,"%Lu",lm35); //xxx.x °C
lcd_gotoxy(1,2);
printf(lcd_putc,"%2x-%2x-20%2x %2x:%2x:",date,month,year,hours,minutes); //xxx.x °C
}
}
int bcd()
{
unidad = data%10;
decena = data/10;
}
-
te adjunto unas capturas de mi simulacion para que lo veas ...
-
dentro de la int del timer 1 haz esto:
int1 update=0
int cont=0
#int_timer1
void t1()
{
cont++;
set_timer1(3036);
if(cont==2)// con esto se activara la bandera cada segundo, osea, cada 2 interrupciones
{
update=1;
cont=0;
}
}
y cuando regreses al main
while(true)
{
....
if(update)
{
update=0;//desactivas la bandera
//actualizas
}
}
despues de poner el valor al pwm pon esta instruccion:
set_timer2(0);// si no la pones a veces la simulacion no funciona bien, pero en hardware si
si con eso no queda tambien imprime el valor que metes al pwm y checa si esta variando, talvez sea tu ADC.
me voy a dormir, ya son las 2 am aca, mañana checo si te quedo