Arduino Automotive Heater Controller - advice welcome!

Hi guys,

I am really excited to share my project here with a hope to learn from the more experienced among you!

Lets keep this short and sweet.

I used to hate electronics and I had zilch experience, after I did an k20 supercharged engine swap I discovered it may not be too bad, I then decided to jump in and get an DFRobot starter kit and a few evening later I find myself here.

My project is to create an automotive heating and air conditioning controller using a 2.8" TFT capacitive touch screen. Components so far:

  1. Arduino Uno R3.
  2. Adafruit 2.8” TFT Capacitive touch screen.
  3. Engine coolant temp sensor – yet to be determined.
  4. Cabin air temp sensor – yet to be determined.
  5. 4 Pos fan switch (with settable fan speeds) or Pot.
  6. Pot for heater controller.
  7. 12v 2-3a DC Fan.
  8. 12v DC Servo to control cable based water control valve.
  9. DC Motor Driver. I think this is called a H Bridge?
  10. 12v Air valves.

My plans are to have your typical automotive HVAC functions operated via buttons on the touch screen, current ideas for control:

• AC On/Off
• Defrost Vents On/Off
• Dash Vents On/Off
• Footwell Vents On/Off
• User Set Cabin Temp – Arduino control over fan, water valve and AC to maintain.

The layout of the touch screen control is to have the buttons at the bottom with the engine coolant and air temps displayed at the top of the screen.

I am still at the very early stages of writing the code but thought now is a good a time as any to show where I am and to seek recommendations on whether I am going in the right direction.

So far I have the button change colour from blue to cyan when pressed, and back to blue when pressed again, unfortunately the button can cycle very quickly registered multiple touches per press, I have researched into a timer to not allow a second press within a certain amount of time with using a delay function, what would be the best way to go about this?

//screen size: 240 x 320px
//orientation: portrait

#include <Adafruit_GFX.h>    // Core graphics library
#include <SPI.h>       // this is needed for display
#include <Adafruit_ILI9341.h>
#include <Wire.h>      // this is needed for FT6206
#include <Adafruit_FT6206.h>

// The FT6206 uses hardware I2C (SCL/SDA)
Adafruit_FT6206 ctp = Adafruit_FT6206();

// The display also uses hardware SPI, plus #9 & #10
#define TFT_CS 10
#define TFT_DC 9

// Size of the menu colour selection boxes
#define RecHeight   60
#define RecLength   105

#define BLACK       0x0000
#define CYAN        0x07FF
#define RED         0xF800
#define BLUE        0x001F
#define WHITE       0xFFFF
#define textsize    4

int ACSELECT = 0;

Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC);


void setup() {
 // Serial Touch Setup.
while (!Serial);     // used for leonardo debugging

 Serial.begin(300);
 /*Serial.println(F("Cap Touch Screen")); */

 tft.begin();

 if (! ctp.begin(40)) {  // pass in 'sensitivity' coefficient
   Serial.println("Couldn't start FT6206 touchscreen controller");
   while (1);
 }

 Serial.println("Capacitive touchscreen started");

tft.fillScreen(BLACK);

// 1st Box
// tft,fillRect(X position, Y Position, width, height, colour)
tft.fillRect(10, 250, RecLength, RecHeight, BLUE);

//1st Box Text
tft.setCursor(40, 264);
tft.setTextColor(WHITE);
tft.setTextSize(textsize);
tft.print("AC");

// 2nd Box
tft.fillRect(10, 180, RecLength, RecHeight, BLUE);


// 3rd Box
tft.fillRect(125, 250, RecLength, RecHeight, BLUE);


// 4th Box
tft.fillRect(125, 180, RecLength, RecHeight, BLUE);

}

