查看: 246|回复: 3

[项目] 分光光度计实验-光谱传感器

[复制链接]
本帖最后由 柳春晓 于 2020-10-13 13:53 编辑

这篇文章中我将带大家使用光谱传感器来做一个简易的分光光度计,通过数据采集、拟合曲线等操作,最终实现能将水中的溶解物质的浓度显示出来。

一、背景介绍

首先来给大家介绍一下分光光度计和光谱传感器是什么。

1.分光光度计

分光光度计:又称光谱仪,主要由光源、单色器、样品室、检测器、信号处理器和显示与存储系统组成。当我们用他来测量一个液体中含有某物质的浓度时,由于很多物质是有吸光性的,而且不同物质吸收的光谱(颜色)是不同的,利用这些特性就可以鉴别出液体中含有某种物质的浓度。

光源和单色器:真实的光度计光源使用的是钨光灯,然后用棱镜作为单色器将钨光灯的光折射,得到由红、橙、黄、绿、蓝、靛、紫组成的连续色谱。我们为了实验的简单性,直接使用一个普通的红色LED灯来模拟光源。

剩下的,样品室我们使用的是比色皿,某宝3RMB/个;检测器就是我们的光谱传感器;信号处理单元使用UNO控制器

2.光谱传感器

AS7341可见光传感器,采用业内知名的ams公司推出的新一代AS7341光谱传感IC。该传感器有8个可见光通道、1个闪烁通道、1个NIR通道和1个未加滤光片的通道。该传感器拥有6个独立的16位ADC通道,可以并行的处理数据。可检测F1(405-425nm)、F2(435-455nm)、F3(470-490nm)、F4(505-525nm)、F5(545-565nm)、F6(580-600nm)、F7(620-640nm)、F8(670-690nm)八个波段的波长强度。

3.设备安装

需要准备:

光谱传感器 - 1

红色LED灯 - 1

比色皿 - 1

显示器 - 1

3D打印外壳 - 1

烧杯 - 6(或其他容器)

染料(或其他溶于水的物质)


1.jpg

由于组装比较简单,这里就不一步步展示安装过程了,组装完成后:


2.jpg


二、调试光谱传感器


接线图.png


将LED灯的正负极对应接到板子的正负极上点亮小灯,光谱传感器按照上图连接,然后烧录代码:


[C++] 纯文本查看 复制代码
/*!
 * @file getData.ino
 * @brief 读取光谱传感器10个光通道的数值,光源的某波长的光越多,对应通道的数值越大
 * 
 * @copyright   Copyright (c) 2010 DFRobot Co.Ltd (http://www.dfrobot.com)
 * @licence     The MIT License (MIT)
 * @author [fengli](li.feng@dfrobot.com)
 * @version  V1.0
 * @date  2020-07-16
 * @get from https://www.dfrobot.com
 * @url https://github.com/DFRobot/DFRobot_AS7341
 */
#include "DFRobot_AS7341.h"
/*!
 * @brief Construct the function
 * @param pWire IC bus pointer object and construction device, can both pass or not pass parameters, Wire in default.
 */
DFRobot_AS7341 as7341;

