600 lines
15 KiB
C++
600 lines
15 KiB
C++
#include <Adafruit_GFX.h>
|
|
#include <Adafruit_ST7735.h>
|
|
#include <SPI.h>
|
|
#include <String.h>
|
|
#include <Preferences.h>
|
|
|
|
|
|
#define CLK 25
|
|
#define DT 33
|
|
#define SW 14
|
|
#define cs 5
|
|
#define dc 27
|
|
#define rst 26
|
|
#define RELEY 32
|
|
#define COUNT_selected 5
|
|
|
|
#define GRAY 0x2965
|
|
|
|
Adafruit_ST7735 tft = Adafruit_ST7735(cs, dc, rst);
|
|
|
|
const float BETA = 2450;
|
|
int8_t last_temp[120];
|
|
int8_t index_temp = 0;
|
|
int selected_opt[COUNT_selected];
|
|
const String selected_name[COUNT_selected] = {"Diff P","Diff I","Diff D","Start temp","Preheat temp"};
|
|
int pos = 0;
|
|
int set_temp=0;
|
|
int8_t stage = 0;
|
|
int8_t enc_turn = 0;
|
|
int timer_td = 0;
|
|
int8_t selected = 0;
|
|
volatile boolean flag, resetFlag;
|
|
volatile byte curState, prevState;
|
|
int button_t=0;
|
|
volatile unsigned long last_time;
|
|
int start_hot=0;
|
|
int last_celsius;
|
|
int hoting_on = 0;
|
|
Preferences prefs;
|
|
|
|
|
|
//timer varebles
|
|
bool pwm_flag, pwm_dir;
|
|
uint32_t pwm_timer;
|
|
int pwm_period = 1000;
|
|
int pwm_activePeriod;
|
|
|
|
//action vareblios
|
|
uint32_t act_timer;
|
|
int act_period = 25;
|
|
|
|
//read_temp vareblios
|
|
uint32_t read_timer;
|
|
int read_period = 500;
|
|
|
|
//read_temp vareblios
|
|
uint32_t time_timer;
|
|
int time_period = 1000, timers = 0;
|
|
|
|
void Task_temp_read(void *pvParameters);
|
|
uint32_t blink_delay;
|
|
|
|
|
|
void IRAM_ATTR int0(){
|
|
encoder_tick();
|
|
}
|
|
|
|
//const int8_t increment[16] = {0, -1, 1, 0, 1, 0, 0, -1, -1, 0, 0, 1, 0, 1, -1, 0};
|
|
void setup() {
|
|
pinMode(SW, INPUT_PULLUP);
|
|
pinMode(CLK, INPUT);
|
|
pinMode(DT, INPUT);
|
|
pinMode(RELEY, OUTPUT);
|
|
analogReadResolution(12);
|
|
Serial.begin(9600);
|
|
//attachInterrupt(DT, int0, CHANGE);
|
|
attachInterrupt(CLK, int0, CHANGE);
|
|
//selected_opt[0] = 0;
|
|
//selected_opt[1] = 0;
|
|
//selected_opt[2] = 0;
|
|
|
|
prefs.begin("setting");
|
|
size_t schLen = prefs.getBytesLength("setting");
|
|
Serial.println(schLen);
|
|
if(!schLen){
|
|
prefs.putBytes("setting", selected_opt, sizeof(selected_opt));
|
|
}else{
|
|
char buffer[schLen];
|
|
|
|
Serial.println(schLen);
|
|
Serial.println(sizeof(selected_opt));
|
|
prefs.getBytes("setting", buffer, schLen);
|
|
if (schLen % sizeof(selected_opt)) { // simple check that data fits
|
|
Serial.println("Data is not correct size!");
|
|
return;
|
|
}
|
|
Serial.println(buffer);
|
|
//selected_opt = (int[]) buffer;
|
|
memcpy(&selected_opt, &buffer, sizeof(buffer));
|
|
prefs.end();
|
|
|
|
}
|
|
set_temp = selected_opt[3];
|
|
|
|
tft.initR(INITR_GREENTAB);
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
|
|
ds_main();
|
|
// xTaskCreate(Task_temp_read, "Temp_read", 2048, (void*) &blink_delay, 2, NULL);
|
|
|
|
|
|
|
|
/* tft.fillScreen(ST77XX_BLACK);
|
|
for(int i = 0 ; i < COUNT_selected; i++){
|
|
if(selected == i)tft.drawRoundRect(2,5+(i*19),79,17,3,ST77XX_GREEN);
|
|
tft.setTextWrap(false);
|
|
tft.setCursor(7,10+(i*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print(selected_name[i]);
|
|
|
|
tft.drawRoundRect(83,5+(i*19),42,17,3,ST77XX_RED);
|
|
tft.setCursor(87,10+(i*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_BLACK);
|
|
tft.print(selected_opt[i]);
|
|
}
|
|
*/
|
|
}
|
|
|
|
|
|
|
|
void encoder_tick() {
|
|
curState = digitalRead(CLK);
|
|
if (curState != prevState) {
|
|
enc_turn = (digitalRead(DT) != prevState) ? -1 : 1;
|
|
flag = true;
|
|
prevState = curState;
|
|
}
|
|
}
|
|
|
|
int8_t encoder_read() {
|
|
int8_t ch = 0;
|
|
if (flag) {
|
|
ch = enc_turn;
|
|
flag = 0;
|
|
}
|
|
return ch;
|
|
}
|
|
|
|
int8_t timer_read(){
|
|
if(timer_td > 0){
|
|
timer_td--;
|
|
if(timer_td == 0) return 40;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int8_t button_read(){
|
|
if(!digitalRead(SW)){
|
|
button_t++;
|
|
if(button_t == 30) return 20;
|
|
}else if(button_t != 0){
|
|
if(button_t > 30){
|
|
button_t = 0;
|
|
}else{
|
|
button_t = 0;
|
|
return 10;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int8_t read_action(){
|
|
return button_read() + encoder_read() + timer_read();
|
|
}
|
|
|
|
|
|
//selected config
|
|
void ds_save_set_selected(int opt){
|
|
tft.fillRoundRect(83,5+(selected*19),42,17,3,ST77XX_BLACK);
|
|
tft.drawRoundRect(83,5+(selected*19),42,17,3,ST77XX_RED);
|
|
tft.setCursor(87,10+(selected*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_BLACK);
|
|
tft.print(opt);
|
|
}
|
|
|
|
void ds_set_selected(int opt){
|
|
tft.fillRoundRect(83,5+(selected*19),42,17,3,ST77XX_RED);
|
|
tft.setCursor(87,10+(selected*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_RED);
|
|
tft.print(opt);
|
|
}
|
|
|
|
//config menu
|
|
void ds_config(){
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
for(int i = 0 ; i < COUNT_selected; i++){
|
|
if(selected == i)tft.drawRoundRect(2,5+(i*19),79,17,3,ST77XX_GREEN);
|
|
tft.setTextWrap(false);
|
|
tft.setCursor(7,10+(i*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print(selected_name[i]);
|
|
Serial.println(selected_name[i]);
|
|
|
|
tft.drawRoundRect(83,5+(i*19),42,17,3,ST77XX_RED);
|
|
tft.setCursor(87,10+(i*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_BLACK);
|
|
tft.print(selected_opt[i]);
|
|
}
|
|
|
|
}
|
|
|
|
void ds_change_selected(){
|
|
for(int8_t i = 0 ; i < COUNT_selected; i++){
|
|
if( selected != i){
|
|
tft.drawRoundRect(2 ,(i * 19) + 5 , 79, 17, 3, ST77XX_BLACK);
|
|
}else{
|
|
tft.drawRoundRect(2 ,(i * 19) + 5 , 79, 17, 3, ST77XX_GREEN);
|
|
}
|
|
|
|
/* tft.setTextWrap(false);
|
|
tft.setCursor(7,10+(i*19)); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print(selected_name[i]);*/
|
|
}
|
|
}
|
|
|
|
|
|
//main menu
|
|
void ds_main(){
|
|
tft.fillScreen(ST77XX_BLACK);
|
|
|
|
ds_renew_hoting();
|
|
|
|
ds_renew_temp();
|
|
|
|
ds_tick_timers();
|
|
|
|
tft.fillRoundRect(3,5,78,42,3,ST77XX_RED);
|
|
|
|
tft.setTextWrap(false);
|
|
tft.setCursor(17,14); //Horiz/Vertic
|
|
tft.setTextSize(3);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print("000");
|
|
|
|
|
|
//tft.drawRoundRect(83,27,42,20,3,ST77XX_RED);
|
|
char buff[3];
|
|
sprintf(buff, "%03d", set_temp);
|
|
tft.setTextWrap(false);
|
|
tft.setCursor(87,30); //Horiz/Vertic
|
|
tft.setTextSize(2);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print(buff);
|
|
|
|
|
|
|
|
|
|
//tft.drawFastHLine(3, 70, 120, ST77XX_YELLOW);
|
|
|
|
tft.drawFastHLine(3, 120, 120, ST77XX_WHITE);
|
|
tft.setCursor(3,122); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print("0");
|
|
}
|
|
|
|
void ds_tick_timers(){
|
|
char buff[9];
|
|
sprintf(buff, "%02d:%02d:%02d", timers/3600, (timers%3600)/60, timers%60);
|
|
tft.setCursor(77,122); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_BLACK);
|
|
tft.print(buff);
|
|
}
|
|
|
|
void ds_ch_set_temp(int tmp){
|
|
char buff[4];
|
|
sprintf(buff, "%03d", tmp);
|
|
tft.setCursor(87,30); //Horiz/Vertic
|
|
tft.setTextSize(2);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_BLACK);
|
|
tft.print(buff);
|
|
}
|
|
|
|
void ds_set_temp(int tmp){
|
|
tft.drawRoundRect(83,27,42,20,3,ST77XX_RED);
|
|
ds_ch_set_temp(tmp);
|
|
}
|
|
|
|
void ds_clear_set_temp(int tmp){
|
|
tft.drawFastHLine(3,map(tmp,0,350,120,50), 120, ST77XX_BLACK);
|
|
}
|
|
|
|
void ds_save_set_temp(int tmp){
|
|
tft.drawRoundRect(83,27,42,20,3,ST77XX_BLACK);
|
|
ds_ch_set_temp(tmp);
|
|
}
|
|
|
|
void ds_renew_temp(){
|
|
tft.setCursor(88,8);
|
|
tft.setTextSize(2);
|
|
if(start_hot == 2){
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.fillRoundRect(83,5,20,20,3,ST77XX_GREEN);
|
|
}else if(start_hot == 1){
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.fillRoundRect(83,5,20,20,3,ST77XX_BLACK);
|
|
tft.drawRoundRect(83,5,20,20,3,ST77XX_GREEN);
|
|
}
|
|
else if(start_hot == 0){
|
|
tft.setTextColor(GRAY);
|
|
tft.fillRoundRect(83,5,20,20,3,ST77XX_BLACK);
|
|
tft.drawRoundRect(83,5,20,20,3,GRAY);
|
|
}
|
|
tft.print(">");
|
|
}
|
|
|
|
|
|
void ds_renew_hoting(){
|
|
if(hoting_on){
|
|
tft.fillRoundRect(105,5,20,20,3,ST77XX_YELLOW);
|
|
digitalWrite(RELEY, HIGH);
|
|
}else{
|
|
tft.fillRoundRect(105,5,20,20,3,ST77XX_BLACK);
|
|
tft.drawRoundRect(105,5,20,20,3,ST77XX_YELLOW);
|
|
digitalWrite(RELEY, LOW);
|
|
}
|
|
tft.setCursor(110,8);
|
|
tft.setTextSize(2);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print("+");
|
|
}
|
|
|
|
void ds_ch_temp(int tmp){
|
|
|
|
if(stage < 2){
|
|
char buff[3];
|
|
sprintf(buff, "%03d", tmp);
|
|
tft.setCursor(17,14); //Horiz/Vertic
|
|
tft.setTextSize(3);
|
|
tft.setTextColor(ST77XX_WHITE,ST77XX_RED);
|
|
tft.print(buff);
|
|
ds_grafik_draw(tmp);
|
|
}
|
|
|
|
}
|
|
|
|
void ds_grafik_draw(int tmp){
|
|
/*tft.drawFastVLine(3, 50, 70, ST77XX_WHITE);
|
|
tft.setCursor(5,50); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print("300");
|
|
|
|
tft.drawFastHLine(3, 70, 120, ST77XX_YELLOW);
|
|
|
|
tft.drawFastHLine(3, 120, 120, ST77XX_WHITE);
|
|
tft.setCursor(3,122); //Horiz/Vertic
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.print("0");*/
|
|
|
|
for(int8_t i = 0; i < 12; i++){
|
|
tft.drawFastVLine(i*10+4, 50, 70, GRAY);
|
|
}
|
|
|
|
for(int8_t i = 0; i < 8; i++){
|
|
tft.drawFastHLine(3, 121 - i*10, 120, GRAY);
|
|
}
|
|
if(start_hot==1){
|
|
tft.drawFastHLine(3,map(selected_opt[4],0,350,120,50), 120, ST77XX_YELLOW);
|
|
}else if(start_hot==2){
|
|
tft.drawFastHLine(3,map(set_temp,0,350,120,50), 120, ST77XX_YELLOW);
|
|
}
|
|
|
|
last_temp[index_temp] = map(tmp,0,350,120,50);
|
|
if(last_temp[index_temp] < 50)last_temp[index_temp] = 50;
|
|
for(int8_t i = 0; i < 120; i++){
|
|
int offset = i + index_temp;
|
|
if(offset > 120) offset -= 120;
|
|
// Serial.println(offset);
|
|
tft.drawPixel(i+4, last_temp[offset], ST77XX_BLACK);
|
|
tft.drawPixel(i+3, last_temp[offset], ST77XX_RED);
|
|
}
|
|
|
|
|
|
index_temp++;
|
|
if(index_temp>120) index_temp=0;
|
|
|
|
tft.drawFastVLine(3, 50, 70, ST77XX_WHITE);
|
|
tft.setTextSize(1);
|
|
tft.setTextColor(ST77XX_WHITE);
|
|
tft.setCursor(5,53); //Horiz/Vertic
|
|
tft.print("350");
|
|
tft.setCursor(5,73);
|
|
tft.print("250");
|
|
tft.setCursor(5,93);
|
|
tft.print("150");
|
|
tft.setCursor(128,128);
|
|
|
|
}
|
|
|
|
|
|
int computePID(float input, float setpoint, float kp, float ki, float kd, float dt, int minOut, int maxOut) {
|
|
float err = setpoint - input;
|
|
static float integral = 0, prevErr = 0;
|
|
integral = constrain(integral + (float)err * dt * ki, minOut, maxOut);
|
|
float D = (err - prevErr) / dt;
|
|
prevErr = err;
|
|
return constrain(err * kp + integral + D * kd, minOut, maxOut);
|
|
}
|
|
|
|
void action(){
|
|
int8_t act = read_action();
|
|
if(act != 0){
|
|
Serial.println(act);
|
|
switch(stage){
|
|
case 0://main sreen;
|
|
if(act < 2){
|
|
pos = set_temp;
|
|
stage = 1;
|
|
timer_td = 300;
|
|
Serial.println("stage = 1");
|
|
}else if(act == 20){
|
|
if(start_hot > 0){
|
|
start_hot = 0;
|
|
ds_clear_set_temp(selected_opt[4]);
|
|
ds_clear_set_temp(set_temp);
|
|
Serial.println("stop preheat");
|
|
ds_renew_temp();
|
|
}else{
|
|
stage = 2;
|
|
selected = 0;
|
|
ds_config();
|
|
Serial.println("stage = 2");
|
|
}
|
|
}else if(act == 10){
|
|
if(start_hot == 0){
|
|
start_hot = 1;
|
|
Serial.println("start preheat");
|
|
}else if(start_hot == 1){
|
|
timers = 0;
|
|
start_hot = 2;
|
|
ds_clear_set_temp(selected_opt[4]);
|
|
Serial.println("start hoting");
|
|
}else if(start_hot == 2){
|
|
start_hot = 1;
|
|
ds_clear_set_temp(set_temp);
|
|
Serial.println("stop hoting");
|
|
}
|
|
ds_renew_temp();
|
|
}
|
|
|
|
break;
|
|
|
|
case 1://main sreen;
|
|
if(act < 2){
|
|
pos += act;
|
|
if(pos > 350) pos = 350;
|
|
if(pos < 0) pos = 0;
|
|
ds_set_temp(pos);
|
|
timer_td = 300;
|
|
}else if(act == 40){
|
|
stage = 0;
|
|
ds_save_set_temp(set_temp);
|
|
Serial.println("stage = 0");
|
|
}else if(act == 10){
|
|
stage = 0;
|
|
ds_clear_set_temp(set_temp);
|
|
set_temp = pos;
|
|
timer_td = 0;
|
|
ds_save_set_temp(set_temp);
|
|
ds_grafik_draw(last_celsius);
|
|
Serial.println("stage = 0");
|
|
}else if(act == 20){
|
|
stage = 0;
|
|
timer_td = 0;
|
|
ds_save_set_temp(set_temp);
|
|
Serial.println("stage = 0");
|
|
}
|
|
|
|
Serial.println(pos);
|
|
break;
|
|
case 2://menu
|
|
if(act < 2){
|
|
selected += act;
|
|
if(selected < 0) selected = COUNT_selected-1;
|
|
if(selected > (COUNT_selected -1)) selected = 0;
|
|
ds_change_selected();
|
|
}else if(act == 10){
|
|
stage = 3;
|
|
pos = selected_opt[selected];
|
|
ds_set_selected(selected_opt[selected]);
|
|
timer_td = 300;
|
|
Serial.println("stage = 3");
|
|
}else if(act == 20){
|
|
stage = 0;
|
|
selected = 0;
|
|
ds_main();
|
|
Serial.println("stage = 0");
|
|
}
|
|
Serial.println(selected);
|
|
break;
|
|
case 3://select
|
|
if(act < 2){
|
|
pos += act;
|
|
ds_set_selected(pos);
|
|
timer_td = 300;
|
|
}else if(act == 10){
|
|
stage = 2;
|
|
selected_opt[selected] = pos;
|
|
ds_save_set_selected(selected_opt[selected]);
|
|
timer_td = 0;
|
|
prefs.begin("setting");
|
|
prefs.putBytes("setting", selected_opt, sizeof(selected_opt));
|
|
prefs.end();
|
|
Serial.println("stage = 2 save");
|
|
|
|
}else if(act == 20 || act == 40){
|
|
stage = 2;
|
|
ds_save_set_selected(selected_opt[selected]);
|
|
timer_td = 0;
|
|
Serial.println("stage = 2 nosave");
|
|
}
|
|
Serial.println(pos);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Task_temp_read(){
|
|
int analogValue = analogRead(12);
|
|
int streng;
|
|
int celsius = 1 / (log(1 / (4095. / analogValue - 1)) / BETA + 1.0 / 298.15) - 273.15+3;
|
|
last_celsius = celsius;
|
|
if(start_hot == 1){
|
|
streng = computePID(celsius, selected_opt[4], selected_opt[0]/10, selected_opt[1]/10, selected_opt[2]/10, 0.5, 0, 1000);
|
|
}else if(start_hot == 2){
|
|
streng = computePID(celsius, set_temp, selected_opt[0]/10, selected_opt[1]/10, selected_opt[2]/10, 0.5, 0, 1000);
|
|
}else if(start_hot == 0){
|
|
streng = 0;
|
|
}
|
|
pwm_activePeriod = streng;
|
|
//Serial.println(streng);
|
|
ds_ch_temp((celsius + last_celsius)/2);
|
|
|
|
}
|
|
void Task_time(){
|
|
if(start_hot== 2){
|
|
timers++;
|
|
ds_tick_timers();
|
|
}
|
|
}
|
|
|
|
void loop() {
|
|
if (millis() - time_timer >= time_period){
|
|
time_timer = millis();
|
|
Task_time();
|
|
}
|
|
|
|
|
|
if (millis() - read_timer >= read_period){
|
|
read_timer = millis();
|
|
Task_temp_read();
|
|
}
|
|
|
|
if (millis() - act_timer >= act_period){
|
|
act_timer = millis();
|
|
action();
|
|
}
|
|
|
|
if(pwm_activePeriod){
|
|
if (millis() - pwm_timer >= (pwm_flag ? pwm_activePeriod : (pwm_period - pwm_activePeriod))) {
|
|
pwm_timer = millis();
|
|
pwm_flag = !pwm_flag;
|
|
digitalWrite(RELEY, pwm_flag ^ pwm_dir);
|
|
hoting_on = pwm_flag ^ pwm_dir;
|
|
//Serial.println(hoting_on);
|
|
if(stage < 2){
|
|
ds_renew_hoting();
|
|
}
|
|
}
|
|
}else if(pwm_flag){
|
|
pwm_flag = !pwm_flag;
|
|
digitalWrite(RELEY, pwm_flag ^ pwm_dir);
|
|
hoting_on = pwm_flag ^ pwm_dir;
|
|
ds_renew_hoting();
|
|
}
|
|
|
|
|
|
}
|