---
title: "Modified Car Fridge “Pro” with a PCBWay 2-Layer HASL PCB"
url: "https://maker.wiznet.io/teju/projects/Modified-Car-Fridge-Pro-with-a-PCBWay-2Layer-HASL-PCB/"
markdown_url: "https://maker.wiznet.io/teju/projects/Modified-Car-Fridge-Pro-with-a-PCBWay-2Layer-HASL-PCB/md"
type: "UCC: User Created Content"
author: "teju"
author_url: "https://maker.wiznet.io/teju/"
original_author: "teju"
original_url: "https://goughlui.com/2021/02/06/project-modified-car-fridge-pro-with-a-pcbway-2-layer-hasl-pcb/"
published: "2021-06-24"
language: "en"
hardware: ["Freetronics Etherten"]
likes: 0
views: 296
comments: 0
source: "WIZnet Makers (https://maker.wiznet.io/)"
---

# Modified Car Fridge “Pro” with a PCBWay 2-Layer HASL PCB

> Modified Car Fridge “Pro” with a PCBWay 2-Layer HASL PCB

Original author: teju (source: https://goughlui.com/2021/02/06/project-modified-car-fridge-pro-with-a-pcbway-2-layer-hasl-pcb/)

## Components

- **Freetronics Etherten** x 1

## Documents and links

- [CODE](https://goughlui.com/wp-content/uploads/2021/02/FridgeControlv041goughlui.com_.zip) (code)

## Article

when I presented this rather unwieldy monstrosity of a modification to a Peltier car fridge to turn it into an environmental chamber … [![](https://goughlui.com/wp-content/uploads/2021/01/2021011012518307-1024x688.jpg)](https://goughlui.com/wp-content/uploads/2021/01/2021011012518307.jpg) … even though it was an ugly mess of wires and veroboard, it actually worked quite well and made all the difference in getting just that little bit more stability out of measuring the absolute capacity of a?[Li-ion cell over multiple cycles](https://goughlui.com/2021/01/24/project-temperature-controlled-li-ion-cycling-feat-rs-ngm202-a-car-fridge/). That project was by no means complete. Now that I’ve realised its worth, it’s time to turn it into something more permanent.

## **Designing a PCB**

The whole control system is based around a?[Freetronics EtherTen](https://www.freetronics.com.au/products/etherten), which is basically the “marriage” of an Arduino Uno and an Arduino Ethernet Shield plus some minor tweaks and an I2C-connected EEPROM. This particular one was given to me by a colleague who had left the country to pursue opportunities elsewhere. Common to all such designs is the Arduino shield form factor which allows for additional capabilities through “stacking” boards on the female headers. This is a great concept, but one of the painful legacies of the shield form factor is the non-standard spacing (i.e. not 100-mil) on the digital pins. This makes using veroboard very difficult, while buying protoboard for something like this can be an expense that isn’t justified especially because you’re still limited in density and capabilities compared to spinning your own PCB. Having only recently embarked on designing PCBs of my own using?[KiCad](https://kicad.org/), I decided to see if I could turn this ugly mess into something more professional. I got straight to drawing the schematic, laying out the board, routing the traces and looking at the 3D View, taking a few hours in the process. [![](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb1-top-300x213.png)](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb1-top.png)?[![](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb1-bot-300x215.png)](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb1-bot.png) My first attempt simply replicated the capabilities of the existing veroboard solution, adding an additional diode to prevent the EtherTen from reverse-powering the rest of the peripherals and two LEDs to indicate the status of the heating and cooling outputs. Instead of using a “full” shield size board, I decided to make it a short-board so as to ensure it would clear the tall Ethernet connector without needing taller headers. As with all things, it’s best to?**sleep**?on it, so I didn’t think of getting this made right away. Instead, I ended up deciding that all that unused space on the board could come in very useful to add another two MOSFETs and connections for the inside and outside fans, allowing for fan speed control and for the controller to “shut down” the fans when the unit is not cooling. Additional I2C connections for an LCD would be nice as well. Finally, breaking out some of the unused pins and power connections would be useful in case the board needs to be “patched” to add more capability in the future. [![](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb2-top-300x220.png)](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb2-top.png)?[![](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb2-bot-300x220.png)](https://goughlui.com/wp-content/uploads/2021/02/cf-pcb2-bot.png) This second version necessitated juggling the components around somewhat as the room was beginning to run out. I wasn’t going to go more complex than two-layers (as I wanted the board to be reasonably priced) and the need to ensure the board could handle the current of the loads (~5A) meant that wider copper traces and pours needed to be maintained to ensure a low resistance. As a result, this is a very “traditional” through-hole type design. By now, there really wasn’t much more I could get out of the board, so I settled on this design as the one to be manufactured. Looking back at it, I might have laid off on the thermal reliefs on the pads to reduce resistance even further and moved some of the silkscreen text for the terminal blocks to the underside so they wouldn’t be covered, but other than that, I’m quite happy. [![](https://goughlui.com/wp-content/uploads/2021/02/cf21-schematic-1024x585.png)](https://goughlui.com/wp-content/uploads/2021/02/cf21-schematic.png) The schematic, after being redrawn to make it more neat, is as above. Nothing too complicated, but it definitely does more than my scrap of veroboard and looks like it’s going to fit into the shortened shield form factor in a very neat way. Now it’s time to take this design and make it?**reality**.

## **Putting it All Together & Improving the Code **

I was eager to put everything together right away. While PCBWay was so kind to upgrade me to DHL,?**because of shipping delays with the terminal blocks I ordered**, this post still ended up being delayed. [![](https://goughlui.com/wp-content/uploads/2021/02/2021011818588373-245x300.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021011818588373.jpg)?[![](https://goughlui.com/wp-content/uploads/2021/02/2021011712088370-249x300.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021011712088370.jpg) Assembly of the board was as easy as I had imagined. I decided to use whatever components I had on hand, so there were a few value substitutions that were relatively inconsequential. Everything went into place and it was a dream to solder together ? it even looks almost exactly like the 3D view. [![](https://goughlui.com/wp-content/uploads/2021/02/2021011712078369-1024x476.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021011712078369.jpg) The assembled “shield” is actually quite tall with the TO-220 packages and capacitors standing proud. It is actually quite weighty as well, but nothing that the rows of pins could not handle. After another two to three weeks, my terminal blocks arrived and I could continue my quest to upgrade my modified car fridge. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020612068397-300x186.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020612068397.jpg)?[![](https://goughlui.com/wp-content/uploads/2021/02/2021020612068398-300x175.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020612068398.jpg) For power, I decided to drill into the side of the front fascia of the fridge to install two shrouded banana sockets. This would use regular banana-to-banana test leads to supply power to the fridge. The rear connections are spades, so I would use crimp connectors to make the connections at the final stage. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020612298399-1024x683.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020612298399.jpg) The next step involved finding a home for the board and shield ? I decided the left side of the top unused section of the fridge would be best, wedged between a tab and a standoff. I used my side-cutters to remove all unnecessary plastic and copious amounts of hot glue to cement it into place. It’s not the most professional way to mount something, but it is convenient and does the job. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020612298400-1024x505.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020612298400.jpg) A bit more work with the side-cutters and I managed to create an opening to allow for the microUSB-B connection (for USB-Serial and reprogramming) and Ethernet. The barrel jack connection is left off deliberately as this is not a valid way to power this contraption. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020613248401-1024x486.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020613248401.jpg) The LCD would fit with copious amounts of hot glue in the area formerly occupied by the power jacks. This is not ideal for air-flow, but it is about the right size and involves little work if I just glue it on the outside, which I did. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020613248402-1024x577.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020613248402.jpg) To make the connection to the board, I snipped off the Grove header at the other end and joined it to some jumper cables, insulated with heatshrink and held in place by a cable tie. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020613318404-1024x683.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020613318404.jpg) The wiring for all the inputs and outputs are completed ? the terminal blocks hold well and the input power spade crimp sockets have been fitted. I doubled up the input wire to reduce resistance ? the wires may look like hook-up wire but it’s actually quite stiff 0.5mm^2 wire, so the pair of wires should be even better than your average mains extension lead. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020613408408-1024x513.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020613408408.jpg) I did replace the header pin shrouds from single-pin jumper wires to four/five way blocks to reduce the chance for wire transposition. I also got rid of the halogen light globe heat source, instead opting for a cheap Chinese wire-wound resistor which is a little smaller and neater, recovering some of the limited space inside the box for the device under test. I did cut a little out of the sealing “rim” of plastic to allow the cables a slightly easier path through. The lid still magnetically latches closed, which is great. The updated software is the next part of finishing off the project. The full program is listed in the appendix, but it resolves a few bugs that exist with the previous version (type mismatches, buffer overflows) and introduces new features such as DHCP, EEPROM network configuration memory, SeeedStudio LCD display support, additional commands, faster BME680 handling, elimination of floating point math and sensor error shutdown of the fridge. It can only be commanded by one client at any time, but USB-Serial and Ethernet both can be used. This was made possible by being very careful with memory, throwing out some unneeded help text and simplifying code where possible with reusable functions. The result is 98% flash (31664 bytes) and 76% RAM (1564 bytes) usage on the ATMega328 ? it’s amazing that an 8-bit microcontroller can be coaxed to do this much even with the assistance of intelligent peripherals. [![](https://goughlui.com/wp-content/uploads/2021/02/2021020613458412-836x1024.jpg)](https://goughlui.com/wp-content/uploads/2021/02/2021020613458412.jpg) With everything reassembled and hooked up, I can report the unit works just as well as it did before, but is now so much neater and more convenient to use.

## **Conclusion**

The difference between my first ugly, but functional, hack full of wire spaghetti and this neat, almost-professional-looking result with even more functionality was really down to designing myself a PCB and getting it manufactured. With open-source software such as KiCad, the barrier to PCB design has been very much reduced and it only took me a few hours to become proficient enough to create an Arduino shield design and prepare the manufacturing files correctly. Thanks to?[PCBWay](https://www.pcbway.com/)‘s sponsorship of the PCBs, I had a chance to evaluate their service and realise my design in a physical form. On the whole, I found that PCBWay offers a wide range of manufacturing services that cater for even complex PCB requirements. Uploading your own design files allows you to rapidly preview and select the appropriate manufacturing options. Once submitted, your job is allocated a representative who will handle all queries. Pricing is relatively competitive even at the prototype 5-board level, so much so that shipping is often the bigger cost for small projects. Most impressively, turnaround times (with DHL postage) was only six days total in my case. The delivered boards were manufactured to a very satisfactory standard. A slight unevenness in silkscreen text printing density and jagged lines was noted. There were also other miniscule misalignments (all within specifications) of the solder mask layer and board edge cuts. The identification text label was small and unobtrusive. Based on this experience, I would definitely recommend PCBWay ? they may not be the cheapest on the market, but they are pretty close and in return, it seems you get more manufacturing choices and better support. Perhaps next time you’re looking to upgrade that prototype, it might well be worth spinning a PCB for it ? it might well be cheaper and quicker than you expected.

```
// Gough's Arduino Thermoelectric Cooler Controller V4.1 - goughlui.com
// January 2021 - Intended for use with Freetronics EtherTen for Ethernet & USB/Serial Control
// No warranties expressed or implied. Free to use and modify with credit.

// Depends on Zanshin BME680 library, SeeedStudio Grove RGB I2C LCD library

// New: Integer Math Only, DHCP supported, EEPROM for MAC, IP settings, SeeedStudio Grove I2C LCD
// standalone display, async BME680 ops for speed, shutdown on 20 consecutive sensor errors,
// automatic sensor recovery attempts, new commands & many subtle bugfixes (data types, order of ops).
// Still no PID control, lots of globals, poor function/variable naming, no input validation.

// 31664 bytes (98%) Flash and 1564 bytes (76%) RAM Used - Not Much Space Left (592b Flash, 484b RAM)

#include <avr/pgmspace.h>
#include <EEPROM.h>
#include <Wire.h>
#include <SPI.h>
#include <Ethernet.h>
#include "Zanshin_BME680.h"
#include "rgb_lcd.h"

#define MAX_CMD_LEN 120 // Must be <=255 due byte type counter and RAM limits
#define FRIDGE_PIN 5 // Note 5, 6 (980Hz) PWM Capability.
#define HEAT_PIN 6
#define COOLERFAN_PIN 3 // Note 3, 9 (490Hz) PWM capability.
#define INSIDEFAN_PIN 9

// Ethernet Server Variables
byte mac[6] = {0x12, 0x22, 0x11, 0x21, 0x32, 0x11};
byte ipaddr[4]= {192, 168, 80, 60};
IPAddress ip();
EthernetServer server(5025);
bool dhcpflag = 0;
char ibuf[MAX_CMD_LEN] = {''};
byte iptr=0;
char respbuf[MAX_CMD_LEN] = {''};
bool serbyte=0;
bool newbyte=0;

// Temperature/Humidity Sensor Variables
BME680_Class bme;
long int senstemp; // Val is 100x degC
long int senshum; ?// Val is 1000x hPa
byte sfault=1;

// Fridge Control Variables - Note int instead of byte due to scanf(!)
int target;
int hdeadband;
int hfullpwr;
int cdeadband;
int cfullpwr;
int cpwm;
int cpwmmin;
int cpwmmax;
int hpwm;
int hpwmmin;
int hpwmmax;
int coolerfan;
int internalfan;
bool opmode;
unsigned long ltime;
unsigned long lcdtime;

// Progmem Data
const char helpdata[] PROGMEM = {"*IDN? *RST? READ? SET? HELP? SETHELP? IP? MAC? MEAS:TEMP?nSET START STOP IP MAC DHCP NVERASE LCD TARGET IFAN OFAN"};
const char setdata[] PROGMEM = {"SET Params: Target H-DB, H-FP C-DB C-FP HPWM-Min HPWM-Max CPWM-Min CPWM-Max CFPWM IFPWM"};
const char deviceID[] PROGMEM = {"goughlui.com TEC Control,V4.1,0001"};

// LCD Display
rgb_lcd lcd;
bool lcddispon = 1;

// Software reset function
void(* resetBoard) (void) = 0; // Reboot

void setup() {
 ?int magic;
 ?lcd.begin(16,2);
 ?lcd.print(F("Gough TEC v4.1"));
 ?lcd.setCursor(0,1);
 ?lcd.print(F("Starting ..."));
 ?sinit();
 ?sread();
 ?pinMode(FRIDGE_PIN, OUTPUT);
 ?pinMode(HEAT_PIN, OUTPUT);
 ?varreset();
 ?delay(250); // time for EtherTen Wiznet IC to reset
 ?Serial.begin(115200);
 ?EEPROM.get(500,magic);
 ?if (magic == 1234) { // Magic value passes, EEPROM contents valid
 ???EEPROM.get(0,mac);
 ???EEPROM.get(10,ipaddr);
 ???EEPROM.get(20,dhcpflag);
 ?} else { // Magic value fails, thus restore defaults
 ???EEPROM.put(0,mac);
 ???EEPROM.put(10,ipaddr);
 ???EEPROM.put(20,dhcpflag);
 ???magic = 1234;
 ???EEPROM.put(500,magic); // Write Magic value
 ???resetBoard(); // Reset board to apply values
 ?}
 ?if(dhcpflag) {
 ???lcd.clear();
 ???lcd.print(F("DHCP Request"));
 ???ltime=millis();
 ???while (!Ethernet.begin(mac) && (ltime + 60 < millis())) {
 ?????// Couldn't get an address, let's wait up to 60s for an address.
 ???}
 ?} else {
 ???IPAddress ip(ipaddr[0],ipaddr[1],ipaddr[2],ipaddr[3]);
 ???Ethernet.begin(mac, ip);
 ?} ?
 ?server.begin();
 ?lcd.clear();
 ?sprintf(respbuf,"%02X%02X%02X%02X%02X%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
 ?lcd.print(respbuf);
 ?lcd.setCursor(0,1);
 ?lcd.print(Ethernet.localIP()[0]);
 ?lcd.print('.');
 ?lcd.print(Ethernet.localIP()[1]);
 ?lcd.print('.');
 ?lcd.print(Ethernet.localIP()[2]);
 ?lcd.print('.');
 ?lcd.print(Ethernet.localIP()[3]);
 ?delay(3000);
}

void loop() {
 ?EthernetClient client = server.available();
 ?char c;
 ?if (client) {
 ???if (client.connected() && client.available()) {
 ?????c = toupper(client.read());
 ?????serbyte = 0;
 ?????newbyte = 1;
 ???}
 ?}
 ?if (Serial.available()) {
 ???c = toupper(Serial.read());
 ???serbyte = 1;
 ???newbyte = 1;
 ?}
 ?if(newbyte) {
 ???newbyte = 0;
 ???if (c != 'r') { // eat any carriage returns for compat with rn
 ?????if (c == 'n') {
 ???????ibuf[iptr]='';
 ???????proccmd();
 ???????if(serbyte) {
 ?????????if(strlen(respbuf)) {
 ???????????Serial.print(respbuf);
 ?????????}
 ?????????Serial.write("n");
 ???????} else {
 ?????????if(strlen(respbuf)) {
 ???????????client.print(respbuf);
 ?????????}
 ?????????client.write("n");
 ???????}
 ???????iptr=0;
 ?????} else {
 ???????if (iptr<MAX_CMD_LEN) {
 ?????????ibuf[iptr]=c;
 ?????????iptr++;
 ???????}
 ?????}
 ???}
 ?}
 ?
 ?// Read Sensor at Every Chance to allow best IIR
 ?sread();
 ?
 ?// Temperature Loop Runs Every Two Seconds!
 ?if ((ltime + 2000 < millis()) && opmode) {
 ???ltime = millis();
 ???// Evaluate Temperature Situation
 ???if(senstemp<target) {
 ?????cpwm=0;
 ?????// Compute hpwm value
 ?????if((target-senstemp)<hfullpwr) {
 ???????hpwm=map(target-senstemp,0,hfullpwr,hpwmmin,hpwmmax);
 ???????if((target-senstemp)<hdeadband) {
 ?????????hpwm=0;
 ???????}
 ?????} else {
 ???????hpwm=255;
 ?????}
 ???} else {
 ?????hpwm=0;
 ?????// Compute cpwm value
 ?????if((senstemp-target)<cfullpwr) {
 ???????cpwm=map(senstemp-target,0,cfullpwr,cpwmmin,cpwmmax);
 ???????if((senstemp-target)<cdeadband) {
 ?????????cpwm=0;
 ???????}
 ?????} else {
 ???????cpwm=255;
 ?????}
 ???}
 ???// Update Outputs
 ???analogWrite(FRIDGE_PIN,cpwm);
 ???analogWrite(HEAT_PIN,hpwm);
 ?}
 ?// DHCP Maintain
 ?if (dhcpflag) {
 ???Ethernet.maintain();
 ?}
 ?// LCD Update Only If Enabled!
 ?if (lcdtime+1000 < millis()&&lcddispon) {
 ???lcdtime=millis();
 ???lcdstatus();
 ?}
}

// Command Processing Function
void proccmd() {
 ?respbuf[0]='';
 ?if(ibuf[strlen(ibuf)-1]=='?') { // IS A QUERY STRING
 ???if (!strcmp("*IDN?",ibuf)) {
 ?????for (int n=0; n<strlen_P(deviceID); n++) {
 ???????respbuf[n]=pgm_read_byte_near(deviceID+n);
 ?????}
 ?????respbuf[strlen_P(deviceID)]='';
 ???} else if (!strcmp("*RST?",ibuf)) {
 ?????varreset();
 ???} else if (!strcmp("READ?",ibuf)) { ????????
 ?????sprintf(respbuf,"%ld.%02ld,%ld.%03ld,%d,%d,%d",senstemp/100,senstemp%100,senshum/1000,senshum%1000,cpwm,hpwm,sfault);
 ???} else if (!strcmp("SET?",ibuf)) {
 ?????sprintf(respbuf,"%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d.%02d,%d,%d,%d,%d,%d,%d",target/100,target%100,hdeadband/100,hdeadband%100,hfullpwr/100,hfullpwr%100,
 ?????????????cdeadband/100,cdeadband%100,cfullpwr/100,cfullpwr%100,hpwmmin,hpwmmax,cpwmmin,cpwmmax,coolerfan,internalfan);
 ???} else if (!strcmp("HELP?",ibuf)) {
 ?????for (int n=0; n<strlen_P(helpdata); n++) {
 ???????respbuf[n]=pgm_read_byte_near(helpdata+n);
 ?????}
 ?????respbuf[strlen_P(helpdata)]='';
 ???} else if (!strcmp("SETHELP?",ibuf)) {
 ?????for (int n=0; n<strlen_P(setdata); n++) {
 ???????respbuf[n]=pgm_read_byte_near(setdata+n);
 ?????}
 ?????respbuf[strlen_P(setdata)]='';
 ???} else if (!strcmp("IP?",ibuf)) {
 ?????sprintf(respbuf,"%d.%d.%d.%d",Ethernet.localIP()[0],Ethernet.localIP()[1],Ethernet.localIP()[2],Ethernet.localIP()[3]);
 ???} else if (!strcmp("MAC?",ibuf)) {
 ?????sprintf(respbuf,"%02X:%02X:%02X:%02X:%02X:%02X",mac[0],mac[1],mac[2],mac[3],mac[4],mac[5]);
 ???} else if (!strcmp("MEAS:TEMP?",ibuf)) {
 ?????sprintf(respbuf,"%ld.%02ld",senstemp/100,senstemp%100);
 ???}
 ?} else {
 ???if (!strncmp("SET ",ibuf,4)) {
 ?????// Read in settings using sscanf
 ?????sscanf(ibuf+4,"%d%d%d%d%d%d%d%d%d%d%d",&target,&hdeadband,
 ?????&hfullpwr,&cdeadband,&cfullpwr,&hpwmmin,&hpwmmax,&cpwmmin,&cpwmmax,&coolerfan,&internalfan);
 ???} else if (!strcmp("START",ibuf)) {
 ?????opmode = 1;
 ?????fanstate();
 ???} else if (!strcmp("STOP",ibuf)) {
 ?????stopunit();
 ???} else if (!strncmp("IP ",ibuf,3)) {
 ?????sscanf(ibuf+3,"%d%d%d%d",&ipaddr[0],&ipaddr[1],&ipaddr[2],&ipaddr[3]);
 ?????EEPROM.put(10,ipaddr);
 ?????EEPROM.put(20,bool(0));
 ?????resetBoard();
 ???} else if (!strncmp("MAC ",ibuf,4)) {
 ?????sscanf(ibuf+4,"%x%x%x%x%x%x",&mac[0],&mac[1],&mac[2],&mac[3],&mac[4],&mac[5]);
 ?????EEPROM.put(0,mac);
 ?????resetBoard();
 ???} else if (!strcmp("DHCP",ibuf)) {
 ?????EEPROM.put(20,bool(1));
 ?????resetBoard();
 ???} else if (!strcmp("NVERASE",ibuf)) {
 ?????EEPROM.put(500,int(0)); // Erases the magic value causing EEPROM to be reinitialised
 ?????resetBoard();
 ???} else if (!strcmp("REBOOT",ibuf)) {
 ?????resetBoard();
 ???} else if (!strcmp("LCD ON",ibuf)) {
 ?????lcd.display();
 ?????lcddispon=1;
 ???} else if (!strcmp("LCD OFF",ibuf)) {
 ?????lcd.noDisplay();
 ?????lcddispon=0;
 ???} else if (!strncmp("TARGET ",ibuf,7)) {
 ?????sscanf(ibuf+7,"%d",&target);
 ???} else if (!strncmp("IFAN ",ibuf,5)) {
 ?????sscanf(ibuf+5,"%d",&internalfan);
 ???} else if (!strncmp("OFAN ",ibuf,5)) {
 ?????sscanf(ibuf+5,"%d",&coolerfan);
 ???}
 ?}
}

// Set Fan State
void fanstate() {
 ?if (opmode) {
 ???analogWrite(COOLERFAN_PIN,coolerfan);
 ???analogWrite(INSIDEFAN_PIN,internalfan);
 ?} else {
 ???analogWrite(COOLERFAN_PIN,0);
 ???analogWrite(INSIDEFAN_PIN,0); ???
 ?}
}

// Sensor Initialisation Function
bool sinit() {
 ?bool retval = bme.begin(I2C_STANDARD_MODE);
 ?if(retval) {
 ???sfault = 0;
 ???bme.setOversampling(TemperatureSensor, Oversample16);
 ???bme.setOversampling(HumiditySensor, Oversample1);
 ???bme.setOversampling(PressureSensor, Oversample1);
 ???bme.setIIRFilter(IIR8);
 ???bme.setGas(0,1);
 ?}
 ?return(retval);
}

// Sensor Reading Function
void sread() {
 ?int32_t z;
 ?byte result;
 ?Wire.beginTransmission(0x76); // Check sensor comms on each read
 ?Wire.write(0xD0);
 ?Wire.endTransmission();
 ?Wire.requestFrom(0x76,1);
 ?result=Wire.read();
 ?if (result == 0x61 && sfault) {
 ???sfault = !sinit();
 ?} else if (result == 0x61) {
 ???sfault = 0;
 ???if(!bme.measuring()) {
 ?????bme.getSensorData(senstemp,senshum,z,z,0);
 ???} // Async Operations - Do Not Block!
 ?} else { // Failed to read ID - set Sensor Fault flag, attempt reinit
 ???sfault = sfault + 1;
 ???if (sfault > 20 && opmode) { // 20 consecutive sensor errors cause shutdown
 ?????stopunit();
 ???}
 ???sinit(); // Do not care about return value - can't afford to "hang"
 ?}
}

// Reset Operating Variables
void varreset() {
 ?target = 2500;
 ?hdeadband = 8;
 ?hfullpwr = 50;
 ?cdeadband = 0;
 ?cfullpwr = 28;
 ?cpwmmin = 16;
 ?cpwmmax = 255;
 ?hpwmmin = 0;
 ?hpwmmax = 128;
 ?coolerfan = 255;
 ?internalfan = 255;
 ?ltime = 0;
 ?lcdtime = 0;
 ?stopunit();
}

// Stop Unit Operations
void stopunit() {
 ?opmode = 0;
 ?hpwm=0;
 ?cpwm=0;
 ?analogWrite(FRIDGE_PIN,cpwm);
 ?analogWrite(HEAT_PIN,hpwm);
 ?fanstate();
}

// Update LCD status
void lcdstatus() {
 ?lcd.clear();
 ?if(opmode) {
 ???lcd.print(F("RUN ?"));
 ?} else {
 ???lcd.print(F("STOP "));
 ?}
 ?lcd.print(F("H "));
 ?lcd.print(hpwm);
 ?lcd.print(F(" C "));
 ?lcd.print(cpwm);
 ?lcd.setCursor(0,1);
 ?lcd.print('T');
 ?sprintf(respbuf,"%ld.%02ld",senstemp/100,senstemp%100);
 ?lcd.print(respbuf);
 ?lcd.print(F("c H"));
 ?sprintf(respbuf,"%ld.%03ld",senshum/1000,senshum%1000);
 ?lcd.print(respbuf);
 ?lcd.print('%');
}
```

---

Source: https://maker.wiznet.io/teju/projects/Modified-Car-Fridge-Pro-with-a-PCBWay-2Layer-HASL-PCB/
