Está en la página 1de 15

http://robotypic.blogspot.com/2012/12/sensor-srf08-con-pic.

html

Control de velocidad de un motor DC con PIC


Se 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
r especto 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 cambio


int16 lectura_AD; //Referencia de velocidad

/********************** Prototipos de las funciones ***************************/

void main (void); //función principal


void 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 PIC


https://www.youtube.com/watch?feature=player_embedded&v=HxPH_0CZu2g
https://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 TPA81
o 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 lcd
int TPA81_ID = 0xD0; //Dirección I2C de acceso al TPA81
int b[10]; //Buffer para datos lectura TPA81
int servo; //Posición del servo
int 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 di sminuir 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/D


Se 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(P
IN_B4)
int TPA81_ID = 0xD0; //Dirección I2C de acceso al TPA81
int b[10]; //Buffer para datos lectura TPA81
int servo; //Posición del servo
int 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:

También podría gustarte