Upload
julfo05
View
126
Download
4
Embed Size (px)
http://robotypic.blogspot.com/2012/12/sensor-srf08-con-pic.html
Control de velocidad de un motor DC con PICSe trata de controlar la velocidad de un motor DC con una señal de impulsos. Variando el tiempo en estado alto de la señal con respecto al tiempo en estado bajo conseguiremos reducir la tensión media que le llega al motor y en consecuencia variaremos su velocidad.
Para hacer ese control con el PIC, en este proyecto emplearemos el modo PWM (Pulse Width Modulation). Leeremos una tensión con el conversor AD del PIC proporcionada por un potenciómetro como control manual de la velocidad. Este valor determinará el tiempo de los pulsos en estado alto de la señal que controlará la velocidad.
En el modo PWM el PIC compara el valor del registro CCP (en este caso el CCP2) con el valor del timer1. En el registro CCP habremos cargado previamente un valor responsable de la velocidad del
motor. Cuando ambos coinciden, se produce la interrupción con la que gestionaremos el cambio de estado de la señal hasta una nueva comparación con la cuenta del timer 1.
lectura_AD=read_adc(); //Lectura canal analógico
#int_ccp2
void ccp2_int(){
//Conmutación estado salida CCP2 if(++cambio==1){ //Modo comparación,conmutación salida a 0 setup_ccp2(CCP_COMPARE_CLR_ON_MATCH); //carga del ccp2 con valor semiperiodo alto
ccp_2=lectura_AD; } else{ //Modo comparación, conmutación salida a 1 setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //Carga del ccp2 con valor del semiperiodo bajo ccp_2=255-lectura_AD; } //Reinicio del temporizador para nueva comparación set_timer1(0); }
Prog
[+/-] Ver / Ocultar programa completo en C////////////////////////////////////////////////////////////////////////////////// //// CONTROL VELOCIDAD MOTOR DC CON PIC //// //// (c) RobotyPic 2012 //// //////////////////////////////////////////////////////////////////////////////////
#include <16f876a.h> //Archivo para control del pic 16f876a
#device adc=8 //Configuración conversor AD a 8 bits
#fuses XT,NOWDT
#use delay(clock=4000000) //frecuencia de reloj 4 MHz
#byte trisb=0x86#byte portb=0x06#byte trisc=0x87#byte portc=0x07
#define use_portb_lcd TRUE //Configuración puerto b control lcd#include <lcd.c> //archivo para control del lcd
/***************** Definición de las variables globales ***********************/
int1 cambio=0; //Control del cambioint16 lectura_AD; //Referencia de velocidad
/********************** Prototipos de las funciones ***************************/
void main (void); //función principalvoid ccp2_int (void); //función por interrupción
/******************************************************************************//******************* FUNCIÓN GENERACIÓN MODULACIONES PWM **********************/
#int_ccp2
void ccp2_int(){ if(++cambio==1){ //Conmutación estado salida CCP2 setup_ccp2(CCP_COMPARE_CLR_ON_MATCH); //Modo comparación, conmutación salida a 0 ccp_2=lectura_AD; //carga del ccp2 con valor semiperiodo alto } else{ setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //Modo comparación, conmutación salida a 1 ccp_2=255-lectura_AD; //Carga del ccp2 con valor semiperiodo bajo } set_timer1(0); //Reinicio del temporizador para comparación } /******************************************************************************//******************** FUNCIÓN PRINCIPAL ***************************************/
void main(){ float velocidad; //Porcentaje velocidad trisc=0x00; //Puerto C como salida de datos port_b_pullups(TRUE); //Habilitación resistencias pullups puerto b lcd_init(); //Inicialización del lcd setup_timer_1(T1_INTERNAL|T1_DIV_BY_1); //Configuración Timer para comparación setup_ccp2(CCP_COMPARE_SET_ON_MATCH); //Modo comparación, conmutación salida a 1 setup_adc_ports(AN0); //Canal de entrada analógico AN0 setup_adc(ADC_CLOCK_INTERNAL); //Fuente de reloj RC para conversor AD enable_interrupts(int_ccp2); //habilitación interrupción por comparación enable_interrupts(GLOBAL); //Habilitación de toda las interrupciones
while (true){ set_adc_channel(0); //Habiliatación lectura AD delay_us(20); //Estabilización lectura_AD=read_adc(); //Lectura canal analógico velocidad=(lectura_AD/2.55); //Cálculo % de velocidad printf(lcd_putc, "\fVelocidad = %3.0f%%", velocidad); }}
n esta animación se puede ver la simulación bajo proteus.https://www.youtube.com/watch?feature=player_embedded&v=bFHjIhT03C4
Control del sensor térmico TPA81 con PIChttps://www.youtube.com/watch?feature=player_embedded&v=HxPH_0CZu2ghttps://www.youtube.com/watch?feature=player_embedded&v=FHZt6uNfLxg
El TPA81 es un sensor de temperatura sin contacto, controlado mediante bus I2C. Dispone de medida de temperatura ambiente y 8 píxeles alineados de medida a distancia. Junto con un servo controlado por el propio sensor y sus 32 posiciones es posible crear un mapa de temperaturas de 180º.
El TPA81 posee 10 registros, del 0 al 9.
o Escribir en el registro 0 supone , según su uso, cambiar la dirección I2C del TPA81 o marcar la posición del servo asociado.
o Escribir en los registros 1, 2 y 3 supone recalibrar el sensor, lo cual no es aconsejable.o Escribir en los registros del 4 al 9 no es posible.o Leer el registro 0 devuelve la revisión del software del TPA81o Leer el registro 1 nos proporciona la temperatura ambiente.o Leer los registros 2 al 9 nos informa de las temperaturas correspondientes a los 8 pixeles.
En este proyecto se pretende mostrar a nivel práctico las principales opciones de funcionamiento de este sensor.
En el momento de conectar el circuito en la pantalla lcd aparece un mensaje de presentación y la versión del software del TPA81. Posteriormente ejecutará cuatro posibles opciones según el estado de las entradas A0 a A3. Con todas las entradas a 0 (todas las opciones activas), primero aparece la posición del servo, al cabo de 1 segundo, la temperatura ambiente, y un segundo más tarde, las temperaturas de los 8 píxeles. Cambia de posición el servo y se repite el ciclo para las otras 31 posiciones. Cuando alguna de las entradas no está activa, el proceso correspondiente no se realiza. Y cuando ninguna de las opciones está activa (las cuatro entradas a 1) la pantalla lcd muestra el mensaje de presentación.
El cableado se muestra en el esquema siguiente.
En los comentarios en el archivo fuente para el compilador se intenta explicar el funcionamiento del programa.
[+/-] Ver / Ocultar programa en C
//////////////////////////////////////////////////////////////////////////////// // // // USO DEL SENSOR TPA81 CON PIC 16F876A Y CONTROL DEL SERVO ASOCIADO //// //// El programa muestra la temperatura ambiente y las temperaturas //// de la matriz de pixeles para cada posición //// del servo //// //// (c) RobotyPic 2010 //// // ////////////////////////////////////////////////////////////////////////////////
#include <16F876A.h> //PIC a utilizar #fuses XT,NOWDT,NOPROTECT //Protecciones#use delay(clock=4000000) //Frecuencia cristal de cuarzo#use i2c(master, SCL=PIN_C3, SDA=PIN_C4) //Configuración comunicación I2C#use standard_io(C) #use standard_io(A)#define use_portb_lcd TRUE //Configuración puerto b para lcd#include <lcd.c> //Archivo control lcdint TPA81_ID = 0xD0; //Dirección I2C de acceso al TPA81 int b[10]; //Buffer para datos lectura TPA81int servo; //Posición del servoint i; //Posiciones para Buffer de datos /******************************************************************************//******************** FUNCIÓN MENSAJE PRESENTACIÓN LCD ************************//***** Muestra mensaje de presentación y durante inactividad del proceso ******/
void mensaje_pres (){ printf(lcd_putc,"\fTPA81 y 16F876A"); printf(lcd_putc,"\n (c) RobotyPic "); }/******************************************************************************//******************* FUNCIÓN DE LECTURA DEL SENSOR TPA81 **********************//*Carga valores de temperatura en el buffer b[]y revisión del software en b[0]*/ void lectura_tpa81( byte slaveID ) { for ( i=0; i<10; i++) { i2c_start(); //Comienzo de la comunicación I2C ... i2c_write(slaveID); //...con la dirección del TPA81... i2c_write(i); //...apuntando a la dirección (i) del registro i2c_start(); //Reinicio i2c_write(slaveID+1); //Cambio a función de lectura b[i] = i2c_read(0); //Carga buffer b[] con datos leídos del TPA81 i2c_stop (); //Finalización de la transmisión delay_ms(10); } } /******************************************************************************//********************** FUNCIÓN BARRIDO CON EL SERVO **************************//****************** Control de las posiciones del servo ***********************/void servo_tpa81 ( byte slaveID, byte servo_pos ) { i2c_start(); //Comienzo de la comunicación I2C ... i2c_write(slaveID); //...con la dirección del TPA81... i2c_write(0); //...apuntando a la posición 0 del registro del TPA81 i2c_write(servo_pos&0x1F); //escribe posición del servo i2c_stop (); //Finalización de la transmisión} /******************************************************************************//************************ FUNCIÓN PRINCIPAL ***********************************/void main() { lcd_init(); //Inicialización lcd mensaje_pres (); //Mensaje de bienvenida durante 2 seg. delay_ms(2000); //Muestra en pantalla lcd versión del software TPA81 durante 2 seg. lectura_tpa81( TPA81_ID ); //Lectura de temperaturas y versión software TPA81 printf(lcd_putc,"\f Firmware V.1.%u", b[0]); delay_ms(2000); servo=0; //Inicialización de la posición del servo while (1) { //Con A0 a 0 se medirán temperaturas en diferentes posiciones del servo if (!input(PIN_A0)){ if (servo==31) servo=0; //Reinicializa posición servo servo = servo + 1; //Nueva posición del servo servo_tpa81 ( TPA81_ID, servo ); //Cambio de posición del servo } //Con A1 a 0 se mostrará posición del servo durante 1 seg. if (!input(PIN_A1)){ printf(lcd_putc,"\f Servo Pos. %u",servo); //Muestra posición servo 1 seg. delay_ms(1000);
} lectura_tpa81( TPA81_ID ); //Lectura de las temperaturas //Con A2 a 0 muestra en pantalla tª ambiente durante 1 seg. if (!input(PIN_A2)){ printf (lcd_putc,"\fT. ambiente %u C", b[1]); delay_ms(1000); } //Con A3 a 0 muestra en pantalla tªs de los 8 pixeles durante 1 seg. if (!input (PIN_A3)){ printf (lcd_putc,"\f%u %u %u %u\n", b[2], b[3], b[4], b[5]); printf (lcd_putc,"%u %u %u %u", b[6], b[7], b[8], b[9]); delay_ms(1000); } //Mientras no haya opción activada muestra mensaje de presentación en lcd if (input_state(PIN_A0)){ if (input_state(PIN_A1)){ if (input_state(PIN_A2)){ if (input_state(PIN_A3)){ mensaje_pres(); } } } } }}
Si se quiere reducir el numero de posiciones del servo en los 180º de giro, es decir, en lugar de 32 que lo haga por ejemplo en 8, bastaría con sustituir la línea “servo=servo+1” por “servo=servo+4”. En función del incremento fijado se variará el numero de posiciones a lo largo de los 180º del giro.En el siguiente video se muestra el funcionamiento del proyecto. En realidad, el sensor debería ir montado sobre el servo, pero para una observación más clara se optado por dejarlos por separado. En este caso están seleccionadas solo las opciones para mostrar las temperaturas de los pixeles conforme el servo cambia de posición.
Y en este otro con todas las opciones seleccionadas. En este caso el servo avanza lentamente para poder ver bien todo el proceso. Para acelerarlo bastaría con disminuir los tiempos de visualización en el lcd o disminuir el número de posiciones en los 180º del giro.
Lectura de luminosidad con el conversor A/DSe trata de un sencillo ejemplo de uso del conversor AD del PIC. Mediante un divisor de tensión formado por dos LDR en la entrada analógica obtendremos un valor de tensión proporcional a la diferencia de luminosidad entre ambas LDR. En un display LCD mostraremos los porcentajes de luz de una de las LDR respecto de la otra.
Para configurar el conversor AD del pic primeramente definiremos el número de bits para la conversión. Pueden ser 8, 10, 11 ó 16. En este caso se ha optado por una conversión a 10 bits:
#device adc=10
Dentro ya de la función principal del programa, definimos el canal de entrada analógico que se va a emplear, el canal al que conectaremos el valor de tensión a medir. Aquí se ha empleado en canal AN0, pin 2 del PIC 16F876A.
setup_adc_ports(AN0);
Se selecciona el tipo de oscilación para el tiempo de conversión, en este caso se ha optado como fuente de reloj RC:
setup_adc(ADC_CLOCK_INTERNAL);
Finalmente se habilita el canal para la lectura. Hemos quedado que empleabamos el canal AN0.
set_adc_channel(0);
A partir de este momento, cada vez que queramos optener la lectura ejecutamos la instrucción:
valor_digital=read_adc();
En la variable "valor_digital" optendremos la lectura correspondiente a la tensión analógica en un valor digital de 10 bits, de 000h a 3FFh.
Este es el programa completo.
[+/-] Ver / Ocultar programa en C
//////////////////////////////////////////////////////////////////////////////// // // // LECTURA DE LUMINOSIDAD //// //// Indicación del porcentaje de luminosidad de una LDR //// respecto de la otra. //// //// (c) RobotyPic 2011 //// // ////////////////////////////////////////////////////////////////////////////////
#include <16F876.h> //Driver del pic#device adc=10 //Configuración conversor AD a 10 bits#fuses XT, NOWDT#fuses#use delay (clock=4000000)#define use_portb_lcd TRUE#include <lcd.c> //Driver para pantalla lcd
void main() { int16 valor_digital; float valor_analogico; int luminosidad_der; int luminosidad_izq; setup_adc_ports(AN0); //Canal de entrada analógico AN0 setup_adc(ADC_CLOCK_INTERNAL); //Fuente de reloj RC lcd_init(); //nicialización del LCD for(;;) { set_adc_channel(0); //Habilitación del canal de lectura 0 delay_us(20); //Estabilización valor_digital=read_adc(); //Lectura digitalcanal analógico valor_analogico=5.0*valor_digital/1024.0; //Equivalencia valor analógico luminosidad_der=(100*valor_analogico)/5; //% luminosidad en LDR derecha luminosidad_izq=100-luminosidad_der; //% luminosidad en LDR izquierda //Muestra de porcentajes en LCD printf(lcd_putc, "\fLuz derecha %3.0d%%", luminosidad_der); printf(lcd_putc, "\nLuz izqrda. %3.0d%%", luminosidad_izq); delay_ms(100); //Retardo hasta siguiente lectura } }
En la simulación bajo Proteus se puede ver el funcionamiento.
Y en la animación de la demostración de su funcionamiento real.
Robot con sensor térmico TPA81
https://www.youtube.com/watch?feature=player_embedded&v=3XbeWr1D1QM
Consiste en un robot que detecta y sigue focos de calor. De igual manera, como foco de calor que es, es capaz de seguir el calor generado por el cuerpo humano.
Para conseguirlo se ha empleado un sensor térmico TPA81. Cómo se controla uno de estos sensores con un PIC se puede ver en el artículo anterior.
Los 8 píxeles del sensor estan distribuidos linealmente siguiendo un trazado horizontal. El servo es controlado por la señal que el propio sensor dispone para ello. Básicamente, el robot intenta que el píxel de mayor temperatura quede entre los dos centrales aumentando o disminuyendo el valor que marca la posición del servo. Cuando el servo llega a la posición extrema, el robot hace un giro de todo el cuerpo para seguir frente al foco de calor. De esta forma da la sensación de que el robot lo sigue.
En los comentarios del programa del PIC desarrollado bajo el compilador PCWHD de CCS se explica la función de las diferentes instrucciones.
[+/-] Ver / Ocultar programa en C
//////////////////////////////////////////////////////////////////////////////// // // // ROBOT QUE SIGUE FUENTES DE CALOR //// //// Uso del sensor térmico TPA81 //// //// (c) RobotyPic 2010 //// // ////////////////////////////////////////////////////////////////////////////////
#include <16F876A.h> //PIC a utilizar
#fuses XT,NOWDT,NOPROTECT //Protecciones
#use delay(clock=4000000) //Frecuencia cristal de cuarzo#use i2c(master, SCL=PIN_C3, SDA=PIN_C4) //Configuración comunicación I2C #use standard_io(C) #use standard_io(A)#use standard_io(B)#define GIRO_DERECHA output_high(PIN_B1),output_low(PIN_B3),output_low(PIN_B2),output_high(PIN_B4)#define GIRO_IZQUIERDA output_low(PIN_B1),output_high(PIN_B3),output_high(PIN_B2),output_low(PIN_B4)#define PARO output_low(PIN_B1),output_low(PIN_B3),output_low(PIN_B2),output_low(PIN_B4)int TPA81_ID = 0xD0; //Dirección I2C de acceso al TPA81 int b[10]; //Buffer para datos lectura TPA81int servo; //Posición del servoint i; //Posiciones para Buffer de datos /******************************************************************************//******************* FUNCIÓN DE LECTURA DEL SENSOR TPA81 **********************//*************** Carga valores de temperatura en el buffer b[] ****************/void lectura_tpa81( byte slaveID ) { for ( i=0; i<10; i++) { //Contador de posiciones del buffer b[] i2c_start(); //Comienzo de la comunicación I2C ... i2c_write(slaveID); //...con la dirección del TPA81... i2c_write(i); //...apuntando a la dirección (i) del registro i2c_start(); //Reinicio i2c_write(slaveID+1); //Cambio a función de lectura b[i] = i2c_read(0); //Carga buffer b[] con datos leídos del TPA81 i2c_stop (); //Finalización de la transmisión delay_ms(10); } }/******************************************************************************//*********************** FUNCIÓN CONTROL DEL SERVO ****************************//****************** Control de las posiciones del servo ***********************/void servo_tpa81 ( byte slaveID, byte servo_pos ) { i2c_start(); //Comienzo de la comunicación I2C ... i2c_write(slaveID); //...con la dirección del TPA81... i2c_write(0); //...apuntando a la posición 0 del registro del TPA81 i2c_write(servo_pos&0x1F); //escribe posición del servo i2c_stop (); //Finalización de la transmisión}/******************************************************************************//************************ FUNCIÓN PRINCIPAL ***********************************/void main() { int media_izq; //El valor medio de b[2] b[3] y b[4] int media_der; //El valor medio de b[7] b[8] y b[9] int condicion; //Condición para girar sensor térmico servo=16; //Posición 0º del servo while (1) { lectura_tpa81( TPA81_ID ); //Lectura de los valores de temperatura
condicion = ((b[1]+b[5]+b[6])/3);
//obtine la media de entre b[2], b[3], b[4] y Tª ambiente media_izq=(b[1]+b[2]+b[3]+b[4])/4; //obtiene la media de entre b[7], b[8], b[9] y Tª ambiente media_der=((b[1]+b[7]+b[8]+b[9])/4); //Comprueba si debe girar a la izquierda if (media_izq > condicion){ //Si temp. a izquierda es mayor que central... if (media_izq > media_der){ //...y además es mayor que la derecha... servo=servo+1; //... entonces gira el servo una posición if (servo>=30) { //Si servo llega al final de su giro... servo=16; //...lo deja en 0º ... servo_tpa81 ( TPA81_ID, servo ); delay_ms(50); GIRO_IZQUIERDA; //... y gira el cuerpo a la izquierda delay_ms(800); PARO; } else servo_tpa81 ( TPA81_ID, servo ); //Sino sólo gira el servo } }
//Comprueba si debe girar a la derecha if (media_der > condicion){ //Si temp. a derecha es mayor que central... if (media_der > media_izq){ servo=servo-1; //... entonces gira el servo una posición if (servo<=1){ //Si servo llega al final de su giro... servo=16; //...lo deja en 0º ... servo_tpa81 (TPA81_ID, servo); delay_ms(50); GIRO_DERECHA; //... y gira el cuerpo a la derecha delay_ms(800); PARO; } else servo_tpa81 ( TPA81_ID, servo ); //Sino sólo gira el servo } } }}
Pulsar en la imagen para ampliarla
Los archivos del proyecto se pueden descargar del siguiente enlace: