Модуль сравнения (Output Compare) в dsPIC

реклама
6. Модуль сравнения (Output Compare) в dsPIC
6.1. Описание модуля сравнения
6.2. Пример использования модуля сравнения (пример в PROTEUS)
6.3. Пример режима ШИМ (пример в PROTEUS)
6.1. Описание модуля сравнения
Модуль сравнения работает совместно с таймером. В основном работа модуля
основана на сравнении значения регистра таймера со значением одного или двух
регистров модуля сравнения (в зависимости от режима работы модуля). Состояние на
выходном выводе данного модуля изменяется, когда значение таймера соответствует
значению в регистре сравнения. Модуль сравнения генерирует или одиночный импульс
или последовательность импульсов на выходе, изменяя состояние вывода в соответствии с
режимом работы. Данный модуль может также сгенерировать прерывание.
Для работы модуля сравнения используются следующие регистры:
• OCxCON: Регистр управления модулем сравнения
• OCxR: Регистр модуля сравнения
• OCxRS: Второй регистр модуля сравнения
Microchip рекомендует: Если необходимо произвести изменения в регистре управления,
то необходимо модуль сравнения сперва отключить. После установить нужные
значения, а в последнюю очередь снова включить модуль сравнения.
Рисунок 1. Блок схема модуля сравнения
Примечание
1. Разные dsPIC33F имеют разное количество модулей сравнения. Каждый модуль
сравнения может использовать для сравнения со значением таймера 2 или таймера 3.
2. ‘x’, - используется в обозначении, для того, чтобы обозначить определённый модуль
сравнения (x = 1 - 8).
3: ‘y’,- используется в обозначении, для того, чтобы обозначить определённый таймер (y
= 2 или 3).
Выбор Таймера
Модуль сравнения может выбирать, с каким таймером он будет связан. Или это
будет Timer2 или Timer3. Таймер выбирается с помощью бита OCTSEL в регистре
управления модулем сравнения (OCxCON <3>).
Выбранный таймер начинает счёт с нуля и продолжает считать, пока не достигнет
значения в регистре (PRy). Когда значение периода достигнуто, таймер сбрасывается и
начинает счёт заново. Таймеры могут тактироваться как внутренней тактовой частотой,
так и внешними импульсами, приходящими на вход TxCK.
Microchip рекомендует: Если необходимо записать значение в регистр модуля
сравнения, то необходимо сперва отключить работу связанного таймера. После
записать новое значение в регистр. А таймер включить в последнюю очередь.
Режимы работы модуля сравнения
Для выбора определённого режима работы модуля сравнения используются биты
(OCM <2:0>) регистра управления (OCxCON <2:0>). Таблица 1 показывает перечень
различных режимов работы модуля сравнения. На рисунке 2 показана работа модуля
сравнения для различных режимов.
OCM
<2:0>
000
001
010
011
100
101
110
111
Таблица 1. Режимы работы модуля сравнения
На выходе OCx
Режим работы
Генерирование прерывания OCx
инициализ.
Модуль отключён
Режим одиночного
переключения с активным
0
Передний фронт на OCx
низким уровнем
Режим одиночного
переключения с активным
1
Задний фронт на OCx
высоким уровнем
Режим переключения
Текущее
И по заднему и по переднему
состояние
фронту на OCx
Режим одиночного импульса
0
По заднему фронту на OCx
Режим непрерывных
0
По заднему фронту на OCx
импульсов
ШИМ режим без защиты от
0, если OCxR = 0
ошибки
1, если OCxR <>
Не вызывает прерывания
0
ШИМ режим с защитой от
OCFA Задний фронт для OC1 к
0, если OCxR = 0
ошибки
OC4
1, если OCxR <>
OCFB задний фронт для OC5 к
0
OC8
Рисунок 2. Работа модуля сравнения в различных режимах
1) Режим одиночного переключения с активным низким уровнем
Режим одиночного переключения с активным низким уровнем обеспечивает один
импульс, в котором активным является низкий уровень. Продолжительность импульса
определяется значением регистра модуля сравнения (OCxR). Так как переключение
является одиночным, то, чтобы заново включить данный режим, необходимо перезаписать
регистр управления (OCxCON).
На рисунке 3 показана работа модуля сравнения в режиме одиночного
переключения с активным низким уровнем.
Пример 1 показывает, как в программе настроить модуль сравнения, в частности
данный режим.
Рисунок 3 режим одиночного переключения с активным низким уровнем
1. Включается режим одиночного переключения с активным низким уровнем, вывод OCx
немедленно переводится в низкий уровень.
2. Включается таймер. Он начинает считать.
3. Значение таймера равно значению регистра модуля сравнения, Вывод OCx переходит в
высокий уровень, и устанавливается флаг прерывания.
Пример 1. Настройка модуля сравнения
// Инициализация модуля сравнения
OC1CONbits.OCM = 0b000;
// Отключаем модуль сравнения
OC1CONbits.OCTSEL = 0;
// Выбираем таймер 2 для работы с модулем сравнения
OC1R = 100;
// Загружаем значение в регистр модуля сравнения
IPC0bits.OC1IP = 0x01; // Устанавливаем приоритет модуля сравнения 1
IFS0bits.OC1IF = 0;
// Сбрасываем флаг прерывания модуля сравнения 1
IEC0bits.OC1IE = 1;
// Разрешаем прерывание модуля сравнения 1
OC1CONbits.OCM = 0b001;
// Выбираем нужный режим работы модуля сравнения
// … Также необходимо провести настройку и запуск таймера 2 (не приводится здесь)
/* Обработка прерывания модуля сравнения 1*/
void __attribute__((__interrupt__)) _OC1Interrupt( void )
{
/* Здесь должен быть код, который будет выполнен после прерывания */
IFS0bits.OC1IF = 0; // Сбрасываем флаг прерывания OC1
}
2. Режим одиночного переключения с активным высоким уровнем
Режим одиночного переключения с активным высоким уровнем обеспечивает один
импульс, в котором активным является высокий уровень. Продолжительность импульса
определяется значением регистра модуля сравнения (OCxR). Импульс может быть вызван
снова, только перезаписав регистр управления (OCxCON).
Рисунок 4 режим одиночного переключения с активным высоким уровнем
1. Включается режим одиночного переключения с активным высоким уровнем, вывод
OCx немедленно переводится в высокий уровень.
2. Включается таймер. Он начинает считать.
3. Значение таймера равно значению регистра модуля сравнения, Вывод OCx переходит в
низкий уровень, и устанавливается флаг прерывания.
3. Режим переключения
Данный режим, при равенстве значения таймера и регистра модуля сравнения,
изменяет состояние на выходе OCx. Т.е. если там был «0», то станет «1» или наоборот.
Модуль сравнения генерирует прерывание, как по переднему фронту, так и по заднему
фронту сигнала на выводе OCx.
Для установки начального состояния как «1» - необходимо перед включением
«режима переключения» задать «режим одиночного переключения с активным высоким
уровнем», а затем уже «режим переключения»
Для установки начального состояния как «0» - необходимо перед включением
«режима переключения» задать «режим одиночного переключения с активным низким
уровнем», а затем уже задать «режим переключения»
Рисунок 5. Работа модуля сравнения в режиме переключения
1. Включается «режим переключения», состояние вывода OCx не изменяется.
2. Включается таймер. Он начинает считать.
3. Значение таймера равно значению регистра модуля сравнения, Вывод OCx
переключается в противоположное состояние, и устанавливается флаг прерывания.
Частный случай: Для режимов:
- Режим одиночного переключения с активным низким уровнем
- Режим одиночного переключения с активным высоким уровнем
- Режим переключения
Если значение регистра OCxR равно 0, то переключение произойдёт только на втором
цикле таймера. Смотреть даташит.
4. Режим одиночного импульса
Режим одиночного импульса производит одиночный импульс. Этот импульс
формируется (передний фронт), когда значение связанного таймера станет равным
значению регистра модуля сравнения (OCxR). Ширина импульса определяется вторым
регистром модуля сравнения (OCxRS). Т.е. когда значение таймера будет равно значению
второго регистра модуля сравнения (OCxRS), то импульс завершится (задний фронт).
Импульс может быть вызван снова, только перезаписав регистр управления (OCxCON).
Модуль сравнения прекращает дальнейшие сравнения пока заново не будет
переназначен данный режим в регистре управления.
Рисунок 6. Режим одиночного импульса
1. Включается режим одиночного импульса, на выводе OCx немедленно устанавливается
низкий уровень.
2. Включается таймер. Он начинает считать.
3. Значение таймера равно значению регистра модуля сравнения, На выводе OCx
устанавливается высокий уровень.
4. Значение таймера равно значению второго регистра модуля сравнения, На выводе OCx
устанавливается низкий уровень. Устанавливается флаг прерывания.
5. Режим непрерывных импульсов
Режим непрерывных импульсов обеспечивает импульсы на каждом цикле таймера.
Этот режим полезен для генерирования импульсов фиксированной ширины. На рисунке 7
показана блок схема модуля сравнения в режиме непрерывных импульсов. Рисунок 8
показывает работу модуля сравнения в режиме непрерывных импульсов.
Рисунок 7. Блок схема модуля сравнения в режиме непрерывных импульсов
Рисунок 8. Работа в режиме непрерывных импульсов
1. Включается режим непрерывных импульсов, на выводе OCx немедленно
устанавливается низкий уровень.
2. Включается таймер. Он начинает считать.
3. Значение таймера равно значению регистра модуля сравнения, На выводе OCx
устанавливается высокий уровень.
4. Значение таймера равно значению второго регистра модуля сравнения, На выводе OCx
устанавливается низкий уровень. Устанавливается флаг прерывания.
Частный случай: Для правильной работы модуля сравнения в режиме одиночного
импульса и режиме непрерывных импульсов, значения в регистрах модуля сравнения
OCxR, OCxRS должны удовлетворять следующим условиям:
• OCxRS ≥ OCxR
• PRy >= OCxRS
Когда значения регистра модуля сравнения равно нулю (OCxR = 0), тогда сравнение
происходит только на следующем цикле таймера.
6. ШИМ режим без защиты от ошибки
ШИМ режим используется, чтобы генерировать импульсы переменной
длительностью. Длина импульса ШИМ устанавливается через второй регистр модуля
сравнения (OCxRS), а уже автоматически это значение попадёт в регистр (OCxR). В ШИМ
режиме, регистр модуля сравнения (OCxR) только для чтения. На рисунке 9 приведена
блок схема модуля сравнения в режиме ШИМ.
Рисунок 9. Блок схема модуля сравнения в режиме ШИМ
Рисунок 10. Работа в режиме ШИМ
1. Ширина первого импульса ШИМ должна быть записана непосредственно в регистр
OCxR до включения режима работы ШИМ (т.е. пока ещё можно записывать в данный
регистр).
2. Ширина второго импульса ШИМ должна быть записана в регистр OCxRS.
3. Включаем режим ШИМ, OCx вывод переводится в низкий уровень если OCxR =0. Или
вывод OCx переводится в высокий уровень если OCxR <> 0.
4. Включается таймер и начинает счёт.
5. Когда значение таймера и регистра OCxR сравняется - на выводе OCx устанавливается
низкий уровень.
6. Когда значение таймера достигает значения периода, то таймер обнуляется.
Одновременно с этим значение из регистра OCxRS загружается в регистр OCxR. Вывод
OCx переводится в высокий уровень, если OCxR =0 или вывод OCx переводится в
низкий уровень, если значение OCxR <> 0.
7. В регистр OCxRS можно записывать новое значение периода.
Период PWM
Период ШИМ определяется значением регистра PRy, и значением предделителя
TMRy.
Период ШИМ = [(PRy) + 1] • TCY • (Значение предделитель TMRy)
Частота ШИМ = 1/[ШИМ период]
Ширина импусльса ШИМ
Чтобы установить определённую ширину импульса ШИМ необходимо записать
значения в регистр OCxRS. Значение ширины импульса может быть записано в любое
время, однако данное значение будет скопировано в регистр OCxR только после того как
таймер обнулится. Тем самым обеспечивается двойной буфер для записи ширины
импульса ШИМ и позволяет на лету менять значение ширины импульса.
Некоторые важные граничные параметры для ширины импульса приведены ниже:
• если регистр ширины импульса OCxR, загружен нулевым значением, то вывод OCx
останется в низком уровне (ширина импульса - 0 %)
• если значение регистра ширины импульса OCxR содержит значение больше чем
значение периода таймера (PRy), то на выводе OCx останется высокий уровень (ширина
импульса - 100%)
• если значение регистра ширины импульса OCxR равно значению регистра периода
(PRy), то вывод OCx на одном периоде будет низким уровнем, а на другом будет в
высоком уровне.
Разрешение ШИМ (количество разных значений ширины импульса, которые
можно получить) зависит от самой частоты ШИМ и от частоты счёта таймера. Частота
счёта таймера – это частота (FCY) делённая на значение предделителя. Для
дополнительной информации смотреть документацию на dsPIC «раздел 11. Таймеры».
7. ШИМ режим с защитой от ошибки
Когда включается режим ШИМ с защитой от ошибки, то модуль сравнения
работает также как и в режиме без защиты от ошибки. Кроме этого, добавляется
дополнительный вход для контроля ошибки.
Защита от ошибки обеспечивается с помощью выводов OCFA и OCFB. Вывод
OCFA связан с модулями сравнения 1 - 4, а вывод OCFB связан с модулями сравнения 5 8.
Если на выводе OCFA/OCFB обнаружится логический «0», то вывод выбранного
модуля сравнения переходит в третье состояние и устанавливается флаг ошибки (OCFLT)
регистра управления (OCxCON <4>). Это событие установит флаг прерывания (OCxIF) и
если разрешено прерывание, то оно происходит.
Для большей информации смотреть даташит.
6.2. Пример использования модуля сравнения
Рассмотрим пример работы модуля сравнения в режиме одиночного переключения
с активным низким уровнем. Предположим по нажатию на кнопку нам необходимо
запустить два электродвигателя. Причём первый двигатель нам нужно запустить сразу, а
второй через определённое время. Ниже приведена схема в PROTEUS
Конечно, данную задачу можно решить с помощью одного таймера, и по
прерыванию запустить второй двигатель, т.е. это самое логическое решение. Однако для
примера мы эту задачу решим при помощи модуля сравнения. Будем использовать один
таймер (TMR2) для того, чтобы вести счёт. Нужное время для запуска второго двигателя
мы заносим в регистр модуля сравнения OC1R. И как только значение таймера будет
равно сравниваемому значению, то на выходе модуля сравнения установится высокий
уровень. Именно к этому выходу мы и подключили второй двигатель.
#include "p33Fxxxx.h"
// Устанавливаем биты настройки генератора (HS)
_FOSCSEL(0x02);
_FOSC(0xE2);
void init (void);
//объявляем подпрограмму инициализации
// ********** подпрограмма инициализация **********
void init (void)
{ _CN1PUE=1;
//включаем подтягивающий резистор на вход CN1
AD1PCFGL=0xffff;
// все выводы как цифровые I/O
PORTB=0;
LATB=0;
TRISB=0x0001;
PORTB=0x0;
//устанавливаем RB0 как вход, остальные все выводы на выход
TMR2=0;
// Инициализация модуля сравнения
OC1CONbits.OCM = 0b000;
// Отключаем модуль сравнения
OC1CONbits.OCTSEL = 0;
// Выбираем таймер 2 для работы с модулем сравнения
OC1R = 0x7000;
// Загружаем значение в регистр модуля сравнения
IPC0bits.OC1IP = 0x03;
// Устанавливаем приоритет модуля сравнения 1
IFS0bits.OC1IF = 0;
// Сбрасываем флаг прерывания модуля сравнения 1
IEC0bits.OC1IE = 1;
// Разрешаем прерывание модуля сравнения 1
OC1CONbits.OCM = 0b001;
// Выбираем режим работы "одиночного
// переключения с активным низким уровнем"
// настраиваем таймер, для периодического опроса таймера TMR3, для организации бегущего огня
T2CONbits.TON=0;
//Таймер 2 выключен,
T2CONbits.TCS=0;
//тактовый сигнал внутренний,
T2CONbits.TGATE=0; // отключаем режим GATE
T2CONbits.TCKPS=0b11; // предделитель устанавливаем 1:256
PR2=0xFFFF;
// Заносим значение периода
RPOR4bits.RP9R=0b10010;
RPINR0=0x0000;
_INT1EP=1;
_INT1IE=1;
// Настраиваем выход компоратора 1
// это вывод PR9
// сигнал INT1 настраиваем, чтобы снимать с вывода RP0
// прерывание INT1 происходит по заднему фронту
// разрешаем прерывание INT1
}
// ************ Точка входа в программу *************************
void main (void)
{
init();
// вызываем подпрограмму инициализации
while(1)
// запускаем бесконечный цикл
{ ClrWdt();
// Все действия реализованы в прерываниях
Nop();
} // while(1)
}
//***** обработка прерывания INT1 ******* (кнопка START)
void __attribute__( (__interrupt__) ) _INT1Interrupt()
{
_RB4=1;
// запускаем первый двигатель
T2CONbits.TON=1;
//Включаем таймер 2,
_INT1IF=0;
// сбрасываем флаг прерывания INT1
}
// ****** обработка прерывания модуля сравнения *******
void __attribute__((__interrupt__)) _OC1Interrupt( void )
{
T2CONbits.TON=0;
//Отключаем таймер 2
_INT1IE=0;
// запрещаем прерывание INT1
IFS0bits.OC1IF = 0;
// Сбрасываем флаг прерывания OC1
}
6.3. Пример режима ШИМ
Для ознакомления с режимов ШИМ возьмём простой пример. Пусть у нас имеется
двигатель, скорость которого мы будем задавать с помощью ШИМ. Скорость будем
увеличивать и уменьшать при помощи кнопок.
Собираем схему в PROTEUS
Мы с помощью кнопок будем либо увеличивать ширину импульса, либо её уменьшать. А
чем шире импульс, тем больше скорость двигателя. Для контроля ширины импульса мы
также подключили к управляющему выходу осциллограф. Всё элементарно просто,
переходим к тексту программы.
#include "p33Fxxxx.h"
// Устанавливаем биты настройки генератора (HS)
_FOSCSEL(0x02);
_FOSC(0xE2);
void init (void);
//объявляем подпрограмму инициализации
// ********** подпрограмма инициализация **********
void init (void)
{
_CN1PUE=1;
//включаем подтягивающий резистор на вход CN1
_CN4PUE=1;
//включаем подтягивающий резистор на вход CN4
AD1PCFGL=0xffff;
// все выводы как цифровые I/O
// Инициализация модуля сравнения
OC1CONbits.OCM = 0b000;
// Отключаем модуль сравнения
OC1CONbits.OCTSEL = 0; // Выбираем таймер 2 для работы с модулем сравнения
OC1R = 0x0001;
// Загружаем значение в регистр модуля сравнения
OC1RS = 0x0001;
// Загружаем значение в регистр модуля сравнения
IPC0bits.OC1IP = 0x03; // Устанавливаем приоритет модуля сравнения 1
IFS0bits.OC1IF = 0;
// Сбрасываем флаг прерывания модуля сравнения 1
IEC0bits.OC1IE = 1;
// Разрешаем прерывание модуля сравнения 1
OC1CONbits.OCM = 0b110;
// Выбираем режим работы "ШИМ без контроля ошибки"
// настраиваем таймер, для периодического опроса таймера TMR3, для организации бегущего огня
T2CONbits.TON=0;
//Таймер 2 выключен,
T2CONbits.TCS=0;
//тактовый сигнал внутренний,
T2CONbits.TGATE=0;
// отключаем режим GATE
T2CONbits.TCKPS=0b00; // предделитель устанавливаем 1:1
PR2=0x0F00;
// Заносим значение периода
T2CONbits.TON=1;
//Таймер 2 включён,
PORTB=0;
LATB=0;
TRISB=0x0011;
PORTB=0x0;
//устанавливаем RB0 и RB4 как вход, остальные все выводы на выход
RPOR5bits.RP11R=0b10010; // Настраиваем выход, с которого будем снимать ШИМ сигнал
// это вывод PR11
RPINR0=0x0000;
// сигнал INT1 настраиваем, чтобы снимать с вывода RP0 (увеличить)
_INT1EP=1;
// прерывание INT1 происходит по заднему фронту
_INT1IE=1;
// разрешаем прерывание INT1
RPINR1=0x0004;
// сигнал INT2 настраиваем, чтобы снимать с вывода RP4 (уменьшить)
_INT2EP=1;
// прерывание INT2 происходит по заднему фронту
_INT2IE=1;
// разрешаем прерывание INT2
}
// ************ Точка входа в программу *************************
void main (void)
{
init();
// вызываем подпрограмму инициализации
while(1)
// запускаем бесконечный цикл
{ ClrWdt();
// Все действия реализованы в прерываниях
} // while(1)
}
//***** обработка прерывания INT1 ******* (кнопка увеличить)
void __attribute__( (__interrupt__) ) _INT1Interrupt()
{
if ((OC1RS+0x0200)<0x0F00)
// если можно увеличивать ширину импульса, то
OC1RS = OC1RS+0x0200;
// Увеличиваем длину импульса ШИМ
_INT1IF=0;
// сбрасываем флаг прерывания INT2
}
//***** обработка прерывания INT2 ******* (кнопка уменьшить)
void __attribute__( (__interrupt__) ) _INT2Interrupt()
{
if ((OC1RS-0x0200)>=0x0001)
// если можно уменьшать ширину импульса, то
OC1RS = OC1RS-0x0200;
// Уменьшаем длину импульса ШИМ
_INT2IF=0;
// сбрасываем флаг прерывания INT2
}
Данная программа упрощена, так что при желании можете добавить некоторые
ограничения, чтобы ширина импульса не сбивалась в момент её понижения. В данном
примере я хотел показать, что ширина импульса изменяется только одним оператором.
Мотькин Игорь Сергеевич,
Республика Беларусь, г. Гомель,
+375 (29) 736-67-41
[email protected]
Скачать