ADS1241驱动程序只能采集一通道,其他通道不能选通
各位好
1.我在调试ADS1241芯片程序,现在,配置完后,它默认的采集单通道是AIN0.即Multiplexer Control Register是0000 1000,然后将采集结果发送给上位机观察采集数据,经计算采集回来的数据与我给的信号基本相同。
2.但现在我想循环采集前6个(AIN0~AIN5)通道,但发现数据不正确,所以我单独调试第二通道,配置Multiplexer Control Register为0001 1000,采集回来的数据不正常,通过测试感觉我没有选通第二通道,请麻烦看一下我的程序是否有问题(程序只关系ADS1241的配置和读取的,看了应该一目了然)
/*程序其他部分没有写在这里,怕大家看了会闲麻烦,这里只将AD部分程序写下,请帮忙审阅一些,看是我寄存器配置
有问题还是其他问题,谢谢!如果需要查看全部程序请通知我,我可以提供。POL硬件拉高*/
main(void)
{
uchar chan=0,n=0;
uchar i;
uchar ACRVal;
// 复位ADS1241
ADS1241SendResetCommand();
// 设置增益1
ADS1241SetGain(0);
//暂时设置一个通道AIN1
ADS1241SetChannel(0x10 | ADS1241_MUXN_AINCOM);//这里如果配置为AIN0,采集数据正常,但改成AIN1就不对。
//选择设置寄存器地址,写入数据
//单极性、采样频率19200Hz、输出数据高位在前、满幅输入为±Vref、数据输出速率7.5Hz
ACRVal = 0x41;
ADS1241WriteRegister(ADS1241_ACR_REGISTER, 1, &ACRVal);
// 内部自校正
CS=0;
ADS1241SendByte(ADS1241_CMD_SELFCAL);
CS=1;
for(i=0; i<4; i++)
while(DRDY);
while(1)
{
AD_result=ADS1241ReadData();
/*整理将AD采集结果“AD_result”发给上位机查看结果*/
CS=0;
ADS1241SendByte(ADS1241_CMD_SELFCAL);
CS=1;
for (i=0; i<4; i++)
while (DRDY);
}
}
void ADS1241SendByte(uchar SPI_data)
{
int i;
CS=0;
for (i=0; i<8; i++)
{
if (SPI_data & 0x80)
SDI=1;
else
SDI=0;
SCLK=1;
//延迟一点时间
_nop_(); //延迟
// 时钟管脚输出低电平
SCLK = 0;
//延迟一点时间
_nop_(); //延迟
SPI_data <<= 1;
}
CS=1;
}
/****************************************************************************
**********
*函数原型: uchar ADS1241ReceiveByte(void)
*功能 : 从spi总线上接受8位数据信号,并将接收到的数据作为一个字节返回
*****************************************************************************
*********/
uchar ADS1241ReceiveByte(void)
{
uchar i;
uchar Result=0;
SCLK = 1;
for (i=0; i<8; i++)
{
SCLK=0;
if(SDO==0)
Result=Result << 1;
else
{
Result=Result<<1;
Result +=1;
}
SCLK=1;
}
return(Result);
}
void ADS1241WriteRegister(uchar StartAddress, uchar NumRegs, uchar * pData)
{
uchar i;
CS=0;
// send the command byte
ADS1241SendByte(ADS1241_CMD_WREG | (StartAddress & 0x0f));
// send the command argument
ADS1241SendByte(NumRegs-1);
delayus(10);
// send the data bytes
for (i=0; i< NumRegs; i++)
{
ADS1241SendByte(*pData++);
}
CS=1;
}
int ADS1241SendResetCommand(void)
{
uchar i;
ADS1241SendByte(ADS1241_CMD_RESET);//发送复位命令
//延迟一点时间
for(i = 50;i > 0;i--) ;
}
void ADS1241SetGain(uchar gain)
{//选择放大倍数。 0~7
uchar Temp;
Temp=gain;
ADS1241WriteRegister(ADS1241_SETUP_REGISTER, 0x01, &Temp);
}
void ADS1241SetChannel(uchar MuxCode)
{
uchar nTemp;
nTemp=MuxCode;
ADS1241WriteRegister(ADS1241_MUX_REGISTER, 0x01, &nTemp);
}
lint ADS1241ReadData()
{
int j;
lint Data;
while (DRDY); //当DRDY 为高时,不读取数据 *******
//CS=0;
// 发送命令字节
ADS1241SendByte(ADS1241_CMD_RDATAC);
//ADS1241SendByte(ADS1241_CMD_RDATA);
//延迟一点时间
for(j = 50;j > 0;j--);
CS=0;
// 得到转换结果
Data = ADS1241ReceiveByte();
Data = (Data << 8) | ADS1241ReceiveByte();
Data = (Data << 8) | ADS1241ReceiveByte();
CS=1;
return Data;
}
自己顶一下,等待大家的帮助
Hi
建议你先配置寄存器,然后在读这些配置的寄存器,看数据是否有写进去?
ADS1241,默认的AIN0/AIN1的差分输入通道,所以就算你不写通道,转换出来的也是AIN0/AIN1的数据,而当你写其他通道的时候,可能数据没有被写入。
(建议确认一下相关时序,和上述读寄存器,看数据是否有被写进去)
你好,Johnsin
我采用的是AIN0~AIN5,单极性采集,然后AINCM为公共模拟输入端(接地),BUFEN接地,POL通过10K电阻上拉到5V;
我也看了ADS1241默认的是采集AIN0通道,这点应该符合我现在第一通道能采集到数据,请麻烦帮忙确认一下以下三个子程序分别是想AD1241写字节、读字节和写寄存器函数,看是否正确,时序有没有问题。谢谢!
void ADS1241SendByte(uchar SPI_data)
{
int i;
CS=0;
for (i=0; i<8; i++)
{
if (SPI_data & 0x80)
SDI=1;
else
SDI=0;
SCLK=1;
//延迟一点时间
_nop_(); //延迟
// 时钟管脚输出低电平
SCLK = 0;
//延迟一点时间
_nop_(); //延迟
SPI_data <<= 1;
}
CS=1;
}
/****************************************************************************
**********
*函数原型: uchar ADS1241ReceiveByte(void)
*功能 : 从spi总线上接受8位数据信号,并将接收到的数据作为一个字节返回
*****************************************************************************
*********/
uchar ADS1241ReceiveByte(void)
{
uchar i;
uchar Result=0;
SCLK = 1;
for (i=0; i<8; i++)
{
SCLK=0;
if(SDO==0)
Result=Result << 1;
else
{
Result=Result<<1;
Result +=1;
}
SCLK=1;
}
return(Result);
}
void ADS1241WriteRegister(uchar StartAddress, uchar NumRegs, uchar * pData)
{
uchar i;
CS=0;
// send the command byte
ADS1241SendByte(ADS1241_CMD_WREG | (StartAddress & 0x0f));
// send the command argument
ADS1241SendByte(NumRegs-1);
delayus(10);
// send the data bytes
for (i=0; i< NumRegs; i++)
{
ADS1241SendByte(*pData++);
}
CS=1;
}
Hi
判定时序最好的方法是用示波器直接测试, 然后与datasheet定义的时序做比较(包括那些时间定义).
Hi
Johnsin Tao
经过查看手册的时序图,我现在已经能更改ADS1241的采集通道了(主要修改了SendByte函数和ReceiveByte函数、以及SCLK后的延时时间),但是现在有个问题,我设置采集单通道AIN4(任一),外部给定恒流源4~20mA,然后数据输出高16位是稳定的,值也是正确的,但会偶尔出现FFFFFF 而我测试AD芯片该引脚电压在4mA时为0.4003V左右(采样电阻为1‰的100R电阻);
另外还有个问题,在时序图后面的t11,在写SELFCAL命令后,要有最小4个DRDY PERIODS的时间延时,我用的AD外部晶振是2.4576MHz,请问这个时间是多少呢?如何计算,我在手册中没找到。
谢谢!
另外,我在主程序进来之后,将CS直接置低电平,在其他程序中,不在对其操作。
在
应用报告
ZHCA007–2004 年10 月
连接ADS1241 与MSP430 处理器 文件中,有提到:
// Set the gain and multiplexer
ADS1240SetGain(ADS1240_GAIN_1);
ADS1240SetChannel(chan | ADS1240_MUXN_AINCOM);
// data rate = 15Hz (4.91MHz, SPEED = 1)
ACRVal = SPEED_BIT;
ADS1240WriteRegister(ADS1240_ACR_REGISTER, 1, &ACRVal);
// do an internal self cal
ADS1240AssertCS(1);
ADS1240SendByte(ADS1240_CMD_SELFCAL);
ADS1240AssertCS(0);
for (i=0; i<4; i++)
ADS1240WaitForDataReady(0);
而我对ACR寄存器设置的0X41,
还有这个延时for (i=0; i<4; i++)是如何计算的?我的单片机主时钟是采用的11.0595M晶振,1T模式。
Hi
确认一下出现FFFF时的转换时序是否正常(单片机给到ADC的控制时序)?,以及这个过程中供电是否稳定?
t11的定义,可以结合t1的定义来计算。
Hi Johnsin Tao
这个过程的供电是稳定的,我测试过。
时序是指单片机发给ADC的SCLK时序吗?
我用的fosc是2.4576MHz,那么主时钟周期tosc=1/fosc=400ns,但DRDY Periods是怎么算的呢?
Hi
是的,指的是单片机与ADC所有接口的控制时序。
按照datasheet: http://www.ti.com.cn/cn/lit/ds/symlink/ads1118.pdf 第十四页,
It is reset HIGH when a read operation from the data register is complete.
DRDY goes LOW when a new data word is available in the DOR register.
我认为这个时间没有办法计算,DRDY只是作为ADC输出的标示符,这个时间是ADC内部采样转换并且将数据传到DOR的时间。
Hi Johnsin Tao
我测试了一下各个引脚的时序图,在测试DRDY 和DOUT时,在DRDY为低电平期间,发现DOUT有时为高电平、有时为低电平,我分析应该是正常数据;
但有时DOUT却是一直是高电平(参见附件图4),我分析有可能输出的是FFFFFFh。但是我没办法将我在上位机上看到的数据与示波器中看到的波形同步
我将各波形图抓了下来,请参见附件。
现在网路不太好,附件上传不了,晚一会儿我会上传上来,还烦请分析一下。
多谢!
Hi
DRDY位低电平时得到的应该是转换的数据,但是为高电平时,DOUT输出高是不正常的。
Hi
可以比较上述两种情况下的控制时序(单片机给到ADC的信号)
Hi Tohnsin Tao
我测试了波形图,添加到附件中,发现就是在DRDY为低电平,DOUT有高低变化的电平;
但同时也测试到在DRDY为低电平时,DOUT有时是高电平。
想请问会有哪些原因导致DOUT为高呢?
请参见附件
Hi
Johnsin Tao
问题已经解决了,按照时序图修改了一下程序,现在没有错误码了。
多谢帮忙!
Hi
不客气。
之前提到的,ADC这类转换异常,通过时序测试很容易找是控制异常造成的,然后依据这个修改程序。
你好,我遇到跟你相似的问题,可否共享一下你的程序,谢谢了!
邮箱:zxl404@163.com 感谢