Домой / Социальные сети / Реализация шим с помощью прерывания. Программная ШИМ (PWM). Программная реализация ШИМ

Реализация шим с помощью прерывания. Программная ШИМ (PWM). Программная реализация ШИМ

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

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

Цифровые устройства, как микроконтроллер может генерировать только два уровня на выходных линиях, высокий = 5В и низкий = 0В. Но что, если мы хотим получить 2,5 или 3,1 или любое напряжение в пределах 0-5В? Для этого, вместо создания постоянного напряжения постоянного тока на выходе мы будем генерировать меандр, который имеет высокий = 5В и низкий = 0V уровни (см. рисунок 1).

Рис.1

Из рисунка видно что сигнал на некоторое время остается поочередно на низком и высоком уровне. Т0 - низкий уровень, Т1 - высокий уровень. Период сигнала будет равен Т = Т0+Т1 . Период импульсов - это промежуток времени, между двумя характерными точками двух соседних импульсов. Обычно период измеряют между двух фронтов или двух спадов соседних импульсов и обозначают заглавной латинской буквой T.

Период следования импульсов напрямую связан с частотой импульсной последовательности, и его можно вычислить по формуле: Т = 1/F

Если длина импульса T1 точно равна половине периода T, то такой сигнал часто называют "меандр".

Скважностью импульсов называется отношение периода следования импульсов к их длительности и обозначается буквой S: S = T/T1

Скважность - безразмерная величина и не имеет единиц измерения, но может быть выражена в процентах. Часто в англоязычных текстах встречается термин Duty cycle , это так называемый коэффициент заполнения или величина рабочего цикла ШИМ. Коэффициент заполнения D является величиной, обратной скважности.

Коэффициент заполнения обычно выражается в процентах и вычисляется по формуле: D=1/S или так D = T1/T*100%

На рисунке выше (рис. 1) можно увидеть, что T1 = T0, это равно половине периода времени. Так величина рабочего цикла ШИМ составляет 50%. Если частота таких импульсов достаточно велика (скажем, 5000 Гц), то мы получаем половину от 5В т.е. 2,5В. Таким образом, если выход контроллера связан с двигателем (с помощью соответствующих драйверов) он будет работать на 50% его полной скорости. Техника ШИМ использует этот факт для создания любого напряжения между двумя уровнями (например, между 0-12В). Весь фокус в том,что при изменении величины рабочего цикла между 0-100% получаем тот же процент входного напряжения на выходе. Ниже приведены некоторые примеры ШИМ сигнала различной скважности.

Если на выходе поставить R/С фильтр, то можно получить чистый DC уровень сигнала, а не квадратные волны. Но это не требуется для коллекторных двигателей или для управления яркостью светодиодов. Для этого можно подавать ШИМ сигнал непосредственно на драйвер (например, биполярный транзистор, MOSFET и т.д.).


Под режимом работы 16-разр. таймера понимается его алгоритм счета и поведение связанного с ним выхода формирователя импульсов, что определяется комбинацией бит, задающих режим работы таймера (WGMn3-0) и режим формирования выходного сигнала (COMnx1:0). При этом биты задания режима формирования выходного сигнала не влияют на алгоритм счета, т.к. алгоритм счета зависит только от состояния бит задания режима работы таймера. В режимах с ШИМ биты COMnx1:0 позволяют включить/отключить инверсию на генерируемом ШИМ-выходе (т.е. выбрать ШИМ с инверсией или ШИМ без инверсии). Для режимов без ШИМ биты COMnx1:0 определяют, какое действие необходимо выполнить при возникновении совпадения: сбросить, установить или инвертировать выход (см. также “Блок формирования выходного сигнала” и "Временные диаграммы 16-разр. таймеров-счетчиков").

Нормальный режим работы

Самым простым режимом работы является нормальный режим (WGMn3-0 = 0b0000). В данном режиме счетчик работает как суммирующий (инкрементирующий), при этом сброс счетчика не выполняется. Переполнение счетчика происходит при переходе через максимальное 16-разр. значение (0xFFFF) к нижнему пределу счета (0x0000). В нормальном режиме работы флаг переполнения таймера-счетчика TOVn будет установлен на том же такте синхронизации, когда TCNTn примет нулевое значение.

Фактически, флаг переполнения TOVn является 17-ым битом таймера-счетчика за тем исключением, что он только устанавливается и не сбрасывается. Однако программно это свойство может быть использовано для повышения разрешающей способности таймера, если использовать прерывание по переполнению таймера, при возникновении которого флаг TOVn сбрасывается автоматически. Для нормального режима работы не существует каких-либо особых ситуаций, поэтому запись нового состояния счетчика может быть выполнена в любой момент.

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

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

Режим сброса таймера при совпадении (СТС)

В режиме СТС (WGM01, WGM00 =0b10) регистр OCR0 используется для задания разрешающей способности счетчика. Если задан режим CTC и значение счетчика (TCNT0) совпадает со значением регистра OCR0, то счетчик обнуляется (TCNT0=0). Таким образом, OCR0 задает вершину счета счетчика, а, следовательно, и его разрешающую способность. В данном режиме обеспечивается более широкий диапазон регулировки частоты генерируемых прямоугольных импульсов. Он также упрощает работу счетчика внешних событий.

В режиме сброса таймера при совпадении (WGMn3-0 = 0b0100 или 0b1100) разрешающая способность таймера задается регистрами OCRnA или ICRn. В режиме СТС происходит сброс счетчика (TCNTn), если его значение совпадает со значением регистра OCRnA (WGMn3-0 = 0b0100) или с ICRn (WGMn3-0 = 0b1100). Значение регистра OCRnA или ICRn определяет верхний предел счета, а, следовательно, и разрешающую способность таймера. В данном режиме обеспечивается более широкий диапазон регулировки частоты генерируемых прямоугольных импульсов. Он также упрощает работу счетчика внешних событий. Временная диаграмма работы таймера в режиме СТС показана на рисунке 1. Счетчик (TCNTn) инкрементирует свое состояние до тех пор, пока не возникнет совпадение со значением OCRnA или ICRn, а затем счетчик (TCNTn) сбрасывается.

Рисунок 1 – Временная диаграмма для режима СТС

По достижении верхнего предела счета может генерироваться прерывание с помощью флагов OCFnA или ICFn, соответствующим используемым регистрам для задания верхнего предела счета. Если прерывание разрешено, то процедура обработки прерывания может использоваться для обновления верхнего предела счета. Однако, задание значения вершины счета близкого к значению нижнего предела счета, когда счетчик работает без предделения или с малым значением предделения, необходимо выполнять с особой осторожностью, т.к. в режиме СТС нет двойной буферизации. Если значение, записанное в OCRnA или ICRn, меньше текущего значения TCNTn, то сброс счетчика по условию совпадения наступит, когда он достигнет максимального значения (0xFFFF), затем перейдет в исходное состояние 0x0000 и достигнет нового значения OCRnA или ICRn. Во многих случаях возникновение такой ситуации не желательно. В качестве альтернативы может выступить режим быстрой ШИМ, где регистр OCRnA определяет верхний предел счета (WGMn3-0 = 0b1111), т.к. в этом случае OCRnA имеет двойную буферизацию.

Для генерации сигнала в режиме CTC выход OCnA может использоваться для изменения логического уровня при каждом совпадении, для чего необходимо задать режим переключения (COMnA1, COMnA0 = 0b01). Значение OCnA будет присутствовать на выводе порта, только если для данного вывода задано выходное направление. Максимальная частота генерируемого сигнала равна fOC0 = fclk_I/O/2, если OCRnA = 0x0000. Для других значений OCRn частоту генерируемого сигнала можно определить по формуле:

где переменная N задает коэффициент деления предделителя (1, 8, 32, 64, 128, 256 или 1024).

Также как и для нормального режима работы, флаг TOV0 устанавливается на том же такте таймера, когда его значение изменяется с 0xFFFF на 0x0000.

Режим быстрой ШИМ (FAST PWM)

Режим быстрой широтно-импульсной модуляции (ШИМ) (WGMn3-0 = 0b0101, 0b0110, 0b0111, 0b1110, 0b1111) предназначен для генерации ШИМ-импульсов повышенной частоты. В отличие от других режимов работы в этом используется однонаправленная работа счетчика. Счет выполняется в направлении от нижнего к верхнему пределу счета.

Если задан неинвертирующий режим выхода, то при совпадении TCNTn и OCRnx сигнал OCnx устанавливается, а на верхнем пределе счета сбрасывается. Если задан инвертирующий режим, то выход OCnx сбрасывается при совпадении и устанавливается на верхнем пределе счета. За счет однонаправленности счета, рабочая частота для данного режима в два раза выше по сравнению с режимом ШИМ с фазовой коррекцией, где используется двунаправленный счет. Возможность генерации высокочастотных ШИМ сигналов делает использование данного режима полезным в задачах стабилизации питания, выпрямления и цифро-аналогового преобразования. Высокая частота, при этом, позволяет использовать внешние элементы физически малых размеров (индуктивности, конденсаторы), тем самым снижая общую стоимость системы.

Разрешающая способность ШИМ может быть фиксированной 8, 9 или 10 разрядов или задаваться регистром ICRn или OCRnA, но не менее 2 разрядов (ICRn или OCRnA = 0x0003) и не более 16 разрядов (ICRn или OCRnA = 0xFFFF). Разрешающая способность ШИМ при заданном значении верхнего предела (ВП) вычисляется следующим образом:

В режиме быстрой ШИМ счетчик инкрементируется до совпадения его значения с одним из фиксированных значений 0x00FF, 0x01FF или 0x03FF (если WGMn3:0 = 0b0101, 0b0110 или 0b0111, соответственно), значением в ICRn (если WGMn3:0 = 0b1110) или значением в OCRnA (если WGMn3:0 = 0b1111), а затем сбрасывается следующим тактом синхронизации таймера. Временная диаграмма для режима быстрой ШИМ представлена на рисунке 2. На рисунке показан режим быстрой ШИМ, когда для задания верхнего предела используется регистр OCRnA или ICRn. Значение TCNTn на временной диаграмме показано в виде графика функции для иллюстрации однонаправленности счета. На диаграмме показаны как инвертированный, так и неинвертированный ШИМ-выходы. Короткой горизонтальной линией показаны точки на графике TCNTn, где совпадают значения OCRnx и TCNTnx. Флаг прерывания OCnx устанавливается при возникновении совпадении.

Рисунок 2 – Временная диаграмма для режима быстрой ШИМ

Флаг переполнения таймера-счетчика (TOVn) устанавливается всякий раз, когда счетчик достигает верхнего предела. Дополнительно тем же тактовым импульсом вместе с флагом TOVn могут установиться флаги OCnA или ICFn, если для задания верхнего предела используется регистр OCRnA или ICRn, соответственно. Если одно из этих прерываний разрешено, то в процедуре обработки прерывания может быть выполнено обновление верхнего предела счета и порогов сравнения.

Если изменяется значение верхнего предела счета, то необходимо соблюдение условия, чтобы записываемое новое значение верхнего предела было больше или равно значений во всех регистрах порога сравнения. В противном случае совпадение между TCNTn и OCRnx никогда не возникнет. Обратите внимание, что при использовании фиксированных значений верхнего предела во время записи в регистры OCRnx происходит маскирование к 0 неиспользуемых разрядов.

Механизм модификации регистра ICRn отличается от OCRnA в том случае, если он используется для задания верхнего предела. Регистр ICRn не имеет двойной буферизации. Это означает, что если в ICRn записывается малое значение во время работы счетчика с малым предделением или без него, то имеется опасность записи в регистр ICRn значения, которое окажется меньше текущего значения TCNTn. Как результат, в такой ситуации будет пропущено совпадение на вершине счета. В этом случае счетчик дойдет до максимального значения (0xFFFF), перезапустится со значения 0x0000, а только затем возникнет совпадение. Регистр OCRnA содержит схему двойной буферизации, поэтому, его можно модифицировать в любой момент времени.

class="eliadunit">

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

Рекомендуется использовать регистр ICRn для задания верхнего предела, если верхний предел счета является константой. В этом случае также освобождается регистр OCRnA для генерации ШИМ-сигнала на выходе OCnA. Однако, если частота ШИМ динамически изменяется (за счет изменения верхнего предела), то в этом случае выгоднее использовать регистр OCRnA для задания верхнего предела, т.к. он поддерживает двойную буферизацию.

В режиме быстрой ШИМ блоки сравнения позволяют генерировать ШИМ-сигналы на выводах OCnx. Если COMnx1:0 =0b10, то задается ШИМ без инверсии выхода, а если COMnx1:0 = 0b11, то задается режим ШИМ с инверсией на выходе (см. таблицу 59). Фактическое значение OCnx можно наблюдать на выводе порта, если для него задано выходное направление (DDR_OCnx). ШИМ-сигнал генерируется путем установки (сброса) регистра OCnx при возникновении совпадения между OCRnx и TCNTn, а также путем сброса (установки) регистра OCnx вместе со сбросом счетчика (переход с верхнего предела на нижний предел).

Частота ШИМ выходного сигнала для заданного значения верхнего предела (ВП) определяется выражением:

где N – переменная, которая задает значение коэффициента предделения (1, 8, 32, 64, 128, 256 или 1024).

Запись предельных значений в регистр OCRnx связана с особыми случаями в генерации ШИМ-импульсов. Если OCRnx установить равным нижнему пределу (0x0000), то на выходе будет возникать короткий импульс каждый (ВП+1)-ый такт синхронизации таймера. Запись в OCRnx значения равного верхнему пределу приведет к установке постоянного уровня лог. 1 или 0 на выходе (зависит от выбранной с помощью бит COMnx1:0 полярности выходного сигнала).

Если требуется генерация меандра (прямоугольные импульсы со скважностью 2 или заполнением 50%) высокой частоты, то необходимо использовать режим быстрой ШИМ с установкой бит COMnA1:0 = 0b01, которая вызывает переключение (инвертирование) логического уровня на выходе OCnA при каждом совпадении. Данное применимо, только если OCRnA используется для задания верхнего предела (WGMn3-0 =0b1111). Максимальная генерируемая частота меандра в этом случае fOCnA = fclk_I/O/2, если OCRnA =0x0000. Данная особенность аналогична переключению OCnA в режиме СТС за исключением двойной буферизации, которая имеется в режиме быстрой ШИМ.

Режим широтно-импульсной модуляции с фазовой коррекцией (Phase Correct)

Режим широтно-импульсной модуляции с фазовой коррекцией (ШИМ ФК) (WGMn3-0 = 0b0001, 0b010, 0b0011, 0b1010 или 0b1011) предназначен для генерации ШИМ сигнала с фазовой коррекцией и высокой разрешающей способностью. Режим ШИМ ФК основан на двунаправленной работе таймера-счетчика. Счетчик циклически выполняет счет в направлении от нижнего предела (0x0000) до верхнего предела, а затем обратно от верхнего предела к нижнему пределу. Если задан неинвертирующий режим выхода формирователя импульсов, то выход OCnx сбрасывается/устанавливается при совпадении значений TCNTn и OCRnx во время прямого/обратного счета. Если задан инвертирующий режим выхода, то, наоборот, во время прямого счета происходит установка, а во время обратного – сброс выхода OCnx. При двунаправленной работе максимальная частота ШИМ-сигнала меньше, чем при однонаправленной работе, однако, за счет такой особенности, как симметричность в режимах ШИМ с двунаправленной работой, данные режимы предпочитают использовать при решении задач управления приводами.

Разрешающая способность ШИМ в данном режиме может быть либо фиксированной (8, 9 или 10 разрядов) либо задаваться с помощью регистра ICRn или OCRnA. Минимальная разрешающая способность равна 2-м разрядам (ICRn или OCRnA = 0x0003), а максимальная -16-ти разрядам (ICRn или OCRnA =0xFFFF). Если задан верхний предел, то разрешающая способность ШИМ в данном режиме определяется следующим образом:

В режиме ШИМ ФК счетчик инкрементируется пока не достигнет одного из фиксированных значений 0x00FF, 0x01FF или 0x03FF (соответственно для WGMn3-0 = 0b0001, 0b0010 или 0b0011), а также значения равного ICRn (если WGMn3-0 = 0b1010) или OCRnA (если WGMn3:0 = 0b1011). Далее, при достижении верхнего предела, счетчик изменяет направление счета. Значение TCNTn остается равным верхнему пределу в течение одного такта синхронизации таймера. Временная диаграмма для режима ШИМ ФК представлена на рисунке 3. На рисунке показан режим ШИМ ФК с использованием регистра OCRnA или ICRn для задания верхнего предела. Состояние TCNTn представлено в виде графика функции для иллюстрации двунаправленности счета. На рисунке представлены, как неинвертированный, так и инвертированный ШИМ-выход. Короткие горизонтальные линии указывают точки на графике изменения TCNTn, где возникает совпадение со значением OCRnx. Флаг прерывания OCnx устанавливается при возникновении совпадения.

Рисунок 3 – Временная диаграмма для режима ШИМ ФК

Флаг переполнения таймера-счетчика (TOVn) устанавливается всякий раз, когда счетчик достигает нижнего предела. Если для задания верхнего предела используется регистр OCRnA или ICRn, то, соответственно устанавливается флаг OCnA или ICFn тем же тактовым импульсом, на котором произошло обновление регистра OCRnx из буферного регистра (на вершине счета). Флаги прерывания могут использоваться для генерации прерывания по достижении счетчиком нижнего или верхнего предела.

При изменении значения верхнего предела счета необходимо следить, чтобы оно было больше или равно значениям во всех регистрах сравнения. В противном случае совпадение между TCNTn и OCRnx никогда не возникнет. Обратите внимание, что при использовании фиксированных значений верхнего предела счета во время записи в регистры OCRnx неиспользуемые разряды обнуляются. Третий период на рисунке 53 иллюстрирует случай, когда динамическое изменение верхнего предела счета приводит к генерации несимметричного импульса. Данная особенность основывается на времени обновления регистра OCRnx. Поскольку, обновление OCRnx возникает на вершине счета, то и период ШИМ начинается и заканчивается на вершине счета. Это подразумевает, что длительность обратного счета определяется предыдущим значением верхнего предела, а прямого – новым значением верхнего предела. Если два этих значения разные, то и длительность прямого и обратного счета будет также отличаться. Различие в длительности приводит несимметричности выходных импульсов.

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

В режиме ШИМ ФК блоки сравнения позволяют генерировать ШИМ-сигналы на выводах OCnx. Если установить COMnx1:0 = 0b10, то выход ШИМ будет без инверсии, а если COMnx1:0=0b11, то с инверсией. Фактическое значение OCnx можно наблюдать на выводе порта, если в регистре направления данных для данного вывода порта задано выходное направление (DDR_OCnx). ШИМ-сигнал генерируется путем установки (сброса) регистра OCnx при совпадении значений OCRnx и TCNTn во время прямого счета, а также путем сброса (установки) регистра OCnx при совпадении между OCRnx и TCNTn во время обратного счета. Результирующая частота ШИМ-сигнала в режиме ШИМ ФК при заданном верхнем пределе (ВП) может быть вычислена по следующему выражению:

Запись предельных значений в регистр OCRnx связано с особыми случаями в генерации ШИМ-сигналов в режиме ШИМ ФК. Если задать режим ШИМ без инверсии и OCRnx установить равным нижнему пределу, то на выходе непрерывно будет установлен лог. 0, а если равным верхнему пределу, то на выходе постоянно присутствует лог. 1. Для ШИМ с инверсией указанные уровни необходимо заменить противоположными.

Если задать использование OCnA в качестве верхнего предела (WGMn3:0 = 0b1011) и установить COMnA1:0 =0b01, то на выходе OCnA будет генерироваться меандр.

Режим широтно-импульсной модуляции с фазовой и частотной коррекцией (Phase and Frequency Correct)

Режим широтно-импульсной модуляции с фазовой и частотной коррекцией (ШИМ ФЧК) (WGMn3-0 = 0b1000 или 0b1001) предназначен для генерации ШИМ-импульсов высокой разрешающей способности с фазовой и частотной коррекцией. Также как и режим ШИМ ФК режим ШИМ ФЧК основан на двунаправленной работе счетчика. Счетчик циклически считает от нижнего предела (0x0000) до верхнего предела, а затем обратно от верхнего предела к нижнему пределу. Если задан неинвертирующий режим ШИМ, то выход OCnx сбрасывается, если возникает совпадение между TCNTn и OCRnx во время прямого счета, и устанавливается, если возникает совпадение во время обратного счета. В инвертирующем режиме работа инверсная. Двунаправленная работа, по сравнению с однонаправленной, связана с генерацией более низких частот. Однако, благодаря симметричности в режимах ШИМ с двунаправленным счетом, их применение предпочтительно в задачах управления приводами.

