pcf8591_AD_DA_on_any_Pi_device.c (4.9 KB) The PCF8591 YL-40 AD/DA Module has 3 on-board sensors (light, temperature, manual potentiometer) for easy experimenting with ADC/DAC. These sensors can also be disabled by the 3 jumpers so that the 4 analog input channels AIN0 to AIN3 can be used with own analog sources. Below is a test program in C demonstrating the use of this module. It does not require any external library like the WiringPi or pigpio libraries, rather it uses basic file I/O (open, write, read, close). FYI: BPI offers a similar ADC/DAC module, see under the Accessories product pages.
/*
pcf8591_AD_DA_on_any_Pi_device.c
Programming the ADC/DAC chip PCF8591 (and modules/hats that use such a chip)
for reading data from its analog input channels
as well sending data to its analog output channel.
For details see PCF8591 Data Sheet ( https://www.nxp.com/docs/en/data-sheet/PCF8591.pdf ).
This implementation does use just basic C programming,
and does not need any of the popular RaspberryPi-specific libraries
like WiringPi or pigpio. Ie. this is a portable implementation.
Written by [email protected] (UM)
Changelog:
2019-05-29-We v1.00b UM: Added info on how to disable the 3 on-board sensors on this module
to attach own anaalog sources to the input channels AIN0, AIN1, AIN2, AIN3.
2019-05-29-We v1.00 UM: Initial development. Posted to https://www.mikrocontroller.net/topic/475072#5859321
Prerequisites:
Install package i2c-tools from the Linux repository
list the i2c devices
# ls -l /dev/i2c*
crw-rw---- 1 root i2c 89, 0 Jan 1 1970 /dev/i2c-0
crw-rw---- 1 root i2c 89, 1 Jan 1 1970 /dev/i2c-1
get the address (in hex) of i2c device 1, ie. /dev/i2c-1
# i2cdetect -y 1
0 1 2 3 4 5 6 7 8 9 a b c d e f
00: -- -- -- -- -- -- -- -- -- -- -- -- --
10: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
20: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
30: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
40: -- -- -- -- -- -- -- -- 48 -- -- -- -- -- -- --
50: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
60: -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --
70: -- -- -- -- -- -- -- --
Compile:
# gcc -O2 -Wall -Wextra -std=gnu11 -o pcf8591_AD_DA_on_any_Pi_device.exe pcf8591_AD_DA_on_any_Pi_device.c
Run as root (or use sudo):
# ./pcf8591_AD_DA_on_any_Pi_device.exe
NOTES:
In this example below, only the analog input channel 0 is read. You can change it below.
See also the data sheet of the PCF8591 and also the documentation of your specific module.
I used the following module called "PCF8591 YL-40 AD/DA Module":
https://www.roboter-bausatz.de/207/pcf8591-ad/da-converter-module
That module has some additional sensors (light, temperature and a manual potentiometer)
for easy testing of the ADC/DAC chip.
You can find it (and similar modules) at many places on the net, also in ebay.
Disabling the on-board sensors is done with the 3 jumpers on the above module;
see this review of the module (FYI: I haven't verified the accuracy of this info yet):
https://brainfyre.wordpress.com/2012/10/25/pcf8591-yl-40-ad-da-module-review/
"
The jumpers control whether analog input channels of the IC are connected to the analog sources:
Jumper P4 for AIN1: The temperature sensed by the R6 thermister is provided to the ADC.
Jumper P5 to AIN0: The R7 photocell voltage (resistance drop) is provided to the DAC.
Jumper P6 to AIN3: The single turn 10K ohm trimpot voltage (resistance drop – brighter light, lower resistance).
"
I developed and tested this code on Banana Pi devices (M1, R1): http://www.banana-pi.org/r1.html#others
The module was attached to the 3.3V pin, TWI2-SDA, TWI2-SCK, and GND pin.
It continously just reads 1 byte and displays it. For further usage one would convert/scale that value
to a meaningful range depending on the context, ie. temperature, voltage, daylight etc.
*/
#include
#include
#include
#include
#include
#include
#include
#include
// see comments above
#define MY_I2C_ADDR 0x48
// see PCF8591 Data Sheet, page 6, Control Byte; link above
struct pcf8591_control_byte
{
uint8_t Channel : 2, // 0..3
ChannelAutoInc : 1, // see data sheet
Reserved1 : 1, // value 0
ChannelMixing : 2, // see data sheet
Enable_AOUT : 1, // enabling AOUT, ie. DAC functionality
Reserved2 : 1; // value 0
};
int main(void)
{
int fd = open("/dev/i2c-1", O_RDWR); // see comments above
if (fd < 0)
{
printf("Error opening device: %s\n", strerror(errno));
return 1;
}
if (ioctl(fd, I2C_SLAVE, MY_I2C_ADDR) < 0)
{
printf("ioctl error: %s\n", strerror(errno));
close(fd);
return 1;
}
// write 0x0: ie. use just channel 0, see data sheet, and the jumper info above
struct pcf8591_control_byte S;
memset(&S, 0, sizeof(S));
/*
S.Channel = 0;
S.ChannelAutoInc = 0;
ChannelMixing = 0;
Enable_AOUT = 0;
*/
if (write(fd, &S, 1) != 1)
printf("ERR #1: %s\n", strerror(errno));
// read continously 1000 values with 50ms delay between each reading:
for (int i = 0; i < 1000; ++i)
{
uint8_t u;
const ssize_t n = read(fd, &u, 1);
if (!n)
printf("ERR\n");
else
printf("%d\n", u);
usleep(50 * 1000); // 50ms delay
}
close(fd);
return 0;
}