void setup(void)
{
  Serial.begin(115200);
  //检测IIC是否能正常通信
  while (as7341.begin() != 0) {
    Serial.println("IIC初始化失败,请检测连线是否正确");
    delay(1000);
  }
//  //Integration time = (ATIME + 1) x (ASTEP + 1) x 2.78µs
//  //设置寄存器ATIME的值,通过该值可计算Integration time的值,该值表示读取数据过程中必须要消耗的时间
//  as7341.setAtime(29);
//  //设置ASTEP寄存器的值,通过该值可计算Integration time的值,该值表示读取数据过程中必须要消耗的时间
//  as7341.setAstep(599);
//  //设置增益(0~10对应 X0.5,X1,X2,X4,X8,X16,X32,X64,X128,X256,X512)
//  as7341.setAGAIN(7);
//  //使能LED
//  //as7341.enableLed(true);
//  //设置引脚电流控制亮度(1~20对应电流 4mA,6mA,8mA,10mA,12mA,......,42mA)
//  //as7341.controlLed(10);

}
void loop(void)
{
  DFRobot_AS7341::sModeOneData_t data1;
  DFRobot_AS7341::sModeTwoData_t data2;


  //开始光谱的测量.
  //通道映射的模式 :1.eF1F4ClearNIR,2.eF5F8ClearNIR
  as7341.startMeasure(as7341.eF1F4ClearNIR);
  //读取传感器数据通道0~5的值,eF1F4ClearNIR模式下.
  data1 = as7341.readSpectralDataOne();

  Serial.print("F1(405-425nm):");
  Serial.println(data1.ADF1);
  Serial.print("F2(435-455nm):");
  Serial.println(data1.ADF2);
  Serial.print("F3(470-490nm):");
  Serial.println(data1.ADF3);
  Serial.print("F4(505-525nm):");   
  Serial.println(data1.ADF4);
  //Serial.print("Clear:");
  //Serial.println(data1.ADCLEAR);
  //Serial.print("NIR:");
  //Serial.println(data1.ADNIR);
  as7341.startMeasure(as7341.eF5F8ClearNIR);
  //读取传感器数据通道0~5的值,eF5F8ClearNIR模式下.
  data2 = as7341.readSpectralDataTwo();
  Serial.print("F5(545-565nm):");
  Serial.println(data2.ADF5);
  Serial.print("F6(580-600nm):");
  Serial.println(data2.ADF6);
  Serial.print("F7(620-640nm):");
  Serial.println(data2.ADF7);
  Serial.print("F8(670-690nm):");
  Serial.println(data2.ADF8);
  Serial.print("Clear:");
  Serial.println(data2.ADCLEAR);
  Serial.print("NIR:");
  Serial.println(data2.ADNIR);
  delay(1000);
}


在比色皿中什么都没加入的情况下,打开串口监视器后,可以观察到数据中,F7波段的光强度最高,因此我们将采用F7波段光的强度作为参考,记录F7的数据。



图片1.png

三、实验

接下来我们通过一个实验来记录几组数据。需要准备6个烧杯(或其他容器),一些染料。

1.将6个烧杯中都倒入100ml的清水准备好


清水.jpg

2.将染料按照一定比例加入6个清水的烧杯中,第一杯不加,第二杯加入1滴,第三杯加入2滴,第四杯加入3滴,第五杯加入4滴,第六杯加入5滴。


混入染料.jpg

3.将6个烧杯中的溶液搅拌好,分别倒入到比色皿中进行数据测量,为保证数据准确性,每一次更换溶液时要将比色皿清洗干净,并将测量出的数据记录到excel表格中。

动图.gif

实验数据.jpg


四、分析数据

通过观察数据,我们可以看到随着染料浓度越来越高,F7的强度就变得越来越低,我们假设每滴入一滴染料会使浓度增加15%,所以我们的六次数据可以拟合成一条浓度0%-75%的曲线。接下来我们就在Excel中将这条曲线拟合出来。

1.首先选中浓度一行的数据,然后选中F7一行的数据,最后点击创建散点图。


创建图.png

2.在出现的散点图中任选一点右键,选择添加趋势线,趋势线选项选择一个最贴合数据点的曲线,最后显示公式,这样就可以得到最终拟合出的公式了。我获得的公式是:y = 2E-06x2 - 0.0257x + 70.525。


拟合曲线.jpg

五、屏幕直接显示未知的浓度

将上一步的公式直接带入到代码中,在代码中添加代码:*outdata=(0.000002data2.ADF7data2.ADF7-0.0257data2.ADF7+70.525);**

然后加入对应的显示屏的库文件,以及修改显示部分的代码,教程最后的附件中会给出最终的代码和需要的库。


[C++] 纯文本查看 复制代码
#include "DFRobot_AS7341.h"
#include <DFRobot_SSD1306_I2C.h>

const chCode chBuf[] = {
  {0x6d53,0xe6b593,0xC5A8,{0x00,0x40,0x20,0x40,0x10,0x40,0x17,0xfc,0x84,0x84,0x48,0x88,0x41,0x40,0x11,0x44,0x13,0x48,0x25,0x30,0xe9,0x20,0x21,0x10,0x21,0x08,0x21,0x44,0x21,0x82,0x01,0x00}},
  {0x5ea6,0xe5baa6,0xB6C8,{0x01,0x00,0x00,0x80,0x3f,0xfe,0x22,0x20,0x22,0x20,0x3f,0xfc,0x22,0x20,0x22,0x20,0x23,0xe0,0x20,0x00,0x2f,0xf0,0x24,0x10,0x42,0x20,0x41,0xc0,0x86,0x30,0x38,0x0e}}
};

