Содержание
Урок 1. Первый проект
Урок 2. Управление кнопками
Урок 3. Подключение LCD
Урок 4. Использование ШИМ
Урок 5. Таймеры
Урок 6.1. Статическая индикация
Урок 6.2. Динамическая индикация
Урок 7.1. Генерация звука
Урок 7.2. Генерация звука. Продолжение
Урок 8.1. Передача данных через UART
Урок 8.2. Передача данных через UART. Продолжение»
Урок 9. Передача данных через SPI
Урок 10. Изучение АЦП. Простой вольтметр
Урок 11. Получение синуса при помощи ШИМ
Урок 12. Измерение температуры
Урок 13. Внешние прерывания.
Урок 14. Использование отладчика
Урок 15.1. Управление инкрементальным энкодером
Урок 15.2. Управление громкостью, при помощи энкодера
Урок 16. Управление RGB светодиодом
Урок 17. Использование ИК
Урок 18.1. Знакомство с графическим дисплеем
Урок 18.2 Вывод изображения на графический дисплей
Урок 18.3 Вывод русскоязычного текста
Урок 19. Формирование сигнала, при помощи ЦАП (R2R)
Урок 20. Опрос матричной клавиатуры
Урок 21. Сторожевой таймер
Урок 22.1 Воспроизведение wav. Введение.
Урок 22.2 Воспроизведение wav. Продолжение.
Урок 23.1 Работа с внешней памятью
Урок 23.2 Работа с файловой системой Fat

ШИМ (PWM) — широтно-импульсная модуляция. Не нужно пугаться данного термина. Это всего навсего способ регулирования напряжения. Допустим подсветка монитора горит слишком ярко, вы меняете яркость. А что же происходит в этот момент на самом деле? 

Представим себе, что подсветка монитора это несколько светодиодов. Питается все это дело от постоянного напряжения. Но вот нам понадобилось уменьшить яркость монитора. Логично ответить, что это можно сделать переменным резистором. На маленьких токах — возможно. Но на больших, резистор будет сильно греться. Сильно возрастут габариты, потери, энергопотребление.

Поэтому люди придумали схему на транзисторах, которая делает из постоянного напряжения пульсирующее. Оказывается, пульсирующее напряжение, в зависимости от заполнения периода будет эквивалентно постоянному напряжению. Т.е. если в течение периода напряжение 50% времени было включено, 50% выключено, то эквивалент постоянного напряжения будет равен 50% от номинального.

В цифрах это просто — было 5В постоянного напряжения прогнали через ШИМ — получили 2,5В. Если заполнение импульса равно 75%, то эквивалентное постоянное напряжение будет 3,75В. Думаю идея понятна.

Теперь приступим к практической реализации. Будем при помощи микроконтроллера изменять заполнение от 0 до 100%, потом от 100% до нуля. Конечный результат должен выглядеть так:

Чтобы было более наглядно, подключим светодиод. В результате у нас будет плавно включаться и отключаться светодиод.

Запускаем наш любимый CodeVision. Создаем проект при помощи мастера. В разделе таймеров (Timers), выбираем Timer 2 и выставляем настройки как на рисунке.

Если попробовать сгенерировать проект, то прога может ругнуться. Соглашаемся, ведь у нас нога 3 порта В должна быть настроена как выход.

Приводим код к следующему виду:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <mega8.h>
 
void main(void)
{
PORTB=0x00;
DDRB=0x08;
 
// Timer/Counter 2 initialization
ASSR=0x00;
TCCR2=0x6C;
TCNT2=0x00;
OCR2=0x00;
TIMSK=0x00;
 
while (1)
{
 
};
}

Уделим внимание строке OCR2=0x00; Эта переменная как раз и отвечает за величину заполнения импульса. Изменяется данная величина от 0 до 255(0хFF), т.е. 255 соответствует 100% -му заполнению (постоянный ток). Следовательно, если нужно 30% заполнение (255/100)*30=77. Далее 77 переводим в шестнадцатеричную систему OCR2=0x4D;

