ADC 仅在 ATMEGA324PA 上工作一次
ADC only working once on ATMEGA324PA
我有一些代码应该读取几个 ADC 引脚的值,每次围绕换向器循环。
static uint16_t adc0;
static uint16_t adc1;
void init(void) {
...
hw_configure_adcs();
...
}
void loop(void) {
...
adc0 = hw_read_adc(0);
adc1 = hw_read_adc(1);
...
}
void hw_configure_adcs(void) {
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0);
}
uint16_t hw_read_adc(uint8_t n) {
ADMUX = (1<<REFS0) | (n & 0x07);
ADCSRA |= (1<<ADSC); // start conversion
uint16_t count;
for (count = 0; !(ADCSRA & (1<<ADIF)); count++); // wait for conversion to complete
// ADCSRA |= (1<<ADIF); // tried with and without this
return (ADCH << 8) | ADCL; // return ADC value
}
我看到的很奇怪:adc0和adc1的值设置为相同的值并且永远不会改变,直到AVR芯片为restarted/reflashed。
(0.71V时取值为0x00d1,1.00V时取值为0x0128,貌似合理。)
我试过:
- 降低电压:adc0 和 adc1 保持不变,仅在重新刷新 AVR 代码(并因此重启芯片)时才下降。
- 调高电压:adc0 和 adc1 保持不变,只有在重新刷新 AVR 代码(并因此重启芯片)时才会上升。
- 从
hw_read_adc()
返回 count
而不是 ADC 值:这个 returns 在 0x34 和 0x38 之间变化的数字对于两个 ADC 是不同的并且随着时间不断变化。
从这些测试中,我推断正在读取 ADC,但我遗漏了一些 "clear ADCH and ADCL and get them ready to accept the new reading" 步骤。
我重读了http://www.atmel.com/images/Atmel-8272-8-bit-AVR-microcontroller-ATmega164A_PA-324A_PA-644A_PA-1284_P_datasheet.pdf的第23节很多次,但显然忽略了一些重要的东西。
经过多次谷歌搜索,我发现:http://www.avrfreaks.net/forum/adc-only-happens-once-reset
问题在于 return (ADCH << 8) | ADCL;
被编译为首先读取高位寄存器(如您所料)。
数据表第 252 页说:"Otherwise, ADCL must be read first, then ADCH"。
将我的代码更改为 return ADC
解决了问题。
我对发生的事情的猜测是:
- 发生了从 ADCH 的读取。
- 从 ADCL 读取具有锁定 ADC 结果的作用,以防止撕裂。
- 下一个 ADC 读取无处写入其结果,因为 ADC 结果已锁定。
- 重复...
您的代码存在问题,您首先阅读了 ADCH。
必须先读取ADCL,再读取ADCH,以确保Data Registers的内容属于同一转换。读取 ADCL 后,ADC 对数据寄存器的访问将被阻止。这意味着,如果已读取 ADCL,并且在读取 ADCH 之前转换完成,则两个寄存器都不会更新且转换结果会丢失。读取 ADCH 时,将重新启用 ADC 对 ADCH 和 ADCL 寄存器的访问。
所以正确的代码应该是-
return ADCL | (ADCH << 8) ;
我有一些代码应该读取几个 ADC 引脚的值,每次围绕换向器循环。
static uint16_t adc0;
static uint16_t adc1;
void init(void) {
...
hw_configure_adcs();
...
}
void loop(void) {
...
adc0 = hw_read_adc(0);
adc1 = hw_read_adc(1);
...
}
void hw_configure_adcs(void) {
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS0);
}
uint16_t hw_read_adc(uint8_t n) {
ADMUX = (1<<REFS0) | (n & 0x07);
ADCSRA |= (1<<ADSC); // start conversion
uint16_t count;
for (count = 0; !(ADCSRA & (1<<ADIF)); count++); // wait for conversion to complete
// ADCSRA |= (1<<ADIF); // tried with and without this
return (ADCH << 8) | ADCL; // return ADC value
}
我看到的很奇怪:adc0和adc1的值设置为相同的值并且永远不会改变,直到AVR芯片为restarted/reflashed。
(0.71V时取值为0x00d1,1.00V时取值为0x0128,貌似合理。)
我试过:
- 降低电压:adc0 和 adc1 保持不变,仅在重新刷新 AVR 代码(并因此重启芯片)时才下降。
- 调高电压:adc0 和 adc1 保持不变,只有在重新刷新 AVR 代码(并因此重启芯片)时才会上升。
- 从
hw_read_adc()
返回count
而不是 ADC 值:这个 returns 在 0x34 和 0x38 之间变化的数字对于两个 ADC 是不同的并且随着时间不断变化。
从这些测试中,我推断正在读取 ADC,但我遗漏了一些 "clear ADCH and ADCL and get them ready to accept the new reading" 步骤。
我重读了http://www.atmel.com/images/Atmel-8272-8-bit-AVR-microcontroller-ATmega164A_PA-324A_PA-644A_PA-1284_P_datasheet.pdf的第23节很多次,但显然忽略了一些重要的东西。
经过多次谷歌搜索,我发现:http://www.avrfreaks.net/forum/adc-only-happens-once-reset
问题在于 return (ADCH << 8) | ADCL;
被编译为首先读取高位寄存器(如您所料)。
数据表第 252 页说:"Otherwise, ADCL must be read first, then ADCH"。
将我的代码更改为 return ADC
解决了问题。
我对发生的事情的猜测是:
- 发生了从 ADCH 的读取。
- 从 ADCL 读取具有锁定 ADC 结果的作用,以防止撕裂。
- 下一个 ADC 读取无处写入其结果,因为 ADC 结果已锁定。
- 重复...
您的代码存在问题,您首先阅读了 ADCH。
必须先读取ADCL,再读取ADCH,以确保Data Registers的内容属于同一转换。读取 ADCL 后,ADC 对数据寄存器的访问将被阻止。这意味着,如果已读取 ADCL,并且在读取 ADCH 之前转换完成,则两个寄存器都不会更新且转换结果会丢失。读取 ADCH 时,将重新启用 ADC 对 ADCH 和 ADCL 寄存器的访问。
所以正确的代码应该是-
return ADCL | (ADCH << 8) ;