Форма входа

Категории раздела

Силы природы [10]
Новые технологии [42]
Неопознанное [27]
Интересные факты [32]
Личности [22]
Объявления, предложения пользователей и гостей!!!! [29]
Поисковики хорошо индексирует этот раздел! Вам только остается преподнести как Вам это угодно.
Полезности [83]
Рациональные предложения [26]
Конструирование [68]
СУБКУЛЬТУРЫ [9]
Деньги [10]
Заряди свой комп!!! [49]
Пробуждение ВоинА [39]
Радиолюбителям [75]
Работа с интернетом [14]
Говорун [2]
Энергетика Релейная защита [36]
Авто-мото [3]
Искусство [10]
AliExpress [17]
Видео архив [40]
Рецепты и секреты [0]

Поиск

Слушать

Радио онлайн

"Техстудент"

Наш опрос

Какое время года краше?
Всего ответов: 12

Мини-чат

500

Контроль

Партнёры

Воскресенье, 01.12.2024, 6:52:27
Приветствую Вас Интернет ПутниК
Главная | Регистрация | Вход | RSS

tehstudent.net

Журнал

Главная » Статьи » Полезности [ Добавить статью ]

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

Вкратце, Широтно Импульсная Модуляция (в буржуйской нотации этот режим зовется PWMPulse Width Modulation) это способ задания аналогового сигнала цифровым методом, то есть из цифрового выхода, дающего только нули и единицы получить какие то плавно меняющиеся величины. Звучит как бред, но тем не менее работает. А суть в чем:

Представь себе тяжеленный маховик который ты можешь вращать двигателем. Причем двигатель ты можешь либо включить, либо выключить. Если включить его постоянно, то маховик раскрутится до максимального значения и так и будет крутиться. Если выключить, то остановится за счет сил трения.

А вот если двигатель включать на десять секунд каждую минуту, то маховик раскрутится, но далеко не на полную скорость — большая инерция сгладит рывки от включающегося двигателя, а сопротивление от трения не даст ему крутится бесконечно долго.

Чем больше продолжительность включения двигателя в минуту, тем быстрей будет крутится маховик.
При ШИМ мы гоним на выход сигнал состоящий из высоких и низких уровней (применимо к нашей аналогии — включаем и выключаем двигатель), то есть нулей и единицы. А затем это все пропускается через интегрирующую цепочку (в аналогии — маховик). В результате интегрирования на выходе будет величина напряжения, равная площади под импульсами.

Меня скважность (отношение длительности периода к длительности импульса) можно плавно менять эту площадь, а значит и напряжение на выходе. Таким образом если на выходе сплошные 1, то на выходе будет напряжение высокого уровня, в случае моего робота, на выходе из моста L293 это 12 вольт, если нули, то ноль. А если 50% времени будет высокий уровень, а 50% низкий то 6 вольт. Интегрирующей цепочкой тут будет служить масса якоря двигателя, обладающего довольно большой инерцией.

А что будет если взять и гнать ШИМ сигнал не от нуля до максимума, а от минуса до плюса. Скажем от +12 до -12. А можно задавать переменный сигнал! Когда на входе ноль, то на выходе -12В, когда один, то +12В. Если скважность 50% то на выходе 0В. Если скважность менять по синусоидальному закону от максимума к минимуму, то получим… правильно! Переменное напряжение. А если взять три таких ШИМ генератора и гнать через них синусоиды сдвинутые на 120 градусов между собой, то получим самое обычное трехфазное напряжение, а значит привет бесколлекторные асинхронные и синхронные двигатели — фетиш всех авиамоделистов. На этом принципе построены все современные промышленные привода переменного тока. Всякие Unidrive и Omron Jxx

В качестве сглаживающей интегрирующей цепи в ШИМ может быть применена обычная RC цепочка:

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

Аппаратный ШИМ
В случае ATMega16 проще всего сделать на его ШИМ генераторе, который встроен в таймеры. Причем в первом таймере у нас целых два канала. Так что без особого напряга ATmega16 может реализовать одновременно четыре канала ШИМ.

