这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » DIY与开源设计 » 电子DIY » 【let'sdo|2026年第3期】过程贴:搞定3轴加速度计读取

共1条 1/1 1 跳转至页

【let'sdo|2026年第3期】过程贴:搞定3轴加速度计读取

助工
2026-11-08 08:08:48     打赏

【let'sdo|2026年第3期】开箱贴:为什么我要选NUCLEO-C562RE  

https://forum.eepw.com.cn/thread/402045/1

【let'sdo|2026年第3期】过程贴:使用全新的CubeMX2+CubeIDE2点亮NUCLEO-C562RE  

https://forum.eepw.com.cn/thread/402048/1


书接上回。

搞定了STM32C562的开发环境并点灯成功,接下来切入本项目正题:搞定3轴加速度计的读取,为后续AI应用打下基础。

硬件连接如下:

image.png


这里需要使用到ST的LIS3DH 加速计传感器模块,基于12C通信。

具体来说选用开发板CN10引脚——I2C1_SCL(PB6)及I2C1_SDA(PB7)

image.png

STM32CubeMX2配置如下:

image.png


image.png



同时读取的3轴加速度数据需要通过串口输出,因此涉及到USART模块(对应ST-Link的虚拟串口直接连到电脑)。

使用USART2——PA2(USART2_TX)及PA3(USART2_RX)

image.png

STM32CubeMX2配置如下:


image.png


image.png





另外,还需配置DEBUG引脚


PA13——SWDIO

PA14——SWCLK



image.png


以上配置完毕就可以生成工程。

在STM32CubeIDE 2.2.0中编写代码了。

首先,在工程/generated/hal目录,就可以看到刚刚配置好的硬件模块。

特别是i2c1和usart2。

image.png

在工程/stm32c5xx_drivers/hal目录下,可以看到个各自HAL库,我们可以查阅使用方法并调用。

image.png


首先是一个简单的打印Hello World!的串口程序。

只需要在main.c中添加3行代码。

HAL_UART_Transmit(mx_usart2_uart_gethandle(), msg1, strlen(msg1), 100);

这行尤为关键,同时需mx_usart2_uart_gethandle()的使用。

尽管在mx_usart2.c中自动生成了串口配置代码,但由于使用的是static hal_uart_handle_t hUSART2;

在main.c中就无法直接调用串口句柄,类似extern hal_uart_handle_t hUSART2;


image.png

后面注意到mx_usart2.c的最后有现成的句柄引用函数hal_uart_handle_t *mx_usart2_uart_gethandle(void)

就可以在main.c中直接调用了。

image.png


当然还有个办法是删掉mx_usart2.c中的static,直接用hal_uart_handle_t hUSART2;

然后在main.c中使用extern hal_uart_handle_t hUSART2;



主代码:

#include "main.h"
#include "string.h"
#include <stdint.h>
#include <stdio.h>


char msg1[] = "Hello World!\r\n";


int main(void)
{
if (mx_system_init() != SYSTEM_OK)
{
return (-1);
}
else
{

while (1) {

   	HAL_UART_Transmit(mx_usart2_uart_gethandle(), msg1, strlen(msg1), 100);

   	HAL_Delay(500);
}
}
}


运行效果:

image.png



下面来到搞定3轴加速度计读取

整体流程如下:

image.png


代码如下:

#include "main.h"
#include "string.h"
#include <stdint.h>
#include <stdio.h>
#include <math.h>

char msg1[] = "Hello World!\r\n";
// 扫描得到7bit=0x19,8bit地址0x32
#define LIS3DH_ADDR_8BIT    (0x19 << 1)
#define LIS3DH_REG_WHO_AM_I 0x0F
#define LIS3DH_REG_CTRL1    0x20
#define LIS3DH_REG_CTRL4    0x23
#define LIS3DH_REG_OUT_XL   0x28

// 全局偏移变量
int16_t offset_x = 0;
int16_t offset_y = 0;
int16_t offset_z = 0;
uint8_t cal_done = 0;
#define CAL_SAMPLE_CNT 32  // 校准采样点数


/**
 * @brief 读取LIS3DH WHO_AM_I
 */
hal_status_t LIS3DH_ReadID(hal_i2c_handle_t *hi2c, uint8_t *id)
{
hal_status_t ret;
uint8_t reg = LIS3DH_REG_WHO_AM_I;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, &reg, 1, 100);
if(ret != HAL_OK) return ret;
ret = HAL_I2C_MASTER_Receive(hi2c, LIS3DH_ADDR_8BIT, id, 1, 100);
return ret;
}

/**
 * @brief LIS3DH初始化:100Hz,XYZ使能,±2g高分辨率
 */
hal_status_t LIS3DH_Init(hal_i2c_handle_t *hi2c)
{
hal_status_t ret;
uint8_t buf[2];

// CTRL1: ODR=100Hz, X Y Z enable --> 0x57
buf[0] = LIS3DH_REG_CTRL1;
buf[1] = 0x57;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, buf, 2, 100);
if(ret != HAL_OK) return ret;

