Hola a todos!
Estos días estuve peleandome un módulo I2C de analógicas, el PCF8591P, y gracias a los ejemplos ya existentes en el foro he podido arreglarmelas pero como me ha dado bastante lata a pesar de ello y también he leido unos cuantos mensajes de dificultades varias con éste módulo por parte de otras personas que también se iniciaban, ahora me decido a mostrar este ejemplo que combina la lectura de los 4 canales y la escritura del canal de salida analógica con una sola función.
El programa varía la frecuencia de un variador (salida analogica del PCF8591) y lee el consumo de éste (con una de las entradas analogicas del PCF8591)
GeSHi (c):
/*
Prueba entradas y salida analógicas PCF8591P.
Probado con un variador controlando la referencia de frecuencia y leyendo el consumo.
Funciona ok.
Conexiones PCF8591P:
pines 1,2,3,4,11: N.C.
pines 5,6,7: Address (6)
pines 8,12,13: GND
pines 9,10: SDA y SCL (Bus I2C)
pines 14,16: VDD
pin 15: + Salida analogica
*/
#include <16F877.h>
#FUSES HS,NOPROTECT,PUT,BROWNOUT,NOLVP,NOWDT,DEBUG
#USE DELAY(CLOCK=20000000)
#USE I2C(MASTER,SDA=PIN_C4,SCL=PIN_C3,FORCE_HW)
#USE FAST_IO(B)
#USE rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)
#include <PCF8591P.c>
#byte port_a = 5
#byte port_b = 6
#byte port_c = 7
#byte port_d = 8
#byte port_e = 9
int rfVariador,ain0,ain1,ain2,ain3;
void main()
{
//Definición de E/S
set_tris_a(0b00111111);
set_tris_d(0b11111111);
set_tris_e(0b00000111);
set_tris_b(0b00000000);
set_tris_c(0b00000000);
while(true)
{
// Prueba completa del módulo PCF8591P
rfVariador=ain1; // Lectura del canal 1 (tengo un potenciómetro de 10k para probar rápidamente)
printf("Ref Frecuencia: \%u\n",rfVariador
);
// Monitorizo por RS232 la referencia de frecuencia del variador
// Lectura y Escritura 4 canales Analogicas I2C.
ain0=rwPCF8591P(0,rfVariador);
printf("Entrada AIN-0 PCF8591P: \%u\n",ain0
);
ain1=rwPCF8591P(1,rfVariador);
printf("Entrada AIN-1 PCF8591P: \%u\n",ain1
);
ain2=rwPCF8591P(2,rfVariador);
printf("Entrada AIN-2 PCF8591P: \%u\n",ain2
);
ain3=rwPCF8591P(3,rfVariador);
printf("Entrada AIN-3 PCF8591P: \%u\n\n",ain3
);
// Retardo bucle.
delay_ms(200);
}
}
En el "PCF8591P.c" están las funciones de solo lectura, solo escritura y lectura/escritura:
GeSHi (c):
// Las funciones están pensadas para funcionar como DIRECCION ó Nodo 6 (110)
// Seleccionamos el módulo PCF8591P del bus I2C y damos un valor a la salida analógica
void writePCF8591P(int dato)
{
i2c_start(); // Inicio comunicación I2C
i2c_write(0b10011100); // Envío Dirección I2C del PCF8591 (Nodo6)
i2c_write(0b01000000); // Envío Configuración del PCF8591 para Conv. DA
i2c_write(dato); // Envío el dato de salida analógica
i2c_stop(); // Detengo comunicacion I2C
}
// Lectura analogica 4 canales del módulo PCF8591P.
int readPCF8591P(int canal)
{
int lectura,control,addressWrite,addressRead;
if(canal<=3)
{
addressWrite=0b10011100;
addressRead=0b10011101;
switch(canal)
{
case 0: control=0b01000001; // Para leer el canal 0 hay que indicar que leemos queremos leer el 1
break;
case 1: control=0b01000010; // Para leer el canal 0 hay que indicar que leemos queremos leer el 2
break;
case 2: control=0b01000011; // Para leer el canal 0 hay que indicar que leemos queremos leer el 3
break;
case 3: control=0b01000000; // Para leer el canal 0 hay que indicar que leemos queremos leer el 0
break;
}
i2c_start();
i2c_write(addressWrite); // Byte de dirección. Modo Escritura, nodo 6.
i2c_write(control); // Byte de control.
i2c_write(0); // Dato salida analógica.
i2c_stop();
i2c_start();
i2c_write(addressRead); // Modo Lectura Nodo 6
lectura=i2c_read(0); // Lectura de datos.
i2c_stop(); // Detengo comunicacion I2C
}
else
lectura=0;
return lectura;
}
// Funcion que ejecuta la Lectura y Escritura sobre el módulo PCF8591P
int rwPCF8591P(int canal, int write)
{
int lectura,control,addressWrite,addressRead;
if(canal<=3)
{
addressWrite=0b10011100;
addressRead=0b10011101;
switch(canal)
{
case 0: control=0b01000001; // Para leer el canal 0 hay que indicar que leemos queremos leer el 1
break;
case 1: control=0b01000010; // Para leer el canal 0 hay que indicar que leemos queremos leer el 2
break;
case 2: control=0b01000011; // Para leer el canal 0 hay que indicar que leemos queremos leer el 3
break;
case 3: control=0b01000000; // Para leer el canal 0 hay que indicar que leemos queremos leer el 0
break;
}
i2c_start();
i2c_write(addressWrite); // Byte de dirección. Modo Escritura, nodo 6.
i2c_write(control); // Byte de control.
i2c_write(write); // Envío el dato de salida analógica
i2c_stop();
i2c_start();
i2c_write(addressRead); // Modo Lectura Nodo 6
lectura=i2c_read(0); // Lectura de datos.
i2c_stop(); // Detengo comunicacion I2C
}
else
lectura=0;
return lectura;
}
Se podría optimizar la función de lectura-escritura aportando como variable para el canal un array y después usar un for recorriendo así los canales...
Lo único que me parece extraño es que para leer el canal 0 haya que indicarle canal 1 y así sucesivamente...

, alguién sabe porqué?.
Pues nada más, espero que sea interesante para alguien

.
Salu2!