历史上的今天
返回首页

历史上的今天

今天是:2025年01月29日(星期三)

2020年01月29日 | PIC单片机与AM2302温湿度传感器通信优化

2020-01-29 来源:eefocus

AM2302温湿度传感器采用单总线方式与MCU通信,这就要求MCU有一定的处理速度, 才能正确解析收到的AM2302发送过来的数据。


MCU处理AM2302数据的方式

AM2302一次传送40位数据给MCU。数据位0由50微妙低电平加26微妙高电平组成。 

数据位1有50微妙低电平加70微妙高电平组成。这种编码方式有点象NEC的红外传输协议。


另外AM2302需要由MCU发起启动信号。所以针对这种单线协议,虽然可以采用电平变化中断+计数器,或输入捕捉来解析40位数据位。但这就需要切换端口的输入输出配置及控制相应外设的介入时机。


本文介绍的方法采用简单的端口读+延时操作来解析40位数据位。


    if (data_port == 1)

        delay_us(30);

    if (data_port == 1)

        //bit = 1

    else

        //bit = 0


起始信号通过把端口改为输出,然后通过写端口+延时来实现。


    //改变data_port为输出

    data_port = 0;

    delay_us(1000);

    data_port = 1;

    delay_us(20);

    //改变data_port为输入


数据读取函数实现

根据上述协议的描述,很容易抽象出如下函数:


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;

}


通过调用am2302_read_byte() 5次,把40位数据读取出来。


    humidity_hign = am2302_read_byte();

    humidity_low = am2302_read_byte();

    temperature_high = am2302_read_byte();

    temperature_low = am2302_read_byte();

    checksum = am2302_read_byte();


为什么上面的函数不能使用了

在某些应用场景下,为了降低功耗,需要把MCU的工作频率降到尽可能的低。 

如果在系统时钟很低的情况,指令周期就成为需要考虑的关键因素。


这里拿PIC单片机举例,如果系统时钟为1M Hz,则它的指令周期为4微妙, 

(指令周期为系统时钟的4倍)。 

这个时候如果使用上面提到的函数调用的方法,将无法得到正确的数据。 

因为加上函数调用的开销,当am2302_read_byte()进行电平判断的时候, 

很可能已经错过了起始电平,导致解析不正确。另外当判断是数据位1的时候,


    data += (0x80U >> i);

    while (1 == data_port)

    {

    }


理论上上面的操作要在40~50微妙的时间内完成,大概是10~12个汇编指令。 

但目前上面的操作会转换成很多汇编指令,耗费过多的时间,导致后续数据位解析不正确。


解决方案

简单的方案,继续使用上面的函数,但需要在调用之前提高系统时钟,缩短指令周期即可。 

但对功耗上有些许影响,但基本影响不会太大。这里比较要命的是你提高了系统之中,依赖 系统时钟的外设都要重新设置,例如定时器。当完成温湿度的读取,又要全部切换回来。


考验功力的方案,有没有可能优化上面的数据读取函数,减少生成的汇编指令,使它能够 

在1 MHz的系统时钟下,完成数据读取?

如何改进利用空间换时间的思路,取消函数调用,把里面的逻辑展开。这里可以利用宏函数实现。


#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)


优化数据位1的实现逻辑,把移位操作转换成定值的赋值操作。

#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)

                            {

                            }

                        }

                    }


但在实际的调试过程中,发现有时候还是无法完整的解析数据。特别是当数据位1特别多的 时候,往往不能够正确解析。这时候就需要仔细的分析数据位1的生成汇编代码。

    movlb   0   ; select bank0

    btfss   12,0    ;volatile //对I/O进行判断,相当于if (1 == am2302_data_PORT)

    goto    l435    //I/O不是1,跳转到下一个数据位判断逻辑

    movlw   128     //I/O是1,对数据进行加1操作,这里使用了两条指令

    addwf   _g_th,f

l435:   


使用|=替换+=,把两条指令的加1操作变成一条指令。

    if (1 == am2302_data_PORT)

    {

        data |= bitmask;

        while (1 == am2302_data_PORT)

        {

        }

    }


它生成的汇编代码变成:


    movlb   0   ; select bank0

    btfss   12,0    ;volatile

    goto    l435

    bsf _g_th,7

l435:


结束

使用上述方案,可以使PIC单片机在1 MHz的系统时钟下,与AM2302进行单线通信。

推荐阅读

史海拾趣

ERP公司的发展小趣事

面对不断变化的市场环境和客户需求,电子智链始终保持创新和进取的精神。公司不断投入研发资源,推出新的ERP产品和解决方案,以满足客户日益增长的需求。同时,电子智链也积极应对来自国内外竞争对手的挑战,通过不断提高产品质量和服务水平来巩固自身的市场地位。在未来的发展中,电子智链将继续秉持“客户至上、创新驱动”的理念,致力于为电子企业提供更加先进、高效和可靠的ERP解决方案。

Anaren公司的发展小趣事

为了进一步拓展市场和提高竞争力,电子智链开始寻求与其他企业建立生态合作关系。公司与多家电子制造设备供应商、原材料供应商和物流服务商建立了战略合作关系,共同打造了一个覆盖电子产业全链条的生态圈。这一合作模式不仅为客户提供了更加全面和高效的解决方案,还促进了整个电子产业的协同发展。

American Electric公司的发展小趣事

American Electric公司成立于XXXX年,起初只是一个小型电力供应商,为当地提供电力服务。然而,凭借着对电力行业的深刻理解和对市场需求的敏锐洞察,公司创始人决定扩大业务范围,逐步涉足发电、输电和配电等多个领域。通过不懈的努力和创新,American Electric公司逐渐在电力行业中崭露头角,成为一家备受瞩目的企业。

CEVA, Inc公司的发展小趣事

CEVA公司在超低功耗技术方面取得了显著突破。公司开发的超低功耗IP包括由专用DSP与AI和其他类型的加速器组成的综合平台。这些加速器针对低功耗工作负载进行了优化,包括5G基带处理、智能视觉、语音识别、物理层处理和传感器融合等。这些技术的突破使得CEVA的产品在保持高性能的同时,能够大幅度降低功耗,满足了市场对节能设备的需求。

Cogent_Computer_Systems公司的发展小趣事

在电子行业的发展过程中,Cogent_Computer_Systems公司深知合作共赢的重要性。公司积极与上下游企业建立紧密的合作关系,共同推动产业升级。通过与供应商的深度合作,公司确保了原材料的稳定供应和质量保障;同时,与客户的紧密沟通也帮助公司更好地把握市场需求,推出更符合消费者期望的产品。这种合作共赢的模式不仅提升了公司的竞争力,也为整个电子行业的发展注入了新的活力。

ECLIPSE公司的发展小趣事

随着Eclipse项目的不断发展,越来越多的知名公司加入到这一开源社区中,如Oracle、Red Hat等。这些公司不仅为Eclipse贡献了代码,还提供了资金支持。Eclipse的功能日益完善,逐渐成为了Java开发领域的佼佼者。同时,Eclipse也支持其他编程语言,如C/C++、Python等,进一步扩大了其用户群体。

问答坊 | AI 解惑

生动形象的教学用电子钟[ZT]

生动形象的教学用电子钟[ZT] 笔者在教学中,设计了一套教学实验用“电子钟”电路。此线路包括七段数码显示器BS205和循环彩灯电路,实验显示生动有趣,各部分原理简单,适宜学生直接观察“编码器”、“译码器”、“寄存器”、“计数器”等逻辑 ...…

查看全部问答>

WRITE_PORT_UCHAR()函数会造成蓝屏重启动?

我在驱动程序中加入下面蓝色代码会造成系统蓝屏重启,请问是什么原因呢?是不能直接调用WRITE_PORT_UCHAR这个函数吗?? NTSTATUS WinIoDispatch(IN PDEVICE_OBJECT DeviceObject,               & ...…

查看全部问答>

为什么我的模拟器不能够连接到网络上?

我用的是windows mobile professional模拟器,现在不能连接到网络上(也就是在模拟器上打不开网页),总是提示:无法连接,请确拨号或代理服务器设置是否正确,然后重试),之前还可以,今天公司给我换了个ip就不行了,我把能试的方法都试遍了,还 ...…

查看全部问答>

新手提问:如何同时安装C51 和 MDK

我现在安装了MDK3.22a,但是编译不了C51程序,还要安装什么呀…

查看全部问答>

求教win32工程如何在界面初始化时就调用一个界面。

小弟正学习mobile手机开发, 现在建立一个win32工程, 默认情况下运行程序模拟器上是一个白屏, 现在想一运行就调用自己的一个ID为dialog_main的对话框, 假设他的窗口过程叫MainPro(),请高手指教改在那里修改代码, 望各位能详细指点,很 ...…

查看全部问答>

stm32低功耗管理复位问题,请教~~

下载 (108.1 KB) 2011-1-19 15:42 我现在在做微功耗,用的是待机模式,我在看微功耗的待机模式的启动项中,有个启动方式是IWDG,但是这中启动方式我没有办法跟踪,我在手册中看到可以检测复位标记来判断是什么方式复位 ...…

查看全部问答>

【求助】中断编译不能通过!!

#include<msp430x44x.h> interrupt[TIMERA0_VECTOR] void Timer_A(void) { ~~~ } void InitSystem(void) { ~~~ //TIME_A TACTL=ID1+TASSEL1+TACLR+ ...…

查看全部问答>

比较器

有那位高手可以推荐高速比较器的电路,急!!!!…

查看全部问答>

搞到一个4轴,论坛里的大神说用C2000控制是怎么回事

朋友搞了三个月还没飞起来,给我研究, 什么陀螺仪,加速度,姿态控制啊没头绪啊…

查看全部问答>

【“解BUG”活动】最近在玩LED灯,看到430板子上有三色灯,请教恒压PWM调流

问题描述:最近在玩LED灯,看到430板子上有三色灯,请教恒压PWM调流,因为想利用三色灯变换出很多颜色,只能使用调流电路,目前只懂调压,请高手指导,调流就可以得到很多种颜色,在网上搜了很久,无果。望大神支援 问题范围:LED调流电路…

查看全部问答>