Impulsiveness is not always a good thing. So here’s a handy rule for you: first, prototype; then fabricate the PCBs. Doing it that way, things have a chance of going well. Reverse that order and … well, not so much.
Not that it was a disaster. In fact I had prototyped this little project – mostly. But we’re getting ahead of ourselves.
There was a period when forums were constantly a-twitter with talk of the ESP8266, the miracle microcontroller with built-in wifi loveliness. And for a long time I mostly ignored it because I was busy elsewhere. Then I gave in and ordered a few – the Adafruit Huzzah board, to be precise, because I trust Adafruit. I mucked about with MicroPython and thought, ‘this is rather nice’, then put it aside to concentrate on other stuff.
But over winter I found myself with a need to know the temperature in my office. It wasn’t just a desire. I really needed this information.
As someone who suffers from osteoarthritis, I’m somewhat sensitive to temperature. If it drops too low, the pain in my joints increases notably.
Now, I could have just bought a digital thermometer (actually, I bought two) and set it up at my workstation. But where’s the fun in that? No, I wanted a thing – as in the Internet of Things (IoT).
So I dug out the ESP8266 boards and looked around for a suitable temperature sensor. I had a few lying around, but when I tried using them and compared the results with a digital thermometer I found they were somewhat inaccurate.
Eventually I settled on the DHT22. And then I learned a lesson. I bought a few, very cheap, from China via eBay. Not only didn’t they agree with the digital thermometer, they didn’t even agree with each other. It’s possible they were rejects. Then I bought a few more at slightly higher cost from reputable suppliers. These were consistent in readings, although still half a degree Celsius below the digital thermometer. I can live with that. And although it’s unlikely the error is linear across the full range of temperatures, within the limited range I’ll be experiencing in my office I should be able to just add a 0.5ºC compensation in the software if I want.
The sensor has four pins – VCC, GND, data out and one that isn’t used. You pull the data pin high with a resistor (I used a 10kΩ), attach it to a GPIO pin and then use the Adafruit library. Easy.
(BTW, I developed the code for this project in the Arduino IDE, in its usual dialect of C.)
As a display I opted for a 2.2in SPI-driven 240×320 TFT panel that I’ve used a lot with the Teensy with great success. I’m controlling this with the Bodmer TFT_eSPI library which provides for lots of nice fonts and easy text placement, once you get used to it.
The display shows the current temperature, rounded to the nearest integer (in Celsius, because I’m European and have forgotten why anyone bothers with Fahrenheit). Under that is the actual temperature to one decimal place, the minimum and maximum temperatures since the last reset (more on this in a moment) and the relative humidity.
Then come the time and date. Underneath those is a three-line area for various messages, including one just for errors. These messages disappear after a certain period (which is set in the code). Finally, there’s a line at the bottom showing the SSID of the wifi access point in use and the ESP8266’s IP address.
Time & date
I didn’t want to add a real-time clock. It was just too much complication and besides, the Huzzah board almost certainly wouldn’t have enough GPIO pins to accommodate it. To hell with that anyway because this is an Internet thing. If it wants to know the time it can just ask a server.
In terms of electronic components, then, there isn’t a lot more than the three main items – the ESP8266 board, the TFT LCD display and the temperature sensor. I needed a couple of resistors – one to pull the data line on the DHT sensor high and one to limit the current for the power supply to the screen’s backlighting. I also decided to add a reset button, so I added another resistor to pull that high too.
In spite of the simplicity, though, I decided to have a PCB made. It would save on a lot of wiring and would be smaller than, say, a stripboard solution. Besides, having started to get comfortable with KiCad I just like making PCBs now.
That’s when things got a little wobbly.
While drawing up the schematic I noticed I had three spare pins. Pin 0 on the Huzzah is a bit weird, being associated with the bootloader, so I decided to ignore that. But pins 15 and 16 were also unused.
This was about the same time I decided the display should show maximum high and minimum low temperatures. And I wanted a way of resetting that. No problem – I’ll add a second ‘reset’ button. Pin 15 seemed handy. I’ll pull that high with a resistor and then set up an interrupt to watch for it being pulled low, I thought.
Remember, this is after I’d built the breadboard prototype and while I was drawing the schematic. I was pretty confident it would work, so I went ahead and laid out the PCB and ordered 10 of them from a fab house (total cost $9 including shipping).
Then I added the new button to the breadboard prototype.
It didn’t work.
I’ll save you the agonies I went through. It turns out that pin 15 is also a bit weird on this board. According to Adafruit it is, “used to detect boot-mode. It has a pulldown resistor connected to it, make sure this pin isn’t pulled high on startup. You can always just use it as an output”. Damn. I couldn’t even upload new versions of the code to the ESP8266 board because I had this pulled high.
I switched to pin 16, but couldn’t get the interrupt to fire. So I tried pin 2. That worked with the interrupt, but on my board it’s tied up for use with the temperature sensor. I considered changing lots of pin assignments, but the thought was somewhat daunting.
In the end I redesigned the schematic and board layout and reworked the software to use pin 16 with simple polling, rather than using an interrupt. I still don’t know why the interrupt doesn’t work, but assume it’s somehow connected to the fact that the pin is used to wake the microcontroller from deep sleep.
I hadn’t considered polling before for one good reason – my original version of the code included a long delay (six seconds no less) in the main loop. This is because the device isn’t in any hurry to do anything. The main loop does the following:
- Checks in with a server to update the time and date – once a minute is enough for this.
- Checks in with a server to send the current temperature and humidity, so the server can log them and display the data on our intranet. A side-effect of this is checking the wifi connection is still good. Once every five or 10 minutes is good enough for this.
- Checks and displays the current temperature and humidity – I figured five-minute intervals are good enough for this.
So I used a six-second delay in the loop and integer counters to decide when these actions should take place. That made polling for button pushes very haphazard because the processor was spending most of its time in a delay() function!
To sort that, I divided the delay time by 10 and multiplied the limits for the counters by the same factor to compensate. Now the delay time is 600 milliseconds – just over half a second. This works well because when you press the button to reset the min/max values there’s that slight delay before it happens. You have to be very deliberate about it, which I think is a good thing in a reset button. Also, the delay debounces the switch.
The PCBs I ordered should still work, I just won’t solder in the headers for the min/max reset button and the associated pullup resistor. If I want to reset the minimum and maximum values I’ll just reset the whole shebang with the main reset button.
In the next part I’ll talk about how it talks with the server.
» Read Part 2 »