我現在正在用ATMega328P擺弄一下,想要通過ADC讀取來自引腳的模擬值,並將值簡單地輸出到4個LED。真的很簡單AVR ATMega328P ADC通道選擇問題
#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);
}
}
這種工作很好,除了渠道選擇。當我選擇一個頻道時,它工作正常,但與所選頻道無關,頻道0也會一直讀取並轉換。我的意思是,如果我將電纜插入選定的通道引腳,它會正確讀取值。當我插入任何其他通道引腳時,它顯然不會,除了ADC0。不管我設置什麼通道,不僅是一個讀取,還有ADC0。
這是爲什麼,我該如何解決?
我已經檢查了我的PCB焊橋,但沒有,我也希望有一些稍微不同的行爲。
ADC4和ADC5似乎也不能正確轉換。任何想法,爲什麼?我在數據表中發現的唯一線索是,這兩個使用數字電源,而所有其他ADC使用模擬電源。有什麼區別,爲什麼它很重要,爲什麼它不正確地轉換我的anlogue信號?
ARef和AVCC都根據數據表連接,除ARef的電感器丟失外。
啊,那工作!謝謝! Mino更正,但該行需要爲'ADMUX | =(ADMUX&0xF0)| (通道&0x0F);否則,ANDing將阻止正確的位被設置。 –
正確,你發現我的錯字。很高興有幫助。 – js441