Как это реализовано
У таймера есть особый регистр сравнения OCR**. Когда значение в счётном регистре таймера достигнает значения находящегося в регистре сравнения, то могут возникнуть следующие аппаратные события:

  • Прерывание по совпадению
  • Изменение состояния внешнего выхода сравнения OC**.

Выходы сравнения выведены наружу, на выводы микроконтроллера

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

Предположим, что мы настроили наш ШИМ генератор так, чтобы когда значение в счетном регистре больше чем в регистре сравнения, то на выходе у нас 1, а когда меньше, то 0.

Что при этом произойдет? Таймер будет считать как ему и положено, от нуля до 256, с частотой которую мы настроим битами предделителя таймера. После переполнения сбрасывается в 0 и продолжает заново.

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

Так что меняя значение в регистре сравнения можно менять скважность ШИМ сигнала. А если пропустить этот ШИМ сигнал через сглаживающую RC цепочку (интегратор) то получим аналоговый сигнал.

У таймера может быть сколько угодно регистров сравнения. Зависит от модели МК и типа таймера. Например, у Атмега16

  • Timer0 — один регистр сравнения
  • Timer1 — два регистра сравнения (16ти разрядных!)
  • Timer2 — один регистр сравнения

Итого — четыре канала. В новых AVR бывает и по три регистра сравнения на таймер, что позволяет одним МК организовать просто прорву независимых ШИМ каналов.

Самих режимов ШИМ существует несколько:

Fast PWM
В этом режиме счетчик считает от нуля до 255, после достижения переполнения сбрасывается в нуль и счет начинается снова. Когда значение в счетчике достигает значения регистра сравнения, то соответствующий ему вывод ОСхх сбрасыватся в ноль. При обнулении счетчика этот вывод устанавливается в 1. И все!

Частота получившегося ШИМ сигнала определяется просто: Частота процесора 8Мгц, таймер тикает до 256 с тактовой частотой. Значит один период ШИМ будет равен 8000 000/256 = 31250Гц. Вполне недурно. Быстрей не получится — это максимальная скорость на внутреннем 8Мгц тактовом генераторе. Но если переключить FUSE биты на внешний кварц то можно раскачать МК на 16Мгц.

Еще есть возможность повысить разрешение, сделав счет 8, 9, 10 разрядным (если разрядность таймера позволяет), но надо учитывать, что повышение разрядности, вместе с повышением дискретности выходного аналогового сигнала, резко снижает частоту ШИМ.

Phase Correct PWM
ШИМ с точной фазой. Работает похоже, но тут счетчик считает несколько по другому. Сначала от 0 до 255, потом от 255 до 0. Вывод OCxx при первом совпадении сбрасывается, при втором устанавливается.
Но частота ШИМ при этом падает вдвое, изза большего периода. Основное его предназначение, делать многофазные ШИМ сигналы, например, трехфазную синусоиду. Чтобы при изменении скважности не сбивался угол фазового сдвига между двумя ШИМ сигналами. Т.е. центры импульсов в разных каналах и на разной скважности будут совпадать.

Еще одна тонкость:
Чтобы не было кривых импульсов, то в регистр сравнения любое значение попадает через буфферный регистр и заносится только тогда, когда значение в счетчике достигнет максимума. Т.е. к началу нового периода ШИМ импульса.

Clear Timer On Compare
Сброс при сравнении. Это уже скорей ЧИМ — частотно-импульсно моделированный сигнал. Тут работает несколько иначе, чем при других режимах. Тут счетный таймер тикает не от 0 до предела, а от 0 до регистра сравнения! А после чего сбрасывается.

В результате, на выходе получаются импульсы всегда одинаковой скважности, но разной частоты. А чаще всего этот режим применяется когда надо таймером отсчитывать периоды (и генерить прерывание) с заданной точностью.

Например, надо нам прерывание каждую миллисекунду. И чтобы вот точно. Как это реализовать проще? Через Режим СТС! Пусть у нас частота 8Мгц.

