【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应用打下基础。
硬件连接如下:

这里需要使用到ST的LIS3DH 加速计传感器模块,基于12C通信。
具体来说选用开发板CN10引脚——I2C1_SCL(PB6)及I2C1_SDA(PB7)

STM32CubeMX2配置如下:


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

STM32CubeMX2配置如下:


另外,还需配置DEBUG引脚
PA13——SWDIO
PA14——SWCLK

以上配置完毕就可以生成工程。
在STM32CubeIDE 2.2.0中编写代码了。
首先,在工程/generated/hal目录,就可以看到刚刚配置好的硬件模块。
特别是i2c1和usart2。

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

首先是一个简单的打印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;

后面注意到mx_usart2.c的最后有现成的句柄引用函数hal_uart_handle_t *mx_usart2_uart_gethandle(void)
就可以在main.c中直接调用了。

当然还有个办法是删掉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);
}
}
}运行效果:

下面来到搞定3轴加速度计读取
整体流程如下:

代码如下:
#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, ®, 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, ®, 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,非常准确!

我要赚赏金
