So... At present I have a PID code for my arduino project that is working excellent. Check it out at the bottom of the page.
I'll explain the basics of it.....
It is an arduino programmed as a PID temperature controller that has a 2 line LCD readout. One line for the setpoint and the second line for the current temperature.
I have 2 pushbuttons to adjust the setpoint up or down and one button to trigger the PID controller to run.
The arduino microcontroller takes its analog temperature reading from a AD595 IC that can use a variety of analog sensors and feeds it into the PID algorithm to calculate the apropriate output.
Everything is working fine and now I am just changing sensor types. I am going from analog to digital.
I have a MLX90614 IR temperature sensor that requires a clock signal in and has one serial data line out. It provides
two readings:
A)the body temperature of the sensor
B)the second is the IR temperature.
I have 2 different complete codes that can communicate excellent with the digital IR sensor.
1)The first is written up in ASSEMBLY that works great with the sensor and a 2 LINE LCD.
It prompts the sensor for the two readings and feeds them to the LCD. The first line readout
is the sensor body temperature and the second line readout is the IR temperature.
So this first code is a great example of how this sensor works and has actually been put to use
as a basic IR thermometer.
Please check it out in action here:
http://www.dehnes.com/4/2010/02/03/building-your-own-ir-thermometer-part1/
- The second sample code is written in the C++ that the arduino's use and is fairly simple. What this
second code does is similar to the first but instead of reading out to an LCD, the code is designed to send the digital temperature data through USB to be read through a computer.
http://bildr.org/2011/02/mlx90614-arduino/
What I need is to take these two examples of WORKING digital sensor code, get a good idea of how it works. Then, all I need done is to:
-take my old code that works fine with my old setup
-add some of that code from the digital sensor examples so that my microcontroller reads from the digital sensor
and uses that digital temperature data for the PID control instead of the analog it was using before. Thats it.
I really like the way the ASM code in the first example works ... Especially this part:
"In order to convert the temperature values received from the sensor to degrees celcius, the raw value has to be multiplied by 0.02 according to the documentation. The result is the temperature in degrees Kelvin with two decimal precision. Substract 273.15 from that and you have the temperature in degrees celcius. To do this calculation on the microcontroller, I first subtract 27315 (273.15 x 100) from the raw value and then divided the result by 100. This way, I don’t have to worry about the comma until the very last step. The code for this conversion can be found in main.asm. "
but I am pretty sure that can't be compiled with the arduino program. Is there any way to convert that excellent assembly math to a string in C++ that would work in the arduino compiler?
Or....How can I take some pieces from the second example that provides the serial readout to the computer and just change a few things to have that send the serial data to my PID code?
Here it is :
#include <EEPROM.h>
#include <LiquidCrystal.h>
#include <PID_v1.h>
double Setpoint, Input, Output;
double aggKp=1, aggKi=1, aggKd=1 , LoLIM=0, HiLIM=255;
double consKp=0, consKi=0, consKd=0;
double SampleTime=1000;
LiquidCrystal lcd(12, 11, 8, 4, 3, 2);
const int onPin = 5; //pin to trigger heater
const int upPin = 6; // pin to increase temp
const int downPin = 7; //pin to decrease temp
int buttonState = 0; // variable for reading the pin status
int DownPushed = 0;
int UpPushed = 0;
int OnPushed = 0;
int PID_ON = 0;
int UpdScr = 0;
int inpt;
int gap;
int S_gap;
int count;
int EEPROM_ADDR;
void UpdateEEPROM() {
int val, wr;
val = (int) Setpoint;
wr = val>>8;
EEPROM.write(EEPROM_ADDR, wr);
wr = val & 0XFF;
EEPROM.write(EEPROM_ADDR+1, wr);
};
void LoadEEPROM() {
int val;
val = EEPROM.read(EEPROM_ADDR);
val = val <<8;
val +=EEPROM.read(EEPROM_ADDR+1);
Setpoint = val;
};
unsigned long lastTime, lShowTime;
//Specify the links and initial tuning parameters
PID myPID(&Input, &Output, &Setpoint, aggKp, aggKi, aggKd, DIRECT);
void setup()
{
Serial.begin( 19200 );
//initialize the variables we're linked to
Input = analogRead(0);
LoadEEPROM();
if( (Setpoint +1.) < 0.001)
Setpoint = 570; // Setpoint = xxx;
// Declare inputs
pinMode(onPin, INPUT); // declare pushbutton as input
pinMode(upPin, INPUT); // declare pushbutton as input
pinMode(downPin, INPUT); // declare pushbutton as input
//turn the PID on STANDBY
myPID.SetOutputLimits(LoLIM, HiLIM);
myPID.SetMode(AUTOMATIC);
myPID.SetSampleTime(SampleTime);
myPID.SetTunings(aggKp, aggKi, aggKd);
lShowTime = lastTime = millis();
// set up the LCD's number of columns and rows:
lcd.begin(16,2);
count = 0;
EEPROM_ADDR = 30;
delay(2000);
lcd.clear();
lcd.print(aggKp);
lcd.print("-");
lcd.print((int)(aggKi) );
lcd.print("-");
lcd.print(aggKd);
delay(1000);
lcd.clear();
lcd.print("SR = ");
lcd.print((int)(SampleTime));
lcd.print(" ");
delay(1000);
lcd.clear();
lcd.print("Limits ");
lcd.print((int)(LoLIM));
lcd.print(",");
lcd.print((int)(HiLIM));
delay(1000);
lcd.clear();
}
void loop()
{
Input = analogRead(0);
buttonState = digitalRead(onPin);
if (buttonState == HIGH) {
// turn on
myPID.SetMode(AUTOMATIC);
PID_ON =1;
}
else {
myPID.SetMode(MANUAL);
Output = 0;
PID_ON =0;
}
myPID.Compute();
analogWrite(10,Output);
// I would not change these lines, because you are expecting 250 ms for a "push"
// that is if you hold button for more then 1/4 second,
if(digitalRead(upPin)==HIGH) {
if (millis()-lastTime >= 250) {
Setpoint+=10;
UpdateEEPROM();
lastTime=millis();
UpdScr = 1;
}
}
if(digitalRead(downPin)==HIGH) {
if (millis()-lastTime >= 250) {
Setpoint-=10;
UpdateEEPROM();
lastTime=millis();
UpdScr = 1;
}
}
//and output to LCD
if( (millis() - lShowTime > 100 ) || UpdScr ) {
UpdScr = 0;
lcd.setCursor(0,0);
//if heater is on - show *
//if not - empty
if( PID_ON ==1 ) {
lcd.print("*");
}
else {
lcd.print(" ");
}
lcd.print("SET.TEMP-> ");
lcd.print((int)(Setpoint) );
lcd.setCursor( 0,1);
lcd.print(" ReaLTEMP-> ");
inpt = (inpt *5 + Input)/6;
count = (count +1)%6;
if(count == 0) {
if( inpt < 100) lcd.print( " ");
lcd.print( inpt );
}
lShowTime = millis();
}
}