简介:基于STM32控制英飞凌BGT24MTR11毫米波雷达芯片的嵌入式工程资料,面向嵌入式开发者和雷达信号处理初学者,重点解决雷达芯片驱动、I/Q信号采集、FFT频谱分析以及目标距离解算等核心问题。压缩包共637个文件、约14MB,以C源文件(347个)和头文件(116个)为主,同时包含IAR EWARM工程配置(ewp/eww/icf链接脚本)、编译批处理bat、DSP库FFT初始化文件(arm_rfft_init等)、RADAR.ioc与.mxproject,目录覆盖Src、Inc、Drivers等,导入开发环境即可查看完整代码结构。内容提供了从GPIO、SPI/I2C底层配置,到ADC采样、快速傅里叶变换、峰值检测与距离计算的全链路实现参考;可以学习I/Q双通道数据处理、阈值筛选和峰值提取方法,还可借鉴工程中驱动文件与头文件的分层划分方式,对规范嵌入式项目组织、减少调试时间很有帮助。目前已有1662人学习/下载,适合需要快速上手STM32与毫米波雷达结合应用的初中级开发者。 stm32雷达传感器BGT24MTR11入门控制:从硬件接线到多普勒测速实操
做嵌入式这几年,各种传感器玩了不少,但毫米波雷达这块一直感觉有点门槛。直到最近把手上的STM32和英飞凌的BGT24MTR11这颗24GHz雷达收发芯片搭在一起,才觉得这件事其实没有想象中那么复杂。这颗芯片在运动检测、存在感应、速度测量这些场景里用得非常多,比如智能家居的人体存在检测、工业设备的速度反馈、甚至一些低成本的安防探测,都能看到它的影子。
这篇博文我打算从一个完整的项目视角来拆解,怎么用STM32把BGT24MTR11跑起来。无论你是刚入门嵌入式的学生,还是想快速评估这颗雷达芯片的工程师,都可以参考我走过的路子,不用重复踩坑。项目本身不复杂,但涉及的高速SPI配置、中频信号采集、FFT处理这些环节,每一块都有不少细节值得抠。
1. 项目整体设计与硬件思路
1.1 BGT24MTR11是什么:从射频前端到中频输出
先理清楚芯片定位。BGT24MTR11是英飞凌推出的一款24GHz ISM频段的硅锗雷达收发器,内部集成了VCO(压控振荡器)、功率放大器、低噪声放大器、混频器等核心射频单元。它本身不是一个带完整信号处理的SoC,不直接输出“有人来了”这种结果,而是把目标的距离、速度信息转换成中频(IF)模拟信号输出,由外部MCU负责采样和处理。
这么说可能有点抽象,打个比方:BGT24MTR11就像雷达系统的“眼睛和耳朵”,负责发射24GHz的电磁波,接收目标反射回来的回波,然后通过混频器把高频信号降频成一个频率较低、方便ADC采样的中频信号。至于“看到了什么”“目标移动多快”,需要STM32这类后级处理器去从IF信号里“解读”。这颗芯片配合不同的天线设计,可以做成单通道多普勒雷达,也可以做成FMCW(调频连续波)雷达,前者测速度,后者还能测距离。
所以在项目规划阶段,第一件事不是写代码,而是明确你要用它做什么。如果只想做运动检测和速度测量,BGT24MTR11工作在单音模式(Single Tone)下,STM32只需要采集中频信号做FFT就能得到多普勒频移;如果你想测量目标的绝对距离,那需要配置成FMCW模式,对三角波调制和信号处理的要求会高一个台阶。大多数入门项目,包括我这次做的,都会先从多普勒模式落地。
1.2 方案选型:为什么选STM32而不是其他主控
选STM32作为主控,主要是三个原因:ADC采样率够用、SPI接口方便、生态资料丰富。
BGT24MTR11的中频输出信号频率范围,在多普勒模式下通常在几百赫兹到几十千赫兹之间,具体取决于目标径向速度。比如一个以5m/s速度靠近雷达的目标,在24GHz频段产生的多普勒频移大约是800Hz左右,这个频率太低了,反而要求ADC的采样率不用特别夸张,STM32F103系列内置的12位ADC跑几十kHz到上百kHz完全没有压力。当然,如果你要同时处理距离维的FMCW信号,需要更高的采样率和更多计算资源,可以考虑STM32F4或H7系列。
SPI接口方面,BGT24MTR11的配置寄存器需要通过SPI写入,STM32的硬件SPI天然适合。不过要注意,这颗芯片的SPI是16位数据格式,不是常见的8位,配置时需要做位封装处理。这一点网上很多人踩坑,我后面会详细讲。
开发环境选型,如果你习惯标准外设库,可以用Keil MDK搭配STM32标准库;如果你追求效率,STM32CubeMX加HAL库会更省事。我这个项目用的是HAL库,原因是CubeMX生成的初始化代码结构清晰,后期移植也方便。需要注意的是,BGT24MTR11的数据手册和寄存器说明可以直接在英飞凌官网下载,拿到芯片后第一时间把手册完整读一遍,尤其是SPI时序图和寄存器映射表,这两个文档是开发的“宪法”。
2. 核心细节解析与驱动原理
2.1 寄存器配置与SPI通信的细节坑
BGT24MTR11的SPI接口是16位数据宽度的从机接口,所有配置寄存器都是16位地址、16位数据。这里最大的坑在于,STM32的硬件SPI默认支持8位或16位数据帧格式。你用16位模式直接通信本来没问题,但芯片的写入时序要求先传地址、再传数据,而且是连续16位的命令帧,地址和数据在一个片选周期内完成。
正确做法是把地址和数据的16位拼成一个32位变量,然后分两次16位传输,或者干脆把SPI配置成8位,用字节流拼帧。我试过硬件16位模式,在片选拉低后连续发送两个16位数据,实测也能工作,但必须保证字节序和位序都跟手册一致。最简单可靠的方式是:
void BGT24MTR11_WriteReg(uint16_t regAddr, uint16_t regVal) { uint16_t addrFrame = (regAddr & 0x7FFF) | 0x8000; // 写入标志位 uint16_t dataFrame = regVal; CS_LOW(); HAL_SPI_Transmit(&hspi1, (uint8_t*)&addrFrame, 2, 10); HAL_SPI_Transmit(&hspi1, (uint8_t*)&dataFrame, 2, 10); CS_HIGH(); }注意addrFrame的最高位是读写标志,写操作置1,读操作清0。这个标志位加上16位地址,实际上地址空间只有15位可用,但BGT24MTR11寄存器数量远少于这个量,完全够用。另外,HAL_SPI_Transmit是按字节处理数据的,你要确保16位数据在数组中的字节序是小端还是大端,取决于芯片手册里时序图上MSB还是LSB先出。BGT24MTR11是MSB先出,所以在字节发送前要做好位序整理。
2.2 中频信号采样与FFT处理的核心逻辑
BGT24MTR11输出的是模拟中频信号,直接接STM32的ADC引脚即可。但这里有个容易被忽略的问题:中频信号的直流偏置和幅度范围。
芯片输出的IF信号通常是以某个直流电平为中心的小幅度交流信号,这个直流电平可能在1V到1.5V之间,而STM32的ADC参考电压一般是3.3V或3.0V(取决于VDDA接法)。如果直接采样,信号动态范围利用率不高。我的做法是加一级RC高通滤波器把直流分量隔掉,再用一个运算放大器做幅度放大和电平偏置,把信号搬到ADC的输入范围内。如果你不想引入额外器件,也可以直接用ADC测量原始IF信号,但检测灵敏度和距离会受影响。
FFT部分是整个项目的软件核心。STM32F103这种Cortex-M3内核没有硬件FPU,也没有DSP指令集,做FFT运算需要arm_cortexM3l_math库的软件实现。你可以从STM32官方DSP库中选用已优化的FFT函数。下面是典型的处理流程:
// 采样512点,16位ADC值,转成q15格式做FFT arm_q15_to_float(adc_buf, fft_input, FFT_SIZE); arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_input, 0, 1); arm_cmplx_mag_f32(fft_input, fft_output, FFT_SIZE);采样点数我选512,因为FFT分辨率等于采样率除以点数。如果采样率是20kHz,512点FFT对应的频率分辨率约为39Hz,这对应目标速度分辨率大约0.24m/s,对大多数人体运动检测场景已经够用。点数太多,STM32F103的计算时间会显著上升,实时性反而变差。
FFT之后要做峰值检测,找到幅度最大的频点,再根据多普勒公式换算速度:
- 多普勒频移公式:fd = 2 * v * f0 / c
- 其中f0 = 24GHz,c = 3×10^8 m/s
- 目标速度v = fd * c / (2 * f0) = fd * 0.00625 m/s(fd单位是Hz)
比如FFT峰值落在800Hz,对应目标速度就是5m/s。这个换算关系非常直接,实际工程中还会根据天线安装角度做余弦修正。
3. 实操过程与核心环节实现
3.1 硬件准备与接线清单
先列出我实际用的物料清单,方便你照方抓药:
| 器件 | 型号/规格 | 数量 | 备注 |
|---|---|---|---|
| 主控板 | STM32F103C8T6最小系统板 | 1 | 蓝色Pill板,性价比高 |
| 雷达模块 | 基于BGT24MTR11的24GHz雷达模块 | 1 | 注意区分是否带天线和功放 |
| 运放 | MCP6002或LM358 | 1 | 中频信号调理 |
| 电源 | 3.3V LDO稳压模块 | 1 | 雷达芯片对电源纹波敏感 |
| 调试器 | ST-Link V2 | 1 | 下载和调试 |
| 连接线 | 杜邦线若干 | - | 尽量短,减少干扰 |
我强烈建议买那种已经集成好天线的BGT24MTR11模块,比如一些评估板或第三方模块,而不是自己画射频PCB。24GHz的射频layout对普通人来说调试成本极高,天线阻抗匹配、微带线间距、过孔设计都会影响辐射效率和接收灵敏度。模块化开发可以把精力集中在STM32端,先跑通整个链路,再考虑要不要深入射频部分。
接线方面,BGT24MTR11模块上的SPI接口(CS、CLK、SDI、SDO)分别接STM32的PB12、PB13、PB15、PB14,也就是SPI2的硬件引脚。中频输出IF_OUT接运放输入端,运放输出接STM32的PA0(ADC1通道0)。电源部分特别注意,雷达模块的VCC和STM32的3.3V最好分开供电,或者至少用磁珠做隔离,否则雷达工作时产生的电源噪声会串进ADC采样,导致FFT频谱上出现杂散峰。
3.2 STM32CubeMX工程配置要点
用CubeMX初始化工程时,有几个配置点要特别留意,直接影响后续代码是否能跑通。
时钟树方面,系统时钟设置为72MHz(STM32F103最高主频),APB1总线时钟36MHz,APB2总线时钟72MHz。ADC挂在APB2上,可以拿到72MHz的输入时钟,经过分频后给ADC模块使用。SPI2挂在APB1上,36MHz的输入时钟,分频后用于SPI通信。
ADC配置注意几个参数:
- 采样分辨率12位,这是F103的上限
- 采样时间设置到最大(239.5周期),降低源阻抗对采样精度的影响
- 开启连续转换模式或扫描模式,配合DMA传输
DMA是必须的,如果不开启DMA,在中断里逐个读ADC值会占用大量CPU时间,导致FFT计算卡顿。我配置DMA循环模式,每次采集512个点后自动触发一次DMA传输完成中断,在中断回调里置一个标志位,主循环检测到标志再执行FFT。
SPI配置相对简单,CPOL和CPHA设置为模式0(即空闲低电平、第一个边沿采样),速度设置为2.25MHz。BGT24MTR11的最高SPI时钟频率在10MHz左右,但STM32F103的硬件SPI在从机模式下有时序要求,2.25MHz是一个稳妥的选择。如果你发现SPI通信不稳定,优先降低时钟频率,不要一上来就拉满。
3.3 初始化序列与上电流程实操
BGT24MTR11的上电流程有严格的时序要求,简单说就是:先供电,等待电源稳定,然后释放复位引脚,再通过SPI写入初始寄存器配置。
实际代码中,我会按以下顺序操作:
void BGT24MTR11_Init(void) { // 1. 确保复位引脚拉低 HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_RESET); HAL_Delay(10); // 2. 释放复位 HAL_GPIO_WritePin(RST_GPIO_Port, RST_Pin, GPIO_PIN_SET); HAL_Delay(50); // 3. 写基础配置寄存器 BGT24MTR11_WriteReg(0x0000, 0x0001); // 使能内部稳压器 BGT24MTR11_WriteReg(0x0010, 0x0003); // 配置VCO分频器 BGT24MTR11_WriteReg(0x0011, 0x00A0); // 设置发射功率 // 4. 等待PLL锁定 HAL_Delay(100); // 5. 设置工作模式 BGT24MTR11_WriteReg(0x0001, 0x0000); // 单音模式 }这些寄存器地址和值是我根据BGT24MTR11数据手册的推荐配置整理出来的,不同批次或不同封装的芯片可能会有差异。关键一点是,每次写完寄存器之后,都要回读验证一下,确保写入成功。我遇到过SPI时序不对导致寄存器写不进去的情况,表现为芯片完全没有中频输出,PCB上检查了半天才发现是片选时序问题。
上电到开始采样的等待时间也很重要,PLL需要大约几十毫秒的锁定时间。如果PLL没锁定就采集IF信号,频谱上会出现大量非目标的杂散频率,导致误判。一个简单的判断方法是:上电后先采集一段中频信号做FFT,如果频谱在0Hz附近有一个非常大的直流分量且无明显多普勒峰,大概率是PLL未锁定或芯片未进入正确工作模式。
3.4 数据采集、FFT与速度计算的完整代码框架
以下是整个信号处理链路的精简版实现。为了让代码可读性高,我按功能分成了三个模块:ADC采集、FFT处理、结果输出。
#define FFT_SIZE 512 float fft_input[FFT_SIZE * 2]; // 复数数组,实虚交替 float fft_output[FFT_SIZE]; // 幅值谱 volatile uint8_t adc_complete_flag = 0; uint16_t adc_buffer[FFT_SIZE]; // DMA传输完成回调 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef *hadc) { if (hadc->Instance == ADC1) { adc_complete_flag = 1; } } // 主循环中的处理逻辑 while (1) { if (adc_complete_flag) { adc_complete_flag = 0; // 转浮点并做归一化 for (int i = 0; i < FFT_SIZE; i++) { fft_input[2*i] = ((float)adc_buffer[i] - 2048.0f) / 2048.0f; fft_input[2*i+1] = 0.0f; } // 加汉宁窗,减少频谱泄漏 for (int i = 0; i < FFT_SIZE; i++) { float win = 0.5f * (1.0f - cosf(2.0f * PI * i / (FFT_SIZE - 1))); fft_input[2*i] *= win; } // 执行FFT arm_cfft_f32(&arm_cfft_sR_f32_len512, fft_input, 0, 1); arm_cmplx_mag_f32(fft_input, fft_output, FFT_SIZE); // 找峰值(跳过直流分量,从第3个点开始) uint16_t peak_index = 3; float peak_mag = 0; for (int i = 3; i < FFT_SIZE / 2; i++) { if (fft_output[i] > peak_mag) { peak_mag = fft_output[i]; peak_index = i; } } // 计算频率和速度 float freq = (float)peak_index * SAMPLE_RATE / FFT_SIZE; float speed = freq * 0.00625f; // m/s // 通过串口输出 char msg[64]; sprintf(msg, "freq:%.1fHz speed:%.2fm/s peak:%.3f\r\n", freq, speed, peak_mag); HAL_UART_Transmit(&huart1, (uint8_t*)msg, strlen(msg), 100); } }有几点值得细说。第一,加窗函数是必要的,如果不加窗,FFT频谱会因为矩形窗的旁瓣泄漏在真实峰值附近出现很多伪峰,特别是目标速度很低的时候,低频段的泄漏几乎会把真实信号淹没。我这里用汉宁窗,综合性能比较平衡。第二,跳过前3个FFT点是因为直流分量和极低频噪声会在这里形成很大的幅值,如果不跳过,峰值检测永远会锁定在0Hz附近,什么都测不出来。第三,sprintf输出字符串方便观察,但实际产品中建议直接传输float的二进制数据,或者转成工程单位再打包,减少带宽浪费。
4. 常见问题与调试技巧实录
4.1 典型问题排查:雷达模块没输出、FFT频谱异常、检测距离太短
做这个项目过程中,我遇到了一些坑,这些案例也经常在论坛上看到,这里整理成表格方便对照排查。
| 现象 | 可能原因 | 解决方法 |
|---|---|---|
| SPI写入无响应 | CS时序不对、SCK极性/相位配置错误 | 用逻辑分析仪抓SPI时序,对照手册逐位核对 |
| 上电后IF输出一直是直流 | PLL未锁定、寄存器写入失败 | 回读寄存器验证,加长PLL锁定等待时间 |
| FFT在0Hz附近有一个巨大峰值 | 直流偏置未消除、采样点数太少 | 加高通滤波或软件去直流,增大FFT点数 |
| 人走过时检测不到 | 中频信号幅度太小、阈值设置过高 | 增大运放增益,降低峰值检测阈值 |
| 检测距离只有几十厘米 | 发射功率寄存器配置过低、天线方向不对 | 检查发射功率寄存器,重新调整天线朝向 |
首先要说的是SPI通信不稳定的排查方法。如果寄存器写不进去,你用示波器或逻辑分析仪看CS、SCK、SDI三根线的时序。重点看CS拉低期间,SCK是否保持稳定,SDI数据是否在SCK的有效边沿前建立。BGT24MTR11的数据手册里有时序图,对照着看很直观。我遇到的一次问题是GPIO复用配置错误,导致CS引脚拉低后自动被SPI外设控制,波形完全乱套。
其次是FFT频谱异常的处理思路。如果你看到0Hz附近有巨大的直流分量,可以先检查硬件上有没有加隔直电容。如果没有,软件上可以做一个简单的去直流处理:在FFT之前计算512个采样点的平均值,然后每个采样点减去这个平均值。这个方法在硬件改动不便时很有效,代价是会损失一点低频分量的精度,但对测速场景影响不大。
关于检测距离太短的问题,我建议先确认你的BGT24MTR11模块是否带功率放大器。裸片BGT24MTR11的输出功率只有几个dBm,不带PA的话有效检测距离可能在2-3米左右。如果模块上集成了PA和LNA,检测距离可以延伸到十几米甚至更远。另外天线增益也很关键,如果你的模块用的是PCB天线,指向性可能比较强,人站在正对天线方向时检测距离最远,侧面灵敏度会明显下降。
4.2 调参经验:采样率、FFT点数与实时性的取舍
采样率、FFT点数、实时性这三者之间是互相制约的关系,需要根据你的场景做取舍。
如果你主要测人的走动速度(1~2m/s),多普勒频移在160Hz到320Hz之间,采样率不需要太高,8kHz就够用了。采样率太高反而会让FFT分辨率变差,一个频点对应的速度范围变大,测速精度下降。我的经验是采样率设置为目标最大速度对应多普勒频移的4~6倍即可。
STM32F103因为主频只有72MHz,还不能做浮点运算加速,用软件FFT库算512点FFT大约需要几毫秒,再加上采样时间和串口输出时间,整体循环周期大概在30~50ms。这个速度对于做存在检测或速度显示完全够用,但如果你想拿来做实时闭环控制,比如根据雷达数据控制电机转速,那建议换STM32F4系列,硬件FPU可以把FFT加速好几倍。
还有一个容易被忽视的点:ADC采样触发方式。我用的是ADC连续采样加DMA搬运,采样率由ADC时钟和采样时间决定,并没有用定时器触发。这么做的好处是代码简单,但坏处是采样间隔不均匀,会导致频谱出现微小畸变。如果你对测速精度要求高,可以改用定时器触发ADC采样,确保严格等间隔采样。实现方法是配置一个定时器(比如TIM2)输出PWM信号,PWM周期对应采样周期,PWM输出引脚连接到ADC的触发输入端TRGO,ADC配置为外部触发采样。
4.3 我对这个项目的一些扩展思考
BGT24MTR11和STM32的组合,做一个基础测速demo只算入门。我后来在这个基础上扩展了三个方向,各有各的挑战。
第一个方向是人体存在检测,应用场景是智能家居的室内人员感知。区别在于不再需要精确速度,而是对微弱的人体微动信号(呼吸引起的胸腔起伏)进行检测。呼吸引起的躯干位移大概是几毫米,产生的多普勒频移只有几赫兹,这就要求ADC采样率更低、FFT点数更多,并且要加一个带通滤波器把低频段之外的噪声滤除。我用STM32F401重新实现了这个方案,效果还比较理想。
第二个方向是FMCW测距。这需要BGT24MTR11配合外部PLL或调制信号,实现频率线性扫描,然后把混频输出的中频信号做FFT来解算距离。相比多普勒模式,硬件复杂度增加不少,STM32需要额外控制VCO调制电压,同时处理距离维和速度维两维FFT,对嵌入式工程师的综合能力要求比较高。
第三个方向是数据融合,就是让STM32同时接入BGT24MTR11雷达和PIR红外传感器。雷达负责感知运动、PIR负责感知温度变化,两者逻辑与之后再触发报警,可以大幅降低误报率。这个方案我实际部署在小型安防设备上,效果比单一传感器稳定很多。
最后说点实在的
回头再看这个项目,核心价值其实不在于“把BGT24MTR11驱动起来”这一件事本身,而在于完整走通了一条射频传感器 + MCU + 信号处理的链路。这条链路里涉及的SPI时序、ADC采样、FFT分析、阈值判断,几乎是所有嵌入式信号处理项目的公共底座。BGT24MTR11的数据手册我前前后后翻了不下十遍,很多细节是第一次看根本注意不到的,比如SPI读时序里返回数据的那几个占空周期,还有VCO校准寄存器的默认值在不同芯片上的差异。这些东西只能靠实践去积累。
最后给正在做类似项目的朋友一个建议:先把最基本的多普勒测速跑通,再往复杂功能扩展。遇到问题不要急着怀疑芯片坏了,先用逻辑分析仪看波形,用串口打印中间变量,一步步缩小问题范围。嵌入式开发的绝大多数问题,都出在“你以为配置对了,但实际上没有”的地方。
本文还有配套的精品资源,点击获取