拿到MM32F5270开发板有一些时间了,计划后期用它来实现一个水质过滤采样仪。是利用手机作为控制和显示端,通过手机连接主控板的蓝牙模块。从而实现手机和系统的无线连接。我们通过手机上的android软件以蓝牙作为信息载体。通过蓝牙协议进行通信,将指令发送给系统主控板,主控板通过解析相关的手机发送过来的指令,并设置相应的参数,驱动泵、流量计及过滤装置工作,并实时读取流量计及采样电池电量当前值,以实现流量采集、电池电量监控、远程控制等功能。同时,获取深度传感器所采集的水深度及水温度数据换算后实时的通过蓝牙发送给我们的手机,最后我们就可以通过手机控制完成远程数据采集监控。
由于整个系统需要重新设计硬件,故本次测评基于开发板MindSDK I2C实现深度传感器数度采集。
一. 开发环境搭建
- 开发环境搭建及固件下载参考“【MM32F5270开发板试用】+ 开发环境的搭建并测试GPIO例程”
- MindSDK体验测试参考“【MM32F5270开发板试用】 MindSDK使用测评”
二、关于深度传感器
MS5837-30BA水深压力传感器模块包括一个高线性压力芯片和一个低功耗24位ADC,内部校准系数。提供精确的数字24位压力和温度值以及不同的操作模式,允许优化转换速度和电流消耗。高分辨率的温度输出允许在没有任何附加传感器的情况下实现高度计和温度计功能。MS5837-30BA可以通过IC总线接口连接到任何微控制器。通信协议简单,无需对设备内部寄存器进行编程。
1. MS5837-30BA水深传感器解读
1.简介:无人机实现定高飞行要依靠高度数据,那么水下航行器想要实现定深航行同样需要垂直方向的位置数据,也就是深度,我们使用MS5837-30BA这款压力传感器来测量水深。关于MS5837的使用网上有很多教程,其实都不用看,看数据手册就行了,写得非常非常全面。什么?看不懂英文?好的我已经把它翻译了一遍,可以说是非常非常详细了,相信我,看了数据手册,就会写驱动程序了。
2. 性能参数
MS5837-30BA可以配置成不同的ADC转换精度,用OSR表示,精度越高转换越慢,下表显示了不同精度对应的转换时间。每次读ADC转换数据前要先发送转换命令,必须要按照最大的转换时间去写一个延时,延时时间够了才能继续发送读转换完成的数据,不然数据是错的。比如OSR=4096时转换时间是7.40-9.04,那么延时时间可以设置成10ms.
电气特性,性能特征等请看手册,我们只关注算法。
MS5837-30BA可以配置成不同的ADC转换精度,用OSR表示,精度越高转换越慢,下表显示了不同精度对应的转换时间。每次读ADC转换数据前要先发送转换命令,必须要按照最大的转换时间去写一个延时,延时时间够了才能继续发送读转换完成的数据,不然数据是错的。比如OSR=4096时转换时间是7.40-9.04,那么延时时间可以设置成10ms.
MS5837使用IIC通讯,典型应用电路如下图。经典的IIC通讯电路。
模块硬件连接电路
如上图将MS5837接到开发板GPIO的I2C1的C6、C7上,基于driver_examples\i2c\i2c_master_detect程序检测传感器是否存在,串口输出如下(红框即为传感器地址):
三、功能源码实现
1、时钟滴答及延时实现:
static uint64_t SysRunTimeMs = 0;
static uint8_t fac_us = 0;
static uint32_t fac_ms = 0;
void SysTick_Init(void)
{
uint32_t reload = 0;
SysTick->CTRL &= (uint32_t)0xFFFFFFFB;
fac_us = CLOCK_SYS_FREQ / 8000000U;
fac_ms = CLOCK_SYS_FREQ / 8000U;
reload = CLOCK_SYSTICK_FREQ/1000;
reload--;
SysTick->CTRL |= SysTick_CTRL_TICKINT_Msk;
SysTick->LOAD = reload;
SysTick->CTRL |= SysTick_CTRL_ENABLE_Msk;
}
/**
* @brief This function handles SysTick Handler.
* @param None
* @retval None
*/
void SysTick_Handler(void)
{
SysRunTimeMs++;
}
uint32_t GetSysRunTimeMs(void)
{
return SysRunTimeMs;
}
void delay_us(uint16_t nus)
{
uint32_t ticks = 0;
uint32_t told = 0;
uint32_t tnow = 0;
uint32_t tcnt = 0;
uint32_t reload = 0;
reload = SysTick->LOAD;
ticks = nus * fac_us;
told = SysTick->VAL;
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
}
void delay_ms(uint16_t nms)
{
uint32_t ticks = 0;
uint32_t told = 0;
uint32_t tnow = 0;
uint32_t tcnt = 0;
uint32_t reload = 0;
reload = SysTick->LOAD;
ticks = nms * fac_ms;
told = SysTick->VAL;
while (1)
{
tnow = SysTick->VAL;
if (tnow != told)
{
if (tnow < told)
{
tcnt += told - tnow;
}
else
{
tcnt += reload - tnow + told;
}
told = tnow;
if (tcnt >= ticks)
{
break;
}
}
}
}
2、硬件GPIO初始化及I2C读写函数
#define BOARD_I2C_PORT I2C1
#define BOARD_I2C_IRQn I2C1_IRQn
#define BOARD_I2C_IRQHandler I2C1_IRQHandler
#define BOARD_I2C_FREQ CLOCK_APB1_FREQ
/* Initialize I2C */
void app_i2c_init(void)
{
/* Setup I2C initialization values. */
I2C_Master_Init_Type i2c_init;
i2c_init.ClockFreqHz = BOARD_I2C_FREQ;
i2c_init.BaudRate = I2C_BaudRate_100K;
/* Initialize I2C master. */
I2C_InitMaster(BOARD_I2C_PORT, &i2c_init);
/* The target device address needs to be configured before enabling. */
I2C_SetTargetAddr(BOARD_I2C_PORT, APP_I2C_TARGET_ADDR);
/* Enable I2C. */
I2C_Enable(BOARD_I2C_PORT, true);
}
/* Write data to target device, true to writing succeed, false to writing failed. */
bool app_i2c_write(uint8_t txlen, uint8_t *txbuf)
{
app_i2c_xfer.WaitTimes = APP_I2C_TIMEOUT_TIME;
app_i2c_xfer.TxBuf = txbuf;
app_i2c_xfer.TxLen = txlen;
I2C_Enable(BOARD_I2C_PORT, true); /* Disable I2C to clear tx fifo, and enabled I2C to perform the write operation again. */
if ( false == I2C_MasterWriteBlocking(BOARD_I2C_PORT, &app_i2c_xfer) )
{
return false;
}
else
{
return true;
}
}
/* Read data to target device, true to reading succeed, false to reading failed. */
bool app_i2c_read(uint8_t rxlen, uint8_t *rxbuf)
{
app_i2c_xfer.WaitTimes = APP_I2C_TIMEOUT_TIME;
app_i2c_xfer.RxBuf = rxbuf;
app_i2c_xfer.RxLen = rxlen;
I2C_Enable(BOARD_I2C_PORT, true); /* Disable I2C to clear tx fifo, and enabled I2C to perform the read operation again. */
if ( false == I2C_MasterReadBlocking(BOARD_I2C_PORT, &app_i2c_xfer) )
{
return false;
}
else
{
return true;
}
}
3、传感器初始化及数据获取
/*
C1 压力灵敏度 SENS|T1
C2 压力补偿 OFF|T1
C3 温度压力灵敏度系数 TCS
C4 温度系数的压力补偿 TCO
C5 参考温度 T|REF
C6 温度系数的温度 TEMPSENS
*/
uint32_t Cal_C[7]; //用于存放PROM中的6组数据1-6
double OFF_;
float Aux;
/*
dT 实际和参考温度之间的差异
TEMP 实际温度
*/
uint64_t dT,TEMP;
/*
OFF 实际温度补偿
SENS 实际温度灵敏度
*/
uint64_t SENS;
uint32_t D1_Pres,D2_Temp; // 数字压力值,数字温度值
uint32_t TEMP2,T2,OFF2,SENS2; //温度校验值
uint32_t Pressure; //气压
uint32_t Atmdsphere_Pressure;//大气压
uint32_t Depth;
float TEMP1;
double DEEP;
/*
* Declerations.
*/
void app_i2c_init(void);
bool app_i2c_write(uint8_t txlen, uint8_t *txbuf);
bool app_i2c_read(uint8_t rxlen, uint8_t *rxbuf);
void MS5837_init(void);
void MS583703BA_getPressure(void);
/*******************************************************************************
* @函数名称 MS583730BA_RESET
* @函数说明 复位MS5611
* @输入参数 无
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void MS583703BA_RESET(void)
{
// IIC_Start();
// IIC_Send_Byte(0xEC);//CSB接地,主机地址:0XEE,否则 0X77
// IIC_Wait_Ack();
// IIC_Send_Byte(0x1E);//发送复位命令
// IIC_Wait_Ack();
// IIC_Stop();
uint8_t txData;
txData = 0xEC;
app_i2c_write(1,&txData);//CSB接地,主机地址:0XEE,否则 0X77
txData = 0x1E;
app_i2c_write(1,&txData); //发送复位命令
}
/*******************************************************************************
* @函数名称 MS5611_init
* @函数说明 初始化5611
* @输入参数 无
* @输出参数 无
* @返回参数 无
*******************************************************************************/
void MS5837_init(void)
{
uint8_t txData,rxData,inth,intl,i;
MS583703BA_RESET(); // Reset Device 复位MS5837
delay_ms(20); //复位后延时(注意这个延时是一定必要的,可以缩短但似乎不能少于20ms)
for (i=1;i<=6;i++)
{
txData = 0xEC;
app_i2c_write(1,&txData);
txData = 0xA0 + (i*2);
app_i2c_write(1,&txData);
delay_us(5);
txData = 0xEC+0x01;//进入接收模式
app_i2c_write(1,&txData);
delay_us(1);
app_i2c_read(1,&inth);
delay_us(1);
app_i2c_read(1,&intl);
Cal_C[i] = (((uint16_t)inth << 8) | intl);
}
for(i=0;i<5;i++)
{
delay_ms(1);
MS583703BA_getPressure(); //获取大气压
Atmdsphere_Pressure+=Pressure;
printf("%d\t",Pressure); //串口输出原始数据
}
Atmdsphere_Pressure=Atmdsphere_Pressure/5;
printf("Atmdsphere_Pressure:%d\r\n",Atmdsphere_Pressure); //串口输出原始数据
}
/**************************实现函数********************************************
*函数原型:unsigned long MS561101BA_getConversion(void)
*功 能: 读取 MS5837 的转换结果
*******************************************************************************/
unsigned long MS583703BA_getConversion(uint8_t command)
{
unsigned long conversion = 0;
uint8_t temp[3],txData;
txData = 0xEC;
app_i2c_write(1,&txData);//写地址
txData = command;
app_i2c_write(1,&txData); //写转换命令
delay_ms(10);
txData = 0xEC;
app_i2c_write(1,&txData); //写地址
txData = 0x0;
app_i2c_write(1,&txData); //start read sequence
txData = 0xEC+0x01;
app_i2c_write(1,&txData);//进入接收模式
txData = 0x0;
app_i2c_write(1,&txData);
app_i2c_read(1,&temp[0]);//带ACK的读数据 bit 23-16
app_i2c_read(1,&temp[1]);//带ACK的读数据 bit 8-15
app_i2c_read(1,&temp[2]);//带NACK的读数据 bit 0-7
conversion = (unsigned long)temp[0] * 65536 + (unsigned long)temp[1] * 256 + (unsigned long)temp[2];
return conversion;
}
/**************************实现函数********************************************
*函数原型:void MS561101BA_GetTemperature(void)
*功 能: 读取 温度转换结果
*******************************************************************************/
void MS583703BA_getTemperature(void)
{
D2_Temp = MS583703BA_getConversion(0x58);
delay_ms(10);
dT=D2_Temp - (((uint32_t)Cal_C[5])*256);
TEMP=2000+dT*((uint32_t)Cal_C[6])/8388608;
TEMP1 = TEMP/100.0f/10000;
}
///***********************************************
// * @brief 读取气压
// * @param None
// * @retval None
//************************************************/
void MS583703BA_getPressure(void)
{
D1_Pres= MS583703BA_getConversion(0x48);
delay_ms(10);
OFF_=(uint32_t)Cal_C[2]*65536+((uint32_t)Cal_C[4]*dT)/128;
SENS=(uint32_t)Cal_C[1]*32768+((uint32_t)Cal_C[3]*dT)/256;
if(TEMP/100<20) // low temp
{
Aux = (2000-TEMP)*(2000-TEMP);
T2 = 3*(dT*dT) /0x80000000;
OFF2 = 1.5*Aux;
SENS2 = 5*Aux/8;
OFF_ = OFF_ - OFF2;
SENS = SENS - SENS2;
}
else {
T2=2*(dT*dT)/137438953472;
OFF2 = 1*Aux/16;
SENS2 = 0;
OFF_ = OFF_ - OFF2;
SENS = SENS - SENS2;
}
Pressure= ((D1_Pres*SENS/2097152-OFF_)/8192)/10;
TEMP=(TEMP-T2)/100;
DEEP=Pressure/9794.4/10000;
}
/*
* Functions.
*/
int main(void)
{
BOARD_Init();
SysTick_Init();
printf("\r\ni2c_master_ms5837 example\r\n");
/* Initialize I2C. */
app_i2c_init();
/* Setup the data to be transmitted. */
MS5837_init();
while (1)
{
//printf("press any key to write i2c-eeprom.\r\n");
getchar();
MS583703BA_getTemperature();
MS583703BA_getPressure();
printf(" Temp : %5.2lf\r\n",TEMP1); //串口输出原始数据
printf(" Pressure : %u\r\n\r\n\r\n",Pressure); //串口输出原始数据
printf(" Deep : %5.6f\r\n",DEEP);
}
}
四. 功能测试
编译下载固件,打印输出如下:
下一步通过定时器及串口中断实现不定长数据接收来完成无线数据的透传。