hmilyxia 发表于 2009-11-12 23:45:29

求助:“CS5532发送转换命令(0x80)后,SDO不变低”的问题

各位大侠,请帮忙分析分析,不胜感激!


对CS5532的使用如下:
1. 硬件简单说明: V+=3V;V-=负3V;Ref+=3V;Ref-=负3V,晶振4.9152
2. 软件操作步骤说明
   1)上电后延时了50个ms(datasheet说超过20ms就可以)
   2)发送31个ff,1个fe,完成对端口复位
   3)发送命令03,bit RS=1,即数据0x20000000,复位内部逻辑
   4)等待读取配置寄存器,直到读出RV bit=1,即:数据0x10000000
   5)设置配置寄存器
   6)设置通道寄存器
   7)偏移,增益寄存器(下面的代码中没有,但是也测试过)
   8)发送数据转换指令0x80(datasheet说,不校准也可以直接转换,只是误差大而已)
   9)等待SDO=0
3. 问题描述:
   1)1-7个步骤正常,能够读出RV bit=1
   2)此外,也尝试过在第8个步骤之前,写入,读取配置,增益,偏移,通道寄存器,
      变化写入数据,发现读取数据和写入的一致,也侧面证明了CS5532工作基本正常
   3) 执行了步骤8以后,程序卡死在了步骤9
4. 以下是详细代码,请参考
sbit CS5532_SPI_DO = P1^0;
sbit CS5532_SPI_CS = P1^1;
sbit CS5532_SPI_CK = P1^2;
sbit CS5532_SPI_DI = P1^3;

