PIC. Урок 13. Модуль CCP. Режим сравнения

 

 

 

Продолжим изучения модулей CCP микроконтроллера PIC.

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

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

Режимов сравнения всего четыре и выбираем мы один из них посредством установки соответствующих битов в управляющий регистр CCPxCON. Это мы всё также видели на прошлом занятии.

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

Перед работой с проектом давайте посмотрим вообще принцип работы модуля CCP в режиме сравнения

 

 

По блок-схеме видно, что блок цифрового компаратора, расположенного в модуле CCP постоянно следит за регистровыми парами CCPRxH:CCPRxL и TMRxH:TMRxL и, как только данные пары совпадут, то компаратор подаст сигнал блоку Output Logic, который передаст сигнал триггеру специального события, конечно при условии, если тот включен. Также, если он включен, то запускается преобразование АЦП, если конечно АЦП также включен. Также триггер специального события должен будет сбросить регистр счёта таймера — TMR1. Дальше сигнал передаётся соответствующей ножке CCPx при условии, что включен определённый режим модуля, влияющий определённым образом на уровень данной ножки. Также данная ножка обязательно должна быть предварительно переведена в режим выхода. Ну, и, само собой, взводится флаг прерывания CCPxIF, который, как мы уже знаем, сам не сбросится, и сбросить его нужно будет программно.

Проект мы создадим из проекта прошлого занятия REMCONTROL_NEC и назовём его CCP_CMP.

Откроем наш проект в MPLAB X, назначим его главным и удалим из его дерева файлы lcd.c и lcd.h. с помощью пункта контекстного меню «Remove From Project«

 

 

Затем данные файлы также удалим физически с диска из папки с проектом.

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

Из файла main.h удалим объявление библиотеки

 

#include "lcd.h"

 

В файле main.c из функции main() уберём также инициализацию дисплея. Строковый массив нам тоже не потребуется

 

LCD_PORT_init();

LCD_Init();

char str1[21];

 

Удалим также весь код из бесконечного цикла.

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

Обработчик примет следующий вид

 

void interrupt isr(void)

{

  if(TMR1IE && TMR1IF)

  {

  }

  if(CCP1IF)

  {

  }

}

 

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

Попробуем собрать наш проект. Если всё нормально собралось, то значит мы проект подготовили и настроили. Что ж, начнём.

Идём в функцию main() и начнём немного менять инициализацию таймера и модулей. Таймер остаётся тот же — TIMER1.

Включим весь порт A на выход и инициализируем на всех его ножках низкий уровень

 

void main()

{

  TRISA=0X00;

  PORTA=0X00;

 

Мы будем использовать оба модуля, поэтому разрешим прерывания и от второго

 

CCP1IE=1;

CCP2IE=1;

 

Изменим режим работы модуля CCP1 на сравнение, такой же режим включим и для CCP2

 

CCP1CON=0X0A; //compare mode CCP

CCP2CON=0X0A;

 

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

 

CCP2CON=0X0A;

CCPR1 = 0x4000;

CCPR2 = 0x8000;

 

То есть первый модуль будет генерировать прерывание, когда таймер досчитает до четверти своего полного периода, а второй — до половины периода.

Сбросим флаг прерывания на втором модуле CCP

 

CCP1IF=0;

CCP2IF=0;

 

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

 

T1CKPS0=1; //Prescaler 8 (1000000/65536/8 ≈ 1,9 Hz)

T1CKPS1=1;

 

На всякий случай сбросим счётчик у таймера

 

TMR1CS=0;

TMR1=0x0000;

 

Перейдём в функцию обработки прерываний и в теле условия прерывания от таймера вставим следующий код

 

if(TMR1IE && TMR1IF)

{

  RA3=1;

  TMR1=0x0000;

  TMR1IF=0;

}

 

Мы установили высокий уровень на ножке RA3, сбросили счётчик таймера и сбросили флаг прерываний.

 

 

Теперь добавим следующий код в условие обработки прерываний от модуля CCP1

 

if(CCP1IF)

{

  RA1=1;

  CCP1IF=0;

}

 

Код аналогичный, только устанавливаем мы высокий уровень уже на ножке RA1 и сбрасываем также соответствующий флаг прерываний.

А модуль CCP2 будет уже управлять уровнем ножки RA2. Только код мы пока для него добавлять не будем. Для начала посмотрим предварительный результат, когда у нас обрабатываются только 2 вида прерываний.

Подключим ножки CH0-CH2 к соответствующим ножкам порта RA1-RA3, не забыв также об общем проводе (нажмите на картинку для увеличения изображения)

 

 

Соберём проект, прошьём контроллер и посмотрим график в программе логического анализа

 

 

Из графика мы видим, что прерывание от модуля CCP1 возникает как раз по прошествии четверти полного периода (0,5243:0.1311≈4) после прерывания от таймера, следовательно, и после начала счёта таймера.

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

Обработаем теперь также прерывание от модуля CCP2

 

    CCP1IF=0;

  }

  if(CCP2IF)

  {

    RA2=1;

    CCP2IF=0;

  }

}

 

Код также аналогичный, только вместо 1 везде пишем 2.

Соберём код, прошьём контроллер и посмотрим теперь результат работы нашей программы

 

 

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

Теперь давайте для модуля CCP2 включим режим c применением триггера специального события

 

CCP2CON=0X0B; //compare mode CCP with trigger special event

 

Соберём код, прошьём контроллер и посмотрим результат

 

 

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

Теперь давайте попробуем в процессе работы программы плавно порегулировать частоту наших импульсов.

Для этого добавим глобальную переменную периода CCP2

 

#include "main.h"

//------------------------------------------------

unsigned int per1;

 

В функции main() зададим начальное значение данной переменной, также зададим значение регистра CCPR1, равное половине данного значения, чтобы импульсы у нас были ровные (со скважностью 50 процентов). Также регистру CCPR2 присвоим значение нашей переменной

 

 

CCP2CON=0X0B; //compare mode CCP with trigger special event

 

per1 = 100;

 

CCPR1 = 50;

 

CCPR2 = per1;

 

CCPR1 = 0x4000;

 

CCPR2 = 0x8000;

 

Далее в обработчике прерывания в условии обработки прерывания от модуля CCP2 немного увеличим значение нашей глобальной переменной и присвоим его заново регистру CCPR2

 

RA2=1;

per1+=20;

CCPR2 = per1;

 

Также в этом же условии присвоим значение регистру CCPR1 первого модуля, равное половине значения регистра CCPR2

 

CCPR2 = per1;

CCPR1 = per1>>1; //Use the bit shift to divide by 2 to speed up the operation

 

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

 

CCPR1 = per1>>1;//Use the bit shift to divide by 2 to speed up the operation

if(per1>=2000) per1=80;

 

Соберём проект, прошьём контроллер и посмотрим результат (нажмите на картинку для увеличения изображения)

 

 

Мы чётко видим, что период плавно увеличивается, то есть для этого не надо заново инициализировать какие-то другие регистры, достаточно менять значения только в регистрах сравнения.

Таким образом, сегодня мы изучили ещё один режим работы модулей CCP — режим сравнения.

Всем спасибо за внимание!

 

Предыдущий урок Программирование МК PIC Следующий урок

 

Исходный код

 

 

Купить программатор (неоригинальный) можно здесь: PICKit3

Купить программатор (оригинальный) можно здесь: PICKit3 original

Отладочную плату PIC Open18F4520-16F877A можно приобрести здесь: PIC Open18F4520-16F877A

 

 

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

 

PIC Модуль CCP. Режим сравнения

Один комментарий на “PIC. Урок 13. Модуль CCP. Режим сравнения
  1. Ilyas:

    Здравствуйте… снимайте урок пожалуйста с микросхемам MT8870

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

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

*