I have made a Peltier based Temperature controller. I have used L298 to control the current.
PWM signal from arduino is fed to the enable pin of the L298. I have written the following code to control the temperature of a box which is connected to the petlier. There is a LM35 temperature sensor inside the box.
When I test this code on my hardware without the load (peltier), everything seems to work as it is expected to, but when I connect the peltier to the L298, the arduino seems to freeze or reset after 10 seconds. I can't seem to figure out what could be wrong.
/*
Thermo Electric Cooler (TEC)
````````````````````````````````
Circuit Description:
Serial Communication - Pin 0,1
Input Buttons - Pins 2,3,4
TEC Module (H Bridge) - Pins 5,6,7
LCD - Pins 8,9,10,11,12,13
LED - Pin A0
Current Sensor - Pin A1
LM35 - Pin A3
H Bridge Description (L298)
Enable Pin - Controls the votlage (indirectly current) applied across load.
Digital Inputs:
For positive voltage (cooling)
Pin 6 - HIGH
Pin 7 - LOW
For negative voltage (heating)
Pin 6 - LOW
Pin 7 - HIGH
_____________________________________________________________*/
#include <math.h>
#include <Button.h>
Button start_stop_button = Button(4,PULLUP);
Button dec_button = Button(3,PULLUP);
Button inc_button = Button(2,PULLUP);
#include <LiquidCrystal.h>
LiquidCrystal lcd(13,12,11,10,9,8);
char blank[] = " "; // to earase 4 characters
double Tref = 20, Tmeas = 30;
int button_time = 0;
unsigned long lcd_time = 0, I_tym = 0;
float Imeas = 0;
//----------------------------Variables-----------------
float step_size = 1; // Inc/Dec Button step size
float I_calib = 1; // Current sensor calibration
float T_delta = 2; // +- 3 degree Celsius
int Imax_dutyCycle = 120; // 100 -> ~1.8 Amps of current
//------------------------------------------------------
void setup()
{
Serial.begin(9600);
pinMode(5,OUTPUT); digitalWrite(5,LOW);
pinMode(6,OUTPUT); digitalWrite(6,LOW);
pinMode(7,OUTPUT); digitalWrite(7,LOW);
lcd.begin(16, 2);
lcd.print("Enter Tref: 20");
a:
if(millis() - lcd_time > 2000) //update lcd every 2 sec
{
float Tmeas = analogRead(3);
for(int i=1;i<10;i++)
Tmeas = (Tmeas + analogRead(3) ) / 2; // take 10 samples avg value
Tmeas = Tmeas * 500 / 1024;
lcd.setCursor(0,1);
lcd.print("Tmeas : ");
lcd.print(Tmeas);
lcd_time = millis();
}
if(inc_button.isPressed())
{
Tref += step_size;
lcd.setCursor(12,0);
lcd.print(Tref);
delay(200);
}
if(dec_button.isPressed())
{
Tref -= step_size;
lcd.setCursor(12,0);
lcd.print(Tref);
delay(200);
}
if(start_stop_button.isPressed())
{
lcd.clear();
lcd.print("Starting...");
goto b;
delay(100);
}
goto a;
b:
delay(1000);
}
void loop()
{
//_____________________Temp_______________________
float Tmeas = analogRead(3);
for(int i=1;i<10;i++)
Tmeas = (Tmeas + analogRead(3) ) / 2; // take 10 samples avg value
Tmeas = Tmeas * 500 / 1024; // convert to temp
//_______________________Current____________________
/*
if(millis() - I_tym > 100) // every 100 ms
{
calc_current();
I_tym = millis();
}
*/
//______________________LCD______________________
if(millis() - lcd_time > 1000) //update lcd every 1 sec
{
lcd.clear();
lcd.print("Tr:");
lcd.print(Tref);
// lcd.setCursor(9,0);
// lcd.print("I:");
// lcd.print(Imeas);
lcd.setCursor(0,1);
lcd.print("Tm:");
lcd.print(Tmeas);
lcd_time = millis();
}
// ________________________Buttons________________________
if(inc_button.isPressed())
{
Tref += step_size;
lcd.setCursor(3,0);
lcd.print(Tref);
lcd.print(blank);
delay(200);
}
if(dec_button.isPressed())
{
Tref -= step_size;
lcd.setCursor(3,0);
lcd.print(Tref);
lcd.print(blank);
delay(200);
}
if(start_stop_button.isPressed()) // Used only to stop the controller
{
digitalWrite(5,LOW);
digitalWrite(6,LOW);
digitalWrite(7,LOW);
lcd.clear();
delay(1000);
setup(); // start all over again
}
// ________________________Controller________________________
float E = Tmeas - float(Tref);
if( E > T_delta) // cooling at max - positive voltage
{
//positive voltage
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
analogWrite(5,Imax_dutyCycle);
lcd.setCursor(9,1);
lcd.print("Max-C");
lcd.setCursor(9,0);
lcd.print("D:");
lcd.print(Imax_dutyCycle *100/255);
lcd.print("% ");
}
if( E < -T_delta)
{
//negative voltage
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
analogWrite(5,Imax_dutyCycle);
lcd.setCursor(9,1);
lcd.print("Max-H");
lcd.setCursor(9,0);
lcd.print("D:");
lcd.print(Imax_dutyCycle *100/255);
lcd.print("% ");
}
if( (E > - T_delta) && (E < T_delta))
{
// PID or other control
if( E >= 0 ) // cooling
{
digitalWrite(6,HIGH);
digitalWrite(7,LOW);
int d = fscale( 0, T_delta, 0, Imax_dutyCycle, E, 0);
constrain(d,0,Imax_dutyCycle);
analogWrite(5,d);
lcd.setCursor(9,1);
lcd.print("PID-C");
lcd.setCursor(0,1);
lcd.print("Tm:");
lcd.print(Tmeas);
lcd.setCursor(9,0);
lcd.print("D:");
lcd.print(d*100/255);
lcd.print("% ");
}
else if(E < 0)
{ // heating
digitalWrite(6,LOW);
digitalWrite(7,HIGH);
int d = fscale( (-1* T_delta), 0, Imax_dutyCycle, 0, E, 0);
constrain(d,0,Imax_dutyCycle);
analogWrite(5,d);
lcd.setCursor(9,1);
lcd.print("PID-H");
lcd.setCursor(0,1);
lcd.print("Tm:");
lcd.print(Tmeas);
lcd.setCursor(9,0);
lcd.print("D:");
lcd.print(d*100/255);
lcd.print("% ");
}
}
delay(50);
Serial.print("Error ");
Serial.print(E);
Serial.print(" T : ");
Serial.println(Tmeas);
delay(500);
}
float fscale( float originalMin, float originalMax, float newBegin, float
newEnd, float inputValue, float curve){
float OriginalRange = 0;
float NewRange = 0;
float zeroRefCurVal = 0;
float normalizedCurVal = 0;
float rangedValue = 0;
boolean invFlag = 0;
// condition curve parameter
// limit range
if (curve > 10) curve = 10;
if (curve < -10) curve = -10;
curve = (curve * -.1) ; // - invert and scale - this seems more intuitive - postive numbers give more weight to high end on output
curve = pow(10, curve); // convert linear scale into lograthimic exponent for other pow function
/*
Serial.println(curve * 100, DEC); // multply by 100 to preserve resolution
Serial.println();
*/
// Check for out of range inputValues
if (inputValue < originalMin) {
inputValue = originalMin;
}
if (inputValue > originalMax) {
inputValue = originalMax;
}
// Zero Refference the values
OriginalRange = originalMax - originalMin;
if (newEnd > newBegin){
NewRange = newEnd - newBegin;
}
else
{
NewRange = newBegin - newEnd;
invFlag = 1;
}
zeroRefCurVal = inputValue - originalMin;
normalizedCurVal = zeroRefCurVal / OriginalRange; // normalize to 0 - 1 float
/*
Serial.print(OriginalRange, DEC);
Serial.print(" ");
Serial.print(NewRange, DEC);
Serial.print(" ");
Serial.println(zeroRefCurVal, DEC);
Serial.println();
*/
// Check for originalMin > originalMax - the math for all other cases i.e. negative numbers seems to work out fine
if (originalMin > originalMax ) {
return 0;
}
if (invFlag == 0){
rangedValue = (pow(normalizedCurVal, curve) * NewRange) + newBegin;
}
else // invert the ranges
{
rangedValue = newBegin - (pow(normalizedCurVal, curve) * NewRange);
}
return rangedValue;
}