Основное отличие между режимами ШИМ ФК и ШИМ ФЧК состоит в моменте обновления регистра OCRnx из буферного регистра OCRnx (см. рисунок 3 и рисунок 4).

Разрешающая способность ШИМ в этом режиме может задаваться с помощью регистра ICRn или OCRnA. Минимальная разрешающая способность равна 2-ум разрядам (ICRn или OCRnA = 0x0003), а максимальная разрешающая способность - 16-ти разрядам (ICRn или OCRnA = 0xFFFF). Разрешающая способность ШИМ в разрядах может быть вычислена по следующему выражению:

В режиме ШИМ ФЧК счетчик инкрементируется до совпадения со значением в ICRn (WGMn3:0 = 0b1000) или в OCRnA (WGMn3:0 = 0b1001). Это означает достижение вершины счета, после чего происходит изменение направления счета. Значение TCNTn остается равным вершине счета в течение одного такта синхронизации таймера. Временная диаграмма для режима ШИМ ФЧК показана на рисунке 54. На рисунке показан режим ШИМ ФЧК, когда вершину счета задает регистр OCRnA или ICRn. Значение TCNTn показано в виде графика функции для иллюстрации двунаправленности счета. На диаграмме показан как неинвертирующий, так и инвертирующий ШИМ выходы. Короткие горизонтальные линии указывают на точки график TCNTn, где возникает совпадение между OCRnx и TCNTn. Флаг прерывания OCnx устанавливается после возникновения совпадения.

Рисунок 4 – Временная диаграмма режима ШИМ с фазовой и частотной коррекцией

Флаг переполнения таймера-счетчика (TOVn) устанавливается тем же тактом, когда произошло обновление регистров значением из буферного регистра (на нижнем пределе счета). Если для задания верхнего предела используется регистр OCRnA или ICRn, то по достижении счетчиком верхнего предела устанавливается флаг OCnA или ICFn, соответственно. Флаги прерывания могут использоваться для генерации прерывания при достижении счетчиком верхнего или нижнего предела.

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

На рисунке 4 показано, что в отличие от режима ШИМ ФК, генерируемый выходной сигнал симметричен на всех периодах. Поскольку, регистры OCRnx обновляются на нижнем пределе счета, то длительности прямого и обратного счетов всегда равны. В результате выходные импульсы имеют симметричную форму, а, следовательно, и откорректированную частоту.

Использование регистра ICRn для задания верхнего предела рекомендуется, если значение верхнего предела является константой. В этом случае также освобождается регистр OCRnA для широтно-импульсной модуляции импульсов на выводе OCnA. Однако если требуется динамическое изменение частоты ШИМ за счет изменения верхнего предела, то для задания верхнего предела рекомендуется использовать регистр OCRnA за счет наличия у него двойной буферизации.

В режиме ШИМ ФЧК блоки сравнения позволяют генерировать ШИМ-импульсы на выводе OCnx. Если COMnx1:0 = 0b10, то задается неинвертирующий ШИМ выход, а, если COMnx1:0=0b11, то инвертирующий (см. таблицу 60). Значение OCnx будет присутствовать на соответствующем выводе порта только в случае, если для него задано выходное направление. ШИМ сигнал генерируется путем установки (сброса) регистра OCnx при совпадении между OCRnx и TCNTn во время прямого счета и сброса (установки) регистра OCnx при совпадении между OCRnx и TCNTn во время обратного счета. Частота ШИМ в данном режиме при заданном верхнем пределе (ВП) счета определяется следующим образом:

где N – коэффициент деления предделителя (1, 8, 32, 64, 128, 256 или 1024).

Запись предельных значений в регистр OCRnx связана с особыми случаями в генерации ШИМ-сигналов в данном режиме. Если задать OCRnx равным нижнему пределу (0x0000), то в неинвертирующем режиме на выходе будет постоянного присутствовать низкий логический уровень, а при записи значения равного верхнему пределу на выходе будет длительно присутствовать высокий логический уровень. В инвертирующем режиме приведенные уровни будут противоположными.

Если OCRnA используется для задания верхнего предела (WGMn3:0 = 0b1001) и COMnA1:0 = 0b01, то на выходе OCnA будет генерироваться меандр.


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

Описание флагов прерываний

T1 может генерировать прерывание при наступлении:

  1. переполнения счетного регистра TCNT1;
  2. при равенстве счетного регистра TCNT1 и регистра сравнения OCR1A и OCR1B (по отдельности для каждого регистра);
  3. при сохранении счетного регистра в регистре захвата ICR1.

T2 может генерировать прерывание при наступлении:

  1. переполнения счетного регистра TCNT2;
  2. при равенстве счетного регистра TCNT2 и регистра сравнения OCR2.

Флаги всех прерываний находится в регистре TIFR,а разрешение/запрещение прерываний в регистре TIMSK.

Разряды регистра TIMSK
Регистр 7 6 5 4 3 2 1 0
TIMSK OCIE2 TOIE2 TICIE1 OCIE1A OCIE1B TOIE1 OCIE0* TOIE0
  • OCIE2 - Флаг разрешения прерывания по событию "совпадение" таймера/счетчика Т2
  • TOIE2 - Флаг разрешения прерывания по переполнению таймера/счетчика Т2
  • TICIE1 - Флаг разрешения прерывания по событию "захват" таймера/счетчика Т1
  • OCIE1A - Флаг разрешения прерывания по событию "совпадение А" таймера/счетчика Т1
  • OCIE1B - Флаг разрешения прерывания по событию "совпадение В" таймера/счетчика Т1
  • TOIE1 - Флаг разрешения прерывания по переполнению таймера/счетчика Т1
  • OCIE0* - Флаг разрешения прерывания по событию "совпадение" таймера/счетчика Т0 (* - отсутствует в ATmega8)
  • TOIE0 - Флаг разрешения прерывания по переполнению таймера/счетчика Т0
  • OCF2 - Флаг прерывания по событию "совпадение" таймера/счетчика Т2
  • TOV2 - Флаг прерывания по переполнению таймера/счетчика Т2
  • ICF1 - Флаг прерывания по событию "захват" таймера/счетчика Т1
  • OCF1A - Флаг прерывания по событию "совпадение А" таймера/счетчика Т1
  • OCF1B - Флаг прерывания по событию "совпадение В" таймера/счетчика Т1
  • TOV1 - Флаг прерывания по переполнению таймера/счетчика Т1
  • OCF0 - Флаг прерывания по событию "совпадение" таймера/счетчика Т0
  • TOV0 - Флаг прерывания по переполнению таймера/счетчика Т0

Описание работы тайтер/счетчика Т1 в контроллере ATmega8/16

Шеснадцатиразрядный таймер/счетчик Т1 может использоватся для формирования временных интервалов, подсчета количества внешних сигналов, и для генерации сигналов с ШИМ разной скважности и длительности на выводах OC1A и OC1B. Кроме того по внешнему сигналу с вывода ICP1 или от аналогового компаратора, Т1 может сохранять свое текущее состояние в отдельном регистре захвата ICR1.

Разряды регистров TCCR1A:TCC1B:TCNT1:OCR1A:OCR1B:ICR1
Регистр 7 6 5 4 3 2 1 0
TCCR1A COM1A1 COM1A0 COM1B1 COM1BO FOC1A FOC1B WGM11 WGM10
TCCR1B ICNC1 ICES1 * WGM13 WGM12 CS12 CS11 CS10
TCNT1:H R/W R/W R/W R/W R/W R/W R/W R/W
TCNT1:L R/W R/W R/W R/W R/W R/W R/W R/W
OCR1A:H R/W R/W R/W R/W R/W R/W R/W R/W
OCR1A:L R/W R/W R/W R/W R/W R/W R/W R/W
OCR1B:H R/W R/W R/W R/W R/W R/W R/W R/W
OCR1B:L R/W R/W R/W R/W R/W R/W R/W R/W
ICR1:H R/W R/W R/W R/W R/W R/W R/W R/W
ICR1:L R/W R/W R/W R/W R/W R/W R/W R/W

Каждый 16-разрядный регистр физически размещается в двух 8-разрядных регистрах поэтому при чтении записи в них нужно выполнить две операции. При записи первым загружается старший байт потом младший,при чтении наоборот сначала младший прочитывается потом старший.

TCCR1A:TCCR1B - 8-разрядные регистры управления таймером/счетчиком Т1

TCNT1 - 16-разрядный счетный регистр таймера/счетчика Т1. Взависимости от режима работы содержимое этого регистра обнуляется,инкрементируется(увеличивается значение на 1) или декрементируется(уменьшается значение на 1) по каждому импульсу тактового сигнала таймера/счетчика.

OCR1A:OCR1B - 16-разрядные регистры сравнения

ICR1 - 16-разрядный регистр захвата,сохраняет значение TCNT1 при подаче активного фронта сигнала на вывод ICP1 или по сигналу от компаратора.

Назначение битов

COM1A1:COM1A0:COM1B1:COM1B0 - Эти разряды определяют поведение вывода OC1A:OC1B при совпадении значения счетного регистра TCNT1 и регистра сравнения OCR1A:OCR1B

FOC1A:FOC1B - Эти разряды служат для прнудительного изменения состояния вывода OC1A:OC1B

ICNC1 - Разряд управления схемой помех,если бит равен "0" захват будет по первому активному фронту, если "1" захват будет после четвертой одинаковой выборки сигнала захвата.

ICES1 - Разряд выбора активного фронта сигнала,если его значение равно "0", сохранение счетного регистра TCNT1 в регистре захвата OCR1 будет по спадающему фронту сигнала, если "1" по нарастающему.

WGM13:WGM12:WGM11:WGM10 - Эти разряды определяют режим работы таймера/счетчика Т1

CS22:CS21:C20 - Разряды, определяющие источник тактового сигнала таймера/счетчика Т1.

Выбор режима работы таймера/счетчика Т1
WGM13 WGM12 WGM11 WGM10 Режим работы Модуль счета (TOP)
0 0 0 0 Normal $FFFF
0 0 0 1 Phase correct PWM

8-разрядный

$00FF
0 0 1 0 Phase correct PWM

9-разрядный

$01FF
0 0 1 1 Phase correct PWM

10-разрядный

$03FF
0 1 0 0 CTC (сброс при совпадении) OCR1A
0 1 0 1 Fast PWM

