Содержание
Урок 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.
И напоследок видосик, как это все должно работать. Успехов в изучении)

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

  • как это програмно правильно сделать?

  • после окончания каждого из этих 2-х циклов прописать?

    TCCR2=0x00;
    TCNT2=0x00;
    OCR2=0x00;
    TIMSK=0x00;

  • TCCR2=0x00; достаточно

  • ок. завтра попробую.

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

  • ткнитесь осциллографом, тогда сразу станет понятно

  • Почему не работает такой код для увеличения и уменьшения скважности}
    if (PINB.0==0)
    {
    OCR2=OCR2+0x19;
    delay_ms(5);
    }
    if (PINB.2==0)
    {
    OCR2=OCR2-0x19;
    delay_ms(5);
    }

  • все работает. проверяйте настройки кнопок и добавьте ограничение, чтобы OCR не был больше 255 и меньше 0 иначе будет перескакивать

  • Спасибо. Ув. админ подскажите полезно ли изучать ассемблер для программирования МК или это что-то подобное архилогическим раскопкам. 😆

  • я бы сказал настоятельно рекомендуется

  • Можно копировать сигнал ШИМ на другую ножку (или несколько) МК с помощью команды вроде этой PORTD.0=PINB.3;?

  • только если ножка также настроена на ШИМ

  • Подскажите, если мне нужен ШИМ с периодом 1 секунда с регулировкой скважности, возможно это сделать в в настройках Timer 1? И как при этом регулировать скважность? Если можно часть кода.

  • либо программный, либо не на авр.

  • Подскажите, как можно сделать, чтоб при напряжении на АЦП более 4В, на таймере№2 включался шим, а на таймере№1 шим включался только на 30 сек и отключался? Т.е.
    if (V>4)
    {
    TCCR2=0x6F;
    TCCR1B=0x0C; (и через 30 сек он выкл и больше не включался)

  • Добавьте еще таймер0, который будет отсчитывать 30 сек

  • Подскажите пожалуйста как сделать так чтобы светодиод гас до конца выше вы писали что необходимо остановить таймер написав строку TCCR2=0x00; но я так и не понял куда ее нужно вписать. Заранее благодарен!

    #include
    #include
    void main(void)
    {

    PORTB=0x02;
    DDRB=0b00001000;

    ASSR=0x00;
    TCCR2=0x6C;
    TCNT2=0x00;
    OCR2=0x00;
    TIMSK=0x00;

    while (1)
    {
    if(PINB.1==0)
    {
    while(OCR20x00)
    {
    OCR2=OCR2-0x01;
    delay_ms(5);

    }

    };
    }
    }

  • Извините не тот код!
    #include
    #include
    void main(void)

    {
    PORTB=0x02;
    DDRB=0b00001000;

    ASSR=0x00;
    TCCR2=0x6C;
    TCNT2=0x00;
    OCR2=0x00;
    TIMSK=0x00;

    while (1)

    {
    if(PINB.1==0)
    {
    while(OCR20x00)

    {
    OCR2=OCR2-0x01;
    delay_ms(5);
    }

    };
    }
    }

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

  • заливайте на обменник и оставляйте ссылку

  • Добрый день подскажите пожалуйста как можно организовать двух канальный шим ?

  • Взять 1 таймер, на нем настроить ШИМ, взять 2 таймер, на нем настроить ШИМ.

  • спасибо но не могу получить от 0,7 до 17,5 кГц прошу подсказки какую частоту и какой предделитель использовать

  • Предделители фиксированные.

  • Доброго времени суток.спасибо за чудесный сайт. Подскажите как сделать аппаратно шим на частоте 50Гц не как не пойму??предделитель только максимум до 7кГц сбрасывает.как поступить подскажите?

  • подскажу читать http://avr-start.ru/?p=4500

  • Добрый вечер можно ли получить шим с разными амплитудами и заполнением ? осцилограму не знаю как показать вам но типо этого ( II ii II ii )

  • Здравствуйте. Подскажите пожалуйста в чем может быть дело: при симуляции в протеусе заполнение ШИМ растет до максимума а обратно идти не хочет. Вот мой код. Протеус 8.3 SP2

    #include
    #include

    void main(void)
    {
    PORTB=0x00;
    DDRB=0x08;

    // Timer/Counter 2 initialization

    ASSR=0x00;
    TCCR2=108;//частота шим
    TCNT2=0x00;
    OCR2=0;//заполнение
    TIMSK=0x00;
    while (1)
    {
    while(OCR21);
    {
    OCR2=OCR2-1;
    delay_ms(3);
    }

    // Please write your application code here

    }
    }

  • Артур, вечер добрый. Проектирую блок питания с регулировкой ШИМ на атмеге 328. Какова стратегия выбора частоты для этих целей? И как расчитать интегрирующую цепь, для получения постоянного эквивалента? Шим управляет ОУ типа lm328.

  • Для начала хорошо бы понять какую именно схему вы хотите собрать

  • 8 МГц / 64= 125 кГц — это значит ножка PB.3 должна выдавать 125 кГц? Но протеус выдает совсем другое,,,(((. Может здесь присутствует такая логика: таймер считает до 255, значит 125кГц/255=490 Гц, т.е. ножка должна выдавать 490 Гц??? Или же протеус не правильно показывает???
    Просто хочу сделать генератор на 36кГц для TSOP, чтобы можно было менять скважность…никак из-за этого не разберусь…

  • Для генерации частоты 36 кГц с регулируемой скважностью придется использовать 16 битный таймер?

  • Правильная же настройка? Это на 31,250 кГц на ножке:
    TCCR0=0b01101001;
    TCNT0=0x00;
    OCR0=0x4D; //30 %

    Или будет кушать слишком много питания? Помогите сделать поэкономней…

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

  • Кушать будет только деталь которую вы подключите . например моторчик, чем больше процент или скважность включения гожки тем больше напряжения на моторчик , чем больше кушать будет мотор. но мое мнения что при шиме сон делать как то не тот ефекта даст.

  • добрый день
    подскажите, напряжение до 0-я не спускается,
    #include
    #include

    // Declare your global variables here

    void main(void)
    {
    // Declare your local variables here

    // Input/Output Ports initialization
    // Port B initialization
    // Function: Bit7=In Bit6=In Bit5=In Bit4=In Bit3=Out Bit2=In Bit1=Out Bit0=Out
    DDRB=(0<<DDB7) | (0<<DDB6) | (0<<DDB5) | (0<<DDB4) | (1<<DDB3) | (0<<DDB2) | (0<<DDB1) | (0<<DDB0);
    // State: Bit7=P Bit6=P Bit5=P Bit4=P Bit3=1 Bit2=P Bit1=0 Bit0=0
    PORTB=(1<<PORTB7) | (1<<PORTB6) | (1<<PORTB5) | (1<<PORTB4) | (0<<PORTB3) | (1<<PORTB2) | (1<<PORTB1) | (1<<PORTB0);

    // Port C initialization
    // Function: Bit6=In Bit5=In Bit4=In Bit3=In Bit2=In Bit1=In Bit0=In
    DDRC=(0<<DDC6) | (0<<DDC5) | (0<<DDC4) | (0<<DDC3) | (0<<DDC2) | (0<<DDC1) | (0<<DDC0);
    // State: Bit6=T Bit5=T Bit4=T Bit3=T Bit2=T Bit1=T Bit0=T
    PORTC=(0<<PORTC6) | (0<<PORTC5) | (0<<PORTC4) | (0<<PORTC3) | (0<<PORTC2) | (0<<PORTC1) | (0<<PORTC0);

    // Port D initialization
    // Function: Bit7=Out Bit6=Out Bit5=Out Bit4=Out Bit3=Out Bit2=Out Bit1=Out Bit0=Out
    DDRD=(1<<DDD7) | (1<<DDD6) | (1<<DDD5) | (1<<DDD4) | (1<<DDD3) | (1<<DDD2) | (1<<DDD1) | (1<<DDD0);
    // State: Bit7=0 Bit6=0 Bit5=0 Bit4=0 Bit3=0 Bit2=0 Bit1=0 Bit0=0
    PORTD=(0<<PORTD7) | (0<<PORTD6) | (0<<PORTD5) | (0<<PORTD4) | (0<<PORTD3) | (0<<PORTD2) | (0<<PORTD1) | (0<<PORTD0);

    // Timer/Counter 0 initialization
    // Clock source: System Clock
    // Clock value: Timer 0 Stopped
    TCCR0=(0<<CS02) | (0<<CS01) | (0<<CS00);
    TCNT0=0x00;

    // Timer/Counter 1 initialization
    // Clock source: System Clock
    // Clock value: Timer1 Stopped
    // Mode: Normal top=0xFFFF
    // OC1A output: Disconnected
    // OC1B output: Disconnected
    // Noise Canceler: Off
    // Input Capture on Falling Edge
    // Timer1 Overflow Interrupt: Off
    // Input Capture Interrupt: Off
    // Compare A Match Interrupt: Off
    // Compare B Match Interrupt: Off
    TCCR1A=(0<<COM1A1) | (0<<COM1A0) | (0<<COM1B1) | (0<<COM1B0) | (0<<WGM11) | (0<<WGM10);
    TCCR1B=(0<<ICNC1) | (0<<ICES1) | (0<<WGM13) | (0<<WGM12) | (0<<CS12) | (0<<CS11) | (0<<CS10);
    TCNT1H=0x00;
    TCNT1L=0x00;
    ICR1H=0x00;
    ICR1L=0x00;
    OCR1AH=0x00;
    OCR1AL=0x00;
    OCR1BH=0x00;
    OCR1BL=0x00;

    // Timer/Counter 2 initialization
    // Clock source: System Clock
    // Clock value: 125,000 kHz
    // Mode: Fast PWM top=0xFF
    // OC2 output: Non-Inverted PWM
    // Timer Period: 2,048 ms
    // Output Pulse(s):
    // OC2 Period: 2,048 ms Width: 0 us
    ASSR=0<<AS2;
    TCCR2=(1<<PWM2) | (1<<COM21) | (0<<COM20) | (1<<CTC2) | (1<<CS22) | (0<<CS21) | (0<<CS20);
    TCNT2=0x00;
    OCR2=0x00;

    // Timer(s)/Counter(s) Interrupt(s) initialization
    TIMSK=(0<<OCIE2) | (0<<TOIE2) | (0<<TICIE1) | (0<<OCIE1A) | (0<<OCIE1B) | (0<<TOIE1) | (0<<TOIE0);

    // External Interrupt(s) initialization
    // INT0: Off
    // INT1: Off
    MCUCR=(0<<ISC11) | (0<<ISC10) | (0<<ISC01) | (0<<ISC00);

    // USART initialization
    // USART disabled
    UCSRB=(0<<RXCIE) | (0<<TXCIE) | (0<<UDRIE) | (0<<RXEN) | (0<<TXEN) | (0<<UCSZ2) | (0<<RXB8) | (0<<TXB8);

    // Analog Comparator initialization
    // Analog Comparator: Off
    // The Analog Comparator's positive input is
    // connected to the AIN0 pin
    // The Analog Comparator's negative input is
    // connected to the AIN1 pin
    ACSR=(1<<ACD) | (0<<ACBG) | (0<<ACO) | (0<<ACI) | (0<<ACIE) | (0<<ACIC) | (0<<ACIS1) | (0<<ACIS0);
    SFIOR=(0<<ACME);

    // ADC initialization
    // ADC disabled
    ADCSRA=(0<<ADEN) | (0<<ADSC) | (0<<ADFR) | (0<<ADIF) | (0<<ADIE) | (0<<ADPS2) | (0<<ADPS1) | (0<<ADPS0);

    // SPI initialization
    // SPI disabled
    SPCR=(0<<SPIE) | (0<<SPE) | (0<<DORD) | (0<<MSTR) | (0<<CPOL) | (0<<CPHA) | (0<<SPR1) | (0<<SPR0);

    // TWI initialization
    // TWI disabled
    TWCR=(0<<TWEA) | (0<<TWSTA) | (0<<TWSTO) | (0<<TWEN) | (0<0)
    {

    delay_ms(10);
    OCR2—;

    }
    while(!PINB.2&OCR2<255)
    {

    delay_ms(10);
    OCR2=175;

    }
    }
    }
    }

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

  • чтобы до нуля опустить нужно выключить таймер, про индикаторы смотрите 6 урок, там есть и про статическую и про динамическую индикацию

  • спасибо за подсказку
    в место TCCR2=0x6C; // TCCR2=(1<<PWM2) | (1<<COM21) | (0<<COM20) | (1<<CTC2) | (1<<CS22) | (0<<CS21) | (0<<CS20);
    я использовал TCCR2=0x7C;
    TCCR2=(1<<PWM2) | (1<<COM21) | (1<<COM20) | (1<<CTC2) | (1<<CS22) | (0<<CS21) | (0<<CS20);
    и всё заработало в идеале
    ОГРОМНОЕ СПАСИБО Вам за ваш сайт, очень помогает, особенно новичкам
    осталось разобраться с индикатором
    можно ли использовать индикаторы относительно данных OCR2
    например : OCR2=127 индикатор покажет 50, OCR2=255 на индикаторе число100?

  • конечно, пересчитывайте пропорцией x = (OCR2*100)/255

  • Добрый вечер
    Могли бы Вы привести пример как правильно написать, я пока не совсем понял как связать с шим
    Спаибо

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

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

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