第二周进度报告 arduino传感器程序编写及调试

来源:互联网 发布:网络教育大专,自考本科 编辑:程序博客网 时间:2024/05/19 19:33

    第二周也过去了,这周算是正式步入正轨了,经过前一阶段的学习和联系,我也基本掌握了arduino的基础,也知道了各种传感器的原理,学到了很多的东西,也终于正式开始做项目了,有些小激动。

    这周编写了很多的传感器程序,有风速风向、粉尘、紫外线、光照、温湿度、土壤还有LCD显示器等,最后再把它们的程序写在一起,最后在一块arduino UNO控制器上集中到一起,并通过LCD来显示他们的数据。

     总体上来说编程上还是没遇到什么大问题,找了些资料,了解了各种函数库和函数的用法,在找到各个传感器的相应公式,传感器的程序也就有了大概的框架,不同的只是在传感器上的一些细节差别。

    一 。传感器及部件学习:

       传感器都是一些很神奇的东西,只要用些公式就可以简单的计算数据了,但我不应该只局限在知其然不知其所以然的境界,我应该得了解各个传感器的原理,这样在遇到问题时才有很好的解决思路。

    这些传感器有些很简单,有些又很复杂其中不乏让我花费了大量时间的传感器。下面来说说各个传感器的编写经历和学到的相关知识。

    1、光照传感器:光照传感器核心原理就是通过光敏电阻或者光敏二极管三极管来感应光的大小强度,将其感应到的光照强度转化成电压,最后输出电压。光敏电阻体就是在电极上加上电压,设备开启电极间有电流流通,受到适当波长光线照耀时,电流就会随着光照强度的变化而变化,从而实现光电的转化。我使用的传感器就为光敏电阻器电源为3—5V电压驱动,直接可以使用UNO控制器的电源驱动,传感器内置16bitAD转换器,遵守标准NXP IIC通信协议,模块内部包含通信电平转换,与5V单片机Io直接连接,Features I2C 总线接口(f / s模式支持),使用非常方便,而且光源的依赖性不大(例如白炽灯.荧光灯.卤素灯.白LED),小测变异(+/- 20%)13)的红外线的影响很小.处理值也很精确。

      编程比较简单,需要添加一个BH1750FVI和Wire的函数库,再调用SetAddress,SetMode、GetLightIntensity等几个函数得到需要的电压值,并通过转化器和换算得到需要的光照强度。 


示例程序:

             

#include <Wire.h>                     //IIC连接库#include <BH1750FVI.h>               //光照的库函数BH1750FVI LightSensor;               //定义光照对象void setup() {     Serial.begin(9600);                //设置串口频率  LightSensor.begin();               //对象LightSensor以主机身份加入通信 
 LightSensor.SetAddress(Device_Address_H);  //设置通信地址  LightSensor.SetMode(Continuous_H_resolution_Mode); //设置引脚
    Serial.println("Running...");           //初始化完成提示语}void loop() {  // put your main code here, to run repeatedly:   uint16_t lux = LightSensor.GetLightIntensity();// 得到紫外线的值  Serial.print("Light: ");                     //串口输出提示信息和值  Serial.print(lux);  Serial.println(" lux");  delay(1000);}

    2、风向传感器:风向传感器有一个风向信号发生装置,由风标转轴带动一个有6个格雷码光盘的发生装置,发生装置内部每个光盘有6位格雷码,相邻的部分做了透光于不透光处理。通过位于码盘两侧同一半径上6对光电耦合器输出相应的6位格雷码,码盘上安装了36个红外发光二极管下面有6个光电转换器,都正对码盘的6个轨道。风向变动,码盘下面的光电管接收到的电码发生变化,每一个格雷码代表一个风向,分辨率为5,61.4度。

         此外风向公式为:  WD(风向)  = K(分辨率)* GM(格雷码) 。   //格雷码算法

                                           WD风向值=(输出电压-0.4)/16*360          //电压算法,输出电压上升0.1V对应风向顺时针转移一个方向

         传感器有格雷码、电压、电流三种输出方式,因为我使用的UNO控制器对电压的处理非常方便,所以使用此款arduino风向传感器, 风向传感器的规格为输入电压7~24V,输出电压为0.4~2v,  编程时要通过公式换算,将0.4~2v的输出电压模拟成控制器的0~5v输入电压范围。

char* dirstring[16] = {"North","North1","Northeasterly","Northeasterly1","East","East1","Southeast","Southeast1","South","South1","Southwest","Southwest1","West","West1","Northwest","Northwest1"};       //设置16个风向void setup() {  Serial.begin(9600);}void loop() {  int sensorValue1 = analogRead(A0);                  //读取风向传感器  float value1 = sensorValue1 * (5.0 / 1024.0);         //换算公式,得到值//Serial.println(value1);  int winddirection =( value1 *10) ;                         winddirection = winddirection - 4 ;                 //减去传感器自身电压底限值  Serial.println(winddirection);                  //提示信息//   if(winddirection < 0)//   winddirection = 0;  // if(winddirection > 15) //  winddirection = 15;    Serial.print("winddirection is "); if(winddirection == 0 || winddirection == 15 )       //解决电压误差问题   { Serial.println( dirstring[0] );}  else    { Serial.println( dirstring[winddirection] );} delay(500);}


    3、风速传感器: 风速传感器内部有一个光电子风速计,中心有不锈钢转动轴,内部连接了一个光盘,内部还有红外光速,不锈钢转动轴带动光盘转动,切割红外来实现计算风速。当风推动传感器上的碗推动转动轴,转动轴带动光盘转动,光盘每转动一次切割红外14次,从而有光电晶体产生一个脉冲链,实现信号的发生。脉冲链的速率与风速成正比。

         风速换算公式: ws(风速m/s)  =  Vo(初始风速)  -  f(F)( 每秒计数值)

        风速传感器是看着比较好玩,我也挺喜欢的玩的一个传感器之一,不过也是很简单的传感器,只要用控制器得到传感器的电压在通过公式运算就可以得到风速。

    

void setup() {  Serial.begin(9600);}void loop() {  int sensorValue = analogRead(A2); // Serial.println(sensorValue);  float value = sensorValue * (5.0 / 1024.0);//  Serial.println(value);  float fanspeed = value - 0.4 ; // Serial.print( fanspeed );  fanspeed = fanspeed * 1.6*32.4 ;  Serial.print("fanspeed is ");  Serial.print( fanspeed );  Serial.println( "m/s" ); delay(500);}

     4、温湿度传感器:温湿度传感器原理有三种:

                              热电阻:根据金属丝电阻随温度变化原理工作;

                             热电偶:两种导体接触块结点处稳定电势;同导体两端温度同两端间定电势;

                             液体温度计:利用温液体受热膨胀原理工作。

          三种传感器都是通过自身感应原理将感应到的温湿度信息转化成数据信号,在通过相应的公式换算成有实际意义的数据值。其中电阻式感应器比较常用。

         我使用的是TH22数字温湿度传感器,DHT22数字温湿度传感器是一款含有已校准数字信号输出的温湿度复合传感器。传感器包括一个电容式感湿元件和一个NTC测温元件,并与一个高性能8位单片机相连接。单线制串行接口,系统集成十分简易快捷,连接方便,可直接插接到Arduino传感器扩展板上。

          温湿度传感器的编程和连线都很简单,需要DHT22的函数库,需要函数读取传感器传出的值就ok了。


       5、土壤温湿度传感器:土壤型温湿度传感器的基本检测原理与温湿度传感器基本原理相似,只不过土壤温湿度传感器的工作环境为湿度较高的土壤,为了保护感应原件和确保数据的准确性,所以得添加特殊的保护装置。

            我使用的数字温湿度传感器系列中土壤型专用传感器,它把传感元件和信号处理集成起来,输出全标定的数字信号。传感器包括一个电容性聚合体测湿敏感元件、一个用能隙材料制成的测温元件,并在同一芯片上,与14 位的A/D 转换器以及串行接口电路实现无缝连接。每个传感器芯片都在极为精确的湿度腔室中进行标定,校准系数以程序形式储存在OTP 内存中,在标定的过程中使用。传感器在检测信号的处理过程中要调用这些校准系数。两线制的串行接口与内部的电压调整,使外围系统集成变得快速而简单。

          数字温湿度传感器除了常规的VCC和GND接口外,特殊的接口为:黄色 SCK 时钟 信号  兰色 D ATA  数据输出。数字温湿度传感器除了探测温湿度外还可以计算露点。

#include <Sensirion.h>const uint8_t dataPin  =  2;    //定义数据接口<span style="white-space:pre"></span>const uint8_t clockPin =  3;       //时钟接口float temperature;            //温度float humidity;                //湿度<span style="white-space:pre"></span>
float dewpoint;           //露点
Sensirion tempSensor = Sensirion(dataPin, clockPin);      //创建一个温湿度对象void setup(){  Serial.begin(9600);}void loop(){  tempSensor.measure(&temperature, &humidity, &dewpoint);  //使用对象内部函数获得数据  Serial.print("Temperature: ");       //显示数据  Serial.print(temperature);  Serial.print(" C, Humidity: ");  Serial.print(humidity);  Serial.print(" %, Dewpoint: ");  Serial.print(dewpoint);  Serial.println(" C");    delay(5000);  }


    6、粉尘传感器:一般粉尘传感器的原理大致为:外部含尘空气吸引下进入吸引口,经导流装置(遮掉外部光线)进入检测器暗室。暗室内的平行光与受光部的视野成直角交叉构成灵敏区(图中斜线部分),粉尘通过灵敏区时,其90℃方向散射光透过狭缝射进来由光电倍增管接收并转换成光电流,经光电流积分电路转换成与散射光成正比的脉冲电信号,计算出粉尘的质量浓度信号输出。

         我使用的是PPD42NS粉尘传感器,该传感器为PWM方式输出,结构紧凑,重量轻,光学原理,能够探测1微米以上的粉尘粒子。此外,这个传感器还有两种输出模式,解决不同灵敏度使用要求,洁净环境Vout输出高电平信号(4V)。对应的接线为VCC->PIN3,GND->PIN1,受控角->pin5;而pin2和pin4则为两种模式输出,pin4为设定好的信号输出脚,最小检测颗粒为1μm,而pin2则为可调灵敏度输出教,默认的灵敏度为最小2.5μm,可以通过pin5控制脚来手动调节灵敏度。此外,粉尘传感器的运行周期大约为30S,

30S为一个读取粉尘的周期

int pin = 8;unsigned long duration;unsigned long starttime;unsigned long sampletime_ms = 30000;unsigned long lowpulseoccupancy = 0;float ratio = 0;float concentration = 0;void setup() {  Serial.begin(9600);  pinMode(8,INPUT);  starttime = millis();}void loop() {  duration = pulseIn(pin, LOW);                   //duration 为输入的电压值  lowpulseoccupancy = lowpulseoccupancy+duration;   // 电压值  if ((millis()-starttime) > sampletime_ms)          //如果运行时间大于30S执行  {    ratio = lowpulseoccupancy/(sampletime_ms*10.0);  // Integer percentage 0=>100    ratio比值 = 运行时间/300.0s    concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve 使用规范曲线计算值    Serial.print(ratio);             //比值    Serial.print(",");    Serial.println(concentration);   //计算值    lowpulseoccupancy = 0;    starttime = millis();  }}


  

   7、紫外线传感器:紫外线传感器由于非常简单,所以是做得最快的一个,主要麻烦的是在编程方面,紫外线传感器会根据外界紫外线的强度输出一个电压值,通过arduino板子读取其引脚所输出的电压,在经过一定的换算即可得到想要的紫外线强度的值。我们用analogRead()函数读取其引脚的电压值。在这里需要注意的是,紫外线的级数,从紫外线传感器读取的电压值,还需要经过转换才能得到紫外线强度。
        紫外线传感器主要功能是采集空气中紫外线强度,这里使用UVM-30A紫外线传感器模块,具有准确度高,造价相对较低的特点。 使用时,将其“+”号接口接到arduino UNO板子的5v接口上,将其“—”号接口接到arduinoUNO 板子上的GND接口上,将其”out“号接口接到板子的A0引脚上,插上电源,把事先写好的程序下载到板子上,一个紫外线传感器就接好了。
       

void setup(){  pinMode(3,INPUT);  Serial.begin(9600);}void loop(){ int  a= analogRead(3);     //读取传感器返回电压值 if(0<=a && a<=50) {   Serial.print("The UV index is:    ");    //给各种不同返回值设置紫外线等级   Serial.println(0); } else if(50<a && a<=227){   Serial.println("The UV index is:    ");   Serial.print(1); } else if(227<a && a<=318) {   Serial.print("The UV index is:    ");   Serial.println(2); } else if(318<a && a<=408) {   Serial.print("The UV index is:    ");   Serial.println(3); } else if(408<a && a<=503) { Serial.print("The UV index is:    ");   Serial.println(4); } else if(503<a && a<=606) { Serial.print("The UV index is:    ");   Serial.println(5); } else if(606<a && a<=696) { Serial.print("The UV index is:    ");   Serial.println(6); } else if(696<a && a<=795) { Serial.print("The UV index is:    ");   Serial.println(7); } else if(795<a && a<=881) { Serial.print("The UV index is:    ");   Serial.println(8); } else if(881<a && a<=976) { Serial.print("The UV index is:    ");   Serial.println(9); } else if (976<a && a<=1079) { Serial.print("The UV index is:    ");   Serial.println(10); } else  { Serial.print("The UV index is:    ");   Serial.println(11); }  delay(1000);}


      8、lcd显示器:LCD等显示器都是由多个显示点构成,通过每个显示点显示不同的颜色来实现显示文字和图案的功能。迷你12864液晶显示模块这款模块SPI为接口的显示模块,配合12864LCD库文件,便可轻松显示汉字,字符和图形。并有背光LED控制,可使显示效果更美观。可显示128列×64行点阵单色图片,可显示16×16点阵和12×12点阵汉字及图片,可显示8字/行×4行(16×16点阵汉字),可显示16字/行×8行(8×8点阵的英文、数字、符号)。采用3线SPI串行接口以及一条命令/数据控制线,最多只需5个端口(3线SPI接口加命令/数据控制线,再加上复位信号线)。

   

#include "U8glib.h"U8GLIB_MINI12864 u8g(13, 11, 10, 9, 8); //SPI Com: SCK = 13, MOSI = 11, CS = 10, A0 = 9 ,RST=8;void draw(void) {  u8g.setFont(u8g_font_unifont);  u8g.drawStr( 0, 22, "temperture:  ");   u8g.drawStr( 0, 40, "32");  }void setup(void) {  }void loop(void) {  u8g.firstPage();    do {    draw();  } while( u8g.nextPage() );    delay(500);}

       引脚定义:
            标示符号   名 称          功 能
                    R     RESET        低电平复位,复位完成后,回到高电平,液晶模块开始工作。如果不需软件给芯片复位,可不连接
                    A         A0             数据和命令选择。L:命令 H:数据
                   CS       CS            SPI 片选(内部已拉高),低有效
                   C         SCK           串行时钟
                   D     MOSI(SID)  数据传输
                   -        GND           电源地
                   +         VCC            DC 3.3V~5.5V
                    L        LED            背光LED使能,低有效

                该显示器要使用必须得添加Lcd12864或者u8g库文件。

               Lcd12864是点阵式显示,只能显示点阵信息,可以用于显示图片,但是需要下载一个字模软件,设计一个 128×64 的字符点阵图形。字模软件可以手动输入或是自画,还可以引用pin格式的图画画点阵,字模软件将输入的信息转化成字符点阵图形后就可以使用Lcd12684库函数调用来显示信息和图片了。使用该函数库得遵守spi协议。

               u8g库文件主要是针对显示数据而设计,使用u8g函数可以很方便的显示浮点数,字符串等数据,还可以灵活的设置显示位置,非常方便。不过值得注意,使用u8g后,要显示数据调用print函数之前还得先调用设置字体和设置显示位置u8g.setFont (); u8g.setPrintPos ();的函数。



       二。问题及解决总结:

     

            这一周的进度感觉很快,但是其中也有很多问题需要总结:
            1、第一个遇到的问题就是粉尘传感器的问题,因为刚开始没有详细的手册,资料没找好、没彻底弄清传感器的原理和规格,不知道除了VCC和GND外的三根线哪些是数据输出,应该使用哪一根作为信号传输线,后来通过请教了解了线的问题。测试出的数据又过大,粉尘数过多,而且起伏很大,与一般实测数据差别过大,最后通过滤波和更改公式等方式解决。
           2、LCD:lcd是让我花费时间最多的一个部件。
                 最开始根据教程资料我只知道lcd12864函数库,只是使用lcd12864函数库,全部转换成点阵输出,无法输出数据,让我半筹莫展。后来又下载了u8g函数库,但也只知道部分函数,输出函数只知道drawStr(x,y,string)函数。其中参数x,y用于指定字符的显示位置。由于只能输出字符串,所以我就像办法将数据转换成字符串,将整形和浮点数转换成字符串。
                将整形和浮点数转换成字符串,所以我用到了C语言的函数库stdilib函数库,以及fcvt()函数将浮点型值转换为字符串、itoa()  将整型值转换为字符串。fcvt()函数有4个参数:第一个参数是要转换的浮点型值;第二个参数是转换结果中十进制小数点右侧的位数;第三个参数是指向一个整数的指针,该整数用来返回转换结果中十进制小数点的位置;第四个参数也是指向一个整数的指针,该整数用来返回转换结果的符号(0对应于正值,1对应于负值)。ecvt()    将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点。 gcvt()    将双精度浮点型值转换为字符串,转换结果中包含十进制小数点。
              花费了大量时间转换后,后来也算是勉强将数据显示出来,不过在使用上还是有很大局限,使用非常不方便。后来在无意的翻书中发现u8g还有另一个数据输出函数print(),这个函数及可以输出字符串,可以输出整形浮点型数据。使用这个函数后使用非常方便,这也算是一次小小的插曲吧。

          3、采集终端调试问题:我打算将各个数据采集感应器集中到一个控制器上,我把各个传感器程序编写完成以后一一进行了测试,所有的程序也没发现问题。接下来我就把所有的程序融合在一起,最后一步就是各个感应器的组装。

               由于风速风向感应器需要外界电源,但是外接电源接口还没有弄好,所以我前一天只测试了不要外接电源的粉尘、温湿度,紫外线等数据传感器,将它们组装在一起。第二天我在将剩下的风速风向传感器集中到一起,由于前一天已经将其余的传感器组装到控制器上,所以第二天我只是将传感器信号引脚添加到控制器之上,风速风向的外接电源则接在扩展版之上,而扩展版却没有接在控制器上。我测试出来的风速风向数据始终不正确,以为是程序问题,又不断修改程序,后来发现毫无斩获,又将程序分开来测试运行,将风速风向的程序单独写在加了扩展版的控制器上,发现数据又毫无问题。最后我用测试传感器电压的方法测试传感器电压,发现传感器发出的脉冲信号又无问题。

              最后通过请教导师才发现原来是因为扩展版没有插在主控制器上,导致传感器只接通了电源的负极而没有接通控制器的GND,在主控器上没有形成电流回路,所以无法正确接收到传感器发出的脉冲电流信号。同过导师的点播让我明白了控制器接收脉冲信号的原理,只有在控制器上形成回路,脉冲才在控制器固定的电路上流动,控制器电路上用于读取脉冲信号的电子原件才能读到信号,也才能采集到数据,也算是吃一堑长一智有些收获吧。

          4、点亮Lcd控制器背光灯:突然在一次小测试里发现lcd的背光引脚只是在setup()里设置了引脚为输出模式,在loop里却没有写输出高低电压或是模拟电压的输出语句,但是lcd却神奇的亮了,重复写入程序防止误差也是同样的结果还是一样,到现在也还没有找到原因。

         三。 计划安排:
                              下周主要是对前期的进度进行一些总结,看会书,规范一下自己程序以便传到code上,还计划动手做由无线串口和GPRS模块组成的中间传输节点。

1 0
原创粉丝点击