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.

关于ADS1118与CC2530的SPI通信问题

Other Parts Discussed in Thread: ADS1118, CC2530, ADS1110, ADS1115

参照ADS1118的说明书,我使用CC2530的串口1的SPI方式向ADS1118连接写入4个字节的命令,我想问一下我如何才从ADS1118中读回命令寄存器中的值呢。意思就是在我写入命令字之后,我应该怎样操作才能读回这些值,我现在直接读U1DBUF的值完全与我写进去的不一样啊。谢谢

  • 这个我还真知道,嘿嘿.......如果你用的是硬件SPI的话

    1、命令是16位的,返回值是32位的。手册上有说

    2、发送数据形式形如0xYYYY0000,YYYY是命令,参考手册,0000后面解释。

    3、发送前要把CS拉低。

    4、根据硬件SPI寄存器的位数,确定发送数据的划分,比如16位的,就先发0xYYYY,再发0x0000;8位的就是0xYY,0xYY,0x00,0x00分四次发送.。

    5、硬件SPI,把发送数据赋写到SPI寄存器里,用中断方式或者查询方式读取,不过查询方式可能会遇到一些问题。

    6、因为将要发送的数据写入SPI的数据寄存器后,即被发送,同时伴随的是CLK线上输出,这个是硬件完成,可以不管,但是可以将示波器引线接到CLK脚上,看看波形。如果此时CS线已经被拉低,CLK上的输出的时钟脉冲就会驱动ADS1118将其数据寄存器中的内容从DOUT(沿MISO线)发送给MCU。因为返回值是32位的,所以在命令发完后还要继续发16位的0,以便驱动CLK输出脉冲,并用该脉冲驱动ADS1118将后续16位值发送回来。

    7、发送的过程就是:拉低CS;写MCU硬件SPI数据寄存器,等待MCU的发送完成标志位;再写........;拉高CS。

    8、读取的过程就是:启用中断,中断处理程序中直接读MCU硬件SPI的数据寄存器。

  • 我现在是这样子写的:

    void InitialADS(void)//初始化ADS1118,写入默认的0x8583

    {

      uint8 cmd[4]={0x85,0x83,0x00,0x00};

     //拉低SSN,片选信号使能

     SSN = 0;

     //写入命令字初始化ADS1118工作方式

     while(!U1TX_BYTE);

     for(int i=0;i<4;i++)//写入两次命令字

     {

       U1DBUF = cmd[i];

       while(!U1TX_BYTE);

     }

     SSN = 1;

    }

    然后读取的时候

    void ReadVoltage(uint8 *voltage)//读取电压数据

    {

     //开启转换

     uint8 cmd[8]={0xD5,0x83,0x00,0x00};

     SSN = 0;

     //写入命令字初始化ADS1118工作方式

     for(int i=0;i<4;i++)//写入命令字,0xD5,0x83

     {

       U1DBUF = cmd[i];

       while(!U1TX_BYTE);

     }

    //需要延时吗?

     uint8 *p = voltage;

     for(int i=0;i<4;i++)

     {

       U1DBUF = 0x00;

       while(!U1TX_BYTE);

       p[i] = U1DBUF;

     }

     SSN = 1;

    }

    但是这样子读出来的数据是不对的啊

  •         看程序采用的似乎是查询方式,不建议采用这种方式,因为手册里“状态寄存器”bit0是数据准备好,似乎不管用,据说下一季度更新手册。现在判断数据准备好是根据DOUT的高电平。如果你使用中断方式的话,可以不去管这些。

            另外要注意的是bit4、bit3、bit2和bit1,具体的你去看看手册吧。

            我用的是命令字是0x898B和0x899B分别对应的是取TE和取AD,返回值形如“02 5A 09 8B 06 A7 09 9B”的32位数据,加重的是数值,不加重的是返回的状态寄存器值。其中状态寄存器返回值与你发送下去的可能会略有不同。

           关于程序的结构,中断方式的如下:

           SPI_写()//这是一次发送的,8位的发四次

            {

                MCU的SPI寄存器=要发送的命令字的一部分;

                WHILE(状态字【没有发送完】);

                状态字清除;

            }

             SPI_中断()

            {

                定义的变量=MCU的SPI寄存器;

            }

            查询方式的我没做过,应该是:

           SPI_写()//这是一次发送的,8位的发四次

            {

                MCU的SPI寄存器=要发送的命令字的一部分;  //写

                WHILE(状态字【没有发送完】);

                状态字清除;

               WHILE( ADS1118数据没有准备好);

               变量= MCU的SPI寄存器;                                      /读

            }

  •         你也可以把与SPI相关的程序完整的贴出来,我这儿也有CC2530和ADS1118,如果有时间的话可以调一下。

            另外,我建议你点击一下你问题左下角的“编辑标签“,并加入ADS1118和SPI,然后保存。这样以后其他人遇到类似问题,以ADS1118和SPI为关键字进行检索,可以检索的你的这一篇。重在分享么,我是这么理解的。同样,问题也是可以不断编辑的,所以,后续的问题你可以在原有问题里面接着写,用分割线隔开加上日期即可。

  • 好的,我自己试一下,太谢谢了,因为是第一次做这个,有点纠结,如果有问题我再贴出来,谢谢你呀

  • 我的代码是这样子写的:

    #define SSN P1_3
    #define MISO P1_7
    #define MOSI P1_6
    #define SCLK P1_5

    uint8 voltage[4]={0,0,0,0};
    uint8 counter = 0;

    void InitialUBARTSPI(void)//初始化SPI
    {
    //引脚绑定设置
    PERCFG |=0x02;//选择UBART1作为SPI模式
    P1SEL |=0xE0;//P1_7,P1_6,P1_5
    P1SEL &=~0x08;//P1_3为通用IO口(SSN)
    P1DIR |=0x08;//SSN的方向设为输出
    //SCLK频率设置,设置波特率11520,U1BAUD_M=216,U1GCR_E=11,波特率115200
    U1BAUD = 0xD8;
    U1GCR |= 0x0B;
    //操作模式,设置为Master模式
    U1CSR &= ~0xA0;
    //配置CPOL与CPHA,ADS1118要求CPOL=0,CPHA=1
    U1GCR &=~0x80;
    U1GCR |=0x40;
    //配置传输先后顺序,ADS1118要求先传高再传低
    U1GCR |=0x20;
    //设置P1_7中断模式
    P1DIR &=~0x80;
    P1IEN |=0x080;//使能P1_7中断
    PICTL |= 0x02; //下降沿触发
    IEN2 |=0x10;//端口1中断使能
    P1IFG &= ~0x80;
    EA = 1;//开启所有的中断
    }

    #pragma vector = P1INT_VECTOR
    __interrupt void P1_ISR(void)
    {
    P1IFG &=~0x80;//清除中断标志
    voltage[counter] = U1DBUF;
    counter++;
    if(counter>3)
    counter =0;
    P1IF = 0;
    }

    void InitialADS(void)//初始化ADS1118,写入默认的0x8583
    {
    uint8 cmd[4]={0x85,0x83,0x85,0x83};
    //拉低SSN,片选信号使能
    SSN = 0;
    //写入命令字初始化ADS1118工作方式
    while(!U1TX_BYTE);
    for(int i=0;i<4;i++)//写入两次命令字
    {
    U1DBUF = cmd[i];
    while(!U1TX_BYTE);
    U1TX_BYTE =0;//清除状态字
    }
    SSN = 1;
    }

    void StartConvert(void)//启动转换,写入命令字0xD593
    {
    uint8 cmd[8]={0xD5,0x83,0xD5,0x83};
    //拉低SSN,片选信号使能
    SSN = 0;
    //写入命令字初始化ADS1118工作方式
    for(int i=0;i<4;i++)//写入命令字,0xD5,0xE2
    {
    U1DBUF = cmd[i];
    while(!U1TX_BYTE);
    U1TX_BYTE = 0;
    }
    SSN = 1;
    }

  • 现在的疑问就是在读取数据的时候,怎样才能读取到4个字节的数据,是一次读呢,还是每次触发的时候读一个字节组成四个字节呢,因为看DataSheet上看得我有点迷惑。现在的情况好点了,因为写进命令字之后读出来的数据中有命令字了,就是顺序很乱,我感觉还是我读取的时候有问题。程序里我用的是用的ADS1118的AN1路来采集电压的

  •         从程序和命令字看没什么问题,而且也得到返回值了。下来是数据的问题,答案主要集中在手册的16和17页上。因为你使用的是默认值,关于最终数据结果的计算还要注意下面两部分的内容。(我也看了一下CC2530的手册,发现程序中已经注意到了模式设置和中断打开。)

            1、bit11-bit9,从这部分的描述看,ADS1118转换AD值是有量程的(其他人或许会有别的表述方式,我在这里用量程来表述),默认设定是把信号放大两倍,即输入量程除2。具体对应关系如下:

            000~0:  2/3倍,实际输入量程-6.114~+6.114;001~1: 1,倍,实际输入范围(实际量程)-4.096~+4.096......共2/3~16六个放大级别。

            要根据设定在换算过程中除以不同的放大倍率并进行格式转换才能还原到输入值;如果采集值是被后续电路处理的,且符合要求,就不用换算了,但是要根据设定值的意义告诉电路设计人员采集值的意义。

             2、bit7-bit5,这个与数据换算本身无关,但是与采集速率有关系,因为存在一个采样和准备好的过程,个人感觉与此处有关。

            另外,ADS1118是可以用来采集电压信号,但是它是带有内部温度补偿的AD芯片,如果仅仅是电压采集的话,不必如此,使用ADS1115或者ADS1110不是也可以么,IIC接口。

            最后,是测试相关的,注意检查供电电压,信号发生器与ADS1118线缆的连接,MCU与AD的连接线,如果确信这些都没问题,可以给一个正值按照上述规则计算。计算测试结果可能有偏差甚至错误,通常与上述检查项有关。如果器件是已经焊接在做好的实验板上的话,情况会好很多。

  •         关于读取,是与写入有关的:写入——产生时钟信号——(如果数据准备好)驱动返回值。所以,如果一次写入8位,就会有8个连续时钟信号产生,并驱动返回8位值,那么当中断产生时,SPI寄存器里就会有8位值。

  •         搞定了?