This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

ADS1198/1298开发设计心得以及遗留问题总结!---------希望对正想使用这款芯片的朋友有所帮助!!!

Other Parts Discussed in Thread: ADS1298, ADS1198, MSP430F5418, ADS1299, ADS1298R, ADS1194
                         ADS1198/ADS1298开发设计心得与遗留问题总结
 
    首先非常感谢TI公司的支持,自己手里面的6ADS1198全部是从TI公司申请到的,并且遇到问题后能TI的技术支持工程师能及时给出解答,所以写这篇文章,一是对自己这几个月工作的总结,二是也算是对TI公司的感谢,也希望能帮助到以后使用ADS1198/1298的朋友。
 
本人使用MSP430F5418ADS1198设计12导心电监测仪,其实就是个低档的HOLTER,HOLTER的基础上加了几个操作按键和LCD显示屏。历时3个多月,前几天算是能比较满意的用ADS1198采集到ECG信号了!现在简单说下开发过程以及遇到的一些问题。
先说下MSP430单片机,本人01年开始使用(那是还是大四),先后使用过1100,135,149,2418等型号,这次选用了5418,因为信价比高,等开始实际调试使用时,才发现5418与之前的型号有很多升级。增加了几个功能模块同时也整合了一些功能模块。比如SYS模块,PMM模块,UCS模块等(还有一些功能由于没用上也没研究),这几个模块我看了很长时间英文资料(英文水平不咋地)后,发现SYSPMM模块对我根本就没有用,并且把PMM模块关掉了,增加了这些模块视乎能提高430的安全性,但我觉得430这种单片机由于设计宗旨是低功耗3V供电。所以一般都是采用电池供电的,加上这2个模块似乎意义不大。反而与之前的型号兼容性不好了!
本人在做这款12导心电监测仪之前搞过1年多心电,只用运放做过9导心电监测仪,所以在ECG方面的经验还是很少的,发现这款ADS1198芯片还是在电源网上看到的,申请到样片后,手册和开发指南看了不下七八遍才基本理解明白,现在说说自己曾经迷糊而后来解决以及仍没解决的问题列出来:
1.              ADS119816AD,可是PGA增益最大只有12,没有二级放大,对于ECG信号最大幅值在5mV左右,经过12倍放大为60MV, 60/2400*65536=1638,即只要用12位就能标示出ECG信号了,也就是说浪费掉了4AD,如果用ADS1298也会同样出现这种情况,只是会比1198精确些而已,如果用ADS1198/1298测量EEG信号,EEG信号是uV级的,真不能能不能用啊!
2.             
请看手册第12页,这里的这幅图下面的NOTE写着SPI CPOL=0CPHA=1,但是实际在调试程序时我发现这里应该设置为CKPH=0CKPL=0.
3.              手册20页的公共点参考电压的公式似乎也由点问题,这里是AVDD-0.2V我觉得不对,应该是VREF+,因为如果按以上公式计算出的公共参考电压,有可能最大幅值超过VREF+,也就是AD不能正确的采集出实际数值。
4.              手册第19页中设置CHNSET[2:0]=011时,1,2,5,6,7,8是用来测量AVDD/2,而3,4是用来测量DVDD/2,我设计的电路板是AVDDDVDD电压相同,通过磁珠连接,结果测试出来的数据1,2,5,6,7,8 比我计算的理论数据差了10000多,而3.4比理论数据差了1000多,这两组之间也差了10000多,这个问题我现在也没搞明白,请TI的工程师和使用过的朋友解答一下吧。
5.              当我用心电模拟仪输入信号时,(我的设计中1,2,3,4,5,6,7,8分别对应II,III,V1,V2,V3,V4,V5,V6,发现但我设置8个通道检测导联脱落时(即设置LOFF_SENSP=0XFF, LOFF_SENSN=0XFF),II,III的基线与V1V2V3V4V5V6相差10000多,如果设置LOFF_SENSP=0X00, LOFF_SENSN=0X00时,即不检测导联脱落时,II,III,V1,-V6就在同一基线上了。这个也没搞明白。有待朋友们解答。
6.              当心电模拟仪测试信号好用后,我实测人体信号,发现各路信号基线都不一致,我调试了半个月也没调出来,(我的设计基本上是抄TI的设计指南里的原理图的,我也明白为什么TI设计指南里为什么没有给出实测人体信号!,估计它的板子也一样有这个问题),后来请教TI的技术支持工程师JHL老师,他说要加高通滤波器,后来我在输入进ADS1198前加了各种高通滤波器,发现最实用的竟然是用0.1UF10M电阻,这样这8路信号基本上在一条直线上了,(V1偏差大一点与其他的基线差100左右),但加了电阻电容滤波后,用心电模拟仪再测量时,原本一致的基线现在反而有偏差了,我是搞糊涂了!另外今天刚看到JHL老师的回复,说他说的加高通滤波实际上是软件滤波,如果是这样的话,看来我用430就不行了,应该改DSPFFT变换吧!
 
总结一下,ADS1198/1298的确集成了很多ECG电路,比如8路仪表放大,威尔逊网络,内部测试信号,导联脱落检测(我用着不好使,呵呵)等等,而且也降低了功耗,节省了成本。是做便携式设备很好的选择,但问题也很大,内部只有前级放大,没有加二级放大,同时由于集成度太高,仪表放大后直接进AD,不能加高通,低通,以及抗肌电干扰等电路。这些工作恐怕全部要留给上位机用软件来解决,至于能解决到什么程度,我就不知道了!
以上就是个人使用ADS1198/1298的一些心得,能解决的问题以及遗留的问题,由于本人能力有限,估计会有很多错误和误解。以上所写,仅供大家参考,谢谢!
 
                                                                    作者:liangzuolin
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
一下附上我用430开发的程序,已经调试通过,仅供参考!
#define  ADS1198_CS0             P3OUT &= ~BIT0
#define  ADS1198_CS1             P3OUT |=  BIT0
#define  ADS1198_START0          P2OUT &= ~BIT5
#define  ADS1198_START1          P2OUT |=  BIT5
#define  ADS1198_RST0            P2OUT &= ~BIT6
#define  ADS1198_RST1            P2OUT |=  BIT6
#define  ADS1198_PWDN0           P2OUT &= ~BIT4
#define  ADS1198_PWDN1           P2OUT |=  BIT4
#define  ADS1198_READY           (P2IN&0x40)
#define  RDATAC                  0x10
#define  SDATAC                  0x11
#define  FALSE                   0
#define  TRUE                    1
#define  Addr_ID                 0x00
#define  Addr_CONFIG1            0x01
#define  Addr_CONFIG2            0x02
#define  Addr_CONFIG3            0x03
#define  Addr_LOFF               0x04
#define  Addr_CH1SET             0x05
#define  Addr_CH2SET             0x06
#define  Addr_CH3SET             0x07
#define  Addr_CH4SET             0x08
#define  Addr_CH5SET             0x09
#define  Addr_CH6SET             0x0A
#define  Addr_CH7SET             0x0B
#define  Addr_CH8SET             0x0C
#define  Addr_RLD_SENSP          0x0D
#define  Addr_RLD_SENSN          0x0E
#define  Addr_LOFF_SENSP         0x0F
#define  Addr_LOFF_SENSN         0x10
#define  Addr_LOFF_FLIP          0x11
#define  Addr_LOFF_STATP         0x12
#define  Addr_LOFF_STATN         0x13
#define  Addr_GPIO               0x14
#define  Addr_PACE               0x15
#define  Addr_CONFIG4            0x17
#define  Addr_WCT1               0x18
#define  Addr_WCT2               0x19
//-------------------------------------------------------------------------
//                ADS1198 spi 接口初始化
//-------------------------------------------------------------------------
void ADS1198_Spi_Init(void)
{ 
     P3SEL |= 0x0E;                                        // P3.1,P3.2,P3.3复用功能
     UCB0CTL1 |= UCSWRST;                                  // Put state machine in reset
     UCB0CTL0 |= UCMST+UCSYNC+UCMSB;                       // 3-pin, 8-bit SPI Master,MSB first,Mode 0(ucckpl=0,ucckph=1)
     UCB0CTL1 |= UCSSEL_2;                                 // SMCLK
     UCB0BR0 = 0x04;                                       // /4
     UCB0BR1 = 0;                                          //
     UCB0CTL1 &= ~UCSWRST;                                 // 开启SPI
}
//-------------------------------------------------------------------------
//               发送ADS1198单字节命令
//-------------------------------------------------------------------------
void ADS1198_Send_CMD_One(uchar cmd)
{
     while (!(UCB0IFG&UCTXIFG));                           // USCI_B0 TX buffer ready?
     UCB0TXBUF = cmd;                                      // Transmit data
}
//-------------------------------------------------------------------------
//               传输ADS1198多字节命令
//-------------------------------------------------------------------------
void ADS1198_Send_CMD_Muti(uchar cmd,uchar len,uchar dat[])
{
     uchar i;
     ADS1198_Send_CMD_One(cmd);                            // 发送第一字节命令+地址
     ADS1198_Send_CMD_One(len-1);                          // 发送第二字节命令,发送数据长度
     for(i=0;i<len;i++)
     {
         ADS1198_Send_CMD_One(dat[i]);                     // 发送多字节数据
     }
}  
//-------------------------------------------------------------------------
//              接收ADS1198多字节命令
//-------------------------------------------------------------------------
uchar ADS1198_Recive_Data(uchar cmd,uchar len,uchar dat[])
{
     uchar i;
     ADS1198_Send_CMD_One(cmd);                            // 发送接收命令第一字节+地址
     ADS1198_Send_CMD_One(len-1);                          // 发送接收第二字节命令,接收数据长度
     for(i=0;i<len;i++)
     {
         ADS1198_Send_CMD_One(0);                          // 发送SPI时钟,DOUT=0
         SomeNOP();SomeNOP();SomeNOP();SomeNOP();          // 延时
         SomeNOP();SomeNOP();SomeNOP();SomeNOP();
         if(UCB0IFG&UCRXIFG)                               // 判断接收标志
         {
             dat[i] = UCB0RXBUF;                           // 接收数据字节
         }
         else
         {
             return FALSE;
         }
     }
     return TRUE;
} 
//-------------------------------------------------------------------------
//              连续采集模式下接收数据
//-------------------------------------------------------------------------
uchar ADS1198_ReadData_Continue(uchar dat[],uchar len)
{
     uchar i;
     for(i=0;i<len;i++)
     {
         ADS1198_Send_CMD_One(0);                          // 发送SPI时钟,DOUT=0
         SomeNOP();SomeNOP();SomeNOP();SomeNOP();          // 延时
         SomeNOP();SomeNOP();SomeNOP();SomeNOP();
         if(UCB0IFG&UCRXIFG)                               // 判断接收标志
         {
             dat[i] = UCB0RXBUF;                           // 接收数据字节
         }
         else
         {
             return FALSE;
         }
     }
     return TRUE;  
}
//-------------------------------------------------------------------------
void ADS1198_Init(void)
{
     uchar d[8];
     P2DIR |= 0x60;                                        // ads1198 RST,READY管脚输出
     P3DIR |= 0x01;                                        // ADS1198 CS 管脚输出
     ADS1198_CS0;                                          // 选中ADS1198
     ADS1198_PWDN1;                                        // 禁止进入低功耗模式
     ADS1198_START0;                                       // 禁止采集
     ADS1198_RST1;                                         // 复位置高
     delayMS(1000);                                        // 延时1S
     ADS1198_RST0;                                         // 复位1198
     delayMS(100);                                         // 延时100MS   
     ADS1198_RST1;                                         // 复位清除
     delayMS(1);
     ADS1198_Send_CMD_One(SDATAC);                         // 发送停止命令
     ADS1198_Recive_Data(0x20+Addr_ID,1,d);                // ADS1198 ID
     if(d[0]==0xB6)                                        // 判断是否为ADS1198 ID
     {
         d[0] = 0xCC;                                      // 内部参考+2.4V+RLDREF(AVDD-AVSS)/2+RLD buffer允许+RLD检测允许
         ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG3,1,d);     // 配置寄存器
         d[0] = 0x45;                                      // Multiple readback+250SPS
         ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG1,1,d);     // 配置寄存器
         d[0] = 0x34;                                      // INT_TEST内部测试信号+-2X测试信号)+Fclk/2.048M
         ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG2,1,d);     // 配置寄存器
         d[0] = 0x33;                                      // (7.5%/92.5%)+Pull-up/pull-down mode+DC lead-off detection turned on
         ADS1198_Send_CMD_Muti(0x40+Addr_LOFF,1,d);
         d[0]=0x60;d[1]=0x60;d[2]=0x60;d[3]=0x60;d[4]=0x60;d[5]=0x60;d[6]=0x60;d[7]=0x60;// 12倍增益+正常导联输入
         //d[0]=0x65;d[1]=0x65;d[2]=0x65;d[3]=0x65;d[4]=0x65;d[5]=0x65;d[6]=0x65;d[7]=0x65;// 12倍增益+测试信号输入
         ADS1198_Send_CMD_Muti(0x40+Addr_CH1SET,8,d);
         d[0] = 0x01;d[1] = 0x03;                          // RLD1P,RLD1N,RLD2N对应R,L,F,为右腿驱动源
         ADS1198_Send_CMD_Muti(0x40+Addr_RLD_SENSP,2,d);   // 配置寄存器
         d[0] = 0x00;d[1] = 0x00;                          // 8个通道不检测测导联脱落
         ADS1198_Send_CMD_Muti(0x40+Addr_LOFF_SENSP,2,d);  // 配置寄存器
         d[0] = 0x01;                                      // 通道1,通道2作为起搏检测通道,开启起搏检测缓冲器
         ADS1198_Send_CMD_Muti(0x40+Addr_PACE,1,d);        // 配置寄存器
         d[0] = 0x02;                                      // 持续转换模式+Lead-off comparators enabled
         ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG4,1,d);
         d[0] = 0x08;d[1] = 0xCB;                          // power on WCTA+WCTB+WCTC,RLD1P,RLD1N,RLD2N为威尔逊中心信号源
         ADS1198_Send_CMD_Muti(0x40+Addr_WCT1,2,d);
         ADS1198_Send_CMD_One(RDATAC);                     // 连续读命令
         ADS1198_START1;                                   // 开始数据采集
     }
}    
//--------------------------------------------------------------------------
 
 
 
 
 
 

 

  • 附件中为本文的WORD文档,因为有几张图片这里显示不出来,如果需要详细了解请下载附件!

    ADS1198开发设计心得与遗留问题总结.doc
  • 非常感谢您的分享!!

  • Hi  zuolin liang :

    MSP430F5X系列的MCU内置硬件乘法器,当做乘法运算的时候CCS能够自动调用硬件乘法器,可以完成一些DSP功能。另外,心电信号是几百赫兹以内的信号,使用430完全可以实现数字滤波器的算法。

    这是一篇ti MSP430 关于滤波器的算法的文档,供楼主参考:

    www.ti.com/.../slaa331.pdf

  • 谢谢“秋之初”的指点,非常感谢!

  • 非常感谢你的分享,我正在学习使用ads1298,对我帮助很大,我想问一下,你的msp430的MCLK设置为多少?在ads1198初始化部分有P2DIR |= 0x60; // ads1198 RST,READY管脚输出,READY指的是DRDY这根线么,对单片机而言,它不应该设置成输入么?关于上电复位的延时,手册上是按照tCLK来的,而你的代码中给出了时间,是经验值么?希望能帮助解答一下,非常感谢

  • #define  ADS1198_CS0             P3OUT &= ~BIT0

    #define  ADS1198_CS1             P3OUT |=  BIT0

    #define  ADS1198_START0          P2OUT &= ~BIT5

    #define  ADS1198_START1          P2OUT |=  BIT5

    #define  ADS1198_RST0            P2OUT &= ~BIT6

    #define  ADS1198_RST1            P2OUT |=  BIT6

    #define  ADS1198_PWDN0           P2OUT &= ~BIT4

    #define  ADS1198_PWDN1           P2OUT |=  BIT4

    #define  ADS1198_READY           (P2IN&0x80)      //----------修改

    #define  RDATAC                  0x10

    #define  SDATAC                  0x11

    #define  FALSE                   0

    #define  TRUE                    1

    #define  Addr_ID                 0x00

    #define  Addr_CONFIG1            0x01

    #define  Addr_CONFIG2            0x02

    #define  Addr_CONFIG3            0x03

    #define  Addr_LOFF               0x04

    #define  Addr_CH1SET             0x05

    #define  Addr_CH2SET             0x06

    #define  Addr_CH3SET             0x07

    #define  Addr_CH4SET             0x08

    #define  Addr_CH5SET             0x09

    #define  Addr_CH6SET             0x0A

    #define  Addr_CH7SET             0x0B

    #define  Addr_CH8SET             0x0C

    #define  Addr_RLD_SENSP          0x0D

    #define  Addr_RLD_SENSN          0x0E

    #define  Addr_LOFF_SENSP         0x0F

    #define  Addr_LOFF_SENSN         0x10

    #define  Addr_LOFF_FLIP          0x11

    #define  Addr_LOFF_STATP         0x12

    #define  Addr_LOFF_STATN         0x13

    #define  Addr_GPIO               0x14

    #define  Addr_PACE               0x15

    #define  Addr_CONFIG4            0x17

    #define  Addr_WCT1               0x18

    #define  Addr_WCT2               0x19

    //-------------------------------------------------------------------------

    //                ADS1198 spi 接口初始化

    //-------------------------------------------------------------------------

    void ADS1198_Spi_Init(void)

    {  

        P3SEL |= 0x0E;                                        // P3.1,P3.2,P3.3复用功能

        UCB0CTL1 |= UCSWRST;                                  // Put state machine in reset

        UCB0CTL0 |= UCMST+UCSYNC+UCMSB;                       // 3-pin, 8-bit SPI Master,MSB first,Mode 0(ucckpl=0,ucckph=1)

        UCB0CTL1 |= UCSSEL_2;                                 // SMCLK

        UCB0BR0 = 0x04;                                       // /4

        UCB0BR1 = 0;                                          //

        UCB0CTL1 &= ~UCSWRST;                                 // 开启SPI

    }

    //-------------------------------------------------------------------------

    //               发送ADS1198单字节命令

    //-------------------------------------------------------------------------

    void ADS1198_Send_CMD_One(uchar cmd)

    {

        while (!(UCB0IFG&UCTXIFG));                           // USCI_B0 TX buffer ready?

        UCB0TXBUF = cmd;                                      // Transmit data

    }

    //-------------------------------------------------------------------------

    //               传输ADS1198多字节命令

    //-------------------------------------------------------------------------

    void ADS1198_Send_CMD_Muti(uchar cmd,uchar len,uchar dat[])

    {

        uchar i;

        ADS1198_Send_CMD_One(cmd);                            // 发送第一字节命令+地址

        ADS1198_Send_CMD_One(len-1);                          // 发送第二字节命令,发送数据长度

        for(i=0;i<len;i++)

        {

            ADS1198_Send_CMD_One(dat[i]);                     // 发送多字节数据

        }

    }  

    //-------------------------------------------------------------------------

    //              接收ADS1198多字节命令

    //-------------------------------------------------------------------------

    uchar ADS1198_Recive_Data(uchar cmd,uchar len,uchar dat[])

    {

        uchar i;

        ADS1198_Send_CMD_One(cmd);                            // 发送接收命令第一字节+地址

        ADS1198_Send_CMD_One(len-1);                          // 发送接收第二字节命令,接收数据长度

        for(i=0;i<len;i++)

        {

            ADS1198_Send_CMD_One(0);                          // 发送SPI时钟,DOUT=0

            SomeNOP();SomeNOP();SomeNOP();SomeNOP();          // 延时

            SomeNOP();SomeNOP();SomeNOP();SomeNOP();

            if(UCB0IFG&UCRXIFG)                               // 判断接收标志

            {

                dat[i] = UCB0RXBUF;                           // 接收数据字节

            }

            else

            {

                return FALSE;

            }

        }

        return TRUE;

    }  

    //-------------------------------------------------------------------------

    //              连续采集模式下接收数据

    //-------------------------------------------------------------------------

    uchar ADS1198_ReadData_Continue(uchar dat[],uchar len)

    {

        uchar i;

        for(i=0;i<len;i++)

        {

            ADS1198_Send_CMD_One(0);                          // 发送SPI时钟,DOUT=0

            SomeNOP();SomeNOP();SomeNOP();SomeNOP();          // 延时

            SomeNOP();SomeNOP();SomeNOP();SomeNOP();

            if(UCB0IFG&UCRXIFG)                               // 判断接收标志

            {

                dat[i] = UCB0RXBUF;                           // 接收数据字节

            }

            else

            {

                return FALSE;

            }

        }

        return TRUE;  

    }

    //-------------------------------------------------------------------------

    void ADS1198_Init(void)

    {

        uchar d[8];

        P2DIR |= 0x60;                                        // ads1198 RST,START管脚输出----修改

        P3DIR |= 0x01;                                        // ADS1198 CS 管脚输出

        ADS1198_CS0;                                          // 选中ADS1198

        ADS1198_PWDN1;                                        // 禁止进入低功耗模式

        ADS1198_START0;                                       // 禁止采集

        ADS1198_RST1;                                         // 复位置高

        delayMS(1000);                                        // 延时1S

        ADS1198_RST0;                                         // 复位1198

        delayMS(100);                                         // 延时100MS    

        ADS1198_RST1;                                         // 复位清除

        delayMS(1);

        ADS1198_Send_CMD_One(SDATAC);                         // 发送停止命令

        ADS1198_Recive_Data(0x20+Addr_ID,1,d);                // 读ADS1198 ID号

        if(d[0]==0xB6)                                        // 判断是否为ADS1198 ID

        {

            d[0] = 0xCC;                                      // 内部参考+2.4V+RLDREF(AVDD-AVSS)/2+RLD buffer允许+RLD检测允许

            ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG3,1,d);     // 配置寄存器

            d[0] = 0x45;                                      // Multiple readback+250SPS

            ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG1,1,d);     // 配置寄存器

            d[0] = 0x34;                                      // INT_TEST内部测试信号+(-2X测试信号)+Fclk/2.048M

            ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG2,1,d);     // 配置寄存器

            d[0] = 0x33;                                      // (7.5%/92.5%)+Pull-up/pull-down mode+DC lead-off detection turned on

            ADS1198_Send_CMD_Muti(0x40+Addr_LOFF,1,d);

            d[0]=0x60;d[1]=0x60;d[2]=0x60;d[3]=0x60;d[4]=0x60;d[5]=0x60;d[6]=0x60;d[7]=0x60;// 12倍增益+正常导联输入

            //d[0]=0x65;d[1]=0x65;d[2]=0x65;d[3]=0x65;d[4]=0x65;d[5]=0x65;d[6]=0x65;d[7]=0x65;// 12倍增益+测试信号输入

            ADS1198_Send_CMD_Muti(0x40+Addr_CH1SET,8,d);

            d[0] = 0x01;d[1] = 0x03;                          // RLD1P,RLD1N,RLD2N对应R,L,F,为右腿驱动源

            ADS1198_Send_CMD_Muti(0x40+Addr_RLD_SENSP,2,d);   // 配置寄存器

            d[0] = 0x00;d[1] = 0x00;                          // 8个通道不检测测导联脱落

            ADS1198_Send_CMD_Muti(0x40+Addr_LOFF_SENSP,2,d);  // 配置寄存器

            d[0] = 0x01;                                      // 通道1,通道2作为起搏检测通道,开启起搏检测缓冲器

            ADS1198_Send_CMD_Muti(0x40+Addr_PACE,1,d);        // 配置寄存器

            d[0] = 0x02;                                      // 持续转换模式+Lead-off comparators enabled

            ADS1198_Send_CMD_Muti(0x40+Addr_CONFIG4,1,d);

            d[0] = 0x08;d[1] = 0xCB;                          // power on WCTA+WCTB+WCTC,RLD1P,RLD1N,RLD2N为威尔逊中心信号源

            ADS1198_Send_CMD_Muti(0x40+Addr_WCT1,2,d);

            ADS1198_Send_CMD_One(RDATAC);                     // 连续读命令

            ADS1198_START1;                                   // 开始数据采集

        }

    }    

    是在抱歉,感谢楼上兄弟的提醒,有2个地方的注释修改了。我的READY是P2.7管脚,而原来定义的#define  ADS1198_READY           (P2IN&0x40)---这句是错的,但我在其他程序中调用P2.7的中断这个宏定义没有用上,所以就没看出这个错误!

    //--------------------------------------------------------------------------

  • //------------------------------------------------------------------------

    //              系统工作频率设置函数

    //              系统工作频率为2M HZ

    //        初始化主时钟: MCLK = REFO×(FLL_FACTOR+1)=2M,ACLK=REFO=32K              

    //------------------------------------------------------------------------

    void UCS_Clock_Config(void)

    {

       UCSCTL3 |= SELREF_2;                              // Set DCO FLL reference = REFO

       UCSCTL4 = SELA_2+SELM_4+SELS_4;                   // Set ACLK = REFO,MCLK=DCODIV,SMCLK=DCODIV

       __bis_SR_register(SCG0);                          // Disable the FLL control loop

       UCSCTL0 = 0x0000;                                 // Set lowest possible DCOx, MODx

       UCSCTL1 = DCORSEL_3;                              // Select DCO range 4MHz operation

       UCSCTL2 = FLLD_1 + 124;                           // Set DCO Multiplier for 4MHz

                                                         // (N + 1) * FLLRef = Fdco

                                                         // (124 + 1) * 32768 = 4MHz

                                                         // Set FLL Div = fDCOCLK/2

       __bic_SR_register(SCG0);                          // Enable the FLL control loop

       // Worst-case settling time for the DCO when the DCO range bits have been

       // changed is n x 32 x 32 x f_MCLK / f_FLL_reference. See UCS chapter in 5xx

       // UG for optimization.

       // 32 x 32 x 4 MHz / 32,768 Hz = 125000 = MCLK cycles for DCO to settle

       __delay_cycles(125000);

       // Loop until XT1,XT2 & DCO fault flag is cleared

       do

       {

           UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG);

                                                         // Clear XT2,XT1,DCO fault flags

           SFRIFG1 &= ~OFIFG;                            // Clear fault flags

       }while (SFRIFG1&OFIFG);                           // Test oscillator fault flag

    }

    以上是频率设置函数,上电复位延时是怎么定的我记不清了,应该就是个经验值!呵呵!

  • 不客气,也感谢你的回复和分享,我是新手,以后遇到问题还请多多指教

  • 好贴

    就需要这个的经验分享

  • Zuolin Liang,

    你的反馈及任何意见对TI公司及产品来说都是非常宝贵的,它可以帮助TI公司及设计人员作出更符合特定市场需求的产品!谢谢!

    对你的疑问及问题,有以下回复供参考。

    1, 关于精度(16/24bit)的问题。考虑到很多来自人体的心电信号中有极化电压高达几百mV, 还有pace pulse,两者叠加在一起时,就需要较大动态范围了。另外专业ECG的RTI noise 要求15uVpp以下,所以16bit肯定是不够的。另外,以前的ECG需要很多颗运放,三级模拟处理,12bit ADC就够用了。而ADS129x只需一片就够用了,而且只需设置PGA GAIN=6就够用了, 这也正是高精度的24bit ADC的重要作用,即使对幅度很小的信号,它可以保证足够高的分辨率。

    2,EEG的信号幅度很小,如你所说uV级。 但是TI ADS1299 for EEG的RTI noise<1.0uV p-p* (70Hz BW),是专门针对脑电的。

    3,AVDD-0.2V是absolute input voltage,超过Vref确实没用处,但允许超过。

    4,COPL 和 CPHA 的注释和你的结果有差异,极可能是笔误,容我们确认一下,稍后反馈。

    5,AVDD和DVDD测量误差的问题,去掉AVDD and DVDD之间的磁珠看一下,所测误差值是多少?电流流过磁珠必然会有压降。对24bit ADC, 2.4V基准来说, 两三豪伏的差分电压输入就会产生10000个以上的数字量输出。

    6,当电极脱落时,CH1 CH2的两对差分输入自然就100%悬空了,但是对CH3~CH8不同,因为伴随V1~V6输入的是WCT,其源输出阻抗是不能忽略的,所以差分信号肯定会有一定偏移,高通滤波器同样可以去除它。

    7,个人认为MSP430运行大量的FFT肯定不够用,如果是做holter,考虑到低功耗及运算能力,还有价格因素等, TMS320C553x DSP是不错的选择。但是如果算法过于复杂,推荐用32bit ARM.

    8,导联检测需要设置相关的寄存器,比如 DC lead off, 特定情况下还要调整 comparator的threshold register setting。如果现场有强干扰,软件做一些智能判断会使这个功能更实用。

    9,前面提到过, 即使一级放大只有6倍增益,分辨率已经足够用了,因为有高精度24bitADC。 所谓有得必有失, 集成度高了,所以就不需要以前传统的硬件高通滤波器了,而且硬件高通对电容的要求不是一般的高。 当今的CPU处理器速度越来越快,简单的滤波器不会占用什么资源。从做产品的角度来看,只要在软件中能实现的,尽量不用硬件做,这早已是行业共识。它不仅能节省成本,更能为今后产品服务灵活省级。

    Regards,

    JHL

  • 谢谢JHL老师的指点,很多疑惑我都解释清楚了!因为搞这东西的时间很短,很不专业,所以有些问题可能很幼稚让您见笑了!另外,有2个问题麻烦您有空试验下.1是AVDD,DVDD测量误差的问题,我曾经怀疑过时磁珠的问题,就把磁珠去掉,用跳线短接了,可是问题依旧!2就是CH1,CH2的基线电压比CH3-CH8基线高的问题,这种情况是在连接心电模拟仪就出现的,不存在电极脱落的情况!

  • 非常感谢楼主的分享。但又个问题不明白  ADS1298_SpiSend_CMD_One(0);                          // 发送SPI时钟,DOUT=0

    这句话的意义何在呢?时钟不是应该由430的uclk管脚发出去吗?

  • To Zuolinliang,

    之前提到的CPOL = 0 and CPHA = 1 是针对MCU SPI的设置,这个设置的作用是 SLCK在空闲时是低电平,MCU SPI口会在SCLK的上升沿发送数据到ADS1198 SDI,而在SLCK的下降沿锁存ADS1198的输出数据。因此ADS1198 datasheet Figure1的波形和CPOL = 0 and CPHA = 1时一致的。如果你的实测结果不同且怀疑是ADS1198 SPI 口的问题,请用示波器看一下SPI 的 SCLK/SDI/SDO的波形。

    1,即使外部电源AVDD DVDD相同,内部的电源通路或架构也可能会产生几个mV的差异。你可以计算下10000LSB对应几个豪伏。即使AVDD DVDD之间有微小偏差也不会影响正常使用时有效信号的准确测量。想一下,DVDD是控制数字逻辑功能模块的。

    2,这也是源阻抗不同造成的偏差,只要不是严重的基线飘移,后端软件都可以处理好。

    Regards,

    JHL

  • 看来兄弟对SPI协议不是很了解啊!SPI的CLK是由主机发送出来的,如果要接收从机的数据,主机就要发送一下无关的数据,目的是在发送的时候启动CLK,这样在发送的同时数据就跟着接收到了!这条语句的目的就是发送一个无关紧要的0,目的是发送完后同时也就接收到了1字节数据!

  • 谢谢JHL老师的指点!

    1.手册上说的CPOL=0和CPHA=1,我不知道到底指的是什么意思,但是对用的MSP430的SPI中要设置CKPH=0,CKPL=0才能正确接收到数据!也许对于其他的单片机设置CPOL=0和CPHA=1是正确的!

    2.AVDD,DVDD相同,而ADS1198是16位的,相差10000就相当于相差了0.4V的电压,这个实在是说不过去!当然这个在实际应用中似乎也没有影响到各个通道的数据采集!只是感觉很不对劲!

    3.CH1-CH2比CH3-CH8基线高这个问题,只要8个通道不检测测导联脱落就可以解决,但我就不能用导联脱落检测这个功能了!呵呵

  • 1,CPOL CPHA有很多公开的描述,在此不多写。 建议对照波形及MSP430的相关设置,还有ADS1198 datasheet figure1 来验证。

    2,  我之前是按照24bit ADC计算的,所以一直在讲几个豪伏。 ADS1198的datasheet 描述有笔误, CH3, 4测出来应该是 1/4(MVDDP-MVDDN),TI会尽快修改ADS1198 datasheet. 另外ADS1298 datasheet对此描述是对的。但是你得到0.4V肯定是不对的,你读出的数值应该差接近10922LSB左右,这样才符合查值(AVDD/2 - DVDD/4) = 0.8V。

    3,导联脱落打开,各通道基线不同是可以用软件处理好的。即使不打开导联检测,各通道之间也有微小的offset,都可以软件滤波形式处理掉。

  • 确实以前没用过spi协议 之前也只理了一下spi的时序。 明白了, 非常感谢老兄了。

  • 请教关于数据读取的问题,数据转换完毕后,是在DIDY的上升沿读呢,还是下降沿呢,还有读到的数据貌似噪声很大啊,前端不需要噪声处理的么

  • 哈哈,这回明白了,谢谢JHL老师指点!

    另外,我采集到的数据的确接近10922,我当初是这么想的,16位AD对应65535,而AD参考电压是2.4V,10922/65535*2.4=0.4V。呵呵

  • 什么沿读手册上有详细介绍,另外不是前段不需要加噪声处理,而是1198加不了噪声处理,只能通过单片机或电脑进行软件滤波,这点我也感觉很郁闷!

  • 您好 我用你的这个代码调试时运行到 while (!(UCB0IFG&UCTXIFG));         这一步时卡住了,直接原地不动死循环了。意思就是说之前缓存中的数据没发出去,请问这是为什么。您当初调试时没出现这种情况吗

  • 没有遇到你说的情况,出现你这种问题和ADS1198/1298没有什么关系,是不是你的芯片里没有SPI模块啊,是MSP430F5418这个芯片么?

  • 请问在设计这个ECG采集电路的时候有没有遇到人体引入noise过大的问题? 人体从环境中采集的大量工频noise和其他频率的noise让我很头疼,请问您是怎么处理的?依赖工频限波还是其他电路?另外,有没有将整个pcb板用屏蔽的金属外壳装起来?谢谢!

  • 楼主您确定主机的spi时钟要设置为CPOL=0和CPHA=0?我现在在用ADS1298R,一直写不进去寄存器,是不是时钟的问题?

  • 楼主留下邮箱,交流交流吧,我也用的430,用你的程序模板写的,能调通,就是测试人体的时候感觉数据不对啊。我的邮箱:chenyongpeng001@163.com。谢谢。

  • 你好,用你的程序做心电采集,但是DRDY引脚持续为高电平,不知为何?恳请指教!

  • 楼主,我能否将您的电路图发给我参考一下,我也在做这个,605775252@qq.com

  • 你好,我想问一下,按照你的程序框架,为什么我读出的1298的ID号始终为254?好似数据无法写入,可能是什么原因呢?

  • JHL您好

    请问ADS1299EEG-FE支持哪几款脑电电极?我们最近想用针状颅内深部电极进行信号采集,请问这块板子支持吗?

  • 您好,您现在有这个电路图了吗 能不能发我一份 万分感谢!

  • 我记得好像有TI的文档附电路图的,晚上了没找到,明天有空再看看吧

  • 你好 能否将你的电路图给我发一份参考下 现在处于焦头烂额的状态 bruellyyang@126.com谢谢

  • Hi JHL,

    我现在想用ads1299测脑电,我用的是ti的那个评估板,现在我能在通道1测量到test signal,也就是片子内部产生的那个方波,但是我用正常输入模式时,外接信号发生器的方波,正向输入端接信号端,反相输入端接信号地,就完全检测不到信号发生器产生的方波,请问这是怎么回事啊?

  • 你好,zuolin liang

    我现在在用ads1299测脑电,遇到一些问题,想向你请教一下,我现在可以检测到test signal,但是正常输入模式,外接信号发生器的方波时,却检测不到信号,正向输入端接信号,反相输入端接信号地,请问这是怎么回事啊?

  • 亲,有相关于ADS1299的程序吗?有的话方便发我一份吗?万分感谢  邮箱:974002504@qq.com

  • 关于ads129x的CPOL和CPHA的问题,我用的是STM32,要设置成CPOL=0,和CPHA=1的模式,对于stm32的设置来讲,要设成以下模式:

    hspi2.Init.CLKPolarity = SPI_POLARITY_LOW;
    hspi2.Init.CLKPhase = SPI_PHASE_2EDGE;

    在调试过程中可以看到,设置为CPOL=0,CPHA=1.

     楼主有心人,把学习过程记录了下来,给大家分享,有心了。好像楼主也是用于EEG/ECG的测量用途,我也是,希望有空多交流。

  • 你好,JHL

    我用ADS1194时,发现CONFIG1寄存器写不进去,我写了寄存器然后再回读的,只有CONFIG1的值不对。还有一个奇怪的问题,只要对寄存器进行过操作,就读不到测量数据。

        SPI_CS1;
        SPI_START0;
        SPI_PWDN1;          
        SPI_RESET1;            
        HAL_Delay(100);
        SPI_RESET0;             
        HAL_Delay(100);
        SPI_RESET1;           
        HAL_Delay(1000);
        ADS_WriteByte(ADS_SDATAC);      
        ADS_WReg(CONFIG1, 0x20);    
        ADS_WReg(CONFIG2, 0x10);
        ADS_WReg(CONFIG3, 0xE8);  
        ADS_WReg(CONFIG4, 0x00);  
        ADS_WReg(CH1SET, 0x05);       
        ADS_WReg(CH2SET, 0x05);
        ADS_WReg(CH3SET, 0x05);
        ADS_WReg(CH4SET, 0x05);     
        ADS_WriteByte(ADS_RDATAC);     
        SPI_START1;
        SPI_CS1;             

    这是我上电初始化的代码,请您帮忙看下哪里有问题吗?

  • 实在报歉,这个项目我调试的差不多就离职了,现在不但不做医疗了,连单片机也由430换为stm32了,这个项目的情况早都忘没了,帮不了大家了。

  • 问题解决,寄存器写不进去是因为前面的SDATAC命令没有拉高CS,等到后面写完寄存器才拉高的,所以第一个寄存器的值被忽略了。

  • 您好,关于ADS1298的SPI通信我遇到了一些问题。为什么ADS1298上电之后,VCAP1是1.1v+,我读取或写入ADS1298寄存器数据的时候总是返回0xff呢?

    (单片机SPI的输出我也看过了,是正确的。然后是一些配置的检查,时钟极性配置没有问题,也顾忌到了ADS1298的解码时间。)

  • 你的问题解决了吗?如果解决了是怎么回事?