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.
您好,
几天以来,我一直在尝试与我的电路板上的ADC进行通信。 作为n ü µC,我使用的是Atmega168及其硬件SPI引脚。 我已经尝试了不同的SPI模式,但没有成功。 在网上的几个地方,我看到DIN和DOUT (T6)之间的时间间隔非常关键。 所以我在SPI收发器方法中增加了50 µs的延迟。
我想我可以简单地开始读出芯片的状态寄存器。 所以我把命令送到了芯片上。 问题是,即使我将注册表更改为DRATE或其他内容,我也始终在读回"0xFFFFFFFFFFF"。 因此这是无效的。 我是这种ADC通信的新手,所以可能我做了一些完全错误的事情。 我将在此处添加我的代码,也许有人可以立即识别出一些错误。 我还没有使用!DRDY的外部中断。 在主循环中,我只以1000毫秒的间隔读取状态寄存器。
芯片的示例根据第28页的数据集。 非常感谢
#define baud 11.52万UL #define UBRR0_value (F_CPU/(16*bau)-1) #include <avr/io.h> #include <util/delay.h> #include <avr/interrup.h> #include <string.h> #include <stdio.h> #include <stdlib.h>#include <util/delay.h>#include <ave/interrinterrinterrupt.h>#include <ave_sch; unchar <us_1<uschar <rch; unch; unsigned <1<rch; unch_1<1<) 1<rchar <rch; unstch; unch+<1<rch; unsigned <rch; unch; unch;<1<1<1< } char UART_receive(void){ while (!(UCSR0A &(1<RXC0)); return UDR0; } void UARTIinit(){ UBRR0H =(unsigned SCSPI)(UBRR0_valu)>8); UBRR0L =(unsigned char) UBRCHAR0_value; UC1<C1<C1=<C1<C1<) <C0=<C01<C1<C1<C1<C+1<C1=1<C1<C1<C1<C1<C1<) <C+1<C1= <C1=<C1<C1<C1=<C1<C1=<C1=<C1=<C1=<C1=<C1<C1=<C1<C1=<C1<C1<C1=<C1= C1<C1<C1= // SPI启用,SPI =主中继器,Prescaler =16 } unsigned char ADS1255_transceive (unsigned char数据) { SPDR =数据; while (!(SPSR &(1<<SPIF))); _DELAY _US(50); //等待50µ 直到DOUT (T6) 返回(SPDR); } CHAR ADS1255_READ_Status(){ CHAR ANS; //返回变量 PORTB &=~(1 <<PORTB2);// !CS = LOW _DELAY _US(10); ADS1255_transceive(0x10|0x00);//发送RREG命令(状态) _DELAY _US(10); ADS1255_transceive(0); //读取一个寄存器 _delay_us(10); ans = ADS1255_transceive(0); //发送虚拟字节并保存返回值 _delay_us(10); PORTB |=(1<<PORTB2);// !CS =高 _delay_us(10); 返回ans; } int main(void){ char test; ddrd &=~<2); PORTD |=(1<2); EICRA |=(1 << ISC00)|(1 << ISC01); EIMSK |=(1<INT0); // INT0 UARTinit()处的外部中断(!DOUT); // UART SPI_init(); // SPI //// sei(); 同时(1) { 测试= ADS1255_READ_Status(); UART_Transmit_CHAR(TEST); _DELAY _ms(1000); } } ISR(INT0_Vect){// !DOUT-Interrupt }
您好,Christopher:
感谢您的回答。 我执行了你推荐给我的步骤。 我检查了水晶,它摆动的很好,正如你在第一张图片中看到的那样。 它是7.3728 MHz晶体,因此频率看起来也不错。
接下来,我探测SPI引脚。 我的主板列表配置为堆叠式PCB我无法直接在引脚处测量。 所以我必须在连接到板的针座处进行测量。 但是 ,除了输入线路中的三个电阻器外,测量点和芯片针脚之间没有任何东西。
我在尝试读取状态寄存器之前添加了SDATAC命令和唤醒命令。 下图显示了记录的SPI线路。 所有三个命令均显示在图中。 我认为信号目前看起来还可以。 但无论我做什么,DOUT系列都保持安静,正如您在上一张图片中看到的那样。 我只能录制到频道,所以我做了三种不同的图片。 在每个图片通道上,一个(黄色)显示!CS线。 第一个图片通道2用于连接DIN线,第二个用于连接SCK线。 你怎么看? 非常感谢。
这是代码。
#define baud 11.52万UL #define UBRR0_value (F_CPU/(16*bau)-1) #include <AVR/IO.h> #include <util/delay.h> #include <AVR/interrup.h> #include <string.h> #include <stdio.h> //要_ ______________________________________________________________________________________________________ 静态void UART_TRANSABLE_CHAR (无符号字符) { while (!(UCSR0A &(1<UDR0))))){ ; }UDR0 = ch; }// 通过UART发送字符串 //_______________________ 静态void UART_Transmit_string (car * s) { while (*s) { UART_putc (*s); s++ ;} // 通过UART接收字节 //_______________________ CHAR UART_RECEive(void){ while (!(UCSR0A &(1<<RXC0)); RETURN UDR0; }// 配置UART //________________________ void UARTinit(){ UBRR0H =(无符号字符)(UBRR0_value >> 8); UBRR0L =(无符号字符) UBRR0_value; UCSR0B =(1<<TXEN0)|(1<<RXEN0); UCSR0C =(1<<UCSZ00)|____/________(___ void SPI_init() { DDRB =(1<5)|(1<3)|(1<2);// MOSI,!CS , SCK as Output SPCR =(1<SPE)|(1<MSTR)|(1<SPR0); // SPI启用,SPI =主中继器,Prescaler =16 }// 发送SPI数据并返回返回字节 //_______________________________ unsigned char ADS1255_transceive (unsigned char数据) { SPDR =数据; while (!(SPSR &(1<<SPIF)));//等待传输完成 _DELAY _US(20);// 等待20µ 直到DOUT (T6) Return (SPDR); } //读取ADS1255的状态寄存器 //____________________________________________ CHAR ADS1255_READ_Status(){ CHAR ANS; //返回值 PORTB &=~(1 <<PORTB2);// !CS = LOW _DELAY _US(20); ADS1255_transceive(0b10|0x00);//发送RREG命令(状态) //_delay_us(10); ADS1255_transceive(0); //读取一个寄存器 //_day_us(10); ans = ADS1255_transceive(0); //发送虚拟字节并保存返回值 // _delay_us(10); PORTB |=(1<<PORTB2);// !CS =高 _delay_us(20); 返回ans; } int main(void) { char test; //用于!DRDY //________________________________的外部中断 - DDRD &=~(1 <<2); PORTD |=(1<2); EICRA |=(1 <<ISC00)|(1 <<ISC01); EIMSK |=(1<<INT0); //启动UART和SPI //________________________________ UARTinit(); SPI_init(); _delay_ms(500);//等待0.5 sec //发送SDATAC命令 //________________________________ PORTB |=(1 <<PORTB2); _DELAY _US(20); PORTB &=~(1 <<PORTB2); //!CS = low _delay_us(20); ADS1255_transceive(0xF); // SDATAC PORTB |=(1 <<PORTB2); //!CS = HIGH _DELAY _US(20); //________________________________ //sei(); 同时(1) { // senbd wakeup命令 //________________________________ PORTB &=~(1 << PORTB2); //!CS = low _delay_us(20); ADS1255_transceive(0); //发送WAKUP PORTB |=(1<< PORTB2);// !CS = HIGH _DELAY _US(20);// 每秒读取一次状态寄存器 //___________________ 测试= ADS1255_READ_STATUS();//发送RREG命令(状态) UART_Transmit_CHAR (测试); //通过UART _DELAY _ms(1000)发送寄存器值; //等待1秒 } } ISR(INT0_Vect){// !DOUT-Interrupt }
您好,Christopher:
Dout连接到Atmega的Miso引脚和ISP接头,用于对n ü µC进行编程。 但ISP连接器仅用于编程,而不是在测试ADC时连接。 因此,没有其他任何连接到该引脚。
我在PCB上分离了AGND和DGND,但它们直接连接在ADC下。
是的,两个板的接地板通过引脚插头连接。 另外,同一个电压调节器(3,3V)也为 µC Ω 和ADC供电。
/PDWN和/RESET始终与3,3 V相连,因此它们不可能保持在低电平状态。 ICH会在这里添加一部分我的scematics。 右侧的针脚插头连接到放置n ü µC的第二块板。 有什么想法? 谢谢你。
您好Daniel:
这是一个很好的观察,我没有注意到。 但是,我几乎说过与/CS信号上显示的RC时间恒定充电相同的内容...
从您所展示的内容来看,我只在SPI信号上看到100欧姆系列电阻器,我不会期望这些电阻足够大而导致这些影响。 是否有任何其他组件连接到这些信号? 此外,我不清楚您的MCU是位于同一PCB上还是与ADC单独的PCB上?
SCLK是ADS1255上的高阻抗输入,因此我不会期望在将此信号驱动为低电平时出现任何问题。 如果此信号上没有其他任何东西会使其拉高,我可以尝试看看我是否可以测量ADC的DGND和MCU的GND之间的电压差,看看这些器件的接地参考是否存在一些差异。
此致,
Chris
感谢您的回答。 很抱歉,我没有清楚地描述PCB的情况。 ADC和MCU不在同一PCB上。 我为模拟电路和混合器件(ADC)制作了一个PCB。 在第二个PCB上有MCU和稳压器。 两个印刷电路板通过引脚管座连接。 因此,SPI信号离开ADC通过引脚管座,然后直接进入MCU。 它之间没有其他的东西。 除ISP外,没有其它设备连接到SPI总线。
在我之前发布的示意图上,您可以使用引脚管座连接。 下图是第二个PCB (MCU)上的计数器部件。 如您所见。 除了ISP之外没有其他。 MCU和ADC靠近其PCB上的引脚管座。
我还刚刚测量了GND (MCU)和DGND (ADC)之间的电位。 它的0.00 V。我期望这一点,因为MCU和ADC的接地通过引脚管座连接。
您好,Chris:
首先,我有好消息。 ADC ist正在工作。 对我来说很丢脸…… 我在显微镜下发现了SCLK (PIN18) 和D0 (Pin19)之间的焊接桥。 我无法通过眼睛或放大镜看到它。 我还没有测量它,但我认为这可能是SCLK不能接地和ADC不能接收正确时钟信号的原因。 现在,我可以毫无问题地读写寄存器。 我一直在编程,现在尝试从ADC读取数据。 现在我又陷入了麻烦。 根据数据表,ADS1255将数据输入到2的补码中。 现在我不确定 在将这三个字节合并到一起之前是否必须处理数据。 我阅读了这篇文章
并尝试了代码示例,但未按预期工作。 在文章中,他们不是在谈论2人的赞美。
首先,我将进一步解释我的信号流。 我想测量热电偶电压。 我有一个放大器,它正在进行冷接点补偿并输出5 mV/°C 之后,还有一个单位增益放大器,它创建了差分信号,并充当ADC驱动器。 差分信号进入ADC。 ADC中没有额外的增益。
为了进行测试,我将万用表及其集成温度传感器测量到热水(80°C)中。 在我的印刷电路板上,我有两个测试点。 一个在热电偶放大器后面,一个在单位增益放大器后面,这将产生差分信号。 在第一个放大器之后,我测量约395 mV。 5 mV /°C时,非常接近80°C 这就是它的工作。
在差分线路上,继第二个放大器之后,我在负电压线路3.56 V和正电线路1.46 V上测量。输出的共模输出电压为2.5 V。因此差分电压0.4 V正是我想要测量的。 到目前为止还不错。
现在我尝试用ADC测量这400 mV。 为此,我首先根据数据表第23页计算了LSB。 我连接了2.5V参考电压。
LSB = 2 * 2500 mV (((2^23)- 1)= 0.0.00596047亿 ... mV /位
我在3个伪字节之后发送RDATA命令,以获得转换结果。 其余的我都是跟着标记的文章。 我要将结果值与LSB值相乘,以获得以mV为表示的电压。 但我得到的是一种随机数字,所以我认为我的计算有问题。 热电偶在热水中时,ADC的输出大约为“6”或“7”。 如果我放入冷水中,它是“12”或其它。 所以不是很合理。 有时在否定值和正负值之间切换。
由于我能够读写登记簿,我认为一般的通信是有效的。 但不知怎么的,我不能得到合理的结果。读了2的赞美或一些东西的价值后,我有什么需要做的?
抱歉,我对ADC不熟悉,想学习。
如果有人能看看就好了。 非常感谢。
这是我的代码:
#include <AVR/IO.h> #include <util/delay.h> #include <avr/interrupT.h> #include <string.h> #include <stdlib.h> #define 11.52万UL #define UBRR0_value (F_CPU/(16*UART)-1)#include <strate_bau.h>#define <__ ~ bub__<_<_ b波特 _<_<_ //____ 配置UART _______ void UART_INIT(){ UBRR0H =(无符号字符)(UBRR0_value >> 8); UBRR0L =(无符号字符) UBRR0_value; UCSR0B =(1<<TXEN0)|(1<<RXEN0); UCSR0C =(1<<UCSZ00)| _/<Z01_ 通过UART ______发送CHAR 静态void UART_TRANSABLE_CHAR (无符号字符) { while (!(UCSR0A &(1<<UDR0))))){;}UDR0 = ch;}//______ 通过UART _____发送字符串 静态void UART_Transmit_string (char * s) { while (*s) { UART_Transmit_char (*s); s++ } //______ 通过UART接收字节_____CHAR UART_RECEive(void){ while (!(UCSR0A &(1<RXC0)); 返回UDR0; }//END UART功能_______________________ // SPI函数______________________________________________________________ //____ 配置SPI ______ void SPI_Init() { DDRB |=(1<5)|(1<3)|(1<2);// MOSI,!CS , SCK as Output SPCR ||(1<<SPE)|(1<<MSTR)|(1<<SPR0)|(1<<CPHA); // SPI启用,SPI =主中继器,Prescaler =16 }//___ 发送SPI数据并返回接收的字节______ 未签名的char ADS1255_transceive (未签名的char数据) { SPDR = data; while (!(SPSR &(1<SPIF)));//等待传输完成 _delay_us(20); //等待10µ 直到DOUT (T6) 返回(SPDR); }// 模拟数字转换器(ASD1255)函数。_________________________________________________________________________________ //____ 读取ADS1255的寄存器并返回寄存器值______ void ADS1255_Init(){ CS_low; ADS1255_transceive (0xFE); UART_Transmit_string ("ADS1255 reset"); UART_Transmit_char('\r'); _Delay_us(5); ADS1255_transceive(0xF); UART_Transmit_string("ADS1255 SDATAC"); UART_Transmit_char('\r'); _Delay_us(10); ADS1255_transceive(0xF0); _delay_ms(1000); UART_Transmit_string("ADS1255偏移和增益自校准"); UART_Transmit_char('\r\n); _Delay_us(10); CS_high ;} char 1255_read_Register(char reg, char num){ ADSceans; CS_low;// CS =低 ADS1255_transceive;状态(0x10_reach) //读取一个寄存 器ans = ADS1255_transceive(0); //发送伪字节并保存接收的值 CS_HIGH; //!CS = HIG _DELAY _US(10); 返回ANS; } void ADS1255_Write_Register (charg,char num,charg数据){ CS_LOW; // 发送ceREG_REG;状态(0x1255); //读取一个寄存器 ADS1255_transceive(data; //发送伪字节并保存接收到的值 CS_HIGH; //!CS = HIG _DELAY _US(10); } Int32_t ADS1255_READ_Data(){ Int32_t result =0; uint8_t ADC_bytes[3]; CS_LOW;_CE_ADS1255_ADS5; transive(ADS1201)= 0 ADC_bytes[0]= ADS1255_transceive(0);// ADC_bytes[1]= ADS1255_transceive(0); ADC_bytes[2]= ADS1255_transceive(0); _delay_us(10); CS_high; _delay_us(5); IF (ADC_bytes[0]和0x80) //负值{结果=(Int32_t)((((((0xFF)<24)|((ADC_Bytes[0]&0xFF)<16)|((ADC_Bytes[1]&0xFF)<8)|((ADC_Bytes[2]&0xFF)<0_<0_;<0_)返回<__<0_=_<0_<_=_0_=_0_0_=_0=_0_0_0=_0=_0_0_0=_0=_0_0_0=_0_0=_0_0=_0=_0_0_0=_0_0=_0=_0=_0=_0_0=_0=_0_0_0_0_0_0_0=_0=_0_0_0=_0_0=_0_0_0_0_0=_0=_0_0_0=_0=_0_0_0_0_0_0=0_0=_0=0_0_0 //___为!DRDY ______配置外部中断 void External_Intterupt_Init(){ DDRD &=~(1 <<2); PORTD |=(1 <<2); EICRA |=(1 <<ISC00)|(1 <<INT01); EIMSK |=(1<<INT0); }//___ ISC0 外部中断服务例程________________________________________________________ ISR(INT0_Vect){ Drdy_flag =0; } //主要功能_______________________________ int main (void) { Int32_t result =0; double voltage =0; char buf[32]; _delay_ms(3000);//启动延迟 UART_init(); SPI_Init(); ADS1255_Init(); External_Intterupt_Init(); sei(); 同时(1) { 如果(Drdy_flag ==0)//数据可用? { 结果= ADS1255_READ_Data();// 读取ADC数据 电压=(双)结果* 0.0.596万 ; //转换为电压[V] _DELAY _ms (100); UART_Transmit_string ("ADC值:"); UART传输字符串(itoa(voltage,buf,10));//将电压转换为字符串..no浮点,但 UART_Transmit_char('\r'); } }
您好Daniel:
好消息,我很高兴您能够了解哪些因素阻碍了您与ADC进行通信!
关于数据格式设置,我认为您做得正确... 由于ADC数据是带符号二的补充数据,因此您只需象您所做的那样,将其扩展为带符号的32位整数。
我观察到的一个问题是,在RDATA命令和开始发送伪字节以检索ADC数据之间,您缺少"T6"延迟。 尝试在该处添加短暂延迟,看看这是否不能改善您的结果。
如果我正在调试,我要做的另一件事是将您收集的值打印到“adc_bytes[0]”, “adc_bytes[1]”和 “adc_bytes[2]”中,并查看这些值是否有意义,以及连接的32位“结果”值是否正确。 希望是...我写了这个示例代码:)
此致,
Chris
您好,Chris:
我想向您发送一些反馈,以感谢您的帮助。 现在一切都如预期的那样正常工作。 我在您的几篇文章(也在其他线程中)中读到,最好是手动写入ADC的所有寄存器,而不是依赖其默认设置。 我现在就这么做了! 在将三个数据字节放在一起时,也会出现一些类型转换问题。MSB总是丢失,所以我发送了一个16位值...这就是为什么发送的值总是在短时间间隔内从否定值更改为正负值的原因。
关于您的代码示例... 我确实是这样尝试的,但对我来说没有效果。 也许我做错了。 我在您的代码示例中注意到的内容。 如果我的眼睛不老,我在return命令和(Int32_t)-type cast.后计算11 x "("但13 x ")"。 因此,在将字节数放在一起时,"括号情形"可能存在问题? 但没关系,我可能只是做错了:)
再次感谢您的耐心和帮助。
您好Daniel:
感谢您的反馈! 我认为您对该示例中的括号数不匹配的说法是正确的;我对混淆表示抱歉。 另外,我仅使用TI编译器在CCS中测试了该代码,因此使用其他编译器时,代码的行为可能会有所不同。 不管怎样,我很高兴您的代码现在工作了!
此致,
Chris