8-разрядный

$00FF
0 1 1 0 Fast PWM

9-разрядный

$01FF
0 1 1 1 Fast PWM

10-разрядный

$03FF
1 0 0 0 ICR1
1 0 0 1 Phase and Freguensy Correct PWM OCR1A
1 0 1 0 Phase correct PWM ICR1
1 0 1 1 Phase correct PWM OCR1A
1 1 0 0 CTC (сброс при совпадении) ICR1
1 1 0 1 Зарезервировано *
1 1 1 0 Fast PWM ICR1
1 1 1 1 Fast PWM OCR1A

Выбор источника тактового сигнала

Режим Normal

Самый простой режим работы Т1. По каждому импульсу тактового сигнала происходит инкремент счетного регистра TCNT1 (увеличение значения на 1). При переходе через значение $FFFF модуля счета (ТОР) возникает переполнение и вследующем такте начинается счет со значения $0000, в этот же момент устанавливается флаг TOV1=1 в регистре TIFR, и может быть сгенерировано прерывание если установлен флаг TOIE1=1 в регистре TIMSK. Для того, чтобы сгенерировать сигна заданной частоты в этом режиме необходимо записать в разряды COM1A1=0:COM1A0=1 для вывода OC1A или COM1B1=0:COM1B0=1 для вывода OC1B контроллера.

Кроме того по каждому такту происходит сравнение счетного регистра TCNT1 и регистра сравнения OCR1A:OCR1B, при совпадении устанавливается флаг прерывания OCF1A=1:OCF1B=1 и если разряд OCIE1A=1:OCIE1B=1 регистра TIMSK генерируется прерывание. В тот же момент может быть изменено состояние вывода OC1A:OC1B в зависимости от установок битов COM1A1:COM1A0:COM1B1:COM1B0.

Режим СТС (сброс при совпадении)

В этом режиме Т1 работает по такому же принципу как и в режиме Normal. Отличие заключается в том, что максимально возможное значение счетного регистра TCNT1 ограничивается значением регистра сравнения OCR1A или ICR1 (смотрите таблицу выбора режима таймер/счетчика). При достижении TCNT1 значения OCR1A или ICR1, значение TCNT1 обнуляется в TCNT1=$0000 В этот же момент устанавливается флаг TOV1=1 COM1A1:COM1A0:COM1B1:COM1B0 Опрелеляют поведение вывода ОС1A:OC1B при совпадении.

Режим Fast PWM (быстродействующий ШИМ)

С помощью этого режима можно генерировать высокочастотный сигал ШИМ. Принцип и порядок работы не отличается от режима Normal, кроме наличия двойной буферизации регистра OCR1A:OCR1B, благодаря которому исключается появление несиметричных импульсов сигнала, а также отличается поведением выводов ОС1A:OC1B (смотрите таблицу).


Режим Phase Correct PWM (ШИМ с точной фазой)

Отличие этого режима от предыдущих заключается в том, что счетный регистр работает как реверсивный счетчик. Так как этот режим рекомендуется Atmel как наиболее подходящий для регулировки двигателей, мы его рассмотрим наиболее подробно. При достижении счетным регистром TCNT1 значения модуля счета (ТОР) (или значения регистра ICR1 или значения регистра OCR1A, смотрите таблицу выбора режима таймер/счетчика), происходит изменение направления счета. При достижении счетным регистром TCNT1 минимального значения ($0000) также происходит изменение направления счета и в тот же момент устанавливается флаг прерывания TOV1 регистра TIFR. Так же при равенстве содержимого счетного регистра TCNT1 и регистра сравнения OCR1A:OCR1B ,устанавливается флаг OCF1A:OCF1B регистра TIFR и изменяется состояние вывода OC1A:OC1B,согласно таблице.

Во избежание несимметричных выбросов во время записи значения в регистр OCR1A:OCR1B, в этом режиме реализована двойная буферизация записи. Благодаря этому действительное изменение значения регистра изменяется в момент достижения счетным регистром TCNT1 значения модуля счета (ТОР) (или значения регистра ICR1 или значения регистра OCR1A смотрите таблицу выбора режима таймер/счетчика). Поэтому в самом начале, при инициализации таймер/счетчика вывод ОС1A:OC1B не изменит свое состояние при совпадении до тех пор, пока регистр не достигнет значения (ТОР).


Задача: Разработаем программу управления яркостью лампы накаливания на 12 Вольт при помощи ШИМ. При нажатии на кнопку «Больше» яркость лампы увеличивается, при нажатии на кнопку «Меньше» яркость уменьшается. Схема нашего будущего устройства показана на рисунке. Как обычно используем микроконтроллер Atmega8, который будет тактироваться от внутреннего генератора частотой 4MHz. Собственно у нас получится диммер, эти устройства предназначены для регулировки яркости осветительных приборов. Сейчас наибольшее распространение получили светодиодные диммеры.

Для простоты к нашей схеме можно тоже подключить светодиод, но с лампочкой будет нагляднее. Кнопки подключены к выводам PD0 , PD1 . Нагрузку подключаем к выводу PB1(OC1A) через резистор и полевой транзистор MOSFET, который и будет работать у нас в качестве ключа (в ключевом режиме). Полевой транзистор предпочтительней потому, что его затвор изолирован от силовой схемы и управление производится электрическим полем, а ток управления достигает микроампер. Это позволяет, используя один-два транзистора, управлять нагрузкой огромной мощности (до десятков ампер и десятков-сотен вольт), не нагружая микроконтроллер. Учитывая также тот факт, что полевые транзисторы можно соединять параллельно (в отличие от биполярных), возможно получить еще более мощный каскад на сотни ампер.

Теперь разберемся, как микроконтроллер реализует ШИМ и напишем программу. Как уже говорилось ранее, в нашем МК есть 3 таймера, и все они могут работать в ШИМ-режиме. Мы будем работать с шестнадцатиразрядным таймером/счетчиком. Битами WGM13-10 настроим наш таймер на работу FastPWM с верхним пределом счета ICR1 . Принцип программы такой, наш таймер считает от 0 до 65535(0xFFFF), в регистр ICR1 впишем число 255, это будет верхний предел счета таймера(TOP), частота ШИМ сигнала у нас будет постоянной. Также наш таймер настроен на то, что при совпадении счетного регистра и регистра сравнения (TCNT1 = OCR1A) будет переключатся вывод контроллера OC1A . Коэффициент заполнения ШИМ можно изменить, записав в регистр сравнения OCR1A определенное число от 0 до 255, чем больше это число тем больше будет коэффициент заполнения, тем ярче будет гореть лампа. В зависимости от того какая кнопка нажата меняется переменная i , а потом она записывается в регистр OCR1A .

Полный текст программы представлен ниже. В комментариях более подробно описана работа программы.

/***Занятие №8. Формирование ШИМ сигналов***/ #include #include int main(void) { unsigned int i=0; //определяем переменную i /***Настройка портов ввода-вывода***/ PORTB = 0x00; DDRB |= (1 << PB1); PORTD |= (1 << PD1)|(1 << PD0); // подключаем внутренние нагрузочные резисторы DDRD = 0x00; /***Настройка таймера***/ TCCR1A |= (1 << COM1A1)|(0 << COM1A0) // Установим биты COM1A1-COM1A0:0b10, означает сброс вывода канала A при сравнении |(1 << WGM11)|(0 << WGM10); // Установим биты WGM13-10:0b1110, согласно таблице это TCCR1B |= (1 << WGM13)|(1 << WGM12) // будет режим - FAST PWM, где верхний предел счета задается битом ICR1 |(0 << CS12)|(0 << CS11)|(1 << CS10); // Битами CS12-10:0b001 задаем источник тактового сигнала для таймера МК, включен без делителя TCNT1 = 0x00; // начальная установка счетчика ICR1 = 0xFF; // задаем период ШИМ, здесь у нас число 255, // по формуле fPWM=fclk_I/O/N*(1+ICR1)// вычисляем частоту ШИМ, она будет равна 15625 Hz OCR1A = 0x00; // начальный коэффициент заполнения ШИМ /***Основной цикл программы***/ while(1) { if((PIND&(1 << PD0)) == 0) //если кнопка "больше" нажата { if (i < 254) { // коэффициент заполнения ШИМ изменяется от 0 до 255 i=i+1; // увеличиваем i на единицу OCR1A = i; // записываем переменную в регистр сравнения _delay_ms(30); // задержка 30ms } } if((PIND&(1 << PD1)) == 0) //если кнопка "меньше" нажата { if (i > 0) // коэффициент заполнения ШИМ изменяется от 255 до 0 { i--; // уменьшаем i на единицу(так тоже можно писать) OCR1A = i; // записываем переменную в регистр сравнения _delay_ms(30); // задержка 30ms } } } }

Внимание! Сперва подаем питание на микроконтроллер, потом нужно убедиться, что транзистор подсоединен к выводу МК, и лишь затем подавать питание в цепь с лампой и полевым транзистором. Иначе можете сжечь транзистор. Дело в том, что в выключенном состоянии "ножки" МК "болтаются в воздухе" - они ни к чему не подключены, и на них возникают наводки. Этих слабеньких наводок достаточно, чтобы частично открыть очень чувствительный полевой транзистор. Тогда его сопротивление между стоком и истоком упадет от нескольких МОм до нескольких Ом или долей Ом и через него потечет большой ток к лампе. Но транзистор не откроется полностью, т. к. для этого нужно подать на затвор не 1-3 В наводки, а стабильные 5 В, и его сопротивление будет намного больше минимального. Это приведет к выделению на нем большого количества тепла, и он задымится, а может и сгореть.

Таймеры ШИМ (Лекция)

Очевидно, что нужен какой-то внешний счетчик, который тикал бы независимо от работы процессора, а процессор мог в любой момент посмотреть, что в нем такое натикало. Либо чтобы счетчик выдавал события по переполнению или опустошению – флаг поднимал или прерывание генерировал. А процессор это увидит и обработает. И такой счетчик есть, даже не один – это периферийные таймеры. В AVR их может быть несколько штук с разной разрядностью. В ATmega16 три, в ATmega128 четыре. Причем таймер может быть не просто счетчиком, таймер является одним из самых многофункциональных (в плане альтернативных функций) периферийных устройств.

Что умеют таймеры

· Работать от внешнего кварца на 32768 Гц

· Генерировать несколько видов ШИМ сигнала

· Выдавать прерывания (по полудесятку разных событий) и устанавливать флаги

Источник тиков таймера

Таймер/Счетчик (далее ТС) считает либо тактовые импульсы от встроенного тактового генератора, либо со счетного входа. При соответствующей настройке ТС будет считать либо передний (перепад с 0-1), либо задний (перепад 1-0) фронт импульсов, пришедших на входы. Главное, чтобы частота входящих импульсов не превышала тактовую частоту процессора, иначе он не успеет обработать импульсы.

Кроме того, некоторые таймеры способны работать в асинхронном режиме. То есть ТС считает не тактовые импульсы процессора, а импульсы своего собственного генератора, работающего от отдельного кварца. Для этого у ТС есть отдельные входы, на которые можно повесить кварцевый резонатор. Зачем это надо? Хотя бы для того, чтобы организовать часы реального времени. Повесил на них часовой кварц на 32768 Гц и можно засекать время - за секунду произойдет 128 переполнений (если ТС – восьмиразрядный). Так что одно переполнение это 1/128 секунды. Причем на время обработки прерывания по переполнению таймер не останавливается, он также продолжает считать.

Предделитель

Если таймер считает импульсы от тактового генератора или от своего внутреннего, то их еще можно пропустить через предделитель. То есть еще до попадания в счетный регистр частота импульсов будет делиться. Делить можно на 8, 32, 64, 128, 256, 1024. Так что если повесить на ТС часовой кварц и пропустить через предделитель на 128, то таймер будет считать со скоростью один раз в секунду. Также удобно использовать предделитель, когда надо просто получить большой интервал, а единственный источник счета –это тактовый генератор процессора, а считать эти мегагерцы сложно, а вот если пропустить через предделитель, то все уже проще. Однако если запустить ТС с предделителем, то первый тик на счетный регистр придет не обязательно через необходимое количество импульсов.

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

Например, первый таймер работает на выводе 1:64, а второй на выводе 1:1024 предделителя. У второго почти дотикало в предделителе до 1024 и вот вот должен быть тик таймера, но тут ты взял и сбросил предделитель, чтобы запустить первый таймер точно с нуля. Что произойдет? У второго делитель тут же скинется в 0 (предделитель единый, регистр у него один), и второму таймеру придется ждать еще 1024 такта, чтобы получить таки импульс! А если сбрасывать предделитель в цикле, во благо первого таймера, чаще, чем раз в 1024 такта, то второй таймер так никогда и не тикнет. Для сброса предделителей достаточно записать бит PSR10 в регистре SFIOR. Бит PSR10 будет сброшен автоматически на следующем такте.

Счетный регистр

Весь счет накапливается в счетном регистре TCNTх, где вместо х номер таймера. Он может быть как 8-, так и 16-разрядным, в таком случае он состоит из двух регистров TCNTxH и TCNTxL – старший и младший байты соответственно.

Причем тут есть подвох. А дело все в чем – таймер считает независимо от процессора, поэтому мы можем положить вначале один байт, он начнет считаться, потом второй, и начнется пересчет уже с учетом второго байта. Таймер точное устройство, поэтому грузить его счетные регистры надо одновременно! Но как? А инженеры из Atmel решили проблему просто: Запись в старший регистр (TCNTxH) ведется вначале в регистр TEMP. Этот регистр чисто служебный, и нам никак недоступен.

Что в итоге получается? Записываем старший байт в регистр TEMP (для нас все равно TCNTxH), а затем записываем младший байт. В этот момент в реальный TCNTxH заносится ранее записанное значение. То есть два байта, старший и младший, записываются одновременно! Менять порядок нельзя! Выглядит это так:

Зачем запрещать прерывания? Да чтобы после записи первого байта, программа случайно не ушла не прерывание.

Читается все также, только в обратном порядке. Сначала младший байт (при этом старший – в TEMP), потом старший. Это гарантирует то, что мы считаем именно тот байт, который был на данный момент в счетном регистре.

Контрольные регистры

Основная функция таймера - счетная. Главным регистром является TCCRx. Для ТС0 – это TCCR0, для других таймеров TCCR n соответственно. Первые 3 бита этого регистра: CSx2..CSx0 отвечают за установку предделителя и источник тактового сигнала, вместо х подставляется номер таймера. У разных таймеров немного по-разному, поэтому опишем биты CS02…CS00 только для таймера0.

· 000 - таймер остановлен

· 001 - предделитель равен 1, то есть выключен. Таймер считает тактовые импульсы

· 010 - предделитель равен 8, тактовая частота делится на 8

· 011 - предделитель равен 64, тактовая частота делится на 64

· 100 - предделитель равен 256, тактовая частота делится на 256

· 101 - предделитель равен 1024, тактовая частота делится на 1024

· 110 - тактовые импульсы идут от ножки Т0 на переходе с 1 на 0

· 111 - тактовые импульсы идут от ножки Т0 на переходе с 0 на 1

Прерывания

У каждого аппаратного события есть прерывание, и таймер не исключение. Как только происходит переполнение или другое событие, так сразу же генерируется прерывание. За прерывания от таймеров отвечают регистры TIMSК, TIFR. А у мощных AVR, таких как ATMega128, есть еще ETIFR и ETIMSK - своего рода продолжение, так как таймеров там больше.TIMSK – это регистр масок. То есть биты, находящиеся в нем, локально разрешают прерывания. Если бит установлен, значит, конкретное прерывание разрешено. Если бит в нуле, значит, данное прерывание не обрабатывается. По умолчанию все биты в нуле. За прерывание по переполнению отвечают биты:

· TOIE - разрешение на прерывание по переполнению таймера 0

· TOIE1 - разрешение на прерывание по переполнению таймера 1

· TOIE2 - разрешение на прерывание по переполнению таймера 2

Регистр TIFR это непосредственно флаговый регистр. Когда какое то прерывание срабатывает, то флаг прерывания устанавливается. Этот флаг сбрасывается аппаратно, когда программа уходит по вектору. Если прерывания запрещены, то флаг так и будет стоять до тех пор, пока прерывания не разрешат и программа не уйдет на прерывание. Чтобы этого не произошло, флаг можно сбросить вручную. Для этого в TIFR в него нужно записать 1!

Подробнее о таймера A T MEGA128 будет рассказано позже.

Широтно Импульсная Модуляция

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

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

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

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

Аппаратная реализация ШИМ

В случае ATMega проще всего сделать на его ШИМ-генераторе, который встроен в таймеры. Причем в первом таймере есть два канала. Так что ATmega может реализовать одновременно четыре канала ШИМ .

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

· Прерывание по совпадению

· Изменение состояния внешнего выхода сравнения OC .

Выходы сравнения выведены наружу, на выводы микроконтроллера. Предположим, что ШИМ - генератор настроен так , что когда значение в счетном регистре больше , чем в регистре сравнения, то на выходе 1, а когда меньше, то 0. Что при этом произойдет? Таймер будет считать, как ему и положено, от нуля до 256 с частотой , которую мы настроим битами предделителя таймера. После переполнения сбрасывается в 0 и продолжает считать заново.

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

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

Б ы страя ШИМ ( Fast PWM)

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

Частота получившегося ШИМ сигнала определяется просто: Частота процессора, например, 8Мгц, таймер тикает до 256 с тактовой частотой. Значит, один период ШИМ будет равен 8000 000/256 = 31250Гц. Быстрей не получится - это максимальная скорость на внутреннем 8Мгц тактовом генераторе. Еще есть возможность повысить разрешение, сделав счет 8, 9, 10 разрядным (если разрядность таймера позволяет), но надо учитывать, что повышение разрядности, вместе с повышением дискретности выходного аналогового сигнала, резко снижает частоту ШИМ.

ШИМ с фазовой коррекцией (Phase Correct PWM)

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


Рис. Режим быстрой ШИМ и ШИМ с фазовой коррекцией

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

Сброс по совпадению (Clear Timer On Compare)

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

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


Например, надо нам прерывание каждую миллисекунду. И чтобы вот точно. Как это реализовать проще? Через Режим СТС! Пусть частота равна 8Мгц. Предделитель будет равен 64, таким образом, частота счета таймера составит 125000 Гц. А нам надо прерывание с частотой 1000Гц. Поэтому настраиваем прерывание по совпадению с числом 125. Дошел счет до 125 – выработалось прерывание, обнулился счетчик. Дошел до 125 – дал прерывание, обнулился.

8-разрядный таймер-счетчик 0 с функциями ШИМ и асинхронного тактирования

Таймер-счетчик 0 - модуль многофункционального одноканального 8-разрядного таймера-счетчика с аппаратным выходом для генерации ШИМ-сигнала и встроенным асинхронным опциональным тактовым генератором, который оптимизирован под использование часового кварца (32768Гц) для асинхронного по отношению к системной синхронизации тактирования.




Регистры

Регистр таймера-счетчика (TCNT0) и регистр порога сравнения (OCR0) - 8-разр. регистры. Сигналы запроса на прерывание представлены как флаги прерываний таймера в регистре TIFR. Все прерывания индивидуально маскируются с помощью регистра маски прерываний таймеров (TIMSK). Таймер-счетчик может тактироваться через предделитель внутренне или асинхронно через внешние выводы TOSC1/2. Асинхронная работа управляется регистром ASSR. Блок синхронизации осуществляет выбор, какой тактовый источник используется. Если источник тактирования не задан, то таймер-счетчик находится в неактивном состоянии. Выход clkT0 – это выход логики выбора синхронизации. Значение регистра порога сравнения с двойной буферизацией (OCR0) непрерывно сравнивается со значением таймера-счетчика. Результат сравнения может использоваться для генерации сигналов с ШИМ или прямоугольных импульсов переменной частоты на выводе OC0. Совпадение порога сравнения со значением таймера-счетчика приводит к установке флага результата сравнения (OCF0), который может использоваться для генерации запроса на прерывание по результату сравнения.

НП (нижний предел)

Счетчик достигает нулевого значения (0х00)

МАКС (макс. значение)

Счетчик достигает максимального значения 0xFF (десятич. 255)

ВП (верхний предел)

Счетчик достигает верхнего предела счета (вершина счета). В качестве вершины счета может выступать фиксированное значение 0xFF или содержимое регистра OCR0.

Тактовые источники таймера-счетчика 0

ТС0 может тактироваться внутренне синхронно или внешне асинхронно (по отношению к внутренней системной синхронизации). По умолчанию используется clkT0, эквивалентный clkI/O. Если в бит AS0 регистра ASSR записать «1», то в качестве источника выступает генератор на выводах TOSC1 и TOSC2.

