1. ADXL362与STM32F103硬件连接指南
第一次拿到ADXL362这颗三轴加速度传感器时,我对着开发板上的STM32F103发愁——这堆引脚该怎么接?经过反复测试,终于摸清了门道。ADXL362采用标准的SPI接口,与STM32F103的连接其实比想象中简单。具体接线时要注意:SCLK接PB13、MISO接PB14、MOSI接PB15,这是STM32硬件SPI2的固定引脚分配。CS片选信号可以自由选择GPIO,我习惯用PB12方便记忆。
电源方面有个坑要注意:虽然ADXL362标称工作电压1.6V-3.5V,但实测发现与3.3V供电的STM32通信时,必须将ADXL362的VDD也接到3.3V。我曾尝试用2.5V供电,结果SPI通信异常不稳定。另外记得把GND共地,这是很多新手容易忽略的点。
硬件连接完整清单:
- VDD → 3.3V
- GND → GND
- SCLK → PB13
- MOSI → PB15
- MISO → PB14
- CS → PB12(可自定义)
- INT1 → 可悬空(用于中断功能)
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. SPI通信配置详解
STM32的SPI配置是驱动ADXL362的核心环节。刚开始我直接套用原子哥的例程,结果发现数据读取全是0xFF。后来仔细研究手册才发现,ADXL362要求CPOL=0且CPHA=0的SPI模式,而例程默认是CPHA=1。这里给出经过验证的配置代码:
c复制void SPI2_Init(void) {
GPIO_InitTypeDef GPIO_InitStructure;
SPI_InitTypeDef SPI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2, ENABLE);
// PB13/14/15复用推挽输出
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_Low; // 关键配置
SPI_InitStructure.SPI_CPHA = SPI_CPHA_1Edge; // 关键配置
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_8;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_Init(SPI2, &SPI_InitStructure);
SPI_Cmd(SPI2, ENABLE);
}
实际调试时发现,波特率预分频值建议设为8(即SPI_BaudRatePrescaler_8),这样SPI时钟约4.5MHz,既保证速度又稳定。分频值太大(如256)会导致通信超时,太小(如2)则可能不稳定。
3. 寄存器读写实战
ADXL362的所有功能都通过寄存器控制,掌握寄存器操作是基本功。这里分享几个关键函数:
c复制// 读寄存器(重点理解时序)
uint8_t ADXL362_ReadReg(uint8_t addr) {
uint8_t txBuf[3] = {0x0B, addr, 0x00}; // 读命令+地址+空数据
uint8_t rxData;
CS_LOW(); // 拉低片选
SPI2_ReadWriteByte(txBuf[0]); // 发送读命令
SPI2_ReadWriteByte(txBuf[1]); // 发送地址
rxData = SPI2_ReadWriteByte(txBuf[2]); // 获取数据
CS_HIGH(); // 释放片选
return rxData;
}
// 写寄存器(注意时序间隔)
void ADXL362_WriteReg(uint8_t addr, uint8_t value) {
uint8_t txBuf[3] = {0x0A, addr, value}; // 写命令+地址+数据
CS_LOW();
for(int i=0; i<3; i++) {
SPI2_ReadWriteByte(txBuf[i]);
Delay_us(10); // 关键延时!
}
CS_HIGH();
}
有个坑我踩过:写寄存器后必须加至少10us延时,否则可能写入失败。这是因为ADXL362需要时间处理写入操作。读寄存器时那个"空数据"发送也很关键——SPI是全双工通信,必须发送数据才能接收数据。
4. 加速度数据采集实现
获取三轴加速度数据是基础功能,但要做好需要处理以下细节:
- 初始化配置:
c复制void ADXL362_Init(void) {
ADXL362_WriteReg(0x2D, 0x02); // 进入测量模式
ADXL362_WriteReg(0x2C, 0x03); // 100Hz输出速率
ADXL362_WriteReg(0x20, 0x04); // 量程±4g
}
- 数据读取优化:
c复制void ADXL362_ReadXYZ(int16_t *x, int16_t *y, int16_t *z) {
uint8_t buf[6];
CS_LOW();
SPI2_ReadWriteByte(0x0B); // 读命令
SPI2_ReadWriteByte(0x08); // X轴数据低字节地址
buf[0] = SPI2_ReadWriteByte(0x00); // X_L
buf[1] = SPI2_ReadWriteByte(0x00); // X_H
buf[2] = SPI2_ReadWriteByte(0x00); // Y_L
buf[3] = SPI2_ReadWriteByte(0x00); // Y_H
buf[4] = SPI2_ReadWriteByte(0x00); // Z_L
buf[5] = SPI2_ReadWriteByte(0x00); // Z_H
CS_HIGH();
*x = (int16_t)((buf[1]<<8) | buf[0]);
*y = (int16_t)((buf[3]<<8) | buf[2]);
*z = (int16_t)((buf[5]<<8) | buf[4]);
}
实测发现两个优化点:1) 连续读取6个字节比分开读效率高;2) 数据需要转换为有符号整型。ADXL362的分辨率是1mg/LSB,在±4g量程下,实际加速度值 = 读数×0.004。
5. 运动检测功能深度解析
运动检测是ADXL362的杀手锏功能,特别适合低功耗场景。完整实现流程如下:
- 参数配置:
c复制// 运动检测阈值设置(示例值)
#define MOTION_THRESHOLD 50 // 约0.2g
#define MOTION_TIME 5 // 持续5个采样周期
void Motion_Config(void) {
ADXL362_WriteReg(0x20, MOTION_THRESHOLD); // 运动阈值低字节
ADXL362_WriteReg(0x21, 0x00); // 高字节固定0
ADXL362_WriteReg(0x22, MOTION_TIME); // 持续时间
ADXL362_WriteReg(0x27, 0x01); // 使能运动检测
}
- 状态检测优化:
c复制uint8_t Check_Motion(void) {
uint8_t status = ADXL362_ReadReg(0x0B); // 状态寄存器
if(status & 0x01) { // 检测到位0是运动标志
ADXL362_ReadReg(0x0C); // 读FIFO清除状态
return 1;
}
return 0;
}
实际项目中我发现,运动检测的响应时间与ODR(输出数据速率)设置强相关。当设置为100Hz时,检测延迟约10ms;6.25Hz时延迟可达160ms。建议根据应用场景权衡功耗和响应速度。
6. 低功耗优化技巧
ADXL362最大的优势就是超低功耗,通过以下配置可实现最优功耗:
- 工作模式选择:
c复制void Set_LowPowerMode(void) {
ADXL362_WriteReg(0x2D, 0x02); // 测量模式
ADXL362_WriteReg(0x2C, 0x02); // 12.5Hz ODR
ADXL362_WriteReg(0x1F, 0x40); // 开启自动休眠
}
- 中断唤醒方案:
c复制// 配置INT1引脚为运动中断输出
ADXL362_WriteReg(0x2A, 0x01);
// 在STM32端设置外部中断
void EXTI_Config(void) {
GPIO_InitTypeDef GPIO_InitStructure;
EXTI_InitTypeDef EXTI_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0);
EXTI_InitStructure.EXTI_Line = EXTI_Line0;
EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Rising;
EXTI_InitStructure.EXTI_LineCmd = ENABLE;
EXTI_Init(&EXTI_InitStructure);
}
实测电流:全功能模式约3μA,运动唤醒模式仅300nA。配合STM32的低功耗模式,可使整个系统续航时间大幅延长。
7. 常见问题排查手册
在实验室调试时遇到过各种奇怪问题,这里总结几个典型case:
问题1:读取的加速度值始终为0
- 检查SPI模式是否为CPOL=0/CPHA=0
- 确认VDD电压≥2.0V
- 测量CS信号是否正常拉低
问题2:运动检测不触发
- 检查STATUS寄存器值
- 确认THRESHOLD寄存器已正确写入
- 测试INT1引脚是否有信号输出
问题3:数据跳动严重
- 尝试降低SPI时钟速度
- 检查PCB布局,缩短走线长度
- 在VDD引脚添加0.1μF去耦电容
问题4:无法唤醒MCU
- 确认EXTI中断配置正确
- 检查ADXL362的中断映射寄存器(0x2A)
- 测试INT1引脚电压变化
有个特别隐蔽的bug:当STM32的GPIO速度设置为2MHz时,SPI通信偶尔会出错。将GPIO_InitStructure.GPIO_Speed设为50MHz后问题消失。
