ATmega328p模数转换无响应
ATmega328p analog to digital conversion not responding
以下代码不更新初始 adcValue。 LED 在不同的程序中正常工作,并且在给定初始 adcValue 的情况下它们也可以正常工作。他们不响应电位器调整。延迟只是为了让它变慢,没有它也不起作用。
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
double adcValue = 700;
void startConversion()
{
ADCSRA |= (1 << ADSC);
}
void setupADC()
{
// AVcc with external capacitor as reference, ADC5 as input
ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2);
// Enabling ADC, acticating interrupts, setting prescaler to 8
ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1) ;
//disabling digital input buffer
DIDR0 = (1 << ADC5D);
startConversion();
}
ISR(ADC_vect)
{
adcValue = ADC;
}
int main(void)
{
DDRB = 0b00111111;
setupADC();
sei();
while(1)
{
_delay_ms(500);
if( adcValue < 400)
{
PORTB = 0b00000000;
}
else if ( adcValue < 800)
{
PORTB = 0b00000011;
}
else
{
PORTB = 0b00000111;
}
startConversion();
}
}
解决方案:
现在可以使用了
volatile double adcValue = 700;
adcValue
正在优化,因为编译器不会“看到”ISR 中的变量更改(它无法判断是否会调用 ISR)。因此,它只会被替换为常量。解决这个问题的方法是将它标记为 volatile
,它告诉编译器不要假设该变量的任何内容,并防止编译器对其进行优化。
现在,除此之外,adcValue
是双精度类型。通常,您希望避免在没有 FPU 的设备中使用浮点(尤其是双精度)变量。具体来说,整数和浮点类型之间的转换需要很多周期。就像,大约数百个周期。你可能不想在你的 ISR 中使用这个。
如果您确实需要将变量设为浮点数,我建议在 ISR 之外进行转换。你有两个变量,static volatile uint16_t wAdcValue
和你需要浮点数的局部变量,你会分配 float fAdcValue = (float) wAdcValue;
请注意,任何浮点操作都需要更多的处理和闪存使用来处理它。
以下代码不更新初始 adcValue。 LED 在不同的程序中正常工作,并且在给定初始 adcValue 的情况下它们也可以正常工作。他们不响应电位器调整。延迟只是为了让它变慢,没有它也不起作用。
#define F_CPU 1000000UL
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
double adcValue = 700;
void startConversion()
{
ADCSRA |= (1 << ADSC);
}
void setupADC()
{
// AVcc with external capacitor as reference, ADC5 as input
ADMUX = (1 << REFS0) | (1 << MUX0) | (1 << MUX2);
// Enabling ADC, acticating interrupts, setting prescaler to 8
ADCSRA = (1 << ADEN) | (1 << ADIE) | (1 << ADPS0) | (1 << ADPS1) ;
//disabling digital input buffer
DIDR0 = (1 << ADC5D);
startConversion();
}
ISR(ADC_vect)
{
adcValue = ADC;
}
int main(void)
{
DDRB = 0b00111111;
setupADC();
sei();
while(1)
{
_delay_ms(500);
if( adcValue < 400)
{
PORTB = 0b00000000;
}
else if ( adcValue < 800)
{
PORTB = 0b00000011;
}
else
{
PORTB = 0b00000111;
}
startConversion();
}
}
解决方案:
现在可以使用了
volatile double adcValue = 700;
adcValue
正在优化,因为编译器不会“看到”ISR 中的变量更改(它无法判断是否会调用 ISR)。因此,它只会被替换为常量。解决这个问题的方法是将它标记为 volatile
,它告诉编译器不要假设该变量的任何内容,并防止编译器对其进行优化。
现在,除此之外,adcValue
是双精度类型。通常,您希望避免在没有 FPU 的设备中使用浮点(尤其是双精度)变量。具体来说,整数和浮点类型之间的转换需要很多周期。就像,大约数百个周期。你可能不想在你的 ISR 中使用这个。
如果您确实需要将变量设为浮点数,我建议在 ISR 之外进行转换。你有两个变量,static volatile uint16_t wAdcValue
和你需要浮点数的局部变量,你会分配 float fAdcValue = (float) wAdcValue;
请注意,任何浮点操作都需要更多的处理和闪存使用来处理它。