Решил научиться управлять 4-х контактными кулерами, для этого необходим ШИМ с частотой 25 кГц. Разбираемся, реализуем требуемое.
Задача
Для управления скоростью вращения вентилятора при помощи МК ATmega 328P организовать 2-х канальный ШИМ, с частотой 25 кГц. Проверить, что при помощи настроенной схемы можно управлять вентиляторами.
Отступление
Не имею профильного образования по работе с МК, в данный момент самостоятельно изучаю данное направление. Например на изучение работы таймеров и закрепления материала в виде написания данной статьи потрачено ~ 10 часов. Как следствие решение может содержать некоторые не точности.
Решение
Как обычно расписывать много теории не буду, благо много информации в интернетах и есть документация от производителя(далее по тексту буду ссылаться на эту документацию с указанием номеров страниц и таблиц). Для облегчения жизни МК организуем ШИМ при помощи таймеров.
По условиям задачи необходимо реализовать 2 канала, в ATmega 328P можно реализовать двумя способами:
- Использовать два 8-ми битных таймера T0 и T2;
- Использовать один 16-ти битный таймер T1.
Свободные таймеры всегда пригодятся, потому будем использовать вариант с одном таймером, да и смотрится он красивее.
Расчет таймера
В документации есть раздел с описанием работы T1 стр. 149-185(в целом не мало), а на страницах 171-172 размещена таблица 20-6 с режимами работы таймера.
Как писал выше интересен вариант независимого управления двумя каналами на частоте 25 кГц, из прочитанного понял, что не подойдут следующие:
- Нормальный режим(
ШИМ = Тактовая частота / ( Делитель * Разрядность таймера )
16 000 000 / ( 1 * 65 535 ) = 244,144 Гц
), счет происходит от нижнего до разрядности таймера. Даже с применением делителя, его не достаточно. Рассчитать можно по формуле: - Режим очистки по совпадению( ), в которых переполнение в происходит при достижения установленного значения в регистре OCR1A — на выходе имеем только один канал;
- Режимы быстрого ШИМ(Fast PWM) и с коррекцией фазы(Phase Correct), с разрядностью 8, 9 , 10 бит смотри пункт 1.
Остаются режимы работы в которых переполнение в происходит при достижения установленного значения в регистре ICR1,
Режим Fast PWM
Режим 14 в таблице 20-6 на странице 172. В этом режиме счетчик считает до верхнего предела и сбрасывается, формула расчета следующая:
ШИМ = Тактовая частота / Делитель * ( 1 + Верхний предел )
16 000 000 / 1 * ( 1 + 639 ) = 25 000 Гц
Ну и напишу формулу, которой я получил верхний предел:
Верхний предел = ( Тактовая частота * Делитель / ШИМ ) — 1
( 16 000 000 * 1 / 25 000 ) — 1 = 639
Полученное значение помещаем в регистр ICR1. Скважность сигнала будет регулироваться регистрами OCR1A и OCR1B. Предполагал, что диапазон должен быть от 0 до 639, но по работе вентилятора пришел к значениям от 320 до 640(при условии, что по документации вентилятор не меняет скорости, при скважности 0-30%). Попробую позже разобрать(TODO).
Остается воспользоваться таблицей выходного сигнала 20-4, параметрами режима 14 таблицы 20-6, таблицей делителей 20-7, и написать функцию инициализации:
void pwm_initial() { DDRB |= 1 << 1; // PB1 как выход, канал 1 DDRB |= 1 << 2; // PB2 как выход, канал 2 TCCR1A = 0; // Сброс данных регистра TCCR1B = 0; // Сброс данных регистра TCNT1 = 0; // Установка нижнего предела TCCR1B |= (1 << CS10); // Работа без делителя TCCR1A |= (1 << COM1A1) | (1 << COM1B1); // Не инверсный режим работы ICR1 = 639; // 16 МГц / 1 * ( 1 + 639 ) = 25 кГц // Установка верхнего предела // значением в бите ICR1 // Режим 14 из документации TCCR1A |= (1 << WGM11); TCCR1B |= (1 << WGM12) | (1 << WGM13); OCR1A = 416; // Начальное значение уровня 30% OCR1B = 416; // Начальное значение уровня 30% }
Режим Phase Correct
Режим 10 в таблице 20-6 на странице 172. В этом режиме счетчик считает от 0 до верхнего предела, а потом обратно до 0, формула расчета следующая:
ШИМ = Тактовая частота / 2* Делитель * Верхний предел
16 000 000 / 2 * 1 * 320 = 25 000 Гц
Ну и напишу формулу, которой я получил верхний предел:
Верхний предел = Тактовая частота / ( 2 * Делитель * ШИМ )
16 000 000 / ( 2 * 1 * 25 000 ) = 320
Полученное значение помещаем в регистр ICR1. Скважность сигнала будет регулироваться регистрами OCR1A и OCR1B, по документации диапазон от 0 до 320.
Остается воспользоваться таблицей выходного сигнала 20-5, параметрами режима 10 таблицы 20-6, таблицей делителей 20-7, и написать функцию инициализации:
void pwm_initial() { DDRB |= 1 << 1; // PB1 как выход, канал 1 DDRB |= 1 << 2; // PB2 как выход, канал 2 TCCR1A = 0; // Сброс данных регистра TCCR1B = 0; // Сброс данных регистра TCNT1 = 0; // Установка нижнего предела TCCR1B |= (1 << CS10); // Работа без делителя TCCR1A |= (1 << COM1A1) | (1 << COM1B1); // Не инверсный режим работы ICR1 = 320; // 16 МГц / 2 * 1 * 320 = 25 кГц // Установка верхнего предела // значением в бите ICR1 // Режим 10 из документации TCCR1A |= (1 << WGM11); TCCR1B |= (1 << WGM13); OCR1A = 96; // Начальное значение уровня 30% OCR1B = 96; // Начальное значение уровня 30% }
Режим Phase and Frequency Correct
Режим 8 в таблице 20-6 на странице 172. В этом режиме возможно менять не только скважность, но и частоту сигнала. В остальном аналогичен режиму Phase Correct PWM, в рамках данной статьи разбирать не буду.
Проверка работы
Теперь при остается вызвать описанную функцию при начале работы программы, и на ножках PB1 и PB2 будет работать ШИМ с частотой 25 кГц
Для проверки работы нам хватит одного вентилятора. К вентилятору производим подключение к контактам
- GND вентилятора к Atmega;
- + 12 В;
- Не задействован;
- ШИМ сигнал от порта PB1 или PB2.
После запуска вентилятор начнет вращаться с небольшой скоростью. Для управления скоростью необходимо менять значение битов OCR1A и OCR1B для портов PB1 и PB2 соответственно.
Для проверки частоты можно воспользоваться осциллографом или написать небольшую программку на том же МК, об этом опубликована статья ATmega. Счетчик импульсов ШИМ.
Спасибо за материал. Режим 15 (ШИМ) не смог настроить, а 14 режим заработал на ATmega328.
Vladimir, рад, что пригодилось!
Здравствуйте, уважаемый Guesto! Возникло несколько вопросов. Прошу прощения, если они глупые.
1. -12В и +12В от какого источника питания вы подали на вентилятор?
2. Вы в коде указали, что «TCCR1A |= (1 << COM1A1) | (1 << COM1B1); // Не инверсный режим работы». А инверсный это какой? С отрицательным напряжением?
Артём, добрый день!
Вопросы не глупые, просто некоторые моменты со временем кажутся примитивными, хотя ранее на них было потрачено не мало времени.
По вопросам:
1. Использовал компьютерный блок питания, он умеет выдавать 5 и 12 Вольт одновременно и имеет общий GND. И правильней написать именно GND, а не -12 Вольт(в статье поправил);
2. Тут я намудрил, дословно переведя документацию. Правильнее для понимания будет «Порямой» и «Обратный» режимы.
Если очень грубо, различие в установке высокого или низкого сигнала на выходе, при совпадении счетчика с верхним переделом. Надеюсь не запутал еще больше.
Рекомендую изучить документацию, в ней подробно описаны механизмы работы.
Сам же освежу знания и поправлю статью, после прочтения остались вопросы(