If you want to mimic this at home, here's a basic code to start with.
Pins 2,3 and 4 are connected to from ground pin through momentary push buttons on the dashboard for volume and 'pause/recall' last voice readout.
Pins 5 through 9 get connected to ignition, lights ect, you can add more functions if you like, if you can find or make the sound effects for them.
In this code the pins for the max6675 thermocouple module are 12,13 & A1
All these pins are visible on the board.
And you'll need one of the DFRobot mini MP3 modules. They're not expensive & take a little tf card? micro Sd card?
Just add the files for the sound effects (MP3 or wave files) with names like "0001" or "0002". The power up sound is 0002 in my code.
If you add more to this code. The code module seems to like receiving commends in hex. So 0011 would be read as '000b'.
I used zener diodes for cutting the voltage from the 12 volt system down to a safe 3.3 or 5 volts for the arduino. But you can, and should use relays.
You'll need to download & add the software serial and max6675 libraries but that's pretty easy.
#include <max6675.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(10, 11);
int soPin = 12;// SO=Serial Out
int csPin = 13;// CS = chip select CS pin
int sckPin = A1;// SCK = Serial Clock pin
MAX6675 thermoSensor(sckPin, csPin, soPin);
int volatile thermoSensorNewVal, thermoSensorOldVal; // an attempt to add zoomcats potentometer test to thermosensor
#define TEMP_BAND 2
#define TEMP_MINOR 60
#define TEMP_GENERAL 75
#define TEMP_DIRE 90
#define INCR_MINOR (TEMP_MINOR + TEMP_BAND)
#define INCR_GENERAL (TEMP_GENERAL + TEMP_BAND)
#define INCR_DIRE (TEMP_DIRE + TEMP_BAND)
#define DECR_IDLE (TEMP_MINOR - TEMP_BAND)
#define DECR_MINOR (TEMP_GENERAL - TEMP_BAND)
#define DECR_GENERAL (TEMP_DIRE - TEMP_BAND)
enum warningStates_t {IDLE = 0, WARN_MINOR, WARN_GENERAL, WARN_DIRE};
warningStates_t curState, oldState;
int buttonPause = 3;
int buttonVolPlus = 2;
int buttonVolMinus = 4;
# define ACTIVATED LOW
boolean isPlaying = false;
const int buttonPin = 6; // the pin that the pushbutton is attached to
const int buttonPin2 = 7; // the pin that the pushbutton is attached to
const int buttonPin3 = 8; // the pin that the pushbutton is attached to
const int buttonPin4 = 9; // the pin that the pushbutton is attached to
const int buttonPin5 = 5;
// the pin that the pushbutton is attached to
// Variables will change:
int buttonPushCounter = 0; // counter for the number of button presses
int buttonState = 0; // current state of the button
int lastButtonState = 0; // previous state of the button
int buttonPushCounter2 = 0; // counter for the number of button presses
int buttonState2 = 0; // current state of the button
int lastButtonState2 = 0; // previous state of the button
int buttonPushCounter3 = 0; // counter for the number of button presses
int buttonState3 = 0; // current state of the button
int lastButtonState3 = 0; // previous state of the button
int buttonPushCounter4 = 0; // counter for the number of button presses
int buttonState4 = 0; // current state of the button
int lastButtonState4 = 0; // previous state of the button
int buttonPushCounter5 = 0; // counter for the number of button presses
int buttonState5 = 0; // current state of the button
int lastButtonState5 = 0; // previous state of the button
void setup() {
Serial.begin(9600);
Serial.println("Robojax MAX6675");
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00 //Returns info with command 0x41 [0x01: info, 0x00: no info]
# define ACTIVATED LOW
pinMode(buttonPause, INPUT);
digitalWrite(buttonPause,HIGH);
// initialize the button pin as a input:
pinMode(buttonVolPlus, INPUT);
digitalWrite(buttonVolPlus,HIGH);
// initialize the button pin as a input:
pinMode(buttonVolMinus, INPUT);
digitalWrite(buttonVolMinus,HIGH);
// initialize the button pin as a input:
pinMode(buttonPin, INPUT);
// initialize the button pin as a input:
pinMode(buttonPin2, INPUT);
// initialize the button pin as a input:
pinMode(buttonPin3, INPUT);
// initialize the button pin as a input:
pinMode(buttonPin4, INPUT);
// initialize the button pin as a input:
pinMode(buttonPin5, INPUT);
// initialize the button pin as a input:
mySerial.begin (9600);
delay(1000);
execute_CMD(0x06, 0, 0x12); // Set the volume between 0-30 (0x00~0x30)//
execute_CMD(0x03, 0, 0x0002); //file to play at system start-up//
isPlaying = true;
}
void loop()
{
thermoSensorNewVal = thermoSensor.readCelsius();
if (thermoSensorNewVal != thermoSensorOldVal) {
Serial.print(" C = ");
Serial.print(thermoSensorNewVal);
thermoSensorOldVal = thermoSensorNewVal;
}
switch (curState) {
default: curState = IDLE; /* should never happen, but good practice to have a default */
case IDLE: if (thermoSensorNewVal >= INCR_MINOR) curState = WARN_MINOR; break;
case WARN_MINOR: if (thermoSensorNewVal <= DECR_IDLE) curState = IDLE;
if (thermoSensorNewVal >= INCR_GENERAL) curState = WARN_GENERAL; break;
case WARN_GENERAL: if (thermoSensorNewVal <= DECR_MINOR) curState = WARN_MINOR;
if (thermoSensorNewVal >= INCR_DIRE) curState = WARN_DIRE; break;
case WARN_DIRE: if (thermoSensorNewVal <= DECR_GENERAL) curState = WARN_GENERAL; break;
}
if (curState > oldState) {
// Increased temp warnings
switch (curState) {
case WARN_MINOR: playThermalExceed(); break;
case WARN_GENERAL: playHeatLevelCrit(); break;
case WARN_DIRE: playMeltdownImminent(); break;
default: break; /* should never happen, but good practice to have a default */
}
}
if (curState < oldState) {
// Decreased temp warnings
switch (curState) {
case IDLE: playHeatNominal();/* Could do an 'all clear' message here */ break;
case WARN_MINOR: break;
case WARN_GENERAL: playHeatModerate(); break;
default: break; /* should never happen, but good practice to have a default */
}
}
oldState = curState;
delay(500);
Serial.print(" C = ");
Serial.print(thermoSensorNewVal);
// read the pushbutton input pin:
buttonState = digitalRead(buttonPin);
// compare the buttonState to its previous state
if (buttonState != lastButtonState) {
// if the state has changed, increment the counter
if (buttonState == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
playEngineEnabled();
} else {
// if the current state is LOW then the button went from on to off:
playShuttingDown();
}
// Delay a little bit to avoid bouncing
delay(20);
}
// save the current state as the last state, for next time through the loop
lastButtonState = buttonState;
// read the pushbutton input pin:
buttonState2 = digitalRead(buttonPin2);
// compare the buttonState to its previous state
if (buttonState2 != lastButtonState2) {
// if the state has changed, increment the counter
if (buttonState2 == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter2++;
playLightAmpEngaged();
} else {
// if the current state is LOW then the button went from on to off:
playButtonOff();
}
// Delay a little bit to avoid bouncing
delay(20);
}
// save the current state as the last state, for next time through the loop
lastButtonState2 = buttonState2;
buttonState3 = digitalRead(buttonPin3);
// compare the buttonState to its previous state
if (buttonState3 != lastButtonState3) {
// if the state has changed, increment the counter
if (buttonState3 == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter++;
playLightAmp2Engaged();
} else {
// if the current state is LOW then the button went from on to off:
playButtonOff();
}
// Delay a little bit to avoid bouncing
delay(20);
}
// save the current state as the last state, for next time through the loop
lastButtonState3 = buttonState3;
// read the pushbutton input pin:
buttonState4 = digitalRead(buttonPin4);
// compare the buttonState to its previous state
if (buttonState4 != lastButtonState4) {
// if the state has changed, increment the counter
if (buttonState4 == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter4++;
playEXcamEngaged();
} else {
// if the current state is LOW then the button went from on to off:
playButtonOff();
}
// Delay a little bit to avoid bouncing
delay(20);
}
// save the current state as the last state, for next time through the loop
lastButtonState4 = buttonState4;
// read the pushbutton input pin:
buttonState5 = digitalRead(buttonPin5);
// compare the buttonState to its previous state
if (buttonState5 != lastButtonState5) {
// if the state has changed, increment the counter
if (buttonState5 == HIGH) {
// if the current state is HIGH then the button went from off to on:
buttonPushCounter5++;
playPhoneChargePort();
} else {
// if the current state is LOW then the button went from on to off:
playButtonOff();
}
// Delay a little bit to avoid bouncing
delay(20);
}
// save the current state as the last state, for next time through the loop
lastButtonState5 = buttonState5;
if (digitalRead(buttonPause) == ACTIVATED)
{
if(isPlaying)
{
pause();
isPlaying = false;
}else
{
isPlaying = true;
play();
}
}
if (digitalRead(buttonVolPlus) == ACTIVATED)
{
if(isPlaying)
{
setVolumeUp();
}
}
if (digitalRead(buttonVolMinus) == ACTIVATED)
{
if(isPlaying)
{
setVolumeDown();
}
}
} // end of loop?
void playThermalExceed()
{
Serial.println(" Thermal Exceeded Triggered Once ");
execute_CMD(0x03, 0, 0x000c); //file between 0-2999 in main folder. Doesn't love folders.//
delay(500);
}
void playHeatLevelCrit()
{
Serial.println(" Heat Critical Triggered Once ");
execute_CMD(0x03, 0, 0x000a); //file between 0-2999 in main folder. Doesn't love folders.//
delay(500);
}
void playMeltdownImminent()
{
Serial.println(" Meltdown Triggered Once ");
execute_CMD(0x03, 0, 0x000b); //file between 0-2999 in main folder. Doesn't love folders.//
delay(500);
}
void playHeatModerate()
{
Serial.println(" HeatModerate Once ");
execute_CMD(0x03, 0, 0x000d); //file between 0-2999 in main folder. Doesn't love folders.//
delay(500);
}
void playHeatNominal()
{
Serial.println(" HeatNominal Triggered Once ");
execute_CMD(0x03, 0, 0x000e); //file between 0-2999 in main folder. Doesn't love folders.//
delay(500);
}
void pause()
{
execute_CMD(0x0E,0,0);
delay(500);
}
void play()
{
execute_CMD(0x0D,0,1);
delay(500);
}
void playNext()
{
execute_CMD(0x01,0,1);
delay(50);
}
void playPrevious()
{
execute_CMD(0x02,0,1);
delay(50);
}
void setVolumeUp()
{
execute_CMD(0x04, 0, 1); // Set the volume (0x00~0x30)
delay(50);
}
void setVolumeDown()
{
execute_CMD(0x05, 0, 1); // Set the volume (0x00~0x30)
delay(50);
}
void setVolume(int volume) //Specify volume using code. Not applicable to the normal button interface.
{
execute_CMD(0x06, 0, volume); // Set the volume (0x00~0x30)
delay(2000);
}
void playEngineEnabled()
{
execute_CMD(0x03, 0, 0x0006); //file between 0-2999 in main folder. Doesn't love folders.//
delay(1500);
}
void playLightAmpEngaged()
{
execute_CMD(0x03, 0, 0x0004); //file between 0-2999 in main folder. Doesn't love folders.//
delay(2200);
}
void playLightAmp2Engaged()
{
execute_CMD(0x03, 0, 0x0005); //file between 0-2999 in main folder. Doesn't love folders.//
delay(2500);
}
void playEXcamEngaged()
{
execute_CMD(0x03, 0, 0x0007); //file between 0-2999 in main folder. Doesn't love folders.//
delay(2500);
}
void playShuttingDown()
{
execute_CMD(0x03, 0, 0x0003); //file between 0-2999 in main folder. Doesn't love folders.//
delay(600);
}
void playPhoneChargePort()
{
execute_CMD(0x03, 0, 0x0009); //file between 0-2999 in main folder. Doesn't love folders.//
delay(1500);
}
void playButtonOff()
{
execute_CMD(0x03, 0, 0x0008); //file between 0-2999 in main folder. Doesn't love folders.//
delay(400);
}
void execute_CMD(byte CMD, byte Par1, byte Par2)
// Excecute the command and parameters
{
// Calculate the checksum (2 bytes)
word checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);
// Build the command line
byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge,
Par1, Par2, highByte(checksum), lowByte(checksum), End_Byte
};
//Send the command line to the module
for (byte k = 0; k < 10; k++)
{
mySerial.write( Command_line[k]);
}
}
Have fun.
Edited by HimseIf, 27 June 2019 - 06:59 PM.