电子产品的开发中CS1238芯片调试心得

电子产品设计开发过程中,很多情况会涉及到AD的采集的需求,一般我们会选择单片机内部的ADC模块进行采集,但是会遇到一个问题,他们的采集的精度不能满足我们采集微小信号或差分信号的需求,一般我们会选择成品的ADC芯片进行电压信号的采集。我们市面上的ADC芯片的选型种类太多,对于设计产品我们比较关心的几个方面分别是精度,硬件设计的要求,软件调试的复杂程度和芯片的价格。今天我把公司刚开发一款产品上用的一款ADC芯片推荐给大家。

CS1238 是一款高精度、低功耗模数转换芯片,两路差分输入通道,内置温度传感器和

高精度振荡器。

CS1238 的 PGA 可选:1、2、64、128,默认为 128。

CS1238 的 ADC 数据输出速率可选:10Hz、40Hz、640Hz、1.28kHz,默认为 10Hz;

MCU 可以通过 2 线的 SPI 接口 SCLK、 DRDY / DOUT与 CS1238 进行通信,对其进行配置,例如通道选择、PGA 选择、输出速率选择等。2线的通信方式占用MCU资源较少,同时通信协议比较简单。

但是调试过程中遇到挺大的问题,下面我把调试的一些具体问题及解决的方法分享给大家。

1、硬件连接比较简单, SCLK、 DRDY / DOUT端分别连接到单片机的任意两脚(两脚需要能满足基本输入和输出功能),在程序的配置方面,SCLK配置为上拉输出,DRDY / DOUT端配置为上拉输入。

2、对于芯片一般会操作三个功能分别是进行芯片采集到的AD值得读取,读取芯片内部的配置信息,写入芯片内部的配置信息。这些所有的指令传输与SCLK端的电平的变化优化,通过电平的变化进行信息的传输。同时需要注意DRDY / DOUT端在传输过程中需要切换该端口的输入和输出的状态。如:在写命令时DRDY / DOUT端就是输入状态,当读芯片发出的信息时DRDY / DOUT端就是输出状态。

3、当 SCLK 从低电平变高电平并保持在高电平超过 100µs,CS1238 即进入 PowerDwon模式,此时功耗低于 0.1μA。当 SCLK 重新回到低电平时,芯片会重新进入正常工作状态。所以在做完相关的操作后要把SCLK的电平拉低,等待下一次信息的传输。

4、应保证 SCLK 的上升和下降时间都小于 50ns,否则会影响CS1238对电平的识别。

5、SCLK高低电平的持续时间要在2us~154us之间,超过这个时间长度会影响到芯片对电平的识别。

6、还有一个非常重要的问题就是,DRDY / DOUT端为高电平就绪状态时才能进行芯片的相关的通信操作。

在电子产品设计开发过程中,如果用到ADC芯片,我建议大家可以使用一下这款芯片,价格实惠,同时使用比较便捷,采集精度高等特点,如果针对调试CS1238的问题,可以随时留言或者联系我们。

具体例程程序如下:

//整个通讯时序的时间必须小于1个数据转换周期

//推荐每个CLK的时间长度:2uS ~ 15uS

/*—————————————————————————–

Name : F_AD_Clock

Function: ADC时序时钟

—————————————————————————–*/

void F_AD_Clock(void)

{

IO_CLK_AD = 1;

F_Delay();

IO_CLK_AD = 0;

F_Delay();

}

 

/*—————————————————————————–

Name : F_Read_AD_Byte

Function: 读3字节AD值

—————————————————————————–*/

void F_Read_AD(void)

{

_UCHAR i;

R_AD0.word = 0;

EIC20_EIE0 = 0; //关闭MCU_DAT管脚的外部中断(防止读写时误触发)

// while(IO_Data_AD);

for(i = 0; i < 24; i++) //发送24个CLK,接收数据

{

R_AD0.word <<= 1;

F_AD_Clock();

if(IO_Data_AD)

{

R_AD0.word ++;

}

}

F_AD_Clock();

F_AD_Clock();

F_AD_Clock(); //CLK27,拉高DRDY

//如果一个数据转换周期内对ADC进行两次或以上的读写操作,则需要发送46个CLK,而不是27个CLK

//(即:发送24个CLK读取数据,然后再发送22个CLK)

EIC20_EIE0 = 1; //重新开启MCU_DAT管脚的外部中断

}

 

