El chip PCF8591 realiza conversiones digitales con una resolución de 8 bits y un A/D de aproximaciones sucesivas, incorpora también un conversor D/A, todo controlado mediante el bus I2C. El chip incorpora pines de direccionamiento por hardware (Igual que las memorias I2C), un pin de salida analógica para el DAC y entrada de Vref. Esto funcional al DAC como al ADC.

Funcionamiento.

En este ejemplo lo vemos trabajar en los dos modos en un programa que se divide en dos partes que son accedidas mediante la acción de un botón conectado en el pin RA0 de un PIC18F4620.
En el modo por defecto el PIC recibe los datos de dos canales (A0 y A1) enviados por I2C desde el PCF8591, luego actuando sobre el botón en RA0 enviamos al módulo DAC el número 128 lo que pondrá en la salida analógica el 50% de la tensión de alimentación aproximadamente. Puede ver a continuación el programa completo para el manejo de este dispositivo con XC8 y MPLAB X.
(Para mas detalles consulte la hoja de datos del chip).

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/* *********************************************************************************
**  Nombre       : PCF8591.c
**  Descripcion  : Midiendo en dos canales del ADC y funcionamiento del DAC
**  Target       : PIC18F4620
**  Compilador   : Microchip XC8
**  XTAL         : 20MHZ  
** *********************************************************************************
 El pulsador colocado en RA0 controla el flujo del programa.
***********************************************************************************/
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#include <plib/i2c.h>
//#include "PCF8591.h"
 
#pragma config OSC=HS,PWRT=ON,MCLRE=OFF,LVP=OFF,WDT=OFF
 
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.c"
#include "C:\ELECTRÓNICA\Programas PIC\2014\EJERCICIOS_XC8\PCF8591.X\lcd_xc8.h"
 
#ifndef _XTAL_FREQ
 #define _XTAL_FREQ 20000000
#endif
 
static  bit bandera1 = 0;    // Bandera para cambiar el canal.
unsigned char bandera2 = 0;
char Str_float[5];       // Cadena para convertir el float en ASCII.
float voltaje = 0.00;    // Contenedor para guardar la medición.
 
unsigned char  Lee_Byte( unsigned char ByteControl, unsigned char Direccion)
{
	unsigned char Valor;
	IdleI2C();                 // El modulo esta activo?
	StartI2C();                // Condicion de START
	while ( SSPCON2bits.SEN ); // Espera a que la condición de inicio termine
	WriteI2C( ByteControl );
	WriteI2C( Direccion );
 
	RestartI2C();                // Envia ReStart
	while ( SSPCON2bits.RSEN );  // Si se ha recibido el byte sigue
	WriteI2C( ByteControl | 0x01 ); // Cambia bit0 de ByteControl a 1 para realizar lectura.
	Valor=ReadI2C();		// Realiza lectura.
	NotAckI2C();                   // Envia NACK
	while ( SSPCON2bits.ACKEN );   // Espera a que de ASK termine
	StopI2C();                     // Condicion de STOP
	while ( SSPCON2bits.PEN );     // Espera a que la condición de stop termine
	return ( Valor );              // Retorna Lectura
}
//-------------------- FUNCIÓN PARA EL CONTROL DEL ADC -------------------------
void ADC(void){
      switch(bandera1){   // Se discrimina en cual canal se medirá.
   case 0:{             // Si es "0" se lee en el canal cero.
     voltaje =Lee_Byte(0x90,0); // En voltaje se guarda el dato desde el A/D.
     __delay_ms(10);
     bandera1 =1;        // Se cambia bandera para el siguiente canal.
    break;
   }
case 1:{
     voltaje =Lee_Byte(0x90,1);
     __delay_ms(10);
     bandera1 =0;
    break;
   }
 }
   voltaje = (voltaje*5.0)/256; // Se escala el valor para medir entre 0 y 5V
   sprintf(Str_float,"%1.2f ",voltaje); // El float es convertido a ASCII
   if(bandera1 ==0)      // Si bandera es cero se coloca el cursor en el lugar
   lcd_gotoxy(4,2);     // indicado junto al cartel que le corresponde.
   else
    lcd_gotoxy(13,2);   // Si bandera es uno se coloca el cursor en el lugar
   lcd_puts(Str_float); // indicado junto al cartel que le corresponde.
}
//--------------- FUNCIÓN VERIFICA LA PRESENCIA DEL PCF8591 --------------------
void check_PCF8591(unsigned short dir){
 StartI2C();            // Condición de inicio en el bus.
 if (WriteI2C(dir)){    // Escribe la direción del chip en el bus.
  lcd_gotoxy(2,2);      // Si retorna "1" no hay sensor en el bus.
lcd_putrs("PCF8591 ERROR!!");  // Aviso de que no hay sensor en el BUS.
while(1);               // Programa termina.
 }
 else {
     lcd_gotoxy(3,1);
     lcd_putrs("Chip PCF8591");  // Cartel incial para indicar la presencia
 }                               // del chip en el bus I2C.
     StopI2C();
}
//--------------------- FUNCION PRINCIPAL DEL PROGRAMA -------------------------
void main() {
 
TRISA=0X01;	// Configura el pin 2 como entrada digital 
ADCON1 = 0X0F; 	// Configura los pines del PORT A como I/O Digitales
 
  OpenI2C(MASTER,SLEW_OFF);  	// Modo Master.
  SSPADD = 49;			// 100KHz para 20MHz.
  
 lcd_init();            // Configura el LCD a valores por defecto.
 check_PCF8591(0x90);   // Verifica la presencia del chip en el BUS.
 
 while(1) {
 // El boton en RA0 es el encargado de cambiar al DAC o al ADC
   if(PORTAbits.RA0!=1 && bandera2== 1){
    while(!PORTAbits.RA0);   // Espera a que el boton se suelte
    lcd_gotoxy(1,2);
 lcd_putrs("                "); // Limpia la línea inferior para el ADC
 bandera2=0;   // Coloca la bandera para que el ADC sea el modo por defecto
   }
   if(PORTAbits.RA0!=1 && bandera2== 0){ // Pasa al modo DAC
   while(!PORTAbits.RA0);  // Espera a que el boton se suelte
   bandera2++;
   lcd_gotoxy(1,2);
   lcd_putrs("  Conversor DAC ");
  StartI2C(); 
  WriteI2C(0x90);
   __delay_ms(2);
   WriteI2C(0x40);   // Coloca el chip en modo DAC
   __delay_ms(2);
   WriteI2C(128);   // Saca por el pin analógico 2.5V aprox. (256/2=128)
   StopI2C();       // Condición de STOP
   while ( SSPCON2bits.PEN ); // Espera que termine la condición de STOP
   }
  if(bandera2==0){  // Si bandera es 0 se activa el modo por defecto (ADC)
 lcd_gotoxy(1,2);       // Coloca los carteles para los canales analógicos
  lcd_putrs("A0:");
    lcd_gotoxy(10,2);
     lcd_putrs("A1:");
      ADC();         // LLama a la función del conversor analógico
  }
 }
}
 

 

 

 El ejemplo funcionando.

Material extraído de nuestro libro Introducción al C para PIC.