With an Atmega, create a wireless temperature sensor
To continue the project of automation with the Raspberry, the first important step for me is to have a sensor able to send wireless data. Here I present to you an example of a probe measuring temperature and humidity.
In this article (very very long), I warn you that you will might not create the best probe in the world. Many sites offer extensive methods to arrive at an optimal solution. Here I introduce the results of my tests. Je compte sur les experts pour proposer des améliorations via les commentaires 🙂
To recap my probe runs on two AA batteries, with an Atmega328, a LED to indicate the operation and a 433 Mhz transmitter. The LED is optional because it uses energy but useful to confirm that everything is working.
After 16 17 18 19 20 days of work (the writing of the article took me time), my probe still emits the data with a distance of 5m between the sensor and the Gateway (an arduino connected to a Raspberry Pi), without walls but with a wooden furniture. Here is the evolution of the level of the batteries on the two weeks :
The probe has the following operating : all the 5 seconds (Yes this is for testing), the DHT11 probe is activated, the temperature and humidity are read as well as the battery level. These data constitute the message to send. The message is sent 4 time at an interval of 160ms. Each sending done turn on then turn off LED.
You can therefore imagine that by decreasing the number of messages' send, removing the LED and by increasing the time between each measurement, your battery can last easily a year (I would soon do an article on the subject).
Prerequisites
Before embark you on the adventure, you need a bit of hardware and a ready to use working environment.
Hardware
You will need :
- An atmega328 (just the chip) with or without bootloader, No matter because we will install our. You can easily find on ebay or Chinese sites in the €1.5 / piece or Amazon. In commissioning several you can still somewhat decrease the price.
- An Arduino UNO where you can remove the atmega. It will be used to send the bootloader and probe management program. You can use this Arduino (or another) as receiver. Count in the €10 (official but legal version), a little more on Amazon (faster). The Arduino can be used to build other probes.
- A temperature sensor. I used a DHT11 I had at home. This really isn't the best, the DHT22 is much better, but I only had it at the time. Count € 1.40 the DHT11 or € 4.5 the DHT22 (but ca is worth the cost)
- Resistance 4.7KΩ necessary for the DHT11 probe
- A transmitter and a receiver 433 Mhz. The transmitter will be for the probe, the receiver for the Arduino connected to the Raspberry. A little less than €1 the pair. But beware not all have the same quality … Subsequently I will test other communication modules.
- AA batteries. I'm using 2 that I put in a case from a Christmas LED wreath. The boxes cost about € 3.5 10 pieces (or here for a faster delivery).
- Wires
- A breadboard. Then you can use prototyping plates, smaller and then reuse the breadboard for other installations.
- (Optional but highly recommended !) 22µF capacitors. You will need 2 if your Atmega328 are configured by default to use an external oscillator (and I do not think that you can know in advance)
- (Optional but highly recommended !) A 8 Mhz or 16 Mhz resonator if your Atmega328 are configured by default to use an external oscillator
You are now equipped and ready to assemble your probe.
Workspace
When I speak of working environment, it is basically the tool Arduino IDE. Take the version 1.5.8+, even if it is a beta, in order to work !
It is now to be able to configure your Atmega to work with its internal oscillator (8MHz) to reduce its overall consumption. For this I advise you to load the ZIP file here. The archive must be unpacked in the sub directory hardware located with your Arduino programs. Here is what you should have :
At the launch of the Arduino IDE you should see new cards :
Installing an optimized bootloader
Here is the wiring to load the bootloader :
Once completed :
- Connect the arduino UNO to your computer via its USB cable
- Start Arduino IDE then confirm the configuration
- Upload of the programme so that the UNO can send the bootloader. The program is available in the menu “File > Examples > ArduinoISP”. Then click on “Upload”
TheArduino UNO is now ready to send a bootloader to your mounting !
- Select the type of card for your probe. We therefore choose an atmega328 on an arduino in 3.3V and the frequency of 8 Mhz
- Now select the card that will program the bootloader. It's our Arduino
- Rest to burn the bootloader with the command “Burn the bootloader”
You have now configured your node to operate in 3.3V using the internal oscillator which operates at 8 Mhz. This is the first step to optimize the use of energy !
You can now add your sensor and transmitter. If you have a resonator, You can remove it (as well as the capacitors) :
The Arduino UNO card can be used to send the program in your new Atmega. You can connect it as shown in the drawing above or else take the Atmega's node, put it on the UNO card, load the program through the IDE then replace the atmega's node on the breadboard. Up to you to decide, personnellement je déplace l’atmega 😉
The photo of the final stage :
Installation of the sensor program
In the Arduino IDE you will need to install the following libraries :
- The DHT library to retrieve the data of your DHT11. Available here.
- The Narcoleptic library to put at sleep (you can say that ?) “deep” your node and thus save the batteries. Available here.
- The Manchester Library to send the data via your 433 Mhz transmitter. Available here.
The installation of libraries is as follows :
- Retrieve the .zip of the library
- Import it using the import tool in Arduino IDE (Sketches > Import libraries)
Here is the program to send to your node using the Arduino IDE :
#include <Narcoleptic.h> #include <dht.h> #include <Manchester.h> #define BLINK_MODE true #define NODE_ID 1 // On 8bits so 0..255 #define MESSAGE_SIZE 6 // Number of bytes to send #define SEND_MESSAGE_DELAY 5000 // Delay in ms between each value's extraction #define SEND_433_COUNT 4 // How many times the message has to be send #define SEND_433_PAUSE 160 // 16 multiple // Define connectors used for the node #define TX_PIN 7 #define LED_PIN 13 #define DHT11_PIN 2 dht DHT; // Array of bytes to will make the message // In this node : 2 bytes for voltage, 2 bytes for uint8_t msgData[MESSAGE_SIZE] = {0, 0, 0, 0, 0, 0}; //-------------------------------------------------------------------------------------------------- // Read current supply voltage //-------------------------------------------------------------------------------------------------- long readVcc() { bitClear(PRR, PRADC); ADCSRA |= bit(ADEN); // Enable the ADC long result; // Read 1.1V reference against Vcc #if defined (__AVR_ATtiny24__) || defined(__AVR_ATtiny44__) || defined(__AVR_ATtiny84__) ADMUX = _BV(MUX5) | _BV(MUX0); // For ATtiny84 #elif defined (__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__) ADMUX = _BV(MUX3) | _BV(MUX2); #else ADMUX = _BV(REFS0) | _BV(MUX3) | _BV(MUX2) | _BV(MUX1); // For ATmega328 #endif delay(2); // Wait for Vref to settle ADCSRA |= _BV(ADSC); // Convert while (bit_is_set(ADCSRA,ADSC)); result = ADCL; result |= ADCH<<8; result = 1126400L / result; // Back-calculate Vcc in mV ADCSRA &= ~ bit(ADEN); bitSet(PRR, PRADC); // Disable the ADC to save power return result; // Vcc in millivolts } void setup() { pinMode(LED_PIN, OUTPUT); if (BLINK_MODE) digitalWrite(LED_PIN, LOW); man.setupTransmit(TX_PIN, MAN_1200); msgData[0] = NODE_ID; // Wait 1s to allow DHT11 to initialize Narcoleptic.delay(1000); } void loop() { // Read Vcc value long currentVcc = readVcc(); uint16_t uint16_currentVcc = (uint16_t)currentVcc; // Save millivolts in two bytes to keep high precision. Will be decoded by the gateway uint8_t byteData[2] = {uint16_currentVcc >> 8, uint16_currentVcc & 0xFF}; msgData[2] = byteData[0]; msgData[3] = byteData[1]; // Read data from DHT11 sensor int chk = DHT.read11(DHT11_PIN); // DHT11 values can be put in a byte value due to the low precision msgData[4] = (uint8_t)DHT.humidity; msgData[5] = (uint8_t)DHT.temperature; // Send message SEND_433_COUNT times with a delay of SEND_433_PAUSE ms for each for (int i=0; i<SEND_433_COUNT; i++) { msgData[1] = i; if (BLINK_MODE) digitalWrite(LED_PIN, HIGH); man.transmitArray(MESSAGE_SIZE, msgData); if (BLINK_MODE) digitalWrite(LED_PIN, LOW); // Wait between each send Narcoleptic.delay(SEND_433_PAUSE); } // Wait before getting new sensor value Narcoleptic.delay(SEND_MESSAGE_DELAY); }
And after ?
The next article will show how to receive data and send them to the Raspberry Pi that will (i hope) know what to do !
There so much to improve ! As for example :
- Code optimization. The idea is to make a generic library, available on GitHub, that will bring together the functions of recovery, conversion, etc. Depending on the sensors connected : DHT11, DHT22, LM36, etc.
- Other modules of emission : NRF24L01 , ESP8266, etc.
The 433Mz modules are capricious, not always of good quality, I have the impression that this is the best choice. So, I'll continue the investigation
The project Pi Home Connect continues !
Pingback: With an Atmega, create a wireless temperature sensor | RoboTechno()