/*—————————————————————————–

Name : F_Rd_AdReg

Function: 读取ADC寄存器

—————————————————————————–*/

_UCHAR F_Rd_AdReg(void)

{

_UCHAR i;

union _UCHAR_BIT R_Temp;

 

//———————————-

EIC20_EIE0 = 0; //关闭MCU_DAT管脚的外部中断(防止读写时误触发)

 

//———————————-

//1 ~ 3:clk1-clk27

//———————————-

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

{

F_AD_Clock();

}

 

//———————————-

//4:clk28-clk29

//———————————-

IO_Data_AD_Dir = 1; //把MCU_Data管脚设为输出

F_AD_Clock();

F_AD_Clock();

 

//———————————-

//5:clk30-clk36(发送读命令)

//———————————-

R_Temp.byte = 0xAC; //读命令(0x56)左移1位

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

{

if(R_Temp.bit.b07) //MSB

{

IO_Data_AD = 1;

}

else

{

IO_Data_AD = 0;

}

R_Temp.byte = R_Temp.byte << 1;

F_AD_Clock();

}

 

//———————————-

//6:clk37

//———————————-

IO_Data_AD_Dir = 0; //把MCU_Data管脚设为输入

F_AD_Clock();

//———————————-

//7:clk38-clk45(读取寄存器)

//———————————-

R_Temp.byte = 0;

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

{

R_Temp.byte <<= 1;

F_AD_Clock();

if(IO_Data_AD)

{

R_Temp.byte ++;

}

}

//———————————-

//8:clk46

//———————————-

F_AD_Clock();

 

//———————————-

EIC20_EIE0 = 1; //重新开启MCU_DAT管脚的外部中断

 

return R_Temp.byte;

}

 

/*—————————————————————————–

Name : F_Wr_AdReg

Function: 写入ADC寄存器

—————————————————————————–*/

void F_Wr_AdReg(_UCHAR R_AdReg)

{

_UCHAR i;

union _UCHAR_BIT R_Temp;

 

//———————————-

EIC20_EIE0 = 0; //关闭MCU_DAT管脚的外部中断(防止读写时误触发)

 

//———————————-

//1 ~ 3:clk1-clk27

//———————————-

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

{

F_AD_Clock();

}

 

//———————————-

//4:clk28-clk29

//———————————-

IO_Data_AD_Dir = 1; //把MCU_Data管脚设为输出

F_AD_Clock();

F_AD_Clock();

 

//———————————-

//5:clk30-clk36(发送写命令)

//———————————-

R_Temp.byte = 0xCA; //写命令(0x65)左移1位

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

{

if(R_Temp.bit.b07) //MSB

{

IO_Data_AD = 1;

}

else

{

IO_Data_AD = 0;

}

R_Temp.byte = R_Temp.byte << 1;

F_AD_Clock();

}

 

//———————————-

//6:clk37

//———————————-

F_AD_Clock();

//———————————-

//7:clk38-clk45(写入寄存器)

//———————————-

R_Temp.byte = R_AdReg;

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

{

if(R_Temp.bit.b07) //MSB

{

IO_Data_AD = 1;

}

else

{

IO_Data_AD = 0;

}

R_Temp.byte = R_Temp.byte << 1;

F_AD_Clock();

}

//———————————-

//8:clk46

//———————————-

IO_Data_AD_Dir = 0; //把MCU_Data管脚设为输入

F_AD_Clock();

 

//———————————-

EIC20_EIE0 = 1; //重新开启MCU_DAT管脚的外部中断

}

 

评论( 1 )

  • 融宇电子

    不错的文档,对调试有帮助

留下评论

咨询