Создать сайт
Практическое руководство по программированию STM8. Урок №1. “Привет, светодиод!”, часть 2.. Раздел: STM8.

Eugene's MCU

Пятница, 13.07.2012, 01:47

Главная | | Мой профиль | Выход | RSS
Меню сайта
Категории каталога
Рекламный блок





Рекомендовать этот сайт:

Главная » Статьи » » STM8


Практическое руководство по программированию STM8. Урок №1. “Привет, светодиод!”, часть 2.
     
     В предыдущей статье мы остановились на использовании таймера для отсчета временных задержек, далее мы рассмотрим, как можно реализовать задержки с помощью прерываний, что позволит программе выполнять полезную работу вместо ожидания окончания счета. Контроллер прерываний (ITC) имеет 32 вектора прерывания от периферийных устройств. Каждому вектору может быть задан уровень приоритета от 0 (низший) до 3 (высший). По умолчанию всем векторам присвоен уровень 0. В нашем примере изменять уровень приоритета не нужно, поэтому дополнительная инициализация ITC не нужна.
Для отсчета задержки будем использовать уже знакомый нам 8-разрядный таймер TIM4. Таймер может вырабатывать прерывания по переполнению счетчика. Прерывание должно вырабатываться циклически, поэтому будем использовать таймер в режиме циклического счета с автозагрузкой при переполнении. Данный режим отличается тем, что запись начального значения счетчика производится один раз в регистр автозагрузки TIM4_ARR, причем записывается в него не само начальное значение счетчика, а число импульсов до сброса в 0, т.е. формула приобретает вид:
 
     X = Fclk / (2n / T),
 
     где Fclk – частота на выходе блока CLK,
     n – значение регистра предделителя (для TIM4 может быть от 0 до 7),
     T – время задержки.
     Данное представление более наглядно (фактически мы записываем коэффициент деления входной частоты), однако в документации на таймер эта особенность не описана, что поначалу ввело меня в заблуждение, разобраться удалось только после изучения исходного текста библиотеки сенсорных кнопок от ST Microelectronics.
Запросы на прерывание разрешаются установкой бита UIE в регистре TIM4_IER, для того, чтобы не произошло неожиданного прерывания сразу после его разрешения, сбросим флаг генерации прерывания UIF в регистре TIM4_SR.
     Таким образом, инициализация таймера примет вид:
 
     //Инициализируем TIM4
     TIM4_SR_bit.UIF=0;        //Сбросим признак прерывания
     TIM4_PSCR=0x07;           //Предделитель на 2^7=128   16000000/128 = 125000 Hz
     TIM4_ARR=250;             //Регистр автозагрузки таймера при переполнении 125000 / 250 = 500 Hz
     TIM4_IER_bit.UIE=1;       //Разрешаем генерацию прерывания при переполнеини
     TIM4_CR1_bit.CEN=1;       //Разрешаем счет
 
     Введем в текст программы, перед функцией main() обработчик прерывания таймера. Те, кто знаком со средой IAR для AVR могут заметить, что синтаксис описания векторов совпадает, за исключением имен векторов. Вектора для нашего МК описаны в файле iostm8s105s6.h.
  
     #include "intrinsics.h"     //Здесь описана функция __enable_interrupt()
     char Timer1;
     #pragma vector=TIM4_OVR_UIF_vector
     __interrupt void TIM4_OVR_UIF(void)
     {
          TIM4_SR_bit.UIF=0;        //Сбросим признак прерывания
          if(Timer1) Timer1--;      //Программный таймер
     }
  
     Первое, что необходимо сделать в любом обработчике прерывания – это сбросить флаг прерывания на устройстве, которое вызвало прерывание. В противном случае, при выходе из обработчика прерывания мы вновь в него попадем. Далее, мы можем выполнить необходимые действия по обслуживанию прерывания – в нашем случае декрементировать программный счетчик.
     Основной цикл функции main() запишем следующим образом:
  
     __enable_interrupt();     //Разрешаем прерывания
     //Собственно мигание
     Timer1=250;               //500 / 250 = 2 Hz (500 мс)
     while(1)
     {
          if(!Timer1)             //Прошло 500 мс?
          {
               Timer1=250;           //500 / 250 = 2 Hz (500 мс)
               PD_ODR_bit.ODR0=~PD_ODR_bit.ODR0;        //Изменим состояние светодиода
          }
     //Здесь можно добавить другие действия
     }
 
     В строчке if(!Timer1) мы проверяем прошло ли заданное нами число прерываний с момента присвоения начального значения переменной Timer1. Прерывания в нашем примере вызываются с частотой 500Гц, значит, с учетом коэффициента деления Timer1 светодиод будет изменять свое состояние раз в 500 мс, что дает нам частоту мигания 1 Гц.