TCCR2=0x6C; Изменяя данную величину мы можем регулировать частоту ШИМ. Величина частоты работы ШИМ кратна частоте, на которой работает микроконтроллер. В проекте использована частота микроконтроллера 8 МГц, частоту ШИМ использовали 125кГц, следовательно делитель равен 8/125=64
0x6C в двоичной системе счисления 1101100, открываем даташит на Atmega8 и видим описание регистра TCCR2, так вот 1101100 последние цифры 100 и отвечают за выбор частоты работы ШИМ

Приступим непосредственно к программе:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <mega8.h>
#include <delay.h>
void main(void)
{
 
PORTB=0x00;
DDRB=0x08;
 
ASSR=0x00;
TCCR2=0x6C;
TCNT2=0x00;
OCR2=0x00;
TIMSK=0x00;
 
while (1)
{
      while(OCR2<0xff)
      {
          OCR2=OCR2+0x01;
          delay_ms(5);
      }
      while(OCR2>0x00)
      {
          OCR2=OCR2-0x01;
          delay_ms(5);
      }
};
}

Код прост до безобразия: сначала в цикле увеличиваем заполнение от 0 до 255(ff), потом уменьшаем от 255 до 0.
И напоследок видосик, как это все должно работать. Успехов в изучении)

149 комментариев: Урок 4. Использование ШИМ в AVR микроконтроллерах

  • смотрите 6 урок там расписано

  • С ПИД регулятора получаю значение в десятичной системе (от 0 до 255 или от -255 до 255)
    Как мне это значение пропорционально перевести в шестнадцатиричное, что бы послать в OCR2?

  • пропорцией

  • подскажите пожалуйста как сделать так чтобы при наступлении прерываний ШИМ останавливался а на ножку мк выводился тот коэффициент заполнения который был в момент остановки таймера?

  • посмотрите в даташите, какой то бит TCCR2 отвечает за вкл/выкл таймера, соответственно внутри прерывания выключайте таймер и смотрите OCR

  • Скажите а у вас нет урока по использованию программного шим?
    Если есть задача управлять 5-8-ю каналами. например поочередно плавно зажигая и гася СвДиоды, как это лучше сделать.
    спасибо.

  • Добрый вечер

    в протеусе код программы работает отлично, но стоит использовать ШИМ и протеус начинает виснуть
    может ли МК atmega16 выполнять ШИМ параллельно с кодом программы?

  • может

  • Подскажите пожалуйста, не могу разобрать ошибку:

    adc = (int)read_adc(1); //считываем значение АЦП
    adc_f =(int) adc/4; //делим его на 4 и берём только целую часть
    adc_in=(char)adc_f; //преобразование типов

    if (adc_in>=0 && 18 && 20 && 23 && <=26) Error:invalid expression
    {OCR2=19;}
    …………
    Когда писал так же под тини13 — не было никаких ошибок

  • надо каждую расписать adc_in>=18 && adc_in>=20 и тп

  • Спасибо, теперь работает… :grin:

  • Либо возможно скобки расставить:
    if (adc_in>=(0 && 18 && 20 && 23) && adc_in<=26)

  • как регулировать шим с ацп. дайте направление .подскажите.код не прошу это будет не правильно.

  • как то вы написали это будет шикарный код что вы имели ввиду? заранее говорю спасибо .

  • ivan, какой шикарный код) у вас есть 1 регистр 8 битный и есть второй регистр 8 битный. В чем проблема читать один и ложить значение в другой?

  • вы имеете ввиду что есть регистр АЦП читать его и ложить значение в регистр OCR?
    я так понимаю.Может я не правильно понимаю?

  • правильно

  • а в настройках ацп выставить в одиночном преобразовании или в беспрерывном? Можете ответить? заранее говорю спасибо.

  • можна ещё один вопрос.В регистре ацп от 0 до 1023=1024 а в регистре таймера 255
    это шаг ~~ 4.011 это нужно вводить float вещественное

  • можете пересчитать пропорцией или взять старшие 8бит регистра АЦП

  • вот у меня получился вот такой код в протеусе работает только 1 mux 0 не работает работает в инверсси ну так мне нужно.я хочуэту программу использовать в домовом освещении.что можете посоветовать.может тренироватся в железе? заранее говорю спасибо.

    * ADC(PWM)_2mega8.c
    *
    * Created: 17.11.2016 19:05:54
    * Author : User
    */
    #define F_CPU 8000000UL
    #include
    #include «pauza.h»
    #include
    //#include

    ISR(ADC_vect)
    {
    //OCR1A=ADCW/4;
    //OCR1B=ADCW/4;
    asm(«sei»);
    ADMUX |=(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);

    OCR2=~ADCW/4;
    asm("cli");
    asm("sei");

    OCR1A=~ADCW/4;
    ADMUX |=(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(1<<MUX0);
    asm("cli");

    ADCSRA |=(1<<ADSC);//бит разрешает проводить замер АЦП

    }

    int main(void)
    {
    DDRC|=0x00;
    DDRB|=(1<<1)|(1<<2)|(1<<3);
    PORTB&=~((1<<1)|(1<<2)|(1<<3));
    TCCR1A|=(1<<COM1A1)|(0<<COM1A0)|(1<<COM1B1)|(0<<COM1B0)|(0<<FOC1A)|(0<<FOC1B)|(0<<WGM11)|(1<<WGM10);
    TCCR1B|=(0<<ICNC1)|(0<<ICES1)|(0<<WGM13)|(1<<WGM12)|(1<<CS12)|(0<<CS11)|(0<<CS10);
    TCCR2|=(0<<FOC2)|(1<<WGM20)|(1<<COM21)|(0<<COM20)|(1<<WGM21)|(1<<CS22) | (1<<CS21) | (0<<CS20);

    ADCSRA|=(1<<ADEN);//регистр разрешающийи работу ацп
    ADCSRA|=(1<<ADIF)|(1<<ADIE)|(1<<ADFR)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);//4 бит регистра разрешает прерывание в АЦП 3 бит флаг по прерыванию уст.1
    ADMUX |=(0<<REFS1)|(1<<REFS0)|(0<<MUX3)|(0<<MUX2)|(0<<MUX1)|(0<<MUX0);
    ADCSRA |=(1<<ADSC);//бит разрешает проводить замер АЦП
    asm("sei");
    while (1)
    {

    }
    }

  • лениво по даташитам лазить и смотреть регистры, как минимум вы запрещаете глобальные прерывания при выходе из прерывания.

  • Почему плавает уровень при перестроении шим?

  • спасибо.Оказывается программирование это тоже труд.Энергоёмкий по информации

  • Я так понимаю то, что Вы называете частотой ШИМ, является частотой работы таймера. Но таймер отсчитывает 255 «тиков» для формирования импульса (выставляя либо 0, либо 1 в порт, в зависимости от значения регистра OCR2). Эти 255 «тиков» являются одним периодом импульса. То есть реальная частота ШИМ будет в 255 раз меньше частоты, выбранной на вкладке Timer 2 и для Вашего случая будет равна 490 Гц. Поправьте, если ошибаюсь.

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

  • Здравствуйте, admin. Пните пожалуйста в нужном направлении основного цикла. Необходимо плавно зажечь светодиод с помощью ШИМ.Здесь понятно всё. Теперь надо его просто потушить кнопкой. Как кнопками плавно увеличить или уменьшить яркость , мне понятно. А вот как мгновенно ШИМ уменьшить до нуля ?

  • выключить таймер

  • Спасибо !

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Можно использовать следующие HTML-теги и атрибуты: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Свежие записи
Последние комментарии
  • Загрузка...
Архивы
Счетчик
Яндекс.Метрика