个人微型气象站搭建终极范例教程

发布于: 27 January, 2014
分享:

//@微型气象站 //@光照度传感器(I2C)、温湿度传感器(One Wire)、地磁气压温度传感器(I2C) //@锂电池保护模块、太阳能锂电池充电模块、时钟日历芯片、EEPROM储存芯片、无线口透传模块 //@MCU:ATmega328P //@电压:锂电3.7V,可直接使用5V外接电源,但不可与锂电一同使用,太阳能充电输入电压4.35~6V

//@实测电流(锂电池): //@MCU运行,未在测量,无线模块开启:31.9mA //@MCU休眠,无线模块休眠,传感器闲置:450uA

////加载外部库//////////////////////////////////////////////

#include     //I2C库(Arduino自带库) #include      //I2C库(Arduino自编库)

////测试用按钮、LED//////////////////////////////////////////////

#define Test_Button_Pin 3  //测试按钮针脚位 #define Test_LED_Pin    15  //测试LED针脚位

////电压//////////////////////////////////////////////

#define Voltage_Pin 0  //电压值读取针脚位,A0 #define Voltage_Read() (97.8851.1analogRead(Voltage_Pin)/1023)  //读取电压值并计算终值,100倍于原值,选择片内1.1V基准电压源 //分压电阻精度误差调整系数分压电阻比例(75K+300K,最高检测电压5.5V)标准电压值检测读数/1023 + 输入二极管压降(实测0.224-0.336V) unsigned int Voltage_Result = 0;  //电压值,100倍于原值

////BH1751FVI光照度芯片//////////////////////////////////////////////

#define I2C_Address_BH1751FVI 0x23    //BH1751FVI芯片I2C地址转换为7位地址 unsigned char BH1751FVI_Mode = 0x11;  //测量模式 /* 0x10 连续高分辨率模式 在1lx 分辨率下开始测量,测量时间一般为120ms,最大180ms 0x11 连续高分辨率模式2 在0.5lx 分辨率下开始测量,测量时间一般为120ms 0x13 连续低分辨率模式 在41lx 分辨率下开始测量,测量时间一般为16ms,最大24ms 0x20 一次高分辨率模式 在1lx 分辨率下开始测量,测量时间一般为120ms,测量后自动设置为断电模式 0x21 一次高分辨率模式2 在0.5lx 分辨率下开始测量,测量时间一般为120ms,测量后自动设置为断电模式 0x23 一次低分辨率模式 在41lx 分辨率下开始测量,测量时间一般为16ms,测量后自动设置为断电模式 */ unsigned int BH1751FVI_Result = 0;    //测量结果

////BMP085气压计//////////////////////////////////////////////

#define I2C_Address_BMP085 0x77  //BMP085气压计芯片I2C地址 const unsigned char REG_BMP085_Command       = 0xF4;  //测量控制寄存器地址 const unsigned char Param_BMP085_Close       = 0x00;  //将芯片设置到断电状态 const unsigned char Param_BMP085_Open        = 0x01;  //将芯片设置到通电状态,等待测量指令 // const unsigned char Param_BMP085_Rest        = 0x01;  //重置数字寄存器 const unsigned char Param_BMP085_Temperature = 0x2E;  //温度,4.5ms // const unsigned char Param_BMP085_Pressure0   = 0x34;  //低精度气压,4.5ms // const unsigned char Param_BMP085_Pressure1   = 0x74;  //中精度气压,7.5ms // const unsigned char Param_BMP085_Pressure2   = 0xB4;  //高精度气压,13.5ms // const unsigned char Param_BMP085_Pressure3   = 0xF4;  //最高精度气压,25.5ms const unsigned char REG_BMP085_MSB           = 0xF6;  //测量值寄存器高位 // const unsigned char REG_BMP085_LSB           = 0xF7;  //测量值寄存器低位 // const unsigned char REG_BMP085_XLSB          = 0xF8;  //测量值寄存器低位

#define OSS 3  //气压采样精度设置,低精度到高精度 0~3

//校准值 int ac1; int ac2; int ac3; unsigned int ac4; unsigned int ac5; unsigned int ac6; int b1; int b2; int mb; int mc; int md; //b5用于计算BMP085_read_Temperature(),它也同时用于BMP085_read_Pressure() //所以BMP085_read_Temperature()必须放在BMP085_read_Pressure()之前 long b5;

int BMP085_Temperature = 0;  //温度值,10倍于原值 unsigned long BMP085_Pressure = 0;  //气压值(Pa)

////HMC5883L数字罗盘//////////////////////////////////////////////

