Advertisement
Szerelo

PID setting Demo on LCD display with Rotary encoder

May 16th, 2021 (edited)
572
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 7.48 KB | None | 0 0
  1. // PID setting menu demo with Rotary encoder
  2. // and autosave function
  3. // Pressing the button starts or stops the output (Built in LED)
  4. // A long press on the button enters the setting, then you can switch there by a short press on the button
  5. // The values can be changed with the encoder
  6. // You can exit the setting by long pressing
  7. // The values are saved automatically
  8.  
  9. // It also has a built-in auto-save function, but it only works if a sufficiently large capacity is connected to the 5V supply voltage.
  10.  
  11. #include <LiquidCrystal_I2C.h>
  12. #include <Rotary.h>
  13. #include <EEPROM.h>
  14. #include <PID_v1.h>
  15.  
  16. #define button A0   // Rotary encoder button
  17. #define led 13      // Built in LED
  18.  
  19. #define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit))    // bit operation macro
  20. #define bit_is_set(sfr, bit) (_SFR_BYTE(sfr) & _BV(bit))
  21.  
  22. float Ucc = 0;    // Microcontroller supply voltage
  23.  
  24. unsigned long currentMillis=0;
  25. unsigned long previousMillis=0;
  26. unsigned int value=0;     // This is just an example value to have something on the display
  27. bool Run=false;
  28. byte menu=0;
  29.  
  30. unsigned long lastDebounceTime = 0;
  31. unsigned long debounceDelay = 50;
  32. unsigned long longPressDelay = 1000;
  33.  
  34. bool readingButton;
  35. bool buttonShort=false;
  36. bool buttonLong=false;
  37. bool buttonShortPress=false;
  38. bool buttonLongPress=false;
  39. bool reading=true;
  40. bool setting=false;
  41.  
  42. double Setpoint, Input, Output;
  43. double Kp=1, Ki=0.05, Kd=0.25;
  44.  
  45. PID myPID(&Input, &Output, &Setpoint, Kp, Ki, Kd, DIRECT);
  46.  
  47. //LiquidCrystal_I2C lcd(0x27, 2, 1, 0, 4, 5, 6, 7, 3, POSITIVE);  // Set the LCD I2C address
  48. LiquidCrystal_I2C lcd(0x27,16,2);  // set the LCD address to 0x27 for a 16 chars and 2 line display
  49.  
  50. Rotary r = Rotary(9, 8);            // define rottary encoder and pins
  51.  
  52. void setup() {
  53.   ADMUX = (0 << ADLAR) | (1 << REFS0) | (14 << MUX0) ;  // ADC settings
  54.   sbi(ADCSRA, ADSC);      // ADC conversion start
  55.   Serial.begin(115200);
  56.   Serial.println("Start ...");
  57.   lcd.init();                      // initialize the lcd
  58.   lcd.backlight();
  59.   pinMode(button, INPUT_PULLUP);
  60.   pinMode(led, OUTPUT);
  61.   r.begin(true);
  62.   EEPROM.get(0, Kp);
  63.   EEPROM.get(4, Ki);
  64.   EEPROM.get(8, Kd);
  65.   if (Kp<0){  // For an empty EEPROM, these will be the default values
  66.     Kp=1;
  67.     Ki=0.05;
  68.     Kd=0.25;
  69.   }
  70.   while(bit_is_set(ADCSRA,ADIF)){
  71.      Ucc=(1024*1.1)/(ADCL+256*ADCH );   // Calculation of the Microcontroller supply voltage
  72.      sbi(ADCSRA, ADSC);
  73.   }
  74.   Serial.println(Ucc);
  75.   delay(500);   // Waiting for a power-on transient
  76.   while(bit_is_set(ADCSRA,ADIF)){
  77.      Ucc=(1024*1.1)/(ADCL+256*ADCH );
  78.      sbi(ADCSRA, ADSC);
  79.   }
  80.   Serial.println(Ucc);
  81.   delay(500);   // expecting the supply voltage to be measured for sure
  82.   lcd.clear();
  83.   disp();     // Print on the display
  84.   Serial.println("..");
  85.   myPID.SetMode(AUTOMATIC);
  86. }
  87.  
  88. void loop() {
  89.   while(bit_is_set(ADCSRA,ADIF)){
  90.      Ucc=(1024*1.1)/(ADCL+256*ADCH );
  91.      sbi(ADCSRA, ADSC);
  92.   }
  93.   if (Ucc<4) {    // Supply voltage check
  94.     lcd.noBacklight();
  95.     digitalWrite(led, LOW);
  96.     save();
  97.     digitalWrite(led, HIGH);
  98.   }
  99.  
  100.   unsigned char result = r.process();   // Encoder check
  101.  
  102.   myPID.Compute();
  103.  
  104.   pressButton();    // Button check
  105.   if (setting==false) {  // Normal mode
  106.     if (buttonShort==true and readingButton==HIGH){
  107.       reading=false;
  108.       buttonShort=false;
  109.       Serial.println("Short Press");    // The button has been pressed short time
  110.       if (Run==false) {
  111.         Run=true;
  112.         digitalWrite(led,HIGH);
  113.         Serial.println("Start");
  114.       } else {
  115.         Run=false;
  116.         digitalWrite(led,LOW);
  117.         Serial.println("Stop");
  118.       }
  119.       disp();
  120.     }
  121.   } else {    // Settings
  122.     if (buttonShort==true and readingButton==HIGH){
  123.       reading=false;
  124.       buttonShort=false;
  125.       Serial.println("Short Press");
  126.       menu++;
  127.       if (menu==4) menu=1;
  128.       disp();
  129.     }
  130.     if (result == DIR_CCW) {
  131.       setplus();
  132.       myPID.SetTunings(Kp,Ki,Kd);
  133.       disp();
  134.     }
  135.     if (result == DIR_CW) {
  136.       setminus();
  137.       myPID.SetTunings(Kp,Ki,Kd);
  138.       disp();
  139.     }
  140.   }
  141.  
  142.   if (buttonLong==true){
  143.     reading=false;
  144.     buttonLong=false;
  145.     Serial.println("Long Press");   // The button has been pressed long time
  146.     if (setting==true) {
  147.       setting=false;
  148.       menu=0;
  149.       Serial.println("Normal");
  150.       save();
  151.     } else {
  152.       setting=true;
  153.       menu=1;
  154.       Serial.println("Setting");
  155.     }
  156.     disp();
  157.   }
  158.  
  159.   currentMillis = millis();
  160.   if (currentMillis - previousMillis >= 1000) {   // Timer every 1 second due to display refresh
  161.     previousMillis = currentMillis;
  162.     tick();
  163.   }
  164.  
  165. }
  166.  
  167. void setplus() {    // Increase value
  168.   Serial.print(menu);
  169.   Serial.print(" ");
  170.   Serial.println(Kp);
  171.   if (menu==1) {
  172.     Kp=Kp+0.01;
  173.     if (Kp>10) Kp=10;
  174.   }
  175.   if (menu==2) {
  176.     Ki=Ki+0.01;
  177.     if (Ki>10) Ki=10;
  178.   }
  179.   if (menu==3) {
  180.     Kd=Kd+0.01;
  181.     if (Kd>10) Kd=10;
  182.   }
  183. }
  184.  
  185. void setminus() {   // Decrease value
  186.   if (menu==1) {
  187.     Kp=Kp-0.01;
  188.     if (Kp<0) Kp=0;
  189.   }
  190.   if (menu==2) {
  191.     Ki=Ki-0.01;
  192.     if (Ki<0) Ki=0;
  193.   }
  194.   if (menu==3) {
  195.     Kd=Kd-0.01;
  196.     if (Kd<0) Kd=0;
  197.   }
  198. }
  199.  
  200. void tick() {
  201.   value++;
  202.   disp();
  203. }
  204.  
  205. void disp() {
  206.   if (menu==0) {
  207.     lcd.setCursor(0,0);
  208.     if (Run==false) {
  209.       lcd.print("Waiting         ");
  210.     } else {
  211.       lcd.print("Running         ");
  212.     }
  213.     lcd.setCursor(10,0);
  214.     if (value<10) lcd.print(" ");
  215.     if (value<100) lcd.print(" ");
  216.     if (value<1000) lcd.print(" ");
  217.     if (value<10000) lcd.print(" ");
  218.     lcd.print(value);
  219.   }
  220.   if (menu==1) {
  221.     lcd.setCursor(0,0);
  222.     lcd.print(" Kp             ");
  223.   }
  224.   if (menu==2) {
  225.     lcd.setCursor(0,0);
  226.     lcd.print("       Ki       ");
  227.   }
  228.   if (menu==3) {
  229.     lcd.setCursor(0,0);
  230.     lcd.print("             Kd ");
  231.   }
  232.   lcd.setCursor(0,1);
  233.   lcd.print(Kp);
  234.   lcd.print("  ");
  235.   lcd.setCursor(6,1);
  236.   lcd.print(Ki);
  237.   lcd.print("  ");
  238.   lcd.setCursor(12,1);
  239.   lcd.print(Kd);
  240.   lcd.print("  ");
  241. }
  242.  
  243.  
  244. void pressButton() {
  245.   readingButton = digitalRead(button);
  246.   if (readingButton==LOW and reading==true) {
  247.     if ((millis() - lastDebounceTime) > debounceDelay) {  // Check the prell time
  248.       buttonShort=true;
  249.     }
  250.     if ((millis() - lastDebounceTime) > longPressDelay) {
  251.       buttonLong=true;
  252.       buttonShort=false;
  253.     }
  254.   }// else {
  255.   if (readingButton==HIGH) {
  256.     lastDebounceTime=millis();
  257.     reading=true;
  258.   }
  259. }
  260.  
  261. void save() {
  262.   EEPROM.put(0,Kp);
  263.   EEPROM.put(4,Ki);
  264.   EEPROM.put(8,Kd);
  265. }
  266. /*
  267. Alternative function
  268. When pressed for a long time, it does not enter automatically, but waits for the button to be released
  269.  
  270. void pressButton() {
  271.   readingButton = digitalRead(button);
  272.     if (readingButton==LOW ) {   // meg van nyomva a gomb
  273.       if ((millis() - lastDebounceTime) > debounceDelay) {
  274.         buttonShort=true;
  275.       }
  276.       if ((millis() - lastDebounceTime) > longPressDelay) {
  277.         buttonLong=true;
  278.         buttonShort=false;
  279.       }
  280.     } else {  // nincs megnyomva a gomb
  281.       lastDebounceTime=millis();
  282.       if (buttonShort==true) {
  283.         buttonShortPress=true;
  284.         buttonShort=false;
  285.       }
  286.       if (buttonLong==true) {
  287.         buttonLongPress=true;
  288.         buttonLong=false;
  289.       }
  290.     }
  291.   if (buttonShortPress==true) {
  292.     buttonShortPress=false;
  293.     Serial.println("Short Press");
  294.   }
  295.   if (buttonLongPress==true) {
  296.     reading=true;
  297.     lastDebounceTime=millis();
  298.     buttonLongPress=false;
  299.     Serial.println("Long Press");
  300.   }
  301. }
  302.  */
  303.  
  304. // END
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement