Question About Arduino Power and Question about Rotary Encoder

I am currently working on a heating stage project and I wanted to know if I can use a 12V AC Adapter to convert 120VAC to 12VDC to power my Arduino Uno Rev3 with its power barrel. The adapter is rated for 12 V and 850 mA. I also have one that is 9 V and 750 mA as well. I am trying to plug in the adapter into the barrel and use the Vin to power a polyimide heating element and use the 5V pin on the Arduino to power a LCD display, encoder, and Max675 module for an encoder. Is the 12V AC adapter safe to use and is the Arduino able to power components using Vin and 5V pin? I have attached a schematic to explain how the circuit is wired. It is based on a Youtube video for PID control.

I also am having issues with my rotary encoder. I am using a 360 Degree Rotary Encoder Module KY-040 but when I have it running only using the 5V pin on the Arduino the menu on the LCD menu constantly change while increasing the PID constants.
Here is my code:

/*                                Project Details:
* The heating stage device will use an Arduino as a PID controller to regulate the heat liquid crystal samples will use.
* The device will use two polyimide heating elements to apply heat to the top and bottom of the sample.
* The sample holding case will be made of aluminum for its good conductive properties.
* It is assumed that both sides will have the same temperature, but an average will be used for calculations.
* The heating stage will also incorporate a 5mm hole so that POM images can be taken.
*/

/*                                  Code Info:
 * Uses Max6675 Module for two thermal couple sensors to tell temperature and prints to LCD
 * The code will provide information for if the two sensors are reading the same temperature.
 * This revision of the code will add in the encoder and set temperature for the device.
 * For the PID control an average will be taken for the temperature calculations.
 * The ecoder will be used to determine the setpoint and will allow the user to have access to 4 different menus.
 * Menu: (When selecting a value press the encoder to slect that value and move to the next menu)
 *  1) setpoint
 *  2) Set P value
 *  3) Set I value
 *  4) Set D value
 * Once values are selected press the encoder again to start.
*/

/*                                     Notes:
* For the liquid crystal display and Max667 Module the appropriat libraries must be installed
* For the Max667 Module portion of the code install the MAX6675 library designed for the chip and k type thermalcouple.
* For LCD I2C portion of code install the LiquidCrystal I2C libray. 
* To operate the heating stage a 12 VDC powersupply will be required.
*/

/*                                   Pinouts:                                     
*     Max6675 Module(x2) ==>   Arduino
 *     - CS              ==>     D10 (Top)         D6 (Bottom)
 *     - SO              ==>     D12 (Top)         D4 (Bottom)
 *     - SCK             ==>     D13 (Top)         D5 (Bottom)
 *     - Vcc             ==>     Vcc - 5v (Both)
 *     - Gnd             ==>     Gnd      (Both) 
 
 *    i2c LCD Module     ==>   Arduino
 *     - SCL             ==>     A5
 *     - SDA             ==>     A4
 *     - Vcc             ==>     Vcc - 5v 
 *     - Gnd             ==>     Gnd      
 
 *    Encoder           ==>    Arduino
 *     - PWM_pin        ==>    D3
 *     - Clock          ==>    D8
 *     - Data           ==>    D9
*      - Switch         ==>    D11

 /*                                    Code:                                                       */
#include <SPI.h>
//LCD config
#include <Wire.h> 
#include <LiquidCrystal_I2C.h>
LiquidCrystal_I2C lcd(0x27,20,4);  //sometimes the adress is not 0x3f. Change to 0x27 if it dosn't work.

/* Input For Encoder */
int PWM_pin = 3;  //Pin for PWM signal to the MOSFET driver (the BJT npn with pullup)
int clk = 4;      //Pin 1 from rotary encoder
int data = 5;     //Pin 2 from rotary encoder
int SW = 11;      //Switch

/*                                   Variables:                                                     */
float temperature_read = 0;          // Used in set temperature calculations
float set_temperature = 0;            //Default temperature setpoint. Leave it 0 and control it with rotary encoder
float Top_temperature_read = 0.0;     // Used for reading top part etemperature
float Bottom_temperature_read = 0.0;  // Used for reading bottom part temperature
float avg_temperature = 0.0;          // Used for average temperature for the two plates
float PID_error = 0;                  // Error of PID control
float previous_error = 0;             // Used for Derivative portion of code
float elapsedTime, Time, timePrev;    // Time variables
float PID_value = 0;                  // Value for PWM
int button_pressed = 0;               // Used for encoder code portion for menu selection
int menu_activated=0;                 // Menu for prompt selection
float last_set_temperature = 0;       // Used for updating temperature

//Variables for rotary encoder state detection
int clk_State;
int Last_State;  
bool dt_State;  

//PID constants
int kp = 0;                         // Proportional Term
int ki = 0;                         // Integral Term
int kd = 0;                         // Derivative Term
int PID_p = 0;                       // PID value for Poportional Term
int PID_i = 0;                       // PID value for Intergral Term  
int PID_d = 0;                       // PID value for Derivative Term
float last_kp = 0;                   // Update value for Proportional Term
float last_ki = 0;                   // Update value for Itergral Term
float last_kd = 0;                   // Update value for Derivative Term
int PID_values_fixed = 0;

//Pins for the SPI with MAX6675
#define TOP_MAX6675_CS   10
#define TOP_MAX6675_SO   12
#define TOP_MAX6675_SCK  13

#define BOT_MAX6675_CS   6
#define BOT_MAX6675_SO   4
#define BOT_MAX6675_SCK  5

void setup() 
{     
  pinMode(PWM_pin,OUTPUT);
  TCCR2B = TCCR2B & B11111000 | 0x03;    // pin 3 and 11 PWM frequency of 928.5 Hz
  Time = millis();

  //Encoder Triggers
  Last_State = (PINB & B00000001);      //Detect first state of the encoder
  PCICR |= (1 << PCIE0);    //enable PCMSK0 scan                                                 
  PCMSK0 |= (1 << PCINT0);  //Set pin D4 trigger an interrupt on state change. 
  PCMSK0 |= (1 << PCINT1);  //Set pin D5 trigger an interrupt on state change. 
  PCMSK0 |= (1 << PCINT2);  //Set pin D11 trigger an interrupt on state change.    

  //I/O      
  pinMode(11,INPUT);                    // For switch
  pinMode(9,INPUT);                     // For data
  pinMode(8,INPUT);                     // For clock

  // For the LCD
  lcd.init();
  lcd.backlight();

}

void loop() 
{

  float Top_Temp = readThermocouple_TOP();                    // Reads as a decimal
  float Bot_Temp = readThermocouple_BOT();                    // Reads as a decimal
  float avg_temperature = (Top_Temp + Bot_Temp)/2;

    if(menu_activated==0)
    {
        // First we read the real value of temperature
        temperature_read = avg_temperature ;  
        //Next we calculate the error between the setpoint and the real value
        PID_error = set_temperature - temperature_read + 3;
        //Calculate the P value
        PID_p = 0.01*kp * PID_error;
        //Calculate the I value in a range on +-3
        PID_i = 0.01*PID_i + (ki * PID_error);
        //For derivative we need real time to calculate speed change rate
        timePrev = Time;                            // the previous time is stored before the actual time read
        Time = millis();                            // actual time read
        elapsedTime = (Time - timePrev) / 1000; 
        //Now we can calculate the D calue
        PID_d = 0.01*kd*((PID_error - previous_error)/elapsedTime);
        //Final total PID value is the sum of P + I + D
        PID_value = PID_p + PID_i + PID_d;
        //We define PWM range between 0 and 255
        if(PID_value < 0)
          {    PID_value = 0;    }
          if(PID_value > 255)  
          {    PID_value = 255;  }
      //Now we can write the PWM signal to the mosfet on digital pin D3
      //Since we activate the MOSFET with a 0 to the base of the BJT, we write 255-PID value (inverted)
      analogWrite(PWM_pin,255-PID_value);
      previous_error = PID_error;     //Remember to store the previous error for next loop.
      delay(300); //Refresh rate + delay of LCD print
      //lcd.clear();
        
      lcd.setCursor(0,0);
      lcd.print("PID TEMP control");
      lcd.setCursor(0,1);
      lcd.print("S:");
      lcd.setCursor(2,1);
      lcd.print(set_temperature,1);
      lcd.setCursor(9,1);
      lcd.print("R:");
      lcd.setCursor(11,1);
      lcd.print(temperature_read,1);
    }//end of menu 0 (PID control)

{
  //First page of menu (temp setpoint)
  if(menu_activated == 1)
    {
      analogWrite(PWM_pin,255);
      if(set_temperature != last_set_temperature)
      {
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Set  temperature");    
      lcd.setCursor(0,1);
      lcd.print(set_temperature);  
      }
      last_set_temperature = set_temperature;
    }//end of menu 1


  //Second page of menu (P set)
  if(menu_activated == 2)
    {
      if(kp != last_kp)
        {
          lcd.clear();
          lcd.setCursor(0,0);
          lcd.print("Set   P  value  ");    
          lcd.setCursor(0,1);
          lcd.print(kp);  
        }
        last_kp = kp;
    }//end of menu 2

//Third page of menu (I set)
  if(menu_activated == 3)
    {
      if(ki != last_ki)
      {
        lcd.clear();
        lcd.setCursor(0,0);
        lcd.print("Set   I  value  ");    
        lcd.setCursor(0,1);
        lcd.print(ki);  
      }
        last_ki = ki;
    }//end of menu 3

//Forth page of menu (D set)
  if(menu_activated == 4)
    {
      
      if(kd != last_kd)
      {
      lcd.clear();
      lcd.setCursor(0,0);
      lcd.print("Set   D  value  ");    
      lcd.setCursor(0,1);
      lcd.print(kd);  
      }
      last_kd = kd;
    }//end of menu 4
}
}

//Functions that reads the SPI data from MAX6675
/* Top Thermal Couple Function */
double readThermocouple_TOP()
{
  uint16_t v;
  pinMode(TOP_MAX6675_CS, OUTPUT);                 // Output
  pinMode(TOP_MAX6675_SO, INPUT);                   
  pinMode(TOP_MAX6675_SCK, OUTPUT);
  digitalWrite(TOP_MAX6675_CS, LOW);
  delay(1);
  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit  
  //  1..0  = uninteresting status
  v = shiftIn(TOP_MAX6675_SO, TOP_MAX6675_SCK, MSBFIRST);
  v <<= 8;
  v |= shiftIn(TOP_MAX6675_SO, TOP_MAX6675_SCK, MSBFIRST);
  digitalWrite(TOP_MAX6675_CS, HIGH);
  if (v & 0x4) 
      {    
        // Bit 2 indicates if the thermocouple is disconnected
        return NAN;     
      }
  // The lower three bits (0,1,2) are discarded status bits
  v >>= 3;
  // The remaining bits are the number of 0.25 degree (C) counts
  return v*0.25;
}

/* Bottom Thermal Couple Function */
 double readThermocouple_BOT()
{
  uint16_t v;
  pinMode(BOT_MAX6675_CS, OUTPUT);                 // Output
  pinMode(BOT_MAX6675_SO, INPUT);                   
  pinMode(BOT_MAX6675_SCK, OUTPUT);
  digitalWrite(BOT_MAX6675_CS, LOW);
  delay(1);
  // Read in 16 bits,
  //  15    = 0 always
  //  14..2 = 0.25 degree counts MSB First
  //  2     = 1 if thermocouple is open circuit  
  //  1..0  = uninteresting status
  v = shiftIn(BOT_MAX6675_SO, BOT_MAX6675_SCK, MSBFIRST);
  v <<= 8;
  v |= shiftIn(BOT_MAX6675_SO, BOT_MAX6675_SCK, MSBFIRST);
  digitalWrite(BOT_MAX6675_CS, HIGH);
  if (v & 0x4) 
  {    
    // Bit 2 indicates if the thermocouple is disconnected
    return NAN;     
  }
  // The lower three bits (0,1,2) are discarded status bits
  v >>= 3;
  // The remaining bits are the number of 0.25 degree (C) counts
  return v*0.25;
}

