//本程序所包含的库文件
#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;
    }
  }
}
*/