基于STM32WB55的脑电采集系统设计:从模拟前端到蓝牙传输
2026/8/28 1:01:49 网站建设 项目流程

1. 项目缘起:当脑电波遇见嵌入式开发板

几年前,我在一个脑机接口(BCI)的爱好者聚会上,听到一个朋友抱怨:“想入门EEG(脑电图)采集,门槛也太高了!” 他指的不是算法,而是硬件。市面上的成品脑电采集设备,要么是价格高昂的科研级设备,动辄数万甚至数十万,要么是像NeuroSky、Muse这样的消费级头戴设备,虽然便宜,但接口封闭,数据格式不透明,采样率也有限,对于想深入折腾、理解底层原理的开发者来说,总觉得隔着一层纱。

当时我手里正好有一块ST的NUCLEO-WB55开发板。这块板子很有意思,它集成了一个STM32WB55微控制器,自带蓝牙5.0,还有丰富的模拟和数字外设。我就在想,STM32的ADC性能不差,运算能力也足够,为什么不能用它来做一个开源的、可深度定制的微型脑电采集前端呢?这个想法就是“MicroBCI”项目的起点。它的核心目标很明确:利用STM32 NUCLEO-WB55开发板,搭建一个从电极信号调理、模数转换、数据处理到无线传输的完整EEG信号采集原型系统。这不是一个玩具,而是一个旨在降低专业级脑电采集硬件入门门槛、提供完全透明数据流和控制权的开发平台。

EEG信号极其微弱,通常在微伏(μV)级别,并且淹没在强大的工频干扰(50/60Hz)、肌电(EMG)和眼电(EOG)噪声中。因此,一个可用的EEG采集系统,其核心挑战不在于单片机本身,而在于前端的模拟信号调理电路。MicroBCI项目正是要直面这个挑战,将STM32作为系统的“大脑”和“桥梁”,连接高要求的模拟世界和灵活的数字处理与通信。

2. 系统架构设计:从电极到数据包的全链路拆解

一个完整的EEG采集系统,信号链路可以清晰地划分为三个主要阶段:模拟前端(AFE)、数字处理核心、以及数据通信与输出。MicroBCI项目基于NUCLEO-WB55的硬件特性,对这三个阶段进行了针对性的设计。

2.1 模拟前端:信号调理的“战场”

这是整个系统中最关键、最考验设计功底的部分。STM32的ADC无法直接测量头皮上的微弱信号,我们必须构建一个模拟前端电路来完成信号的放大、滤波和驱动。

第一级:仪表放大器与高通滤波EEG信号是差分信号,我们需要测量两个活性电极之间的电位差,同时强力抑制共模干扰(如工频干扰)。因此,第一级必须使用仪表放大器。我选择了ADI的AD8221,这是一款经典的低噪声、高共模抑制比(CMRR)的仪放。它的高输入阻抗确保了不会从电极-皮肤界面汲取过多电流,影响信号质量。 在这一级,我们同时需要引入一个高通滤波器,以滤除由于电极半电池电位漂移、出汗等产生的极低频(<0.5 Hz)直流偏移和超低频噪声。一个简单的一阶RC高通网络放在仪放之前或之后均可。我将截止频率设定在0.5Hz,这对于大多数EEG应用(如α波8-13Hz,β波13-30Hz)是合适的起点。

第二级:增益放大与抗混叠滤波经过仪放初步放大和高速滤波后的信号,幅度可能仍在毫伏级别,需要进一步放大到适合STM32 ADC输入的范围(通常是0-3.3V)。这里我使用了一个同相放大电路作为第二级增益级。总增益需要仔细计算:假设EEG信号最大峰峰值约100μV,我们希望ADC输入最大动态范围在1V左右,那么总增益大约需要10000倍(80dB)。这个增益由仪放和后续放大级共同分担。 在第二级放大之后,必须加入一个抗混叠低通滤波器。根据奈奎斯特采样定理,如果我们的目标EEG带宽是0.5-50Hz,那么采样率至少需要100Hz。为了稳妥起见,我计划将采样率设为250Hz。抗混叠滤波器的截止频率应略高于信号最高频率(50Hz),但远低于采样率的一半(125Hz),我设定在70Hz左右,采用二阶有源低通滤波器(如Sallen-Key结构),以提供足够的滚降特性,防止高频噪声混叠到有效频带内。

右腿驱动电路这是一个提升共模抑制能力的关键技巧。我们用一个运放将所有电极信号的共模平均值反相放大后,通过一个较大的电阻反馈到受试者的右腿(或耳垂)参考电极上。这形成了一个负反馈环路,主动抵消了身体拾取到的共模干扰(尤其是50Hz工频干扰),可以显著提升系统的整体CMRR。

2.2 数字核心:STM32WB55的角色与配置

NUCLEO-WB55上的STM32WB55是双核架构(Cortex-M4应用核 + Cortex-M0+无线核),在这里我们主要用其M4核来完成数据采集与预处理。

ADC配置要点STM32WB55的ADC分辨率可达12位。对于EEG采集,精度和稳定性比超高采样率更重要。

  1. 采样率:设置为250 SPS(每秒采样点数)。这个速率对于捕捉主要脑电节律(如α, β波)足够,同时降低了数据量和处理负担。
  2. 采样模式:使用定时器触发ADC进行规则组转换。这样可以确保采样间隔绝对均匀,对于后续的信号处理(如FFT)至关重要。我使用一个基本定时器(如TIM6)产生250Hz的触发信号。
  3. 多通道与扫描模式:如果设计多通道(如2-4通道),需要配置ADC的扫描模式,按顺序转换多个通道。注意通道间的切换时间要计入采样周期。
  4. 参考电压:使用稳定的内部参考电压或板载的基准源,确保ADC转换的准确性。

DMA传输为了不占用CPU资源进行频繁的ADC数据搬运,必须启用DMA。将ADC的转换完成数据寄存器配置为DMA的源地址,目标地址设置为内存中的一个缓冲区(数组)。采用循环缓冲模式,当缓冲区半满或全满时产生DMA中断,在中断服务程序中将数据打包或进行初步处理(如减去直流偏置)。

初步数字信号处理在数据送入无线传输队列前,可以在M4核上进行一些轻量级的预处理:

  • 直流移除:计算一个滑动窗口内的平均值并实时减去,以消除ADC本身的偏置或前端电路的残余直流。
  • 简单的工频陷波:如果50Hz干扰在模拟端抑制得不够好,可以在数字端加一个IIR陷波滤波器。但要注意,数字滤波会引入相位延迟,对于需要精确时序的分析需谨慎。
  • 数据格式转换:将ADC原始值(如0-4095)转换为以微伏(μV)为单位的物理值。这需要事先对系统进行校准。

2.3 无线通信:蓝牙5.0的数据桥梁

NUCLEO-WB55最大的特色是其集成的STM32WB无线协处理器。我们将利用蓝牙5.0将采集到的EEG数据流发送到上位机(PC或手机)。

服务与特征设计我们创建一个自定义的蓝牙GATT服务。在这个服务下,定义几个关键特征:

  1. EEG数据流特征:属性为Notify(无响应)或Indicate(有确认)。我们将预处理后的EEG数据包通过这个特征发送。数据包结构可以设计为:[包头|时间戳|通道1数据|通道2数据|...|校验和]。为了平衡效率和实时性,可以每采集10个点(即40ms的数据)打包发送一次。
  2. 配置特征:属性为Write。上位机可以通过它向下位机发送命令,如修改采样率、开启/关闭某个数字滤波器、开始/停止采集等。
  3. 状态特征:属性为ReadNotify。用于上报设备状态,如电池电量、连接状态、错误码等。

双核通信机制M4应用核将打包好的数据通过内部IPC(进程间通信)机制(如共享内存+信号量)传递给M0+无线核。ST提供了完整的无线栈和示例,我们需要在M0+侧实现数据从共享内存到蓝牙栈的搬运和发送逻辑。关键在于确保两个核之间的同步,避免数据覆盖或丢失。

3. 硬件实现细节与避坑指南

理论设计需要落到实际的电路板和代码上。这部分是项目从图纸变成实物的关键,充满了需要警惕的细节。

3.1 PCB布局与布线的“军规”

EEG采集板的PCB设计,其重要性不亚于原理图设计。糟糕的布局布线会毁掉一个精心设计的模拟电路。

  1. 严格分区:将PCB清晰地划分为模拟区、数字区和电源区。模拟区(包含仪放、滤波器、ADC模拟输入)必须与数字区(单片机、晶振、数字接口)物理隔离。
  2. 地平面分割与单点连接:使用完整的接地层,但在模拟地和数字地之间进行分割。两地之间通过一个磁珠或0欧电阻在一点连接,这个连接点通常选择在电源入口处或ADC芯片下方。这确保了高频数字噪声不会通过地平面污染敏感的模拟信号。
  3. 电源去耦是生命线:在每个集成电路(尤其是运放和STM32)的电源引脚附近,放置一个0.1μF的陶瓷电容到地。对于功耗较大的芯片,还需要并联一个10μF的钽电容或电解电容。这些电容必须尽可能靠近芯片引脚,走线要短而粗。
  4. 模拟信号走线:走线尽量短、直。避免在数字信号线或电源线下方穿过。如果必须交叉,应垂直交叉。对于来自电极的差分对,应保持平行、等长、紧耦合,以增强抗干扰能力。
  5. 屏蔽与保护:电极输入线应使用屏蔽线,屏蔽层在板端单点接地(通常接模拟地)。可以在模拟输入端口添加TVS二极管或稳压管,防止静电放电(ESD)损坏昂贵的仪放。

踩坑实录:地环路导致的顽固噪声在第一个版本中,我忽略了电源适配器引入的地环路问题。当开发板、示波器和PC都通过各自的电源适配器接地时,形成了一个地环路,50Hz干扰异常强大,右腿驱动电路也收效甚微。解决方案:整个系统采用单点供电和接地。使用电池给开发板和模拟前端供电,上位机(PC)通过蓝牙连接,彻底隔离了地环路。或者,使用高质量的隔离型DC-DC模块为模拟部分供电。

3.2 元器件选型与电源设计

  1. 运放选型:核心是输入噪声电压密度(nV/√Hz)。对于EEG,需要选择在1-100Hz频段内噪声极低的运放。AD8221的输入噪声电压密度约为8 nV/√Hz @ 1kHz,是不错的选择。第二级运放可以选择更通用的低噪声运放,如OPA2188。
  2. 电阻电容:模拟通路上的电阻应使用金属膜电阻,精度1%即可,但温度系数要小。电容首选C0G/NP0介质的陶瓷电容,其容值稳定,几乎无压电效应。避免使用Y5V、Z5U等介质的电容,它们的容值随电压和温度变化剧烈。
  3. 电源设计:模拟部分需要极其干净的电源。线性稳压器(LDO)如TPS7A系列,其噪声性能远优于开关稳压器。可以为模拟部分单独使用一个LDO(如+5V转±2.5V),与数字部分的3.3V电源隔离。注意LDO的输入输出也要做好滤波。

3.3 与NUCLEO-WB55的接口

NUCLEO-WB55通过Arduino兼容的排针和ST Morpho排针引出接口。我们需要将自定义的模拟前端板通过排针与它连接。

  • ADC输入:使用开发板的PA0PA1等ADC通道引脚。
  • 电源:从开发板的3.3VGND引脚取电给模拟前端。如果模拟部分需要更高电压或负电压,则需要额外的电源电路。
  • 控制信号:如果需要控制模拟前端的增益或开关,可以使用普通的GPIO引脚。

注意:NUCLEO开发板上的ST-LINK部分(负责编程和调试)也会产生数字噪声。在最终产品化时,可以考虑将ST-LINK部分断开,仅使用核心的STM32WB55芯片,但这会牺牲调试便利性。在原型阶段,可以通过软件在采集时暂时关闭不必要的数字外设(如调试串口)来降低噪声。

4. 固件开发:STM32Cube生态下的实战

ST的STM32CubeMX和HAL库极大地简化了初始化工作,但对于EEG采集这种对时序和稳定性要求高的应用,我们需要深入底层进行优化。

4.1 基于CubeMX的工程初始化

  1. 时钟树配置:确保系统时钟、ADC时钟、定时器时钟都准确无误。ADC时钟不能超过其最大允许频率(STM32WB55的ADC时钟最高可达80MHz,但通常运行在较低频率以获得更好性能)。
  2. ADC配置
    • Mode: Independent mode
    • Resolution: 12 bits
    • Data Alignment: Right alignment(便于处理)
    • Scan Conversion Mode: Enabled(如果多通道)
    • Continuous Conversion Mode: Disabled(我们使用外部触发)
    • Discontinuous Conversion Mode: Disabled
    • DMA Continuous Requests: Enabled
    • End Of Conversion Selection: EOC flag at the end of all conversions(多通道时)
    • External Trigger Source: Timer Trigger Out event(例如 TIM6_TRGO)
  3. 定时器配置:配置一个基本定时器(如TIM6)产生250Hz的更新事件(UEV)。计算ARR(自动重装载值)和PSC(预分频器)以得到准确的频率。
  4. DMA配置:为ADC外设添加一个DMA流,模式设为Circular(循环),数据宽度为Half Word(对应16位,虽然ADC是12位),内存地址自增。
  5. 蓝牙配置:这部分相对复杂,建议从ST提供的BLE示例工程(如BLE_DataThroughput)开始,修改其中的GATT配置文件,添加我们自定义的EEG服务与特征。

4.2 采集主循环与数据处理流程

// 伪代码示意 int main(void) { // HAL初始化,时钟、ADC、定时器、DMA、蓝牙等 MX_Init(); // 启动定时器,它将周期性地触发ADC HAL_TIM_Base_Start(&htim6); // 启动ADC的DMA转换 HAL_ADC_Start_DMA(&hadc1, (uint32_t*)adc_buffer, BUFFER_SIZE); // 开启蓝牙广播 aci_gap_start_discovery_proc(...); while (1) { // 等待DMA半满或全满中断标志 if (dma_half_flag) { process_buffer(adc_buffer, 0, HALF_BUFFER_SIZE); // 处理前半部分 dma_half_flag = 0; } if (dma_full_flag) { process_buffer(adc_buffer, HALF_BUFFER_SIZE, HALF_BUFFER_SIZE); // 处理后半部分 dma_full_flag = 0; } // 处理蓝牙事件(如连接、断开、写入命令) BLE_Process(); // 低功耗模式(可选) // __WFI(); } } void process_buffer(uint16_t *buf, uint32_t start, uint32_t len) { for (uint32_t i = 0; i < len; i++) { // 1. 转换为电压值 (假设Vref=3.3V) float voltage = (buf[start + i] * 3.3f) / 4095.0f; // 2. 转换为微伏值 (需乘以前端总增益的倒数,并减去偏置) // float uV = (voltage - offset) * (1.0 / total_gain) * 1e6; // 3. 可在此进行简单的数字滤波(如移动平均去直流) // 4. 存入发送队列 eeg_data_queue[queue_idx++] = (int16_t)(uV); // 假设用int16存储 if (queue_idx >= PACKET_SIZE) { // 打包数据,通过IPC发送给M0+核 send_data_via_ipc(eeg_data_queue, PACKET_SIZE); queue_idx = 0; } } }

4.3 蓝牙数据发送优化

蓝牙的传输速率和稳定性是关键。蓝牙5.0在物理层速率上有提升,但实际应用层吞吐量受连接间隔、数据包长度等参数影响。

  1. 连接参数协商:在建立连接时,从设备(我们的MicroBCI)可以请求更短的连接间隔(如15ms-30ms)和更大的数据包长度,以提高吞吐量,但这会增加功耗。
  2. 数据分包与流控:如果一包数据太大,可能需要分包。或者,在固件中实现简单的流控:当发送队列快满时,暂停ADC采集;当队列空时再恢复。避免数据丢失。
  3. M0+侧的任务:M0+核从共享内存获取数据包后,调用aci_gatt_update_char_value函数来更新特征值并通知(Notify)已连接的中央设备(如手机)。确保这个操作在连接事件内完成,以提高效率。

5. 上位机软件与数据验证

硬件和固件跑通只是第一步,我们需要一个上位机来接收、显示和分析数据,以验证整个系统的性能。

5.1 简单的Python数据接收与绘图

可以使用pybluezbleak库(跨平台)来连接MicroBCI设备,订阅EEG数据特征的通知,并实时绘图。

import asyncio from bleak import BleakClient import numpy as np import matplotlib.pyplot as plt # 替换成你设备的地址和特征UUID DEVICE_ADDR = "AA:BB:CC:DD:EE:FF" EEG_DATA_CHAR_UUID = "0000xxxx-0000-1000-8000-00805f9b34fb" class EEGPlotter: def __init__(self): self.data_buffer = np.zeros(1000) # 环形缓冲区 self.idx = 0 self.fig, self.ax = plt.subplots() self.line, = self.ax.plot(self.data_buffer) self.ax.set_ylim(-200, 200) # 假设数据范围在±200uV def notification_handler(self, sender, data): """ 蓝牙通知回调函数 """ # 解析数据包,假设每个数据点是int16_t,小端字节序 points = np.frombuffer(data, dtype='<i2') # 小端有符号16位整数 for point in points: self.data_buffer[self.idx] = point self.idx = (self.idx + 1) % len(self.data_buffer) # 更新绘图 self.line.set_ydata(self.data_buffer) self.fig.canvas.draw() self.fig.canvas.flush_events() async def main(): plotter = EEGPlotter() async with BleakClient(DEVICE_ADDR) as client: print(f"Connected: {client.is_connected}") # 启动通知 await client.start_notify(EEG_DATA_CHAR_UUID, plotter.notification_handler) plt.show(block=True) # 阻塞,保持绘图窗口打开 # 当窗口关闭时,停止通知 await client.stop_notify(EEG_DATA_CHAR_UUID) asyncio.run(main())

5.2 性能测试与信号质量评估

连接好系统后,进行以下测试:

  1. 本底噪声测试:将两个输入电极短路并连接到参考地(模拟前端输入共模电压)。观察上位机接收到的信号。一个设计良好的系统,本底噪声的峰峰值应该在几个微伏以内。计算其RMS值。
  2. 正弦波测试:使用信号发生器,产生一个10Hz、50μV峰峰值(注意衰减到合适电平)的正弦波,输入到模拟前端。观察上位机波形是否清晰,幅度是否正确。进行FFT分析,看频谱中是否只有10Hz的单峰。
  3. 共模抑制比测试:在两个输入电极上同时施加一个50Hz、1V峰峰值的共模正弦波(相对于参考地)。测量输出端该50Hz信号的幅度。CMRR = 20 * log10(共模输入电压 / 输出端测得的该频率电压)。一个合格的EEG前端,CMRR应大于80dB。
  4. 实际人体测试:佩戴电极(通常使用预凝胶的Ag/AgCl电极),位置可以是标准的10-20系统位置,如O1、O2(枕叶,易采集α波)或Fp1、Fp2(前额,但易受眼电干扰)。让受试者闭眼放松,观察是否能在8-13Hz频段出现α波功率增高的现象。

5.3 常见问题与调试技巧

  • 信号全是噪声:首先检查电极接触是否良好,阻抗是否过高(应低于10kΩ)。然后用地环路排查法,尝试电池供电。用示波器逐级测量模拟前端各关键点的波形,定位噪声引入点。
  • 50Hz工频干扰严重:检查右腿驱动电路是否工作,反馈电阻是否接对。检查PCB地平面分割和单点连接。尝试在屏蔽室内或远离强电环境测试。
  • 蓝牙连接不稳定或数据丢失:检查天线周围是否有金属遮挡。优化蓝牙连接参数(连接间隔、从机延迟)。检查固件中DMA缓冲区和蓝牙发送队列的大小,避免溢出。在代码中添加数据包计数和丢失统计。
  • 基线漂移:检查高通滤波器的截止频率是否足够高(0.5Hz)。检查电极是否稳定,皮肤是否清洁。模拟前端运放的输入偏置电流是否过大,导致与电极阻抗产生压降。

这个项目从构思到实现,是一个典型的硬件、固件、软件结合的嵌入式系统挑战。它不仅仅是为了采集到“看起来像”的脑电波,更是为了理解生物电信号采集的每一个技术细节。通过MicroBCI,你可以完全掌控从皮肤表面的离子电流到计算机屏幕上数字曲线的整个链条,这种透明度和可定制性,是任何闭源商业设备都无法给予的。当你第一次从自己搭建的系统里,清晰地看到受试者闭眼时枕叶α波的涌现,那种成就感是无与伦比的。这不仅是技术的实现,更是对生命活动进行观测的一扇窗。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询