Ic For Fun: Humidity and temperature measurements with Sensirion’s SHT1x/SHT7x sensors (Part 2)

Ic For Fun: Humidity and temperature measurements with Sensirion’s SHT1x/SHT7x sensors (Part 2)

Humidity and temperature measurements with Sensirion’s SHT1x/SHT7x sensors (Part 2)

Posted: 07 May 2012 08:13 PM PDT

In Part 1 of this tutorial, we discussed about Sensirion's SHT1x and SHT7x series of humidity sensors, their interface specifications, the communication protocol used for transferring data in and out of the sensor, and the equations to convert their digital outputs to actual physical quantities. These sensors are capable of measuring temperature along with relative humidity and provide outputs in fully-calibrated digital words. We will now see how a PIC microcontroller can be programmed to communicate with these sensors, read the temperature and relative humidity data, and display the information on a character LCD.

SHT setup Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
Circuit setup on breadboard


Circuit Diagram

We will be interfacing the SHT11 and SHT75 sensors simultaneously to different port pins of PIC18F2550 and display the measured values of relative humidity and temperature from both on a 16×2 character LCD. The two sensors are placed next to each other and are supposed to measure the same values for relative humidity and temperature. The circuit diagram below shows the connection of the two sensors and a 16×2 character LCD to StartUSB for PIC board. StartUSB for PIC is a small development board for PIC18F2550 from mikroElektronika. The microcontroller comes preprogrammed with a bootloader, and therefore, no external programmer is required.

SHT Ckt1 550x414 Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
Connecting a LCD and SHT sensors to StartUSB for PIC board

The LCD is operating in 4-bit mode, where the data pins D4-D7 are driven by RB4-RB7 pins of PIC18F2550. The RS and E pins are connected to RC6 and RC7 respectively. The clock lines of SHT11 and SHT75 are driven separately by RB1 and RB3 pins of PIC18F2550, respectively. On the other hand, the RB0 and RB2 pins are connected to the data pins (SDA or DATA) of SHT11 and SHT75, respectively. A decoupling capacitor (100 nF) is connected between Vcc and Gnd pins of each sensor. The PIC18F2550 microcontroller on-board StartUSB for PIC board runs at 48 MHz using the internal PLL along with an external 8.0 MHz crystal. A pull-up resistor of 10 K is required for each DATA line (in fact, the SHT11 board from mikroElektronika has pull-up resistors of 1 K on both DATA and SCK lines, but the manufacturer's datasheet recommends 10 K).


The sensor's serial communication protocol was described in Part 1. We will implement it for PIC18F2550 using mikroC Pro for PIC. MikroElektronika provides a sample code written in mikroC for reading temperature and relative humidity from a SHT11 sensor. This code was later modified by Uroš Pešović (from Serbia) in order to account for the new conversion coefficients released by Sensirion for its version 4 sensors. I am adapting the same code for dual sensor case with some modifications that are required for our specific case.

The following subroutine is to reset the interface, in case the communication to the sensor is lost. In our case this routine will be always called before sending a new measurement command to the sensor. In order to pull the DATA line high, all you need is to define the direction of PIC port pin driving the DATA line as input. The pull-up resistor will then pull the line high. However, the same port pin direction must be defined as output and set to logic '0′ to pull the line low.

void SHT_Reset() {   SCL = 0;                     // SCL low   SDA_Direction = 1;           // Define SDA as input to pull the DATA line high   for (i = 1; i <= 10; i++)    // repeat 18 times   SCL = ~SCL;                  // invert SCL   }

Once the connection is reset, you need to send a Start Transmission sequence. The subroutine for this would be something like this.

void Transmission_Start() {   SDA_Direction = 1;            // Pull SDA high   SCL = 1;                      // Clock high   Delay_1us();                  // 1 us delay   SDA_Direction = 0;            // SDA as output   SDA = 0;                      // DATA low   Delay_1us();                  // 1us delay   SCL = 0;                      // Clock low   Delay_1us();                  // 1us delay   SCL = 1;                      // Clock high   Delay_1us();                  // 1 us delay   SDA_Direction = 1;            // SDA as input, DATA is high   Delay_1us();                  // 1us delay   SCL = 0;                      // SCL low   }

As we discussed in Part 1 of this tutorial that the microcontroller is required to send an acknowledge pulse on receiving a data byte from the sensor, the following routine takes care of that.

void MCU_ACK() {    SDA_Direction = 0;     // define SDA as output    SDA = 0;               // DATA low    SCL = 1;               // Clock high    Delay_1us();           // 1us delay    SCL = 0;               // Clock low    Delay_1us();           // 1us delay    SDA_Direction = 1;     // DATA high   }

The following subroutine sends a measurement command to the sensor, then waits till the measurement is finished, and finally receives the two byte measurement readings.

long int Measure(short command) {    j = command;                  // j = command (0x03 or 0x05)    SHT_Reset();                  // Reset interface    Transmission_Start();         // procedure for sTmprting transmission    k = 0;                        // k = 0    SDA_Direction = 0;            // define SDA as output    SCL = 0;                      // SCL low    for(i = 1; i <= 8; i++) {     // repeat 8 times      if (j.F7 == 1)              // if bit 7 = 1       SDA_Direction = 1;         // make DATA line high      else {                      // else (if bit 7 = 0)       SDA_Direction = 0;         // set DATA line as output and       SDA = 0;                   // pull DATA line low      }      Delay_1us();                // 1us delay      SCL = 1;                    // SCL high      Delay_1us();                // 1us delay      SCL = 0;                    // SCL low      j <<= 1;                    // move contents of j one place left                                  // until all 8-bits of command are sent     }    // Wait until the DATA line is pulled low by the sensor     SDA_Direction = 1;           // define SDA as input     SCL = 1;                     // SCL high     Delay_1us();                 // 1us delay     SCL = 0;                     // SCL low     Delay_1us();                 // 1us delay     while (SDA == 1)             // while DATA is high, do nothing     Delay_1us();                 // 1us delay    // Read 2 bytes of measurement data after it is ready    for (i = 1; i <=16; i++) {    // repeat 16 times      k <<= 1;                    // move contents of k one place left      SCL = 1;                    // SCL high      if (SDA == 1)               // if DATA is high       k = k | 0x0001;            // set the corresponding bit of K to 1      SCL = 0;      if (i == 8 )                 // Send an acknowledge after each byte       MCU_ACK();     }    return k;                     // Return the measurement data    }

Once you get the two-byte measurement output from the sensor, you can use the conversion coefficients provided in the datasheet to retrieve the temperature or relative humidity. This part is just a mathematical manipulation and hence not described in here. The complete code for this project is however, downloadable from the link provided below.

Download complete mikroC project files

Important note

The datasheet recommends to use a 10K pull-up resistor to the DATA line, and the SCK line may work fine without a pull-up resistor. However, the SHT11 proto board from mikroElektronika has got two 1 K resistors to pull-up both SCL and SDA lines. The resistors dissipate some heat when the lines are pulled low. This may introduce error in the measurement of  both temperature and relative humidity, as the resistors are in the close proximity of the sensor as all of them are on the same board. In order to minimize this heat dissipation, the port pins of microcontrollers that drive SCK and SDA lines, must be defined as input pins, while in idle state. If you leave them as outputs with logic 0 states, there will be current continuously flowing through the pull-up resistors, which will dissipate more heat and raise the temperature of the sensor.


The picture below shows the two sets of temperature and relative humidity readings shown on the LCD, which were measured by SHT11 and SHT75 sensors. The temperature values are consistent within 0.1 °C. However, the SHT11 seems to be off from SHT75 by 1.2 % in the measurement of relative humidity. These readings are taken right after the circuit is powered on.

SHT Output Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
Temperature and relative humidity readings from two sensors

The sensors are scheduled to take the measurements in every 2 sec. Because of heat dissipation in the resistors on-board, the temperature measurement from SHT11 module slowly increases and drifts apart from that of SHT75.

Drift1 Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
SHT11 drifting apart from SHT75 because of heat dissipation

The drifting of SHT11 becomes more severe if you don't change the SCK pin direction to input while it is in idle condition. See the picture below where the SHT11 measurement of the temperature is more than 2 °C higher than that of SHT75. This drift occurred within less than first two minutes after the circuit is powered on. Here, you can also see the inverse relationship between temperature and humidity. With increasing temperature, the relative humidity is decreasing.

LargeDrift Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)
Temperature of the SHT11 module increases significantly due to power dissipation in the pull-up resistors during idle conditions


Sensirion's SHT series of humidity sensors are very handy in measuring both relative humidity and temperature because of on-board signal processing and providing fully calibrated digital outputs. They communicate with a host controller through two wire serial bus: DATA and SCK. The DATA line requires an external pull-up resistor that dissipates some power as heat when the DATA line is pulled low. Therefore, care must be taken, specially for surface mount type sensor like SHT1x, in placing the resistor along with the sensor on the same module. The port pins of the microcontroller driving the clock and data lines must be set as input during idle conditions to minimize the heat dissipation in the pull-up resistors.


Further suggestions

SHT1x/7x sensors cannot measure dew point directly, but it can be derived from the humidity and temperature measurements. The datasheet provides the equation and necessary coefficients required to calculate dew point. There are some other details such as the stability of sensor, normal operating conditions, wiring considerations, etc. that are not discussed here, but readers can find those information in the datasheet.

SharePinExt Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2) tumblr Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2) myspace Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 2)

Related posts:

  1. Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1)
  2. Testing active analog temperature sensors with a multimeter
  3. A Digital temperature meter using an LM35 temperature sensor

