PWM або ШИМ на AVR для новачків. Частина 2 - програмний ШІМ

  • Час 17-12-2014, 14:57
  • Автор admin
  • Коментарів 0 Комент.
  • Силка url

У першій частині статті було розглянуто апаратний ШІМ генератор мікроконтролера. Все в ньому добре, але є кілька "але":
- апаратний ШІМ жорстко прив'язаний до певних висновків МК, його неможливо перепризначити на іншу ногу
- кількість апаратних ШІМ каналів обмежена, їх кількість залежить від моделі МК
- розрядність апаратного ШІМ неможливо змінити

У цьому випадку може стати в нагоді програмний метод отримання ШІМ сигналу. Робиться він не складно, але вимогливий до частоті роботи мікроконтролера і займає досить багато процесорного часу, на відміну від апаратного, працюючого непомітно для основної програми. Але так як застосовується він, як правило, для світлодіодних мигалок, то це не настільки важливо.

Нам необхідно на початку періоду ШІМ сигналу виставляти певну ногу МК в 1 або 0 (залежно від того, який сигнал нам потрібен), а потім, по досягненні заданої тривалості імпульсу, інвертувати значення ніжки. Робити це найзручніше у перериванні по переповненню. Так ми і поступимо, скористаємося перериванням по переповненню таймера T0. Управляти будемо RGB світлодіодом, тому й назви змінних і макроозначення для портів зробимо легкими для читання.

/ * Блок дефайнов***************************************************************************************************/ #define RED PORTB.0 #define GREEN PORTB.1 #define BLUE PORTB.2 /*****************************************************************************************************************/ / * Оголошуємо прерменные********************************************************************************************/ unsigned char red = 255, green, blue; // Змінні, для зміни шпаруватості ШІМ в програмі unsigned char red_b, green_b, blue_b; // Змінні, для буферизації значень шпаруватості ШІМ unsigned char count; // Переменная- лічильник викликів обробника переривань unsigned char temp = 1; // Змінна для роботи алгоритму зміни кольорів /*****************************************************************************************************************/

Коли настає переривання, необхідно збільшити програмний лічильник на 1 і перевірити, чи не переповнений він. Якщо таймер переповнений, то потрібно на всі ніжки, на які виводиться ШІМ, вивести логічний 1, а так само зберегти змінні в буфер. Змінні в буфер зберігаються для того, щоб дані про скважности оновлювалися раз на початку кожного періоду, це виключає непередбачувана поведінка виходу. Далі порівнюємо значення лічильника зі значенням буфера скважности кожного каналу. Якщо лічильник досяг цього значення- виводимо в відповідну ногу МК логічний 0.

/ * Обробник прерывания*******************************************************************************************/ interrupt [TIM0_OVF] void timer0_ovf_isr (void) {count ++; if (count == 0) {// якщо лічильник переповнився і прийняв значення 0 red_b = red; // Зберіг значення в буфер green_b = green; blue_b = blue; RED = 1; // Виставляємо ноги, відповідальні за ШІМ в логічну 1 GREEN = 1; BLUE = 1; } if (red_b == count) {RED = 0;} // по досягненні заданої шпаруватості виводимо логічний 0 в ніжку МК if (green_b == count) {GREEN = 0;} if (blue_b == count) {BLUE = 0; }} /*****************************************************************************************************************/

Для демонстрації роботи будемо виводити на світлодіод плавну зміну кольору за кольорами веселки (Кожен Мисливець Бажає Знати Де Сидить Фазан). Для цього скористаємося нехитрим алгоритмом, який будемо крутити в нескінченному циклі.

/ * Головна функция*************************************************************************************************/ void main (void) { PORTB = 0x08; // Конфігуруємо порт DDRB = 0x07; TCCR0 = 0x01; // Налаштовуємо таймер TCNT0 = 0x00; TIMSK = 0x01; // Дозволяємо генерацію переривання по переповненню таймера T0 #asm ("sei") // глобально дозволяємо переривання / * Нескінченний цикл************************************************************************************************/ while (1) {if (temp == 1) {if (green lt; 255) green + = 1; else temp = 2;} if (temp == 2) {if (red gt; 0) red - = 1; else temp = 3;} if (temp == 3) {if (blue lt; 255) blue + = 1; else temp = 4;} if (temp == 4) {if (green gt; 0) green - = 1; else temp = 5;} if (temp == 5) {if (red lt; 255) red + = 1; else temp = 6;} if (temp == 6) {if (blue gt; 0) blue - = 1; else temp = 1;} delay_ms (2); }; /*****************************************************************************************************************/ } /*****************************************************************************************************************/ Прикріплені файли:
  • Soft_PWM.zip (39 Кб)
Tags

Коментарі до новини