Что ж, я думаю, у вас все в порядке со всеми выводами портов B и C. Кроме того, вам не нужно ничего делать при сборке на AVR. Только сборка доступна в виде макросов в avr-libc.
Настраивать
Во-первых, вы неправильно настраиваете TCCR0. Вы должны установить все биты сразу или использовать операцию чтения-изменения-записи (обычно TCCR0 |= _BV(bit_num);
для установки бита или TCCR0 &= ~_BV(bit_num);
для его очистки). (_BV(N)
- это макрос avr-libc, который более разборчив, чем (1<<N)
материал, который вы используете, но делает то же самое.) Кроме того, вам не хватает полярности вывода ШИМ, установленной битами COM00 и COM01. Прямо сейчас у вас (неявно) отключен выход PWM (OC0 отключен).
Поэтому я предполагаю, что вам нужен положительный ШИМ, то есть более высокие входные значения ШИМ приводят к большим рабочим циклам с высокой выходной мощностью. Это означает, что COM01
необходимо установить, а COM00
нужно очистить. (См. Стр. 80-81 спецификации ATmega32 (L).) В результате появится строка настройки:
TCCR0 = _BV(WGM01) | _BV(WGM00) // PWM mode: Fast PWM.
| _BV(COM01) // PWM polarity: active high
| _BV(CS02) | _BV(CS00); // PWM clock: CPU_Clock / 1024
Рабочий цикл
Теперь мы переходим к фактической генерации рабочего цикла. Таймер 0 довольно глупый, и он жестко связывает свой НИЖНИЙ с 0
, а верхний с 0xFF
. Это означает, что каждый период ШИМ равен PWM_Clock / 256
, а поскольку вы устанавливаете PWM_Clock
на CPU_Clock / 1024
, период равен CPU_Clock / 262144
, что составляет около 33 мс для тактовой частоты процессора 8 МГц. Таким образом, каждый такт ШИМ этот счетчик считает от 0 до 255, затем возвращается к 0 и повторяется.
Фактическая ШИМ генерируется схемой OC согласно таблице 40. Для имеющейся у нас настройки COM0*
она говорит:
Очистить OC0 при сравнении совпадения, установить OC0 в НИЖНЕЕ
Это означает, что каждый раз, когда счетчик ведет счет, он сравнивает значение счетчика с регистром OCR0
и, если они совпадают, переводит выходной контакт OC0
на GND. Когда счетчик возвращается к 0, он переводит вывод на VCC.
Итак, чтобы установить рабочий цикл, вы просто записываете значение, соответствующее этому рабочему циклу, в OCR0
:
OCR0 = 0; // 0% duty cycle: always GND.
OCR0 = 64; // 25% duty cycle
OCR0 = 128; // 50% duty cycle
OCR0 = 172; // 67% duty cycle
OCR0 = 255; // 100% duty cycle; always VCC. See below.
Этот последний случай предназначен для решения общей проблемы с ШИМ: количество возможных настроек рабочего цикла всегда на единицу больше, чем количество шагов счета. В этом случае имеется 256 шагов, и если на выходе может быть VCC для 0, 1, 2,… 256 из этих шагов, это дает 257 вариантов. Таким образом, вместо того, чтобы предотвращать случай 0% или 100%, они заставляют исчезнуть случай, когда меньше 100%. В примечании 1 к таблице 40 говорится:
Особый случай возникает, когда OCR0 равен TOP и установлен COM01. В этом случае сравнение игнорируется, но установка или очистка выполняется ВНИЗ.
И еще одно: если вы пишете в OCR0
в середине цикла ШИМ, он просто ждет следующего цикла.
Моделирование ускорения
Теперь, чтобы получить желаемое «постоянное ускорение», вам нужна какая-то стандартная временная база. Прерывание TOV0
(переполнение таймера 0) может сработать, или вы можете использовать другой таймер или какую-то внешнюю ссылку. Вы будете использовать эту стандартную временную базу, чтобы знать, когда обновлять OCR0
.
Постоянное ускорение просто означает, что скорость изменяется линейно со временем. Если пойти дальше, это означает, что для каждого события обновления вам необходимо изменить скорость на постоянную величину. Вероятно, это не что иное, как арифметика насыщения:
#define kAccelStep 4
void accelerate_step() {
uint8_t x = OCR0;
if(x < (255 - kAccelStep))
OCR0 = x + kAccelStep;
else
OCR0 = 255;
}
Просто делайте что-то подобное для каждого временного шага, и вы получите постоянное ускорение. Аналогичный алгоритм можно использовать для замедления, и вы даже можете использовать более изящные алгоритмы для моделирования нелинейных функций или для компенсации того факта, что двигатель не сразу переходит на скорость, заданную ШИМ.
person
Mike DeSimone
schedule
29.10.2013