摘要:ADS1292R是TI公司早在2012年就出产的一款医用级ADC芯片,它主要应用在医疗仪器(心电图ECG),可以监护患者以及和人护理和健身监视器。ADS1292R具有两个低噪声可编程增益放大器(PGA)和和两个高分别率模数转换器器(ADC),集成了心电采集所需要的部件,方便设备小型化。它的功耗极低,使得可以作为长时间监控成为可能。而且输入参考噪音低,共模抑制比高。足以进行心电采集。电赛很可能会让大家利用这款芯片做一个心电图检测仪,显示模块很可能就是大家所熟知的RGB大屏幕,同时这道题应该是信号题了。
心电信号和呼吸信号是人体的重要生物电信号。尤其是心电信号,它比其他生物电信号更直观,更具有规律性,它是反映心脏健康状况的重要依据。心电图是诊断和分析治疗心血管疾病的一个重要手段,在临床治疗中心电图得到广泛应用。但是常规心电图一般需要通过大型医疗场所,如医院、疗养院的心电图机采集数据获得,其获得途径较难、价格较高、耗时长等弊端阻碍了心电图机的进一步应用。今年大家经历了新冠疫情,所以出这种题目也是情理当中,毕竟学以致用,学了不能用,那学了又有何用?对吧。
1、引脚功能及配置
这可芯片的引脚还不少,一共有32个引脚。当然做电赛大家肯定都是买的几百块钱的模块,肯定不会自己亲自动手焊接,而且买的模块只会把芯片所需要的通信引脚和电源引脚引出来。所以做硬件的也就节省了很多时间。当然节省的时间不是让你去休息的。你需要花大量的时间来研究数据手册,把外围电路优化好才能让软件更好地去写代码。
这里我简单的看一下数据手册,可能分析的不对,需要各位大显身手去开动你们聪明的大脑了。我们从1号到32号引脚讲讲它的引脚功能:
- 1号和2号引脚PGA1N/PGA1P是PGA的输出引脚。
- 3号和4号引脚IN1N/IN1P这是一对模拟输入,这里用的是差分输入以减小共模干扰,在它们输入到MUX之前,还经过了EMI滤波器。
- 5号和6号引脚 IN2P/IN2N和3号和4号引脚同样是一对模拟输入,差分输入以减小共模干扰。
- 7号和8号引脚PGA2N/PGA2P和上面的1号和2号引脚对应,是PGA的输出引脚。
- 9号和10号引脚VREFP和VREFN分别是同相和反相反馈电压。
- 11号和27号引脚VCAP1和VCAP2是旁路电容,作用是吸收器件的交流成分(纹波常常被认为是交流成分)
- 12号AVDD是模拟电源.
- 13号AVSS是模拟地。
- 14号CLKSEL引脚和寄存器中时钟管理的部分共同控制了外部或者内部时钟的选择,以及时钟是否从17号引脚CLK引脚输出。
- 15号PWDN/RESET是低有效的复位功能。
- 16号START使能引脚。
- 18号到21号四个引脚CS SCLK DIN DOUT 是标准的SPI通信协议。
- 22号引脚DRDY低有效的数据传输准备完成标志信号。
- 23号引脚DVDD数字电源。
- 24号引脚DGND数字地。
- 25号和26号引脚GPIO1和GPIO2是配置寄存器的引脚。
- 28号和引脚RLDINV是右腿驱动的反向输入端,不用的时候连到模拟地上。
- 29号和引脚RLDIN/RLDREF是右腿驱动电路对MUX的输入,或者右腿驱动电路的非逆变输入,不用的时候必须接到模拟地AVSS上。
- 30号和引脚RLDOUT 右腿驱动输出。
- 31号和32号引脚RESP_MODP/IN3P ==RESP_MODN/IN3N== 这一对引脚有两个功能:第一是作为呼吸的激励信号(模拟输出);第二个作用是辅助的模拟差分输入,可以被MUX复用到任何一路PGA上。
注意:
- ==RLD== 开头的引脚,RLD是“右腿驱动电路”,是医疗电子中一个常见的概念。因为医疗电子实际上是采集人体固定位置间的生物电压,在它的量级,人体本身作为天线接收的家庭用电电器等的辐射产生的电压就是一个不可忽略的噪声了,所以这时候我们需要想办法抑制这个共模电压:
- 什么是PGA? PGA是“可编程增益放大器” ,可以作为前端减小高速ADC的噪声,其原理就是使用PGA提供的高增益下,信噪比提升,这样就总的降低了噪声。
2、信号采集的硬件要求
心电及呼吸信号采集前端是整个监护系统的核心部分,如果前端信号采集部分的电路出现问题,即使你的模块板子再好也不能得到你想要的输入信号,自然就GG。ECG 属于微弱的小信号,其幅值在 10μ V~5mV 之间,极易受到干扰,导致有用信号淹没在诸多噪声中。为了能有效地提取出有用信号,对信号采集硬件提出如下要求:
- (1)高输入阻抗
人体阻抗高达几 KΩ 至几十 KΩ,可以将人体看成是高阻抗的弱信号输出源。人体本身、衣着和环境等的不同会引起人体阻抗很大的变化,为了防止人体阻抗的波动引起监护系统信号的不稳定,信号采集硬件应具有较高的输入阻抗。同时,硬件采集电路的输入阻抗也不宜过高,否则会引入较强的外界干扰。那这时你的硬件手就应该好好利用运算放大器来设计电路。
- (2)高共模抑制比CMRR
心电信号受到的最大干扰是 50Hz 的工频干扰,它以共模的形式加载到每一个电极上,形成共模干扰。因此心电采集电路应具有很高的共模抑制比,一般要求在 60~80dB。
这两点是前端设计电路最重要的两点。
3、电极片的选择
极片也是传感器的一种,其作用是将人体内的离子导电的位移电流转化为检测电路中的电子导电的传导电流,电极片作为检测电路输入前端,其性能也影响着检测电路的噪声、共模抑制比等,所以选择合适的电极片对整个系统的信号质量尤为重要。既然是比赛那就用学校的钱买最好的点电极片了,战术后仰!!!
4、测量的电路
下图1是官方数据手册中截取的,图二是对应的中文内部框图,图三是在网上多次看到的原理图。有些图用的人多了自然有他的道理,这个不必纠结。设计电路首先要遵从数据手册然后再在此电路的基础上进行修改。
注意:由于人体阻抗高达几KΩ 至几十KΩ,在心电信号采集时常常遇到信号误差大或者失真现象。心电信号除了易受外界干扰以外,人体内部器官之间、表皮之间都存在相互影响,甚至是人的情绪变化也会引起心电信号不稳定。
5、信号输入电路和右腿驱动电路设计
ADS1292R 可以实现双通道信号采集和模数转换,通道 1(IN1N 和 IN1P)为呼吸信号采集通道,IN3N 和 IN3P 为 ADS1292R 内部产生的32kHz 正弦电流信号的输出端。在正弦电流信号的输出电路中,可以在31号和32号引脚外加保护电阻,限制从 ADS1292R 流向人体的电流,同时还可以在电阻后加电容起到隔离流回人体的直流的作用(电阻和电容是串联)。在呼吸信号输入电路中,C2和 C7起到抑制流回人体的直流电流的作用。C1和 C6起到人体免受电路突发故障所引起的大电流伤害的作用。
心电信号极易受到 50Hz 工频干扰,这种干扰常以共模的形式出现。一般在生物电信号检测电路中,需要对消驱动电路即右腿驱动电路来消除这种共模干扰,从而提高系统的共模抑制比。
ADS1292R 片内集成了右腿驱动电路,这样有利于减小监护设备的体积,降低功耗。右腿信号由 RLDINV 端口输入至片内右腿驱动电路,设置 ADS1292R内部 RLD_SENS 寄存器,使片内右腿驱动电路的输出连至通道 2 以减少心电信号中共模干扰。官方公开的资料中并未给出片内右腿驱动电路的反相放大器中电阻阻值,其放大倍数未知,为保证整个电路的信号稳定、可靠,右腿驱动电路需要各位大佬根据系统需要外搭。
6、心电及呼吸信号降噪
心电信号非常微弱,典型值仅为 1mV 左右。正常的心电信号大部分为 0.5~ 40Hz 的低频信号,而心电信号的总体范围为 0.05~100Hz。心电信号极易受到来自外界、人体自身以及电路的干扰,如基线漂移、工频干扰、肌电噪声等。干扰信号混杂于心电及呼吸信号中,导致有用信号畸变,有时有用信号会完全淹没在噪声里,故有用信号的特征值很难被提取。所以相应的滤波去噪处理是必要的。
常用的心电信号去噪方法有硬件降噪和软件滤波这两种。硬件降噪主要是通过搭建相应的电路来实现滤波功能,但这种硬件滤波电路不仅搭建调试难度大,而且增加了成本、体积和功耗。建议大家通过软件滤波,这对参加电赛的软件手来说肯定不难,智能车都搞过这点滤波的问题还能难道你这个大佬吗?对吧!
7、主控芯片
TI杯当然是建议用TI提供的板子—MSP430。如果你前期没有用过MSP430的板子也没有问题,用STM32也不是不可以。另外芯片也单片机通信的方式是SPI通信,我相信SPI通信大家都会,因为有的7针的OLED显示屏就是用的SPI通信,这点就不用多说了。
8、驱动代码
代码初始化需要配置寄存器,具体程序中已经注释的非常清楚,仅供参考啊!
void ads_Init(void)
{
uint8_t send_data[20], read_data[20];
ads_Reset(1); // 复位引脚置一,正常工作
osDelay(1000);
osDelay(100);
//指令:停止连续读数据模式
send_data[0]=ADS1292R_CMD_SDATAC;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,1,1000));
osDelay(10);
//写配置寄存器2=0xa0,内部参考电压为2.42V
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_CONFIG2);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0xa0;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写配置寄存器1=0x01,连续转换模式,采样率为250
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_CONFIG1);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0x01;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写导联脱落检测寄存器=0xF0,正负极分别为70%和30%,该功能实际未使用
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_LOFF);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0xF0;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写通道1设置寄存器=0x30,设置增益为3,正常节点输入
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_CH1SET);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0x30;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写右腿驱动寄存器=0xEF,PGA的斩波频率为4分频,使能右腿驱动,关闭右腿驱动的脱落检测,通道2的右腿驱动负极和正极分别连接到通道2输入的负极和正极,通道1的右腿驱动负极和正极分别连接到通道1的负极和正极
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_RLD_SENS);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0xEF;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写脱落检测寄存器=0x0F,关闭通道1和2的电流方向检测,使能通道1和2的正负极脱落检测
//其实只使用了通道1,而且脱落检测实际上没有使用
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_LOFF_SENS);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0x0F;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写呼吸控制寄存器1=0xF2,使能呼吸调制解调电路,呼吸解调相位为135°,时钟为32KHz,内部时钟
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_RESP1);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0xF2;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
//写呼吸控制寄存器2=0x83,关闭偏置校准,呼吸控制频率为32KHz,右腿驱动参考信号为外部信号
send_data[0] = ADS1292R_CMD_WREG_1(ADS1292R_REG_RESP2);
send_data[1] = ADS1292R_CMD_WREG_2(1);
send_data[2] = 0x83;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,3,1000));
osDelay(10);
ads_Start(1); //启动转换
osDelay(10);
//指令:连续读模式
send_data[0]=ADS1292R_CMD_RDATAC;
while(HAL_OK!= HAL_SPI_TransmitReceive(&hspi1,send_data,read_data,1,1000));
osDelay(10);
}
void ads_Get_Data(uint8_t* raw_data)
{
static uint8_t sendBuf[9]={0,0,0,0,0,0,0,0,0};
HAL_SPI_TransmitReceive_DMA(&hspi1,sendBuf,raw_data,9);
}