Блок счетчика

Основу ТС0 составляет программируемый двунаправленный счетчик.


Описание сигналов (внутренние сигналы):

Счет - Инкрементирует или декрементирует TCNT0 на 1.

Направление - Задает направление счета: (+1, прямой счет) или (-1, обратный счет).

Сброс - Сбрасывает содержимое TCNT0 (запись 0 во все разряды).

clkT0 - Синхронизация таймера-счетчика.

Верхний предел - Задает максимальное значение на TCNT0.

Нижний предел - Задает минимальное значение на TCNT0 (0) .

В зависимости от выбранного режима работы счетчик сбрасывается, инкрементируется или декрементируется на каждом такте clkT0. Тактовый сигнал clkT0 может быть внутренним или внешним, а его частота выбирается с помощью бит CS02-CS00. Если источник синхронизации не задан (CS02-CS00=0b000), то таймер останавливается. Состояние TCNT0 доступно ЦПУ независимо от того синхронизации. Последовательность счета определяется установкой бит WGM01 и WGM00 из регистра TCCR0. Имеется точная связь между поведением счетчика и генерируемой на выходе OC0 формы сигнала. Флаг переполнения ТС (TOV0) устанавливается в соответствии с режимом работы, который выбирается битами WGM01, WGM00. Бит TOV0 может использоваться для генерации прерывания ЦПУ.

Блок сравнения

8-разрядный цифровой компаратор непрерывно выполняет сравнение содержимого регистра таймера-счетчика TCNT0 с регистром порога сравнения OCR0. Всякий раз, когда значение TCNT0 совпадает со значением OCR0, компаратор устанавливает флаг совпадения OCF0 следующим тактом синхронизации таймера. Если разрешено прерывание битом OCIE0=1, то установка флага совпадения вызывает запрос на прерывание. Флаг OCF0 автоматически сбрасывается во время обработки прерывания. Генератор сигнала использует сигнал результата сравнения для генерации прямоугольных импульсов по одному из алгоритмов, который выбирается битами задания режима работы таймера WGM01, WGM00 и битами задания режима формирования выходного сигнала (COM01, COM00). Верхний и нижний пределы счета используются в некоторых режимах работы для выполнения специальных действий.

Регистр OCR0 выполнен по схеме двойной буферизации при использовании режимов с широтно-импульсной модуляцией (ШИМ). В нормальном режиме и режиме сброса таймера при совпадении (CTC) схема двойной буферизации отключается. Двойная буферизация позволяет синхронизировать обновление регистра сравнения OCR0 по достижении верхнего или нижнего предела счета. Такая синхронизация предотвращает возможность возникновения несимметричных ШИМ-импульсов нечетной длины, тем самым гарантируя отсутствие сбоев при генерации прямоугольных импульсов. Доступ к регистру OCR0 может показаться сложным, но это выполнено не случайно. После разрешения двойной буферизации ЦПУ осуществляет доступ к буферному регистру OCR0, а после отключения - непосредственно адресуется к регистру OCR0.

Принудительная установка результата сравнения

В режимах генерации импульсов без ШИМ в формирователе импульсов результат сравнения может быть установлен непосредственно через бит FOC0. Принудительная установка результата сравнения компаратора не приводит к установке флага OCF0 или сбросу/перезагрузке таймера, но влияет на состояние вывода OC0, который будет устанавливаться, сбрасываться или переключаться (инвертироваться) в зависимости от выбранной установки бит COM01, COM00. Данная функция позволяет установить в регистре OCR0 то же значение, что и в TCNT0 без генерации запроса на прерывание, если разрешено тактирование таймера-счетчика.

Использование блока сравнения

Поскольку запись в TCNT0 блокирует любые действия по результату сравнения на один такт синхронизации таймера независимо от режима работы, то при изменении TCNT0 при использовании канала сравнения (независимо работает синхронизация таймера или нет) необходимо учесть следующие особенности. Если в регистр TCNT0 записано значение равное OCR0, то игнорирование совпадения приведет к генерации некорректной формы сигнала. По аналогии следует избегать записи в TCNT0 значения равного нижнему пределу (0x00), если счетчик работает как вычитающий. Установка OC0 должна быть выполнена перед настройкой линии ввода-вывода на вывод в регистре направления.

Блок формирования выходного сигнала

Биты задания режима формирования выходного сигнала (COM01:0) имеют двойное назначение. С одной стороны биты COM01, COM00 используются формирователем сигнала и определяют какое логическое состояние должно быть на выходе OC0 при возникновении следующего совпадения. С другой стороны, биты COM01, COM00 используются для разрешения/запрета альтернативной функции вывода порта OC0. На рисунке представлена упрощенная логическая схема, на которую воздействуют биты COM01, COM00. П оказаны только те регистры управления портом ввода-вывода (DDR и PORT), на которые оказывает действие биты COM01, COM00.


Функция линии универсального порта ввода-вывода заменяется на функцию выхода формирователя сигнала OC0, если хотя бы один из бит COM01, COM00 равен 1. Однако, управлением направлением вывода OC0 (вход или выход) в этом случае остается за соответствующим битом регистра направления данных порта В (DDRB.4). Чтобы значение регистра OC0 присутствовало на выводе OC0 необходимо настроить данную линию на вывод (установить бит DDRB.4). Управление вводом альтернативной функции не зависит от режима генерации сигнала.

Режимы работы таймера-счетчика 0

Режим работы таймера, в т.ч. поведение таймера-счетчика и связанного с ним выхода формирователя сигнала, задается комбинацией бит, задающих режим работы таймера (WGM01, WGM00) и режим формирования выходного сигнала (COM01, COM00). При этом биты задания режима формирования выходного сигнала не влияют на алгоритм счета, т.к. алгоритм счета зависит только от состояния бит задания режима работа таймера. В режимах с ШИМ биты COM01, COM00 позволяют включить/отключить инверсию на генерируемом ШИМ-выходе (т.е. выбрать ШИМ с инверсией или ШИМ без инверсии). Для режимов без ШИМ биты COM01:0 определяют, какое действие необходимо выполнить при выполнении условия сравнения: сбросить, установить или инвертировать выход.

Режимы работы таймера были описаны выше (нормальный (счетный), сброс по совпадению, быстрая ШИМ и ШИМ с фазовой коррекцией).

Асинхронная работа таймера-счетчика 0

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

1. Отключить прерывания таймера-счетчика 0 путем сброса бит OCIE0 и TOIE0.

2. Выбрать необходимый тактовый источник с помощью бита AS0

3. Выполнить запись новых значений в TCNT0, OCR0 и TCCR0.

4. При переходе в асинхронный режим тактирования дождаться сброса флагов TCN0UB, OCR0UB и TCR0UB.

5. Сбросить флаги прерывания таймера-счетчика 0

6. При необходимости разрешить прерывания

Генератор оптимизирован под использование часового кварцевого резонатора на частоту 32768 Гц. Тактовая частота ЦПУ должна быть минимум в четыре раза выше частоты генератора. Запись в TCNT0, OCR0 или TCCR0 происходит за два положительных фронта TOSC1, т.к. данные предварительно помещаются во временный регистр, а затем передаются по назначению. Каждый из трех упомянутых регистров имеют свои индивидуальные временные регистры. Это означает, что, например, запись в TCNT0 не влияет на процесс записи в регистр OCR0. Чтобы определить, в какой регистр была выполнена запись, реализован регистр асинхронного состояния ASSR.

Если выбрана асинхронная работа, то генератор на 32768 Гц находится постоянно включенным, за исключением режима выключения и дежурного режима МК.

Предделитель таймера-счетчика 0


Тактовый источник ТС0 обозначен как clkT0. По умолчанию clkT0 подключен к clkI/O. Если бит AS0=1 в регистре ASSR, то ТС0 тактируется асинхронно с вывода TOSC1. Так можно использовать ТС0 в качестве часов реального времени (RTC). Если AS=1, то выводы TOSC1 и TOSC2 не выполняют функции порта С, а между ними может быть подключен кварцевый резонатор в качестве отдельного тактового источника. Подключение к выводу TOSC1 внешнего тактового источника не рекомендуется. Предделитель позволяет выбрать следующие тактовые сигналы: clkT0S/8, clkT0S/32, clkT0S/64, clkT0S/128, clkT0S/256 и clkT0S/1024. Есть возможность остановить синхронизацию. Если PSR0=1 в регистре SFIOR, сбрасывает предделитель.

Описание регистров 8-разрядного таймера-счетчика 0 смотрите в спецификации.

Урок 13

Часть 1

ШИМ. Мигаем светодиодом плавно

Сегодня мы изучим возможность использования широтно-импульсной модуляции в микроконтроллере AVR , или, как говорят в народе, ШИМ .

В технической документации мы будем видеть чаще аббревиатуру PWM или pulse-width modulation , что преводится имено также.

Что же такое вообще широтно-импульсная модуляция.

ШИМ — это управление свечением светодиодов, вращением двигателей, и прочими устройствами необычным способом, при котором данное управление осуществляется не приложенным напряжением к контактам, а квадратными импульсами. При этом напряжение будет только двух видов — высокое (1 ) и низкое (0 ). При данном способе результирующее напряжение вычисляется как среднее по времени между временем высокого состояния в одном импульсе и временем низкого состояния. Мы вычисляем отношение времени (или широты) высокого состояния к общему периоду импульса. Называем мы это скважностью импульса. То есть чем больше в периоде напряжение находилось в высоком состоянии, тем больше скважность, а, следовательно, тем больше и результирующее среднее напряжение. То есть, чтобы найти результирующее напряжение, нам необходимо и достаточно вычисленную скважность умножить на напряжение и разделить на 100, так как скважность как правило измеряется в процентах. Например, если у нас в квадратном импульсе широта логического нуля равна широте логической единицы, то скважность у нас будет 50 процентов, и, если напряжение будет 5 вольт, то среднее результирующее напряжение мы получим равное 2,5 вольт и т.д. Лучшую картину объяснения данной ситуации мы можем увидеть, посмотрев видеоурок, ссылка на который дана в конце данной статьи.

Это конечно очень упрощённое понятие ШИМ. Есть более серьёзные разъяснение данной технологии, но нам для наших экспериментов этого будет вполне достаточно.

