连续读取后重置 ADC 控制标志 (ATMega2560)/Arduino
Posted
技术标签:
【中文标题】连续读取后重置 ADC 控制标志 (ATMega2560)/Arduino【英文标题】:Resetting ADC control flags after continuous read (ATMega2560)/Arduino 【发布时间】:2021-12-08 15:48:51 【问题描述】:我正在使用带有电阻触摸屏的 ATMega2560(使用带有 analogRead
命令的 ADC)——我还使用带有 analogRead
(NTC 温度传感器)的其他 ADC 引脚。这一切都很好。
我最近添加了一个功能,该功能要求我以已知的时间间隔获取 ADC 读数,并决定最好使用自动采样 - 我在网上找到了执行此操作的代码,它适用于所需的功能。
我的问题是,在进行连续采样之后,我无法让 ADC analogRead
值返回与连续采样之前相同的值。
我检查了数据表,它显示了 ADCSRA、ADCSRB 和 ADMUX = 0 的初始值——我已经尝试过这个以及 很多其他方法,但没有成功。
我附上了一些与我的程序相同的代码——即analogRead
在连续采样之后返回一个不同的值。
byte samplesADC[100];
int samplesADCCount = 0;
bool ADCEnd = false;
void startADCAcquire()
int dacChan = 14;
Serial.println("Start ADC Aquire: ");
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX |= dacChan&0x07;
if (dacChan >= 8)
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
ADMUX |= (1 << REFS0); //set reference voltage
ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
ADCSRA |= (1 << ADATE); //enabble auto trigger
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADSC); //start ADC measurements
sei();//enable interrupts
void stopADCAcquire()
Serial.println("");
Serial.println("Stop ADC Acquire");
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX = 0;
// ADCSRB &= ~_BV(MUX5);
// ADMUX &= ~(1 << ADLAR);
// ADCSRA &= ~(1 << ADSC); // disable adc interrupt
sei();//enable interrupts
void setup()
Serial.begin(9600);
Serial.println("");
Serial.println("START");
Serial.print("Pin A2 (1): ");
Serial.println(analogRead(A2));
startADCAcquire();
int i;
while(ADCEnd == false)
i++;
while ((UCSR0A & _BV (TXC0)) == 0)
Serial.print("Pin A2 (2): ");
Serial.println(analogRead(A2));
Serial.println("END");
ISR(ADC_vect) //when new ADC value ready
samplesADC[samplesADCCount] = ADCH;
Serial.print(samplesADC[samplesADCCount]);
Serial.print(", ");
samplesADCCount++;
if(samplesADCCount == 100)
stopADCAcquire();
ADCEnd = true;
void loop()
输出:
START
Pin A2 (1): 0
Start ADC Aquire:
127, 127, 127...... (x100)
Stop ADC Acquire
Pin A2 (2): 510
END
【问题讨论】:
在interrupt 上阅读 Nick Gammon。 【参考方案1】:谢谢@hcheung...
所以我不确定您是否将我指向了中断页面,参考了我的中断处理程序周围的代码问题 - 我想我已经通过使用 volatile 变量和从 ISR 处理程序中删除多余的代码/打印语句对这些进行了排序.所以感谢您的链接 - 这是一个有用的提醒。
但是,这并没有解决我的问题,并且输出保持不变!在中断页面上,我注意到一些代码将寄存器复制到缓冲区,然后再重新分配。我决定试试这个,并在程序加载时复制 ADCSRA、ADCSRB 和 ADMUX 寄存器,并在 AD 扫描后重新分配它们。 这也失败了——最后,我在调用开始 AD 扫描之前复制了寄存器(即在调用了模拟读取之后)并且它起作用了。我现在可以在连续阅读后使用analogRead 命令。
我附上了有效的更新代码 - 即模拟读取在处于连续模式后工作。
volatile byte samplesADC[100];
volatile int samplesADCCount = 0;
volatile bool ADCEnd = false;
uint8_t ADCSRASave;
uint8_t ADCSRBSave;
uint8_t ADMUXSave;
void startADCAcquire()
int dacChan = 14;
ADCSRASave = ADCSRA;
ADCSRBSave = ADCSRB;
ADMUXSave = ADMUX;
cli();//diable interrupts
//set up continuous sampling of analog pin 0
//clear ADCSRA and ADCSRB registers
ADCSRA = 0;
ADCSRB = 0;
ADMUX |= dacChan&0x07;
if (dacChan >= 8)
ADCSRB |= _BV(MUX5);
else
ADCSRB &= ~_BV(MUX5);
ADMUX |= (1 << REFS0); //set reference voltage
ADMUX |= (1 << ADLAR); //left align the ADC value- so we can read highest 8 bits from ADCH register only
ADCSRA |= (1 << ADPS2) | (1 << ADPS0); //set ADC clock with 32 prescaler- 16mHz/32=500kHz
ADCSRA |= (1 << ADATE); //enabble auto trigger
ADCSRA |= (1 << ADIE); //enable interrupts when measurement complete
ADCSRA |= (1 << ADEN); //enable ADC
ADCSRA |= (1 << ADSC); //start ADC measurements
sei();//enable interrupts
void stopADCAcquire()
cli();//diable interrupts
ADCSRA = ADCSRASave; //0;
ADCSRB = ADCSRBSave; //0;
ADMUX = ADMUXSave; //;
sei();//enable interrupts
void setup()
Serial.begin(9600);
Serial.println("");
Serial.println("START");
Serial.print("Pin A2 (1): ");
Serial.println(analogRead(A14));
Serial.println("Start ADC Aquire: ");
while ((UCSR0A & _BV (TXC0)) == 0)
startADCAcquire();
while(ADCEnd == false)
stopADCAcquire();
for(int x = 0; x < 100; x++)
Serial.print(samplesADC[x]);
Serial.print(", ");
Serial.println("");
Serial.println("Stop ADC Acquire");
Serial.print("Pin A2 (2): ");
Serial.println(analogRead(A14));
Serial.println("END");
ISR(ADC_vect) //when new ADC value ready
samplesADC[samplesADCCount] = ADCH;
// Serial.print("p");
samplesADCCount++;
if(samplesADCCount == 100)
ADCEnd = true;
void loop()
输出:
START
Pin A2 (1): 511
Start ADC Aquire:
127, 127, 127, 127 <<< x 100
Stop ADC Acquire
Pin A2 (2): 511 <<< value now same as first
END
【讨论】:
以上是关于连续读取后重置 ADC 控制标志 (ATMega2560)/Arduino的主要内容,如果未能解决你的问题,请参考以下文章