This posting includes an audio/video/photo media file: Download Now

Humidity and temperature measurements with Sensirion’s SHT1x/SHT7x sensors (Part 1)

Posted: 07 May 2012 08:10 PM PDT

Temperature and relative humidity are two very important ambient parameters that are directly related to human comfort. Sometimes, you may be able to bear higher temperatures, if there is a lower relative humidity, such as in hot and dry desert-like environment. However, being in a humid place with not very high temperature may make you feel like melting. This is because if there is high relative humidity, sweat from our body will evaporate less into the air and we feel much hotter than the actual temperature. Humidifiers and dehumidifiers help to keep indoor humidity at a comfortable level. Today we will discuss about Sensirion's SHT series of digital sensors, more specifically SHT11 and SHT75, which are capable of measuring both temperature and relative humidity and provide fully calibrated digital outputs. We will interface both the sensors to PIC18F2550 microcontroller and compare the two sets of  measurements to see the consistency between the two sensors. This tutorial is divided into two parts. The first part will cover all the details regarding the sensors, including their specification, interface, and communication protocol. The second part will be more focussed on the circuit diagram, implementation of the communication protocol with PICMicro, and the results.

SHT Title Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Relative humidity and temperature measurements with SHT1x and SHT7x sensors



Sensirion offers multiple SHT series of digital sensors for measuring both relative humidity and temperature. The temperature is measured using a band-gap sensor, whereas the humidity sensor is capacitive; which means the presence of moisture in air changes the dielectric constant of the material in between the two plates of a parallel-plate capacitor, and hence varies the capacitance. The required signal conditioning, analog-to-digital conversion, and digital interface circuitries are all integrated onto the sensor chip. The various SHT series sensors have different levels of accuracy for humidity and temperature measurements, as described below.