void CS5532Test(void)
{
int i;
unsigned char rec=0;
unsigned char rec1,rec2,rec3,rec4;
//reset port
CS5532Delay(50000);

CS5532_SPI_CK = 0;CS5532Delay(3);
CS5532_SPI_CS = 0;CS5532Delay(3);

//复位端口,datasheet上说最少15个ff和1个fe,不放心,用了31个ff
//其中用15个ff也做过测试,效果和31个ff一样
for( i = 0; i< 31; i++ )
    CS5532ByteSend( 0xff );
CS5532ByteSend( 0xfe );
//复位内部逻辑,发送指令03,数据是0x20000000
CS5532Delay(50000);
CS5532ByteSend( 0x03 );
CS5532ByteSend( 0x20 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
//等待复位(RV=1)完成,当读出值为0x10000000时候,复位完成
while( rec != 0x10 )
{
    CS5532ByteSend( 0x0b );
    rec = CS5532ByteRec( );
    CS5532ByteRec( );
    CS5532ByteRec( );
    CS5532ByteRec( );
}
//设置配置寄存器,V+,V-是正负3V,Ref电压是正负3V
CS5532Delay(100);
CS5532ByteSend( 0x03 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
//设置通道寄存器
CS5532Delay(100);
CS5532ByteSend( 0x05 );
CS5532ByteSend( 0x02 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
CS5532ByteSend( 0x00 );
//发送单词转换命令
CS5532ByteSend( 0x80 );
while( CS5532_SPI_DO == 1 );//等待SDO从1变成0
CS5532ByteSend( 0x00 );   //清楚SDO flag
rec1 = CS5532ByteRec( );    //读取32bit数据
rec2 = CS5532ByteRec( );
rec3 = CS5532ByteRec( );
rec4 = CS5532ByteRec( );

}
void CS5532ByteSend( unsigned char ucData )
{
int i;

for( i = 0; i < 8; i++ )
{
    if( ucData & 0x80 )
      CS5532_SPI_DI = 1;
    else
      CS5532_SPI_DI = 0;
    CS5532Delay(10);
    CS5532_SPI_CK = 1;
    CS5532Delay(10);
    ucData = ucData << 1;
    CS5532_SPI_CK = 0;
    CS5532Delay(10);
}
CS5532_SPI_DI = 0;
}

unsigned char CS5532ByteRec( void )
{
int i;
unsigned char ucData = 0;

for( i = 0; i < 8; i++ )
{
    ucData = ucData << 1;
    if( CS5532_SPI_DO )
      ucData = ucData | 0x01;
    else
      ucData = ucData & 0xfe;
    CS5532Delay(10);
    CS5532_SPI_CK = 1;
    CS5532Delay(10);
    CS5532_SPI_CK = 0;
    CS5532Delay(10);
}
return ucData;
}
void CS5532Delay( unsigned int i ) { while(i--); }

hmilyxia 发表于 2009-11-13 09:41:58

有用过的朋友请指点指点,着急等待中!

hanbao0371 发表于 2009-11-13 11:26:27

这是我以前写的,调试通过的,你可以看下,如有问题,和我联系吧:hanbao0371@sina.com
/******************************************
Project    :读取CS5532的数据,并在LED上显示





*******************************************/
#ifndef_CS5532_
#define_CS5532_



/*********端口定义*********/
#define CS5532_CS    PD1                        //定义片选端
#define CS5532_SDO   PD2                        //定义数据输入端
#define CS5532_SDI   PD3                        //定义数据输出端
#define CS5532_SCLKPD4                        //定义移位脉冲端

#define BIT_CS    PORTD |= BIT(CS5532_CS)       //置CS端为1
#define CLR_CS    PORTD &=~BIT(CS5532_CS)       //清CS端
#define BIT_SDI   PORTD |= BIT(CS5532_SDI)      //置SDI端为1
#define CLR_SDI   PORTD &=~BIT(CS5532_SDI)      //清SDI端
#define BIT_SCLKPORTD |= BIT(CS5532_SCLK)   //置SCLK端为1
#define CLR_SCLKPORTD &=~BIT(CS5532_SCLK)   //清SCLK端


/************全局变量定义************/
uchar CS5532_data={0};
uchar zhongduan_flag=0;                        //转换数据完成标志位
/*~~~~~~~~~宏定义,配置建立通道寄存器~~~~~~~~~~~~*/
#define Physics_channel1      0x00             //通道1
#define Physics_channel2      0x01             //通道2
      /************设置增益”***********/
#define Gain_bit                3                //增益控制位是3位
#define Gain_1                  0                //Gain=1
#define Gain_2                  1                //Gain=2
#define Gain_4                  2                //Gain=4
#define Gain_8                  3                //Gain=8
#define Gain_16               4                //Gain=16
#define Gain_32               5                //Gain=32
#define Gain_64               6                //Gain=6
      /********设置字数率(FRS=0)*********/
#define WR_bit                  4                //Word_Rate(字输出率)控制是4位
#define WR_120                  0                //Word_Rate=120Hz
#define WR_60                   1                //Word_Rate=60Hz
#define WR_30                   2                //Word_Rate=30Hz
#define WR_15                   3                //Word_Rate=15Hz
#define WR_7.5                  4                //Word_Rate=7.5Hz
#define WR_3840               8                //Word_Rate=384120Hz
#define WR_1920               9                //Word_Rate=1920Hz
#define WR_960                  10               //Word_Rate=960Hz
#define WR_480                  11               //Word_Rate=480Hz
#define WR_240                  12               //Word_Rate=240Hz
   /*******设置单/双极性******/
#define Jixing_bit            1                //Unipolar/Bipolar控制是1位
#define Select_unipolar         1                //选择单极性
#define Select_bipolar          0                //选择双极性

                  
/********向CS5532写入一个字节数据*********/
void write_byte(uchar data)
{
uchar i=0;
CLR_SCLK;                                     //清SCLK端
for(i=0;i<8;i++)
   {
    if((data<<i)& 0x80)                        //从MSB开始发送,
             BIT_SDI;                                 //与0x80后为1时,SDI输出1
          else                                       //否则,SDI输出0
              CLR_SDI;
        BIT_SCLK;                                    //SCLK上升沿,完成一位数据的写入
        delay_us(1);
        CLR_SCLK;
        delay_us(1);
   }
}

/************配置建立通道寄存器**************
uchar Channel1_setup_set(uchar value ,uchar bit)
{
uchar i=0,xy=0;
/*
for(i=0;i<bit;i++)
   {
   xy <<= 1;
   xy |= 0x01;
   }
xy &=~xy;
*/
      
//}

/**********读寄存器************/
ulong Read_Register(uchar commd)
{
uchar i=0;
ulong Register_buf=0;
CLR_CS;                                       //置片选有效                                 
write_byte(commd);                              //被访问的寄存器地址
//CLR_SCLK;
CLR_SDI;
delay_us(1);
for(i=0;i<32;i++)
{
    CLR_SDI;                                    //读数据期间,SDI输出必须为0
    Register_buf <<= 1;
    BIT_SCLK;                                     //SCLK上升沿,完成一位数据的写入
        delay_us(1);
        if(PIND & 0x04 )                              //读取32位数据
           Register_buf |= 0x00000001;
        delay_us(1);   
        CLR_SCLK;
        delay_us(1);
}
//BIT_CS;
delay_us(1);
return (Register_buf);
}


/************初始化CS5532*************/
void init_CS5532 (void)
{
uchar i=0;
delay_ms(2000);                                 //延时20MS
delay_ms(2000);                                 //延时20MS
BIT_CS;
delay_us(1);
CLR_CS;                                       //置片选有效                                 
delay_us(1);
for(i=0;i<18;i++)                               //写入15次0xff
    write_byte(0xff);
write_byte(0xfe);                               //写一次0xfe
/******向配置寄存器写入复位命令*****/
write_byte(0x03);                               //通道1,配置寄存器
write_byte(0x20);                               //分4次写入32位数据,RESET=1,
write_byte(0x00);
write_byte(0x00);
write_byte(0x00);                               /**按理说应写入32位数据,但手册上默然后几位是0,故写入24位数据**/

delay_ms(2000);                              //等待复位完成

write_byte(0x03);
write_byte(0x02);                               //RESET=0,VREF=2.5V,FRS=0
write_byte(0x00);
write_byte(0x00);
write_byte(0x00);
/********配置建立通道寄存器**********/
write_byte(0x05);                               //单个建立通道寄存器地址
write_byte(0x02);                               //通道1,Gain=1,字速率为7.5(FRS=0 )
write_byte(0x40);
write_byte(0x02);                               //为32位数据,其实是两个相同的16位的数据
write_byte(0x40);

write_byte(0xc0);                               //启动持续转换命令
}

/*********读取CS5532的数据**********/
ulong Read_CS5532(void)
{
uchar i=0,j=0;
ulong data_buf=0;
CLR_CS;                                       //置片选端有效
CLR_SCLK;                                       //脉冲端置低
//CLR_SDI;                                        //SDI输出0
CLR_SDI;
for(i=0;i<8;i++)                              //连续写入8个0到SDI
   {
        BIT_SCLK;
        delay_us(1);
        CLR_SCLK;
        delay_us(1);   
   }
   for(i=0;i<32;i++)
    {
          BIT_SCLK;                                 //下降沿读数据
          delay_us(1);
          data_buf <<= 1;                        //先收到的数据放在最高位
          if(PIND & 0x04 )                        //读取到高电平时,该位为1
          data_buf |= 0x00000001;
          else
          data_buf &= 0xfffffffe;
          CLR_SCLK;
          delay_us(1);
          }
   data_buf >>= 8;
   return (data_buf);       
}

/********MCU初始化函数*******/
void mcu_init(void)
{
DDRA=0xff;                              //PA口设为输出
PORTA=0xff;
DDRB=0xff;                              //PB口设为输出
PORTB=0xff;
   
DDRC=0xff;
PORTC=0xff;
                                             
DDRD =0xfe;                            //SDO设为输入,其他的为输出
PORTD=0xff;

timer1_init();
//CS5513_init();
init_CS5532();
//SHT11_connect_reset();                  //SHT11初始化复位
}

/*********读取到的32位数据分装在6个数组中,便于送数码管显示***********/
void Change_To_display (ulong data)
{
uchar i=0;
// data >>= 4;
/***
ulong temp=0;
uchar tempf=0;                                  //定义数据整数部分
float tempi=0,data1;                            //定义数据小数部分

data >>= 4;                                    
data1 = (float)((data*2.5)/1048576);            //甩掉4位数据后,转换为电压值      
//data = (data*2.5)/16777215;
tempf=(uchar)data1;      
tempi=data1-tempf;                              //获得小数部分
CS5532_data=duan_ma[(uchar)tempf];         //获得整数部分

temp=(ulong)(tempi*100000);                     //数据放大1000000倍,便于显示小数
for(i=5;i>0;i--)
{
   CS5532_data=duan_ma;
   temp = temp/10;
}
CS5532_data &= 0x7f;                        //个位上数据加小数点
***/
/***用于测试读取AD最大值和最小值的十六进制显示*/
for(i=0;i<4;i++)                                 //高16位数据分离
   CS5532_data=duan_ma[(uchar)((data & (0xf0000000 >>i*4))>>(28-i*4))];
for(i=4;i<8;i++)                                 //低16位数据分离
    CS5532_data=duan_ma[(uchar)((data & (0xf0000000 >> 4*i))>>(12-4*(i-4)))];

}



/***********未在实际中测试*******************
名称:Self_offset_calibration
功能:完成自我漂移校验
说明:
       硬件电路说明:差分模拟输入电压连接到一起后接入到CS5532的AIN-
       自我漂移校验只针对增益为1时,对其他值不起作用
*********************************************/
void Self_offset_calibration(void)
{
/********配置寄存器至校验模式********/       
write_byte(0xc1);                              //CSRP2~0=000(指向建立通道寄存器1和2)
                                                 //CC2~0=001,自我漂移校验
write_byte(0x0a);                              //IS=1,OGS=0
write_byte(0x00);                              //校验后的数据保存至漂移寄存器中
write_byte(0x00);

write_byte(0x81);                              //启动自我漂移校验

timer1_init();                                 //校验初始化完成后,开启外中断
if(zhongduan_flag == 1)                        //转换完成标志位有效
        {
       GICR= 0x00;                                 //关闭中断
   SREG= 0x00;
       zhongduan_flag=0;       
       Change_To_display(Read_Register(0x09));   //读取漂移寄存器       
       SREG|= 0x80;                              //开中断
           GICR|= 0x40;        
        }
/******配置寄存器至普通模式*******/       
write_byte(0x03);
write_byte(0x02);                               //RESET=0,VREF=2.5V,FRS=0
write_byte(0x00);
write_byte(0x00);
write_byte(0x00);                                          
}


#pragma interrupt_handler INT1_isr:3       
void INT1_isr(void)
{
GICR= 0x00;                              //关闭外部中断
SREG= 0x00;
zhongduan_flag=1;                        //转换数据完成
//Change_To_display(Read_CS5532());

}       


/***********显示程序*************/
void display(void)
{
uchar i=0,j=0;
for(i=0;i<6;i++)
{
   PORTA = SHT11_data;
   PORTB = 0x80>>i;
   delay_ms(100);
}
}

#endif

hanbao0371 发表于 2009-11-13 11:31:46

问题好像出现你读CS5532上,读取的时候是读取32位,而且保存的时候是后者24位的数据,
你最好用示波器看下,CS5532在初始化后,是否能观察到SDO被拉低,如果没有,说明你的初始化程序有问题。

hmilyxia 发表于 2009-11-13 13:02:25

感谢hanbao0371 朋友的帮助,有两点问题,请请教一下
1. > 读取的时候是读取32位,而且保存的时候是后者24位的数据,
   现在我的问题是,发送完毕0x80(或者0xc0)转换命令之后,SDO一直不等于0,
   个人感觉和“读数据的位数”有什么关系呢。
2. > 你最好用示波器看下,CS5532在初始化后,是否能观察到SDO被拉低,如果没有,说明你的初始化程序有问题。
   手册上没有提到过初始化之后,SDO会拉低,应该是您个人的经验把,如果是这样子,非常感谢,我可以试试。
再次感谢您的回答。

wjchang724 发表于 2009-11-16 13:22:02

本人程序:
CLR AD_CS
                              LCALL INIT_SPI   ;初始化,发15个FFH和1个FEH
                              CLR AD_CS
                              NOP
                              NOP
                              MOV A,#03H          ;复位寄存器
                              LCALL Write8bit
                              MOV A,#20H
                              LCALL Write8bit
                              LCALL Write8bit
                              LCALL Write8bit
                              LCALL Write8bit
                              ;MOV A,#03H          ;写设置寄存器
                              ;LCALL Write8bit
                              ;MOV A,#20H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              MOV A,#05H          ;写通道寄存器
                              LCALL Write8bit
                              MOV A,#10H
                              LCALL Write8bit
                              MOV A,#80H
                              LCALL Write8bit
                              MOV A,#10H
                              LCALL Write8bit
                              MOV A,#80H
                              LCALL Write8bit
                              ;MOV A,#01H          ;写偏移寄存器
                              ;LCALL Write8bit
                              ;MOV A,#000H
                              ;LCALL Write8bit
                              ;MOV A,#000H
                              ;LCALL Write8bit
                              ;MOV A,#000H
                              ;LCALL Write8bit
                              ;MOV A,#000H
                              ;LCALL Write8bit
                              ;MOV A,#02H          ;写增益寄存器
                              ;LCALL Write8bit
                              ;MOV A,#01H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              ;MOV A,#00H
                              ;LCALL Write8bit
                              
                              MOV A,#0c0H          ;发送连续转换命令
                              CLR AD_SDI
                              LCALL Write8bit
NNN:                            NOP
LOOP:                           ;LCALL DELAY1uS
                              JB AD_SDO,$         ;等待输出口变低
                              MOV A,#00H
                              LCALL Write8bit
                              MOV R0,#30H      ;调用读取32位子程序
                              LCALL Read32bit
                              LCALL DELAY200MS
jmp loop
本人在用中,也有些许问题,愿意共同讨论的加我的qq 273045940

hanbao0371 发表于 2009-11-16 21:37:08

to hmilyxia
    发送完毕0x80(或者0xc0)转换命令之后,SDO一直不等于0,
   个人感觉和“读数据的位数”有什么关系呢。

这样理解好像不太对,好像没有关系。
所谓的初始化就是:
/******配置寄存器至普通模式*******/
write_byte(0x03);
write_byte(0x02);                               //RESET=0,VREF=2.5V,FRS=0
write_byte(0x00);
write_byte(0x00);
write_byte(0x00);      
上面的程序按硬件电路进行配置后,应该就能看到SDO拉低了,最好用示波器看下波形。
我不是经常上论坛的,有事发EMAIL:hanbao0371@sina.com,这个每天都要用

hmilyxia 发表于 2009-11-23 14:19:38

问题已经解决了。给大家反馈一下结果,是硬件上电顺序问题。
解决办法:调整了上电顺序,单片机先上电,然后再给CS5532上电。
之前的问题,可能是由于CS5532上电过程中,单片机也在上电,对CS5532构成了影响,
导致上电过程过程有问题。

爱情转移 发表于 2013-7-24 23:10:15

楼主说的问题我的也是,9楼的回答我明天调试一下试试,如果方便的话我们可以讨论一下,我qq7937298276,期待楼主的赐教

bondxie3 发表于 2014-9-24 17:16:39

标记,CS5532驱动程序.
页: [1]
查看完整版本: 求助:“CS5532发送转换命令(0x80)后,SDO不变低”的问题