viernes, 1 de abril de 2011

Sensor de Fuerza con PIC, en CCS

Muy bien amigos y publico en General
142fc496eac1104b24ae30fdcb1cffa1.12746009667
Hace ya un rato realice un proyecto para una clase en mi universidad, crear un sensor de presion

aqui comparto mi diagrama, por si alguien necesita ayuda para elaborar uno.

LISTA DE MATERIALES:
* Amplificador Operacional LM741
* PIC16f877a (Con el mismo codigo sirve igual el PIC16f887)
*4 Resistencias de 1 Mega ohm
*1 Resistencia de 1 Kohm
*1 Potenciomentro de 5kohm
*2 capacitor de 22 pico Faradios
*Cristal de 4Mhz oscilador para el Pic
*1 Push Button
*1 Led
* 1 Resistencia de 330 ohm
* Pantalla LCD 16x2 (De la que tiene el driver Hitachi HD 44780 "que es ahora de las mas comunes"
*Galga de presion Flexiforce (http://www.tekscan.com/flexible-force-sensors)

->Si pueden alimentar al Opamp con una fuente de 8v en lugar de la de 5v da mejor resultado
->LA LCD y el PIC se alimentan con 5v, no alimentar con mas voltaje o las quemas

La galga, aqui en Monterrey Mexico yo la compre en: http://www.5hz-electronica.com/sensordepresinflexiforce-100lbs.aspx

El diagrama lo muestro a continuación:



Diagrama Esquemático de conexiones




Atencion, el diagrama el Potenciometro RV2 (5M) es la galga, sus tres terminales de la galga van conectadas como si fueran el potenciometro, debido a que proteus no posee la galga entre sus dispositivos tuve que colocarla asi.
La galga posee tres terminales (pines o patitas), la primera (lado izquierdo) va conectada a la entrada No Inversora del opamp y la 3ra (lado derecho) va directo al PIC, la terminal del centro no va conectada.

Diagrama en Proteus (.DSN):
DSN

CODIGO_CSS

Explicación:

*La galga cambia su resistencia al momento de aplicarle una fuerza, esta tiene una resistencia por arriba de 5Mega ohms cuando no hay fuerza aplicada, al momento de aplicar fuerza su resistencia disminuye.

*Por medio de un arreglo en el Opamp (LM741) a manera de Convertidor Voltaje Corriente, colocamos la Galga a manera de Resistencia de carga, gracias al arreglo del opamp, por ella va a cirular una corriente continua asi que al vairar su resistencia, variara directamente proporcional el voltaje en la misma

*El voltaje en la galga se lleva al convertidor analogico/digital del pic y voila, obtienes una variacion de voltaje traducida en bits.

*Solo falta calibrar el peso en la galga de tal manera que al colocar una fuerza nos de la medida en Kf

El codigo del PIC lo coloco a continuacion: 


#include "16f877.h"                    // Pic a utilizar
#device adc=10                         // Usa resolución de 10 bits
#use delay(clock=4000000)       // Cristal a utilizar
#fuses xt,nowdt,noput,nobrownout,nolvp,noprotect   // Fusibles
#include "lcd.c"              // Libreria para utilizar LCD por el puerto D
#use standard_io (D)
#include <math.h>
#include <string.h>

void mostrar_en_lcd(float peso);//prototipo de metodo para mostrar en la lcd el peso actual
int checa_numero_o_punto(char caracter);
float obtiene_lectura();
float valor_absoluto(float num);
float calcula_peso(float bits);


//**********************--------------COMIENZA EL MAIN
void main() {
int i=0;
float numdec1=0;
float numdec2=0;

lcd_init();


lcd_putc("\f");
lcd_putc("Comenzando...\n");
delay_ms(500);

numdec1=obtiene_lectura();
//*******************************-*-*-*-*BUCLE INFINITO
while (TRUE) {
delay_ms(10);//esperamos un cuarto de segundo
numdec2=obtiene_lectura();
delay_ms(10);
if(valor_absoluto((numdec2-numdec1))>5)
{
numdec1=numdec2;
mostrar_en_lcd(calcula_peso(numdec1));
}
}

//*******************************/*/**/*/TERMINA BUCLE INFINITO
}
//**********************--------------TERMINA EL MAIN


///********************************************************************************************
//COMIENZAN LOS METODOS PRIVADOS

float calcula_peso(float bits)
{
float peso_real=0;
return peso_real=-0.013135593*bits+11.76949153;
}

float valor_absoluto(float num)
{
//calculamos valor absoluto
if (num<0)
{
//rango=rango*(-1);
num*=(-1);   
}

return num;
}

//Metodo que muestra en la lcd el peso actual registrado
void mostrar_en_lcd(float peso)
{
int i=0;
int mayor=9;
int verifica=0;
char pesochar[9];//array que contendra el string del peso
//inicializamos el array
for(i=0;i<=(mayor-1);i++)
{
pesochar[i]=0;
}

//sprintf redondea todo a 3 decimales
//sprintf(array char para a guardar,"string de estructura y tipo",variable a convertir)
sprintf(pesochar,"%5.4f",peso);//convertimos a char

//checamos que todos los caracteres sean numeros o punto
//si no lo son, metemos un "0"
for(i=0;i<=(mayor-1);i++)
{
verifica=checa_numero_o_punto(pesochar[i]);//verificamos si es un numero o punto
if(verifica==0)
{
pesochar[i]='0';//si no es numero o punto entonces metemos un "0"
}
}

//borramos la pantalla
lcd_putc("\f");

//mostramos el letrero de "El peso es:" y damos un salto de linea
lcd_putc("La Fuerza es:\n");

//mostramos en la lcd el peso
for(i=0;i<=(mayor-1);i++)
{
lcd_putc(pesochar[i]);
}

//agregamos la palabra kilos al final
lcd_putc(" Kgf");

}

//Metodo que checa si el caracter char pasado como parametro
//es un numero u un punto, si no lo es regresa un cero
//si lo es, regresa un uno
int checa_numero_o_punto(char caracter)
{
int verificador=0;
switch(caracter)
{
case '0':
{
verificador=1;
}
break;

case '1':
{
verificador=1;
}
break;

case '2':
{
verificador=1;
}
break;

case '3':
{
verificador=1;
}
break;

case '4':
{
verificador=1;
}
break;

case '5':
{
verificador=1;
}
break;
case '6':
{
verificador=1;
}
break;

case '7':
{
verificador=1;
}
break;

case '8':
{
verificador=1;
}
break;

case '9':
{
verificador=1;
}
break;

case '.':
{
verificador=1;
}
break;

default:
verificador=0;
break;
}
return verificador;
}


//metodo usado para obtener el numero binario directo del convertidor A/D
//en el puerto B
//considerando el bit de mayor peso en el pin RB7 y el de menor peso en el pin RB0
//metodo usado para obtener el numero binario directo del convertidor A/D
//en el puerto B
//considerando el bit de mayor peso en el pin RB7 y el de menor peso en el pin RB0
float obtiene_lectura()
{
float medicion=0;                     //variable entera que contendra la medicion del convertidor AD

delay_ms(10);
setup_adc (adc_clock_internal);
setup_adc_ports (all_analog);
set_adc_channel (0);                // Elige canal a medir RA0
delay_ms(10);
medicion=read_adc ();              // Hace conversión AD 
setup_adc (adc_off);                //detenemos al convertidor
delay_ms(10);

return medicion;
}





Sigo en construccion del POST, despues coloco como se calibra el sensor por si los valores de mi calibracion no coinciden con los tuyos, que suele pasar mucho debido a la fuente de voltaje que uses. CHIDO

6 comentarios:

  1. Grande! terminalo porfa!

    El programa esta en C?

    ResponderEliminar
  2. Esta en Pic C de CCS, deja me doy un tiempo para actualizar todo

    ResponderEliminar
  3. Hola, Excelente trabajo!
    Tienes la parte de la calibración del sensor?

    ResponderEliminar
    Respuestas
    1. Eit, que onda Anónimo.

      Lo siento, este proyecto quedó hasta allí pero te puedo dar una explicación sencilla:

      la calibración se realiza modificando la variable peso_real en la función calcula_peso(float bits).

      Si observas "peso_real=-0.013135593*bits+11.76949153;" se esta usando una relación de línea recta que no pasa por cero (si graficas esa función te dara una linea recta que no pasará por cero, ya que estamos suponiendo que para cierto intervalo de valores la galga es lineal).

      Y = aX + B
      donde:
      Y es el peso real (lo que deseas obtener)
      a es la pendiente de la recta
      B es la ordenada del origen
      X es el valor del ADC leído

      Puedes encontrar tus propios valores para tus necesidades encontrando a y B.

      1.- Encuentra un objeto el cual sepas su peso exacto (obtendras "P1")

      2.- Pesalo con el circuito arriba mencionado y observa cuantos bits te da el ADC, obviamente tendrás que modificar algo el codigo para que puedas ver los bits del ADC (obtendras "bits1").

      Quizá te dirva de algo esto: http://hzsquare.blogspot.fr/2011/10/convertidor-ad-con-pic16f887-y-lcd-jhd.html

      3.- Repite los pasos 1 y 2 con un segundo objeto (obtendras "P2" y "bits2")

      a = (P2 - P1) / (bits2 - bits1) <--- pendiente de la recta
      B = P2 - (a)(bits2) ó
      B = P1 - (a)(bits1)

      Lo bueno es que es una explicación sencilla, si no, imaginate!!!

      Saludos y Suerte

      Eliminar
    2. Muchas gracias por tu respuesta, me quedo claro lo de la calibración, pero tengo otra duda...
      En el esquemático conectas la salida del operacional a RA0 y el pin3 de la galga a RA1... Cuando realizas la conversión A/D, lo haces del pin RA0.... con RA1 no haces nada... es como si lo conectaras a tierra? o cual es la finalidad de esa conexión?
      Por otro lado, no manejo CCS... me gustaría realizar el programa en lenguaje basic, pero veo que realizas varias acciones como esta :

      if(valor_absoluto((numdec2-numdec1))>5)
      {
      numdec1=numdec2;
      mostrar_en_lcd(calcula_peso(numdec1));


      Pero no logro comprender por que o para que...

      Otra forma mas sencilla de hacerlo seria realizar la conversión A/D, realizar el ajuste de la calibración y listo? Es posible? Se obtendría el mismo resultado?

      Muchas gracias por tu aporte!

      Eliminar
    3. Podrías responder al anterior comentario.
      Gracias

      Eliminar