无法在atmega328上使用ADC

时间:2017-06-04 07:20:53

标签: avr atmega adc atmelstudio proximitysensor

我正在尝试使用ATmega328P制作接近传感器。我使用板载ADC转换电压值,如果它高于环境温度,LED会亮起。

正在感测的电压取决于此电路: enter image description here

在电路中,VOUT将进入ADC通道3并应被感知(想想右侧的LED作为IR传感器)。

当程序启动时,它会检测到30个读数并将其平均值用作环境设置。如果任何后续测量值高于此值,LED应点亮。

但即使我将手放在传感器上方,LED也不亮。

我只用LED测试,看看红外传感器是否正常。顺便说一下,这是好的。

微控制器的代码如下:

/*
 * Proximity Sensor IR.c
 *
 * Created: 6/3/2017 2:35:33 PM
 * Author : Rishav
 */ 

#include <avr/io.h>
#include <stdio.h>

#define F_CPU 16000000UL
#include <util/delay.h>

int calibration()
{
    unsigned int sum = 0;

    for (int i=0; i<30; i++)
        {
            ADCSRA |= (1<<ADSC);
            while(!(ADCSRA & (1<<ADIF)));

            ADCSRA |= (1<<ADIF);

            sum += (ADCH<<8)|ADCL;
        }

    return (sum/30);
}

int main(void)
{
    unsigned int val = 0;

    ADMUX |= (0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(1<<MUX1)|(1<<MUX0);     //setting the multiplexer to ADC3
    ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);

    DDRB = 0b00000010;

    DDRD |= (1<<PCINT22);
    PORTD |= (1<<PCINT22);

    int calib_value = calibration();

    while (1) 
    {       
        ADCSRA |= (1<<ADSC);
        while(!(ADCSRA & (1<<ADIF)));

        val = (ADCH<<8)|ADCL;

        ADCSRA |= (1<<ADIF);

        if (val > calib_value)
            PORTB = 0b00000010;
    }
}

我认为代码中存在一些问题。请帮忙。

2 个答案:

答案 0 :(得分:1)

查看代码时会想到一些事情:

  1. 您实际上并非完全初始化 ADMUXADCSRA个注册表 - 您在其中放置的所有内容都只是&#39; ORed&#39; -in。 (ADLAR中的ADMUX 未处于已定义的状态,例如,ADCSRA具有更多未定义的位。)
  2. 在ADMUX寄存器中设置参考电压源后,您应该等待芯片切换,但不要。最有可能的是,您在calibration中的第一次测量将会消失。解决这个问题的最简单方法是先进行一次测量,然后忽略其结果。 (或者在设置ADC后等待几毫秒)。
  3. 您应该始终在 ADCL之前读取ADCH (AVR锁定ADC,以便在读取ADCL时将更多结果写入结果寄存器,直到读取ADCH为止好)。您当前的代码具有这两个寄存器的未定义读取顺序。

答案 1 :(得分:0)

您必须首先启用ADC,然后选择通道和参考电压。在数据表中很容易跳过这个事实。

  

通过将ADCSRA中的ADC使能位ADEN置1来使能ADC。   电压参考和输入通道选择不会生效   直到ADEN设定。 Datasheet page 238.

我没有检查您的所有设置,但我很确定这一定是您的问题。

示例顺序:

void init_adc()
{
    ADCSRA |= (1<<ADEN);                            // enable ADC
    ADMUX |= (1<<MUX1) | (1<<MUX0);                 // channel selection ADC3 - PB3
    ADMUX &= ~(1<<REFS0);                           // VCC as reference
    ADCSRA |= (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0); // setting prescaler to 128
}

如上所述,您应首先阅读ADCL:

  

必须先读取ADCL,然后再读取ADCH,以确保其内容   数据寄存器属于同一转换

我建议将此部分移动到一个单独的函数中:

uint16_t read_adc()
{
    ADCSRA |= (1<<ADSC);

    while(!(ADCSRA & (1<<ADIF)));

    uint8_t adcl = ADCL;
    uint8_t adch = ADCH;

    ADCSRA |= (1<<ADIF);

    return (adch<<8) | adcl;
}