1.前言
树莓派自身不带有模拟量采集功能(A/D)功能,当需要AD功能时,常通过IIC外接一个A/D模块来实现,如8位A/D芯片PCA9685。本文首先简要介绍PCA9685特性,然后基于树莓派的Bcm2835库开发PCA9685的驱动库。树莓派安装Bcm2835库参考这篇文章。
2.PCA9685
PCA9685芯片有4路8位的A/D采集通道和一路8位D/A输出通道,其他通过IIC与外部通信。其芯片引脚见下图,其工作电压VDD可以2.5-6V,参考电压VREF为A/D转化参考电压可以与VDD一致也可不一致。芯片IIC地址可以通过物理引脚A0,A1,A2配置,若三引脚全接GND,芯片地址0x48。某宝中有对该芯片封装成的模块,其实物图和原理图分别见下图。 按照芯片手册的IIC协议,要采集AD通道,首先要发送一个一条控制指令,该指令由一个字节CONTROL BYTE组成(如果还要D/A输出,该指令有两个字节组成,CONTROL BYTE和一个字节的AD输出电压)。CONTROL BYTE可以配置1.模拟输出使能;1.模拟采集模式,单边输入模式和多种差分输入模式;3.AUTO-INCREMENT FLAG;4.A/D采集通道。发送该条指令后,再读取一个字节的数据即为指定通道的A/D值,再乘以分辨率就得到该通道的电压。
3.树莓派基于Bcm2835编写驱动库
使用C++语言编写该库,为PCA9685芯片编写一个类,其头文件pca9685.h
#ifndef PCF8591_H
#define PCF8591_H
#include <bcm2835.h>
#include <cstdio>
#include <cstdint>
class PCF8591{
public:
PCF8591(uint8_t addr = 0x48);
bool init();
void setRefV(float refV);
uint8_t readAD(uint8_t channel);
float readVoltage(uint8_t channel);
private:
uint8_t _addr;
float _refV;
char sendBuf[3];
uint8_t errCode;
};
#endif
pca9685.cpp文件
#include "pcf8591.h"
PCF8591::PCF8591(uint8_t addr)
{
_addr = addr;
_refV = 5.03f;
}
bool PCF8591::init()
{
printf("PCF8591 Init...\n");
if(!bcm2835_i2c_begin())
{
printf("bcm2835_i2c_begin failed at %s%d\n",__FILE__,__LINE__);
return false;
}
bcm2835_i2c_setSlaveAddress(_addr);
bcm2835_i2c_set_baudrate(100000);
return true;
}
void PCF8591::setRefV(float refV)
{
_refV = refV;
}
uint8_t PCF8591::readAD(uint8_t channel)
{
bcm2835_i2c_setSlaveAddress(_addr);
sendBuf[0] = 0x00 | channel;
if((errCode = bcm2835_i2c_write(sendBuf,1)))
printf("bcm2835_i2c_write failed at %s%d, errCode = 0x%x\n",__FILE__,__LINE__, errCode);
char byte;
if((errCode = bcm2835_i2c_read(&byte,1)))
printf("bcm2835_i2c_read failed at %s%d, errCode = 0x%x\n",__FILE__,__LINE__, errCode);
return byte;
}
float PCF8591::readVoltage(uint8_t channel)
{
return readAD(channel)/255.0f*_refV;
}
一个测试例程testMain.cpp
#include "pcf8591.h"
#include <iostream>
using namespace std;
int main()
{
bcm2835_init();
PCF8591 pcf8591;
if(pcf8591.init())
cout << "PCF8591 init successfully" << endl;
else
{
cout << "PCF8591 init failed" << endl;
exit(-1);
}
int i = 10;
while(i)
{
int byte = pcf8591.readAD(3);
cout << byte << endl;
bcm2835_delay(100);
}
return 0;
}
驱动库可以直接github下载
|