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年而无需更换电池,可大规模应用在智慧城市、工业物联网等领域。
项目的测量、校准、评估和设计这里参照于纳芯微电子传感器解决方案实现,没办法,工业级传感器设计就是烧钱啊。
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
关注打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?