ADS1292检测心电的原理与示波器类似,只是人体的心电信号是低频、小信号,
ADS1292就是捕捉人体不同位置间的心电信号,并降噪、放大。
人体心电信号的特点
离开人体体表微小的距离就检测不到信号,因此电极必须贴近人体;
信号非常微弱,至多为mV量级;
属于低频信号,能量主要集中在几百赫兹以下;
干扰特别强,既有来自生物体内,如肌电、呼吸等干扰,也有来自生物体外,如工频干扰、不良接地引入的干扰等。
ADS1292电路简介
IN1P/IN1N IN2P/IN2N 这是两对模拟输入,这里用的是差分输入以减小共模干扰,在它们输入到MUX(数据选择器)之前,还经过了EMI(电磁干扰)滤波器,然后进入PGA(可编程放大器)进行信号放大,并供ADC采样转成数字信号。
RESP_MODP/IN3P RESP_MODN/IN3N 这一对引脚有两个功能:第一是作为呼吸的激励信号(模拟输出);第二个作用是辅助的模拟差分输入,可以被MUX复用到任何一路PGA上。
从PGA出来有一路经过RLD电路接回人体右腿位置。
RLD是“右腿驱动电路”,是医疗电子中一个常见的概念。因为医疗电子实际上是采集人体固定位置间的生物电压,在它的量级,人体本身作为天线接收的家庭用电电器等的辐射产生的电压就是一个不可忽略的噪声了,所以这时候我们需要想办法抑制这个共模电压:
RLDIN/RLDREF是右腿驱动电路对MUX的输入,或者右腿驱动电路的非逆变输入,不用的时候必须接到模拟地AVSS上。
RLDOUT 右腿驱动输出 RLDINV右腿驱动的反向输入端,不用的时候连到模拟地上
驱动
static uint8_t State1292 = 0; //停止工作
static uint8_t rdyPinIsLow = 0; //ready脚被拉低,开始接受数据
static const nrf_drv_spi_t spi_1292 = NRF_DRV_SPI_INSTANCE(0); /**< SPI instance. */
/*
**1292DRDY数据准备好后的回调函数
**/
void ads1292_drdy_handler(nrf_drv_gpiote_pin_t pin, nrf_gpiote_polarity_t action)
{
switch (pin)
{
case ADS1292_DRDY_PIN:
if (!nrf_drv_gpiote_in_is_set(ADS1292_DRDY_PIN)) //信号被拉低
{
if(!rdyPinIsLow)
rdyPinIsLow=1;
}
break;
default:
break;
}
}
void ADS1292_PowerOnInit(void)
{
uint8_t device_id = 0;
char strBuff[20];
// START_H;
// CS_H;
// PWDN_L; // 进入掉电模式
// nrf_delay_ms(1000);
// PWDN_H; // 退出掉电模式
// nrf_delay_ms(1000); // 等待稳定
// PWDN_L; // 发出复位脉冲
// PWDN_H;
// nrf_delay_ms(1000); // 等待稳定,可以开始使用ADS1292R
START_L;
CS_L;
ADS1292_ReadWriteByte(SDATAC); // 发送停止连续读取数据命令
CS_H;
// 获取芯片ID
device_id = ADS1292_Read_Reg(RREG | ID);
while(device_id != 0x81)
{
nrf_delay_ms(1);
device_id = ADS1292_Read_Reg(RREG | ID);
}
ADS1292_Write_Reg(WREG | CONFIG2, 0XE0); // 使用内部参考电压
nrf_delay_ms(10); // 等待内部参考电压稳定
ADS1292_Write_Reg(WREG | CONFIG1, 0X01); // 设置转换速率为250SPS
ADS1292_Write_Reg(WREG | LOFF, 0XF0); // 该寄存器配置引出检测操作
// ADS1292_Write_Reg(WREG | CH1SET, 0X60); // 通道1,增益12,连接到电极
ADS1292_Write_Reg(WREG | CH1SET, 0X00); // 通道1,增益6,连接到电极
ADS1292_Write_Reg(WREG | CH2SET, 0X00); // 通道2,增益6,连接到电极
ADS1292_Write_Reg(WREG | RLD_SENS, 0x30);//开启RLD buffer和lead-off sense
// ADS1292_Write_Reg(WREG | LOFF_SENS, 0x3F);//设置通道1输出的通道2输入的电流方向,
ADS1292_Write_Reg(WREG | LOFF_SENS, 0x0F);//设置通道1输出的通道2输入的电流方向,
ADS1292_Write_Reg(WREG | LOFF_STAT, 0x00);//电极连接状态,采用默认值
ADS1292_Write_Reg(WREG | RESP1, 0xEA); // 开启呼吸检测和相位(ADS1292R特有)
ADS1292_Write_Reg(WREG | RESP2, 0x03);// 关闭呼吸校准功能,
ADS1292_Write_Reg(WREG | GPIO, 0x0C);//GPIOD作为输入并写入0
}
//-----------------------------------------------------------------
//
// 函数功能: ADS1292引脚初始化
// 入口参数: 无
// 返 回 值: 无
// 注意事项: 无
//
//-----------------------------------------------------------------
void ADS1292_Init(void)
{
// ADS1292_PWDN -> P0.13
// ADS1292_START -> P0.12
// ADS1292_CS -> P0.03
// ADS1292_DRDY -> P0.14
ret_code_t errCode;
//配置引脚为输出模式
nrf_gpio_cfg_output(ADS1292_PWDN_PIN);
nrf_gpio_cfg_output(ADS1292_START_PIN);
nrf_gpio_cfg_output(ADS1292_CS_PIN);
nrf_gpio_cfg_output(ADS1292_SCKSEL_PIN);
nrf_gpio_cfg_output(ADS1292_POWER_PIN);
uint8_t reacive_1292_data(void)
{
uint8_t j;
uint8_t read_data[9]= {0};
if(rdyPinIsLow)
{
taskENTER_CRITICAL();//进入临界区
CS_L;
for (j = 0; j < 9; j++) // 连续读取9个数据
{
read_data[j] = ADS1292_ReadWriteByte(0xFF);
}
CS_H;
ch1_data = 0;
ch2_data = 0;
//一次读取9个字节。其中前3个字节包含了电极状态,后面3+3个字节分别表示两个通道的数据,高位在前
//依据1292内部电路,如果是能了呼吸监测,通道1就是呼吸数据
ch1_data |= (uint32_t)read_data[3] << 16;
ch1_data |= (uint32_t)read_data[4] << 8;
ch1_data |= (uint32_t)read_data[5] << 0;
ch2_data |= (uint32_t)read_data[6] << 16;
ch2_data |= (uint32_t)read_data[7] << 8;
ch2_data |= (uint32_t)read_data[8] << 0;
point_cnt++;
rdyPinIsLow=0;
taskEXIT_CRITICAL();//退出临界区
return 1;
}
else
return 0;
}
//使用1292内部时钟
nrf_gpio_pin_set(ADS1292_SCKSEL_PIN);
// ADS1292_SCLK -> P0.ADS1292_SCLK_PIN
// ADS1292_DOUT -> P0.06
// ADS1292_DIN -> P0.04
//初始化spi
nrf_drv_spi_config_t spi_config = NRF_DRV_SPI_DEFAULT_CONFIG;
spi_config.miso_pin = ADS1292_DOUT_PIN;
spi_config.mosi_pin = ADS1292_DIN_PIN;
spi_config.sck_pin = ADS1292_SCLK_PIN;
spi_config.frequency = NRF_DRV_SPI_FREQ_500K;
errCode = nrf_drv_spi_init(&spi_1292, &spi_config, spiCallbackFunc, NULL);
APP_ERROR_CHECK(errCode);
//给1292上电
nrf_gpio_pin_set(ADS1292_POWER_PIN);
nrf_delay_ms(1000); // 等待稳定
ADS1292_PowerOnInit(); // ADS1292上电初始化
// ADS1292_DRDY
nrf_drv_gpiote_in_config_t adsDRDY = GPIOTE_CONFIG_IN_SENSE_TOGGLE(true);
adsDRDY.pull = NRF_GPIO_PIN_PULLUP;
nrf_drv_gpiote_in_init(ADS1292_DRDY_PIN, &adsDRDY, ads1292_drdy_handler);
nrf_drv_gpiote_in_event_enable(ADS1292_DRDY_PIN, true);
}//
// 函数功能: 1292开始数据转换并读取ADS1292的数据
// 入口参数: 无
// 返 回 值: 无
// 注意事项: 无
//
//-----------------------------------------------------------------
void ADS1292_Start_Read(void)
{
if (State1292 == 0)
{
//给1292上电
nrf_gpio_pin_set(ADS1292_POWER_PIN);
vTaskDelay(1000);//等待稳定
CS_L;
ADS1292_ReadWriteByte(RDATAC); // 发送启动连续读取数据命令
CS_H;
START_H; // 启动转换
State1292 = 1; //开始工作
}
}
//
// 函数功能: 1292停止数据转换
// 入口参数: 无
// 返 回 值: 无
// 注意事项: 无
//
//-----------------------------------------------------------------
void ADS1292_Stop_Read(void)
{
if (State1292)
{
CS_L;
START_L; // 停止转换
ADS1292_ReadWriteByte(SDATAC); // 发送停止连续读取数据命令
CS_H;
State1292 = 0; //停止工作
//给1292断电,节省电量
nrf_gpio_pin_clear(ADS1292_POWER_PIN);
}
}