Запишем получившуюся программу (проект LED-03) в МК и проверим результат работы.
      Данный пример является простейшим генератором временной шкалы. Чтобы выполнять какие-либо действия с определенной периодичностью необходимо добавить в обработчик прерывания конструкции вида:
   
     if(Timer2) Timer2--;
     …
     if(TimerN) TimerN--;
  
     не забывая при этом объявить глобальные переменные TimerN. А в главный цикл функции main() необходимо ввести обработчики событий вида:
 
     if(!Timer2)
     {
          Timer2=100;           //500 / 100 = 5 Hz  (200мс)
          //Выполним какие-либо действия
     }     
     
     if(!TimerN)
    {
          TimerN=50;           //500 / 100 = 10 Hz (100 мс)
          //Выполним какие-либо действия
     }
  
     Количество обработчиков событий зависит от числа используемых в программе периодических временных интервалов. Каждый обработчик в общем случае является независимым от других. В последующих уроках мы также будем использовать данные конструкции для выполнения периодических действий.
 
     Следующий пример демонстрирует использование возможностей 16-разрядного таймера для генерации сигналов с заданным периодом и длительностью. На плате Discovery вывод PD0 имеет альтернативную функцию – выход канала сравнения таймера TIM3_CH2, что позволяет нам наглядно исследовать некоторые возможности данного канала. За основу возьмем проект LED-01 из первой части статьи. Оставим в нем только инициализацию CLK. Основной цикл запишем просто в виде:
 
     while(1);
 
     т.е. программа, дойдя до этого места, просто зациклится. За счет чего же будет изменяться состояние светодиода? Да за счет импульсов с выхода канала сравнения таймера. Канал имеет несколько различных режимов, определяемых битами OC2M регистра TIM3_CCMR2. Возможны следующие значения:
  
     0x00 – Заморожено – состояние выхода канала сравнения не меняет состояние вывода МК
     0x01 – Активный уровень при совпадении – при совпадении значений регистров канала сравнения и счетчика на выход передается 1
     0x02 – Неактивный уровень при совпадении – при совпадении значений регистров канала сравнения и счетчика на выход передается 0
     0x03 – Изменить состояние выхода при совпадении.
     0x04 – Установить выход в 0 постоянно
     0x05 – Установить выход в 1 постоянно
     0x06 – режим 1 ШИМ – выход в 1, пока TIM3_CNTR < TIM3_CCR2
     0x07 – режим 2 ШИМ – выход в 0, пока TIM3_CNTR < TIM3_CCR2
  
     Для решения нашей задачи мигания светодиодом, наиболее подходящим является режим 0x03, в этом случае, значение регистра TIM3_CCR2 может быть любым, но должно выполняться условие TIM3_CCR2 < TIM3_ARR. Универсальным решением будет задание TIM3_CCR2=0, данное значение записывается в регистр при сбросе МК. Для того, чтобы сигнал с выхода канала сравнения CH2 попал на физический вывод МК, необходимо установить бит CC2E в регистре  TIM3_CCER1.
     Таймер TIM3 является 16-битным и, аналогично TIM4 имеет те же основные функциональные узлы - счетчик со схемой автозагрузки, регистры управления, состояния, разрешения прерываний. Названия регистров и битов, выполняющих аналогичные функции, совпадают. Различия заключаются в том, что регистры, связанные со значением счетчика TIM3_CNTR, TIM3_ARR, TIM3_CCR1, TIM3_CCR2 представлены в виде пары 8-битных регистров xxxRH и xxxRL каждый. При записи в такие регистры всегда сначала записывается старший байт, затем младший. Изменение значения 16-битного регистра происходит только после записи младшего байта. Для расчета значения регистра TIM3_ARR можно использовать ту же формулу, что и для TIM4, только значение регистра предделителя n может находиться в диапазоне от 0 до 15, а диапазон выходных значений X расширяется до 65535.
     Теперь мы можем записать в нашу программу перед вызовом бесконечного цикла код инициализации для TIM3:
     //Инициализируем TIM3. Светодиод подключен на TIM3_CH2
     TIM3_PSCR=0x08;           //Предделитель 16000000 / 256 = 62500 Hz
     TIM3_ARRH=0x7A;           //Автозагрузка счетчика старший байт 31250 = 0x7A12
     TIM3_ARRL=0x12;           //Автозагрузка счетчика младший байт
     TIM3_CCER1_bit.CC2E=1;    //Разрешаем выход CH2
     TIM3_CCMR2_bit.OC2M=0x03; //Режим изменения состояния выхода при совпадении
     TIM3_CR1_bit.CEN=1;       //Разрешаем счет
 
     Остается записать нашу программу (проект LED-04) в МК и увидеть тот же самый результат, что и в двух предыдущих примерах, однако программа в это время выполняет пустой цикл, в который можно вписать любые необходимые действия, в том числе, с использованием прерываний и временной шкалы.
     Данный метод генерации импульсов может использоваться для получения сигналов прямоугольной формы с заданной частотой (например, звуковых). Включение и выключение сигнала может производиться изменением бита CC2E регистра TIM3_CCER1.
     Следующий пример (проект LED-05) иллюстрирует использование канала сравнения в режиме ШИМ для управления яркостью свечения светодиода. Он объединяет в себе два предыдущих. Таймер TIM4 используется для генерации временной шкалы, TIM3 - управляет светодиодом. Для перевода канала TIM3_CH2 в режим ШИМ, запишем в поле OC2M регистра TIM3_CCMR2 значение режима 0x06. Чтобы зависимость яркости свечения от значения в регистре TIM3_CCR2 была прямой, включим инверсию выхода (не забываем, что светодиод светится при низком уровне на выходе) установкой бита CC2P в регистре TIM3_CCER1. Несущая частота ШИМ должна быть достаточно высокой (обычно более 30Гц), чтобы не наблюдалось мерцание светодиода. При аппаратной генерации мы можем получить максимальную частоту Fшим = 16000000 / 65535 =  244Гц, что вполне достаточно для нашего случая. Производитель также рекомендует в режиме ШИМ включать буферизацию записи в регистры TIM3_ARR и TIM3_CCR2, чтобы обновление значений производилось автоматически в момент окончания счета. Для этого нужно установить бит ARPE в регистре TIM3_CR1 и OC2PE в регистре TIM3_CCMR2.
     Таким образом, код инициализации TIM3 примет вид:
 
     //Инициализируем TIM3. Светодиод подключен на TIM3_CH2
     CLK_PCKENR1|=0x40;        //Разрешаем подачу Clock на TIM3
     TIM3_CR1_bit.ARPE=1;      //Разрешаем буферизацию ARR
     TIM3_CCMR2_bit.OC2PE=1;   //Разрешаем буферизацию CCR2
     TIM3_PSCR=0x00;           //Предделитель 16000000 / 1 = 16000000 Hz
     TIM3_ARRH=0xFF;       //Автозагрузка счетчика старший байт 16000000 / 65535 = 244 Hz
     TIM3_ARRL=0xFF;           //Автозагрузка счетчика младший байт
     TIM3_CCER1_bit.CC2E=1;    //Разрешаем выход CH2
     TIM3_CCER1_bit.CC2P=1;    //Включим инверсию CH2 (светодиод горит при CH2=0)
     TIM3_CR1_bit.CEN=1;       //Разрешаем счет
 
     Для управления яркостью достаточно изменять  старший 8-битный регистр сравнения TIM3_CCR2H от 0 до 255, но нужно помнить, что для изменения значения 16-битного регистра обязательно нужно записать что-либо в регистр TIM3_CCR2L.
     Изменения в регистре TIM3_CCR2 производятся в основном цикле программы с использованием временной шкалы на базе TIM4. Отличие от примера из проекта LED-03 заключается в том, что значение частоты прерываний выбирается кратным 256, поскольку цикл изменения яркости в одну сторону содержит 256 итераций, а для полного цикла мигания потребуется 512 итераций, следовательно, чтобы полный цикл продолжался 1 секунду, частота прерываний должна быть равна 512 Гц.
     Для этого изменим в инициализации TIM4 значение регистра TIM4_ARR:
 
     TIM4_ARR=244; //Регистр автозагрузки таймера при переполнении 125000 / 244 = 512,2 Hz
 
     Основной цикл программы будет выглядеть следующим образом:
     __enable_interrupt();     //Разрешаем прерывания
     //Собственно мигание
     char i=0;
     char flag=0;
     Timer1=1;                   //512 / 1 = 512 Hz
     while(1)
     {
          if(!Timer1)               //Прошло 500 мс?
          {
               Timer1=1;               //512 / 1 = 512 Hz
               TIM3_CCR2H=i;           //Пишем длительность импульса в регистр сравнения
               TIM3_CCR2L=0x00;
               if(!flag)               //Флаг направления счета
               {
                       if(++i==255) flag=1;  //Увеличение длительности
               }
               else
               {
                    if(--i==0) flag=0;    //Уменьшение длительности
               }
          }
     }
 
     В переменной i организован реверсивный 8-битный счетчик, направление счета которого определяется переменной flag. Значение счетчика изменяется с частотой 512Гц и записывается в регистр сравнения TIM5, изменяя скважность импульсов на выходе канала ШИМ, что приводит к изменению яркости свечения светодиода.
     Запишем получившуюся программу (проект LED-05) в МК и увидим результат – яркость светодиода циклически изменяется от максимальной до минимальной.
     На практике режим ШИМ может быть применен в светодиодных светильниках, для регулировки яркости светодиодных табло, для воспроизведения речевых сообщений (в этом случае необходимо повысить несущую частоту ШИМ за счет уменьшения числа задействованных разрядов счетчика до 8-10).
     Еще большие возможности предоставляет многофункциональный таймер TIM1. Он имеет 4 канала сравнения с реверсивными счетчиками, каждый канал имеет прямой и инверсный выход с возможностью программирования задержки deadtime, что дает возможность управлять двухтактными силовыми ключами, работающими на индуктивную нагрузку. Все возможности TIM1 будут рассмотрены позднее, в рамках отдельной статьи.
     Мы рассмотрели некоторые возможности МК STM8S105 на плате Discovery, которые можно было изучить на практике, не прибегая к помощи паяльника. Еще на данной плате расположена сенсорная кнопка, состояние которой тоже можно узнать с помощью данного МК. Это и будет темой следующего урока. Для проведения экспериментов с МК, которые будут рассматриваться в последующих статьях, Вы можете вооружиться паяльником и добавить к Discovery недостающие элементы или приобрести плату STM8_QS на нашем сайте.
   
     Коды к статье под IAR >> STM8_001_02.zip
     Коды с использованием заголовков библиотеки от ST (main.c компилируется на Cosmic,
     Raisonance, IAR). >> STM8_001_STLIB.zip
     (!) Для Cosmic не забудьте поместить код обработчика прерывания из примера в файл
     stm8s_it.c
 


При использовании материалов сайта ссылка на данный источник обязательна.

Категория: STM8 | Добавил: EugenyAM (10.11.2010) | Автор: Евгений Монастырёв

Просмотров: 6148 | Рейтинг: 5.0/3 |
Статистика

Наш магазин




Какую среду разработки Вы используете?

[ Результаты · Архив опросов ]
Всего ответов: 925



Им нужна Ваша помощь: