Para manejar una imagen o foto por ejemplo tenemos que tener en cuenta que necesitamos de un microcontrolador con buena memoria y velocidad, ya que el renderisado se realiza de forma secuencial, por ejemplo el microcontrolador utilizado para este ejemplo no es suficiente para mostrar una imagen.
En este ejemplo se mostrara un voltimetro y amperimetro, dentro de unos recuadros, con texto informativo y demás.
Para este ejemplo estoy utilizando las librerías para CCS, HDM64GS12.c y graphics.c
La librería HDM64GS12, posee el control del GLCD propiamente dicho y dentro de la misma en su encabezado encontraremos el pinout del mismo para poder conectarlo. El GLCD debe tener el controlador KS0108, debemos tener en cuenta que en el pinout debe tener los pines de selección de chip CS1 y CS2.
La librería Graphics es la librería que nos permitirá dibujar y escribir en el mismo, que detallare las funciones principales de la misma (de todas formas pueden verlo en el encabezado de la librería).
Funciones para controlar el GLCD:
glcd_line(x1, y1, x2, y2, color)
Dibuja una linea desde la coordenada (x1,y1) hasta (x2,y2), la variable color puede ser ON o OFF, esta es la que habilita la linea o no (para mostrarla o no).
glcd_rect(x1, y1, x2, y2, fill, color)
Dibuja un rectángulo desde la coordenada (x1,y1) hasta (x2,y2), la variable fill es para rellenar el rectángulo si esta en YES, o solo dibuja el contorno con NO. la variable color al igual que en el resto de las funciones es la que habilita o no el rectángulo.
glcd_bar(x1, y1, x2, y2, width, color)
Dibuja una barra desde la coordenada (x1,y1) hasta (x2,y2), la variable width es el número de pixel de ancho de la barra, la variable color al igual que en el resto de las funciones es la que habilita o no la barra.
glcd_circle(x, y, radius, fill, color)
Dibuja un circulo en la coordenada (x,y), la variable radius es el numero de pixeles de radio de del circulo, a variable fill es para rellenar el circulo si esta en YES, o solo dibuja el contorno con NO. la variable color al igual que en el resto de las funciones es la que habilita o no el circulo.
glcd_text57(x, y, textptr, size, color)
Escribe texto en la coordenada (x,y), la variable textptr es la variable puntero donde esta alojado el carácter o string, a variable size es el tamaño del carácter, la variable color al igual que en el resto de las funciones es la que habilita o no el texto.
glcd_pixel(x, y, color)
Dibuja un punto o pixel en la dirección de la coordenada (x,y), la variable color al igual que en el resto de las funciones es la que habilita o no el punto o pixel.
A continuación mostrare el pinout del GLCD:
En este programa realizaremos un voltimetro y amperimetro que utilizara 2 canales ADC.
Se implementa el PIC16F887 por la cantidad de pines y puertos del mismo, recordemos que este GLCD requiere de una cantidad considerable de pines.
- #include <16F887.h>
- #device adc=10
- #fuses HS,NOWDT,NOPROTECT,NOLVP
- #use delay(clock=20000000)
- #include <HDM64GS12.c>
- #include <graphics.c>
- void main(){
- int16 voltajeADC, voltajeADC_ant,
- corrienteADC, corrienteADC_ant;
- setup_adc_ports(sAN0|sAN1|VSS_VDD);
- setup_adc(ADC_CLOCK_DIV_2);
- char nombre[]="Electgpl";
- char parametro[]=" [V] [A] ";
- char voltaje[9];
- char corriente[9];
- glcd_init(ON);
- glcd_rect(1, 1, 127, 63, NO, ON);
- glcd_rect(3, 3, 125, 13, NO, ON);
- glcd_text57(41, 5, nombre, 1, ON);
- glcd_rect(3, 15, 125, 25, NO, ON);
- glcd_text57(8, 17, parametro, 1, ON);
- glcd_rect(3, 27, 125, 61, NO, ON);
- while(true){
- set_adc_channel(0);
- delay_us(10);
- voltajeADC=read_adc();
- if(voltajeADC_ant != voltajeADC){
- glcd_text57(13, 38, voltaje, 2, OFF);
- sprintf(voltaje, "%1.2f", (float)voltajeADC*5/1023.0);
- voltaje[4] = '\0';
- glcd_text57(13, 38, voltaje, 2, ON);
- voltajeADC_ant=voltajeADC;
- }
- set_adc_channel(1);
- delay_us(10);
- corrienteADC=read_adc();
- if(corrienteADC_ant != corrienteADC){
- glcd_text57(70, 38, corriente, 2, OFF);
- sprintf(corriente, "%1.2f", (float)corrienteADC*5/1023.0);
- corriente[4] = '\0';
- glcd_text57(70, 38, corriente, 2, ON);
- corrienteADC_ant=corrienteADC;
- }
- }
- }
Como podemos ver en el código fuente, incluimos las dos librerías necesarias para el GLCD, luego definimos las variables para el ADC y las variables character donde alojaremos los strings a mostrar y las dos variables dinámicas de tensión y corriente.
Luego podemos encontrar la configuración de los dos canales de ADC y seguida de la misma la primera instrucción del GLCD que sera la inicialización del mismo que lo borrara cuando el argumento de la función sea ON.
Ahora pasaremos a la función principal de loop donde se aloja el programa.
Ya que la medición de corriente como la de tensión poseen el mismo código, solo explicare una y la otra es igual.
Como podemos ver, seteamos el canal ADC a leer, esperamos los 10us para conversión segura y luego volcamos el contenido del ADC (de 0 a 1023 por estar seteado a 10bit) a la variable voltajeADC.
Por ahora voy a saltear el if y el intercambio de variables, ya que quiero demostrar de forma sencilla el funcionamiento.
La primer función para escribir de forma dinámica, necesitamos la función sprintf se utiliza para escribir strings por eso la letra s antes de printf, y aquí ingresaremos el string (en este caso voltaje[], luego le sigue el formato de dato "%1.2f" que nos dará un entero y dos decimales y por ultimo el valor que vamos a volcar al string (en este caso realizamos todo el acondicionamiento de la entrada en el mismo lugar, que es multiplicar el valor del ADC por 5V que es el fondo de escala y dividirlo por los 1023 pasos de resolución, así nos mostrara un valor de tensión de 0 a 5V).
Luego podemos encontrar el string voltaje[4] que se iguala a '\0', que se encarga de delimitar el máximo de caracteres a 4.
Ahora debemos enviar el valor que hemos convertido a string en la función sprintf a la función del GLCD glcd_text57() donde damos origen al texto en la posición (13,38), luego viene la variable string, el tamaño de la letra que le he puesto valor 2 (es un valor mediano como para que entren las dos variables) y por ultimo ON que sera el que habilita esta función para que se muestre el valor.
Ahora si nosotros cambiamos un valor por otro, que es lo que va a pasar al medir con el ADC, se sobre escribirán uno sobre el otro y no se entenderá lo que se lee, para ello es el uso del if y el intercambio de variables, como pueden ver el if es verdadero cuando el valor del ADC es distinto al ultimo valor leido por el ADC, esto es para ver si el valor cambio o no.
Una vez que es verdadero porque el valor cambia, se procede a la función glcd_text57 pero con el ultimo valor del argumento OFF ya que esto apaga e texto en ese momento y da lugar a la actualización del mismo, y luego lo pone ON y lo deja ahi hasta que se vuelva a actualizar el valor del ADC y entre al if.
De esta forma se logra actualizar en la pantalla de forma dinámica el valor.
Muy bueno voy a probarlo
ResponderBorrarMuy bueno voy a probarlo
ResponderBorrartengo una consulta si quiero gregar una medición mas repito esta parte del codigo
ResponderBorrarset_adc_channel(0);
25. delay_us(10);
26. voltajeADC=read_adc();
27. if(voltajeADC_ant != voltajeADC){
28. glcd_text57(13, 38, voltaje, 2, OFF);
29. sprintf(voltaje, "%1.2f", (float)voltajeADC*5/1023.0);
30. voltaje[4] = '\0';
31. glcd_text57(13, 38, voltaje, 2, ON);
32. voltajeADC_ant=voltajeADC;
y porque se ven muy oscuros los dígitos cuando cambio el valor de tencion
Hola, si lo que queres es tener tres mediciones, es decir leer tres canales ADC y mostrar tres valores en el GLCD, tenes que clonar las lineas de la 24 a 33, y setear set_adc_channel(2); ya que el 0 y el 1 ya los estas usando. Aunque no es solo eso, ya en el mapa de la pantalla no entran otros dos números, tendrías que jugar un poco con los tamaños de los dígitos (achicarlos un poco para que entren dos números mas), tal vez redistribuirlos de otra forma, etc.. Todo lo que es escribir en pantalla se maneja las funciones comentadas al principio para escribir mediante text57, para hacer los rectangulos, etc... La realidad es que posiblemente te cambien todas las funciones del GLCD para que te logren entrar los 3 valores en la misma pantalla y eso.
BorrarTe recomendaría que primero juegues un poco con las funciones de rectángulo, texto, etc y lo simules en el Proteus para familiarizarte con estas funciones y luego ya vas a darte cuenta de esto de como mostrar los valores y como ordenarlos en pantalla a tu propio gusto.
Saludos!
si lo pude armar, gracias , ahora cuando tomo la medición los números se van poniendo como una mancha negra en el proteus, tendría que probarlo en la realidad para ver si se ven bien o me hace lo mismo, que puede ser?
ResponderBorraraparte felicitarte muy buena pagina¡¡
Es raro que en el proteus se vea como una mancha negra, no te quedo ningún número superpuesto? proba comentando cada bloque (bloque ejemplo de 24 a 32), de esa forma si tenes los tres bloques de las tres mediciones, podes comentar 2 de ellos y ver el que queda como se ve en la pantalla sin que se te pisen los números y demás. lo podes ir probando asi para los tres, una vez que tenes eso ahí des-comentas todo y lo corroboras, pero es raro que te haga esa mancha.
BorrarA veces pasa que en la realidad funciona diferente pero no se si sea el caso, antes de que compres el GLCD proba ir comentando el código para que veas si te anda bien de a un numero por vez.
Bueno Gracias!!
Cualquier cosa avísame!
Saludos.
te consulto porque la línea 38 es la misma que la 41 con la difencia del on of ?
ResponderBorrarEs la misma linea pero en una enciende y en la otra apaga, eso lo hace a modo "refresco" de pantalla para que la variación numérica, sin ese refresco (si dejaríamos siempre habilitado el valor) se pisaría el valor actual con el próximo que lee el ADC. De esta forma se genera el refresco de pantalla en el sector del numero solamente y no en el resto, asi no se ve el parpadeo.
BorrarSaludos!
si cuando muevo el "pote" me muestra los valores pixelados y cada ves que vas moviendo se pone como una mancha negra te subo el código si queres para verlo
ResponderBorrarClaro, eso debe ser porque se están pisando, porque no se esta borrando el display en cada cambio de dígito para que no se distorsione. Si queres pasame el código asi lo pruebo acá.
BorrarSaludos!
ResponderBorrar#include <18f4550.h>
#device adc=10
#fuses HS,NOWDT,NOPROTECT,NOLVP
#use delay(clock=20000000)
#include
#include
#use fast_io(b)
#use fast_io(c)
char cps[]="CPS";
char volt[]="V";
char amper[]="A";
char voltaje[9];
char minuto[9];
char corriente[9];
int16 voltajeADC, voltajeADC_ant,
cpsADC,cpsADC_ant,
corrienteADC, corrienteADC_ant;
void main(){
setup_adc_ports(AN0_to_an2|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_32);
glcd_init(ON);
glcd_line(0, 25, 125, 25, on);
while(true){
set_adc_channel(0);
delay_us(62);
voltajeADC=read_adc();
if(voltajeADC_ant != voltajeADC){
glcd_text57(5, 3, voltaje, 1, OFF);
sprintf(voltaje, "%1.1f", (float)voltajeADC*5/1023.0);
voltaje[4] = '\0';
glcd_text57(5, 3, voltaje, 2, ON);
voltajeADC_ant=voltajeADC;
glcd_text57(45,12,volt,1,on);
}
set_adc_channel(1);
delay_us(62);
corrienteADC=read_adc();
if(corrienteADC_ant != corrienteADC){
glcd_text57(65, 3, corriente, 1, OFF);
sprintf(corriente, "%1.1f", (float)corrienteADC*5/1023.0);
corriente[4] = '\0';
glcd_text57(65, 3, corriente, 2, ON);
corrienteADC_ant=corrienteADC;
glcd_text57(105,12,amper,1,on);
}
set_adc_channel(2);
delay_us(62);
cpsADC=read_adc();
if(cpsADC_ant != cpsADC){
glcd_text57(5, 3, minuto, 1, OFF);
sprintf(minuto, "%02.2f", (float)cpsADC*5/1023.0);
minuto[4] = '\0';
glcd_text57(30, 40, minuto, 3, ON);
cpsADC_ant=cpsADC;
glcd_text57(105,55,cps,1,on);
}
}
}
en la ultima medición estoy tratando de medir frecuencia tengo que cambiar los decimales por la medición de 3 cifras sin coma
ResponderBorrarOk, en un rato cuando llego a casa lo miro y te aviso por este medio que resultados me dio!
BorrarSaludos!
Dale gracias
ResponderBorrarDale gracias
ResponderBorrarHola, ya lo tengo andando, proba este código. http://pastebin.com/JvWnMiej
BorrarSaludos!
Si lo voy a probar estube modificando y logre que ande y le agregue una imagen voy mejorando, gracias saludos
ResponderBorrarPor nada!, ahí en el código que te pase ya estaría andando al menos lo de que se superponían los dígitos y el mapeo.
BorrarSaludos!
como estas no te quiero molestar, pero te consulto tengo un parpadeo que no puedo sacar como hago para que queden bien quietos los números, se me desvanecen de un lado al otro siempre es raro, saludos
ResponderBorrarHola, el parpadeo supongo que se debe al refresco de pantalla, ya que para lograr de que no se vea ese cumulo de números en el mismo dígito hay que habilitar, mostrar, deshabilitar y consultar si el numero cambio para ver si hay que actualizarlo o no, en ese ciclo hay un pequeño parpadeo, te recomendaría bajar el delay de ese proceso, o bien corregir la histeresis para que el numero no cambie tanto (de esa forma no actualice tan seguido), para ello podrías demorar el muestreo o bien sacar promedio.
BorrarSaludos.
Si pensaba en sacar promedios con un bucle for y después mostrar el resultado
ResponderBorrarVoy a ver como lo hago, saludos
Si, es la forma mas fácil, podes tomar valores, alojarlos en un vector y después sumar cada valor del vector y dividirlo por el indice máximo., va hay muchas formas de hacerlo.
BorrarSaludos.
Lo hago y te cuento como me va, gracias saludos
ResponderBorrarEste comentario ha sido eliminado por el autor.
ResponderBorrarset_adc_channel(2);
ResponderBorrardelay_us(20);
cpsadc=0;
for(var1=0;var1<500;var1++)
{
cpsadc=cpsadc+ read_adc();
delay_us(62);
}
glcd_text57(30, 40, minuto, 3, ON);
cpsadc = cpsadc * 50 / 1023;
sprintf(minuto, "%1.1f", (float)cpsADC);
minuto[5] = '\0';
que me falta para lograr el promedio y mostrarlo en el glcd
Esta bien, haces un acumulador sumando el actual mas el anterior con la linea cpsadc=cpsadc+read_adc(); por 500 veces, y luego lo ideal seria tomar ese valor y dividirlo en 500 para que se complete el promedio, por ahí 500 son muchos valores, pensa que los números crecen y podría darte un overflow según el tipo de variable.
BorrarMe esta volviendo loco y no logro hacerlo andar
ResponderBorrarMe esta volviendo loco y no logro hacerlo andar
ResponderBorrar
ResponderBorrarint16 cpsADC,cpsADC_ant;
int var1;
setup_adc_ports(san0|san1|san2|VSS_VDD);
setup_adc(ADC_CLOCK_DIV_2);
char minuto[9];
glcd_init(ON);
while(true)
{
set_adc_channel(2);
delay_us(20);
cpsadc=0;
for(var1=0;var1<500;var1++)
{
cpsadc=cpsadc+ read_adc();
delay_us(62);
}
cpsADC_ant=cpsadc/500;
glcd_text57(30, 40, minuto, 3, ON);
sprintf(minuto, "%1.1f", (float)cpsADC_ant* 50 / 1023);
minuto[5] = '\0';
}
}
sabes que no me funciona con el for
Me pone que la condición no es verdadera y me marca la línea del for
ResponderBorrarMe pone que la condición no es verdadera y me marca la línea del for
ResponderBorrarQue raro, que no te compile un for, tal vez tengas un overflow, podes probar con un while y las variables de control dentro del mismo.
BorrarComo seria me podes dar un ejemplo
ResponderBorrarMe pone una advertencia y no muestra nada en pantalla
BorrarComo seria me podes dar un ejemplo
ResponderBorrarEn el For le das la configuracion con i=0, i<500 y i++, en el while no podes poner todas esas condiciones, pero si podes hacer que sea verdadero o no. Por ejemplo, para que el while se cumpla tiene que ser verdadero, ahi podes poner que i menor a 500, quedando while(i<500){ }, de esta forma el while se cumple siempre que i<500 sea verdadero. Para que i se incremente en uno cada vez que se repite el ciclo tenes que poner dentro del while un i++; y i=0 tenes que ponerlo fuera del mismo.
Borrari=0;
while(i<500){
codigo
codigo
codigo
...
i++;
}
Puedo colocar varios while uno por cada medición?
ResponderBorrarSi claro, el while es solo un bucle condicional como el For que ejecuta el código en su interior si la condición es verdadera. Al manejar menos parámetros que el for tenes que poner el incremento y eso adentro, pero el uso es el mismo.
BorrarPuedo colocar varios while uno por cada medición?
ResponderBorrarlo hice funcionar mejor estaba usando un cristal de 4mhz lo cambie y funciono mucho mejor ahora los números se mueven muy rápido le tengo que poner un capacitor de 10uf para que quede un poco estable estará mucho ruido , creo que igual voy a tener que hacer promedios para que quede mas estable la medición, con if no puedo promediar?
ResponderBorrarvoy a probar con el while
Claro, me olvide de ese detalle, yo en el código del post lo tengo con 20MHz, creo que ese era un tema también por eso lo use asi.
BorrarEl capacitor en la entrada es clave para que no fluctué tanto.
Podes hacer ese promedio, o podes poner un delay, para que tome muestras mas lentas.
El promedio podes hacerlo con muchas funciones diferentes, la lógica que necesites depende de como pienses tu promedio, pero si podes proba primero dándole un delay entre cada medición del ADC para que actualice mas lento.
Saludos.!
Si pude hacer andar el for pero no funciona bien tengo que ver como implementar el for y que haga efecto en el código, no se si ponerlo después de if o antes y después que el if haga la comparación de la variable.
ResponderBorrarPosteame el código asi puedo verlo mejor, asi te puedo ayudar mas fácil.
BorrarSaludos.
while(true){
ResponderBorrarset_adc_channel(0);
delay_us(20);
volt1=0;
if(volt1 != voltajeADC){
for(var1=0;var1<5;var1++)
{
volt1 = volt1+read_adc();
delay_us(62);
}
glcd_text57(5, 3, voltaje, 2, OFF);
voltajeadc=volt1/5;
voltajeadc=voltajeadc*50/1023;
sprintf(voltaje, "%4.1f", (float)voltajeADC);
voltaje[4] = '\0';
glcd_text57(5, 3, voltaje, 2, ON);
volt1=voltajeADC;
}
}
}
Lo que veo a simple vista es que esta algo desordenado el codigo, lo que yo haria es primero leer el ADC (set adc channel, y read adc(), lo alojas en una varibale, luego el delay de conversion de 20us).
BorrarUna vez que tenes el valor, recien ahi lo metes en un for de mas de 5 valores para que fluctue menos, una vez que sale del for, tomas esa variable y la dividis por la cantidad de ocurrencias que le pusiste al for.
y recien despues de eso aplicas el calculo para pasarlo a tension
y despues lo mostras en el GLCD.
Para que sea mas estructurado y sencillo.
Este comentario ha sido eliminado por el autor.
ResponderBorrarEste comentario ha sido eliminado por el autor.
ResponderBorrarLo probé y no funciona no cambia que tildado en 2 volt y baja a cero pero borroso, no se me ocurre como hacer que cambie dígito a dígito y de una forma más lenta, voy a ver si con el if puedo lograr algo, gracias saludos
ResponderBorrarEste comentario ha sido eliminado por el autor.
ResponderBorrarBueno logre que queden fijos los dígitos con capacitores pero ahora no logro promediar y cuando toma la lectura adc se mueve muy rápido alguna idea como hacer un promedio, gracias
ResponderBorrarEste comentario ha sido eliminado por el autor.
ResponderBorrarBuenas tardes, se que esta informacion es antigua, pero por si acaso tendra disponibles las librerias que usó?
ResponderBorrar