#define I2C_Address_HMC5883L 0x1E  //HMC5883L数字罗盘芯片I2C地址 const unsigned char REG_HMC5883L_SetA   = 0x00;  //配置寄存器A地址 const unsigned char REG_HMC5883L_SetB   = 0x01;  //配置寄存器B地址 const unsigned char REG_HMC5883L_Mode   = 0x02;  //模式寄存器地址 const unsigned char REG_HMC5883L_X      = 0x03;  //X轴数据寄存器MSB地址 // const unsigned char REG_HMC5883L_Z      = 0x05;  //Z轴数据寄存器MSB地址 // const unsigned char REG_HMC5883L_Y      = 0x07;  //Y轴数据寄存器MSB地址 // const unsigned char REG_HMC5883L_Status = 0x09;  //状态寄存器地址 // const unsigned char REG_HMC5883L_IDA    = 0x10;  //识别寄存器A地址 // const unsigned char REG_HMC5883L_IDB    = 0x11;  //识别寄存器B地址 // const unsigned char REG_HMC5883L_IDC    = 0x12;  //识别寄存器C地址

const int HMC5883L_Declination = -4;  //磁偏角修正值

unsigned int HMC5883L_Result = 0;  //测量结果

////AM2302温湿度计//////////////////////////////////////////////

#define AM2302_Pin 9  //针脚位 unsigned int AM2302_Humidity = 0;  //湿度,10倍于原值 int AM2302_Temperature = 0;  //温度,10倍于原值

////EEPROM储存芯片//////////////////////////////////////////////

#define I2C_Address_EEPROM 0x53  //此处为AT24C256的地址

unsigned int        DATA_EEPROM_TotalKB    = 32;    //芯片总容量,AT24C256 - 32K unsigned int        DATA_EEPROM_DataUsed   = 0;     //已使用数据个数 const unsigned char DATA_EEPROM_DataLength = 24;    //每个数据长度,24字节 const unsigned int  DATA_EEPROM_DataFirst  = 0x20;  //首个数据地址

const unsigned int  REG_EEPROM_TotalKB     = 0x00;  //EEPROM芯片总容量(Kbyte),2字节 // const unsigned int  REG_EEPROM_DataLength  = 0x02;  //每个数据长度(Byte),1字节 const unsigned int  REG_EEPROM_DataUsed    = 0x03;  //已使用数据个数,2字节 // const unsigned int  REG_EEPROM_DataFirst   = 0x05;  //首个数据地址,2字节 const unsigned int  REG_EEPROM_LastPowerOn = 0x07;  //最后开机时间,6字节

////PCF8563时钟芯片//////////////////////////////////////////////

#include   //PCF8563库 Rtc_Pcf8563 PCF8563; #define PCF8563_Pin 2  //PCF8563时钟芯片报警中断脚

// #define I2C_Address_PCF8563  0x51  //PCF8563时钟芯片I2C地址 // #define REG_PCF8563_Year   0x08  //年 // #define REG_PCF8563_Month  0x07  //月 // #define REG_PCF8563_Week   0x06  //周 // #define REG_PCF8563_Day    0x05  //日 // #define REG_PCF8563_Hour   0x04  //时 // #define REG_PCF8563_Minute 0x03  //分 // #define REG_PCF8563_Second 0x02  //秒 // #define REG_PCF8563_Alarm_Week   0x0C  //报警-周 // #define REG_PCF8563_Alarm_Day    0x0B  //报警-日 // #define REG_PCF8563_Alarm_Hour   0x0A  //报警-时 // #define REG_PCF8563_Alarm_Minute 0x09  //报警-分 // #define REG_PCF8563_Control_1    0x00  //控制状态1 // #define REG_PCF8563_Control_2    0x01  //控制状态2 // #define REG_PCF8563_Frequency    0x0D  //频率寄存器 // #define REG_PCF8563_Timer_1      0x0E  //定时器1寄存器 // #define REG_PCF8563_Timer_2      0x0F  //定时器倒计数寄存器

// unsigned char Time_year, Time_month, Time_day, Time_hour, Time_minute, Time_sec;

////模块电源MOS开关//////////////////////////////////////////////

#define PowerSwitch_Pin_EEPROM 8  //EEPROM电源开关 针脚位 #define PowerSwitch_Pin_Sensor 7  //传感器电源开关 针脚位 #define PowerSwitch_Pin_Radio  6  //无线模块电源开关 针脚位

#define Open_EEPROM()  {digitalWrite(PowerSwitch_Pin_EEPROM,HIGH);delay(10);}    //开EEPROM电源开关 #define Close_EEPROM() {delay(10);digitalWrite(PowerSwitch_Pin_EEPROM,LOW);}     //关EEPROM电源开关 #define Open_Sensor()  {digitalWrite(PowerSwitch_Pin_Sensor,HIGH);delay(1000);}  //开传感器电源开关 #define Close_Sensor() {digitalWrite(PowerSwitch_Pin_Sensor,LOW);}               //关传感器电源开关 #define Open_Radio()   {digitalWrite(PowerSwitch_Pin_Radio,HIGH);delay(2000);}   //开无线数传模块电源开关 #define Close_Radio()  {if(!PowerSwitch_Radio_Enable){delay(1000);digitalWrite(PowerSwitch_Pin_Radio,LOW);}}    //关无线数传模块电源开关

bool NoSleep = 0;  //是否强制不进入休眠模式 bool PowerSwitch_Radio_Enable = 0;  //是否强制无线模块电源一直开着

//串口部分////////////////////////////////////////////////

String comdata = "";  //串口读取数据值 unsigned int CommandVal = 0;   //串口命令值,0表示没有命令

//串口命令值 #define Command_EEPROM_AllAndEccAndClear       0x01  //传输所有数据(带CRC校验) #define Command_EEPROM_AllNoEccAndClear        0x02  //无确认传输所有数据 #define Command_EEPROM_AllNoEccNoClear         0x03  //无确认传输所有数据,不清除EEPROM数据 #define Command_EEPROM_AllNoEccNoClearFormat   0x04  //无确认传输所有数据,不清除EEPROM数据,格式化回传数据 #define Command_EEPROM_LastNoEccNoClearFormat  0x05  //无确认传输最后一个数据,不清除EEPROM数据,格式化回传数据 #define Command_ReadImmediately                0x06  //读当前数据并传输 #define Command_CurrentTime                    0x07  //传输当前时间 #define Command_SetTime                        0x08  //设置当前时间 // #define Command_EEPROM_LastPowerOn             0x09  //读最后开机时间 #define Command_EEPROM_Information             0x0A  //传输当前EEPROM信息 #define Command_EEPROM_TotalKB                 0x0B  //设置EEPROM芯片总容量(KByte) #define Command_EEPROM_Clear                   0x0C  //清空EEPROM中所有数据(将已使用数据个数写0) #define Command_PowerSwitch_Radio_OPEN         0x0D  //强制开启无线模块电源 #define Command_NoSleep                        0x0E  //强制不进入休眠模式 #define Command_EEPROM_WritePresent            0x0F  //将当前数据写入EEPROM

//////////////////////////////////////////////////

volatile bool IntTime = 0;    //判断是否产生时间中断 volatile bool IntButton = 0;  //判断是否按下按钮

//外部中断0//////////////////////////////////////////////// void Int_time()  //时钟唤醒中断 {  SMCR &= ~(1< 0)    {      while(Serial.available() > 0) //当串口有信息传入,读取之      {        comdata += char(Serial.read());        delay(2);      }      if(comdata.length() > 0)      {        //串口命令格式:头字($*)+ 命令数(2位数字);例:$01        if(comdata.substring(0,2) == "$") CommandVal = (comdata.substring(2,4)).toInt();  //命令头字        comdata = ""; //清空变量      }      if(CommandVal)  //如果有命令      {        Wireless(CommandVal);        CommandVal = 0;  //清空命令值      }

     _time = millis();  //重新开始超时循环    }

   if(IntTime)  //时钟中断发生    {      Sensor_Read();   //读取传感器数据      Open_Radio();    //打开无线模块电源      EEPROM_Write();  //把数据存入EEPROM

     //设置时钟芯片下次定时时间      PCF8563.setAlarm((PCF8563.getMinute()<30?30:0), 99, 99, 99);  //设置时钟芯片唤醒时间,分、时、日、周,设置为99时此位无效

     IntTime = 0;                            //告知程序已经出了时钟唤醒中断      attachInterrupt(0, Int_time, FALLING);  //重新打开时钟芯片中断

     _time = millis();  //重新开始超时循环    }

   if(IntButton)  //按钮被按下    {      Open_Radio();  //打开无线模块电源

     if(!NoSleep)  //进入无休眠、无线模块强制打开状态      {        NoSleep = 1;                   //打开强制无休眠模式        PowerSwitch_Radio_Enable = 1;  //打开强制开启无线模块模式

       Serial.println("No sleep.");        Serial.println();

       digitalWrite(Test_LED_Pin, 1);  //打开测试灯        delay(50);  //延时去毛刺,同时用于闪灯        digitalWrite(Test_LED_Pin, 0);  //关闭测试灯        delay(100);        digitalWrite(Test_LED_Pin, 1);  //打开测试灯        delay(50);  //延时去毛刺,同时用于闪灯        digitalWrite(Test_LED_Pin, 0);  //关闭测试灯      }      else  //进入正常状态      {        NoSleep = 0;                   //关闭强制无休眠模式        PowerSwitch_Radio_Enable = 0;  //关闭强制开启无线模块模式

       Serial.println("Sleep mode.");        Serial.println();

       digitalWrite(Test_LED_Pin, 1);  //打开测试灯        delay(100);  //延时去毛刺,同时用于闪灯        digitalWrite(Test_LED_Pin, 0);  //关闭测试灯        delay(500);      }

     IntButton = 0;  //按钮复位      attachInterrupt(1, Int_button, FALLING); //再次打开中断

     _time = millis();  //重新开始超时循环    }

   if((millis() - _time) > 30000) break;  //超时设置,30s内无串口命令则跳出循环进入休眠模式  }

 //启动MCU休眠模式,直到被外部中断唤醒(时钟芯片或串口读取到数据)  if(!NoSleep)  {    Serial.print(PCF8563.formatDate(2));    Serial.print(' ');    Serial.println(PCF8563.formatTime());    Serial.println("Sleep.");    Serial.println();

   PowerSwitch_Radio_Enable = 0;    //关闭强制开启无线模块模式    Close_Radio();                   //关闭无线模块    SMCR |= (1< 0)  //等待串口输入    {      _comdata += char(Serial.read());      delay(2);    }    if(_comdata.length() > 0) _Judge = 1;  //将判断字设为true退出循环  }

 return _comdata; }

//串口输出当前数据 void Print_CurrentData() {  //注意:需确保串口无线数传模块已经开启  Serial.print(PCF8563.formatDate(2));  Serial.print(' ');  Serial.println(PCF8563.formatTime());  Serial.print("Vol: ");  Serial.print(float(Voltage_Result)/100);  Serial.println(" V");  Serial.print("Tem: ");  Serial.print(float(AM2302_Temperature)/10);  Serial.println(" ^C");  Serial.print("Hum: ");  Serial.print(float(AM2302_Humidity)/10);  Serial.println(" %RH");  Serial.print("Pre: ");  Serial.print(BMP085_Pressure);  Serial.println(" Pa");  Serial.print("Lig: ");  Serial.print(BH1751FVI_Result);  Serial.println(" lx");  Serial.print("Geo: ");  Serial.print(HMC5883L_Result);  Serial.println(" ^");  Serial.println(); }

////开机校准方向//////////////////////////////////////////////

void Test_init() {  unsigned long _time = millis();  //用于超时

 Serial.print(PCF8563.formatDate(2));  Serial.print(' ');  Serial.println(PCF8563.formatTime());  Serial.println("Set dir.");  Serial.println();

 while(1)  {    HMC5883L_init();  //配置HMC5883L    HMC5883L_Read();  //读取地磁方向

   if(HMC5883L_Result%90 == 0) digitalWrite(Test_LED_Pin, 0);  //如果地磁在4个90度方向,关闭测试LED    else digitalWrite(Test_LED_Pin, 1);  //否则打开测试LED

   if(!digitalRead(Test_Button_Pin))  //按下测试按钮后退出    {      digitalWrite(Test_LED_Pin, 0);  //关闭测试灯

     Serial.println("Dir set OK.");      Serial.println();

     return;    }

   if(millis() - _time > 30000)  //如果操作时间大于30s,超时退出    {      digitalWrite(Test_LED_Pin, 0);

     Serial.println("Dir set OT.");      Serial.println();

     return;    }  } }

////读取传感器//////////////////////////////////////////////

void Sensor_Read() {  Open_Sensor();  //打开传感器电源  delay(2000);

 HMC5883L_init();  //配置HMC5883L  BMP085_init();    //读取BMP085的校准值

 PCF8563.getDate();  //获取当前日期  PCF8563.getTime();  //获取当前时间

 while(AM2302_Read() == 0);        //温、湿度值  BMP085_read_Temperature();        //温度(读大气压之前必须读此温度值,作为大气压校准)  BMP085_read_Pressure();           //大气压  BH1751FVI_Read();                 //光照度  HMC5883L_Read();                  //地磁方向  Voltage_Result = Voltage_Read();  //电压

 Close_Sensor();  //关闭传感器电源 }

////数据写入EEPROM//////////////////////////////////////////////

void EEPROM_Write() {  Open_EEPROM();  //打开EEPROM电源  delay(10);

 //写入地址=数据首地址 + 每个数据长度 * 当前已使用数据个数  DATA_EEPROM_DataUsed = I2C.read(I2C_Address_EEPROM, REG_EEPROM_DataUsed, 2);  //再次核对已使用数据个数  delay(10);  //EEPROM读写周期  unsigned int writeAdd = DATA_EEPROM_DataFirst + DATA_EEPROM_DataLength * DATA_EEPROM_DataUsed;

 //写入EEPROM  EEP.write(I2C_Address_EEPROM, writeAdd,    (unsigned char)PCF8563.getYear());    //年  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+1,  (unsigned char)PCF8563.getMonth());   //月  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+2,  (unsigned char)PCF8563.getDay());     //日  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+3,  (unsigned char)PCF8563.getHour());    //时  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+4,  (unsigned char)PCF8563.getMinute());  //分  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+5,  Voltage_Result);      //电压  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+7,  AM2302_Temperature);  //温度  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+9,  AM2302_Humidity);     //湿度  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+11, BMP085_Pressure);     //大气压  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+15, BH1751FVI_Result);    //光照度  delay(10);  //EEPROM写周期  EEP.write(I2C_Address_EEPROM, writeAdd+17, HMC5883L_Result);     //地磁方向  delay(10);  //EEPROM写周期

 DATA_EEPROM_DataUsed++;  //已使用数据个数增一位  EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //已使用数据个数写入EEPROM  delay(10);  //EEPROM读写周期

 //校验EEPROM写入数据(未写)

 Close_EEPROM();  //关闭EEPROM电源

 Print_CurrentData();  //串口输出当前数据  // Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.println(PCF8563.formatTime());  // Serial.println("EEPROM write OK.");  // Serial.println(); }

////读取EEPROM数据//////////////////////////////////////////////

void EEPROM_Read(unsigned int num, bool crc, bool clear, bool format) {  //如果EEPROM中没有数据  if(DATA_EEPROM_DataUsed == 0)  {    Serial.println("EEPROM no data.");  //传输出错信息    Serial.println();    return;  }

 String _date, _time;

 //读取地址 = 数据首地址 + 每个数据长度 * (需要读取的位数 - 1)  unsigned int ReadAdd = DATA_EEPROM_DataFirst + DATA_EEPROM_DataLength * (num - 1);

 //读EEPROM内容  _date = (String)I2C.read(I2C_Address_EEPROM, ReadAdd, 1);                  //年  _date = _date + '-' + (String)I2C.read(I2C_Address_EEPROM, ReadAdd+1, 1);  //月  _date = _date + '-' + (String)I2C.read(I2C_Address_EEPROM, ReadAdd+2, 1);  //日  _time = (String)I2C.read(I2C_Address_EEPROM, ReadAdd+3, 1);                //时  _time = _time + ':' + (String)I2C.read(I2C_Address_EEPROM, ReadAdd+4, 1);  //分  Voltage_Result     = I2C.read(I2C_Address_EEPROM, ReadAdd+5,  2);          //电压  AM2302_Temperature = (int)I2C.read(I2C_Address_EEPROM, ReadAdd+7, 2);      //温度(需转换为int类型)  AM2302_Humidity    = I2C.read(I2C_Address_EEPROM, ReadAdd+9,  2);          //湿度  BMP085_Pressure    = I2C.read(I2C_Address_EEPROM, ReadAdd+11, 4);          //大气压  BH1751FVI_Result   = I2C.read(I2C_Address_EEPROM, ReadAdd+15, 2);          //光照度  HMC5883L_Result    = I2C.read(I2C_Address_EEPROM, ReadAdd+17, 2);          //地磁方向

 //已使用数据个数减一位  if(clear)  {    delay(10);  //EEPROM读写转换周期    DATA_EEPROM_DataUsed--;    I2C.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //写入EEPROM    delay(10);  //EEPROM写周期  }

 //无线发送数据  if(format)  //发送格式化数据  {    Serial.print(_date);    Serial.print(' ');    Serial.println(_time);    Serial.print("Vol: ");    Serial.print(float(Voltage_Result)/100);    Serial.println(" V");    Serial.print("Tem: ");    Serial.print(float(AM2302_Temperature)/10);    Serial.println(" ^C");    Serial.print("Hum: ");    Serial.print(float(AM2302_Humidity)/10);    Serial.println(" %RH");    Serial.print("Pre: ");    Serial.print(BMP085_Pressure);    Serial.println(" Pa");    Serial.print("Lig: ");    Serial.print(BH1751FVI_Result);    Serial.println(" lx");    Serial.print("Geo: ");    Serial.print(HMC5883L_Result);    Serial.println(" ^");  }  else  //发送打包数据  {    Serial.print(_date);    Serial.print(',');    Serial.print(_time);    Serial.print(',');    Serial.print(float(Voltage_Result)/100);    Serial.print(',');    Serial.print(float(AM2302_Temperature)/10);    Serial.print(',');    Serial.print(float(AM2302_Humidity)/10);    Serial.print(',');    Serial.print(BMP085_Pressure);    Serial.print(',');    Serial.print(BH1751FVI_Result);    Serial.print(',');    Serial.println(HMC5883L_Result);

   //加CRC校验值    // if(crc)    // {    // unsigned char _CRC = 0;    // for(unsigned char i = 0; i < SendString.length(); i++) _CRC |= SendString.charAt(i);    // SendString += (String)_CRC;    // }  }  Serial.println(); }

////无线传输数据////////////////////////////////////////////// void Wireless(unsigned char command) {  //从最后一个数据开始回传,每传完一个数据就把EEPROM中的此位数据清除掉(仅减少一位数据位)  //命令:  // 1 - 传输所有数据(带CRC校验)  // 2 - 无确认传输所有数据  // 3 - 无确认传输所有数据,不清除EEPROM数据  // 4 - 无确认传输所有数据,不清除EEPROM数据,格式化回传数据  // 5 - 无确认传输最后一个数据,不清除EEPROM数据,格式化回传数据  // 6 - 读当前数据并传输  // 7 - 传输当前时间  // 8 - 设置当前时间  // 9 - 读最后开机时间 - 未用  // 10 - 传输当前EEPROM信息  // 11 - 设置EEPROM芯片总容量(KByte)  // 12 - 清空EEPROM中所有数据(将已使用数据个数写0)  // 13 - 强制开启无线模块电源  // 14 - 强制不进入休眠模式  // 15 - 将当前数据写入EEPROM

 Open_EEPROM();  //打开EEPROM电源

 if(command == Command_EEPROM_AllAndEccAndClear)  //传输所有数据(带CRC校验),每传完一个数据要求回传确认信息  {    for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)  //循环读取、发送    {      EEPROM_Read(i, 1, 1, 0);

     //等待回传      unsigned long _time = millis();      String comval = "";      while(1)      {        while(Serial.available() > 0) //当串口有信息传入,读取之        {          comval += char(Serial.read());          delay(2);        }        if(comval == "Next") break;        else if (comval == "Again")        {          DATA_EEPROM_DataUsed++;  //已使用数据个数重新增一位          EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //写入EEPROM          delay(10);  //EEPROM写周期          i++;          break;        }        if ((millis() - _time) > 2000)  //超时2s直接结束        {          DATA_EEPROM_DataUsed++;  //已使用数据个数重新增一位          EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //写入EEPROM          delay(10);  //EEPROM写周期          i++;          Close_EEPROM();  //关闭EEPROM电源          return;        }      }    }  }  else if(command == Command_EEPROM_AllNoEccAndClear)  //无确认传输所有数据  {    for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)    {      EEPROM_Read(i, 0, 1, 0);      delay(100);  //间隔时间    }  }  else if(command == Command_EEPROM_AllNoEccNoClear)  //无确认传输所有数据,不清除EEPROM数据  {    for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)    {      EEPROM_Read(i, 0, 0, 0);      delay(100);  //间隔时间    }  }  else if(command == Command_EEPROM_AllNoEccNoClearFormat)  //无确认传输所有数据,不清除EEPROM数据,格式化回传数据  {    for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)    {      EEPROM_Read(i, 0, 0, 1);      delay(100);  //间隔时间    }  }  else if(command == Command_EEPROM_LastNoEccNoClearFormat)  //无确认传输最后一个数据,不清除EEPROM数据  {    EEPROM_Read(DATA_EEPROM_DataUsed, 0, 0, 1);  }  else if(command == Command_ReadImmediately)  //如果是要求传输当前传感器数据  {    Serial.println("Reading Sensor...");    Serial.println();

   Sensor_Read();  //读取当前数据

   Print_CurrentData();  //串口输出当前数据  }  else if(command == Command_CurrentTime)  //如果是要求传输当前时间  {    Serial.print(PCF8563.formatDate(2));    Serial.print(' ');    Serial.println(PCF8563.formatTime());    Serial.println();  }  else if(command == Command_SetTime)  //如果是要求设置当前时间,输入格式为:“年月日周时分秒”,连续14个数字,如13011603234500  {    Serial.println("Input time.");  //输入提示符    String comdata = Wait_Input();  //等待串口输入

   //设置时钟芯片时间值    PCF8563.setDate((comdata.substring(4,6)).toInt(), (comdata.substring(6,8)).toInt(), (comdata.substring(2,4)).toInt(), 0, (comdata.substring(0,2)).toInt());  //设置日期:日、周、月、世纪、年    PCF8563.setTime(comdata.substring(8,10).toInt(), comdata.substring(10,12).toInt(), comdata.substring(12,14).toInt());  //设置时间:时、分、秒

   Serial.print(PCF8563.formatDate(2));    Serial.print(' ');    Serial.println(PCF8563.formatTime());    Serial.println("Time set OK.");    Serial.println();  }  // else if(command == Command_EEPROM_LastPowerOn)  //读取最后开机时间(会死机)  // {  // String _date, _time;

 // _date = (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn, 1);                  //年  // _date = _date + '-' + (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+1, 1);  //月  // _date = _date + '-' + (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+2, 1);  //日  // _time = (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+3, 1);                //时  // _time = _time + ':' + (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+4, 1);  //分  // _time = _time + ':' + (String)I2C.read(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+5, 1);  //秒

 // Serial.print("Last poweron : ");  // Serial.print(_date); Serial.print(' '); Serial.println(_time);  // Serial.println();  // }  else if(command == Command_EEPROM_Information)  //传输当前EEPROM信息  {    Serial.print("EEPROM: ");    Serial.print(DATA_EEPROM_TotalKB = I2C.read(I2C_Address_EEPROM, REG_EEPROM_TotalKB, 2));    Serial.println(" Kbyte");  //EEPROM芯片总容量(Kbyte),同时更新变量数据    Serial.print("Data used: ");    Serial.println(DATA_EEPROM_DataUsed = I2C.read(I2C_Address_EEPROM, REG_EEPROM_DataUsed, 2));  //已使用数据个数,同时更新变量数据    Serial.print("Data remain: ");    Serial.println((DATA_EEPROM_TotalKB1024 - DATA_EEPROM_DataFirst - DATA_EEPROM_DataUsed * DATA_EEPROM_DataLength) /DATA_EEPROM_DataLength);  //剩余可使用数据个数=(芯片总容量-首个数据地址-已使用数据个数每个数据长度)/每个数据长度    Serial.println();  }  else if(command == Command_EEPROM_TotalKB)  //设置EEPROM总容量(KByte)  {    Serial.println("Input EEPROM size (KByte).");  //输入提示符    String comdata = Wait_Input();  //等待串口输入

   EEP.write(I2C_Address_EEPROM, REG_EEPROM_TotalKB, (unsigned int)comdata.toInt());    delay(10);  //EEPROM读写转换周期    Serial.print("EEPROM size set to ");    Serial.print(DATA_EEPROM_TotalKB = I2C.read(I2C_Address_EEPROM, REG_EEPROM_TotalKB, 2));  //同时向变量赋值    Serial.println(" KByte.");    Serial.println();  }  else if(command == Command_EEPROM_Clear)  //清空EEPROM中所有数据  {    DATA_EEPROM_DataUsed = 0;    EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, (unsigned int)0);  //清零已使用数据个数    delay(10);

   Serial.println("EEPROM clear OK.");    Serial.println();  }  else if(command == Command_PowerSwitch_Radio_OPEN)  //强制开启无线模块电源  {    PowerSwitch_Radio_Enable = !PowerSwitch_Radio_Enable;    if(PowerSwitch_Radio_Enable) Serial.println("Radio open.");    else Serial.println("Radio close.");    Serial.println();  }  else if(command == Command_NoSleep)  //强制开启无线模块电源  {    NoSleep = !NoSleep;    if(NoSleep) Serial.println("Sleep is disenable.");    else Serial.println("Sleep is enable.");    Serial.println();  }  else if(command == Command_EEPROM_WritePresent)  //将当前数据写入EEPROM  {    EEPROM_Write();  }

 Close_EEPROM();  //关闭EEPROM电源 }

////光照度 读取////////////////////////////////////////////// void BH1751FVI_Read() {  unsigned long _Result = 0;  //发送测量命令  I2C.write(I2C_Address_BH1751FVI, BH1751FVI_Mode);  //发送测量模式命令  for(unsigned char i = 0; i < 15; i++)  {    //读取数据    delay(130);  //等待转换结果    _Result += I2C.read(I2C_Address_BH1751FVI, 2);  //回传测量结果,2个字节  }  BH1751FVI_Result = _Result/15;  //计算平均值  //关闭BH1751FVI芯片  I2C.write(I2C_Address_BH1751FVI, Param_BMP085_Close);  //发送关闭命令  //计算最终值  unsigned int tmp = 0;  for(unsigned char i = 0; i < 16; i++) tmp += pow(2*((BH1751FVI_Result>>i)&1), i);  //返回测量结果  BH1751FVI_Result = tmp/1.2; }

////气压值 读取//////////////////////////////////////////////

//读校准值 void BMP085_init() {  ac1 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAA, 2);  ac2 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAC, 2);  ac3 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAE, 2);  ac4 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB0, 2);  ac5 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB2, 2);  ac6 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB4, 2);  b1  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xB6, 2);  b2  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xB8, 2);  mb  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBA, 2);  mc  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBC, 2);  md  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBE, 2); } //读取温度(返回真实值的10倍) void BMP085_read_Temperature() {  unsigned int ut;  unsigned long ut_clac = 0;  for(unsigned char i = 0; i < 3; i++)  {    //读取未补偿的温度值(每秒一次)    I2C.write(I2C_Address_BMP085, REG_BMP085_Command, Param_BMP085_Temperature);  //请求读取温度    delay(5);  //至少等待4.5ms    //从测量值寄存器读取两个字节    ut = I2C.read(I2C_Address_BMP085, REG_BMP085_MSB, 2);    ut_clac += ut;    delay(1000);  }  ut = ut_clac/3;  //计算平均值  //计算温度值  b5 = ((((long)ut - (long)ac6)(long)ac5) >> 15) + (((long)mc << 11)/(((((long)ut - (long)ac6)(long)ac5) >> 15) + md));  BMP085_Temperature = ((b5 + 8)>>4); } //读取气压(Pa) void BMP085_read_Pressure() {  unsigned long up, up_clac = 0, b4;  long b3, p;  for(unsigned char i = 0; i < 64; i++)  {    //读取未补偿的压力值(最多每秒128次)    I2C.write(I2C_Address_BMP085, REG_BMP085_Command, (unsigned char)(0x34 + (OSS<<6)));  //写请求读取气压    //等待转换,延迟时间依赖于OSS    delay(2 + (3<> (8-OSS);    Wire.endTransmission();    up_clac += up;    delay(10);  }  up = up_clac/64;  //计算平均值  //计算气压值  b3 = (ac4 * (unsigned long)((((((ac3 * (b5-4000))>>13) + (((b5-4000) * (((b5-4000) * (b5-4000))>>12))>>16)) + 2)>>2) + 32768))>>15;  b4 = ((unsigned long)(up - ((((((long)ac1)*4 + (((b2 * ((b5-4000) * (b5-4000))>>12)>>11) + ((ac2 * (b5-4000))>>11)))<>2)) * (50000>>OSS));  if(b4 < 0x80000000) p = (b4<<1)/b3;  else p = (b4/b3)<<1;  BMP085_Pressure = p + ((((((p>>8) * (p>>8)) * 3038)>>16) + ((-7357 * p)>>16) + 3791)>>4); }

////地磁方向 读取 (没有校准过程)//////////////////////////////////////////////

void HMC5883L_init() {  I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_SetA, (unsigned char)0x78);  //配置寄存器A,平均采样数8、输出速率75Hz  I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_SetB, (unsigned char)0x20);  //配置寄存器B,增益1090高斯  I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_Mode, (unsigned char)0x00);  //模式寄存器,连续测量模式 } void HMC5883L_Read() {  int _x, _y, _z;

 for(unsigned char i = 0; i < 3; i++)  {    //发送测量命令    I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_X);    delay(10);  //等待转换结果    //接收6个字节    Wire.beginTransmission(I2C_Address_HMC5883L);    Wire.requestFrom(I2C_Address_HMC5883L, 6);    _x = Wire.read()<<8 | Wire.read();  //X轴数据    _z = Wire.read()<<8 | Wire.read();  //Z轴数据    _y = Wire.read()<<8 | Wire.read();  //Y轴数据    Wire.endTransmission();    delay(50);  }  //计算地磁方向  HMC5883L_Result = ((atan2(_y, _x) + M_PI) * 180 / M_PI);  //纠正磁偏角  HMC5883L_Result -= HMC5883L_Declination;  if(HMC5883L_Result < 0) HMC5883L_Result = 360 - HMC5883L_Result;  else if(HMC5883L_Result > 359) HMC5883L_Result -= 360;  //将HMC5883L芯片设置到闲置模式  I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_Mode, (unsigned char)0x01); }

////温湿度 读取//////////////////////////////////////////////

bool AM2302_Read()  //读取AM2302数据值,返回读取是成功 {  //注意:两次读取间隔至少2s,长时间未读取的话,第一次值不能用,因为读到的是上一次读取完后模块自己读的值

 unsigned char CRC;

 for(unsigned char i = 0; i < 3; i++)  {    AM2302_Temperature = 0;    AM2302_Humidity = 0;    CRC = 0;  //CRC校验值(读取出来的)

   pinMode(AM2302_Pin, OUTPUT);    //设置为输出状态    digitalWrite(AM2302_Pin, LOW);  //输出低电平    delay(18);    pinMode(AM2302_Pin, INPUT);     //设置为输入状态

   if(pulseIn(AM2302_Pin, HIGH));  //等待80us高电平,80ms或50ms的低电平不管它

   //读取数据    for(char i = 15; i >= 0; i--)  //读16bit的湿度值    {      if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(AM2302_Humidity, i);  //读取26us或70us高电平    }    for(char i = 15; i >= 0; i--)  //读16bit的温度值    {      if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(AM2302_Temperature, i);  //读取26us或70us高电平    }    for(char i = 7; i >= 0; i--)  //读8bit的CRC值    {      if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(CRC, i);  //读取26us或70us高电平    }    delay(2000);  }

 //校验CRC  unsigned int CRC_tmp = 0;  //CRC校验计算值  for(char i = 15; i >= 0; i--)  {    CRC_tmp = (AM2302_Humidity >> 8) + (AM2302_Humidity & 0x00FF) + (AM2302_Temperature >> 8) + (AM2302_Temperature & 0x00FF);  }

 //修正负温度  if(AM2302_Temperature < 0) AM2302_Temperature = -(AM2302_Temperature&0x7FFF);

 if((CRC_tmp & 0x00FF) == CRC) return 1;  //注:校验计算值可能会超出8位,但CRC读取值只有8位,故将8位以上的数据值过滤掉  else return 0; } /* @end */  

分享:

0 留言

留言

您的留言将被人工审核,请勿发表色情、反动言论。