|
|
需要在arduino ide-管理库-自己安装一下对应的库,LCD用的是瑞立德12864 i2c接口,程序基本上兼容大部分arduino比如uno r3 r4 due
LCD库是我自己修改过的,厂家提供那个没有直接使用wire库,导致多个i2c使用有问题,而且不能用在avr以外的mcu
#include <Wire.h>
#include <Adafruit_AHTX0.h> // AHT20 专用库
#include <Adafruit_BMP280.h> // BMP280 库
#include "RSCG12864B.h"
#include "Arduino_LED_Matrix.h"
ArduinoLEDMatrix matrix;
Adafruit_AHTX0 aht; // 创建 AHT20 对象
Adafruit_BMP280 bmp; // 创建 BMP280 对象
float temp_aht,humidity,temp_bmp,pressure,altitude,dewPoint ;
// 全局变量 - 可以在任何函数中访问
float currentTemperature = 0;
float currentHumidity = 0;
// 多个定时任务同时执行
unsigned long previousMillis1 = 0;
unsigned long previousMillis2 = 0;
unsigned long previousMillis3 = 0;
unsigned long previousMillis4 = 0;
const long interval1 = 500; // 任务1: ms秒
const long interval2 = 2500; // 任务2: ms秒
const long interval3 = 500; // 任务3: ms秒
const long interval4 = 5000; // 任务4: ms秒
// 定义存储历史数据的数组大小 (例如:存储60个点,每5秒一个,即5分钟窗口)
const int HISTORY_SIZE = 60;
float pressureHistory[HISTORY_SIZE];
int currentIndex = 0;
bool historyFull = false;
//定义字符串用于中文显示
char f1[]={0XBC,0XB4,0XBD,0XAB,0X20,0XCF,0XC2,0XD3,0XEA,0,};//即将 下雨
char f2[]={0XBC,0XB4,0XBD,0XAB,0X20,0XCF,0XC2,0XD3,0XEA,0,};//即将 晴天
char f3[]={0XD7,0XAA,0XD2,0XF5,0X20,0XCF,0XC2,0XD3,0XEA,0,};//转阴 下雨
char f4[]={0XCC,0XEC,0XC6,0XF8,0X20,0XBA,0XC3,0XD7,0XAA,0,};//天气 好转
char f5[]={0XCC,0XEC,0XC6,0XF8,0X20,0XC6,0XBD,0XCE,0XC8,0,};//天气 平稳
char f6[]={0XB8,0XC9,0XD4,0XEF,0,};//干燥
char f7[]={0XC6,0XAB,0XB8,0XC9,0,};//偏干
char f8[]={0XCA,0XE6,0XCA,0XCA,0,};//舒适
char f9[]={0XC2,0XD4,0XCA,0XAA,0,};//略湿
char f10[]={0XB3,0XB1,0XCA,0XAA,0,};//潮湿
char f11[]={0XC3,0XC6,0XC8,0XC8,0,};//闷热
char f12[]={0XB5,0XE7,0XB3,0XD8,0XB5,0XE7,0XC1,0XBF,0XB2,0XE2,0XC1,0XBF,0,};//电池电量测量
char f13[]={0XC7,0XEB,0XC1,0XAC,0XBD,0XD3,0XB5,0XE7,0XB3,0XD8,0,};//请链接电池
char f14[]={0XB2,0XE2,0XC1,0XBF,0X20,0X20,0XCD,0XEA,0XB3,0XC9,0,};//测量 完成
void setup() {
Serial.begin(9600);
// 初始化 I2C
Wire.begin();
analogReadResolution(12);
// --- 初始化 AHT20 (使用 Adafruit_AHTX0 库)---
aht.begin();
bmp.begin(0x77);
// 可选:配置 BMP280 采样模式
bmp.setSampling(Adafruit_BMP280::MODE_NORMAL,// 普通模式
Adafruit_BMP280::SAMPLING_X16,// 温度过采样 ×2
Adafruit_BMP280::SAMPLING_X16,// 气压过采样 ×16
Adafruit_BMP280::FILTER_X16,// IIR滤波系数 ×4
Adafruit_BMP280::STANDBY_MS_500);// 间隔250ms
// 初始化LCD
delay(500);
RSCG12864B.begin();
RSCG12864B.display_on();
RSCG12864B.clear();
//初始化LED点阵
matrix.begin();
// 加载并播放开机动画
matrix.loadSequence(LEDMATRIX_ANIMATION_TETRIS_INTRO);
matrix.play(true); // true = 无限循环
}
void loop() {
unsigned long currentMillis = millis();
// 声明事件变量
sensors_event_t humidity_event, temp_event;
// 任务1
if (currentMillis - previousMillis1 >= interval1) {
previousMillis1 = currentMillis;
// --- 读取 AHT20 数据(Adafruit_AHTX0 的简洁方式)---
sensors_event_t humidity, temp;
aht.getEvent(&humidity, &temp); // 一次性获取温湿度
// 将温湿度结果赋值给自定义变量
currentTemperature = temp.temperature;
currentHumidity = humidity.relative_humidity;
// 调用函数计算露点
dewPoint = calculateDewPoint(currentTemperature, currentHumidity);
// Serial.print(F("AHT20 - 温度: "));
// Serial.print(temp.temperature, 1);
// Serial.println(F(" °C"));
// Serial.print(F("AHT20 - 湿度: "));
// Serial.print(humidity.relative_humidity, 1);
// Serial.println(F(" %"));
//digitalWrite(12,HIGH);
}
// 任务2
if (currentMillis - previousMillis2 >= interval2) {
previousMillis2 = currentMillis;
// --- 读取 BMP280 数据 ---
temp_bmp = bmp.readTemperature();
pressure = bmp.readPressure() / 100.0F;
// Serial.print(F("BMP280 - 温度: "));
//Serial.print(temp_bmp, 1);
// Serial.println(F(" °C"));
//Serial.print(F("BMP280 - 气压: "));
// Serial.print(pressure, 2);
// Serial.println(F("hPa"));
// 你也可以从 BMP280 读取并计算近似海拔 (需要输入当前海平面气压作为参考)
altitude = bmp.readAltitude(1013.25); // 1013.25 hPa 是标准海平面气压
// Serial.print(F("BMP280 - 海拔: "));
// Serial.print(altitude, 1);
// Serial.println(F(" 米"));
}
// 任务3
if (currentMillis - previousMillis3 >= interval3) {
previousMillis3 = currentMillis;
lcd();
}
// 任务4
if (currentMillis - previousMillis4 >= interval4) {
previousMillis4 = currentMillis;
addPressureSample(pressure); // 将新数据加入环形缓冲区
// 当数据足够时,进行趋势分析和预测
if (historyFull) {
float slope = calculateTrend(pressureHistory, HISTORY_SIZE);
String weather = getWeatherPrediction(slope);
Serial.print("气压变化斜率 (hPa/h): ");
Serial.println(slope * 12); // 因为我们每5秒采一个点,斜率需要换算成每小时的变化率
Serial.print("天气预测: ");
Serial.println(weather);
if (weather == "气压快速下降,可能下雨或风暴") {
RSCG12864B.print_string_12_xy(62, 42, f1);
} else if (weather == "气压持续上升,天气将转晴") {
RSCG12864B.print_string_12_xy(62, 42, f2);
} else if (weather == "气压下降,天气可能转阴或有雨") {
RSCG12864B.print_string_12_xy(62, 42, f3);
} else if (weather == "气压上升,天气正在好转") {
RSCG12864B.print_string_12_xy(62, 42, f4);
} else if (weather == "气压稳定,天气无明显变化") {
RSCG12864B.print_string_12_xy(62, 42, f5);
}
}
}
}
void lcd(){
//int br=map(analogRead(A0),0,4095,0,255);
RSCG12864B.brightness(255); // 设置中等亮度
char str1[20];char str2[20];char str3[20];char str4[20];
char str5[20];char str6[20];
sprintf(str1, "%3.2f", currentTemperature); // 调整为8宽度
sprintf(str2, "%3.2f", currentHumidity); // 调整为8宽度
sprintf(str3, "%4.2f", temp_bmp); // 调整为8宽度
sprintf(str4, "%4.2f", pressure); // 调整为8宽度
sprintf(str5, "%4.2f", altitude); // 调整为8宽度
sprintf(str6, "%4.2f", dewPoint); // 调整为8宽度
RSCG12864B.print_string_5x7_xy(2,2,"AHT20");
RSCG12864B.print_string_5x7_xy(2,12,"T");
RSCG12864B.print_string_5x7_xy(2,22,"RH");
RSCG12864B.print_string_5x7_xy(46,12,"'C");
RSCG12864B.print_string_5x7_xy(46,22,"%");
RSCG12864B.print_string_5x7_xy(2,32,"DP");
RSCG12864B.print_string_5x7_xy(46,32,"'C");
RSCG12864B.print_string_5x7_xy(63,2,"BMP280");
RSCG12864B.print_string_5x7_xy(114,12,"'C");
RSCG12864B.print_string_5x7_xy(108,22,"hpa");
RSCG12864B.print_string_5x7_xy(120,32,"m");
RSCG12864B.draw_line(60, 0, 60, 62); // 垂直线
RSCG12864B.draw_line(0, 10, 127, 10); // 横线
RSCG12864B.draw_line(0, 20, 127, 20); // 横线
RSCG12864B.draw_line(0, 30, 127, 30); // 横线
RSCG12864B.draw_line(0, 40, 127, 40); // 横线
RSCG12864B.draw_rectangle(0, 0, 127, 63);//矩形 边框
RSCG12864B.print_string_5x7_xy(16,12,str1);
RSCG12864B.print_string_5x7_xy(16,22,str2);
RSCG12864B.print_string_5x7_xy(63,12,str3);
RSCG12864B.print_string_5x7_xy(63,22,str4);
RSCG12864B.print_string_5x7_xy(16,32,str6);
RSCG12864B.print_string_5x7_xy(63,32,str5);
if(dewPoint<=5){
RSCG12864B.print_string_12_xy(2,42,f6);
}
else if(dewPoint>5&&dewPoint<=10){
RSCG12864B.print_string_12_xy(2,42,f7);
}
else if(dewPoint>10&&dewPoint<=16){
RSCG12864B.print_string_12_xy(2,42,f8);
}
else if(dewPoint>16&&dewPoint<=18){
RSCG12864B.print_string_12_xy(2,42,f9);
}
else if(dewPoint>18&&dewPoint<21){
RSCG12864B.print_string_12_xy(2,42,f10);
}
else if(dewPoint>21){
RSCG12864B.print_string_12_xy(2,42,f11);
}
}
// 计算露点温度(摄氏度)
double calculateDewPoint(double temp, double humidity) {
// Magnus公式中的常数
double a = 17.67;
double b = 243.5; // 单位:°C
// 计算中间变量 γ (gamma)
double gamma = (a * temp / (b + temp)) + log(humidity / 100.0);
// 计算露点温度 Td
double dewPoint = (b * gamma) / (a - gamma);
return dewPoint;
}
// 将新气压值加入环形缓冲区
void addPressureSample(float pressure) {
pressureHistory[currentIndex] = pressure;
currentIndex = (currentIndex + 1) % HISTORY_SIZE;
if (currentIndex == 0) historyFull = true;
}
// 最小二乘法计算斜率
float calculateTrend(float* data, int size) {
if (!historyFull) return 0;
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_x2 = 0;
int n = size;
for (int i = 0; i < n; i++) {
// 从环形缓冲区中按时间顺序取出数据
int idx = (currentIndex + i) % n;
float x = i; // 用索引作为时间轴
float y = data[idx];
sum_x += x;
sum_y += y;
sum_xy += x * y;
sum_x2 += x * x;
}
float denominator = (n * sum_x2 - sum_x * sum_x);
if (denominator == 0) return 0;
// 斜率公式: (n*Σxy - Σx*Σy) / (n*Σx² - (Σx)²)
float slope = (n * sum_xy - sum_x * sum_y) / denominator;
return slope;
}
// 根据斜率预测天气
String getWeatherPrediction(float slopePerPoint) {
// 将斜率换算为每小时的变化量 (hPa/h)
// 因为我们每个点间隔5秒,每小时有720个点。所以 slope_per_hour = slope_per_point * 720 / 采样间隔(秒)?
// 更简单的方法:slope_per_hour = slope_per_point * (3600 / SAMPLE_INTERVAL_SECONDS)
float slope_per_hour = slopePerPoint * (3600.0 / 5.0); // 这里5是采样间隔(秒)
if (slope_per_hour < -1.0) {
return "气压快速下降,可能下雨或风暴";
} else if (slope_per_hour > 1.0) {
return "气压持续上升,天气将转晴";
} else if (slope_per_hour < -0.5) {
return "气压下降,天气可能转阴或有雨";
} else if (slope_per_hour > 0.5) {
return "气压上升,天气正在好转";
} else {
return "气压稳定,天气无明显变化";
}
}
////////////////////////////////////////////////////////////
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?立即注册
x
打赏
-
查看全部打赏
|