Практически в каждом своем проекте, вне зависимости от его сложности и предназначения, радиолюбители используют ШИМ. Ниже информация для тех, кто еще не встречался с такой аббревиатурой. Если же вы уже знаете что это такое, то смело можете пропускать следующий абзац.
Итак, что же такое ШИМ? На английском это сокращение звучит иначе - PWM, что расшифровывается как pulse-width modulation (широтно-импульсная модуляция). Вся суть ШИМа в изменении скважности импульсов, что позволяет изменять среднее напряжение на нагрузке. Всего различают три вида ШИМ: аналоговый, двоичный (наш вариант) и троичный.
Рис 1.1. Пример ШИМ.
В микроконтроллерах AVR ШИМ организован аппаратно. Забегая вперед, скажу, что при желании его можно сделать и программно, использовав прерывания. Но это тема следующего урока.
Подведем промежуточные итоги: мы знаем что в МК фирмы Atmel есть аппаратный ШИМ (зачастую не один, а несколько), а так же знаем, что собственно он собой представляет. Но как им управлять?
Оказывается все довольно просто. Для управления ШИМом в mikroPascal есть специальные процедуры, с помощью которых можно инициализировать ШИМ, запустить/остановить и задать длительность импульсов. Далее, предлагаю вашему вниманию простой пример, в котором мы просто запустим ШИМ с заданной длительностью импульса и частотой.
program PWM_mega8_1_2_3ch_def; //Самый простой метод работы с ШИМом в mikroPascal. //Достаточно просто инициализировать модуль ШИМ и просто //забыть про него. procedure Init(); //Для простоты вынес инициализацию в отдельную процедуру. begin //В этом примере это не существенно, но далее тк будет проще. DDRB := 0xFF; //Для правильной работы ШИМа необходимо настроить порт "на выход". PWM16bit_Init(_PWM16_FAST_MODE_8BIT, _PWM16_PRESCALER_16bit_8, _PWM16_NON_INVERTED, 200, _TIMER1); //Инициализация 16 битного ШИМа (OCR1A, OCR1B). PWM2_Init(_PWM2_FAST_MODE, _PWM2_PRESCALER_8, _PWM2_NON_INVERTED, 200); //Тоже самое, но для 8-ми битного модуля (OCR2). end; begin Init(); while TRUE do begin end; end.
Думаю вас заинтересовали функции "PWM16bit_Init" и "PWM2_Init". Это функции из стандартной библиотеки mikroPascal, которая так и называется - PWM Library. Советую вам все-таки почитать даташит для ATmega8 (для демонстрации примеров будет использоваться именно этот доступный МК). И как из последнего следует, в ATmega8 есть три канала ШИМ: один 8-ми битный и два 16-ти битных. Первый работает за счет таймера/счетчика 2, а второй - таймера/счетчика 1. К сожалению, для T0 такой опции нет.
Теперь немного о самих функциях инициализации.
procedure PWM16bit_Init(тип генерации : byte; предделитель : byte; инверсия : byte; длительность импульса : word; используемый таймер : byte);
Для PWM2 отличий мало:
procedure PWM2_Init(тип генерации : byte; предделитель : byte; инверсия : byte; длительность импульса : word);
Отсутствует только выбор таймера. Что касается выбора параметров, то для этого нужно открыть help. Там все неплохо расписано, хоть и на английском (в статье я это приводить не буду, уж больно много места это займет).
Теперь можно посмотреть, что получилось в итоге. Для этого запускаем Proteus, выбираем МК.. ну и так далее. Вот результат:
Но согласитесь, довольно редко требуется чтобы скважность ШИМ была неизменной. Ведь практически всегда нужно изменять яркость светодиода и т.д. во время выполнения программы. Так что немного дополним первый пример.
program PWM_mega8_1_2_3ch_def_adv; procedure Init(); //Инициализация ШИМа в этом примере ничем не отличается от прошлого примера. begin DDRB := 0xFF; PWM16bit_Init(_PWM16_FAST_MODE_8BIT, _PWM16_PRESCALER_16bit_8, _PWM16_NON_INVERTED, 200, _TIMER1); PWM2_Init(_PWM2_FAST_MODE, _PWM2_PRESCALER_8, _PWM2_NON_INVERTED, 200); end; begin Init(); delay_ms(1000); //Выставляем задержку 1с PWM2_Set_Duty(128); //Изменяем скважность импульсов для второго модуля ШИМ. delay_ms(1000); //Еще 1с задержки. Далее изменяем скважность уже для 1-го модуля ШИМ. PWM16bit_Change_Duty(128, _TIMER1_CH_A); //Очень интересный момент! Подробнее смотрите в видео! while TRUE do begin end; end.
Теперь, как вы видите, через 1с после запуска программы изменится длительность импульсов на выходе OC2, а еще через 1с - на выходе OC1A.
Но можно еще немного усложнить программу. Например, добавим выключение ШИМа через 3с после старта.
delay_ms(1000); //Допишем еще три строчки, которые будут отключать ШИМ (оба канала), PWM2_Stop; //через 1с. PWM16bit_Stop(_TIMER1_CH_A);
Этот кусочек кода вставьте перед бесконечным циклом. И вот результат:
Использование библиотек, конечно удобно. Но в любом случае, необходимо уметь работать с регистрами напрямую, что бы не зависеть от других разработчиков (которые как раз и пишут эти библиотеки).
Так как мы используем в качестве "наглядного пособия" микроконтроллер ATmega8, то у ШИМ тут относятся следующие регистры: OCR1AL, OCR1AH, OCR1BL, OCR1BH, OCR2, TCCR1A, TCCR1B, TCCR2. Регистры OCRx служат для записи значения, до которого будет считать таймер, и соответственно это определяют длительность импульса на выходе. Регистры TCCRx служат для настройки режимов ШИМ, настройки таймеров и их предделителей.
В прикрепленном файле TCCR.rar (скачать в конце статьи) привожу "расшифровку" вышеупомянутых регистров
Зададим такие же параметры ШИМ как и в первом примере.
Начнем с TCCR2. Для этого нам нужно:
- Установить режим Fast PWM. Это можно сделать, выставив биты 3 и 6 (WGM21 и WGM20).
- Кроме того, не забываем про бит 5 (COM21), для не инвертированного режима.
- И устанавливаем предделитель на 8 - это бит 1 (CS21).
Должно получиться так: 01101010 (нулевой бит справа).
Далее конфигурируем регистры TCCR1A и TCCR1B.
- В TCCR1A нужно записать такую последовательность: 10100001;
- А в TCCR1B нужно записать: 00001010.
- Что я предлагаю вам туда записать, посмотрите в даташите или картинках выше.
Ниже представлен полный код:
program PWM_1_2_3ch_reg_adv; //В этом примере рассмотрим //"ручную" настройку ШИМа для //популярного микроконтроллера ATmega8. var i: byte; procedure Init(); begin DDRB := 0xFF; //Привычно настраиваем порт на выход. OCR2 := 200; //Но теперь, уже простого заглядывания в "магический" help не будет. OCR1AH := 0x0; //Нужно брать в руки даташит на тот контроллер, под который вы пишите программу и OCR1AL := 200; //выискивать раздел с описанием регистров для таймеров. OCR1BH := 0x0; //В данном случае, нужно было найти информацию по регистрам TCCR2, TCCR1A и TCCR1B. OCR1BL := 200; //В регистры OCRx записывается число, с которым потом будет сравниваться значение TCCR2 := %01101010; //таймера, и которое, соответственно будет определять длительность (заполнение) импульсов. TCCR1A := %10100001; TCCR1B := %00001010; end; begin Init(); while TRUE do begin end; end.
Как уже упоминалось, для изменения длительности импульсов на выходе достаточно просто записать другое число в регистры OCRx. Не забывайте, регистры OCR1AH и OCR1AL представляют собой "половинки" одного 16-ти битного регистра. Можно сразу "закрепить" знания, дописав немного кода:
var i: byte; .... for i := 0 to 255 do begin //Просто сидеть и наблюдать за неизменной длительностью импульсов OCR2 := i; //довольно скучно, по этому мы немного внесем разнообразия в этот проектик. OCR1AL := i; OCR1BL := i; //Просто возьмем и сделаем так, чтобы сначала длительность импульсов delay_ms(10); //увеличивалась, а потом уменьшалась. end; //Это крайне легко сделать с помощью цикла! for i := 255 downto 0 do begin //Такую конструкцию не очень часто встретишь, но слово "downto" обозначает декремент. OCR2 := i; OCR1AL := i; OCR1BL := i; delay_ms(10); end;
Объявите переменную i (byte) и вставьте код в бесконечный цикл. После запуска симуляции в Proteus, можно наблюдать такую картину:
На этой ноте я заканчиваю. Надеюсь, что вы нашли в этой статье что-то полезное для себя. Спасибо за внимание!
Прикрепленные файлы:
- mikroPascal(lessn7_PWM_).rar (1194 Кб)
- TCCR.rar (276 Кб)
Комментарии (4) | Я собрал (0) | Подписаться
Для добавления Вашей сборки необходима регистрация
Даже если догадаться, что сравниваются ДЛИТЕЛЬНОСТИ уровней, всё равно ваше определение в корне не верно. Скважность есть отношение периода к длительности импульса S=T/t. Ещё есть величина обратная скважности, коэффициент заполнения, он же Duty cycle (ИМХО, понятней, наглядней и удобней, чем скважность), D=t/T.
И да, что ещё за аналоговый ШИМ? Можно ссылку на описание/определение?
[Автор]
[Автор]