То есть, подведя итоги объяснению, мы управляем результирующим напряжением, а также и свечением светодиода, угловой скоростью электродвигателя и прочими значениями за счёт изменения скважности импульсов.

Но всё-таки самое интересное, как же всё-таки всё это организовано в нашем микроконтроллере?

В микроконтроллере AVR широтно-импульсную модуляцию можно организовать как программно , так и аппаратно .

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

Поэтому всегда в любой технологии мы стараемся придерживаться всё-таки именно аппаратного способа реализации.

Аппаратная организация ШИМ в МК AVR происходит на уровне таймера 2 .

Как мы помним из предыдущего занятия, таймеров в конкретном нашем микроконтроллере Atmega8 три. И таймеры 0 и 2 являются восьмибитными. Но на уровне 2-го таймера как раз и организована широтно-импульсная модуляция.

Давайте посмотрим вот такую вот картину

Здесь иллюстрируется то, какие мы должны включить биты в регистре TCCR второго таймера, чтобы запустить широтно-импульсную модуляцию.

Биты WGM как раз и включают таймер в резим PWM (ШИМ). С остальными битами разберёмся позже, если это потребуется.

А сейчас, чтобы это всё прочувствовать, нам необходим проект, который мы и создадим сейчас.

Проект создаем таким же образом, как и на прошлых занятиях. Назовём его Test10, создадим и добавим файлы PWM.c и PWM.h, последний автоматически оформится при создании соответствующими директивами прероцессора. А в главном файле Test01.c мы напишем стандартный код

#include «main.h»

//—————————————-

void port_ini ( void )

PORTB =0x00;

DDRB =0x08;

//—————————————-

int main ( void )

Port_ini ();

While (1)

Как мы видим в коде, в порте B мы включили на выход 3 ножку. В распиновке контроллера мы видим, что у данной ножки есть ещё альтернативное обозначение OC2 , которое и означает возможность этой ножки работать непосредственно с ШИМ

Файл main.h мы можем даже подключить с прошлого занятия по LCD и немного исправим код, подключив туда уже новый наш модуль PWM

#ifndef MAIN_H_

#define MAIN_H_

#define F_CPU 8000000UL

#include

#include

#include

#include

#include

#include «PWM.h»

#endif /* MAIN_H_ */

Ну и теперь начнём писать код в новую библиотеку для работы непосредственно с ШИМ — в файл PWM.c.

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

#include «PWM.h»

void init_PWM_timer ( void )

{

}

А в заголовочный файл нашей библиотеки мы добавим прототип данной функции, а также подключим библиотеку для работы с прерываниями

#ifndef PWM_H_

#define PWM_H_

#include

void init_PWM_timer ( void );

#endif /* PWM_H_ */

И вызовем сразу эту функцию в main()

port_ini ();

init_PWM_timer ();

Начнём теперь писать код непосредственно в функцию. Сначала запишем все нули в регистр ASSR , который существует у таймера, но мы его никак не используем

void init_PWM_timer ( void )

ASSR =0x00;

Дальше уже займёмся управляющим регистром нашего таймера. Назначение битов WGM и то, какие именно из них мы включим, мы разобрали. Теперь биты COM20 и COM21, отвечающие за режим самого ШИМ. Мы выберем вот такой режим и соответственно ему и включим данные биты

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

И останется нам только настроить делитель. Слишком большая частота нам не нужна. Но когда была слишком маленькая, также было заметно мерцание, поэтому давайте включим следующую величину

Поэтому мы включим все три бита.

В итоге значение регистра станет вот таким

ASSR =0x00;

TCCR2 =0b01101110; //Fast PWM, Clear OC2 on Compare Match, clkT2S/256 (From prescaler) (реальная частота получится 8мгц/256 = 31250 гц)

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

Смотреть ВИДЕОУРОК (нажмите на картинку)

Post Views: 9 484

