0

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

被感测的电压是根据这个电路: 在此处输入图像描述

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

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

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

我只用 LED 测试过 IR 传感器是否正常。顺便说一句,没关系。

微控制器的代码如下:

/*
 * 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;
    }
}

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

4

2 回答 2

1

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

  1. 您实际上并没有完全初始化ADMUXand寄存器-您放入的ADCSRA所有内容都只是“或”-in。(例如, ADLARinADMUX处于定义状态ADCSRA具有更多未定义位)。
  2. 在 ADMUX 寄存器中设置参考电压源后,您应该等待芯片切换,但不要。最有可能的是,您的第一次测量calibration将遥遥无期。解决此问题的最简单方法是进行第一次测量,您只需忽略其结果。(或在设置 ADC 后等待几毫秒)。
  3. 您应该总是ADCL 在之前 ADCH读取(AVR 锁定 ADC 以便在读取 ADCL 时将进一步的结果写入结果寄存器,直到 ADCH 也被读取)。您当前的代码具有这 2 个寄存器的未定义读取顺序。
于 2017-06-04T10:34:07.410 回答
0

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

ADC 通过设置 ADC 使能位,ADCSRA 中的 ADEN 来使能。在设置 ADEN 之前,参考电压和输入通道选择不会生效。数据表第 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,以确保 Data Registers 的内容属于同一个转换

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

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;
}
于 2017-06-04T18:55:26.967 回答