gpt4 book ai didi

c - AVR ATMega328P ADC channel 选择问题

转载 作者:行者123 更新时间:2023-12-03 05:20:34 26 4
gpt4 key购买 nike

我现在正在摆弄 ATMega328P,希望通过 ADC 从引脚读取模拟值,然后将该值简单地输出到 4 个 LED。真的很简单

#define F_CPU 20000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

#define BRIGHTNESS_PIN 2
#define ADC_SAMPLES 5

void init_adc()
{
//set ADC VRef to AVCC
ADMUX |= (1 << REFS0);
//enable ADC and set pre-scaler to 128
ADCSRA = (1 << ADPS0) | (1 << ADPS1) | (1 << ADPS2) | (1 << ADEN);
}

uint16_t read_adc(unsigned char channel)
{
//clear lower 4 bits of ADMUX and select ADC channel according to argument
ADMUX &= (0xF0);
ADMUX |= (channel & 0x0F); //set channel, limit channel selection to lower 4 bits

//start ADC conversion
ADCSRA |= (1 << ADSC);

//wait for conversion to finish
while(!(ADCSRA & (1 << ADIF)));

ADCSRA |= (1 << ADIF); //reset as required

return ADC;
}

int main(void)
{
uint32_t brightness_total;
uint16_t brightness = 0;
uint32_t i = 0;

init_adc();
sei();
while (1)
{
//reset LED pins
PORTB &= ~(1 << PINB0);
PORTD &= ~(1 << PIND7);
PORTD &= ~(1 << PIND6);
PORTD &= ~(1 << PIND5);

PORTB |= (1 << PINB1); //just blink

read_adc(BRIGHTNESS_PIN); //first throw-away read
//read n sample values from the ADC and average them out
brightness_total = 0;
for(i = 0; i < ADC_SAMPLES; ++i)
{
brightness_total += read_adc(BRIGHTNESS_PIN);
}
brightness = brightness_total / ADC_SAMPLES;

//set pins for LEDs depending on read value.
if(brightness > 768)
{
PORTB |= (1 << PINB0);
PORTD |= (1 << PIND7);
PORTD |= (1 << PIND6);
PORTD |= (1 << PIND5);
}
else if (brightness <= 768 && brightness > 512)
{
PORTB |= (1 << PINB0);
PORTD |= (1 << PIND7);
PORTD |= (1 << PIND6);
}
else if (brightness <= 512 && brightness > 256)
{
PORTB |= (1 << PINB0);
PORTD |= (1 << PIND7);
}
else if (brightness <= 256 && brightness >=64)
{
PORTB |= (1 << PINB0);
}

_delay_ms(500);
PORTB &= ~(1 << PINB1); //just blink
_delay_ms(500);
}
}

除了 channel 选择之外,这工作得很好。当我选择一个 channel 时,它工作正常,但与所选 channel 无关, channel 0 也始终会读取和转换。我的意思是,如果我将电缆插入选定的 channel 引脚,它会正确读取值。当我将其插入任何其他 channel 引脚时,显然没有,除了 ADC0。无论我设置哪个 channel ,不仅会读取该 channel ,还会读取 ADC0。

为什么会这样以及如何解决这个问题?

我已经检查了 PCB 上的焊桥,但没有焊桥,而且我预计会有一些稍微不同的行为。

此外,ADC4 和 ADC5 似乎也无法正确转换。知道为什么吗?我在数据表中发现的唯一线索是,这两个使用数字电源,而所有其他 ADC 使用模拟电源。有什么区别,为什么它很重要,为什么它不能正确转换我的模拟信号?

ARef 和 A​​VCC 均根据数据表进行连接,但 ARef 的电感器缺失。

最佳答案

认为正在发生的事情是这样的

ADMUX &= (0xF0);

将 channel 设置为 0,并且

ADMUX |= (channel & 0x0F);

然后将 channel 设置为您想要的 channel 。然后,您将读取读数并丢弃结果,这意味着将初始 channel 设置为 0 并不重要。

但是,当您尝试获取实际读数时,您将通过使用 read_adc 获取读数来再次设置 channel 。所以,你永远不要扔掉阅读的内容。

我要做的是将 ADMUX 设置命令替换为:

ADMUX = (0xF0) | (channel & 0x0F)

然后将其移至一个名为 set_adc_channel(int channel) 的单独函数中。在该函数中包含一次性读取,然后从 read_adc 函数中删除 ADMUX 设置。只需开始转换即可获得结果。

另请注意,由于您只使用一个 channel ,因此您可以将 channel 设置部分移至 init_adc()。我假设它位于一个单独的函数中,这样您以后就可以阅读多个 channel 。

我希望这是清楚的。如果没有请告诉我。

关于c - AVR ATMega328P ADC channel 选择问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39320267/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com