RHT03 is a hygrometer of MaxDetect. Today, I report how to control an RHT03 with a Raspberry Pi. It was great effort because I am a beginner.
Even its accuracy is +-2%, RHT03 is sold only for about $10 at Sengoku densyo. There are two product names (RHT03 and DHT22), but they have the same specification. To drive an RHT03, I wired it to my Raspberry Pi (RasPi) with a GPIO and check GPIO’s voltage. It was great effort because it took almost half a year to know how. Well, I have doing wood and metal works and I was away from RasPi.
First of all, I followed the instructions of RHT03 and wired like this.
I kept using GPIO7.
Then, I looked for sample program to make sure the RHT03 was working. The manufacture has sample program on the web, but its format is Word. 😯 Additionaly, I couldn’t understand very well. 🙁 I found WiringPi had a sample code in it. I compiled right away, but it looped unlimitedly. I opened the source code (wiringPi-da38443/examples/rht03.c) and sniffed a suspicious line.
#define RHT03_PIN 0
This might mean the GPIO number I wired. I modified “0” into “7”, but the situation didn’t change. As I investigated deeply, I found the function maxDetectLowHighWait in the library (wiringPi-da38443/devLib/maxdetect.c) timed out again and again. This function measures voltage in an infinite loop, and exits when the voltage changes from LOW to HIGH. There is a 2-seconds timeout but I don’t think 2 means anything.
Finally, I decided to make program by myself. As I wrote before I program in C++. I sent a start signal and read voltage on GPIO. What I did corresponds with the following part of the manual.
When MCU send start signal, RHT03 change from standby-status to running-status. When MCU finishs sending the start signal, RHT03 will send response signal of 40-bit data that reflect the relative humidity and temperature to MCU. Without start signal from MCU, RHT03 will not give response signal to MCU.
This is the program.
setDirection(gpio_number, DIRECTION_OUTPUT); setVoltage(gpio_number, VOLTAGE_LOW); sleep_milliseconds(1); setVoltage(gpio_number, VOLTAGE_HIGH); sleep_microseconds(40); setDirection(gpio_number, DIRECTION_INPUT); while (ETERNAL) cout << getVoltage(gpio_number) << endl;
I copied the result and pasted on Excel.
Voltage went up and down, and its width was varying. This means my RHT03 is responding 😉
All I had to do was converting this graph into number, but I didn’t know how. I thought first that I measure voltage for a certain length of time, and if I get HIGH longer, I count the bit as 1, and if I get LOW longer, I count the bit as 0. After doing this for 40 times, I convert bits into numbers. For example, suppose 1 bit is transferred in 1 millisecond,
- Measure voltage for 1 millisecond
- If voltage HIGH is longer, suppose the bit as 1. If voltage LOW is longer, suppose the bit as 0
- Measure 40 times
- Convert 0 and 1 into decimal.
I found later this was wrong.
Measuring exact time
Is there a way to measure voltage like this? We can measure voltage through GPIO, but the result is the voltage “at that moment” when I measure. I thought I needed to measure “for a certain period”. The first idea came up to my mind was using usleep().
I found right away that I failed. Raspberry Pi sleeps for 155 to 164 microseconds when usleep(1) was called. Also this program reads voltage “at that moment” and sleeps, which doesn’t mean to measure “for a certain period”.
The next approach was to measure “at a moment” “for a certain period”. If I get HIGH “more”, I suppose I get 1, and if I get LOW “more”, I suppose I get 0. To measure exact time, I used hardware clock. The hardware clock is time since my Raspberry Pi booted. The unit is microsecond. I referred to BCM2835 ARM Peripherals.
You can use the same way to measure GPIO voltage “at a moment” and hardware clock “at a moment”. Both can be taken directly from BCM2835’s memory. For example, the address of GPIO is this.
// Peripheral base address static const unsigned int BASE_ADDRESS_PERIPHERAL = 0x20000000; // Offset from BASE_ADDRESS_PERIPHERAL to GPIO registers static const unsigned int OFFSET_GPIO = 0x200000;
Address to GPIO = BASE_ADDRESS_PERIPHERAL + OFFSET_GPIO = 0x20000000 + 0x200000 = 0x20200000.
The address of system timer is this.
// Offset from BASE_ADDRESS_PERIPHERAL to system timer registers static const unsigned int OFFSET_SYSTEM_TIMER = 0x3000; // Offset from system timer registers to counter (lower 32 bits) static const unsigned int OFFSET_SYSTEM_TIMER_COUNTER_LOW = 0x1;
Address to system timer = 0x20000000 + 0x3000 + 0x1 = 0x20003001.
There is another register called System Timer Compare, and this this sets System Timer Control/Status to 1. If you measure multiple devices at the same time, you need to use these registers, but I don’t use this time.
Converting voltage into binary
I copied the result and pasted on Excel.
I couldn’t tell how to convert this into binary bits. Suppose humidity is 50% and temperature is 20 celsius degrees, the binary bits should be like this.
50% = 0000 0001 1111 0100
20C = 0000 0000 1100 1000
There are some 0s but voltage does not stay on LOW. It goes HIGH and LOW. I searched and found result measured with an oscilloscope.
I finally understood.
- Wrong: HIGH means1 and LOW means 0
- Correct: Voltage goes LOW first and then goes HIGH always for each bit. If voltage is HIGH for 26 to 28 microseconds, the bit is 0. If voltage is HIGH for 70 microseconds, the bit is 1.
I tried to calculate on Excel and got exactly 40 bits. The number also looks ok.
RHT03 outputs check sum digits. If you add the first 32 bits by 8 digits, the sum should match the check sum digits. In the other words, if the sum doesn’t match, there is a data transfer error.
Let’s calculate. Because this is binary, 1+1=10.
Suppose we got 0000001000011100000000101010110011011010, the sum of the first 32 bits is:
This doesn’t match the check sum (last 8bits of 40 bits), 11011010. This means there is a data transfer error. Hmm…
By the way, finding errors in this way is called “Error detection”. There are ways not only finding errors but also correcting mathematically, which is called “Error correction”.
The check sum of RHT03 is for “Error detection”. Unfortunately not for “Error correction”.
Checking Error Cause
I sought the error cause. This is the normal voltage transition.
There are some unusual points when I got check sum error.
Data has dropped around 3,500 microseconds. My RasPi can measure voltage 3 times a microsecond, but it took 173 microseconds only once at that moment. I guess RasPi missed the RHT03’s signal. RasPi might be “busy”. It must be a matter of task scheduling of operating system. As symptomatic treatment, I added a code to handle measuring voltage which takes more than 26 microseconds as an error.
Then I kept my RasPi and RHT03 working for one day. I set cron so that my program run every 10 minutes. I copied the result and pasted on Excel.
The result is abnormal. Humidity doesn’t exceed 100% 😉 The transaction between RasPi and RHT03 must be incorrect but the check sum happened to match. I added a code to check humidity and report an error when it exceeds 100%.
I could finally draw a graph.
I found Raspberry Pi warmed RHT03, so I put RHT03 away. Also I added a STMicroelectronics STTS751-0WB3F and a Freescale Semiconductor MPL115A2 to work together. These are devices I have introduced a little before.
This is how the wiring looks.
I left the breadboard on my Raspberry Pi because it is useful, so I prepared another breadboard and connected them with a LAN cable. I chose LAN cable because of these reasons.
- It is cable for transferring data.
- I have stocks at home.
- It is available even in convenience stores.
- Therefore price is reasonable and quality is stable.
- It is enough soft to wire.
- It has even 8 cables inside.
I don’t think there are cables satisfy all of these. By the way, I’m still learning about noise, frequency and wiring. I could be wrong.
To wire with a LAN cable, I bought two Akizuki LAN connector DIP kits.
This is the side for power.
This is another side for I2C wiring.
I measured all of them at once.
I judged temperature is ok because STTS751 and RHT03 have almost same value. The problem is humidity. It goes 1% or 2% higher sometimes. I overwrote how many times the program measured humidity.
The problems are:
- Measuring fails always 2 time.
- Measuring is done always in odd number.
- Humidity goes up 1% or 2% higher only when it measures 5 times and more.
- The amount of humidity increase doesn’t change.
I fixed the first 2 problems by improving my program. I added 500 milliseconds sleep before measuring. This might be because of the task scheduling I mentioned above.
I investigated the error causes and there are 5 causes.
- Raspberry Pi was too busy to measure voltage
- The check sum unmatched
- Raspberry Pi couldn’t receive all 40 bits
- Measuring time out
- Humidity is invalid (humidity exceed 100%)
There are reason-and-result combinations. I picked up all the combinations I got and put them into a truth table.
The root cause is the check sum. The sum matched once. This is because the sum matched by coincidence when Raspberry Pi was too busy to measure voltage. Remember. The check sum of RHT03 is for “Error detection”. The sum could match by coincidence.
The reason why humidity goes up by 1or 2% is because the fifth bit always increases. The number of 10000 in binary equals to 16. This value is equal to 1.6% of RHT03.
I don’t know why this happens. I’m still investigating if there is a relation, but even if I can find something, I couldn’t tell what to do because I know I can’t verify the inside of RHT03. I gave up investigating more. This could be why RHT03 has +-2% accuracy. 😉
If you want to execute the program I made, download Tango limited edition for RHT03. The program is still written in Japanese, but it should work in any languages.
Updated on September 26, 2016
This post was introduced by a human resource agency! Click here for detail.
Also the story continues to “Weather Observation with Raspberry Pi – Vol1 Circuit“.
If you are interested in this post, check all posts of Raspberry Pi and Electronics DIY. For example, I posted these articles.
- A total beginner started to learn electronics with Raspberry Pi
A cigarette-box-size computer Raspberry Pi “bridged” between my knowledge of computer science and electronics. More precisely, RasPi made me one of zombies that crowd around circuit boards and connectors. LOL
- Electronics with Raspberry Pi Vol. 2
I couldn’t understand what current, resistance and voltage meant, but having spent money (aka investment;)), I’m getting to understand what they mean.
- Tools I bought besides Raspberry Pi
4 months have passed since I got a RasPi and started to learn electronics. As I study, I needed to buy many things including books, electronic parts and tools. Today I show you what tools I’ve bought besides RasPi.
This post is also available in: Japanese