Прескалер будет равен 64, таким образом, частота тиков таймера составит 125000 Гц. А нам надо прерывание с частотой 1000Гц. Поэтому настраиваем прерывание по совпадению с числом 125.

Дотикал до 125 — дал прерывание, обнулился. Дотикал до 125 — дал прерывание, обнулился. И так бесконечно, пока не выключим.

Вот вам и точная тикалка.

Нет, конечно, можно и вручную. Через переполнение, т.е. дотикал до переполнения, загрузил в обработчике прерывания заново нужные значение TCNTх=255-125, сделал нужные полезные дела и снова тикать до переполнения. Но ведь через СТС красивей! :)

Аппаратура
А теперь контрольные регистры, которыми все это безобразие задается и программируется. Опишу на примере Двухканального FastPWM на таймере 1. В других все похоже. Даташит в зубы и вперед.

Итак, тут правят бал регистры TCCR1A и TCCR1B. Гы, кто бы сомневался %)

Распишу их по битам.
Регистр TCCR1A, биты COM1A1:COM1A0 и COM1B1:COM1B0. Эта братия определяет поведение вывода сравнения OC1A и OC1B соответственно.

COMxx1COMxx0Режим работы выхода
00вывод отцеплен от регистра сравнения и не меняется никак.
01Поведение вывода зависит от режима заданного в WGM, различается для разных режимов (FastPWM, FC PWM, Compar out) и разных МК, надо сверяться с даташитом.
10прямой ШИМ (сброс при совпадении и установка при обнулении счета)
11обратный ШИМ (сброс при обнулении и установка при совпадении)

Регистр TCCR1A, биты WGM11 и WGM10 вместе с битами WGM12 и WGM13, находящимися в регистре TCCR1B задают режим работы генератора.

WGM13WGM12WGM11WGM10Режим работы
0101Fast PWM 8 бит
0110Fast PWM 9 бит
0111Fast PWM 10 бит

Другие комбинации битов WGM задают режимы Phase Correct PWM и CTC (сброс OCxx при совпадении). Если интересно, то читай даташит, я для себя много интересного там не нашел, кроме Phase Correct PWM. И то мне сейчас важней скорость, а не точность фазы :)

После остается только запустить таймер, установив бит CS10 (подсчет тактовых импульсов с делителем 1:1)

Пример кода:

Попробуем поиграться яркостью светодиодов с помощью ШИМ сигналов. Подключи джамперы, чтобы запитать светодиоды LED1 и LED2

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

1
2
3
4
5
6
7
8
9
10
11
12
;FastPWM Init
 SETB DDRD,4,R16 ; DDRD.4 = 1 Порты на выход
 SETB DDRD,5,R16 ; DDRD.5 = 1
 
; Выставляем для обоих каналов ШИМ режим вывода ОС** сброс при совпадении. 
; COM1A = 10 и COM1B = 10
; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает
; большую разрядность ШИМ сигнала. Вплоть до 10 бит. WGM = 0101
; Осталось только запустить таймер на частоте МК CS = 001
 
 OUTI TCCR1A,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10 
 OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10

Готово! Теперь ШИМ таймера1 генерит сигнал на выходаx OC1А и OC1B

Закинем в регистры сравнения первого и второго канала число 255/3=85 и 255/2 = 128
Так как ШИМ у нас 8ми разрядный, то заброс идет только в младший разряд. Старший же остается нулем. Но регистры сравнения тут у нас 16ти разрядные поэтому грузить надо оба байта сразу. Не забыв запретить прерывания (это важно!!! ибо атомарный доступ)

1
2
3
4
5
6
7
 CLI
 OUTI OCR1AH,0
 OUTI OCR1AL,85
 
 OUTI OCR1BH,0
 OUTI OCR1BL,128
 SEI

Поехали! :)

Прошиваем, тыкаемся в ноги микроконтроллера осциллографом — видим следующую картину по каналам:

Как мы и запланировали. С первого канала длительность импульса в 1/3 периода, а со второго в 1/2
Ну и светодиоды горят с разной яркостью. Один ярче, другой тусклей. Меняя значение в регистрах OCR*** мы можем менять скважность.

Давай сделаем так, чтобы светодиод плавно менял свою яркость от нуля до максимума. Как помнишь, у нас там была программа, с мигающем по таймеру0 светодиодом. Немного ее подправим, сделаем так, чтобы по таймеру не светодиод мигал, а менялось значение в регистрах сравнения OCR1A и OCR1B. Причем меняться оно будет в разные стороны :)

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
; Main =========================================================
Main: LDS R16,TCNT ; Грузим числа в регистры
 LDS R17,TCNT+1
 
 CPI R16,0x10 ; Сравниванем побайтно выдержку
 BRCS NoMatch
 CPI R17,0x01 ; Выдержку сделали поменьше = 0x0110
 BRCS NoMatch
 
; Если совпало то делаем экшн
Match: CLI ; Запрет прерываний, т.к. атомарный доступ
 
; Меняем первый канал
; Особенность 16ти разрядных регистров в том, что их надо правильно читать и записывать.
; Читают вначале младший, потом старший байты. Так надо, чтобы младший не успел измениться
; (он ведь может тикать по таймеру) пока читают первым старший. Укладывают их в обратном
; порядке. Сначала старший, потом младший. Правда для регистров OCR это не имеет большой 
; разницы -- они статичные, а вот для TCNT очень даже!
 
 IN R16,OCR1AL ; Достали первый байт сравнения
 IN R17,OCR1AH ; он 16ти разрядный, но старший байт будет 0
 
 INC R16 ; Увеличили
 
 OUT OCR1AH,R17 ; И сунули их обратно
 OUT OCR1AL,R16
 
; Меняем второй канал
 IN R16,OCR1BL ; Достали второй байт сравнения
 IN R17,OCR1BH ; он 16ти разрядный, но старший байт будет 0
 
 DEC R16 ; Уменьшили
 
 OUT OCR1BH,R17 ; И сунули их обратно
 OUT OCR1BL,R16 
 SEI ; Конец атомарного доступа
 
; Теперь надо обнулить счетчик, иначе за эту же итерацию главного цикла
; Мы сюда попадем еще не один раз -- таймер то не успеет натикать 255 значений
; чтобы число в первых двух байтах счетчика изменилось. 
 
 CLR R16 ; Нам нужен ноль
 CLI ; Таймер меняется и в прерывании. Нужен
 ; атомарный доступ. Запрещаем прерывания
 OUT TCNT0,R16 ; Ноль в счетный регистр таймера
 STS TCNT,R16 ; Ноль в первый байт счетчика в RAM
 STS TCNT+1,R16 ; Ноль в второй байт счетчика в RAM
 STS TCNT+2,R16 ; Ноль в третий байт счетчика в RAM
 STS TCNT+3,R16 ; Ноль в первый байт счетчика в RAM
 SEI ; Разрешаем прерывания. 
; Не совпало - не делаем :) 
NoMatch: NOP
 
 INCM CCNT ; Шарманка вращается дальше, вхолостую
 JMP Main

А теперь давайте включим режим с точной фазой (WGM = 0001) и посмотрим на то как будет меняться скважность.

1
2
 OUTI TCCR1A,2<<COM1A0|2<<COM1B0|0<<WGM11|1<<WGM10 
 OUTI TCCR1B,0<<WGM13|0<<WGM12|1<<CS10

ШИМ на прерываниях.
Но вот засада — плата уже разведена, захотелось ШИМ, а выводы OCxx уже задействованы под другие цели.

Ничего страшного, малой кровью можно это исправить. Также запускаем ШИМ, только:

  • Отключаем выводы OCxx от регистра сравнения.
  • Добавляем два обработчика прерывания на сравнение и на переполнение. В прерывании по сравнению сбрасываем нужный бит, в прерывании по переполнению счетчика устанавливаем.

Все просто :)

Пример:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
;FastPWM Init на прерываниях
 