//The interruption vector for push button and rotary encoder
ISR(PCINT0_vect)
{
if(menu_activated==1)
   {
  clk_State =   (PINB & B00000001); //pin 8 state? It is HIGH? 
  dt_State  =   (PINB & B00000010); 
  if (clk_State != Last_State)
  {     
     // If the data state is different to the clock state, that means the encoder is rotating clockwise
     if (dt_State != clk_State) { 
       set_temperature = set_temperature+0.5 ;
     }
     else {
       set_temperature = set_temperature-0.5;
     } 
  }
  Last_State = clk_State; // Updates the previous state of the clock with the current state
} 

if(menu_activated==2)
   {
  clk_State =   (PINB & B00000001); //pin 8 state? 
  dt_State  =   (PINB & B00000010); 
  if (clk_State != Last_State){     
     // If the data state is different to the clock state, that means the encoder is rotating clockwise
     if (dt_State != clk_State) { 
       kp = kp+1 ;
     }
     else {
       kp = kp-1;
     } 
  }
  Last_State = clk_State; // Updates the previous state of the clock with the current state
} 


if(menu_activated==3)
   {
  clk_State =   (PINB & B00000001); //pin 8 state? 
  dt_State  =   (PINB & B00000010); 
  if (clk_State != Last_State){     
     // If the data state is different to the clock state, that means the encoder is rotating clockwise
     if (dt_State != clk_State) { 
       ki = ki+1 ;
     }
     else {
       ki = ki-1;
     } 
  }
  Last_State = clk_State; // Updates the previous state of the clock with the current state
}

 if(menu_activated==4)
   {
  clk_State =   (PINB & B00000001); //pin 4 state? 
  dt_State  =   (PINB & B00000010); 
  if (clk_State != Last_State){     
     // If the data state is different to the clock state, that means the encoder is rotating clockwise
     if (dt_State != clk_State) { 
       kd = kd+1 ;
     }
     else {
       kd = kd-1;
     } 
  }
  Last_State = clk_State; // Updates the previous state of the clock with the current state
}
   
  //Push button was pressed!
  if (PINB & B00001000) //Pin D11 is HIGH?
  {       
    button_pressed = 1;
  } 
  //We navigate through the 4 menus with each button pressed
  else if(button_pressed == 1)
  {
   
   if(menu_activated==4)
   {
    menu_activated = 0;  
    PID_values_fixed=1;
    button_pressed=0; 
    delay(1000);
   }

   if(menu_activated==3)
   {
    menu_activated = menu_activated + 1;  
    button_pressed=0; 
    kd = kd + 1; 
    delay(1000);
   }

   if(menu_activated==2)
   {
    menu_activated = menu_activated + 1;  
    button_pressed=0; 
    ki = ki + 1; 
    delay(1000);
   }

   if(menu_activated==1)
   {
    menu_activated = menu_activated + 1;  
    button_pressed=0; 
    kp = kp + 1; 
    delay(1000);
   }


   if(menu_activated==0 && PID_values_fixed != 1)
   {
    menu_activated = menu_activated + 1;  
    button_pressed=0;
    set_temperature = set_temperature+1;   
    delay(1000);
   }
   PID_values_fixed = 0;
   
  }  
}

Also here is information about the heater:
Voltage Range: 1.5v~400v
Power density range :0.03w/cm2~1.5w/cm2
Using temperature range:-185ºC - 180ºC

You can not power any Arduino from AC.

yes the AC DC adapter are OK. both. Vin will have the DC of the adapter 12 or 9 V.

Try INPUT_PULLUP on your encoder inputs.

You have several delay(1000)s in the interrupt routine. delay() means do nothing for X time. You should investigate timing with millis(). Sources abound on the web and this forum.

There is way too much going on the the interrupt routine. An ISR should be very short - set a flag at minimum - and the processing be done in the mainline code. There's also a lot of repetitive checking of the encoder in the ISR. It'd be better to just check the encoder for rotation and return a clockwise/counter-clockwise signal and handle the value adjustments in the main code.

Also, any variables used in both main code and the ISR should be declared with the 'volatile' keyword.

1 Like

Could you state which parts please. I am a little confused.

For the encoder portion of the circuit the LCD keeps cycling each menu with out being pressed and adding 1 to the constant value. It worked before and I am not sure what I did wrong.

To be specific if i hold done the press button I am able to increase the setpoint by turning the shaft.

I'd start with these two items. You can find more info at

1 Like

What should variables do recommend to change to volatile? Also I am using external pull up resistors is input pull even needed? I think that there is something wrong with the switch would I need to use that for pin 11? For instance if I hold the button the menu stops changing rapidly.

It's a language issue. I don't understand the question.

Did you read about volatile in the link given in #9?

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.