分享

我的微型气象站全站程序

 开启美好每一天 2015-11-13
ARDUINO 代码
  1. // 微型气象站
  2. // 光照度传感器(I2C)、温湿度传感器(One Wire)、地磁气压温度传感器(I2C)、锂电池保护模块、太阳能锂电池充电模块、时钟日历芯片、EEPROM储存芯片、无线口透传模块
  3. // MCU:ATmega328P
  4. // 电压:锂电3.7V,可直接使用5V外接电源,但不可与锂电一同使用,太阳能充电输入电压4.35~6V

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

  8. ////加载外部库//////////////////////////////////////////////

  9. #include <Wire.h>    //I2C库(Arduino自带库)
  10. #include <I2C.h>     //I2C库(Arduino自编库)

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

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

  14. ////电压//////////////////////////////////////////////

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

  19. ////风向、风速//////////////////////////////////////////////

  20. // #define Wind_direction_Pin1 0  //风向传感器1(线性霍尔传感器)针脚位
  21. // #define Wind_direction_Pin2 1  //风向传感器2(线性霍尔传感器)针脚位
  22. // #define Wind_speed_Pin      2  //风速传感器 (开关霍尔传感器)针脚位

  23. unsigned int Wind_direction_Result = 0;  //风速(转/分)
  24. unsigned int Wind_speed_Result = 0;      //风向,0-359度(正东向为0度)

  25. ////BH1751FVI光照度芯片//////////////////////////////////////////////

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

  43. //箱内外光照度:箱内 - 297Lx;箱外 - 6175Lx;相差95.19%

  44. ////BMP085气压计//////////////////////////////////////////////

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

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

  59. //校准值
  60. int ac1;
  61. int ac2;
  62. int ac3;
  63. unsigned int ac4;
  64. unsigned int ac5;
  65. unsigned int ac6;
  66. int b1;
  67. int b2;
  68. int mb;
  69. int mc;
  70. int md;
  71. //b5用于计算BMP085_read_Temperature(),它也同时用于BMP085_read_Pressure()
  72. //所以BMP085_read_Temperature()必须放在BMP085_read_Pressure()之前
  73. long b5;

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

  76. ////HMC5883L数字罗盘//////////////////////////////////////////////

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

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

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

  90. ////AM2302温湿度计//////////////////////////////////////////////

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

  94. ////AM2321温湿度计//////////////////////////////////////////////

  95. #define I2C_Address_AM2321 0x5C  //AM2321温湿度计I2C地址
  96. const unsigned char Param_AM2321_Read  = 0x03;  //读寄存器命令
  97. const unsigned char REG_AM2321_Humidity_MSB = 0x00;     //湿度寄存器高位
  98. const unsigned char REG_AM2321_Humidity_LSB = 0x01;     //湿度寄存器低位
  99. const unsigned char REG_AM2321_Temperature_MSB = 0x02;  //温度寄存器高位
  100. const unsigned char REG_AM2321_Temperature_LSB = 0x03;  //温度寄存器低位

  101. unsigned int AM2321_Humidity = 0;  //湿度,10倍于原值
  102. int AM2321_Temperature = 0;  //温度,10倍于原值

  103. ////EEPROM储存芯片//////////////////////////////////////////////

  104. #define I2C_Address_EEPROM 0x53  //EEPROM储存芯片I2C地址

  105. // unsigned int        DATA_EEPROM_TotalKB    = 32;    //芯片总容量,AT24C256 - 32Kbyte
  106. unsigned int        DATA_EEPROM_TotalKB    = 64;    //芯片总容量,AT24C512 - 64Kbyte
  107. unsigned int        DATA_EEPROM_DataUsed   = 0;     //已使用数据个数
  108. const unsigned char DATA_EEPROM_DataLength = 24;    //每个数据长度,24字节
  109. const unsigned int  DATA_EEPROM_DataFirst  = 0x20;  //首个数据地址

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

  115. ////PCF8563时钟芯片//////////////////////////////////////////////

  116. #include <Rtc_Pcf8563.h>  //PCF8563库,I2C地址:0x51
  117. Rtc_Pcf8563 PCF8563;
  118. #define PCF8563_Pin 2  //PCF8563时钟芯片报警中断脚

  119. // #define I2C_Address_PCF8563  0x51  //PCF8563时钟芯片I2C地址
  120. // #define REG_PCF8563_Year   0x08  //年
  121. // #define REG_PCF8563_Month  0x07  //月
  122. // #define REG_PCF8563_Week   0x06  //周
  123. // #define REG_PCF8563_Day    0x05  //日
  124. // #define REG_PCF8563_Hour   0x04  //时
  125. // #define REG_PCF8563_Minute 0x03  //分
  126. // #define REG_PCF8563_Second 0x02  //秒
  127. // #define REG_PCF8563_Alarm_Week   0x0C  //报警-周
  128. // #define REG_PCF8563_Alarm_Day    0x0B  //报警-日
  129. // #define REG_PCF8563_Alarm_Hour   0x0A  //报警-时
  130. // #define REG_PCF8563_Alarm_Minute 0x09  //报警-分
  131. // #define REG_PCF8563_Control_1    0x00  //控制状态1
  132. // #define REG_PCF8563_Control_2    0x01  //控制状态2
  133. // #define REG_PCF8563_Frequency    0x0D  //频率寄存器
  134. // #define REG_PCF8563_Timer_1      0x0E  //定时器1寄存器
  135. // #define REG_PCF8563_Timer_2      0x0F  //定时器倒计数寄存器

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

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

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

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

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

  150. //串口部分////////////////////////////////////////////////

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

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

  169. //////////////////////////////////////////////////

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

  172. //外部中断0////////////////////////////////////////////////
  173. void Int_time()  //时钟唤醒中断
  174. {
  175.         SMCR &= ~(1<<SE);    //停止休眠
  176.         detachInterrupt(0);  //禁止再次接收时钟中断
  177.         IntTime = 1;         //告知程序已经在时钟唤醒中断内
  178. }
  179. //外部中断1////////////////////////////////////////////////
  180. void Int_button()  //按钮中断
  181. {
  182.         SMCR &= ~(1<<SE);    //停止休眠
  183.         detachInterrupt(1);  //禁止再次接收时钟中断
  184.         IntButton = 1;       //按钮按下
  185. }

  186. void setup()
  187. {
  188.         //针脚位设置
  189.         pinMode(PCF8563_Pin, INPUT);              //时钟芯片中断   针脚位
  190.         pinMode(Test_Button_Pin, INPUT);          //测试用按钮     针脚位
  191.         pinMode(Test_LED_Pin, OUTPUT);            //测试用灯       针脚位
  192.         // pinMode(Wind_speed_Pin, OUTPUT);          //风速霍尔传感器 针脚位
  193.         pinMode(PowerSwitch_Pin_EEPROM, OUTPUT);  //EEPROM芯片 电源开关 针脚位
  194.         pinMode(PowerSwitch_Pin_Sensor, OUTPUT);  //传感器     电源开关 针脚位
  195.         pinMode(PowerSwitch_Pin_Radio, OUTPUT);   //无线模块   电源开关 针脚位
  196.         //电压检测设置
  197.         analogReference(INTERNAL);  //选择片内1.1V基准电压源
  198.         //MCU休眠设置
  199.         SMCR = 0x04;                //休眠模式 - 掉电模式

  200.         Serial.begin(9600);  //串口波特率设置
  201.         Wire.begin();        //开启I2C总线
  202.         Open_Radio();        //打开无线模块

  203.         //时钟芯片首次定时唤醒时间设置
  204.         PCF8563.getDate();  //获取当前日期
  205.         PCF8563.getTime();  //获取当前时间
  206.         PCF8563.setAlarm((PCF8563.getMinute()<30?30:0), 99, 99, 99);  //分、时、日、周,设置为99时此位无效

  207.         //写入EEPROM首数据
  208.         // EEP.write(I2C_Address_EEPROM, REG_EEPROM_TotalKB,    DATA_EEPROM_TotalKB);     //EEPROM芯片总容量(Kbyte)
  209.         // EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataLength, DATA_EEPROM_DataLength);  //每个数据长度(Byte)
  210.         // EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataFirst,  DATA_EEPROM_DataFirst);   //首个数据地址
  211.         // delay(10);  //EEPROM读写转换周期
  212.         //读出现在芯片的已使用数据个数
  213.         DATA_EEPROM_DataUsed = I2C.read(I2C_Address_EEPROM, REG_EEPROM_DataUsed, 2);  //已使用数据个数
  214.         delay(10);  //EEPROM读写转换周期
  215.         //EEPROM写最后开机时间
  216.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn,   (unsigned char)PCF8563.getYear());    //年
  217.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+1, (unsigned char)PCF8563.getMonth());   //月
  218.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+2, (unsigned char)PCF8563.getDay());     //日
  219.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+3, (unsigned char)PCF8563.getHour());    //时
  220.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+4, (unsigned char)PCF8563.getMinute());  //分
  221.         EEP.write(I2C_Address_EEPROM, REG_EEPROM_LastPowerOn+5, (unsigned char)PCF8563.getSecond());  //秒

  222.         //开机校准方向
  223.         // Test_init();
  224.         // delay(1000);

  225.         //外部中断
  226.         attachInterrupt(1, Int_button, LOW);    //按钮中断(此设置一定要在开机校准方向后)
  227.         attachInterrupt(0, Int_time, FALLING);  //时钟芯片中断

  228.         digitalWrite(Test_LED_Pin, 1);  //打开测试灯
  229.         delay(100);                     //延时
  230.         digitalWrite(Test_LED_Pin, 0);  //关闭测试灯
  231. }

  232. void loop()
  233. {
  234.         unsigned long _time = millis();  //用于超时

  235.         while(1)
  236.         {
  237.                 //串口读取
  238.                 if(Serial.available() > 0)
  239.                 {
  240.                         while(Serial.available() > 0) //当串口有信息传入,读取之
  241.                         {
  242.                                 comdata += char(Serial.read());
  243.                                 delay(2);
  244.                         }
  245.                         if(comdata.length() > 0)
  246.                         {
  247.                                 //串口命令格式:头字($*)+ 命令数(2位数字);例:$*01
  248.                                 if(comdata.substring(0,2) == "$*") CommandVal = (comdata.substring(2,4)).toInt();  //命令头字
  249.                                 comdata = ""; //清空变量
  250.                         }
  251.                         if(CommandVal)  //如果有命令
  252.                         {
  253.                                 Wireless(CommandVal);
  254.                                 CommandVal = 0;  //清空命令值
  255.                         }

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

  258.                 if(IntTime)  //时钟中断发生
  259.                 {
  260.                         //打开无线模块电源
  261.                         Open_Radio();
  262.                         //读取传感器数据
  263.                         Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.print(PCF8563.formatTime()); Serial.print(' '); Serial.println("Reading sensor..."); Serial.println();
  264.                         Sensor_Read();
  265.                         //串口输出当前数据
  266.                         Serial.print("&*");
  267.                         Serial.print(PCF8563.formatDate(2)); Serial.print(','); Serial.print(PCF8563.formatTime(2)); Serial.print(',');
  268.                         Serial.print(Voltage_Result); Serial.print(',');
  269.                         Serial.print(AM2321_Temperature); Serial.print(',');
  270.                         Serial.print(AM2321_Humidity); Serial.print(',');
  271.                         Serial.print(BMP085_Pressure); Serial.print(',');
  272.                         Serial.print(BH1751FVI_Result); Serial.print(',');
  273.                         Serial.print(HMC5883L_Result); Serial.println(';'); Serial.println();
  274.                         //把数据存入EEPROM
  275.                         EEPROM_Write();
  276.                         Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.print(PCF8563.formatTime()); Serial.print(' '); Serial.println("EEPROM write OK."); Serial.println();
  277.                         //设置时钟芯片下次定时时间
  278.                         PCF8563.setAlarm((PCF8563.getMinute()<30?30:0), 99, 99, 99);  //设置时钟芯片唤醒时间,分、时、日、周,设置为99时此位无效

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

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

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

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

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

  292.                                 digitalWrite(Test_LED_Pin, 1);  //打开测试灯
  293.                                 delay(50);  //延时去毛刺,同时用于闪灯
  294.                                 digitalWrite(Test_LED_Pin, 0);  //关闭测试灯
  295.                                 delay(100);
  296.                                 digitalWrite(Test_LED_Pin, 1);  //打开测试灯
  297.                                 delay(50);  //延时去毛刺,同时用于闪灯
  298.                                 digitalWrite(Test_LED_Pin, 0);  //关闭测试灯
  299.                         }
  300.                         else  //进入正常状态
  301.                         {
  302.                                 NoSleep = 0;                   //关闭强制无休眠模式
  303.                                 PowerSwitch_Radio_Enable = 0;  //关闭强制开启无线模块模式

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

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

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

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

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

  317.         //启动MCU休眠模式,直到被外部中断唤醒(时钟芯片或串口读取到数据)
  318.         if(!NoSleep)
  319.         {
  320.                 Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.print(PCF8563.formatTime()); Serial.print(' '); Serial.println("Sleep."); Serial.println();
  321.                 PowerSwitch_Radio_Enable = 0;    //关闭强制开启无线模块模式
  322.                 Close_Radio();                   //关闭无线模块
  323.                 SMCR |= (1<<SE);                 //开启休眠模式
  324.                 __asm__ __volatile__ ("SLEEP");  //进入休眠模式
  325.         }
  326. }

  327. ////串口输入模块//////////////////////////////////////////////

  328. String Wait_Input()
  329. {
  330.         bool _Judge = 0;  //判断是否完成输入
  331.         String _comdata = "";  //串口输入临时变量

  332.         while(_Judge == 0)  //判断输入完成后退出循环
  333.         {
  334.                 while(Serial.available() > 0)  //等待串口输入
  335.                 {
  336.                         _comdata += char(Serial.read());
  337.                         delay(2);
  338.                 }
  339.                 if(_comdata.length() > 0) _Judge = 1;  //将判断字设为true退出循环
  340.         }

  341.         return _comdata;
  342. }

  343. //串口输出当前数据
  344. void Print_CurrentData()
  345. {
  346.         //注意:需确保串口无线数传模块已经开启
  347.         Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.println(PCF8563.formatTime(2));
  348.         Serial.print("Vol: "); Serial.print(float(Voltage_Result)/100); Serial.println(" V");
  349.         Serial.print("Tem: "); Serial.print(float(AM2321_Temperature)/10); Serial.println(" ^C");
  350.         Serial.print("Hum: "); Serial.print(float(AM2321_Humidity)/10); Serial.println(" %RH");
  351.         Serial.print("Pre: "); Serial.print(BMP085_Pressure); Serial.println(" Pa");
  352.         Serial.print("Lig: "); Serial.print(BH1751FVI_Result); Serial.println(" lx");
  353.         Serial.print("Geo: "); Serial.print(HMC5883L_Result); Serial.println(" ^");
  354.         Serial.println();
  355. }

  356. ////开机校准方向//////////////////////////////////////////////

  357. /* void Test_init()
  358. {
  359.         int _x, _y, _z;
  360.         HMC5883L_init();  //配置HMC5883L

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

  364.         unsigned long _time = millis();  //用于超时

  365.         while(1)
  366.         {
  367.                 //读取地磁方向
  368.                 I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_X);  //发送测量命令
  369.                 delay(10);  //等待转换结果
  370.                 //接收6个字节
  371.                 Wire.beginTransmission(I2C_Address_HMC5883L);
  372.                 Wire.requestFrom(I2C_Address_HMC5883L, 6);
  373.                 _x += Wire.read()<<8 | Wire.read();  //X轴数据
  374.                 _z += Wire.read()<<8 | Wire.read();  //Z轴数据
  375.                 _y += Wire.read()<<8 | Wire.read();  //Y轴数据
  376.                 Wire.endTransmission();
  377.                 //计算地磁方向
  378.                 HMC5883L_Result = ((atan2(_y, _x) + M_PI) * 180 / M_PI);
  379.                 //纠正磁偏角
  380.                 HMC5883L_Result -= HMC5883L_Declination;
  381.                 if(HMC5883L_Result < 0) HMC5883L_Result = 360 - HMC5883L_Result;
  382.                 else if(HMC5883L_Result > 359) HMC5883L_Result -= 360;

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

  386.                 //判断是否按下按钮
  387.                 if(!digitalRead(Test_Button_Pin))  //按下测试按钮后退出
  388.                 {
  389.                         digitalWrite(Test_LED_Pin, 0);  //关闭测试灯

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

  392.                         break;
  393.                 }

  394.                 //判断是否超时
  395.                 if(millis() - _time > 30000)  //如果操作时间大于30s,超时退出
  396.                 {
  397.                         digitalWrite(Test_LED_Pin, 0);

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

  400.                         break;
  401.                 }
  402.         }

  403.         I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_Mode, (unsigned char)0x01);  //将HMC5883L芯片设置到闲置模式
  404. } */

  405. ////读取传感器//////////////////////////////////////////////

  406. void Sensor_Read()
  407. {
  408.         Open_Sensor();  //打开传感器电源
  409.         delay(2000);

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

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

  414.         AM2321_Read();                    //温、湿度值
  415.         BMP085_read_Temperature();        //温度(读大气压之前必须读此温度值,作为大气压校准)
  416.         BMP085_read_Pressure();           //大气压
  417.         BH1751FVI_Read();                 //光照度
  418.         HMC5883L_Read();                  //地磁方向
  419.         Voltage_Result = Voltage_Read();  //电压

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

  422. ////数据写入EEPROM//////////////////////////////////////////////

  423. void EEPROM_Write()
  424. {
  425.         Open_EEPROM();  //打开EEPROM电源
  426.         delay(10);

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

  431.         //写入EEPROM
  432.         EEP.write(I2C_Address_EEPROM, writeAdd,    (unsigned char)PCF8563.getYear());    //年
  433.         delay(10);  //EEPROM写周期
  434.         EEP.write(I2C_Address_EEPROM, writeAdd+1,  (unsigned char)PCF8563.getMonth());   //月
  435.         delay(10);  //EEPROM写周期
  436.         EEP.write(I2C_Address_EEPROM, writeAdd+2,  (unsigned char)PCF8563.getDay());     //日
  437.         delay(10);  //EEPROM写周期
  438.         EEP.write(I2C_Address_EEPROM, writeAdd+3,  (unsigned char)PCF8563.getHour());    //时
  439.         delay(10);  //EEPROM写周期
  440.         EEP.write(I2C_Address_EEPROM, writeAdd+4,  (unsigned char)PCF8563.getMinute());  //分
  441.         delay(10);  //EEPROM写周期
  442.         EEP.write(I2C_Address_EEPROM, writeAdd+5,  Voltage_Result);      //电压
  443.         delay(10);  //EEPROM写周期
  444.         EEP.write(I2C_Address_EEPROM, writeAdd+7,  AM2321_Temperature);  //温度
  445.         delay(10);  //EEPROM写周期
  446.         EEP.write(I2C_Address_EEPROM, writeAdd+9,  AM2321_Humidity);     //湿度
  447.         delay(10);  //EEPROM写周期
  448.         EEP.write(I2C_Address_EEPROM, writeAdd+11, BMP085_Pressure);     //大气压
  449.         delay(10);  //EEPROM写周期
  450.         EEP.write(I2C_Address_EEPROM, writeAdd+15, BH1751FVI_Result);    //光照度
  451.         delay(10);  //EEPROM写周期
  452.         EEP.write(I2C_Address_EEPROM, writeAdd+17, HMC5883L_Result);     //地磁方向
  453.         delay(10);  //EEPROM写周期

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

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

  458.         Close_EEPROM();  //关闭EEPROM电源
  459. }

  460. ////读取EEPROM数据//////////////////////////////////////////////

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

  470.         String _date, _time;
  471.         unsigned char _tmp;

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

  474.         //读EEPROM内容
  475.         _date = "20" + (String)I2C.read(I2C_Address_EEPROM, ReadAdd, 1);  //年
  476.         _tmp = I2C.read(I2C_Address_EEPROM, ReadAdd+1, 1);
  477.         if(_tmp < 10) _date = _date + "-0" + (String)_tmp;  //月
  478.         else _date = _date + '-' + (String)_tmp;
  479.         _tmp = I2C.read(I2C_Address_EEPROM, ReadAdd+2, 1);
  480.         if(_tmp < 10) _date = _date + "-0" + (String)_tmp;  //日
  481.         else _date = _date + '-' + (String)_tmp;
  482.         _tmp = I2C.read(I2C_Address_EEPROM, ReadAdd+3, 1);
  483.         if(_tmp < 10) _time = '0' + (String)_tmp;          //时
  484.         else _time = (String)_tmp;
  485.         _tmp = I2C.read(I2C_Address_EEPROM, ReadAdd+4, 1);
  486.         if(_tmp < 10) _time = _time + ":0" + (String)_tmp;  //分
  487.         else _time = _time + ':' + (String)_tmp;

  488.         Voltage_Result     = I2C.read(I2C_Address_EEPROM, ReadAdd+5,  2);          //电压
  489.         AM2321_Temperature = (int)I2C.read(I2C_Address_EEPROM, ReadAdd+7, 2);      //温度(需转换为int类型)
  490.         AM2321_Humidity    = I2C.read(I2C_Address_EEPROM, ReadAdd+9,  2);          //湿度
  491.         BMP085_Pressure    = I2C.read(I2C_Address_EEPROM, ReadAdd+11, 4);          //大气压
  492.         BH1751FVI_Result   = I2C.read(I2C_Address_EEPROM, ReadAdd+15, 2);          //光照度
  493.         HMC5883L_Result    = I2C.read(I2C_Address_EEPROM, ReadAdd+17, 2);          //地磁方向

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

  502.         //无线发送数据
  503.         if(format)  //发送格式化数据
  504.         {
  505.                 Serial.print(_date); Serial.print(' '); Serial.println(_time);
  506.                 Serial.print("Vol: "); Serial.print(float(Voltage_Result)/100); Serial.println(" V");
  507.                 Serial.print("Tem: "); Serial.print(float(AM2321_Temperature)/10); Serial.println(" ^C");
  508.                 Serial.print("Hum: "); Serial.print(float(AM2321_Humidity)/10); Serial.println(" %RH");
  509.                 Serial.print("Pre: "); Serial.print(BMP085_Pressure); Serial.println(" Pa");
  510.                 Serial.print("Lig: "); Serial.print(BH1751FVI_Result); Serial.println(" lx");
  511.                 Serial.print("Geo: "); Serial.print(HMC5883L_Result); Serial.println(" ^");
  512.                 Serial.println();
  513.         }
  514.         else  //发送打包数据
  515.         {

  516.                 Serial.print("&*");
  517.                 Serial.print(_date); Serial.print(',');
  518.                 Serial.print(_time); Serial.print(',');
  519.                 // Serial.print(float(Voltage_Result)/100); Serial.print(',');
  520.                 // Serial.print(float(AM2321_Temperature)/10); Serial.print(',');
  521.                 // Serial.print(float(AM2321_Humidity)/10); Serial.print(',');
  522.                 Serial.print(Voltage_Result); Serial.print(',');
  523.                 Serial.print(AM2321_Temperature); Serial.print(',');
  524.                 Serial.print(AM2321_Humidity); Serial.print(',');
  525.                 Serial.print(BMP085_Pressure); Serial.print(',');
  526.                 Serial.print(BH1751FVI_Result); Serial.print(',');
  527.                 Serial.print(HMC5883L_Result); Serial.println(';');
  528.                 // if(_date == PCF8563.formatDate(2)) delay(1500);  //用于向LCD传输数据
  529.                 Serial.println();
  530.                 //加CRC校验值
  531.                 // if(crc)
  532.                 // {
  533.                         // unsigned char _CRC = 0;
  534.                         // for(unsigned char i = 0; i < SendString.length(); i++) _CRC |= SendString.charAt(i);
  535.                         // SendString += (String)_CRC;
  536.                 // }
  537.         }
  538. }

  539. ////无线传输数据//////////////////////////////////////////////
  540. void Wireless(unsigned char command)
  541. {
  542. //从最后一个数据开始回传,每传完一个数据就把EEPROM中的此位数据清除掉(仅减少一位数据位)
  543. //命令:
  544. // 1 - 传输所有数据(带CRC校验)
  545. // 2 - 无确认传输所有数据
  546. // 3 - 无确认传输所有数据,不清除EEPROM数据
  547. // 4 - 无确认传输所有数据,不清除EEPROM数据,间隔1.5s,用于向LCD传输数据
  548. // 5 - 无确认传输最后一个数据,不清除EEPROM数据,格式化回传数据
  549. // 6 - 读当前数据并传输
  550. // 7 - 传输当前时间
  551. // 8 - 设置当前时间
  552. // 9 - 读最后开机时间 - 未用
  553. // 10 - 传输当前EEPROM信息
  554. // 11 - 设置EEPROM芯片总容量(KByte)
  555. // 12 - 清空EEPROM中所有数据(将已使用数据个数写0)
  556. // 13 - 强制开启无线模块电源
  557. // 14 - 强制不进入休眠模式
  558. // 15 - 将当前数据写入EEPROM

  559.         Open_EEPROM();  //打开EEPROM电源

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

  565.                         //等待回传
  566.                         unsigned long _time = millis();
  567.                         String comval = "";
  568.                         while(1)
  569.                         {
  570.                                 while(Serial.available() > 0) //当串口有信息传入,读取之
  571.                                 {
  572.                                         comval += char(Serial.read());
  573.                                         delay(2);
  574.                                 }
  575.                                 if(comval == "Next") break;
  576.                                 else if (comval == "Again")
  577.                                 {
  578.                                         DATA_EEPROM_DataUsed++;  //已使用数据个数重新增一位
  579.                                         EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //写入EEPROM
  580.                                         delay(10);  //EEPROM写周期
  581.                                         i++;
  582.                                         break;
  583.                                 }
  584.                                 if ((millis() - _time) > 2000)  //超时2s直接结束
  585.                                 {
  586.                                         DATA_EEPROM_DataUsed++;  //已使用数据个数重新增一位
  587.                                         EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, DATA_EEPROM_DataUsed);  //写入EEPROM
  588.                                         delay(10);  //EEPROM写周期
  589.                                         i++;
  590.                                         Close_EEPROM();  //关闭EEPROM电源
  591.                                         return;
  592.                                 }
  593.                         }
  594.                 }
  595.         }
  596.         else if(command == Command_EEPROM_AllNoEccAndClear)  //无确认传输所有数据
  597.         {
  598.                 for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)
  599.                 {
  600.                         EEPROM_Read(i, 0, 1, 0);
  601.                         delay(100);  //间隔时间
  602.                 }
  603.         }
  604.         else if(command == Command_EEPROM_AllNoEccNoClear)  //无确认传输所有数据,不清除EEPROM数据
  605.         {
  606.                 for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)
  607.                 {
  608.                         EEPROM_Read(i, 0, 0, 0);
  609.                         delay(100);  //间隔时间
  610.                 }
  611.         }
  612.         else if(command == Command_EEPROM_AllNoEccNoClearFormat)  //无确认传输所有数据,不清除EEPROM数据,间隔1.5s,用于向LCD传输数据
  613.         {
  614.                 for(unsigned int i = DATA_EEPROM_DataUsed; i >=1 ; i--)
  615.                 {
  616.                         EEPROM_Read(i, 0, 0, 0);
  617.                         delay(1500);  //间隔时间
  618.                 }
  619.         }
  620.         else if(command == Command_EEPROM_LastNoEccNoClearFormat)  //无确认传输最后一个数据,不清除EEPROM数据
  621.         {
  622.                 EEPROM_Read(DATA_EEPROM_DataUsed, 0, 0, 1);
  623.         }
  624.         else if(command == Command_ReadImmediately)  //如果是要求传输当前传感器数据
  625.         {
  626.                 Serial.println("Reading sensor...");
  627.                 Serial.println();

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

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

  641.                 //设置时钟芯片时间值
  642.                 PCF8563.setDate((comdata.substring(4,6)).toInt(), (comdata.substring(6,8)).toInt(), (comdata.substring(2,4)).toInt(), 0, (comdata.substring(0,2)).toInt());  //设置日期:日、周、月、世纪、年
  643.                 PCF8563.setTime(comdata.substring(8,10).toInt(), comdata.substring(10,12).toInt(), comdata.substring(12,14).toInt());  //设置时间:时、分、秒
  644.                 //设置时钟芯片下次定时时间
  645.                 PCF8563.setAlarm((PCF8563.getMinute()<30?30:0), 99, 99, 99);  //设置时钟芯片唤醒时间,分、时、日、周,设置为99时此位无效
  646.                 Serial.print("Time set to : "); Serial.print(PCF8563.formatDate(2)); Serial.print(' '); Serial.println(PCF8563.formatTime());
  647.                 Serial.println();
  648.         }
  649.         // else if(command == Command_EEPROM_LastPowerOn)  //读取最后开机时间(会死机)
  650.         // {
  651.                 // String _date, _time;

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

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

  673.                 EEP.write(I2C_Address_EEPROM, REG_EEPROM_TotalKB, (unsigned int)comdata.toInt());
  674.                 delay(10);  //EEPROM读写转换周期
  675.                 Serial.print("EEPROM size set to ");
  676.                 Serial.print(DATA_EEPROM_TotalKB = I2C.read(I2C_Address_EEPROM, REG_EEPROM_TotalKB, 2));  //同时向变量赋值
  677.                 Serial.println(" KByte.");
  678.                 Serial.println();
  679.         }
  680.         else if(command == Command_EEPROM_Clear)  //清空EEPROM中所有数据
  681.         {
  682.                 DATA_EEPROM_DataUsed = 0;
  683.                 EEP.write(I2C_Address_EEPROM, REG_EEPROM_DataUsed, (unsigned int)0);  //清零已使用数据个数
  684.                 delay(10);
  685.                 Serial.println("EEPROM clear.");
  686.                 Serial.println();
  687.         }
  688.         else if(command == Command_PowerSwitch_Radio_OPEN)  //强制开启无线模块电源
  689.         {
  690.                 PowerSwitch_Radio_Enable = !PowerSwitch_Radio_Enable;
  691.                 if(PowerSwitch_Radio_Enable) Serial.println("Radio open.");
  692.                 else Serial.println("Radio close.");
  693.                 Serial.println();
  694.         }
  695.         else if(command == Command_NoSleep)  //强制开启无线模块电源
  696.         {
  697.                 NoSleep = !NoSleep;
  698.                 if(NoSleep) Serial.println("Sleep disenable.");
  699.                 else Serial.println("Sleep enable.");
  700.                 Serial.println();
  701.         }
  702.         else if(command == Command_EEPROM_WritePresent)  //将当前数据写入EEPROM
  703.         {
  704.                 EEPROM_Write();
  705.                 Serial.println("EEPROM write OK.");
  706.                 Serial.println();
  707.         }

  708.         Close_EEPROM();  //关闭EEPROM电源
  709. }

  710. ////光照度 读取//////////////////////////////////////////////
  711. void BH1751FVI_Read()
  712. {
  713.         unsigned long _Result = 0;
  714.         //发送测量命令
  715.         I2C.write(I2C_Address_BH1751FVI, BH1751FVI_Mode);  //发送测量模式命令
  716.         for(unsigned char i = 0; i < 15; i++)
  717.         {
  718.                 //读取数据
  719.                 delay(130);  //等待转换结果
  720.                 _Result += I2C.read(I2C_Address_BH1751FVI, 2);  //回传测量结果,2个字节
  721.         }
  722.         BH1751FVI_Result = _Result/15;  //计算平均值
  723.         //关闭BH1751FVI芯片
  724.         I2C.write(I2C_Address_BH1751FVI, Param_BMP085_Close);  //发送关闭命令
  725.         //计算最终值
  726.         unsigned int tmp = 0;
  727.         for(unsigned char i = 0; i < 16; i++) tmp += pow(2*((BH1751FVI_Result>>i)&1), i);
  728.         //返回测量结果
  729.         BH1751FVI_Result = tmp/1.2;
  730. }

  731. ////气压值 读取//////////////////////////////////////////////

  732. //读校准值
  733. void BMP085_init()
  734. {
  735.         ac1 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAA, 2);
  736.         ac2 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAC, 2);
  737.         ac3 = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xAE, 2);
  738.         ac4 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB0, 2);
  739.         ac5 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB2, 2);
  740.         ac6 = I2C.read(I2C_Address_BMP085, (unsigned char)0xB4, 2);
  741.         b1  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xB6, 2);
  742.         b2  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xB8, 2);
  743.         mb  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBA, 2);
  744.         mc  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBC, 2);
  745.         md  = (int)I2C.read(I2C_Address_BMP085, (unsigned char)0xBE, 2);
  746. }
  747. //读取温度(返回真实值的10倍)
  748. void BMP085_read_Temperature()
  749. {
  750.         unsigned int ut;
  751.         unsigned long ut_clac = 0;
  752.         for(unsigned char i = 0; i < 3; i++)
  753.         {
  754.                 //读取未补偿的温度值(每秒一次)
  755.                 I2C.write(I2C_Address_BMP085, REG_BMP085_Command, Param_BMP085_Temperature);  //请求读取温度
  756.                 delay(5);  //至少等待4.5ms
  757.                 //从测量值寄存器读取两个字节
  758.                 ut_clac += I2C.read(I2C_Address_BMP085, REG_BMP085_MSB, 2);
  759.                 delay(1000);
  760.         }
  761.         ut = ut_clac/3;  //计算平均值
  762.         //计算温度值
  763.         b5 = ((((long)ut - (long)ac6)*(long)ac5) >> 15) + (((long)mc << 11)/(((((long)ut - (long)ac6)*(long)ac5) >> 15) + md));
  764.         BMP085_Temperature = ((b5 + 8)>>4);
  765. }
  766. //读取气压(Pa)
  767. void BMP085_read_Pressure()
  768. {
  769.         unsigned long up, up_clac = 0, b4;
  770.         long b3, p;
  771.         for(unsigned char i = 0; i < 64; i++)
  772.         {
  773.                 //读取未补偿的压力值(最多每秒128次)
  774.                 I2C.write(I2C_Address_BMP085, REG_BMP085_Command, (unsigned char)(0x34 + (OSS<<6)));  //写请求读取气压
  775.                 //等待转换,延迟时间依赖于OSS
  776.                 delay(2 + (3<<OSS));
  777.                 //读取测量值寄存器
  778.                 I2C.write(I2C_Address_BMP085, REG_BMP085_MSB);
  779.                 Wire.beginTransmission(I2C_Address_BMP085);
  780.                 Wire.requestFrom(I2C_Address_BMP085, 3);
  781.                 up_clac += (((unsigned long) Wire.read() << 16) | ((unsigned long) Wire.read() << 8) | (unsigned long) Wire.read()) >> (8-OSS);
  782.                 Wire.endTransmission();
  783.                 delay(10);
  784.         }
  785.         up = up_clac/64;  //计算平均值
  786.         //计算气压值
  787.         b3 = (ac4 * (unsigned long)((((((ac3 * (b5-4000))>>13) + (((b5-4000) * (((b5-4000) * (b5-4000))>>12))>>16)) + 2)>>2) + 32768))>>15;
  788.         b4 = ((unsigned long)(up - ((((((long)ac1)*4 + (((b2 * ((b5-4000) * (b5-4000))>>12)>>11) + ((ac2 * (b5-4000))>>11)))<<OSS) + 2)>>2)) * (50000>>OSS));
  789.         if(b4 < 0x80000000) p = (b4<<1)/b3;
  790.         else p = (b4/b3)<<1;
  791.         BMP085_Pressure = p + ((((((p>>8) * (p>>8)) * 3038)>>16) + ((-7357 * p)>>16) + 3791)>>4);
  792. }

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

  794. void HMC5883L_init()
  795. {
  796.         I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_SetA, (unsigned char)0x78);  //配置寄存器A,平均采样数8、输出速率75Hz
  797.         I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_SetB, (unsigned char)0x20);  //配置寄存器B,增益1090高斯
  798.         I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_Mode, (unsigned char)0x00);  //模式寄存器,连续测量模式
  799. }
  800. void HMC5883L_Read()
  801. {
  802.         int _x, _y, _z;
  803.         long x_clac = 0, y_clac = 0, z_clac = 0;

  804.         for(unsigned char i = 0; i < 15; i++)
  805.         {
  806.                 //发送测量命令
  807.                 I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_X);
  808.                 delay(10);  //等待转换结果
  809.                 //接收6个字节
  810.                 Wire.beginTransmission(I2C_Address_HMC5883L);
  811.                 Wire.requestFrom(I2C_Address_HMC5883L, 6);
  812.                 x_clac += Wire.read()<<8 | Wire.read();  //X轴数据
  813.                 z_clac += Wire.read()<<8 | Wire.read();  //Z轴数据
  814.                 y_clac += Wire.read()<<8 | Wire.read();  //Y轴数据
  815.                 Wire.endTransmission();
  816.                 delay(50);
  817.         }
  818.         _x = x_clac/15;
  819.         _y = y_clac/15;
  820.         _z = z_clac/15;
  821.         //计算地磁方向
  822.         HMC5883L_Result = ((atan2(_y, _x) + M_PI) * 180 / M_PI);
  823.         //纠正磁偏角
  824.         HMC5883L_Result -= HMC5883L_Declination;
  825.         if(HMC5883L_Result < 0) HMC5883L_Result = 360 - HMC5883L_Result;
  826.         else if(HMC5883L_Result > 359) HMC5883L_Result -= 360;
  827.         //将HMC5883L芯片设置到闲置模式
  828.         I2C.write(I2C_Address_HMC5883L, REG_HMC5883L_Mode, (unsigned char)0x01);
  829. }

  830. ////AM2302 温湿度 读取//////////////////////////////////////////////

  831. void AM2302_Read()  //读取AM2302数据值
  832. {
  833. //注意:两次读取间隔至少2s,长时间未读取的话,第一次值不能用,因为读到的是上一次读取完后模块自己读的值
  834.         unsigned char CRC;
  835.         unsigned int CRC_tmp;
  836.         long Temperature_clac = 0;
  837.         unsigned long Humidity_clac = 0;
  838.         for(unsigned char i = 0; i < 6; i++)
  839.         {
  840.                 AM2302_Temperature = 0;
  841.                 AM2302_Humidity = 0;
  842.                 CRC = 0;  //CRC校验值(读取出来的)

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

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

  848.                 //读取数据
  849.                 for(char i = 15; i >= 0; i--)  //读16bit的湿度值
  850.                 {
  851.                         if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(AM2302_Humidity, i);  //读取26us或70us高电平
  852.                 }
  853.                 for(char i = 15; i >= 0; i--)  //读16bit的温度值
  854.                 {
  855.                         if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(AM2302_Temperature, i);  //读取26us或70us高电平
  856.                 }
  857.                 for(char i = 7; i >= 0; i--)  //读8bit的CRC值
  858.                 {
  859.                         if(pulseIn(AM2302_Pin, HIGH) > 60) bitSet(CRC, i);  //读取26us或70us高电平
  860.                 }

  861.                 if(i == 0) goto breakfirst;  //去掉第一次的值

  862.                 //校验CRC
  863.                 CRC_tmp = 0;  //CRC校验计算值
  864.                 for(char i = 15; i >= 0; i--)
  865.                 {
  866.                         CRC_tmp = (AM2302_Humidity >> 8) + (AM2302_Humidity & 0x00FF) + (AM2302_Temperature >> 8) + (AM2302_Temperature & 0x00FF);
  867.                 }

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

  870.                 if((CRC_tmp & 0x00FF) == CRC)  //注:校验计算值可能会超出8位,但CRC读取值只有8位,故将8位以上的数据值过滤掉
  871.                 {
  872.                         Temperature_clac += AM2302_Temperature;
  873.                         Humidity_clac += AM2302_Humidity;
  874.                 }
  875.                 else i--;

  876.                 breakfirst:

  877.                 delay(2000);
  878.         }
  879.         AM2302_Temperature = Temperature_clac/5;
  880.         AM2302_Humidity = Humidity_clac/5;
  881. }

  882. ////AM2321 温湿度 读取//////////////////////////////////////////////

  883. void AM2321_Read()  //读取AM2321数据值,2次间隔2s以上,本处不做CRC检验
  884. {
  885.         long Temperature_clac = 0;
  886.         unsigned long Humidity_clac = 0;

  887.         for(unsigned char i = 0; i < 6; i++)
  888.         {
  889.                 //唤醒传感器
  890.                 Wire.beginTransmission(I2C_Address_AM2321);
  891.                 delay(3);
  892.                 Wire.endTransmission();

  893.                 //发送读取温、湿度命令
  894.                 Wire.beginTransmission(I2C_Address_AM2321);
  895.                 Wire.write(Param_AM2321_Read);
  896.                 Wire.write(REG_AM2321_Humidity_MSB);
  897.                 Wire.write(4);
  898.                 Wire.endTransmission();

  899.                 //等待数据准备好
  900.                 delay(2);

  901.                 //回传数据
  902.                 Wire.requestFrom(I2C_Address_AM2321, 7);
  903.                 delayMicroseconds(30);  //等待30us
  904.                 Wire.read();
  905.                 Wire.read();
  906.                 AM2321_Humidity = (Wire.read()<<8) | Wire.read();
  907.                 AM2321_Temperature = (Wire.read()<<8) | Wire.read();
  908.                 Wire.read();
  909.                 Wire.endTransmission();

  910.                 //修正负温度
  911.                 if(AM2321_Temperature < 0) AM2321_Temperature = -(AM2321_Temperature&0x7FFF);

  912.                 if(i > 0)  //舍弃第一次读取的数值
  913.                 {
  914.                         Temperature_clac += AM2321_Temperature;
  915.                         Humidity_clac += AM2321_Humidity;
  916.                 }

  917.                 delay(2000);
  918.         }

  919.         AM2321_Temperature = Temperature_clac/5;
  920.         AM2321_Humidity = Humidity_clac/5;
  921. }

传感器模块

这个是传感器模块,分别是AM2321温湿度模块、BMP085气压模块及HMC5883L地磁方向模块、BH1751FVI光照度模块

内部设备

内部设备的图片,右边那个模块是太阳能充电管理模块

盒子中是主控模块

密封盒子里是主控板和无线串口数传模块

未阉割前的主控板

主控板上带3只芯片和1只超级电容,3只芯片分别是328P-AU主控芯片、PCF8563时钟日历芯片(之前用的其它的芯片,选它的原因是电压可以达到3.3V供电,适用于锂电池,可以自由设定一周内任意时间定时唤醒MCU,这个对节能非常的重要)、AT24C512 EEPROM储存芯片

3大件

盒子三大件(太阳能电池外接,没拍进去),盒子是用老婆的化妆品盒子,下面挖空透气,上面用弧形玻璃盖玻片挡雨,玻璃与盒间是有空隙的,空气可以自下而上的自由流通这,所有外面都贴了反射膜,用于反射太阳光,不让盒内温度因阳光的照射而上升。

装配好

装配好的样子(没有显示太阳能板)。

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多