; ШИМ будет на выводах 3 и 6 порта D
 SETB DDRD,3,R16 ; DDRD.3 = 1 Порты на выход
 SETB DDRD,6,R16 ; DDRD.6 = 1
 
; Выставляем для обоих каналов ШИМ режим вывода ОС** выключеным. 
; COM1A = 00 и COM1B = 00
; Также ставим режим FAST PWM 8bit (таймер 16ти разрядный и допускает
; большую разрядность ШИМ сигнала. Вплоть до 10 бит. WGM = 0101
; Осталось только запустить таймер на частоте МК CS = 001
 
 OUTI TCCR1A,0<<COM1A0|0<<COM1B0|0<<WGM11|1<<WGM10 
 OUTI TCCR1B,0<<WGM13|1<<WGM12|1<<CS10 
 
 SETB TIMSK,OCIE1A,R16 ; Включаем прерывание по сравнению А
 SETB TIMSK,OCIE1B,R16 ; Включаем прерывание по сравнению Б
 SETB TIMSK,TOIE1,R16 ; Включаем прерывание по переполнению Т1
 ; Причем в режиме WGM=1010 переполнение
 ; будет на FF т.е. таймер работает как
 ; 8ми разрядный.

Осталось только прописать обработчики и вектора:

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
 .CSEG
 .ORG $000 ; (RESET) 
 RJMP Reset
 .ORG $002
 RETI ; (INT0) External Interrupt Request 0
 .ORG $004
 RETI ; (INT1) External Interrupt Request 1
 .ORG $006
 RETI ; (TIMER2 COMP) Timer/Counter2 Compare Match
 .ORG $008
 RETI ; (TIMER2 OVF) Timer/Counter2 Overflow
 .ORG $00A
 RETI ; (TIMER1 CAPT) Timer/Counter1 Capture Event
 .ORG $00C 
 RJMP Timer1_OCA ; (TIMER1 COMPA) Timer/Counter1 Compare Match A
 .ORG $00E
 RJMP Timer1_OCB ; (TIMER1 COMPB) Timer/Counter1 Compare Match B
 .ORG $010
 RJMP Timer1_OVF ; (TIMER1 OVF) Timer/Counter1 Overflow
 .ORG $012
 RJMP Timer0_OV ; (TIMER0 OVF) Timer/Counter0 Overflow
 .ORG $014
 RETI ; (SPI,STC) Serial Transfer Complete
 .ORG $016
 RETI ; (USART,RXC) USART, Rx Complete
 .ORG $018
 RETI ; (USART,UDRE) USART Data Register Empty
 .ORG $01A
 RETI ; (USART,TXC) USART, Tx Complete
 .ORG $01C
 RETI ; (ADC) ADC Conversion Complete
 .ORG $01E
 RETI ; (EE_RDY) EEPROM Ready
 .ORG $020
 RETI ; (ANA_COMP) Analog Comparator
 .ORG $022
 RETI ; (TWI) 2-wire Serial Interface
 .ORG $024
 RETI ; (INT2) External Interrupt Request 2
 .ORG $026
 RETI ; (TIMER0 COMP) Timer/Counter0 Compare Match
 .ORG $028
 RETI ; (SPM_RDY) Store Program Memory Ready
 
 .ORG INT_VECTORS_SIZE ; Конец таблицы прерываний
 
; Interrupts ==============================================
Timer0_OV: PUSHF
 PUSH R17
 PUSH R18
 PUSH R19
 
 INCM TCNT
 
 POP R19
 POP R18
 POP R17
 POPF
 
 RETI
 
; Вот наши обработчики на ШИМ
Timer1_OCA: SBI PORTD,3
 RETI
 
Timer1_OCB: SBI PORTD,6
 RETI
 
Timer1_OVF: CBI PORTD,3
 CBI PORTD,6
 RETI
; End Interrupts ==========================================

Почему я в этих обработчиках не сохраняю регистры и SREG? А незачем! Команды SBI меняют только конкретные биты (а больше нам и не надо), не влияя на флаги и другие регистры.

Запустили…

И получили полную херню. Т.е. ШИМ как бы есть, но почему то адово мерцает. А на осциллографе в этот момент полный треш. Кто виноват? Видимо конфликт прерываний. Осталось только выяснить где именно. Сейчас я вам дам практический пример реалтаймовой отладки :)