В устройствах на микроконтроллерах иногда требуется генерировать аналоговый сигнал. В зависимости от частоты аналогового сигнала, требуемого разрешения и типа используемого микроконтроллера, выполнить это можно несколькими способами. А именно: с помощью широтно-импульсной модуляции, используя функционал аппаратных таймеров или программную реализацию, с помощью встроенного цифроаналогового преобразователя (ЦАП`а), с помощью внешних схем цифроаналоговых преобразователей на дискретных элементах или с помощью внешних микросхем цифроаналоговых преобразователей.

1. Принцип генерации аналогового сигнала с помощью ШИМ (PWM)

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


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

1.1 Характеристики сигнала

Максимальная амплитуда выходного аналогового сигнала будет определяться амплитудой логической единицы цифрового ШИМ сигнала. Если микроконтроллер питается от +5 В, то грубо говоря, амплитуда выходного аналогового сигнала будет от 0 до 5 В.

Минимальный шаг изменения аналогового сигнала (разрешение) будет определяться выражением:


dUa = Umax/2^n,


где Umax максимальная амплитуда аналогового сигнала (В), а n - разрядность счетчика реализующего ШИМ.

Например, ШИМ сигнал формируется с помощью программного 8-ми разрядного счетчика. Количество градаций ШИМ сигнала, которые можно получить с помощью этого счетчика, равно 2^8 = 256. Тогда разрешение аналогового сигнала при Umax = 5 В будет равно


dUa = 5/256 = 0,0195 В.


Частота ШИМ сигнала будет определять так:


Fpwm = Fcpu/(K*2^n),


где Fcpu - тактовая частота микроконтроллера (Гц), K - коэффициент предделителя счетчика, n - разрядность счетчика.

Например, тактовая частота микроконтроллера 8 МГц, коэффициент предделителя равен 8, разрядность счетчика 8 бит. Тогда частота выходного ШИМ сигнала будет равна:

Fpwm = 8000000/(8*256) = ~3906 Гц


Частота выходного аналогового сигнала будет определяться выражением:

Fa = Fpwm/Ns = Fcpu/(K*2^n*Ns),


где Fpwm - частота ЩИМ сигнала, а Ns - количество отсчетов аналогового сигнала.

Например, ШИМ сигнал реализуется на 8-ми разрядном счетчике с коэффициентом предделителя равным 8 и тактовой частотой микроконтроллера 8 МГц. В памяти микроконтроллера записано 32 отсчета синусоидального сигнала, которые представляют собой один его период. Тогда частота выходной синусоиды будет равна:

Fa = 8000000/(8*2^8 * 32) = ~122 Гц

Разрядность ЦАП`a сделанного на основе ШИМ эквивалентна разрядности используемого счетчика.

1.2 Аппаратная реализация ШИМ

Все современные микроконтроллеры имеют в своем составе таймеры/счетчики. Один или несколько режимов этих таймеров предназначены для генерации ШИМ сигнала. Как правило этот сигнал генерируется на специальных выводах. Например, у микроконтроллера mega16 фирмы Atmel 8-ми разрядный таймер/счетчик Т0 имеет два режима генерации ШИМ сигнала (быстрый ШИМ и ШИМ с точной фазой), а для вывода сигнала используется пин порта B - OC0 (PINB3).

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

1.3 Программная реализация ШИМ

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

Преимущество программной реализации - простота, неограниченное количество каналов, неограниченное разрешение. Конечно, условно неограниченное, с учетом доступной памяти. Недостатки программной реализации - высокая загрузка микроконтроллера. Прерывания должны вызываться на каждый инкремент счетчика и каждый раз нужно проверять не достиг ли он одного из крайних значений. Также программная реализация имеет меньшую точность (большее дрожание фронтов сигнала) и еще меньшую частоту (из-за первого недостатка).

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

Ниже приведен пример кода, который выполняет функцию генерацию аналогового сигнала с помощью аппаратной и программной широтно-импульсной модуляции. Код написан для микроконтроллера atmega16, тактовая частота 8 МГц, компилятор IAR. На выходах PB2 и PB3 генерируются две синусоиды (разной частоты) из 32 двух отсчетов.


#include
#include
#include

#define SPWM_PIN 2

//таблица синуса
__flash uint8_t tableSin =
{
152,176,198,218,234,245,253,255,
253,245,234,218,198,176,152,128,
103, 79, 57, 37, 21, 10, 2, 0,
2, 10, 21, 37, 57, 79,103,128
};

uint8_t softCount = 0;
uint8_t softComp = 0;

int main(void)
{
//настройка портов
PORTB = 0;
DDRB = 0xff;

//разрешение прерывания по совпадению Т0
TIMSK = (1< //режим FastPWM, неинв. шим сигнал, предделитель 8
TCCR0 = (1< (0<

//обнуляем счетный регистр
TCNT0 = 0;
OCR0 = 0;

Enable_interrupt();
while(1);
return 0;
}

//прерывание таймера Т0
#pragma vector = TIMER0_COMP_vect
__interrupt void Timer0CompVect(void)
{
static uint8_t i = 0;
static uint8_t j = 0;

OCR0 = tableSin[i];
i = (i + 1) & 31;

//программный ШИМ
softCount++;
if (softCount == 0){
PORTB |= (1< softComp = tableSin[j];
j = (j + 1) & 31;
}

If (softCount == softComp){
PORTB &= ~(1< }
}

1.4 Фильтр для ШИМ

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

Рассмотрим пример. ШИМ сигнал генерируется аппаратным 8-ми разрядным счетчиком с коэффициентом предделителя равным 8, тактовая частота микроконтроллера 8МГц, количество отсчетов аналогового сигнала - 32.

Частота ШИМ сигнала будет равна:

Fpwm = Fcpu/(K*2^n) = 8000000/(8*256) = ~3906 Гц

Частота аналогового сигнала будет равна:

Fa = Fpwm/Ns = 3906/32 = 122 Гц

Выберем частоту среза равную 200 Гц и рассчитаем номиналы пассивного низкочастотного RC фильтра. Частота среза такого фильтра определяется выражением:

Fc = 1/(2*Pi*R*C),

где R - номинал резистора (Ом), а C -емкость конденсатора (Ф).

Задавшись номиналом одного из компонентов можно вычислить номинал второго. Для резистора номиналом 1 кОм, емкость конденсатора будет равна:


C = 1/(2*Pi*Fc*R) = 1/(6.28 * 1000*200) = ~0.8 мкФ


Выбираем ближайшее значение из ряда E12 - 0.82 мкФ. При таких номиналах фильтра мы получим уже похожий аналоговый сигнал.

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

После того, как мы поморгали светодиодами, разобрались с тактированием и источниками прерываний, пришло время освоить таймер контроллера MSP430G2553.
Таймер – это счетный механизм, привязанный к импульсам сигнала тактового генератора. Таймер Timer_A , является 16-ти битным таймером. Это означает, что он считает от нуля до двоичного 0b1111111111111111, или шестнадцатеричного 0xFFFF, или десятеричного 65535. Таймер является периферийным устройством и так же имеет собственные прерывания.
Таймер Timer_A имеет три режима работы.

Режим непрерывного счёта, в нём таймер просто считает от 0 до 0xFFFF, потом начинает с начала, и так до бесконечности.

Режим прямого счёта, в нём таймер работает так же, считает до верхней границы, и начинает опять с 0. Только в этом режиме вы можете выбирать, верхнюю границу, до которой будет считать таймер.

Режим реверсивного счёта, похож на режим прямого счёта тем, что в нём вы можете выбрать максимальное значение таймера. Отличие его в том, что достигнув максимума, таймер начинает считать вниз, потом, достигнув 0, опять вверх и т.д.
На графиках есть обозначение TACCR0 – это регистр захвата сравнения. Их может быть два (TACCR0 и TACCR1), может быть три (TACCR0, TACCR1 и TACCR2) в зависимости от модели. В этот регистр можно записывать так называемые ключевые точки, по достижению которых таймер будет вызывать прерывание.

Ниже подробно описаны регистры Таймера А
TACTL – Timer_A Control Register, Регистр управления Таймера А. Используется для связи таймера с тактовыми сигналами и выбора режимов работы.
TASSELx , биты 8 и 9, указывают таймеру, какой из тактовых сигналов использовать.
IDx , биты 6 и 7, указывают, какой делитель частоты тактового сигнала использовать, 2, 4 или 8. Делится частота, полученная уже после применения делителя в самом генераторе тактового сигнала.
MCx , биты 4 и 5, указывают на режим работы таймера. Если они равны 0 (стоит по умолчанию) таймер полностью остановлен.
TACLR , бит 2. Если в него вписать 1, это приведет к сбросу таймера. Микроконтроллер автоматически вписывает в этот бит 0, после перезапуска таймера.
TAIE и TAIFG , биты 0 и 1, соответственно. Контролируют прерывание таймера, об этом чуть ниже.
TAR – Timer_A Register, Регистр счётчика Таймера А, в нём содержится текущее значение таймера.
TACCRx – Timer_A Capture/Compare Registers, Регистры захвата/сравнения Таймера А. Их может быть два (TACCR0 и TACCR1), может быть три (TACCR0, TACCR1 и TACCR2) в зависимости от модели микроконтроллера. В режиме сравнения, мы вписываем в них значения, по достижении которых, таймер должен подать нам сигнал. TACCR0 зачастую используется для указания верхней границы счёта. В режиме захвата, процессор записывает в них текущее значение TAR, по сигналу на входе.
TACCTLx – Timer_A Capture/Compare Control Registers, Регистр управления блоком захвата/сравнения Таймера А. От его значения, зависят режимы работы регистров захвата/сравнения.
CMx , биты 14 и 15, определяют тип сигнала, по которому происходит захват. (По нарастающему, спадающему, обоим фронтам. – Прим. пер.)
CCISx , биты 12 и 13, выбирают, откуда берется сигнал захвата.
SCS и SCCI, биты 11 и 10 соответственно, синхронизация сигнала захвата с тактовым сигналом таймера. Обычно, таймер работает независимо, асинхронно, от внешних сигналов. (Я сам до конца не разобрался в этой функции, напишу подробней в следующих уроках)
CAP , бит 8, выбор режима работы, 1 – режим захвата, 0 – режим сравнения.
OUTMODx , биты 5-7, выбор режима работы модуля вывода, т.е. тип реакции на событие захвата или сравнения.
CCIE и CCIFG , биты 4 и 0 соответственно, обработка прерываний по захвату/сравнению.
CCI и OUT , биты 3 и 2 соответственно, вход и выход захвата/сравнения.
COV , бит 1, переполнение захвата. Устанавливается в 1, если произошел второй захват, а первый еще не был считан. Должен сбрасываться программно.
TAIV – Taimer_A Interrupt Vector Register, регистр вектора прерывания Таймера А. Так как прерывание таймера, может быть вызвано по нескольким разным причинам, содержимое этого регистра, указывает на причину вызова прерывания.
TAIVx , биты 1-3, содержат тип случившегося прерывания, что позволяет нам, совершить разные действия для обработки разных причин прерываний.

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

TACCR0 = 62499; // период 62,500 циклов TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению значения CCR0. TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; //Настройка режима работы Timer_A: // TASSEL_2 - источник так тов SMCLK (SubMainCLocK), // по умолчанию настроенны х на работу от DCO // ID_3 - делитель частоты на 8, от 1MHz это будет 125kHz // MC_1 - режим прямого счёта (до TACCR0) // TACLR - начальное обнуление таймера

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

Чтобы было понятнее, на рисунке ниже приведены сигналы ШИМ для коэффициента заполнения: а – 25%; б – 50 %; в – 75 %; г – 100 %.

t0– время импульса;
T – период;
Изменяя t0, можно получать различные средние значения напряжения на нагрузке, таким образом, изменяя яркость свечения светодиода.
Период широтно-импульсной модуляции должен быть постоянным и больше чем время импульса. Поэтому запишем TACCR0 = 600; // период 600 циклов . Это число я подобрал экспериментальным путём, чтобы работу таймера было видно невооруженным глазом.
Так как светодиод должен медленно начать светиться, то начальное время импульса должно быть очень маленьким например TACCR1 = 10; // время импульса 10 циклов . TACCR1 – это второй регистр захвата\сравнения Таймера А. Итак, получается, что при достижении значения TACCR0 = 600 таймер будет генерировать прерывание, в котором мы будем устанавливать выход микроконтроллера в единицу, что будет началом импульса. При это таймер обнуляется и начинает считать заново с нуля пока не дойдёт до TACCR1 = 10, тогда будет сгенерировано прерывание по второму регистру захвата\сравнения, в котором мы установим выход микроконтроллера в ноль. Таким образом длительность импульса t0 будет длиться 5 тактов.
Для того, чтобы светодиод увеличивал интенсивность свечения, необходимо увеличивать время импульса. Для этого после каждого прерывания от TACCR0 будем прибавлять к текущему значению TACCR1 какое-то значение. При этом максимально значения, которое может иметь TACCR1 будет равно периоду, то есть 600. В зависимости о значения, которое мы будем прибавлять, будет зависеть плавность и скорость изменения интенсивности свечения.

TACCR0 = 600; // Период TACCR1 = 5; //Время импульса TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению CCR0. TACCTL1 = CCIE; // Разрешаем прерывание таймера по достижению CCR1. TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; //Настройка режима работы Timer_A

Теперь необходимо написать обработчик прерываний для TACCR0 , который будет задавать начало каждому новому периоду, а так же прибавлять или отнимать значение TACCR1, чтобы светодиод плавно зажигался и так же плавно тух.

#pragma vector = TIMER0_A0_VECTOR __interrupt void CCR0_ISR(void) //вектор прерывания для TACCR0, Таймера А { P1OUT |= BIT0; // устанавливаем нулевой бит в еденицу if (TACCR1><=5) // если TACCR1 меньше минимального значения, то увеличиваем TACCR1 { indeX=2; } if (indeX == 1) { --TACCR1; // уменьшаем TACCR1 на 1 } if ((indeX == 2) || (indeX == 0)) { ++TACCR1; // увеличиваем TACCR1 на 1 } }

Прерывание для TACCR1 будет выглядеть следующим образом.

#pragma vector=TIMER0_A1_VECTOR __interrupt void CCR1_ISR(void) //вектор прерывания для TACCR1, Таймера А { P1OUT &= ~BIT0; // устанавливаем нулевой бит порта Р1 в ноль. TAIV &= ~TA0IV_TACCR1; //сбрасываем флаг прерывания. }

Обратите внимание, что в первом случае, в обработчике прерывания от TACCR0 я не сбрасывал флаг прерывания, а для TACCR1 сделал это. Все потому, что флаг прерывания для TACCR0 сбрасывается автоматически при вызове такого прерывания, а для TACCR1 его нужно сбрасывать вручную.

Теперь можно составить полный текст программы.

#include /* Глобальные переменные */ unsigned int indeX = 0; /* Объявление функций */ void main(void) { WDTCTL = WDTPW + WDTHOLD; // отключаем сторожевой таймер P1DIR |= 0x01;// настраиваем нулевой бит порта Р1 на выход P1OUT = 0x01; // устанавливаем нулевой бит порта Р1 в единицу BCSCTL1 = CALBC1_1MHZ; // Устанавливаем частоту DCO DCOCTL = CALDCO_1MHZ; TACCR0 = 600; // Период TACCR1 = 10; // Время импульса TACCTL0 = CCIE; // Разрешаем прерывание таймера по достижению CCR0 TACCTL1 = CCIE; // Разрешаем прерывание таймера по достижению CCR1 TACTL = TASSEL_2 + ID_3 + MC_1 + TACLR; //Настройка режима работы Timer_A: // TASSEL_2 - источник так тов SMCLK (SubMainCLocK), // по умолчанию настроенны х на работу от DCO // ID_3 - делитель частоты на 8, от 1MHz это будет 125kHz // MC_1 - режим прямого счёта (до TACCR0) // TACLR - начальное обнуление таймера _enable_interrupt(); // разрешаем все прерывания } #pragma vector = TIMER0_A0_VECTOR __interrupt void CCR0_ISR(void) //вектор прерывания для TACCR0, Таймера А { P1OUT |= BIT0; // устанавливаем нулевой бит в еденицу if (TACCR1>=(TACCR0-5)) // если TACCR1 больше TACCR0, то уменьшаем TACCR1 { indeX=1; } if (TACCR1<=5) // если TACCR1 меньше минимального значения, то увеличиваем TACCR1 { indeX=2; } if (indeX == 1) { --TACCR1; // уменьшаем TACCR1 на 1 } if ((indeX == 2) || (indeX == 0)) { ++TACCR1; // увеличиваем TACCR1 на 1 } } #pragma vector=TIMER0_A1_VECTOR __interrupt void CCR1_ISR(void) //вектор прерывания для TACCR1, Таймера А { P1OUT &= ~BIT0; // устанавливаем нулевой бит порта Р1 в ноль. TAIV &= ~TA0IV_TACCR1; //сбрасываем флаг прерывания. }

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