基于N32WB482的i2c读取QMA7981的三轴数据(C语言)

通讯总线地址

根据数据手册可知,通讯总线的高6位固定位00100100B 根据PIN 1 即AD0接GND还是VIDDIO 来选择设置LSB 为1还是为0,
最后一位为读或写标志

AD0 拉高时:00100110B = 0x26
AD0 拉低时:00100100B = 0x24

在这里插入图片描述

读取芯片ID

查询芯片ID所在的寄存器地址

根据9.1 Register Map章中的Table 13. Register Map可知,芯片ID的寄存器地址为0x00,部分截图如下所示
表头部分寄存器描述

编写程序读芯片ID

参考:国民技术资料:examples\I2C\EEPROM工程
我用的I2C2 使用的引脚是PA4,PA5 ,需要重映射管脚的功能,通过查阅N32WB452系列用户手册V3.07.2.5.12.2 I2C2 管脚重映射可知,需要将管脚配置为GPIO_RMP3_I2C2
在这里插入图片描述
以下为7.4.8 AFIO复用重映射配置寄存器3(AFIO_RMP_CFG3) 的部分描述
在这里插入图片描述

I2C初始化代码

	//外部定义
	#define QMA_I2Cx I2C2
	
    /** GPIO configuration and clock enable */
    GPIO_InitType GPIO_InitStructure;
    I2C_InitType I2C_InitStructure;

    /** enable peripheral clk*/
    RCC_EnableAPB1PeriphClk(RCC_APB1_PERIPH_I2C2, ENABLE);
    I2C_DeInit(QMA_I2Cx);

    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOA, ENABLE);
	RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_AFIO, ENABLE);
	GPIO_ConfigPinRemap(GPIO_RMP3_I2C2, ENABLE); //复用io

    GPIO_InitStructure.Pin        = GPIO_PIN_4 | GPIO_PIN_5;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_2MHz;
    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_OD;
    GPIO_InitPeripheral(GPIOA, &GPIO_InitStructure);

    /** I2C periphral configuration */
    I2C_DeInit(QMA_I2Cx);
    I2C_InitStructure.BusMode     = I2C_BUSMODE_I2C;
    I2C_InitStructure.FmDutyCycle = I2C_FMDUTYCYCLE_2;
    I2C_InitStructure.OwnAddr1    = QMA_OWN_ADDR;
    I2C_InitStructure.AckEnable   = I2C_ACKEN;
    I2C_InitStructure.AddrMode    = I2C_ADDR_MODE_7BIT;
    I2C_InitStructure.ClkSpeed    = 100000; // 100000 100K
    I2C_Init(QMA_I2Cx, &I2C_InitStructure);

读芯片id代码

	//外部定义
	#define sQMA7981_FLAG_TIMEOUT ((uint32_t)0x1000)
	#define sQMA7981_LONG_TIMEOUT ((uint32_t)(100 * sQMA7981_FLAG_TIMEOUT))
	#define QMA_WRITE_ADDR 0x24
	#define QMA_READ_ADDR 0x24
	u32 sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
	//具体程序
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (I2C_GetFlag(QMA_I2Cx, I2C_FLAG_BUSY))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }
    QMA_I2Cx->CTRL1 &= ~0x0800; // clear POSEN
    I2C_ConfigAck(QMA_I2Cx, ENABLE);
    /** Send START condition */
    I2C_GenerateStart(QMA_I2Cx, ENABLE);

    /** Test on EV5 and clear it */
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (!I2C_CheckEvent(QMA_I2Cx, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }
    /** 发送数据,寄存器地址为QMA_WRITE_ADDR 方向为主机发送 */
    I2C_SendAddr7bit(QMA_I2Cx, QMA_WRITE_ADDR, I2C_DIRECTION_SEND);
    /** Test on EV6 and clear it */
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (!I2C_CheckEvent(QMA_I2Cx, I2C_EVT_MASTER_TXMODE_FLAG))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }
    /** Clear EV6 by setting again the PE bit */
    I2C_Enable(QMA_I2Cx, ENABLE);
    /** 发送需要读取的寄存器地址 */
    I2C_SendData(QMA_I2Cx, ReadAddr);
    /** Test on EV8 and clear it */
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (!I2C_CheckEvent(QMA_I2Cx, I2C_EVT_MASTER_DATA_SENDED))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }
    /** Send STRAT condition a second time */
    I2C_GenerateStart(QMA_I2Cx, ENABLE);
    /** Test on EV5 and clear it */
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (!I2C_CheckEvent(QMA_I2Cx, I2C_EVT_MASTER_MODE_FLAG))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }
    /** 发送数据,寄存器地址为QMA_WRITE_ADDR 方向为三轴芯片发送,主机接收 */
    I2C_SendAddr7bit(QMA_I2Cx, QMA_WRITE_ADDR, I2C_DIRECTION_RECV);
    sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
    while (!I2C_GetFlag(QMA_I2Cx, I2C_FLAG_ADDRF))
    {
        if ((sQMA7981Timeout--) == 0)
            sQMA7981_TIMEOUT_UserCallback();
    }

    /** While there is data to be read */
    if (NumByteToRead == 1)
    {
        /** Disable Acknowledgement */
        I2C_ConfigAck(QMA_I2Cx, DISABLE);
        (void)(QMA_I2Cx->STS1); /// clear ADDR
        (void)(QMA_I2Cx->STS2);
        I2C_GenerateStop(QMA_I2Cx, ENABLE);
    }
	
	/** One byte */
	if (NumByteToRead == 1)
	{
		/** Wait until RXNE flag is set */
		sQMA7981Timeout = sQMA7981_LONG_TIMEOUT;
		while (!I2C_GetFlag(QMA_I2Cx, I2C_FLAG_RXDATNE))
		{
			if ((sQMA7981Timeout--) == 0)
				sQMA7981_TIMEOUT_UserCallback();
		}
		/** 读取数据*/
		*pBuffer = I2C_RecvData(QMA_I2Cx);
	}