SHT Series Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) SHT1x, 2x, and 7x series of humidity sensors (Source:

SHT1x are available in surface mount type whereas SHT7x are supplied with four pins which allows easy connection. The SHT11 and SHT75 sensors both provide fully calibrated digital outputs that can be read through a two-wire (SDA for data and SCK for clock) serial interface which looks like I2C but actually it is not compatible with I2C. An external pull-up resistor is required to pull the signal high on the SDA line. However, the SCK line could be driven without any pull-up resistor. The signaling detail of the serial bus is described in the datasheet, which we will implement for PIC18F2550 microcontroller using mikroC pro for PIC compiler. The operating range of both the sensors is 0 to 100% for relative humidity, and -40.0 to 123.8 °C for temperature. The sensor consumes 3 mW power during measurement, and 5 μW, while in sleep mode.

The SHT11 module that I have got is from mikroElektronika. The sensor (SMD) is soldered on a tiny proto board with all the four pins accessible through a standard 0.1 inch spacing male header. The board comes with pull-up resistors connected to both SDA and SCK lines. One concern in this type of arrangement is the heat dissipated by the pull-up resistors could affect the measurements if the resistors and the sensor are close in the board. We will discuss about this issue later too. The SHT75 module from Sensirion, however, does not include any pull-up resistor for SDA line and therefore must be included externally.

SHT11 Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) SHT11 proto board from mikroElektronika comes with pull-up resistors for both SDA and SCK lines

SHT751 Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Pin descriptions of SHT75

Brief description of SHT1x/7x sensors

Please read the datasheets for SHT1x and SHT7x for detail information about these sensors. I am only providing a brief summary here.

SHT11 and SHT75 are functionally same with SHT75 being more accurate (±1.8% vs ±3%) in measuring relative humidity. Both the sensors can operate from 2.4-5.5 V supply voltage, however the datasheet recommends to use 3.3V for highest accuracy. The default measurement resolution is 14-bit for temperature and 12-bit for relative humidity, which can be reduced to 12- and 8-bit respectively by changing the bit settings of the Status Register (discussed later) inside the sensor chip. We will be using the default resolution settings for measurements.

SCK is the clock line that is used to synchronize the communication between the micrcontroller and the sensor. It is an input only pin on the sensor's side and therefore the microcontroller should be responsible to generate the clock signal. DATA or SDA is a bidirectional data transfer pin for sending data in and out of the sensor. The sensor should receive a conversion command from the microcontroller in order to start measuring temperature or relative humidity. The measurement commands for relative humidity and temperature are 00000101 (05H) and 0000011 (03H), respectively [The first three most-significant bits are actually the address bits, which are always zero for SHT1x and SHT7x sensors, and the remaining 5 bits are the command bits]. Prior to sending a command, a Transmission Start sequence must be issued by the microcontroller which consists of a lowering of the DATA line while SCK is high, followed by a low pulse on SCK and raising the DATA line high again, while the SCK is already high.

StartTransmission Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Transmission Start signal

After receiving a command from microcontroller, the sensor issues an acknowledge pulse by pulling the DATA line low for one clock cycle. It takes place after the falling edge of the 8th clock (corresponding to the 8th bit of command sent) on the SCK line, and the DATA line is pulled low until the end of the 9th clock on the SCK line.

After issuing a measurement command ('00000101' for relative humidity, '00000011' for temperature) the microcontroller has to wait for the measurement to complete, which takes a maximum of 20/80/320 ms for a 8-/12-/14-bit measurement. During this time, the microcontroller can stop generating clocks on SCK line, and release DATA line. Upon the completion of measurement, the sensor generates a Data Ready signal by pulling the DATA line low. Upon receiving the Data Ready signal, the microcontroller can restart the clock on SCK line to readout the measurement data. The measurement data is kept stored into the memory of the sensor until readout.

The readout involves two bytes of measurement data and one byte of CRC checksum. The transmission of data is secured by an 8-bit checksum which is optional. The microcontroller must acknowledge each byte by pulling the DATA line low. The bytes are transferred with MSB first, and are right justified. For 8-bit measurement, the first byte is not used. If CRC-8 checksum is not used the microcontroller may terminate the communication by keeping ACK high after receiving the LSB of the measurement data. The device automatically returns to Sleep Mode after measurement and communication are completed. The figure below is taken from the datasheet of SHT7x and it shows the sequence of relative humidity measurement .

SHT Sequence 550x284 Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Source: SHT7x datasheet

While sending a command to SHT sensor, DATA is valid on the rising edge of the serial clock (SCK) and must remain stable while SCK is high. However, for reading data from the sensor, DATA is valid after SCK has gone low and remains valid until the next falling edge of SCK.

Status register

This is an 8-bit register inside SHT1x/SHT7x sensors that controls some of the advanced functions such as selecting measurement resolution, end-of-battery notice, OTP reload or using the on-chip heater. This register is both readable and writable through appropriate commands. The individual bit definition of the status register is shown below:

StatusRegister Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Status Register bit definition (from SHT7x datasheet)

The commands to read and write to Status Register are 00000111 (07H) and 00000110 (06H), respectively. In order to write a byte to Status Register, the microcontroller must send the write command (06H) followed by the data byte to be written. The sensor must generate an acknowledge signal upon receiving both the command and the data byte. The calibration coefficients of the sensor are pre-programmed inside a small on-board one-time programmable (OTP) memory. These coefficients are used internally by the sensor during measurements. Clearing bit 1 of Status Register disables loading of the calibration coefficients on each measurement and therefore, speeds up the conversion process.

