Peltier cells¶
Preparation of a cell¶
Peltier cells use the Peltier effect to pump heat from one plate to another of the device. The flux of heat is roughly proportional to the current passing through the peltier cell. The image below provides a schematic representation of a Peltier cell.
- One of the two plates of the Peltier cell is engineered to be hot. The other to be cold. Please attach the thermal adesive on both sides, then attach the heat sink to the cold side. To identify the hot side please refer to the
datasheet
. For the particular model provided, place the cell on the bench/desk with the black cable on the right/down and red cable on the left/down, then the top plate is the hot plate. - Connect the Peltier cell to the MAX14870 Driver. The red cable to the M1 pin and the black cable to the M2 pin (but first be sure that your duty cycle is at zero!)
- Place the Peltier cell on your desk/bench with the heat sink in contact with the bench surface and the hot side exposed to the air. Then place the temperature sensor on the hot side (fix it with standard tape).
Constant heat transfer and sensor readings¶
The following code drives the Peltier cell with a small voltage and monitors the temperature of the cold side of the Peltier cell by cyclically reading the temperature sensor. Temperature sensor reading is made available to the user through serial.
The code to drive the Peltier cell is similar to the one for LED and bulb. Setting and reading of the temperature sensor is realized through minor adaptations of the code you have developed in Activity 2. In fact, you will need to connect the temperature sensor to the pins D14 and D15 as in Activity 2.
The code uses the Ticker interface to set up recurring interrupts. Recurrent interrupts allow to read sensors and send information on the serial port at precise time intervals.
#include "mbed.h" #include "stdint.h" // *** PWM driver: pins and variables PwmOut peltierpwm(PA_7); DigitalOut DIR(D5); // *** Temperature sensor: pins and variables #define LM75_REG_TEMP (0x00) // Temperature Register #define LM75_REG_CONF (0x01) // Configuration Register #define LM75_ADDR (0x90) // LM75 address I2C i2c(I2C_SDA, I2C_SCL); //D14 and D15 Ticker dT_input; volatile int read_input = 0; // *** Serial communication: variables Serial pc(SERIAL_TX, SERIAL_RX); Ticker dT_serial; volatile int update_serial = 0; // *** Interrupt functions void sensing() { read_input = 1; } void serial_com() { update_serial = 1; } // *** General functions float read_temperature() { // Read temperature register char data_write[2]; char data_read[2]; data_write[0] = LM75_REG_TEMP; i2c.write(LM75_ADDR, data_write, 1, 1); // no stop i2c.read(LM75_ADDR, data_read, 2, 0); // Calculate temperature value in Celcius int16_t i16 = (data_read[0] << 8) | data_read[1]; // Read data as twos complement integer so sign is correct float temperature = i16 / 256.0; // Return temperature return temperature; } int main() { //*** temperature sensing configuration //Sensor configuration char data_write[2]; data_write[0] = LM75_REG_CONF; data_write[1] = 0x02; i2c.write(LM75_ADDR, data_write, 2, 0); //variables float temperature = 0; //*** PWM drive configuration DIR = 1; peltierpwm.period_us(1000); peltierpwm.write(0.1f); // NEVER GO ABOVE 0.5f! printf("pwm set to %.2f %%\n", peltierpwm.read()); //*** Interrupt configuration dT_input.attach(sensing, 0.01); dT_serial.attach(serial_com, 0.25); while(1) { if (read_input == 1) { read_input = 0; temperature = read_temperature(); } if (update_serial == 1) { update_serial = 0; pc.printf("Pwm set to %.2f, Temperature = %.3f\r\n ",peltierpwm.read() * 100, temperature); } } }
The code in detail¶
The initial part of the code is about setting pins and defining variables.
// *** PWM driver: pins and variables PwmOut peltierpwm(PA_7); DigitalOut DIR(D5);
This is about settings for the PWM driver. Please check that your MAX14870 Driver is connected to the right microcontroller pins.
// *** Temperature sensor: pins and variables #define LM75_REG_TEMP (0x00) // Temperature Register #define LM75_REG_CONF (0x01) // Configuration Register #define LM75_ADDR (0x90) // LM75 address I2C i2c(I2C_SDA, I2C_SCL); //D14 and D15 Ticker dT_input; volatile int read_input = 0;
This code is about settings for the temperature sensors (please refer to Activity 2). The ticker variable dT_input
is used to trigger an interrupt at constant intervals of time. You will see that, as a consequence of the interrupt, the variable read_input
will flip from 0 to 1 to inform the main routine that a sensor read must be performed. This variable is declared as volatile
to inform the compiler that this is a sensitive variable whose state may change at any moment (therefore the compiler will not apply any optimization that could cause a delay in detecting its status).
// *** Serial communication: variables Serial pc(SERIAL_TX, SERIAL_RX); Ticker dT_serial; volatile int update_serial = 0;
This code is about setting for the serial comunication. Please note that the ticker variable dT_serial
is used to trigger an interrupt at constant intervals of time, to request serial comunication. When the volatile variable update_serial
is set to 1, the main routine is informed that a serial comunication must be done.
void sensing() { read_input = 1; }
The function sensing()
is called when the ticker dT_input
triggers an interrupt.
The function flips the read_input
variable to 1, informing the main
code that a sensor reading must be done as soon as possible.
void serial_com() { update_serial = 1; }
The function serial_com()
is called when the ticker dT_serial
triggers an interrupt. The function flips the variable update_serial
to 1, informing the main
code that a serial comunicatoon must be done as soon as possible.
float read_temperature() { // Read temperature register char data_write[2]; char data_read[2]; data_write[0] = LM75_REG_TEMP; i2c.write(LM75_ADDR, data_write, 1, 1); // no stop i2c.read(LM75_ADDR, data_read, 2, 0); // Calculate temperature value in Celcius int16_t i16 = (data_read[0] << 8) | data_read[1]; // Read data as twos complement integer so sign is correct float temperature = i16 / 256.0; // Return temperature return temperature; }
The function read_temperature()
returns a temperature read from the sensor in Celcius. Please refer to Activity 2 for details.
We now go into the details of the main routine.
//*** temperature sensing configuration //Sensor configuration char data_write[2]; data_write[0] = LM75_REG_CONF; data_write[1] = 0x02; i2c.write(LM75_ADDR, data_write, 2, 0); //variables float temperature = 0;
This code initialize the temperature sensor and define the float variable
temperature
which will contain the sensor last read.
//*** PWM drive configuration DIR = 1; peltierpwm.period_us(1000); peltierpwm.write(0.1f); // NEVER GO ABOVE 0.5f! printf("pwm set to %.2f %%\n", peltierpwm.read());
This code set the Peltier PWM duty cycle at 10%. You are encouraged to try different duty cycles but please never go above 50% to avoid termal issues with the cell (the cell may break).
//*** Interrupt configuration dT_input.attach(sensing, 0.01); dT_serial.attach(serial_com, 0.25);
This code set the interval of the recurring interrupts. The first line sets a recurring interrupt every 0.01 seconds, which calls repeadetly the function sensing()
to request a sensor reading. The second line sets a recurring interrupt every 0.25 seconds, which calls the function serial_com()
to request serial comunication.
You will notice that serial comunication happens at much slower rate than sensor reading. The reason for these differences will be clear later, when we will design a more complex actuation mechanism. The idea is that sensing and comunication with the user can occur at different rates. Typically, sensing and actuation need a very fast rate to avoid issues but comunication with the user (serial) can be done at a slower rate to save computational resources.
Finally, the while loop constantly monitors the two variables
read_input
and update_serial
. A sensor read is performed when read_input
is detected equal to 1. Consequently, read_input
is set to $0$, in preparation for the next interrupt. Temperature and PWM status are comunicated to the user when update_serial
is detected equal to 1. After that, update_serial
is set to 0, in preparation for the next interrupt.
while(1) {x if (read_input == 1) { read_input = 0; temperature = read_temperature(); } if (update_serial == 1) { update_serial = 0; pc.printf("Pwm set to %.2f, Temperature = %.3f\r\n ",peltierpwm.read() * 100, temperature); } }
Tasks¶
- Why does the cold side become colder as the duty cycle increase?
- Can you set the temperature of the cold side to a desired value by a suitable selection of the duty cycle?