您当前的位置: 首页 > 

不脱发的程序猿

暂无认证

  • 1浏览

    0关注

    492博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

全网仅此一篇:工业级压力传感器设计及实现(华大半导体HC32L136)

不脱发的程序猿 发布时间:2020-03-10 14:41:11 ,浏览量:1

目录

1、项目概述

2、模组简介

2.1、NSA2862物联网专用桥式传感器调理芯片

2.2、Metallux ME501/ME505陶瓷压力传感器

3、驱动原理

4、项目实现

近期基于Metallux ME501/ME505陶瓷压力传感器模组和NSA2862物联网调理芯片设计一款工业级压力传感器,并使用华大半导体HC32L136 MCU实现控制,特将项目心得与体会分享给各位朋友,目前全网仅此一篇,请多多支持~

1、项目概述

本项目传感器基于Metallux ME501/ME505陶瓷压力传感器模组和纳芯微NSA2862物联网调理芯片,微控制器基于华大半导体HC32L136,在保证高性能的前提下,支持待机与休眠唤醒,具备超低的功耗,可连续工作10年而无需更换电池,可大规模应用在智慧城市、工业物联网等领域。

项目的测量、校准、评估和设计这里参照于纳芯微电子传感器解决方案实现,没办法,工业级传感器设计就是烧钱啊。

2、模组简介 2.1、NSA2862物联网专用桥式传感器调理芯片

NSA2862是一颗专门针对物联网应用推出的用于阻式或者电压型传感器,例如阻式压力传感器,热电偶,RTD等传感器的超低功耗信号调理专用芯片。NSA2862集成了24位主信号测量通道和24位辅助温度测量通道,传感器校准逻辑,双路恒流源等电路,支持I2C、SPI或者OWI输出。通过内置的MCU,NSA2862支持对传感器的零点,灵敏度的二阶温度漂移校准以及最高三阶的非线性校准,校准精度可以达到0.1%以内,其校准系数存储于一组EEPROM中,芯片结构如下所示:

参数特性所示所示:

  • 超低待机功耗:输出 stcGpioCfg.enOD = GpioOdEnable; ///< 开漏输出 stcGpioCfg.enPu = GpioPuEnable; ///< 端口上拉配置->使能 stcGpioCfg.enPd = GpioPdDisable; ///< 端口下拉配置->禁止 Gpio_Init(GpioPortB,GpioPin8,&stcGpioCfg); ///< 端口初始化 Gpio_Init(GpioPortB,GpioPin9,&stcGpioCfg); Gpio_SetAfMode(GpioPortB,GpioPin8,GpioAf1); ///< 配置PB08为SCL Gpio_SetAfMode(GpioPortB,GpioPin9,GpioAf1); ///< 配置PB09为SDA }

    I2C配置代码如下所示:

    ///< I2C 模块配置
    void App_I2cCfg(void)
    {
        stc_i2c_cfg_t stcI2cCfg;
        
        DDL_ZERO_STRUCT(stcI2cCfg);                            ///< 初始化结构体变量的值为0
        
        Sysctrl_SetPeripheralGate(SysctrlPeripheralI2c0,TRUE); ///< 开启I2C0时钟门控
        
        stcI2cCfg.u32Pclk = Sysctrl_GetPClkFreq();             ///< 获取PCLK时钟
        stcI2cCfg.u32Baud = 100000;                            ///< 100K
        stcI2cCfg.enMode = I2cMasterMode;                      ///< 主机模式
        stcI2cCfg.bGc = FALSE;                                 ///< 广播地址应答使能关闭
        I2C_Init(M0P_I2C0,&stcI2cCfg);                         ///< 模块初始化
    }

     第3步:编写接收驱动函数,主机接收状态图如下所示:

    接收驱动代码如下所示: 

    /**
     ******************************************************************************
     ** \brief  主机接收函数
     **
     ** \param u8Addr从机内存地址,pu8Data读数据存放缓存,u32Len读数据长度
     **
     ** \retval 读数据是否成功
     **
     ******************************************************************************/
     en_result_t I2C_MasterReadData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
    {
        en_result_t enRet = Error;
        uint8_t u8i=0,u8State;
        
        I2C_SetFunc(I2CX,I2cStart_En);
        
        while(1)
        {
            while(0 == I2C_GetIrq(I2CX))
            {}
            u8State = I2C_GetState(I2CX);
            switch(u8State)
            {
                case 0x08:                                 ///< 已发送起始条件,将发送SLA+W
                    I2C_ClearFunc(I2CX,I2cStart_En);
                    I2C_WriteByte(I2CX,I2C_SLAVEADDR);
                    break;
                case 0x18:                                 ///< 已发送SLA+W,并接收到ACK
                    I2C_WriteByte(I2CX,u8Addr);            ///< 发送从机内存地址
                    break;
                case 0x28:                                 ///< 已发送数据,接收到ACK, 此处是已发送从机内存地址u8Addr并接收到ACK
                    I2C_SetFunc(I2CX,I2cStart_En);         ///< 发送重复起始条件
                    break;
                case 0x10:                                 ///< 已发送重复起始条件
                    I2C_ClearFunc(I2CX,I2cStart_En);
                    I2C_WriteByte(I2CX,I2C_SLAVEADDR|0x01);///< 发送SLA+R,开始从从机读取数据
                    break;
                case 0x40:                                 ///< 已发送SLA+R,并接收到ACK
                    if(u32Len>1)
                    {
                        I2C_SetFunc(I2CX,I2cAck_En);       ///< 使能主机应答功能
                    }
                    break;
                case 0x50:                                 ///< 已接收数据字节,并已返回ACK信号
                    pu8Data[u8i++] = I2C_ReadByte(I2CX);
                    if(u8i==u32Len-1)
                    {
                        I2C_ClearFunc(I2CX,I2cAck_En);     ///< 已接收到倒数第二个字节,关闭ACK应答功能
                    }
                    break;
                case 0x58:                                 ///< 已接收到最后一个数据,NACK已返回
                    pu8Data[u8i++] = I2C_ReadByte(I2CX);
                    I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
                    break;
                case 0x38:                                 ///< 在发送地址或数据时,仲裁丢失
                    I2C_SetFunc(I2CX,I2cStart_En);         ///< 当总线空闲时发起起始条件
                    break;
                case 0x48:                                 ///< 发送SLA+R后,收到一个NACK
                    I2C_SetFunc(I2CX,I2cStop_En);          ///< 发送停止条件
                    I2C_SetFunc(I2CX,I2cStart_En);         ///< 发送起始条件
                    break;
                default:
                    I2C_SetFunc(I2CX,I2cStart_En);         ///< 其他错误状态,重新发送起始条件
                    break;
            }
            I2C_ClearIrq(I2CX);                            ///< 清除中断状态标志位
            if(u8i==u32Len)                                ///< 数据全部读取完成,跳出while循环
            {
                    break;
            }
        }
        enRet = Ok;
        return enRet;
    }

     第4步:编写发送驱动函数,主机发送状态图如下所示: 

    发送驱动代码如下所示:  

    /**
     ******************************************************************************
     ** \brief  主机发送函数
     **
     ** \param u8Addr从机内存地址,pu8Data写数据,u32Len写数据长度
     **
     ** \retval 写数据是否成功
     **
     ******************************************************************************/
    en_result_t I2C_MasterWriteData(M0P_I2C_TypeDef* I2CX,uint8_t u8Addr,uint8_t *pu8Data,uint32_t u32Len)
    {
        en_result_t enRet = Error;
        uint8_t u8i=0,u8State;
        I2C_SetFunc(I2CX,I2cStart_En);
        while(1)
        {
            while(0 == I2C_GetIrq(I2CX))
            {;}
            u8State = I2C_GetState(I2CX);
            switch(u8State)
            {
                case 0x08:                               ///< 已发送起始条件
                    I2C_ClearFunc(I2CX,I2cStart_En);
                    I2C_WriteByte(I2CX,I2C_SLAVEADDR);   ///< 从设备地址发送
                    break;
                case 0x18:                               ///< 已发送SLA+W,并接收到ACK
                    I2C_WriteByte(I2CX,u8Addr);          ///< 从设备内存地址发送
                    break;
                case 0x28:                               ///< 上一次发送数据后接收到ACK
                    I2C_WriteByte(I2CX,pu8Data[u8i++]);  ///< 继续发送数据
                    break;
                case 0x20:                               ///< 上一次发送SLA+W后,收到NACK
                case 0x38:                               ///< 上一次在SLA+读或写时丢失仲裁
                    I2C_SetFunc(I2CX,I2cStart_En);       ///< 当I2C总线空闲时发送起始条件
                    break;
                case 0x30:                               ///< 已发送I2Cx_DATA中的数据,收到NACK,将传输一个STOP条件
                    I2C_SetFunc(I2CX,I2cStop_En);        ///< 发送停止条件
                    break;
                default:
                    break;
            }
            if(u8i>u32Len)
            {
                I2C_SetFunc(I2CX,I2cStop_En);            ///< 此顺序不能调换,出停止条件
                I2C_ClearIrq(I2CX);
                break;
            }
            I2C_ClearIrq(I2CX);                          ///< 清除中断状态标志位
        }
        enRet = Ok;
        return enRet;
    }

      第5步:为验证I2C通信是否成功,向NSA2862空闲寄存器0XCF中执行读数据0X55并读取出来,空闲寄存器地址如下表所示:

    验证示例代码如下所示:  

    uint8_t u8Senddata[2] = {0x00,0x55};
    uint8_t u8Recdata[1]={0x00};
    
    ///< 向I2C总线发起开始信号
    I2C_SetFunc(M0P_I2C1,I2cStart_En); 
    ///< 写数据
    I2C_MasterWriteData(M0P_I2C0,0x30,&u8Senddata[0],1);  
    I2C_MasterWriteData(M0P_I2C0,0xCF,&u8Senddata[1],1);  
    delay1ms(100);
    
    ///< 读数据
    I2C_MasterReadData(M0P_I2C0,0xCF,u8Recdata,1);    
    
    ///< 串口打印
    for(int i=0;i            
关注
打赏
1664101891
查看更多评论
0.0382s