经过 DongshanPI-D1s开发板使用教程之SHT30温湿度传感器(I2C)数据读取 及 DongshanPI-D1s开发板使用教程之使用LCD1602(I2C)液晶显示屏 、 DongshanPI-D1s开发板使用教程之使用U8g2驾驭SSD1306 OLED(I2C)液晶显示屏的学习研究,已经可以熟练使用I2C设备了。
在此基础上,想要多多挖掘板子的功能。经过查看原理图,以及官方资料,发现在V1.1版本中,增加了GPADC按键,但是不能被我们做通用的ADC功能。
一块板子,要是没有AD/DA功能,就少了很多韵味了。
刚好,我手头有一个ADS1115模块,可以用作ADC功能,经过一番研究,顺利为D1s扩展ADC功能。
ADS1115是一款非常常用的ADC模块,用途非常的官方,某宝某ADS1115介绍如下:
看到没,用词:偉大,虽然是店家介绍,但足以说明ADS1115不是浪得虚名。
其具体参数如下:
实物模样如下:
ADS1115,采用I2C接口,有4个通道可用于测量,使用起来,那是相当方便了。
关于ADS1115数模转换的原理等,这里就不想详细说明了,大家可以在网上查找资料,非常丰富。
下面,就将具体使用方式,分享给大家。
一、硬件材料
- D1s开发板:DongshanPI-D1s开发板
- ADS1115模块:I2C接口
- IoT Power:数字电源,方便模拟实际电压测试
- 连接线:杜邦线若干,需要2.0转2.54线;手头没有转接线,直接用测试钩
二、原理图
通过查看DongshanPI-D1s开发板的原理图,了解到I2C接口使用和连接:
在上图核心板的左下角,可以看到:
PE12:SCL
PE13:SDA
需要注意的是,默认系统中,开启的是I2C2。
上图中的测量点,用于接入需要实际测量的电压点位。注意,测量设备需要和D1s板子共地,也就是把GND接到板子上即可。
三、实物接线
ADS115供电电压使用D1s板子的5V输出即可。
数字电源的输出+接到ADS1115的A0输入口,GND接到D1s板子的GND即可。
上图中的手机可有可无,主要用于方便显示程序运行的结果,和数字电源设定的电压作对比。
四、编译固件
参考 DongshanPI-D1s开发板使用教程之SHT30温湿度传感器(I2C)数据读取 进行。
如果已经编译烧录过,则不用重新编译烧录,直接使用即可。
五、I2C设备检测
DongshanPI-D1s开发板启动后,参考 DongshanPI-D1s开发板使用基础文档【编译、烧录、adb、gpio-led、c】 使用OTG接口通过adb连接,再进行下面的操作。
- 执行
i2cdetect -l
查看当前的I2C控制器:
可以看到,当前可用的i2c设备为i2c-2 - 执行
i2cdetect -r -y 2
,查看识别的I2C外部设备:
可以看到,ADS1115的地址0x48被识别出来了。
ADS1115可以设置地址,请仔细查阅所用设备的说明。如果设置或者不为0x48后续代码中,也要做对应的处理。
如果在列表中,没有看到ADS1115(I2C)的地址,请仔细检查ADS1115的I2C的接线是否正常。
如果因为程序错误,导致I2C设备打开后,进入busy状态,那就把开发板断电,然后重新上电启动,再次进行检查。
六、编写代码
在网上,有很多STM32或者Arduino上使用ADS1115的资料。
我使用的是 adafruit/Adafruit_ADS1X15: Driver for TI’s ADS1015: 12-bit Differential or Single-Ended ADC with PGA and Comparator (github.com),也就是Adafruit为Arduino提供的ADS1X15扩展库。
不过,这个库,只支持Arduino平台。经过一番研究,改造改造,能够支持在Linux上使用了。修改后的代码,已经给官方提交PR了。
如果着急使用的话,可以从我的fork地址下载: HonestQiao/Adafruit_ADS1X15: Driver for TI’s ADS1015: 12-bit Differential or Single-Ended ADC with PGA and Comparator (github.com)
在这个库中,Adafruit_ADS1X15.cpp、Adafruit_ADS1X15.h 为调用库,examples/linux/下面为Linux环境下的测试文件。这个测试文件,参考Arduino下的测试文件来的。
关于调用库的具体信息,请大家查看源码,重点讲解测试文件。
测试文件内容具体如下:
#include "../../Adafruit_ADS1X15.h"
Adafruit_ADS1115 ads; /* Use this for the 16-bit version */
// Adafruit_ADS1015 ads; /* Use this for the 12-bit version */
void setup(void) {
// Serial.begin(9600);
// Serial.println("Hello!");
// Serial.println("Getting single-ended readings from AIN0..3");
// Serial.println("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015,
// 0.1875mV/ADS1115)");
printf("Getting single-ended readings from AIN0..3");
printf("ADC Range: +/- 6.144V (1 bit = 3mV/ADS1015, 0.1875mV/ADS1115)");
// The ADC input range (or gain) can be changed via the following
// functions, but be careful never to exceed VDD +0.3V max, or to
// exceed the upper and lower limits if you adjust the input range!
// Setting these values incorrectly may destroy your ADC!
// ADS1015
// ADS1115
// -------
// -------
// ads.setGain(GAIN_TWOTHIRDS); // 2/3x gain +/- 6.144V 1 bit = 3mV 0.1875mV
// (default) ads.setGain(GAIN_ONE); // 1x gain +/- 4.096V 1 bit =
// 2mV 0.125mV ads.setGain(GAIN_TWO); // 2x gain +/- 2.048V 1
// bit = 1mV 0.0625mV ads.setGain(GAIN_FOUR); // 4x gain +/- 1.024V
// 1 bit = 0.5mV 0.03125mV ads.setGain(GAIN_EIGHT); // 8x gain +/-
// 0.512V 1 bit = 0.25mV 0.015625mV ads.setGain(GAIN_SIXTEEN); // 16x
// gain +/- 0.256V 1 bit = 0.125mV 0.0078125mV
if (!ads.begin(ADS1X15_ADDRESS, 2)) {
// Serial.println("Failed to initialize ADS.");
printf("Failed to initialize ADS.");
while (1)
;
}
}
void loop(void) {
int16_t adc0, adc1, adc2, adc3;
float volts0, volts1, volts2, volts3;
adc0 = ads.readADC_SingleEnded(0);
adc1 = ads.readADC_SingleEnded(1);
adc2 = ads.readADC_SingleEnded(2);
adc3 = ads.readADC_SingleEnded(3);
volts0 = ads.computeVolts(adc0);
volts1 = ads.computeVolts(adc1);
volts2 = ads.computeVolts(adc2);
volts3 = ads.computeVolts(adc3);
// Serial.println("-----------------------------------------------------------");
// Serial.print("AIN0: "); Serial.print(adc0); Serial.print(" ");
// Serial.print(volts0); Serial.println("V"); Serial.print("AIN1: ");
// Serial.print(adc1); Serial.print(" "); Serial.print(volts1);
// Serial.println("V"); Serial.print("AIN2: "); Serial.print(adc2);
// Serial.print(" "); Serial.print(volts2); Serial.println("V");
// Serial.print("AIN3: "); Serial.print(adc3); Serial.print(" ");
// Serial.print(volts3); Serial.println("V");
printf("-----------------------------------------------------------\n");
printf("AIN0: %d %f V\n", adc0, volts0);
printf("AIN1: %d %f V\n", adc1, volts1);
printf("AIN2: %d %f V\n", adc2, volts2);
printf("AIN3: %d %f V\n", adc3, volts3);
delay(1000);
}
int main(int argc, char *argv[]) {
setup();
while (true) {
loop();
}
}
上述代码的逻辑如下:
- 实例化ADS1115对象:Adafruit_ADS1115 ads
- 设置放大倍数:ads.setGain(GAIN_TWOTHIRDS),可以不用,使用默认值
- 开启设备I2C通信:ads.begin(ADS1X15_ADDRESS, 2),两个参数,一个为ADS1115的地址0x48,一个为/dec/i2c-2的序号
- 读取数据:ads.readADC_SingleEnded(0),表示读取通道0的数据,也就是A0;可用通道为0~3
- 电压转换:ads.computeVolts(adc0);表示转换adc0的数据到实际的电压值
ads.setGain()设置表示测量的范围和精度,具体值如下:
- GAIN_TWOTHIRDS:+/- 6.144V 1 bit = 3mV
- GAIN_ONE:+/- 4.096V 1 bit = 2mV
- GAIN_TWO:+/- 2.048V 1 bit = 1mV
- GAIN_FOUR:+/- 1.024V 1bit = 0.5mV
- GAIN_EIGHT:+/- 0.512V 1 bit = 0.25mV
- GAIN_SIXTEEN:+/- 0.256V 1 bit = 0.125mV
基本的使用只需要上面即可步骤即可。更丰富的使用,可以查看Arduino的示例。
七、编译代码并执行
这里需要注意的是,编写、编译、上传、执行,是在不同的环境:
- 编写:可以在编译固件的环境,也可以在主机环境编写好以后在编译环境编译
- 编译:在编译固件的环境中编译
- 上传:在主机环境,通过adb上传到开发板
- 执行:在开发板上执行
那就先编译代码:
# 设置编译工具路径
export PATH=/sdk/tina-d1-h/prebuilt/gcc/linux-x86/riscv/toolchain-thead-glibc/riscv64-glibc-gcc-thead_20200702/bin/:$PATH
# 编译
cd Adafruit_ADS1X15/examples/linux/
riscv64-unknown-linux-gnu-gcc -o singleended singleended.cpp ../../Adafruit_ADS1X15.cpp
# 查看结果
ls -lh singleended
-rwxr-xr-x 1 root 18K Nov 9 13:35 singleended
编译完成后,在主机上,使用adb上传:
cd Adafruit_ADS1X15/examples/linux/
adb push singleended /root/
最后,在开发板上执行:
/root/singleended
实际的显示结果如下:
因为最开始,数字电源的输出是关闭的,所以读数只有接近0V。
打开数字电源输出,设定输出为3V,实际2.999V,所以AIN0的数值从接近0上升到了2.999…
此时,数字电源实际电压设置如下:
通过上面的实例,可以学习到,使用ADS1115,可以很方便的为D1s提供ADC功能扩展,能够极大地丰富D1s的功能,值得好好使用!