TODOPIC
Microcontroladores PIC => Todo en microcontroladores PIC => Mensaje iniciado por: juancho056 en 05 de Abril de 2015, 23:59:55
-
Hola!
Estoy realizando un programa en el cual uso la funcion make8 o bien corrimientos y una and para sacar la parte alta y baja de un dato capturado por el adc de 10 bit que poseen los microcontroladores, esta parte alta y la baja del dato las envio en 2 registro en al memoria eeprom a VB6, y hasta y todo de maravilla.
El problema es que no entiendo como volver a unir la parte alta y baja del dato para saber el valor del voltaje capturado, el voltaje que estoy capturando con el adc es de 0-5V, si alguien tiene conocimientos respecto al tema o sabe como volvera unir ambos datos con una formula estare muy agradecido.
Feliz dia! :)
-
int datoCompleto
datoCompleto = (ParteAlta << 8) + ParteBaja;
algo así?
sds.
-
También sirve con matemáticas tradicionales:
datoCompleto = ParteAlta *256 + ParteBaja;
-
datoCompleto = (ParteAlta << Cool + ParteBaja;
.
Estas desplazando la parte alta, un numero equivalente a un emoticono con gafas xd, haha ;-)
-
Hola gracias por sus respuestas ((:-)), pero el caso es el siguiente:
La simulacion la estoy haciendo en proteus, al medir el valor suministrado al adc es 3.40 v, el programa al cual me llegan ls datos como entreos se visualiza este valor como parte alta 2 y parte baja 184 entonces
(2*256)+184=696
Todo esto dividido por 2 me esta dando 348 que es un valor con una tolerancia aceptable.
El problema ya vi que radica en que cuando los voltajes disminuyen por debajo de 1v la parte alta toma el valor de 0 y la parte baja siempre toma un valor de 138 sin importar cual sea el voltaje 0.85, o 0.25v los 2 registros simepre son los mismos. Es posible que este valor se de por la manera en que estoy imprimiendo el mensaje desde CCS %U, o cual puede ser el motivo?
Gracias por responder :mrgreen:
-
El problema ya vi que radica en que cuando los voltajes disminuyen por debajo de 1v la parte alta toma el valor de 0 y la parte baja siempre toma un valor de 138 sin importar cual sea el voltaje 0.85, o 0.25v los 2 registros simepre son los mismos. Es posible que este valor se de por la manera en que estoy imprimiendo el mensaje desde CCS %U, o cual puede ser el motivo?
Si parece que tu problema es esem es que se esta enviando mal. Deberias enviar el hexadecimal a la PC o aunque sea en 2 partes.
Si usas una referencia de 5V deberia variar la lectura de 0 a 5V significa que el AD varia desde 0 a 1023 (0x000 a 0x3FF ). Para obtener el valor que da el AD en voltios es simplemente:
Voltios = (AD * 5) / 1023
Si seguimos con la misma referencia de tension 5V. cada bit del ADC reprentaria 5 /1023 aproximadamente 4.88mV
Todo esto dividido por 2 me esta dando 348 que es un valor con una tolerancia aceptable.
Por que dividirlo por 2 ? no entiendo cual es tu objetivo ahi.
-
Hola KILLERJC, gracias por responder.
Al estar enviando los datos de forma entera desde CCS el planteamineto era el siguiente (Parte alta*256)+parte baja que al ser dividido por 2 me da un valor bastante aproximado al valor dc medido sin el punto flotante por estar trabajando en entero:
Valor DC medido: 3.40V
valor parte alta enviando los datos como entero:2 y parte baja:184
Utilizando la formula (2*256)+184=696 donde 696/2=348 me da un valor aproximado sin el punto, que con funciones de VB6 pensaba acomodar para que graficara 3.48v
(trabajo inecesario 8)), valores similares se aprecian con diferentes voltajes.
Cuando envio los datos en hexadecimal desde ccs osea %x, 5v es parte alta 3 y parte baja FF como explicas, pero sigue ocurriendo lo mismo para valores inferiores a 1.25v los registros siempre toman el mismo valor para este caso 00 parte alta y 8a parte baja, no varian.
La idea de tomar todos estos valores es graficar el comportamiento de unos sensores, como los registros toman el mismo valor siempre que bajen de 1.25 v, el comportamiento de la grafica seria el mismo para 1v, 0.85v o 0.25v. Mientras el voltaje sea menor de 1.25v no podre saber cual fue le voltaje minimo que registro el sensor :(
Gracias por responder lo aprecio bastante :mrgreen:
-
No te fíes de Proteus trabajando con analógica, pruébalo en real.
-
La idea de tomar todos estos valores es graficar el comportamiento de unos sensores, como los registros toman el mismo valor siempre que bajen de 1.25 v, el comportamiento de la grafica seria el mismo para 1v, 0.85v o 0.25v. Mientras el voltaje sea menor de 1.25v no podre saber cual fue le voltaje minimo que registro el sensor :(
Entiendo perfectamente. el AD como dije da un numero de 0 a 1023 asi que siempre trabajas con enteros, luego si lo convertis a flotante para saber el voltaje.
Tu problema pasaria a otro. me parece raro que el ADC no este dandote los valores como corresponde. O el mismo printf te lo esta convirtiendo en un mal valor o hay un problema de simulacion si lo estas haciendo por simulacion. Ya que deberia variar, sino puede haber algo raro en el programa ( pero esto no lo creo por que te da el maximo como 0x3FF ).
Al estar enviando los datos de forma entera desde CCS el planteamineto era el siguiente (Parte alta*256)+parte baja que al ser dividido por 2 me da un valor bastante aproximado al valor dc medido sin el punto flotante por estar trabajando en entero:
Si da un aproximado pero es un error mas cuando queres graficar lo de un sensor y a la PC no le cuesta nada hacer una multiplicacion y division para dar con el resultado en coma flotante.
-
El problema ya vi que radica en que cuando los voltajes disminuyen por debajo de 1v la parte alta toma el valor de 0 y la parte baja siempre toma un valor de 138 sin importar cual sea el voltaje 0.85, o 0.25v los 2 registros simepre son los mismos. Es posible que este valor se de por la manera en que estoy imprimiendo el mensaje desde CCS %U, o cual puede ser el motivo?
Coloca el codigo del pic que estas programando en ccs, para ver como tienes configurado el printf.
Ya que, tal como lo indicas arriba no es posible que te esten dando esos valores :?
Si lo muestras por la lcd o por RS232, la parte baja del resultado, deberia estar disminuyendo a medidas que reduces el voltaje.
-
Si tu compilador tiene la opción de manipular los bits individuales que forman cada byte o word, tienes la vida hecha. En PSI sería así:
Resultado_ADC.LB = Parte_baja
Resultado_ADC.HB = Parte_alta
En PSI el .LB significa el byte menos significativo de un Word (2 bytes) y HB el byte más significativo. Simplemente escribes el valor de cada byte en un solo word y tienes tu resultado ADC.
-
#include <18f252.h>
#device adc= 10
#fuses XT,NOWDT,PUT,NOBROWNOUT,NOWRTB,NOWRTD
#use delay (crystal= 4000000)
#use RS232(baud=9600,xmit= pin_b0,rcv=pin_b1)
void main()
{
long res_adc;
int h_adc, l_adc;
setup_adc_ports(an0);
setup_adc(adc_clock_internal);
set_adc_channel(0);
while(true)
{
res_adc= read_adc();
h_adc= make8(res_adc,1);
l_adc= make8(res_adc,0);
printf("El valor del adc= %lu\r",res_adc);
printf("Parte alta del adc= %u\r",h_adc);
printf("Parte baja del adc= %u\r",l_adc);
delay_ms(1500);
}
}
El codigo adjunto lo probe y funciona a la perfeccion con el ccs :mrgreen:
Pruebalo y nos das tus impresiones. ;-)
-
Hola a todos Gracias por responder, pero el problema persiste, lo explicare paso a paso.
Inicialmente realice todo el montaje para descartar que fuese problemas de simulacion en proteus como indicaba Nocturno, pero proteus y el monatje me funcionan exactamente igual. Actualemente estoy trabajando con el pic16f1936 que es la gama avanzada del pic16f886 que ya no sale, osea tiene muchas mas funciones, mas memoria, pero en sintesis es lo mismo obviamente mucho mas caro.
El problema es que los datos que estoy tomando del adc al ser de 10 bits los tengo que enviar en 2 registros con lo cual uso la funcion make8(dato,1) parte alta y make8(dato,0) parte baja o lo que es lo mismo (dato>>8) y (dato&255), de igual manera lo estoy haciendo para un encoder que me estara contando lo metros (3500) se hace lo mismo divido el dato en la parte alta y baja para guardarlo en 2 registros de la eeprom y poder contar hasta 65535, hasta ahi todo muy bien.
Los datos los estoy guardando en diercciones de la memoria eeprom, una vez se active una bandera asi :
if(flagcommand) {
commad_process(); // Hay algo pendiente de procesar y lo procesa.
write_eeprom(0,voltL1);
delay_us(150); // minimo de tiempo que se debe esperar para guardar el dato en al eeprom
write_eeprom(3,voltH1);
delay_us(150);
write_eeprom(6,voltL2);
delay_us(300);
write_eeprom(9,voltH2);
delay_us(300);
write_eeprom(12,metrosH);
delay_us(200);
write_eeprom(15,metrosL);
delay_us(200);
}
Todo funciona perfecto al recibir y enviar la trama, los datos toman la posicion que requiero, los estoy enviando en entero que la respresentacion ps no tiene mucha importancia en entero 5 v es (3-255) en hexa (3-ff) parte alta y parte baja.
Luego de explicar todo y que todo funciona bien el error es!
en la trama no se visualizan los valores por debajo de 1.25v para el adc captado siempre me muestra parte alta (0) y parte baja (138), para ponerlo mas claro en el contador de metros que empieza en 0 hasta 3500 cuando empieza se visualiza (0) parte alta y (137) parte baja.
Para visualizar que este contando bien estoy imprimendo los metros despues de que envio la trama asi:
printf("%x-%x-%x-%U-%U-%U-%U-%U-%U-%x-%x\r\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]cmd[8],cmd[9],cmd[10]); // ... y lo muestro
printf("%lU Metros: \r\n",metros);
Como se observa envio una trama los %U son los dos sensores y el encoder para los metros en sus partes altas y bajas
En la trama tomando las dos ultimas (%U-%U) es la respresentacion del encoder, mientras la variable metros que la imprimo abajo no llega hasta 255 se ve asi (0)-(137) parte alta y baja en la trama
lo cual me daria mal para tomar el metraja inicial osea
(0*256)+137=137 ese seria el valor siempre desd 1 hasta que supere 255 una vez los lo supera la trama se visualiza asi
(1)-(0) para los registros del encoder, por lo que se puede calcular el metraje
1*256+0=256
(1)-(3)
1*256+3=259
Mientras no se supere el valor de 255 los registros del encoder se veran (0)-(137), lo mismo sucede para el adc que los estoy haciendo para varoles de 0 a 5v, cuando esta por debajo de 1.25 v el valor del registro siempre es (0)-(138), minetras el valor sea >=1.25v todo funciona a la mil maravillas en el adc y mientras el valor sea mayor a 255 funcioan perfecto para llevar el calculo de los metros.
Espero haber expresado bien la idea y que me puedan ayudar, yo vengo rebentando cabeza y no entiendo por uqe se da eso.
Gracias por sus aportes :mrgreen:
-
Pega la parte del código de inicialización y lectura del ADC, por favor.
-
Claro Nocturno, gracias,
va asi:
void main() //Principal
{
//setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
ext_int_edge(H_TO_L); // para contar pulsos de encoder
setup_adc_ports(sAN0);
setup_adc_ports(sAN1);
setup_adc(adc_clock_internal);
delay_ms(100);
init_cbuff(); // Borra buffer al inicio
enable_interrupts(int_ext);
enable_interrupts(int_rda); // Habilita Interrupción RDA
enable_interrupts(global); // Habilita interrupciones
do {
set_adc_channel(0);
delay_us(20);
adc1=read_adc();
voltL1=adc1>>8;
voltH1=adc1&255;
voltaje1=(5.0*adc1)/1024.0;
set_adc_channel(1);
delay_us(20);
adc2=read_adc();
voltL2=adc2>>8;
voltH2=adc2&255;
voltaje2=(5.0*adc2)/1024.0;
if(flagcommand) {
commad_process(); // Hay algo pendiente de procesar y lo procesa.
write_eeprom(0,voltL1);
delay_us(150);
write_eeprom(3,voltH1);
delay_us(150);
write_eeprom(6,voltL2);
delay_us(300);
write_eeprom(9,voltH2);
delay_us(300);
write_eeprom(12,metrosH);
delay_us(200);
write_eeprom(15,metrosL);
delay_us(200);
}
} while (TRUE);
}
-
Esto no es referido a sobre enviar el dato
Yo lo unico que tengo para decir, es pobre EEPROM todas las veces que la estas grabando... podrias dejarlo en las variables voltL1,voltH1,voltL2 y voltH2 y los metros tambien,
Acordate que tenes limitada cantidad de veces para escribirla.
-
Esto no es referido a sobre enviar el dato
Yo lo unico que tengo para decir, es pobre EEPROM todas las veces que la estas grabando... podrias dejarlo en las variables voltL1,voltH1,voltL2 y voltH2 y los metros tambien,
Acordate que tenes limitada cantidad de veces para escribirla.
Es una red modbus se se requieren registros no variables, por ende uso la eeprom :mrgreen:
-
Es una red modbus se se requieren registros no variables, por ende uso la eeprom :mrgreen:
las variables SON registros :)
A nivel hardware son registros, la unica diferencia es que cuando se corta la luz lo perdes (RAM), es la unica diferencia con EEPROM que tendrias.
-
:oops: :oops: :oops:
jajaja tienes toda la razon KILLERJC, la verdad es que el sistema va funcionar continuamente, En el datasheet dice que vienen garantizados 100 000 ciclos de escritura/borrado por lo cual si es mejor solo usar las variables para no tener problemas proximamente, lo bueno de la eeprom es que puedo apuntar directamente a la direccion de memoria con read_eeprom(), mientras que si utilizo variables no sabria especificar en la trama por que direccion de registro preguntar.
Se que la eeprom por defecto tiene inicializado el valor xff o en entero 255 por eso puede estar fallando, voy a investigar como direccionar el registro que ocupan las variables y hare pruebas.
Si alguien sabe y me puede echar una mano no estaria de mas.
KILLERJC y a todos agradece mucho sus comentarios ((:-))
-
int variable;
int *direccion;
Esto: &variable te da la direccion de "variable", suponete que lo guardas en un puntero llamado direccion
direccion = &variable
(ahora "direccion" tiene la direccion del registro donde se almacena "variable")
si haces *direccion es lo mismo que leer "variable", ya que estarias apuntando a lo contenido en esa direccion
o sea "variable" es equivalente a "*direccion"
Seria util/mas facil si proveyeras el codigo donde envias los datos para el MODBUS, imagino que es una funcion.
-
KILLERJC, muchas gracias ((:-)) un algun dia sere como tu :mrgreen:
La verdad no sabia manejar apuntadores con tu explicacion me quedo mas que claro y funciona exactamente igual, con el agregado que ya no gasta la memoria eeprom.
La funcion donde la imprimo es este prinf que me envia todos los datos de un vector de 11 posiciones separados por "-" como lo explique anteriormente, sigue pasando exactamente lo mismo, y en la cita ya modifique la forma de llamar los registros gracias a ti.
Hola a todos Gracias por responder, pero el problema persiste, lo explicare paso a paso.
Inicialmente realice todo el montaje para descartar que fuese problemas de simulacion en proteus como indicaba Nocturno, pero proteus y el monatje me funcionan exactamente igual. Actualemente estoy trabajando con el pic16f1936 que es la gama avanzada del pic16f886 que ya no sale, osea tiene muchas mas funciones, mas memoria, pero en sintesis es lo mismo obviamente mucho mas caro.
El problema es que los datos que estoy tomando del adc al ser de 10 bits los tengo que enviar en 2 registros con lo cual uso la funcion make8(dato,1) parte alta y make8(dato,0) parte baja o lo que es lo mismo (dato>>8) y (dato&255), de igual manera lo estoy haciendo para un encoder que me estara contando lo metros (3500) se hace lo mismo divido el dato en la parte alta y baja para guardarlo en 2 registros y poder contar hasta 65535, hasta ahi todo muy bien.
Los datos los estoy guardando en diercciones de la memoria flash con apuntadores que me llevan la direccion del registro y toman el valor almacenado, una vez se active una bandera asi :
if(flagcommand) {
commad_process(); // Hay algo pendiente de procesar y lo procesa.
dir1=&voltL1;
dir2=&voltH1;
dir3=&voltL2;
dir4=&voltH2;
dir5=&metrosH;
dir6=&metrosL;
}
Todo funciona perfecto al recibir y enviar la trama, los datos toman la posicion que requiero, los estoy enviando en entero que la respresentacion ps no tiene mucha importancia en entero 5 v es (3-255) en hexa (3-ff) parte alta y parte baja.
Luego de explicar todo y que todo funciona bien el error es!
en la trama no se visualizan los valores por debajo de 1.25v para el adc captado siempre me muestra parte alta (0) y parte baja (138), para ponerlo mas claro en el contador de metros que empieza en 0 hasta 3500 cuando empieza se visualiza (0) parte alta y (137) parte baja.
Para visualizar que este contando bien estoy imprimendo los metros despues de que envio la trama asi:
printf("%x-%x-%x-%U-%U-%U-%U-%U-%U-%x-%x\r\n",cmd[0],cmd[1],cmd[2],cmd[3],cmd[4],cmd[5],cmd[6],cmd[7]cmd[8],cmd[9],cmd[10]); // ... y lo muestro
printf("%lU Metros: \r\n",metros);
Como se observa envio una trama los %U son los dos sensores y el encoder para los metros en sus partes altas y bajas
En la trama tomando las dos ultimas (%U-%U) es la respresentacion del encoder, mientras la variable metros que la imprimo abajo no llega hasta 255 se ve asi (0)-(137) parte alta y baja en la trama
lo cual me daria mal para tomar el metraja inicial osea
(0*256)+137=137 ese seria el valor siempre desd 1 hasta que supere 255 una vez los lo supera la trama se visualiza asi
(1)-(0) para los registros del encoder, por lo que se puede calcular el metraje
1*256+0=256
(1)-(3)
1*256+3=259
Mientras no se supere el valor de 255 los registros del encoder se veran (0)-(137), lo mismo sucede para el adc que los estoy haciendo para varoles de 0 a 5v, cuando esta por debajo de 1.25 v el valor del registro siempre es (0)-(138), minetras el valor sea >=1.25v todo funciona a la mil maravillas en el adc y mientras el valor sea mayor a 255 funcioan perfecto para llevar el calculo de los metros.
Espero haber expresado bien la idea y que me puedan ayudar, yo vengo rebentando cabeza y no entiendo por que se da esto.
Gracias por sus aportes :mrgreen:
-
KILLERJC, muchas gracias ((:-)) un algun dia sere como tu :mrgreen:
Vas a ir mal si es asi.
Siguiendo con el tema
El problema persiste. Estaria bueno si pudieras hacer un programita simple que use el ADC y fijarte si funciona como corresponde.
Si funciona correctamente entonces puede que sea tu programa., si funciona mal, entonces existe algo mal en el circuito o el PIC.
-
Ya lo logre solucionar, realice el programa de manera que solo contara los metros y lo puse a imprmir en hyperterminal, y funcionaba bien. Examienando el codigo estoy utilizando una funcion en ccs, antes de imprimir la trama donde almacenaba los registros
strcpy(cmd,modbus.trama); // Lo copio para procesarlo
Basicamente copiaba modbus.trama que es la trama recibida del maestro modbus en otra de igual tamaño llamada cmd, pensando que asi evitaba que se solaparan los datos y salvaguardaba la trama.
Y al parecer como la funcion es para guardar una cadena de strig y los datos los guardaba en enteros, se presentaban los conflictos.
KILLERJC, eres grande!!, me ayudaron mucho tus aportes ((:-)) :mrgreen:
-
Felicidades