//@微型气象站 //@光照度传感器(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 */