DFRobot_AS7341 as7341;
DFRobot_SSD1306_I2C oled12864;
double outdata;
void setup(void)
{
  Serial.begin(115200);
  oled12864.begin(0x3c);
  //检测IIC是否能正常通信
  while (as7341.begin() != 0) {
    Serial.println("IIC初始化失败,请检测连线是否正确");
    delay(1000);
  }
}
void loop(void)
{
  DFRobot_AS7341::sModeOneData_t data1;
  DFRobot_AS7341::sModeTwoData_t data2;


  //开始光谱的测量.
  //通道映射的模式 :1.eF1F4ClearNIR,2.eF5F8ClearNIR
  as7341.startMeasure(as7341.eF1F4ClearNIR);
  //读取传感器数据通道0~5的值,eF1F4ClearNIR模式下.
  data1 = as7341.readSpectralDataOne();

  Serial.print("F1(405-425nm):");
  Serial.println(data1.ADF1);
  Serial.print("F2(435-455nm):");
  Serial.println(data1.ADF2);
  Serial.print("F3(470-490nm):");
  Serial.println(data1.ADF3);
  Serial.print("F4(505-525nm):");   
  Serial.println(data1.ADF4);
  //Serial.print("Clear:");
  //Serial.println(data1.ADCLEAR);
  //Serial.print("NIR:");
  //Serial.println(data1.ADNIR);
  as7341.startMeasure(as7341.eF5F8ClearNIR);
  //读取传感器数据通道0~5的值,eF5F8ClearNIR模式下.
  data2 = as7341.readSpectralDataTwo();
  Serial.print("F5(545-565nm):");
  Serial.println(data2.ADF5);
  Serial.print("F6(580-600nm):");
  Serial.println(data2.ADF6);
  Serial.print("F7(620-640nm):");
  Serial.println(data2.ADF7);
  Serial.print("F8(670-690nm):");
  Serial.println(data2.ADF8);
  Serial.print("Clear:");
  Serial.println(data2.ADCLEAR);
  Serial.print("NIR:");
  Serial.println(data2.ADNIR);
  delay(1000);
  outdata=(0.000002*data2.ADF7*data2.ADF7-0.0257*data2.ADF7+70.525);
  Serial.print("浓度:");
  Serial.println(outdata);

  oled12864.setChCode(chBuf);

  oled12864.setCursor(1, 1);
  oled12864.print("浓度");
  oled12864.setCursor(110, 1);
  oled12864.print("%");
  oled12864.setCursor(40, 1);
  oled12864.print(outdata);
}

最后我随意混合了一些溶液装入了比色皿中


测试溶液.jpg

将比色皿放入我们的仪器中,可以通过屏幕直接读取到溶液的浓度


end.jpg


该传感器还在内测没有上架,感兴趣的小伙伴可以关注一下DF商城,很快就要上架了,官方wiki链接:http://wiki.dfrobot.com.cn/_SKU_SEN0365_AS7341_Visible_Light_Sensor

库文件和代码.zip (27.55 KB, 下载次数: 7)

wcm_e45  高级技匠

发表于 2020-10-13 15:39:06

高级啊, 能不能对不同的玉米油做个比对啊,能不能查地沟油啊,哈!
回复

使用道具 举报

柳春晓  中级技师
 楼主|

发表于 2020-10-14 09:26:51

wcm_e45 发表于 2020-10-13 15:39
高级啊, 能不能对不同的玉米油做个比对啊,能不能查地沟油啊,哈!

可以的,你这个点子非常棒
回复

使用道具 举报

微笑的rockets  NPC

发表于 2020-10-16 11:12:04

wcm_e45 发表于 2020-10-13 15:39
高级啊, 能不能对不同的玉米油做个比对啊,能不能查地沟油啊,哈!

这个需要做实验,不确定他们的光谱吸收特性。
不过这是一个非常好的想法,建议实际的测一下。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

为本项目制作心愿单
购买心愿单
心愿单 编辑
[[wsData.name]]

硬件清单

  • [[d.name]]
btnicon
我也要做!
点击进入购买页面
上海智位机器人股份有限公司 沪ICP备09038501号-4

© 2013-2020 Comsenz Inc. Powered by Discuz! X3.4 Licensed

mail