void loop() {
 // Wait for a touch
 if (! ctp.touched()) {
   return;
 }

 // Retrieve a point  
 TS_Point p = ctp.getPoint();
 
/*
 // Print out raw data from screen touch controller
 Serial.print("X = "); Serial.print(p.x);
 Serial.print("\tY = "); Serial.print(p.y);
 Serial.print(" -> ");
*/

 // flip it around to match the screen.
 p.x = map(p.x, 0, 240, 240, 0);
 p.y = map(p.y, 0, 320, 320, 0);

 // Print out the remapped (rotated) coordinates
 Serial.print("("); Serial.print(p.x);
 Serial.print(", "); Serial.print(p.y);
 Serial.println(")");

if (p.y > 250 && p.y < 310 && p.x > 10 && p.x < 115) { // if this area is pressed
if (ACSELECT < 1){
 tft.fillRect(10, 250, RecLength, RecHeight, CYAN);
tft.setCursor(40, 264);
tft.setTextColor(WHITE);
tft.setTextSize(textsize);
tft.print("AC");

ACSELECT = 1;

} else if (ACSELECT > 0){
 tft.fillRect(10, 250, RecLength, RecHeight, BLUE);
tft.setCursor(40, 264);
tft.setTextColor(WHITE);
tft.setTextSize(textsize);
tft.print("AC");

ACSELECT = 0;  
}
     }
}

Please ask specific questions, and use code tags </> when posting code.

Cheers, updated with tags.

Here is a good debounce that doesnt block like a delay would ,is easy to implement and doesn't require a timer .

const byte button = 5;
const byte ledPin = 13;

void setup() {
  pinMode (button,INPUT_PULLUP);
  pinMode(ledPin,OUTPUT);
}

void loop() {
  byte buttonState = buttonCheck(); // check for button press
  
  if (buttonState) {    // same as:  if (buttonState == 1)
    digitalWrite (ledPin,HIGH);
    delay (250);     // hate delay but its just an example
  } else {
    digitalWrite (ledPin,LOW);
  }
}

byte buttonCheck()   // Returns a positive result Once per press
{
  static int isButtonPressed = 0;

  if (digitalRead(button) == LOW)   //  button reads LOW when Pressed
  {
    isButtonPressed++;              // Increment Debounce variable
  } else {
    isButtonPressed = 0;            // if it bounces reset
  }

  if (isButtonPressed == 10)    //number of consecutive positive reads to be accepted as a legitimate press
  {                                                // Adjust as needed
    return 1;               // Confirmed button Press
  } else {
    return 0;               // button not pressed
  }
}

• AC On/Off
• Defrost Vents On/Off
• Dash Vents On/Off
• Footwell Vents On/Off

Have you thought out the electro-mechanical of all that? If not, you may want to consider it before you jump into this project. - Scotty

Hi,
I think this is a do-able project programming and controller wise.
I agree with scottyjr, some of these mechanical controls are quite hard to move, or use a lot of unseen leverage.
So servo might need to be small linear actuator instead.
You will need to do some tests with simple programs and try the servo idea to get the equipment level right.

This would be an ideal project for customising a vehicle...

Tom.... :slight_smile:

I have installed and serviced many aftermarket and factory automotive HVAC systems, and what you are planning is pretty much spot on how the aftermarket does it. Although the TFT is a nice touch I haven't yet seen.

I'm guessing this is an older car since modern cars and aftermarket units already use Electric Actuators for the vent door's.
I think I would use a small hobby stepper since it takes very little force to move the vent door's, but it needs to hold it's position against the wind pressure of the blower motor. Which a stepper is better at than a servo.

The water valve will need a bigger stepper or servo, but it may be easier to use a ready made unit such as this one: Heater control valve

The hardest part of this project will probably be mounting the steppers to the vent door's as they are often in small and hard to get to area's.

Thanks for the replies!

Hutkikz - Thanks for the recommendation. Shortly after I wrote my original post I came across this function, coded it in and worked fine however would the debounce method be more suitable?

if ((unsigned long)(millis() - previousMillis) >= interval) {

scottyjr - I haven't hooked anything up yet - working on the theory at present. For the air valves I have a commercial device that will operate when 12v is applied to one pin, it will rotate and stop once it reaches its end point, to rotate back you apply 12v to the 3rd pin. The only one that does require full servo control is the water valve. I have a plan to use a 12v servo but still need to look into the wiring.
The fan draws 2a running and 3a startup, I am currently looking for DC motor drivers.

TomGeorge - Definitely agree with trying to get everything working one component at a time, it helps keep things simple. Once I have got it all figured out then I'll try to consolidate the code.

What is the best way to display icons, try to draw them with code or use bitmap images saved to an SD card? I would like to have icons for AC, defrost, footwell and dashboard etc, are there any tutorials on displaying images from the SD card?