玩具共4个功能,心率(hp6),血压测量(hp6),6轴陀螺仪计步(mpu6050),温湿度获取(sh20t).
hp6模块介绍
HP6与主机间通信协议适用于i2c接口通信,7bite硬件地址(0x66);通信速率为100k,HP6与主机间通信对时序较为严格,软件模拟io口速率为建议设置为50MHZ,模拟i2c间加适量延时,等待从机响应,陀螺仪与温湿度可设置100MHZ,且不用加延时等待。
协议信息
1.开始血压测量
//开启血压测量
const uint8_t cmd_bp_open[]=
{0xc8,0xd7,0xb6,0xa5,0x90,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
2.关闭血压测量
//关闭血压测量
const uint8_t cmd_bp_close[]=
{0xc8,0xd7,0xb6,0xa5,0x90,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
3.读取血压测量信息
//获取血压测量结果
const uint8_t cmd_bp_result[]=
{0xc8,0xd7,0xb6,0xa5,0x90,0x02,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
buff[10]高压 buff[11]低压
4.开启心率测量
//开启心率测量
const uint8_t cmd_rate_open[]=
{0xc8,0xd7,0xb6,0xa5,0xD0,0x01,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
5.关闭心率测量
//关闭心率测量
const uint8_t cmd_rate_close[]=
{0xc8,0xd7,0xb6,0xa5,0xD0,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
6.读取心率信息
//获取心率测量结果
const uint8_t cmd_rate_result[]=
{0xc8,0xd7,0xb6,0xa5,0xD0,0x02,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
buff【7】心率结果
7.低功耗
8.校验算法
const uint16_t crc16_tab[256] =
{
0x0000, 0xC0C1, 0xC181, 0x0140, 0xC301, 0x03C0, 0x0280, 0xC241,
0xC601, 0x06C0, 0x0780, 0xC741, 0x0500, 0xC5C1, 0xC481, 0x0440,
0xCC01, 0x0CC0, 0x0D80, 0xCD41, 0x0F00, 0xCFC1, 0xCE81, 0x0E40,
0x0A00, 0xCAC1, 0xCB81, 0x0B40, 0xC901, 0x09C0, 0x0880, 0xC841,
0xD801, 0x18C0, 0x1980, 0xD941, 0x1B00, 0xDBC1, 0xDA81, 0x1A40,
0x1E00, 0xDEC1, 0xDF81, 0x1F40, 0xDD01, 0x1DC0, 0x1C80, 0xDC41,
0x1400, 0xD4C1, 0xD581, 0x1540, 0xD701, 0x17C0, 0x1680, 0xD641,
0xD201, 0x12C0, 0x1380, 0xD341, 0x1100, 0xD1C1, 0xD081, 0x1040,
0xF001, 0x30C0, 0x3180, 0xF141, 0x3300, 0xF3C1, 0xF281, 0x3240,
0x3600, 0xF6C1, 0xF781, 0x3740, 0xF501, 0x35C0, 0x3480, 0xF441,
0x3C00, 0xFCC1, 0xFD81, 0x3D40, 0xFF01, 0x3FC0, 0x3E80, 0xFE41,
0xFA01, 0x3AC0, 0x3B80, 0xFB41, 0x3900, 0xF9C1, 0xF881, 0x3840,
0x2800, 0xE8C1, 0xE981, 0x2940, 0xEB01, 0x2BC0, 0x2A80, 0xEA41,
0xEE01, 0x2EC0, 0x2F80, 0xEF41, 0x2D00, 0xEDC1, 0xEC81, 0x2C40,
0xE401, 0x24C0, 0x2580, 0xE541, 0x2700, 0xE7C1, 0xE681, 0x2640,
0x2200, 0xE2C1, 0xE381, 0x2340, 0xE101, 0x21C0, 0x2080, 0xE041,
0xA001, 0x60C0, 0x6180, 0xA141, 0x6300, 0xA3C1, 0xA281, 0x6240,
0x6600, 0xA6C1, 0xA781, 0x6740, 0xA501, 0x65C0, 0x6480, 0xA441,
0x6C00, 0xACC1, 0xAD81, 0x6D40, 0xAF01, 0x6FC0, 0x6E80, 0xAE41,
0xAA01, 0x6AC0, 0x6B80, 0xAB41, 0x6900, 0xA9C1, 0xA881, 0x6840,
0x7800, 0xB8C1, 0xB981, 0x7940, 0xBB01, 0x7BC0, 0x7A80, 0xBA41,
0xBE01, 0x7EC0, 0x7F80, 0xBF41, 0x7D00, 0xBDC1, 0xBC81, 0x7C40,
0xB401, 0x74C0, 0x7580, 0xB541, 0x7700, 0xB7C1, 0xB681, 0x7640,
0x7200, 0xB2C1, 0xB381, 0x7340, 0xB101, 0x71C0, 0x7080, 0xB041,
0x5000, 0x90C1, 0x9181, 0x5140, 0x9301, 0x53C0, 0x5280, 0x9241,
0x9601, 0x56C0, 0x5780, 0x9741, 0x5500, 0x95C1, 0x9481, 0x5440,
0x9C01, 0x5CC0, 0x5D80, 0x9D41, 0x5F00, 0x9FC1, 0x9E81, 0x5E40,
0x5A00, 0x9AC1, 0x9B81, 0x5B40, 0x9901, 0x59C0, 0x5880, 0x9841,
0x8801, 0x48C0, 0x4980, 0x8941, 0x4B00, 0x8BC1, 0x8A81, 0x4A40,
0x4E00, 0x8EC1, 0x8F81, 0x4F40, 0x8D01, 0x4DC0, 0x4C80, 0x8C41,
0x4400, 0x84C1, 0x8581, 0x4540, 0x8701, 0x47C0, 0x4680, 0x8641,
0x8201, 0x42C0, 0x4380, 0x8341, 0x4100, 0x81C1, 0x8081, 0x4040
};
uint16_t Crc16(uint8_t *data,uint16_t len)
{
uint16_t crc16 = 0xFFFF;
uint32_t uIndex ; //CRC查询表索引
while (len --)
{
uIndex = (crc16&0xff) ^ ((*data) & 0xff) ; //计算CRC
data = data + 1;
crc16 = ((crc16>>8) & 0xff) ^ crc16_tab[uIndex];
}
return crc16 ;//返回CRC校验值
}
六轴陀螺仪
六轴分别测了x,y,z的加速度(acc)和角速度(gry),陀螺仪初始化代码如下
陀螺仪用i2c接口,我用软件i2c
#define MPU6050_SMPLRT_DIV 0x19
#define MPU6050_CONFIG 0x1A
#define MPU6050_GYRO_CONFIG 0x1B
#define MPU6050_ACCEL_CONFIG 0x1C
#define MPU6050_ACCEL_XOUT_H 0x3B
#define MPU6050_ACCEL_XOUT_L 0x3C
#define MPU6050_ACCEL_YOUT_H 0x3D
#define MPU6050_ACCEL_YOUT_L 0x3E
#define MPU6050_ACCEL_ZOUT_H 0x3F
#define MPU6050_ACCEL_ZOUT_L 0x40
#define MPU6050_TEMP_OUT_H 0x41
#define MPU6050_TEMP_OUT_L 0x42
#define MPU6050_GYRO_XOUT_H 0x43
#define MPU6050_GYRO_XOUT_L 0x44
#define MPU6050_GYRO_YOUT_H 0x45
#define MPU6050_GYRO_YOUT_L 0x46
#define MPU6050_GYRO_ZOUT_H 0x47
#define MPU6050_GYRO_ZOUT_L 0x48
#define MPU6050_PWR_MGMT_1 0x6B
#define MPU6050_PWR_MGMT_2 0x6C
#define MPU6050_WHO_AM_I 0x75
#define MPU6050_ADDRESS 0xD0 //MPU6050的I2C从机地址
/**
* 函 数:MPU6050写寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 参 数:Data 要写入寄存器的数据,范围:0x00~0xFF
* 返 回 值:无
*/
void MPU6050_WriteReg(uint8_t RegAddress, uint8_t Data)
{
MyI2C_Start(); //I2C起始
MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(RegAddress); //发送寄存器地址
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(Data); //发送要写入寄存器的数据
MyI2C_ReceiveAck(); //接收应答
MyI2C_Stop(); //I2C终止
}
/**
* 函 数:MPU6050读寄存器
* 参 数:RegAddress 寄存器地址,范围:参考MPU6050手册的寄存器描述
* 返 回 值:读取寄存器的数据,范围:0x00~0xFF
*/
uint8_t MPU6050_ReadReg(uint8_t RegAddress)
{
uint8_t Data;
MyI2C_Start(); //I2C起始
MyI2C_SendByte(MPU6050_ADDRESS); //发送从机地址,读写位为0,表示即将写入
MyI2C_ReceiveAck(); //接收应答
MyI2C_SendByte(RegAddress); //发送寄存器地址
MyI2C_ReceiveAck(); //接收应答
MyI2C_Start(); //I2C重复起始
MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址,读写位为1,表示即将读取
MyI2C_ReceiveAck(); //接收应答
Data = MyI2C_ReceiveByte(); //接收指定寄存器的数据
MyI2C_SendAck(1); //发送应答,给从机非应答,终止从机的数据输出
MyI2C_Stop(); //I2C终止
return Data;
}
/**
* 函 数:MPU6050初始化
* 参 数:无
* 返 回 值:无
*/
void MPU6050_Init(void)
{
//先初始化底层的I2C
/*MPU6050寄存器初始化,需要对照MPU6050手册的寄存器描述配置,此处仅配置了部分重要的寄存器*/
MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01); //电源管理寄存器1,取消睡眠模式,选择时钟源为X轴陀螺仪
MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00); //电源管理寄存器2,保持默认值0,所有轴均不待机
MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09); //采样率分频寄存器,配置采样率
MPU6050_WriteReg(MPU6050_CONFIG, 0x06); //配置寄存器,配置DLPF
MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18); //陀螺仪配置寄存器,选择满量程为±2000°/s
MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程为±16g
}
/**
* 函 数:MPU6050获取ID号
* 参 数:无
* 返 回 值:MPU6050的ID号
*/
uint8_t MPU6050_GetID(void)
{
return MPU6050_ReadReg(MPU6050_WHO_AM_I); //返回WHO_AM_I寄存器的值
}
/**
* 函 数:MPU6050获取数据
* 参 数:AccX AccY AccZ 加速度计X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
* 参 数:GyroX GyroY GyroZ 陀螺仪X、Y、Z轴的数据,使用输出参数的形式返回,范围:-32768~32767
* 返 回 值:无
*/
void MPU6050_GetData(int16_t *AccX, int16_t *AccY, int16_t *AccZ,
int16_t *GyroX, int16_t *GyroY, int16_t *GyroZ)
{
uint8_t DataH, DataL; //定义数据高8位和低8位的变量
DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H); //读取加速度计X轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L); //读取加速度计X轴的低8位数据
*AccX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H); //读取加速度计Y轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L); //读取加速度计Y轴的低8位数据
*AccY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H); //读取加速度计Z轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L); //读取加速度计Z轴的低8位数据
*AccZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H); //读取陀螺仪X轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L); //读取陀螺仪X轴的低8位数据
*GyroX = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H); //读取陀螺仪Y轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L); //读取陀螺仪Y轴的低8位数据
*GyroY = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H); //读取陀螺仪Z轴的高8位数据
DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L); //读取陀螺仪Z轴的低8位数据
*GyroZ = (DataH << 8) | DataL; //数据拼接,通过输出参数返回
}
温湿度sh20t也采用i2c接口废话不多说我们直接上代码
#define SHT20ADDR 0x80 //SHT20写地址
#define ACK 0 //应答信号
#define NACK 1 //非应答信号
#define FAIL 1 //读取温湿度失败的返回值。
#define READ_TEMP_COMD 0xf3 //读取温度命令
#define READ_HUMI_COMD 0xf5 //读取湿度命令
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
/*******************************************************************************
* TYPEDEFS
*/
/*******************************************************************************
* LOCAL VARIABLES
*/
TempHumiValue_t temp_humi_Value;
/*******************************************************************************
* LOCAL FUNCTIONS
*/
static void SHT20_setResolution(void);
static void SHT20_setResolution(void);
void SHT20_softReset(void);
/*******************************************************************************
* PROFILE CALLBACKS
*/
/*******************************************************************************
* PUBLIC FUNCTIONS
*/
/*******************************************************************************
* 函数名:SHT20_writeOneByte
* 功能描述:写一个字节
* 作者:Jahol Fan
* 参数说明: 写一个字节的数据
* 返回值说明:返回的是应答信号
* 修改记录:
*******************************************************************************/
static u8 SHT20_writeOneByte(u8 dataToWrite)
{
u8 ack;
MyI2C_SendByte(dataToWrite);
ack= MyI2C_ReceiveAck();
return ack;
}
/*******************************************************************************
* 函数名:SHT20_softReset
* 功能描述:SHT20软件复位,主函数中调用
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:
* 修改记录:
*******************************************************************************/
void SHT20_softReset(void)
{
MyI2C_Start(); //start I2C
SHT20_writeOneByte(SHT20ADDR&0xfe); //I2C address + write
SHT20_writeOneByte(0xfe); //soft reset
MyI2C_Stop(); //stop I2C
}
/*******************************************************************************
* 函数名:SHT20_Init
* 功能描述:初始化iic总线
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:成功返回测量的结果,失败返回 1
* 修改记录:
*******************************************************************************/
void SHT20_Init(void)
{
SHT20_softReset();
}
/*******************************************************************************
* 函数名:SHT20_readOneByte
* 功能描述:读一个字节
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:
* 修改记录:
*******************************************************************************/
static u8 SHT20_readOneByte(u8 ack)
{
u8 temp;
temp=MyI2C_ReceiveByte();
MyI2C_SendAck(ack);
return temp;
}
/*******************************************************************************
* 函数名:SHT20_setResolution
* 功能描述:写寄存器,设置帧率
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:
* 修改记录:
*******************************************************************************/
static void SHT20_setResolution(void)
{
MyI2C_Start(); //Start I2C
if(SHT20_writeOneByte(SHT20ADDR&0xfe)==ACK) //I2C address + write + ACK
{
if(SHT20_writeOneByte(0xe6)==ACK) //写用户寄存器
{
if(SHT20_writeOneByte(0x83)==ACK); //设置分辨率 11bit RH% 测量时间:12ms(typ.) & 11bit T℃ 测量时间:9ms(typ.)
}
}
MyI2C_Stop(); //Stop I2C
}
/*******************************************************************************
* 函数名:SHT20_readTemOrHum
* 功能描述:读取SHT20的温度或读取湿度测量值
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:成功返回测量的结果,失败返回 1
* 修改记录:
*******************************************************************************/
float SHT20_readTemOrHum(u8 commod)
{
float temp; //温度
u8 ack=1;
u8 MSB,LSB; //温度、相对湿度的寄存器数据
float Humidity,Temperature; //温湿度的转换结果
SHT20_setResolution(); //设置帧率8bit,9bit,10 bit,11bit ,12bit,13bit,14bit
MyI2C_Start(); //iic开始信号
ack = SHT20_writeOneByte(SHT20ADDR&0xfe);
if( ack == ACK ) //写地址,并等待ACK
{
if(SHT20_writeOneByte(commod)==ACK) //写命令
{
do
{
HAL_Delay(6); //延时
MyI2C_Start(); //发送开始信号
}while(SHT20_writeOneByte(SHT20ADDR|0x01)==NACK); //无应答则整形,还在测量中,如果有应答,则结束当前循环
MSB = SHT20_readOneByte(ACK); //读Data(MSB),给应答ACK
LSB = SHT20_readOneByte(ACK); //读Data(LSB),给应答ACK
SHT20_readOneByte(NACK); //读Checksum ,不给应答NACK
MyI2C_Stop(); //Stop I2C
LSB &= 0xfc; //Data (LSB) 的后两位在进行物理计算前前须置‘0’
temp = MSB*256 + LSB; //十六进制转成十进制
if (commod==((u8)READ_HUMI_COMD)) //命令为读取湿度的命令
{
/*-- calculate relative humidity [%RH] --*/
Humidity =(temp*125)/65536-6; //公式: RH%= -6 + 125 * SRH/2^16
return Humidity; //返回值:humidity
}
else if(commod==((u8)READ_TEMP_COMD)) //命令为读取温度的命令
{
/*-- calculate temperature [°C] --*/
Temperature = (temp*175.72f)/65536-46.85f; //公式:T= -46.85 + 175.72 * ST/2^16
return Temperature; //返回值:temperature
}
}
}
return FAIL;
}
/*******************************************************************************
* 函数名:SHT20_readTemAndHum
* 功能描述:读取SHT20的温度和湿度测量值
* 作者:Jahol Fan
* 参数说明:
* 返回值说明:成功返回测量的结果,失败返回 1
* 修改记录:
*******************************************************************************/
TempHumiValue_t * SHT20_readTemAndHum(void)
{
temp_humi_Value.hum = SHT20_readTemOrHum(READ_HUMI_COMD);//读取湿度
temp_humi_Value.tem = SHT20_readTemOrHum(READ_TEMP_COMD);//读取湿度
return &temp_humi_Value;
}