The sensor has also got an on-chip heating element that can be turned on by setting the bit 2 of Status Register. If the heater is turned on, the temperature of the sensor may increase by 5-10 °C. The on-chip heater can be helpful to study the effect of raising the temperature on the measurement of relative humidity. Bit 6 of Status Register is a read-only flag, which is set to 1 when the supply voltage of the sensor drops below 2.47 V.

Connection Reset sequence

If communication between the microcontroller and the sensor is disrupted for some reasons, the following signal sequence may be used to reset the interface. Remember that only the interface is reset, and the value of Status Register is preserved. The reset sequence consists of toggling the SCK line nine or more times, while keeping the DATA line high.

ResetSeq Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Connection reset sequence (from SHT7x datasheet)

Conversion coefficients for relative humidity and temperature

In order to convert the digital readouts from the sensor into appropriate physical quantities (relative humidity and temperature), the datasheet provides optimized conversion coefficients and equations. The humidity sensor is non-linear by design and therefore requires a second order conversion equation, whereas the temperature sensor is pretty linear. At temperatures significantly different from 25°C (~77°F) the humidity signal requires correction to compensate the effect of temperature. The correction coefficients and equation are also provided in the datasheet.

RH Eqn Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Equation for computing relative humidity (from SHT7x datasheet)

RH true Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Temperature compensation coefficients for RH (from SHT7x datasheet)

Temp Eqn Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) Temperature conversion coefficients (from SHT7x datasheet)

SharePinExt Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) tumblr Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1) myspace Humidity and temperature measurements with Sensirion's SHT1x/SHT7x sensors (Part 1)

Related posts:

  1. Testing active analog temperature sensors with a multimeter
  2. A Digital temperature meter using an LM35 temperature sensor

This posting includes an audio/video/photo media file: Download Now

Digital light meter with a calibrated LDR

Posted: 07 May 2012 06:07 AM PDT

Measurement of light intensity is a prime necessity in several occasions.  The diversity of such needs make their way to various branches of physics and engineering as well as in media. For instance, in engineering, such kinds of measurements are needed to design optimum lighting conditions of a room. In photography, light intensity measurements ensure good quality pictures by determining the right exposure. Wiring a phototransistor or a light-dependent-resistor (LDR) with an analogue LED voltmeter chip like the LM3914 or even to a microcontroller and displaying the ADC values is a pretty simple technique of measuring light intensity. The bad part of this technique is that these simple and amateur-level devices can only measure relative intensity of light and are unable to provide measurements on an absolute scale. However, with a precise knowledge of the transfer characteristic (resistance vs light intensity) of the LDR it is possible to relate the LDR output to the intensity of light in standard unit. In case the LDR characteristic is unknown or unreliable, you can still calibrate the sensor output by using a variable light source and an external reference photometer. This project is about a microcontroller based light intensity meter where an LDR light sensor is calibrated against an external photometer to obtain the intensity of incoming light in the unit of lux. The lux is the SI unit of illuminance and luminous emittance, and measures lumens per square meter (lm/m2). The microcontroller used in this project is ATMega8L and its firmware is written using mikroElektronika's MikroC Pro for AVR compiler.

TitleLUXMeter1 Digital light meter with a calibrated LDR
AVR based LUX meter


Circuit diagram

The project's hardware is simple and requires little explanation. I used my custom-built 28 pin AVR demo board that provides all the necessary interfaces. An LDR is used as a light sensing device. I could have used advanced light sensors like TSL257 or TSL230 but they are pretty expensive and rare. A photo transistor is also a good option but photo transistors and photo diodes are very responsive to rapidly changing signals which is not desired here. Besides, ordinary photo transistors and diodes are more specific to a particular wavelength and therefore may not be equally sensitive to the same intensity of different wavelengths. According to the schematic shown below, an LDR and a precision analogue potentiometer form an adjustable light-dependent voltage divider. The output of this divider goes to a 3rd order analog low pass filter (LPF). This filter is designed with Texas Instrument's (TI) TL072 dual Op-Amp and allows frequencies lower than 100Hz to pass and stops anything above this value. The LPF is here needed to reduce noise and unwanted high frequency transitions due to sudden flickering lights, glare, pulsating light sources and so on.

FilterStage1 Digital light meter with a calibrated LDR
Op-Amp Filter stage

Next the output from the LPF is fed to the first analog input channel ADC0 (pin C0). Additional signal conditioning is done inside the microcontroller by performing the root-mean square (R.M.S) of the ADC samples. Thus both analogue and digital filtering are done. The result of such dual filtering is a highly processed signal which is reasonably reliable and accurate than with a direct connection to the ADC pin. However complexities arise both at hardware and software ends. The rest of the works after signal conditioning are done inside the AVR chip itself and in the software end. A 16×2 alphanumerical LCD is connected to PORTB of the AVR micro to show the measured light intensity level in lux. It should be noted that the AVR runs at 8.0 MHz clock derived from its internal source.

Microcontroller and LCD circuit

TL072ckt1 Digital light meter with a calibrated LDR
Op-Amp circuit on breadboard



As stated earlier the coding for the Atmega8L is done with MikroC Pro for AVR compiler from Mikroelektronika. The internal 8MHz RC oscillator is used as the clock source for the Atmega8L. The chip was programmed with low fuse byte of value 0XE4 and high fuse byte of value 0xC9. The lock fuse bytes were unused as they were not necessary. The code was written in a straight-forward manner. The main function first initializes the required variables, registers and library functions. In the main loop, the RMS value of 512 ADC samples is computed and based on a matching "if" condition, the corresponding lux value is determined and displayed.

#define no_of_samples    512    sbit LCD_RS at PORTB2_bit;  sbit LCD_EN at PORTB3_bit;  sbit LCD_D4 at PORTB4_bit;  sbit LCD_D5 at PORTB5_bit;  sbit LCD_D6 at PORTB6_bit;  sbit LCD_D7 at PORTB7_bit;  sbit LCD_RS_Direction at DDB2_bit;  sbit LCD_EN_Direction at DDB3_bit;  sbit LCD_D4_Direction at DDB4_bit;  sbit LCD_D5_Direction at DDB5_bit;  sbit LCD_D6_Direction at DDB6_bit;  sbit LCD_D7_Direction at DDB7_bit;    static void setup();  unsigned int filter_adc();    void main()  {        unsigned int disp_avg[4];        unsigned int avg=0;        unsigned long lux_value=0;        setup();          do        {                avg=filter_adc();                  if(avg>=0 && avg<=286)                {                          lux_value=0;                }                else if(avg>286 && avg<410)                {                          lux_value=1600;                }                else if(avg>=410 && avg<470)                {                          lux_value=3200;                }                else if(avg>=470 && avg<500)                {                          lux_value=4800;                }                else if(avg>=500 && avg<510)                {                          lux_value=6400;                }                else if(avg>=510 && avg<520)                {                          lux_value=8000;                }                else if(avg>=520 && avg<530)                {                          lux_value=9600;                }                else if(avg>=530 && avg<535)                {                          lux_value=11200;                }                else if(avg>=535 && avg<540)                {                          lux_value=12800;                }                else if(avg>=540 && avg<545)                {                          lux_value=14400;                }                else if(avg>=545 && avg<550)                {                          lux_value=16000;                }                else                {                      Lcd_Out(2,6,"Max Limit!  ");                }                LongToStr(lux_value,disp_avg);                Lcd_Out(2,6,disp_avg);        }while(1);  }    static void setup()  {        PORTB=0x00;        DDRB=0x00;        PORTC=0x00;        DDRC=0x00;        PORTD=0x00;        DDRD=0x00;        TCCR0=0x00;        TCNT0=0x00;        TCCR1A=0x00;        TCCR1B=0x00;        TCNT1H=0x00;        TCNT1L=0x00;        ICR1H=0x00;        ICR1L=0x00;        OCR1AH=0x00;        OCR1AL=0x00;        OCR1BH=0x00;        OCR1BL=0x00;        ASSR=0x00;        TCCR2=0x00;        TCNT2=0x00;        OCR2=0x00;        TIMSK=0x00;        UCSRB=0x00;        ACSR=0x80;        SFIOR=0x00;        ADCSRA=0x00;        SPCR=0x00;        TWCR=0x00;        Lcd_Init();        Lcd_Cmd(_LCD_CLEAR);        Lcd_Cmd(_LCD_CURSOR_OFF);        ADC_Init();        delay_ms(100);        LCD_Out(1, 1, "AVR Lux Meter");        LCD_Out(2, 1, "Lux: ");  }    unsigned int filter_adc()  {           register float adc_value=0;           register unsigned long tmp_value=0;           unsigned int sample=0;             while(sample<no_of_samples)           {                           adc_value=(adc_read(0));                           tmp_value=(tmp_value+((unsigned long)(adc_value*adc_value)));                           delay_us(20);                           sample++;           }             adc_value=(tmp_value/no_of_samples);           tmp_value=(sqrt(adc_value));           return tmp_value;  }

Download complete source code and HEX files

Calibration of LDR output

You must be wondering how did I come up with the numbers inside the "if"checks in the program mentioned above. I calibrated the output of LDR in the multiples of 1600 lux using a reference photometer and a varying source of light. The photometer I used was Model LM631. For a varying light source I used a white filament bulb with an electronic regulator that changes the voltage across the bulb to control the light intensity. The photometer and the LDR are both placed equidistant from the light source. I varied the intensity of light in the step of 1600 lux with the aid of the photometer reading. For each setting I noted the ADC output for the incoming input voltage from the Op-Amp filter stage. Of course I wrote a separate program for this that displayed ADC count on the LCD. Later I implemented those numbers in the main program to convert the ADC counts back to lux.

LuxOP1 Digital light meter with a calibrated LDR
Displaying light intensity in lux

Important note

The purpose of this project was to demonstrate a technique of building a digital lux meter using a simple LDR which was calibrated against a reference photometer. It should be kept in mind that the calibration numbers used in this project are not universal and may not be applied to other LDRs. You have to find out the right numbers for your LDR in the similar way as described here.

SharePinExt Digital light meter with a calibrated LDR tumblr Digital light meter with a calibrated LDR myspace Digital light meter with a calibrated LDR

No related posts.

This posting includes an audio/video/photo media file: Download Now

A Beginner’s data logger project using PIC12F683 microcontroller

Posted: 07 May 2012 02:51 AM PDT

It is a very simple data logger project based on PIC12F683 microcontroller. The microcontroller reads temperature values from a temperature sensor on a regular interval basis and stores them into its internal EEPROM memory. The recorded temperatures can be later transferred to a PC through serial interface. I originally published this project on last summer. I thought this could be a very good learning project for beginners, and so I am posting it here for Embedded Lab's readers too.

TitleImage 550x346 A Beginner's data logger project using PIC12F683 microcontroller
Finished temperature logger powered from a 9V battery



The sensor used in this project is DS18B20. It is a digital temperature sensor manufactured by Dallas Semiconductor (now MAXIM) that can measure temperature ranging from -55°C to +125°C with an accuracy of ±0.5°C over the range of -10°C to +85°C. The sensor provides the measured temperature (°C) output in user-configurable 9, 10, 11, or 12-bit data corresponding to the desired resolution of 0.5, 0.25, 0.125, and 0.0625 °C. The sensor communicates with a host microcontroller over a 1-wire bus. Readers are suggested to refer the datasheet on Maxim's website for details on this sensor. Please keep in mind that there are three versions of this sensors, namely DS1820, DS18S20, and DS18B20, and they have some architectural differences. All of them have the same pin configuration and therefore the circuit diagram would be same for all three types. However, some modification in the software may be required while the microcontroller reads the temperature data from them.

PIC12F683 has 256 bytes of internal EEPROM. Each temperature reading is stored as a byte, which means only the eight most significant bits of DS18B20 output is recorded. Therefore, the temperature resolution is decreased down to 1 °C. This temperature logger can store up to 254 temperature values (254 bytes) in its internal EEPROM. The remaining two EEPROM locations are used to store the sampling time and number of samples information. Three tact switches are used to provide user inputs for controlling the operation of the data logger.

Circuit Diagram

The PIC microcontroller uses its internal clock source operated at 4.0 MHz. The DS18B20 sensor is interfaced to GP0 pin (7) of the microcontroller. An LED connected to the GP2 pin serves as the only display in the circuit to indicate various actions of the data logger. For example, it blinks every time a sample is recorded into EEPROM. The circuit is powered with +5 V derived from a 9V battery using an LM78L05 regulator IC. The LM78L05 circuit is a very common circuit and therefore, it is not shown here.

DataLoggerPIC12F683 550x3642 A Beginner's data logger project using PIC12F683 microcontroller Circuit diagram of data logger

The three tact switches provide the following functions.

  • Start: Starts data logging
  • Stop: Stops the logging procedure
  • Send/Reset: Transfers data to PC through serial port. However, if it is held pressed for 2 sec or more, the EEPROM locations are cleared and ready for new recordings.

Selection of sampling time

This data logger offers three options for sampling interval: 1 sec, 1min, and 10 min. The selection is made through the same three tact switches. Here is how it works. Suppose if 10 min sampling time is needed, then first turn OFF the power, hold the 'Send/Reset' button pressed, turn the power ON, and wait till the LED glows. Once the LED glows, release the button, and the sampling interval is set to 10 min. The new sampling time will be updated to EEPROM location 0 so that in case of power failure, the previous sampling time will be restored. Similarly, the use of 'Start' or 'Stop' button instead of the Send/Reset one sets the sampling time to  1 sec, or 1 min respectively. With 10 min sampling interval, this data logger can record temperature samples over 42 hours.

Serial Interface to PC

Transferring data to PC through serial port requires a voltage translation circuit to convert the TTL logic levels from PIC12F683 to appropriate RS232 voltage levels. A regular PNP transistor with few other passive components can do this job. The RS232 standard uses a -3 to -12 V for Logic 1 and +3 to +12 V for Logic 0. The required negative voltage is stolen from the TX pin of the RS232 port on PC's side which is unused as there won't be any data transfer from the PC to PIC12F683. Under idle condition the TX pin on PC's side is held high (-12 V). The two figures below describe the operation of converting TTL levels for 1 and 0 to corresponding RS232 levels. The positive terminal of the 10 uF capacitor is grounded because its negative terminal has to deal with a more negative voltage.

TTL0toRS2320 550x3643 A Beginner's data logger project using PIC12F683 microcontroller Translating TTL Logic 1 level to RS232 Logic 1 level
TTL1toRS2321 550x3623 A Beginner's data logger project using PIC12F683 microcontroller
Translating TTL Logic 0 level to RS232 Logic 0 level
FinishedProject 550x361 A Beginner's data logger project using PIC12F683 microcontroller
Finished project board


The firmware for PIC12F683 is developed in C using mikroC Pro for PIC compiler from mikroElektronika. PIC12F683 doesn't have built-in hardware UART module for serial communication but the mikroC compiler has built-in library routines to implement software UART through any digital I/O pin of PIC microcontroller. Due to wide use of DS18B20 sensor for temperature measurements, mikroC also provides 1-wire library routines for controlling the operation of this sensor. The built-in functions for communicating with a 1-wire sensor are,

  • Ow_Reset is used for reseting sensor;
  • Ow_Read is used for receiving data from sensor; and
  • Ow_Write is used for sending commands to sensor.

MikroC also provides EEPROM library for read and write operations to internal EEPROM locations. The overall programming is made much easier with the help of these built-in library functions of mikroC. The source code with HEX files can be downloaded from the links below.

MikroC project for ds18b20 sensor

MirkoC project for ds1820 sensor

The configuration bits setup for PIC12F683 can be done through Edit Project window in mikroC. The figure below shows the required settings for this project.

ProjectSetting 550x266 A Beginner's data logger project using PIC12F683 microcontroller

Programming sequence

When the circuit is powered on, the LED blinks for 3 times that shows the data logger is turned on and being initiated. The program checks for any key pressed for setting sampling interval. If yes, it identifies the key and store the appropriate sampling interval information to EEPROM location 0. The LED is turned on to indicate that the sampling interval has been set and it's time to release the pressed key. The program is now inside the main loop. The three switches (Start, Stop and Send/Reset) operate in Interrupt-on-change mode, which means, any time the button is pressed, an interrupt is generated. Pressing the Start button begins data recording. Each time a temperature sample is recorded in to the EEPROM, the LED blinks to indicate that the logging process is going on. Pressing the Stop button will interrupt this process, while Send will initiate the serial transfer of recorded samples through GP1 pin (6). If the Send button is pressed for more than 2 sec, the entire EEPROM locations will be cleared.

On PC's side, the hyperterminal program is used to receive logged temperature data from PIC12F683. The rate of data transfer is set to 9600 baud on both end. The figure below shows the hyperterminal settings for this project.

HyperTerminalSetting A Beginner's data logger project using PIC12F683 microcontroller Hyperterminal settings on PC
RS232Connection 550x393 A Beginner's data logger project using PIC12F683 microcontroller
Connecting to PC’s serial port
HyperTerminal A Beginner's data logger project using PIC12F683 microcontroller
Data received by the hyperterminal program

Conclusion and future work

A simple data logger project was demonstrated using a PIC12F683 micrcontroller and DS18B20 temperature sensor. A number of improvements can be done with this project, such as adding an external EEPROM for expanding its recording capacity. A separate application program can be developed on PC's side to receive the serial data from the logger and generate temperature vs time plots. A real time clock chip can also be added in the project to keep record of the actual time stamp. A bigger PIC with more I/O pins would be more appropriate for implementing these additional features.

SharePinExt A Beginner's data logger project using PIC12F683 microcontroller tumblr A Beginner's data logger project using PIC12F683 microcontroller myspace A Beginner's data logger project using PIC12F683 microcontroller

Related posts:

  1. A Digital temperature meter using an LM35 temperature sensor

This posting includes an audio/video/photo media file: Download Now

Digital logic probe for troubleshooting TTL and CMOS circuits

Posted: 07 May 2012 02:32 AM PDT

A logic probe is considered as a stethoscope for engineers and technicians for debugging digital logic circuits that consists of logic gates, memories, registers, etc. A digital multimeter (DVM) can also be used for such analytical purposes but it gives you the numeric value of the voltage at a point instead of the logic state. Depending on whether the circuit is based on TTL or CMOS components, the voltage levels for logic 0 and 1 could be different for each family. DVM users, thus, have to calculate logic levels from the measured voltages, which consumes time and delays the troubleshooting procedure. A logic probe, on the other hand, does all these functions automatically and shows meaningful logic states at test points. In this project, we will discuss about making a digital logic probe that is applicable to both TTL and CMOS circuits and uses minimal components.

LogicProbeTitle Digital logic probe for troubleshooting TTL and CMOS circuits
Logic probe for CMOS and TTL circuits



There are mainly two logic families used in digital circuits: TTL and CMOS. While TTL operates at +5V, the power supply for CMOS circuits could range from +3V to 15V. According to the standard TTL convention, any voltage less than 0.8V is defined as logic low while any voltage above 2.2 is defined as logic high and anything in between these extremes is defined as intermediate state. In case of CMOS circuits, any voltage less than 1/3 of VDD is defined as logic low while any voltage above 2/3 of VDD is defined as logic high. Any voltage between these values is defined as intermediate or transitional state. This logic probe works for both TTL and CMOS circuits powered from +5V to 15V.

This logic probe consists of a 78L05 voltage regulator, a Microchip PIC12F683 microcontroller, a CD4094BE CMOS shift register and a tiny seven segment display. Since the operating voltage range of this logic probe is between 5 to 15V, the role of the 78L05 voltage regulator is to ensure that the microcontroller and the rest of the circuit are always powered with a stable 5V source. There are two voltage divider networks, each made from a 9.1K  and a 1K Ohms (1% tolerance) resistors. The outputs of the two networks go to the ADC channels AN0 and AN1. The AN0 channel reads the logic level voltage of the test pin whereas the AN1 channel is used to measure the supply voltage of the test circuit. The information of the supply voltage is necessary to identify a CMOS circuit powered with > 5V. The GP2, GP4, and GP5 pins of PIC12F683 drives the CD4094 shift register. The shift register acts as an I/O expander in this application and its outputs are connected to a seven segment display.

circuit 550x387 Digital logic probe for troubleshooting TTL and CMOS circuits
Circuit diagram of the logic probe (click on image to enlarge)

Note: In the above circuit, pins 8 and 16 of CD4094 should be connected to ground and Vcc, respectively.

SetUpLogicProbe Digital logic probe for troubleshooting TTL and CMOS circuits
Logic probe circuit setup on a breadboard


The software for this project is written in MikroC PRO for PIC version 5.30. Only the ADC built-in library is used. The rest of the code is written without any library aid. The code starts with the definitions of pin names and common variable declarations. Apart from the main function which does all the tasks, there are six functions in the code. The setup() function sets directions of I/O pins and initiates the built-in ADC for data acquisition. The test_display() function tests the LEDs of the seven segment display connected to the shift register. The way this is done with the shift register will be discussed later in this text. The feature that makes this logic probe universal and unique is its ability to determine the supply voltage level. In the function test_supply(), the power source is tested. During this test if it is found that the ADC average of supply voltage is within the span of 4.75V to 5.25V then the standard TTL minimum high and maximum low logic level voltages are set, otherwise conventional CMOS logic level voltage values are set. These values are kept in the variables called high_level and low_level and are retained till power down. The display(unsigned char val) function is a software-hardware link between the shift register and the micro. It converts any 8 bit value given to the variable val in a way that it can be sent as an output just like a regular I/O port. The strobe pin is at first kept low to allow the access of the internal latches of the CD4094. Eight clock pulses are needed to shift data into the latches. During each clock pulse to the shift register, the variable val's most significant bit (MSB) is read first and is sent as a data to the data input of the shift register. After sending data to the data pin, val is left shifted once and the clock pin is also toggled once. At the end of eight cycles the strobe pin is pulled high and the display is updated. The adc_avg(unsigned char ch) function read the designated ADC channel by taking 16 samples of ADC data and converting these samples into an average voltage value. Lastly the check_logic() function checks the logic input and sends logic symbol data to the seven segment display.

/Definition of shift register pin names//  #define     data_pin        GP5_bit  #define     clock_pin       GP4_bit  #define     strobe_pin      GP2_bit    //Definition of global variables//  float high_level = 0.0;           //minimum logic high voltage value storage  float low_level = 0.0;            //maximum logic low voltage value storage  const unsigned short disp [4] =  {0x38, 0x3E, 0x76, 0x00};         //Symbols for display - L, U, H and blank    //Function prototypes//  static void setup(void);  static void test_display(void);  static void test_supply(void);  void display(unsigned char val);  float adc_avg(unsigned char ch);  void check_logic(void);    void main(void)  {      setup();           //Setup the micro for operation      test_supply();     //Check supply voltage and choose convention      test_display();    //Check display      for(;;)             //Infinite loop      {              check_logic();   //Test logic level at logic input terminal      }  }    static void setup(void)  {       //Set directions and initial states of I/O pins//       TRISIO5_bit = 0;       TRISIO4_bit = 0;       TRISIO3_bit = 1;       TRISIO2_bit = 0;       TRISIO1_bit= 1;       TRISIO0_bit = 1;       data_pin = 0;       strobe_pin = 0;       clock_pin = 0;       adc_init();          //Initiate internal ADC module       delay_ms(100);       //Wait of some time  }    static void test_display(void)  {       unsigned short test = 0;       while(test<3)                       //Test seven segment display       {                    display(disp[test]);   //Put called symbol on display                    delay_ms(400);         //Wait for some time                    test++;                //Continue test       }       display(disp[3]);                   //Turn off display       delay_ms(300);                      // Wait for some time  }    static void test_supply(void)  {       register float supply = 0;       supply = adc_avg(1);                //Take the average of supply voltage       delay_ms(150);                      //Wait for some time       if(((supply >= 4.75) && (supply <= 5.25)))   //TTL convention test       {                       high_level = 2.2;                       low_level = 0.8;       }                                            //CMOS convention test       else       {                       high_level = (supply*0.67);                       low_level = (supply*0.33);       }                                            //Wait for a while       delay_ms(50);  }    void display(unsigned char val)  {      unsigned short clk = 0;      unsigned short d = 0;      strobe_pin = 0;                               //Hold strobe pin low      for(clk = 0; clk < 8; clk++)                  //Do following job eight times      {          d = (0x80 & val);                         //Read the MSB of val          if(d == 0)                                //If the MSB is zero          {               data_pin = 0;                        //then send 0          }          else                                      //otherwise send 1          {               data_pin = 1;          }          clock_pin = 1;                            //Pull clock pin high          delay_ms(1);                              //Wait for a while          val = val << 1;                           //Left shift val          clock_pin = 0;                            //Hold clock pin low          delay_ms(1);                              //Wait for a while      }      strobe_pin = 1;                               //Pull strobe pin high      delay_ms(1);                                  //Wait for a while  }    float adc_avg(unsigned char ch)  {           register unsigned int temp = 0;           unsigned short samples = 0;           register float avg = 0;           delay_ms(1);           for(samples = 1; samples <= 16; samples += 1)   //Take 16 ADC samples           {                           temp = adc_read(ch);            //Read assigned ADC                           temp += temp;                   //channel data and                           delay_us(25);                   //store temporarily           }           avg = (temp * 5.0);                            //Convert to readable           avg /= 1023.0;                                 //value other than count           avg *= 10.0;                                   //Take voltage divider           avg /= 16.0;                                   //and number of samples           return avg;                                    //into account  }    void check_logic(void)  {          register float vin = 0;          vin = adc_avg(0);                   //Read logic input channel          delay_ms(20);                       //Wait for some time          if(vin >= high_level)               //Check if it is high          {              display(disp[2]);               //Send 'H' to display          }          else if(vin <= low_level)           //Check if it is low          {              display(disp[0]);               //Send 'L' to display          }          else                                //Otherwise it is undefined          {              display(disp[1]);               //Toggle and send 'U' to display              delay_ms(400);              display(disp[3]);              delay_ms(400);          }  }

Download source and HEX files


The logic probe discussed here is very simple to operate. It should be powered by the power supply of any circuit which it will test. After power up and initial tests, it is ready for normal use. To check logic level at any point, the logic input terminal is just held at a point and the device reads the logic level at that point. It will show H, U or L which mean logic High, Undefined or intermediate or logic Low.

LogicProbeOP Digital logic probe for troubleshooting TTL and CMOS circuits
Logic probe displays H, L and U for logic states High, Low and Undefined, respectively


In this project not only a logic probe is designed but it was also discussed how to expand outputs of a small micro with an inexpensive shift register. Thus the maximum utility of a small micro is achieved. I/O ports can also be expanded with multiplexer, parallel-input-serial-output (PISO) registers, decoders, encoders and universal shift registers as well as dedicated port expanders like MCP23008, 8255, etc. The seven segment display could also have been driven using several diodes but this technique required a large number of diodes.

Note: The datasheet of 78L05 regulator recommends that the input voltage should be greater than 7V to achieve a regulated +5V output. In our application, when the test circuit is a standard TTL, the supply voltage is only 5V, and as such the output of 78L05 is slightly less than 5V. This introduces some error in ADC calculations which is significantly less compared to the band difference between logic HIGH and LOW, and therefore doesn't affect the operation of the logic probe. The logic probe circuit discussed here was tested in real life under various conditions and results were satisfactory for both TTL and CMOS circuits. I designed this project in a bread board as it was my prototype. A PCB or strip board version of it would have been much smaller than what is shown here.

SharePinExt Digital logic probe for troubleshooting TTL and CMOS circuits tumblr Digital logic probe for troubleshooting TTL and CMOS circuits myspace Digital logic probe for troubleshooting TTL and CMOS circuits

No related posts.

This posting includes an audio/video/photo media file: Download Now