Главная » Микроконтроллеры
Призовой фонд
на октябрь 2017 г.
1. Термометр Relsib WT51
Рэлсиб
2. 1000 руб
PCBWay
3. Регулируемый паяльник 60 Вт
Паяльник
4. 100 руб.
От пользователей

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

В первой части статьи был рассмотрен аппаратный ШИМ генератор микроконтроллера. Всё в нем хорошо, но есть несколько "но":
- аппаратный ШИМ жёстко привязан к определенным выводам МК, его невозможно переназначить на другую ногу
- количество аппаратных ШИМ каналов ограничено, их количество зависит от модели МК
- разрядность аппаратного ШИМ невозможно изменить

В этом случае может пригодиться программный метод получения ШИМ сигнала. Делается он не сложно, но требователен к частоте работы микроконтроллера и занимает достаточно много процессорного времени, в отличие от аппаратного, работающего незаметно для основной программы. Но так как применяется он, как правило, для светодиодных мигалок, то это не столь важно.

Нам необходимо в начале периода ШИМ сигнала выставлять определенную ногу МК в 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 < 255)   green += 1; else temp = 2;}                                                
        if (temp==2) {if (red   >   0)   red   -= 1; else temp = 3;}                              
        if (temp==3) {if (blue  < 255)   blue  += 1; else temp = 4;}  
        if (temp==4) {if (green >   0)   green -= 1; else temp = 5;}  
        if (temp==5) {if (red   < 255)   red   += 1; else temp = 6;}  
        if (temp==6) {if (blue  >   0)   blue  -= 1; else temp = 1;}
        
        delay_ms(2);   

      };
/*****************************************************************************************************************/
}
/*****************************************************************************************************************/
Прикрепленные файлы:

Теги:

Опубликована: 24.12.2013 0 1
Я собрал 0 1
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 4 Проголосовало: 1 чел.

Комментарии (7) | Я собрал (0) | Подписаться

0
Vezd #
Счетчик count может иметь максимальное значение 255 и далее при увеличении на единицу сбрасывается в ноль? Почему это так?
RGB светодиод подключен одновременно к трём портам: PB0, PB1, PB2?
Отредактирован 22.12.2014 11:52
Ответить
0
Ekklesiast #
Переменная count имеет тип unsigned char. Размер 8 бит, т.е. может принимать 256 (двойка в восьмой степени) значений. Это от 0 до 255, дальше - переполнение и сброс в 0.
У RGB светодиода 4 вывода, по одному на каждую цветовую составляющую и один общий (может быть как катод, так и анод). Общий вывод в зависимости от типа диода подключается к + питания или к общему -, а выводы кристаллов (цвета) к выводам порта МК, в данном случае PB0, PB1, PB2.
Отредактирован 23.12.2014 10:50
Ответить
0
Виталий #
Везде один и тот же пример со светодиодами (помигать), вот только программы по разному написаны, а смысл от этого?
Я нигде не нашел примеров плавного открытия того же транзистора, например:
кнопку нажал - лампа плавно зажклась.
её же отпустил - так же плавно потухла
Ответить
+1

[Автор]
serenbkii #
Здесь светодиод не мигает, а плавно меняет цвет. Написать такую программу проще простого, мой пример гораздо сложней.
Ответить
0
Юрасик #
Уважаемый автор, Возможно ли реализовать Ваш проект на Attiny13, используя 5 выходов порта В (за исключением 1 ноги - RESET). Пока я вижу, что hex-файл не выходит за пределы памяти этой МС.
И еще вопрос, какой аналог команде
interrupt [TIM0_OVF] void timer0_ovf_isr(void)
существует в ассемблере AVRStudio?
Ответить
0

[Автор]
serenbkii #
Здравствуйте. Возможно, можно даже ногу reset использовать. Но она слабая по току и светить светодиод будет тускло.
interrupt [TIM0_OVF] void timer0_ovf_isr(void) это обработчик прерывания по переполнения таймера. Я давно не писал на ассемблере и не могу сказать точно, как это делается. Изучите соответствующую литературу.
Ответить
0
Azerhud #
Здравствуйте Уважаемый автор. Можно ли реализовать программный ШИМ для 22 светодиодов на ATMEGA8?
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется электрическое сопротивление?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Pickit 2 - USB-программатор PIC-микроконтроллеров
Pickit 2 - USB-программатор PIC-микроконтроллеров
DC-DC регулируемый преобразователь 1.5-37В 2А с индикатором МиниПК MK809V - 4 ядра, Android 4.4.2
вверх