Я изучаю программирование микроконтроллера AVR, и в настоящее время у меня есть простая светодиодная мигалка, настроенная на ATtiny26.
Потенциометр на 10 кОм подключен к ADC7 (вывод 7) в соответствии с примером в части 1 этого руководства . Выходные контакты порта B подключены к светодиодам через транзисторы в мультиплексированном массиве. (Схема прекрасно работает без участия АЦП.)
Чтобы проверить/обучиться, я мигаю одним светодиодом и жду количество миллисекунд, равное тому, что считывается с АЦП. У меня проблема, когда я пытаюсь умножить значение для реализации более длительных задержек.
Я думал, что проблема в том, что переменная, в которой я храню ADCH, была, int
но должна быть чем-то другим, потому что это 8-битный микроконтроллер и int
может быть только 0-255. Однако замена long
не сработала.
Вот код, который работает:
#define F_CPU 1000000UL
#define ADC_VREF_TYPE = 0x40
int SD = 1;
int main()
{
// Set port A to output (1)
DDRA = 0b11111111;
// Set port B, pin 3, to input (0)
DDRB &= ~(1 << PB3);
// Set control and status register
ADCSR = 0b11100111;
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCH;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
}
Проблема возникает, когда я пытаюсь использовать такой множитель:
SD = ADCH * 10;
При этом светодиод будет быстро мигать на одном конце поворота потенциометра, но будет гореть постоянно и оставаться таким в какой-то момент при повороте потенциометра на более медленные скорости (большие значения ADCH); по существу «блокируется» и требует сброса, когда потенциометр снова находится в исходном положении. Я предполагаю, что я пытаюсь сохранить значение, превышающее числовой тип, но я не могу преодолеть это, изменив тип переменной. Я пробовал long
, uint32_t
но я действительно не понимаю, что числовые типы держат в этом микро.
В: Что мне нужно сделать, чтобы реализовать задержки в диапазоне от 0 до, скажем, 2000 миллисекунд?
К вашему сведению, у меня есть следующие библиотеки:
#include <inttypes.h>
#include <avr/io.h>
#include <util/delay.h>
#include <stdlib.h>
#include <math.h>
Редактировать:
Я поместил _delay_ms(x)
прямо в свой пример, чтобы не публиковать функции, которые я фактически использую, какой вызов _delay_ms(1)
внутри цикла. Я думал, что это будет более лаконично, но, как указал один ответ, на самом деле это оказалось ошибкой.
int
может быть только 0-255
Это неправильно. В C
языке программирования int
всегда имеет ширину не менее 16 бит, даже на 8-битных микропроцессорах. A char
имеет ширину 8 бит.
Но при использовании inttypes.h
я настоятельно рекомендую использовать явные типы uint8_t
, такие как int16_t
или uint32_t
.
Ваша настоящая ошибка заключается в использовании _delay_ms()
с переменным параметром. Это не разрешено, так как это макрос , включающий вычисления с плавающей запятой - по крайней мере, в avr gcc. Вы должны использовать что-то вроде этого:
void DelayMs(int delay) {
while(delay--) _delay_ms(1);
}
ADCH * 10
будет работать безупречно. Любое дополнительное понимание того, почему это может быть не так?Я думаю, проблема в том, что у вас есть результат ADC, выровненный по левому краю в регистре результатов:
Код ниже показывает, что вы установили для ADLAR значение 1 (выравнивание по левому краю):
// Set ADC multiplexer selection register
ADMUX = 0b00100111;
Это означает, что когда вы читаете значение АЦП в ADCH, вы полностью пропускаете два младших бита (LSB). Это означает, что вы читаете число, как если бы оно было в 4 раза меньше (сдвиг на два бита вправо).
То, что вы хотите сделать, это установить его на ПРАВИЛЬНОЕ оправдание:
// Set ADC multiplexer selection register
ADMUX = 0b00000111;
и прочитайте значение вашего АЦП из ADCL (нижний регистр результата АЦП):
while (1)
{
// Set SD (step delay) to value from ADC
SD = ADCL;
// Turn on LED (it is a multiplexer, so two pins are used)
PORTA = 0b00010001;
// Wait for SD milliseconds
milli_delay(SD);
// Turn off LED
PORTA = 0b00000000;
// Wait for SD milliseconds
milli_delay(SD);
}
оправдывающий
Джей Йелтон