Учебный курс. Широтно-импульсная модуляция (ШИМ, PWM). Управление яркостью светодиода. Генерация аналогового сигнала.

Пример №1. Управление яркостью светодиода с помощью ШИМ

управление яркостью светодиода с помощью ШИМ

Пояснения к схеме

   R2 – переменный резистор номиналом 10К. Центральный вывод резистора через НЧ-фильтр подключен к нулевому каналу АЦП. Напряжение на резисторе преобразуется в цифровой код, который записывается в регистр сравнения таймера Т0. Таким образом с помощью резистора   осуществляется регулировка скважности ШИМ сигнала.
   Led1 – мощный светодиод белого цвета. Падение напряжения на нем около 4 Вольт. Максимальный ток светодиода, задается резистором  R5 и равен 100 мА.
(Uпит – Uled)/R5 = (5 - 4)/10 = 100 мА
   IRLU024N – N–канальный полевой транзистор. Вместо него можно использовать любые полевые транзисторы серии IRL (L - это значит, что управляются логическим уровнем)
   R3 – токоограничительный резистор на всякий случай. R4 – pull-down резистор. Затвор полевого транзистора нельзя оставлять "болтающимся в воздухе". 

Программа

//************************************************************
//
//  Учебный курс. Программирование микроконтроллеров AVR на Си
//  Управление нагрузкой с помощью
//  широтно-импульсной модуляции (ШИМ, PWM)                 
//
//************************************************************

#include
#include

int main(void)
{
  //инициализация портов
  PORTB = 0;
  DDRB = 0xff;
 
  //инициализация таймера Т0
  TIMSK = 0;
  //реж. - fast pwm, вывод OC0 - неинверт. шим, clk/64
  TCCR0 = (1<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00)|(0<<CS02)|(1<<CS01)|(1<<CS00);
  TCNT0 = 0;
  OCR0 = 0;

   //инициализируем АЦП
  //ион - напряжение питания, выравнивание влево, нулевой канал

  ADMUX = (0<<REFS1)|(1<<REFS0)|(1<<ADLAR)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
  //вкл. ацп, реж. непрерывн. преобр., разр. прерывания, частота преобр. = FCPU/128
  ADCSRA = (1<<ADEN)|(1<<ADSC)|(1<<ADATE)|(1<<ADIE)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
  //режим непрерывного преобразования
  SFIOR = 0;
 
  __enable_interrupt();
  while(1);
  return 0;
}

//********************************
//прерывание АЦП

#pragma vector=ADC_vect
__interrupt void adc_my(void)
{
  //считываем старший регистр АЦП и
  //записываем в регистр сравнения
  OCR0 = ADCH;
}

Пояснения к коду

Логика работы

   Инициализация периферии - таймера Т0, модуля АЦП. Разрешение прерываний. Бесконечный цикл. В прерывании АЦП напряжение считанное с переменного резистора записывается в регистр сравнения OCR0. В микроконтроллере AVR для этого регистра организован буфер , и на самом деле запись происходит сначала в него. Из буфера же значение переписывается в OCR0, только когда происходит переполнение счетного регистра TCNT0. Параллельно циклу while и модулю АЦП, работает таймер Т0 и генерит на выводе OC0(PB2) ШИМ сигнал. Когда счетный регистр TCNT0 переполняется OC0 устанавливается в 1, когда значение счетного регистра совпадает с регистром сравнения OCR0, вывод устанавливается в 0. 

Инициализация таймера

   Прерывания таймера не используются, поэтому регистр TIMSK = 0. 
   За установки таймера Т0 отвечает конфигурационный регистр TCCR0.
   Биты WGM01, WHM00 определяют режим работы. 11 - режим Fast PWM. 
   Биты CS02, CS01, CS00 - устанавливают коэффициент предделителя таймера. 011 - соответствует предделителю 64. Тактовая частота таймера/счетчика будет Fcpu/64
   Биты COM01, COM00 -определяют поведение вывода OC0. 10 - соответствует неинвертированному ШИМ сигналу. 1 - при переполнении TCNT0, 0 - при совпадении TCNT0 c OCR0.
 
Инициализация АЦП   
 
   Здесь должно быть все понятно. АЦП используется в режиме непрерывного преобразования. Активируется после разрешения всех прерываний и перезапускается автоматически 
 

Пример №2. Генерация синусоидального сигнала с помощью ШИМ

генерация синусоидального сигнала с помощью ШИМ

Пояснение к схемe

   Резистор R2 просто забыл выкинуть из схемы. R3 и C8 интегратор. 

Программа

//************************************************************
//
//  Учебный курс. Программирование микроконтроллеров AVR на Си
//  Генерация синуса с помощью
//  широтно-импульсной модуляции (ШИМ, PWM)                
//
//************************************************************

#include
#include
#include "TableSin.h"

int main(void)
{
  //инициализация портов
  PORTB = 0;
  DDRB = 0xff;

  //инициализация таймера Т0
  TIMSK = (1<<OCIE0);
  //реж. - fast pwm, вывод OC0 - неинверт. шим, предделитель - на 8
  TCCR0 = (1<<WGM01)|(1<<WGM00)|(1<<COM01)|(0<<COM00)|(0<<CS02)|(1<<CS01)|(0<<CS00);
  //обнуляем счетный регистр и регистр сравнения
  TCNT0 = 0;
  OCR0 = 0;

   __enable_interrupt();
  while(1);
  return 0;

}

//**********************************************************
//Прерывание таймера/счетчика Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
  static unsigned char i = 0;
 
  //считываем элемент массива и записываем в регистр сравнения
  OCR0 = TableSin[i];
  i++;
  if (i == 32) i = 0;
}

Пояснения к коду

Таблица значений синуса

   TableSin.h - хедер, в котором прописан константный массив, содержащий 32 значения синуса.  

Инициализация таймера Т0

  В программе используется прерывание таймера Т0 по событию совпадение.Для разрешения прерывания устанавливается бит OCIE0 регистра TIMSK. Остальная часть инициализации таймера, как и в предыдущей программе. 

Обработчик прерывания таймера Т0

  В прерывании таймера микроконтроллер считывает из массива очередное значение синуса и записывает его в регистр сравнения OCR0. Действительная перезапись этого регистра происходит когда счетный регистр таймера Т0 переполняется. Для доступа к элементам массива используется статическая переменная, значение которой увеличивается на 1, пока не дойдет до 32. 

Полученная синусоида на экране осциллографа
Полученный синусоидальный сигнал. Частота 122 Гц. Размах почти 2 В
 
Увеличенный кусок синусоиды
Увеличенный кусок синусоиды.
 

Файлы проектов для IARa.

Другие материалы в этой категории: « Программные таймеры. Часть 1 Трюк с #define »

У вас недостаточно прав для комментирования.