//本程序所包含的库文件
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>
#include <OneWire.h>
#include <DallasTemperature.h>
#include <math.h>
//本程序的引脚定义
#define ONE_WIRE_BUS 26 //设置温度计引脚在ESP8266的GPIO2上D4
#define CLK 25 //编码器输出A D5
#define DT 33 //编码器输出B D6
#define SW 32 //编码器按钮 D7
#define fan1_pwm 17 //定义pwm输出io
#define fan2_pwm 16
#define fan1_speed 34 //测速端口
#define fan2_speed 35 //测速端口
#define TEC 26
//编码器初始化部分
short counter = 0; //编码器旋转计数
short currentStateCLK; //保持CLK输出的状态,并且被用于确定旋转量
short lastStateCLK;
short Speed_PWM = 0;
unsigned long lastButtonPress = 0; //消除开关的抖动
//OLED显示屏初始化部分
//U8G2_SSD1306_128X64_NONAME_F_SW_I2C u8g2(U8G2_R0, /* clock=*/ SCL, /* data=*/ SDA); //初始化U8g2设置针脚GPIO5-D1-SCL,GPIO4-D2-SDA
//U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0);
U8G2_SH1106_128X64_NONAME_F_4W_SW_SPI u8g2(U8G2_R0, 18, 23, 5, 4 , 19);
//U8G2_SH1106_128X64_NONAME_F_4W_SW_SPI u8g2(rotation, clock, data, cs, dc [, reset])
//U8G2_SH1106_128X64_NONAME_1_4W_HW_SPI(rotation, cs, dc [, reset])
//U8G2_SH1106_128X64_NONAME_F_4W_HW_SPI u8g2(U8G2_R0, 15, 12 , 2);
//温度计初始化部分
OneWire oneWire(ONE_WIRE_BUS);
DallasTemperature sensors(&oneWire);
float TemT=3.00;
//时间定义部分
float Time=0;
uint8_t sensor1[8] = { 0x28, 0xEE, 0xD5, 0x64, 0x1A, 0x16, 0x02, 0xEC };
uint8_t sensor2[8] = { 0x28, 0x61, 0x64, 0x12, 0x3C, 0x7C, 0x2F, 0x27 };
uint8_t sensor3[8] = { 0x28, 0x61, 0x64, 0x12, 0x3F, 0xFD, 0x80, 0xC6 };
//开机显示函数
void OLED_Steup() {
u8g2.clearBuffer(); //清除缓存
u8g2.setFont(u8g2_font_wqy16_t_gb2312a); //设定字体为 u8g2_font_wqy16_t_gb2312a 要想显示文字必须设置字体,可重叠使用
u8g2.setCursor(40, 14); //设定print命令的坐标位置,其中y会向下移动2个像素,可重叠使用
u8g2.print("冰 箱"); //在点(40,14)的右上角写文字
u8g2.setCursor(10, 38);
u8g2.print("温度可设置范围");
u8g2.setCursor(10, 60);
u8g2.print("-10°C -- 10°C");
u8g2.sendBuffer(); //将刚刚在缓存中绘制的全部内容发送出去
delay(1000); //延时1.5秒
}
//一般显示函数
void OLED_Norm() {
sensors.requestTemperatures(); // 发送命令获取温度
// float Tem=sensors.getTempCByIndex(0);
float Tem1 = sensors.getTempC(sensor1);
float Tem2 = sensors.getTempC(sensor2);
float Tem3 = sensors.getTempC(sensor3);
u8g2.clearBuffer(); //清除缓存
u8g2.setFont(u8g2_font_wqy13_t_gb2312a); //设定字体为 u8g2_font_wqy16_t_gb2312a
u8g2.setCursor(5, 14);
u8g2.print("目标");
u8g2.setCursor(40, 15);
u8g2.print(TemT);
u8g2.setCursor(95, 14);
u8g2.print("°C");
u8g2.setCursor(5, 38);
u8g2.print("实时");
u8g2.setCursor(40, 38);
u8g2.print(Tem1);
u8g2.setCursor(95, 38);
u8g2.print("°C");
u8g2.setCursor(27, 60);
u8g2.print("6:30 p.m.");
u8g2.sendBuffer(); //将刚刚在缓存中绘制的全部内容发送出去
}
int Speed1_PWM = 0;
int Speed2_PWM = 0;
unsigned long duration1 = 0;
unsigned long duration2 = 0;
void fan1_speed()
{
duration1 = 0;
if (Speed1_PWM < 230) { // 当风扇开始转动时,计算转速
for (int i = 0; i < 5; i++) { //高低电平变化5个周期(如果要精确的话,可以多取几次),取总计时间(微秒)
duration += pulseIn(fan1_speed, HIGH);
duration += pulseIn(fan1_speed, LOW);
}
} else {
duration1 = 4294967295; //如果风扇未转动,设置为unsigned long类型的最大值,让计算后风扇转速接近为0
}
duration1 = duration1 / 5; //高低电平变化1次用时
duration1 = 1000000 / duration1; // 1秒内可变化几次(即转化为风扇转速频率Hz)
duration1 = duration1 * 60; //1分钟内可变化几次(即转换为风扇转速 转/分钟)
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy13_t_gb2312a);
u8g2.setCursor(5, 14);
u8g2.print("风扇转速");
u8g2.setCursor(40, 15);
u8g2.print(duration1);
u8g2.setCursor(95, 14);
u8g2.print("转/分钟");
u8g2.sendBuffer();
}
void fan2_speed()
{
duration2 = 0;
if (Speed2_PWM < 230) { // 当风扇开始转动时,计算转速
for (int i = 0; i < 5; i++) { //高低电平变化5个周期(如果要精确的话,可以多取几次),取总计时间(微秒)
duration += pulseIn(fan2_speed, HIGH);
duration += pulseIn(fan2_speed, LOW);
}
} else {
duration2 = 4294967295; //如果风扇未转动,设置为unsigned long类型的最大值,让计算后风扇转速接近为0
}
duration2 = duration2 / 5; //高低电平变化1次用时
duration2 = 1000000 / duration2; // 1秒内可变化几次(即转化为风扇转速频率Hz)
duration2 = duration2 * 60; //1分钟内可变化几次(即转换为风扇转速 转/分钟)
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_wqy16_t_gb2312a);
u8g2.setCursor(5, 14);
u8g2.print("风扇转速");
u8g2.setCursor(40, 15);
u8g2.print(duration1);
u8g2.setCursor(95, 14);
u8g2.print("转/分钟");
u8g2.sendBuffer();
}
void fan1(){
if(Tem2<25){
analogWrite(fan1_pwm,0);
}
else if(25<=Tem2 && Tem2<35){
PWM1=map(Tem2,25,35,0,50);
analogWrite(fan1_pwm,PWM1); //在pwm引脚输出OUTPUT(0-225)的占空比波
}
else if(35<=Tem2 && Tem2<50){
PWM1=map(Tem2,35,50,50,225);
analogWrite(fan1_pwm,PWM1);
}
else{
analogWrite(fan1_pwm,225);
}
}
void temcontrol(){
if(abs(TemT-Tem)>0.5){
digitalwrite(TEC,HIGH);
}
else if(TemT){
digitalwrite(TEC,LOW);
}
}
void fan2(){
analogWrite(fan2_pwm,125);
}
void setup() {
pinMode(fan1_pwm, OUTPUT);
pinMode(fan1_speed, INPUT);
pinMode(fan2_pwm, OUTPUT);
pinMode(fan2_speed, INPUT);
pinMode(TEC,OUTPUT);
//温度计初始化
sensors.begin();
//PWM输出初始化
analogWriteFreq(25000); //设置PWM输出频率为25kHz,这并不一定准确
//调用显示初始化函数
OLED_Steup();
/*
//编码器初始化
pinMode(CLK,INPUT); //定义CLK-A引脚为输入
pinMode(DT,INPUT); //定义DT-B引脚为输入
pinMode(SW, INPUT_PULLUP); //设置SW引脚被内部拉起
lastStateCLK = digitalRead(CLK); //读取CLK引脚的当前值并将其存储在lastStateCLK变量中
*/
}
void loop(){
OLED_Norm();
fan1();
fan2();
fan1_speed();
fan2_speed();
}
/*
typedef struct
{
const char* str;
byte len;
}SETTING_LIST;
SETTING_LIST list[] = //建立一个表,存放菜单内容
{
{"菜单",2},
{"目标温度设定",6},
{"定时启动",4},
{"退出",2},
};
//变量定义
short key_id=0;
short key_press=0;
short newflag=0;
short moveflag=0;
short hh=16;
short Side=1;
short len=1;
short len2=1;
short x=2;//目录列表
short xt=2;
short y=13;
short yt=13;
short sx=2;//选择框
short sy=16;
short syt=16;
short sl=list[Side].len*14+2;
short slt=list[Side].len*14+2;
short sh=10;
short waitflag=0;
short key_press2=0;
short cyc=0;
unsigned long staytime=0;
//编码器函数
void Enc() {
currentStateCLK = digitalRead(CLK); //再次检查CLK状态并将其与该lastStateCLK值进行比较
//它们不同,则意味着旋钮已旋转且发生了脉冲,还检查的值是否currentStateCLK为1,以便仅对一个状态更改做出反应,以避免重复计数
if (currentStateCLK != lastStateCLK && currentStateCLK == 1){ //如果currentStateCLK不等于lastStateCLK且currentStateCLK等于1
if (digitalRead(DT) != currentStateCLK) { //如果DT-B引脚的与currentStateCLK不同,编码器逆时针旋转
key_id = 1;
key_press = 1;
newflag=1;
staytime=millis();
waitflag=1;
} else { //如果相同,编码器顺时针旋转
key_id = 2;
key_press = 1;
newflag=1;
staytime=millis();
waitflag=1;
}
}
lastStateCLK = currentStateCLK; //将currentStateCLK更新到lastStateCLK中
int btnState = digitalRead(SW);
//millis()返回自 Arduino 板开始运行当前程序以来经过的毫秒数。大约 50 天后,该数字将溢出(归零)。
if (btnState == LOW) { //如果btnState是低电平
if (millis() - lastButtonPress > 50) {//如果按钮按压了超过50毫秒
key_id = 3;
key_press = 1;
key_press2=1;
newflag=1;
staytime=millis();
waitflag=1;
}
lastButtonPress = millis(); //将millis()更新到lastButtonPress中去
}
delay(1); //稍微延迟一下以帮助消除读数
}
void Logi1() {
if(key_press==1)
{
key_press=0;
if(key_id==1 && Side!=1)
{
syt=sy-hh;
Side=Side-1;
slt=list[Side].len*14+2;
}
else if(key_id==2 && Side!=3)
{
syt=sy+hh;
Side=Side+1;
slt=list[Side].len*14+2;
}
else if(key_id==3)
{
waitflag=1;
}
}
}
void Len() {
if(abs(syt-sy)>=5)
{
len=5;
}
else if(abs(syt-sy)<5)
{
len=1;
}
}
void Len2() {
if(abs(slt-sl)>=5)
{
len2=8;
}
else if(abs(slt-sl)<5)
{
len2=1;
}
}
void Logi2() {
if(syt<sy)
{
sy=sy-len;
moveflag=1;
}
else if(syt>sy)
{
sy=sy+len;
moveflag=1;
}
}
void Logi3() {
if(slt<sl)
{
sl=sl-len2;
moveflag=1;
}
else if(slt>sl)
{
sl=sl+len2;
moveflag=1;
}
else if(syt==sy && slt==sl)
{
newflag=0;
moveflag=0;
}
}
void Display() {
int list_len = sizeof(list) / sizeof(SETTING_LIST);
u8g2.clearBuffer();
for(int i = 0 ;i < list_len;i++) //连续显示整个列表
{
u8g2.setFont(u8g2_font_wqy13_t_gb2312a);
u8g2.setCursor(x+2, (y+i*hh));
u8g2.print(list[i].str); //显示前面的菜单列表,第一段输出位置
}
u8g2.setDrawColor(2);
u8g2.drawRBox(sx,sy,sl,hh,3); //drawRFrame(x,y,w,h,r) 绘制一个空心框(圆角),x,y起点坐标,w,h框的宽度和高度,r圆角的半径
u8g2.setDrawColor(1);
u8g2.sendBuffer();
waitflag=1;
staytime=millis();
}
void menu() {
if (key_press2=1)
{
key_press2=0;
if (Side==3 && key_id==3 && cyc!=0)
{
waitflag=0;
cyc=0;
newflag=0;
}
}
}
void loop(){
if(newflag==0 && waitflag==0)
{
Enc();
PWM_Out();
OLED_Norm();
}
else if(newflag==1)
{
if(moveflag==0)
{
Logi1();
Len();
Len2();
Logi2();
Logi3();
Display();
}
else if(moveflag==1)
{
Len();
Len2();
Logi2();
Logi3();
Display();
cyc=cyc+1;
}
}
else if(newflag==0 && waitflag==1)
{
Enc();
menu();
if(millis() - staytime > 5000)
{
waitflag=0;
cyc=0;
}
}
}
*/