// CTRL4: ±2g, HR=1 --> 0x08
buf[0] = LIS3DH_REG_CTRL4;
buf[1] = 0x08;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, buf, 2, 100);
return ret;
}

/**
 * @brief 连续读取XYZ原始数据 6字节
 * @param raw_buf[6] XL,XH,YL,YH,ZL,ZH
 */
hal_status_t LIS3DH_ReadRawXYZ(hal_i2c_handle_t *hi2c, uint8_t *raw_buf)
{
hal_status_t ret;
// bit7=1 自动增量
uint8_t reg = 0x80 | LIS3DH_REG_OUT_XL;
ret = HAL_I2C_MASTER_Transmit(hi2c, LIS3DH_ADDR_8BIT, &reg, 1, 100);
if(ret != HAL_OK) return ret;
ret = HAL_I2C_MASTER_Receive(hi2c, LIS3DH_ADDR_8BIT, raw_buf, 6, 100);
return ret;
}

/**
 * @brief 打印ID
 */
void LIS3DH_PrintID_UART2(void)
{
hal_status_t ret;
uint8_t chip_id = 0;
char msg[64];
ret = LIS3DH_ReadID(mx_i2c1_i2c_gethandle(), &chip_id);
if(ret == HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH ID: 0x%02X, expect 0x33\r\n", chip_id);
}
else
{
snprintf(msg, sizeof(msg), "LIS3DH I2C read FAIL");
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}

/**
 * @brief 读取XYZ并串口打印(mg单位)
 */
void LIS3DH_PrintXYZ_UART2(void)
{
hal_status_t ret;
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int16_t x, y, z;
char msg[128];

ret = LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw);
if(ret != HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH XYZ read error\r\n");
}
else
{
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

// HR高分辨率模式:12bit,左对齐,必须右移4位!
x = x_raw >> 4;
y = y_raw >> 4;
z = z_raw >> 4;

// ±2g:1 LSB = 1mg
snprintf(msg, sizeof(msg), "ACC: X=%d mg, Y=%d mg, Z=%d mg\r\n", x, y, z);
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}

/**
 * @brief 零点校准函数,调用前保持传感器水平平放
 */
void LIS3DH_CalibrateZero(void)
{
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int32_t sum_x = 0, sum_y = 0, sum_z = 0;

for(uint16_t i = 0; i < CAL_SAMPLE_CNT; i++)
{
// 等待读取成功
while(LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw) != HAL_OK);
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

int16_t x = x_raw >> 4;
int16_t y = y_raw >> 4;
int16_t z = z_raw >> 4;

sum_x += x;
sum_y += y;
sum_z += z;
HAL_Delay(20);
}
// 求平均偏移;Z理想值是1000mg
offset_x = sum_x / CAL_SAMPLE_CNT;
offset_y = sum_y / CAL_SAMPLE_CNT;
offset_z = sum_z / CAL_SAMPLE_CNT - 1000;
cal_done = 1;
}

/**
 * @brief 读取并打印【校准后】XYZ,单位 mg
 */
void LIS3DH_PrintXYZ_Cal(void)
{
hal_status_t ret;
uint8_t raw[6];
int16_t x_raw, y_raw, z_raw;
int16_t x, y, z;
char msg[128];

ret = LIS3DH_ReadRawXYZ(mx_i2c1_i2c_gethandle(), raw);
if(ret != HAL_OK)
{
snprintf(msg, sizeof(msg), "LIS3DH XYZ read error, ret=%u\r\n", ret);
}
else
{
x_raw = (int16_t)((raw[1] << 8) | raw[0]);
y_raw = (int16_t)((raw[3] << 8) | raw[2]);
z_raw = (int16_t)((raw[5] << 8) | raw[4]);

// 减去偏移,得到校准值
x = (x_raw >> 4) - offset_x;
y = (y_raw >> 4) - offset_y;
z = (z_raw >> 4) - offset_z;

snprintf(msg, sizeof(msg), "ACC: X=%d mg, Y=%d mg, Z=%d mg\r\n", x, y, z);
}
HAL_UART_Transmit(mx_usart2_uart_gethandle(), (uint8_t *)msg, strlen(msg), 100);
}


int main(void)
{
if (mx_system_init() != SYSTEM_OK)
{
return (-1);
}
else
{
LIS3DH_PrintID_UART2();
LIS3DH_Init(mx_i2c1_i2c_gethandle());
// 上电校准!【板子平放,不要晃动!】
LIS3DH_CalibrateZero();

while (1) {
   	HAL_GPIO_TogglePin(PA5_PORT, PA5_PIN);
   	//HAL_UART_Transmit(mx_usart2_uart_gethandle(), msg1, strlen(msg1), 100);
   	LIS3DH_PrintXYZ_Cal();
   	HAL_Delay(500);
}
}
}


运行结果如下:

其中Z轴约等于1G,非常准确!

image.png




共1条 1/1 1 跳转至页

回复

匿名不能发帖!请先 [ 登陆 注册 ]