news 2026/3/27 18:53:06

66、SPI驱动ADXL345加速度计

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
66、SPI驱动ADXL345加速度计

SPI驱动ADXL345加速度计

一、SPI协议核心原理

SPI是全双工、同步、主从式的通信总线,想要驱动外设,先吃透物理层连线和时序规则。

1.1 物理层:四线制连接逻辑

SPI标准四线制的每根线都有明确分工,IMX6ULL(主设备)与ADXL345(从设备)的具体连线如下:

信号线功能说明IMX6ULL引脚(ECSPI3)ADXL345引脚
SCLK串行时钟,主设备产生UART2_RX_DATASCLK
MOSI主发从收UART2_CTS_BMOSI
MISO主收从发UART2_RTS_BMISO
CS/SS从机选择(低电平有效,GPIO模拟)UART2_TX_DATA(GPIO1_IO20)CS

注:IMX6ULL的ECSPI3本身自带硬件CS,但本文用GPIO模拟CS,更灵活,也便于新手理解“片选”的核心逻辑。

1.2 时序规则:CPOL与CPHA决定通信模式

SPI的时序由两个关键参数定义:CPOL(时钟极性)CPHA(时钟相位),组合出4种通信模式,ADXL345推荐使用模式3(CPOL=1,CPHA=1)

参数含义模式3配置
CPOL时钟闲置时的电平:0=低电平闲置,1=高电平闲置1
CPHA数据采样边沿:0=时钟第1个边沿采样,1=时钟第2个边沿采样1

模式3的时序逻辑:

  • SCLK空闲时保持高电平;
  • 主设备在SCLK的下降沿发送数据,从设备在SCLK的上升沿采样数据(第二个边沿)。

二、IMX6ULL ECSPI控制器:从引脚到寄存器配置

IMX6ULL的SPI控制器称为ECSPI(增强型可配置SPI),我们以ECSPI3为例,完成底层硬件初始化。

2.1 引脚复用配置

IMX6ULL的引脚是多功能的,需要先将对应引脚复用为ECSPI3功能,并配置电气特性(上拉、速率等)。

#include"imx6ull.h"// 引脚复用配置函数(底层寄存器封装,无需修改)voidIOMUXC_SetPinMux(unsignedintmux_register,unsignedintmux_mode);voidIOMUXC_SetPinConfig(unsignedintconfig_register,unsignedintconfig_value);// ECSPI3引脚初始化voidspi3_pin_init(void){// 1. MISO:UART2_RTS_B复用为ECSPI3_MISOIOMUXC_SetPinMux(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0);IOMUXC_SetPinConfig(IOMUXC_UART2_RTS_B_ECSPI3_MISO,0x10B1);// 上拉、速率100MHz// 2. MOSI:UART2_CTS_B复用为ECSPI3_MOSIIOMUXC_SetPinMux(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0);IOMUXC_SetPinConfig(IOMUXC_UART2_CTS_B_ECSPI3_MOSI,0x10B1);// 3. SCLK:UART2_RX_DATA复用为ECSPI3_SCLKIOMUXC_SetPinMux(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0);IOMUXC_SetPinConfig(IOMUXC_UART2_RX_DATA_ECSPI3_SCLK,0x10B1);// 4. CS:UART2_TX_DATA复用为GPIO1_IO20IOMUXC_SetPinMux(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0);IOMUXC_SetPinConfig(IOMUXC_UART2_TX_DATA_GPIO1_IO20,0x10B1);// GPIO1_IO20设为输出,初始高电平(未选中ADXL345)GPIO1->GDIR|=(1<<20);GPIO1->DR|=(1<<20);}

2.2 ECSPI3寄存器核心配置

IMX6ULL的ECSPI控制器核心配置在CONREG(控制寄存器)和CONFIGREG(配置寄存器),重点是匹配ADXL345的模式3时序,同时设置主机模式、数据长度、时钟分频。

// ECSPI3初始化:配置时序、模式、数据长度voidspi3_init(void){// 1. 先初始化引脚spi3_pin_init();// 2. 复位CONREG寄存器ECSPI3->CONREG=0;/* CONREG参数解析: * 7<<20:BURST_LENGTH=7 → 数据长度8位(0~7共8位) * 0x0E<<12:CLK_CTL=14 → 时钟分频(IPG_CLK=66MHz → 66/(14+1)=4.4MHz,适配ADXL345) * 2<<8:CHIP_SELECT=2 → 选择通道0(ECSPI3_CH0) * 1<<4:MODE=1 → 主机模式 * 1<<3:SCLK_CTL=1 → 时钟由CONREG的CLK_CTL控制 * 1<<0:ENABLE=1 → 使能ECSPI3 */ECSPI3->CONREG|=(7<<20)|(0x0E<<12)|(2<<8)|(1<<4)|(1<<3)|(1<<0);// 3. 复位CONFIGREG寄存器ECSPI3->CONFIGREG=0;/* CONFIGREG参数解析: * 1<<20:SCLK_POL=1 → CPOL=1(时钟高电平闲置) * 1<<4:MOSI_POL=0 → MOSI引脚极性正常(无需翻转) * 1<<0:PHASE=1 → CPHA=1(第二个边沿采样) */ECSPI3->CONFIGREG|=(1<<20)|(1<<4)|(1<<0);}

三、ADXL345驱动实现:SPI读写+传感器控制

ADXL345的核心操作是“读写寄存器”——通过SPI向传感器寄存器写配置、读数据,先实现SPI底层读写,再封装传感器专属接口。

3.1 SPI全双工读写基础函数

SPI是全双工通信:发送1个字节的同时,必然会接收1个字节。因此读写函数的核心是“发数据+等接收”,利用ECSPI的TX/RX FIFO完成数据传输。

// SPI3通道0读写函数:发送1字节,同时接收1字节(全双工)unsignedintspi3_ch0_write_and_read(unsignedintdata){// 等待发送FIFO为空(准备好接收新数据)while((ECSPI3->STATREG&(1<<0))==0);// 往TXDATA写入要发送的数据ECSPI3->TXDATA=data;// 等待接收FIFO有数据(数据已接收完成)while((ECSPI3->STATREG&(1<<3))==0);// 返回接收到的数据returnECSPI3->RXDATA;}

3.2 ADXL345寄存器读写封装

ADXL345的寄存器读写有固定规则:

  • 读操作:寄存器地址最高位置1(reg_addr | 0x80),发送地址后发0xFF(伪数据)触发时钟,读取返回值;
  • 写操作:寄存器地址最高位清0,发送地址后发送要写入的数据。
// ADXL345读寄存器:reg_addr=寄存器地址,返回寄存器值unsignedcharadxl345_read(unsignedcharreg_addr){unsignedcharret=0;// 1. 拉低CS,选中ADXL345GPIO1->DR&=~(1<<20);// 2. 发送读指令(地址最高位1)spi3_ch0_write_and_read(reg_addr|0x80);// 3. 发送伪数据0xFF,读取传感器返回值ret=spi3_ch0_write_and_read(0xFF);// 4. 拉高CS,结束通信GPIO1->DR|=(1<<20);returnret;}// ADXL345写寄存器:reg_addr=寄存器地址,data=要写入的值voidadxl345_write(unsignedcharreg_addr,unsignedchardata){// 1. 拉低CS,选中ADXL345GPIO1->DR&=~(1<<20);// 2. 发送写指令(地址最高位0)spi3_ch0_write_and_read(reg_addr&~0x80);// 3. 发送要写入的数据spi3_ch0_write_and_read(data);// 4. 拉高CS,结束通信GPIO1->DR|=(1<<20);}

3.3 ADXL345初始化与数据采集

ADXL345使用前需要初始化(配置量程、进入测量模式),然后读取三轴加速度数据(16位,低位在前)。

// 定义ADXL345数据结构体:存储X/Y/Z三轴加速度值typedefstruct{shortx;// X轴加速度shorty;// Y轴加速度shortz;// Z轴加速度}ADXL345_Data;// ADXL345初始化:验证ID+配置量程+进入测量模式intadxl345_init(void){unsignedchardev_id;// 1. 读取设备ID(DEVID寄存器地址0x00,固定值0xE5)dev_id=adxl345_read(0x00);if(dev_id!=0xE5){return-1;// ID错误,初始化失败}// 2. 配置DATA_FORMAT(0x31):±16g量程(0x0F)adxl345_write(0x31,0x0F);// 3. 配置POWER_CTL(0x2D):0x08 → 进入测量模式adxl345_write(0x2D,0x08);return0;// 初始化成功}// 读取ADXL345三轴加速度数据ADXL345_Dataadxl345_read_data(void){ADXL345_Data data;// X轴:低字节(0x32) + 高字节(0x33)data.x=adxl345_read(0x32);data.x|=(short)(adxl345_read(0x33)<<8);// Y轴:低字节(0x34) + 高字节(0x35)data.y=adxl345_read(0x34);data.y|=(short)(adxl345_read(0x35)<<8);// Z轴:低字节(0x36) + 高字节(0x37)data.z=adxl345_read(0x36);data.z|=(short)(adxl345_read(0x37)<<8);returndata;}

四、主函数测试:验证SPI驱动是否正常

最后写主函数,初始化硬件后循环读取加速度数据,可通过串口打印(需提前实现串口初始化)。

intmain(void){ADXL345_Data accel_data;// 1. 初始化SPI3spi3_init();// 2. 初始化ADXL345if(adxl345_init()!=0){// 串口打印ID错误(需实现uart_printf)uart_printf("ADXL345 init failed! ID error\r\n");while(1);}uart_printf("ADXL345 init success!\r\n");// 3. 循环读取三轴数据while(1){accel_data=adxl345_read_data();// 打印X/Y/Z轴数据uart_printf("X: %d, Y: %d, Z: %d\r\n",accel_data.x,accel_data.y,accel_data.z);// 简单延时for(inti=0;i<1000000;i++);}return0;}

五、实战调试:常见问题排查

新手最容易遇到“ID读取为0/255”或“数据乱跳”,按以下步骤排查:

5.1 ID读取异常(0/255)

  1. 硬件连线:检查SCLK/MOSI/MISO/CS的引脚是否接反、虚焊;
  2. CS电平:用万用表测GPIO1_IO20,读寄存器时是否拉低,读完是否拉高;
  3. SPI模式:确认CONFIGREG的CPOL(1<<20)和CPHA(1<<0)是否配置正确(模式3);
  4. 时钟分频:ECSPI3的时钟不能超过ADXL345的最大速率(5MHz),本文分频后4.4MHz,符合要求;
  5. 逻辑分析仪抓波:观察MOSI是否发送了0x80(读ID指令),MISO是否返回0xE5

5.2 数据乱跳

  1. 电源稳定性:ADXL345需3.3V供电,确保电源纹波小;
  2. 接地:传感器的GND与IMX6ULL的GND共地,避免干扰;
  3. 量程配置:确认DATA_FORMAT寄存器配置的量程与数据解析匹配(如±16g对应分辨率13mg/LSB)。

六、总结

本文从SPI协议原理出发,完成了IMX6ULL ECSPI3的底层配置,再到ADXL345的寄存器读写封装,最终实现了三轴加速度数据的采集。核心要点:

  1. SPI的关键是时序匹配(CPOL/CPHA),必须与外设一致;
  2. IMX6ULL的ECSPI配置重点是“主机模式+数据长度+时钟分频”;
  3. ADXL345的核心是“寄存器读写规则”(读地址最高位1,写地址最高位0);
  4. 裸机开发中,“等待FIFO”“CS电平控制”是SPI通信的关键细节。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/27 18:18:29

RAG干货:为什么不同召回方式需要不同的chunk策略?看完收藏

文章探讨了RAG系统中语义召回和关键字召回对chunk策略的不同需求。语义召回看重语义相似性&#xff0c;适合有overlap的分块&#xff1b;而关键字召回更适合按段落或句子分块。作者提出混合召回方案&#xff0c;建议按段落和句子分块&#xff0c;配合强大embedding模型&#xf…

作者头像 李华
网站建设 2026/3/23 10:01:17

【干货收藏】企业AI Agent实战指南:从技术原理到工程落地,避坑指南

本文系统阐述企业级AI Agent技术路线&#xff0c;从核心原理到工程落地&#xff0c;解析多智能体架构、大模型应用、记忆机制、系统设计、安全保障及运维部署。强调AI Agent应作为新型生产力单元&#xff0c;具备理解目标、拆解任务、调用工具和闭环执行能力&#xff0c;提出从…

作者头像 李华
网站建设 2026/3/14 0:40:50

大数据深度学习|计算机毕设项目|计算机毕设答辩|基于图像识别的桥梁裂缝识别与检测系统设计与实现

一、项目介绍 随着图像识别技术的飞速发展&#xff0c;桥梁裂缝的智能识别与检测已成为桥梁维护领域的重要研究方向。本文介绍了一个基于Python和YOLO11模型的桥梁裂缝识别与检测系统。该系统结合先进的图像识别和深度学习技术&#xff0c;旨在实现对桥梁裂缝的准确、实时检测。…

作者头像 李华
网站建设 2026/3/21 17:21:34

[硬件设计]运放选型记录

ADS131A04 是一款高精度、同步采样的 24-bit $\Delta\Sigma$ 型 ADC&#xff0c;具有极高的动态范围和极低的噪声要求。而 LM358 是一款通用型、廉价的运算放大器&#xff0c;在精度和速度上完全无法匹配 24-bit ADC 的性能需求。 1. 为什么 LM358 会“拖累” ADS131A04&#x…

作者头像 李华
网站建设 2026/3/19 21:57:01

AI自己学会“地图细胞“和“秘密语言“!程序员:这波操作太秀了,代码都省了!

近日&#xff0c;香港城市大学博士生方政儒和所在团队让一群智能体在虚拟迷宫里共同探索&#xff0c;只给它们一个极其简单的目标——那就是学会预测同伴下一秒会看到什么以及会走到哪里。结果发现这些智能体不仅学会了高效合作&#xff0c;还在自己的“大脑”里自发形成了类似…

作者头像 李华
网站建设 2026/3/26 9:07:53

飞滴网约车项目Day01

今日完成 乘客用户中心服务 验证码发送 首先我们需要开发用户注册和登录功能&#xff0c;其中重点是乘客发送验证码&#xff0c;以下是发送验证码的时序图 REST ful 风格 在设计rest fuk 风格的时候&#xff0c;我们需要考虑以下的事情&#xff1a; 协议&#xff08;http&a…

作者头像 李华