Итак, что мы имеем:

ШИМ, как таковой, работает. Скважность меняется. Значит наш алгоритм верен.
Но длительности скачут. Почему? Видимо потому, что что-то мешает им встать вовремя. Когда у нас возникают фронты? Правильно — по прерываниям. А прерывания по таймерам. Т.е. врать не должны. Однако так получается. Давайте узнаем каком месте у нас конфликт.

Первым делом надо добавить в код обработчика отладочную инфу. Будем в обработчике прерываний инвертировать бит. Пусть это будет PD7 — зашли в обработчик, инверснули. Зашли — инверснули. В результате, у нас на выходе этого бита будет прямоугольный сигнал, где каждый фронт — сработка прерываний. Послужит нам как линейка, отмеряющая время.

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
29
30
31
32
33
; Interrupts ==============================================
Timer0_OV: PUSHF
 PUSH R17
 PUSH R18
 PUSH R19
 
 INCM TCNT
 
 POP R19
 POP R18
 POP R17
 POPF
 
 RETI
 
; Установка бита ШИМ канала А
Timer1_OCA: SBI PORTD,3
 RETI
 
; Установка бита ШИМ канала Б
Timer1_OCB: SBI PORTD,6
 RETI
 
;Сброс бита ШИМ канала А и Б
Timer1_OVF: CBI PORTD,3
 CBI PORTD,6
 
;DEBUG PIN BEGIN ---------------
 PUSHF
 INVBM PORTD,7 
 POPF
;DEBUG PIN END -----------------
 RETI

Инверсия бита невозможна без логических операций, поэтому надо сохранять флаги.

Из картинки стало понятно, что у нас накрывается прерывание по сравнению. Давайте попробуем посмотреть с какими прерыванием происходит конфликт. Особых вариантов у нас нет — прерываний у нас тут четрые. А наиболее очевиден конфликт Timer0_OV vs Timer1_OCA vs Timer1_OCB.

OCA и OCB конфликтуют только тогда, когда счетные регистры у них сравниваются — вызов происходит почти одновременно, но сами обработчики короткие — всего несколько тактов, поэтому дребезг не столь сильный.

А вот Timer0_OV делает довольно мощный прогруз стека и еще вычитает четырехбайтную переменную. Т.е. тактов на 20 может задержать обработчик установки бита Timer1_OC* от того и вылазят такие зверские дребезги.

Давайте проверим эту идею. Разрешим прерывания в обработчике Timer0_0V

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
; Interrupts ==============================================
Timer0_OV: SEI
 PUSHF
 PUSH R17
 PUSH R18
 PUSH R19
 
 INCM TCNT
 
 POP R19
 POP R18
 POP R17
 POPF
 
 RETI
 
; Установка бита ШИМ канала А
Timer1_OCA: SBI PORTD,3
 RETI
 
; Установка бита ШИМ канала Б
Timer1_OCB: SBI PORTD,6
 RETI
 
;Сброс бита ШИМ канала А и Б
Timer1_OVF: CBI PORTD,3
 CBI PORTD,6
 RETI

Картина сразу исправилась. Теперь более важное (для нас важное) прерывание задвигает обработчик от Таймера 0. Но тут надо просекать возможные риски:

  • Более глубокий прогруз стека
  • Нарушается атомарный доступ к четырехбайтной переменной TCNT, поэтому если бы у нас было еще какое-то прерывание, меняющее TCNT то его надо было бы запрещать локально. Иначе бы мы получили такой трешняк, что проще заново прогу переписать, чем это отладить

.

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

Исходный код...скачать




Источник: http://easyelectronics.ru
Категория: Полезности | Добавил: snettens (22.02.2012)
Просмотров: 7258 | Теги: Широтно Импульсная Модуляция | Рейтинг: 0.0/0
Всего комментариев: 0
Имя *:
Email *:
Код *: