Optimization of communication between PIC microcontroller and AM2302 temperature and humidity sensor

Publisher:innovation2Latest update time:2020-01-29 Source: eefocus Reading articles on mobile phones Scan QR code
Read articles on your mobile phone anytime, anywhere

The AM2302 temperature and humidity sensor uses a single bus to communicate with the MCU, which requires the MCU to have a certain processing speed in order to correctly parse the data sent by the AM2302.


How MCU processes AM2302 data

AM2302 transmits 40 bits of data to MCU at a time. Data bit 0 is composed of 50 microseconds of low level plus 26 microseconds of high level. 

Data bit 1 consists of 50 microseconds of low level plus 70 microseconds of high level. This encoding method is a bit like NEC's infrared transmission protocol.


In addition, AM2302 needs to be started by the MCU. Therefore, for this single-wire protocol, although level change interrupt + counter or input capture can be used to parse 40 data bits, this requires switching the input and output configuration of the port and controlling the intervention timing of the corresponding peripherals.


The method introduced in this article uses a simple port read + delay operation to parse 40 bits of data.


    if (data_port == 1)

        delay_us(30);

    if (data_port == 1)

        //bit = 1

    else

        //bit = 0


The start signal is achieved by changing the port to output and then writing the port + delay.


    //Change data_port to output

    data_port = 0;

    delay_us(1000);

    data_port = 1;

    delay_us(20);

    //Change data_port to input


Data reading function implementation

According to the description of the above protocol, it is easy to abstract the following functions:


static unsigned char am2302_read_byte(void)

{

    unsigned char i = 0;

    unsigned char data = 0;


    for (i = 0; i < 8; i++)

    {

        //50us low

        while (0 == data_port)

        {

        }

        delay_us(40);

        if (0 == data_port)

        {

            continue;

        }

        else

        {

            data += (0x80U >> i);

            while (1 == data_port)

            {

            }

        }

    }

    return data;

}


By calling am2302_read_byte() 5 times, 40 bits of data are read out.


    humidity_hign = am2302_read_byte();

    humidity_low = am2302_read_byte();

    temperature_high = am2302_read_byte();

    temperature_low = am2302_read_byte();

    checksum = am2302_read_byte();


Why can't the above function be used?

In some application scenarios, in order to reduce power consumption, the operating frequency of the MCU needs to be reduced to the lowest possible level. 

If the system clock is very low, the instruction cycle becomes a key factor to be considered.


Here we take the PIC microcontroller as an example. If the system clock is 1 MHz, its instruction cycle is 4 microseconds. 

(The instruction cycle is 4 times of the system clock). 

At this time, if you use the function calling method mentioned above, you will not be able to get the correct data. 

Because of the function call overhead, when am2302_read_byte() performs level judgment, 

It is very likely that the start level has been missed, resulting in incorrect parsing. In addition, when it is judged that the data bit is 1,


    data += (0x80U >> i);

    while (1 == data_port)

    {

    }


Theoretically, the above operation should be completed in 40 to 50 microseconds, which is about 10 to 12 assembly instructions. 

However, the above operations will currently be converted into many assembly instructions, which consumes too much time and causes incorrect parsing of subsequent data bits.


solution

A simple solution is to continue using the above function, but increase the system clock before calling it to shorten the instruction cycle. 

It has some impact on power consumption, but the impact is not too big. The more fatal thing here is that when you improve the system, all peripherals that rely on the system clock, such as timers, need to be reset. When the temperature and humidity readings are completed, all have to be switched back.


Is it possible to optimize the above data reading function and reduce the generated assembly instructions so that it can 

At 1 MHz system clock, data reading is completed?

How to improve the idea of ​​using space to exchange time, cancel the function call, and expand the logic inside. This can be achieved using macro functions.


#define am2302_read_byte(data) 

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)

                am2302_read_bit(data)


Optimize the implementation logic of data bit 1 and convert the shift operation into a fixed value assignment operation.

#define am2302_read_byte(data) 

                am2302_read_bit(data, 0x80)

                am2302_read_bit(data, 0x40)

                am2302_read_bit(data, 0x20)

                am2302_read_bit(data, 0x10)

                am2302_read_bit(data, 0x08)

                am2302_read_bit(data, 0x04)

                am2302_read_bit(data, 0x02)

                am2302_read_bit(data, 0x01)


#define am2302_read_bit(data, bitmask)   

                    while (0 == am2302_data_PORT)

                    {

                    }

                    __delay_us(26);

                    if (1 == am2302_data_PORT)

                    {

                        NOP();

                        NOP();

                        if (1 == am2302_data_PORT)

                        {

                            data += bitmask;

                            while (1 == am2302_data_PORT)

                            {

                            }

                        }

                    }


However, in the actual debugging process, it is found that sometimes the data cannot be completely parsed. Especially when there are a lot of data bits 1, it is often not possible to parse correctly. At this time, it is necessary to carefully analyze the generated assembly code of data bit 1.

    movlb 0 ; select bank0

    btfss 12,0 ;volatile //Judge I/O, equivalent to if (1 == am2302_data_PORT)

    goto l435 //I/O is not 1, jump to the next data bit judgment logic

    movlw 128 //I/O is 1, add 1 to the data, two instructions are used here

    addwf _g_th,f

l435:   


Use |= to replace += and turn the addition operation of two instructions into one instruction.

    if (1 == am2302_data_PORT)

    {

        data |= bitmask;

        while (1 == am2302_data_PORT)

        {

        }

    }


The assembly code it generates becomes:


    movlb 0 ; select bank0

    btfss 12,0 ;volatile

    goto l435

    bsf _g_th,7

l435:


Finish

Using the above solution, the PIC microcontroller can communicate with the AM2302 in a single-line manner at a system clock of 1 MHz.

Reference address:Optimization of communication between PIC microcontroller and AM2302 temperature and humidity sensor

Previous article:How to connect a rotary encoder using a PIC microcontroller
Next article:Analysis of single chip computer key scanning program, display program and delay program

Latest Microcontroller Articles
Change More Related Popular Components

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
circle

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号