说明

目前先写到这里,只是读了一下芯片的id,读三轴数据时一样的,上方已经给出了三轴的寄存器地址,只需要修改I2C_SendData(QMA_I2Cx, ReadAddr);中的ReadAddr读取相应的寄存器即可,但是需要注意的是,每个轴的数据中,低6位所在的寄存器是低地址的高6位,即
x轴:0x01寄存器地址的2-7位为x轴数据的0-5位,0x02寄存器的0-7位为x轴数据的6-13位

结束

好了 到这里就结束了 有什么问题可以私信我

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我不是很熟悉C语言,但我可以给你一些参考资料,希望能帮助你: 1.QMA7981计步算法API文档:http://www.qmax.com.cn/User/index.php?m=Content&c=index&a=show&catid=3&id=8 2.C语言实现计步算法的博客:https://blog.csdn.net/xiao_kuang/article/details/77277229 3.C语言实现计步算法的视频教程:https://www.bilibili.com/video/BV1LK4y1s7tH?from=search&seid=14172766009995355020 ### 回答2: 下面是一个简单的基于QMA7981的计步算法的C语言代码示例: ```c #include <stdio.h> #include <stdint.h> #define SENSITIVITY 0.7f // 灵敏度 #define STEP_THRESHOLD 50 // 步数阈值 #define ACCELEROMETER_MAXVALUE 16384 // QMA7981的加速度计最大值 int main() { int16_t x, y, z; int16_t lastX = 0, lastY = 0, lastZ = 0; int32_t squareSum = 0; int32_t squareSumLast = 0; int32_t squareDifference; int32_t stepCount = 0; float acceleration; // 这里省略了初始化QMA7981的代码 while (1) { // 读取加速度计数据 x = readAccelerometerX(); y = readAccelerometerY(); z = readAccelerometerZ(); // 计算当前加速度的平方和 squareSum = x * x + y * y + z * z; // 计算当前加速度平方和与上一次的差值 squareDifference = squareSum - squareSumLast; // 如果差值超过阈值,则认为是步子 if (squareDifference > ACCELEROMETER_MAXVALUE * SENSITIVITY) { // 更新上一次加速度平方和 squareSumLast = squareSum; // 根据步数阈值判断是否是有效的步子 if (squareSumLast > STEP_THRESHOLD) { stepCount++; printf("步数:%d\n", stepCount); } } // 延时一段时间,进行下一次采样 delay(100); } return 0; } ``` 以上代码演示了一个简单的计步算法:通过读取QMA7981加速度计的X、Y、Z轴数据,计算加速度的平方和,然后与上一次的平方和进行差值计算。当差值超过设定的灵敏度阈值时,认为发生了一次步伐。通过阈值判断,来排除误差。代码中使用了一个步数阈值来判断是否是有效的步子,并输出步数。这只是一个简单的示例,实际应用中可能需要进一步优化和调整参数。 ### 回答3: QMA7981是一种常见的智能手机传感器,可以测量人体活动的步数。要编写一个基于QMA7981的计步算法代码,我们可以按照以下步骤进行: 1. 首先,我们需要通过调用与QMA7981传感器相关的库函数来获取传感器数据。这包括读取传感器的加速度数据。 2. 接下来,我们可以使用一个变量来记录步数。我们将其初始化为0,并将其命名为step_count。 3. 在循环中,我们可以不断获取QMA7981传感器的加速度数据,并根据这些数据来判断用户是否迈出了一步。 4. 判断步数的方法可以有很多,以下是一种简单的示例算法: - 首先,我们需要确定一个阈值,用于判断加速度是否超过了步行的阈值。可以根据实际情况设置这个阈值。 - 在每次循环中,检查QMA7981传感器的加速度数据是否超过了设置的阈值。 - 如果超过了阈值,我们可以将步数加1,并将加速度数据归零,以便下一步的检测。 5. 循环直到达到预定的时间。 6. 最后,我们可以输出step_count变量的值,即用户在给定时间内的步数。 这只是一个简单的示例代码,实际的计步算法可能会更复杂,需要考虑更多因素,如姿势、速度变化等。但是通过以上步骤,我们可以构建一个基于QMA7981的计步算法代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值