Главная » Микроконтроллеры
Призовой фонд
на март 2017 г.
1. UNI-T UT-39C
Паяльник
2. Тестер компонентов LCR-T4
Паяльник
3. 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-микроконтроллеров
Печатная плата для усилителя "LM3886 + AD825" Радиореле 220В
вверх