|
@@ -0,0 +1,467 @@
|
|
|
+Сам таймер 24 разрядный. И тикает вниз от предзагруженного значения до
|
|
|
+нуля, после чего перезагружается вновь и генерирует прерывание.
|
|
|
+Источником тактирования является системная тактовая частота SYSCLK, либо
|
|
|
+та же частота, но поделенная на 8 – SYSCLK/8.
|
|
|
+
|
|
|
+Управляется он четырьмя регистрами:
|
|
|
+0xE000E010 SYST_CSR RW SysTick control and status register
|
|
|
+0xE000E014 SYSCT_RVR RW SysTick reload value register
|
|
|
+0xE000E018 SYSCT_CVR RW SysTick current value register
|
|
|
+0xE000E01C SYSCT_CALIB RO SysTick calibration value register
|
|
|
+
|
|
|
+
|
|
|
+*SYST_CSR* — SysTick Control and Status Register
|
|
|
+Регистр управления и статуса. Несмотря на то, что он 32 битный заняты там всего 4 бита :)
|
|
|
+ * Бит 0 — ENABLE — бит разрешающий таймеру считать. 1 можно, 0 — нельзя. Когда
|
|
|
+ мы ставим ENABLE в 1 то таймер автоматически загружает свои счетные регистры
|
|
|
+ значением из регистра SYST_RVR и начинает тикать вниз.
|
|
|
+ * Бит 1 — TICKINT — разрешение прерывания. Когда этот бит 1, то на
|
|
|
+ обнулении будет прерывание таймера.
|
|
|
+ * Бит 2 — CLKSOURCE — откуда брать тики. Варианта два 0 — внешнее
|
|
|
+ тактирование эталонного генератора, 1 — с частоты процессора.
|
|
|
+ * Бит 16 — COUNTFLAG — флаг отсчета. Первый раз ставится в 1 после
|
|
|
+ первого обнуления. При чтении, как я понял, автоматом обнуляется.
|
|
|
+ Возвращает 1 если с последнего его чтения таймер перешел через ноль.
|
|
|
+ Позволяет отследить были ли переполнения. Удобно.
|
|
|
+
|
|
|
+
|
|
|
+*SYST_RVR* — SysTick Reload Value Register
|
|
|
+Регистр предзагрузки. Именно отсюда берет таймер свое значение для
|
|
|
+перезагрузки при обнулении. Фактически вот сюда и нужно грузить требуемое
|
|
|
+число задержки. Регистр 32 разрядный, но используются только первые 24
|
|
|
+бита.
|
|
|
+Класть туда можно любое число в диапазоне 0x00000001-0x00FFFFFF. Можно и
|
|
|
+0 положить, но ничего не будет. Т.к. у таймера весь экшн происходит с
|
|
|
+перехода из 0x00000001 в 0x00000000. А на ноль и получается ноль. Разве
|
|
|
+что COUNTFLAG вскочит. Только и всего. Поэтому значение SYST_RVR должно
|
|
|
+быть N-1 от желаемого количества тактов. Т.е. если надо получить
|
|
|
+прерывание на каждые 10000 тактов, то кладем 9999.
|
|
|
+
|
|
|
+
|
|
|
+*SYST_CVR* — SysTick Current Value Register
|
|
|
+Это, собственно, и есть счетный регистр. Тут оно тикает! В первых трех
|
|
|
+байтах. Есть у этого регистра особенность одна забавная. Из него можно
|
|
|
+только читать. А вот запись любого значения сразу его обнуляет. С
|
|
|
+обнулением флага COUNTFLAG.
|
|
|
+Т.е. если надо занулить таймер — пиши сюда :)
|
|
|
+
|
|
|
+
|
|
|
+*SYST_CALIB* — SysTick Calibration Value Register
|
|
|
+Это, как ясно из названия, регистр калибровки. Его можно только читать, и
|
|
|
+возвращает он следующее:
|
|
|
+ * SKEW — Показывает что записано в TENMS 0 — там реальные калибровочные
|
|
|
+ константы. 1 — какой то мусор который не имеет значения. Ну или ноль.
|
|
|
+ * NOREF — показывает есть ли у девайса эталонная тактовая частота. 0 —
|
|
|
+ есть, 1 — нет. Это зависит от производителя, позаботился ли он о такой
|
|
|
+ штуке :) Если эталонных часов нет, то бит CLKSOURCE из регистра SYST_CSR
|
|
|
+ читается как 1 и его нельзя изменить.
|
|
|
+ * TENMS — калибровочная константа. Содержит значение для 10мс задержки.
|
|
|
+ Как я понял, для эталонного генератора. Которого может и не быть.
|
|
|
+
|
|
|
+
|
|
|
+ *** Адреса и имена ***
|
|
|
+Осталось залезть в CMSIS и поискать там описание и дефайны SysTick.
|
|
|
+Находятся быстро в core_cm3.h:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+typedef struct
|
|
|
+{
|
|
|
+ __IO uint32_t CTRL; /*!< Offset: 0x00 SysTick Control and Status Register */
|
|
|
+ __IO uint32_t LOAD; /*!< Offset: 0x04 SysTick Reload Value Register */
|
|
|
+ __IO uint32_t VAL; /*!< Offset: 0x08 SysTick Current Value Register */
|
|
|
+ __I uint32_t CALIB; /*!< Offset: 0x0C SysTick Calibration Register */
|
|
|
+} SysTick_Type;
|
|
|
+
|
|
|
+/* SysTick Control / Status Register Definitions */
|
|
|
+#define SysTick_CTRL_COUNTFLAG_Pos 16 /*!< SysTick CTRL: COUNTFLAG Position */
|
|
|
+#define SysTick_CTRL_COUNTFLAG_Msk (1ul << SysTick_CTRL_COUNTFLAG_Pos) /*!< SysTick CTRL: COUNTFLAG Mask */
|
|
|
+
|
|
|
+#define SysTick_CTRL_CLKSOURCE_Pos 2 /*!< SysTick CTRL: CLKSOURCE Position */
|
|
|
+#define SysTick_CTRL_CLKSOURCE_Msk (1ul << SysTick_CTRL_CLKSOURCE_Pos) /*!< SysTick CTRL: CLKSOURCE Mask */
|
|
|
+
|
|
|
+#define SysTick_CTRL_TICKINT_Pos 1 /*!< SysTick CTRL: TICKINT Position */
|
|
|
+#define SysTick_CTRL_TICKINT_Msk (1ul << SysTick_CTRL_TICKINT_Pos) /*!< SysTick CTRL: TICKINT Mask */
|
|
|
+
|
|
|
+#define SysTick_CTRL_ENABLE_Pos 0 /*!< SysTick CTRL: ENABLE Position */
|
|
|
+#define SysTick_CTRL_ENABLE_Msk (1ul << SysTick_CTRL_ENABLE_Pos) /*!< SysTick CTRL: ENABLE Mask */
|
|
|
+
|
|
|
+/* SysTick Reload Register Definitions */
|
|
|
+#define SysTick_LOAD_RELOAD_Pos 0 /*!< SysTick LOAD: RELOAD Position */
|
|
|
+#define SysTick_LOAD_RELOAD_Msk (0xFFFFFFul << SysTick_LOAD_RELOAD_Pos) /*!< SysTick LOAD: RELOAD Mask */
|
|
|
+
|
|
|
+/* SysTick Current Register Definitions */
|
|
|
+#define SysTick_VAL_CURRENT_Pos 0 /*!< SysTick VAL: CURRENT Position */
|
|
|
+#define SysTick_VAL_CURRENT_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick VAL: CURRENT Mask */
|
|
|
+
|
|
|
+/* SysTick Calibration Register Definitions */
|
|
|
+#define SysTick_CALIB_NOREF_Pos 31 /*!< SysTick CALIB: NOREF Position */
|
|
|
+#define SysTick_CALIB_NOREF_Msk (1ul << SysTick_CALIB_NOREF_Pos) /*!< SysTick CALIB: NOREF Mask */
|
|
|
+
|
|
|
+#define SysTick_CALIB_SKEW_Pos 30 /*!< SysTick CALIB: SKEW Position */
|
|
|
+#define SysTick_CALIB_SKEW_Msk (1ul << SysTick_CALIB_SKEW_Pos) /*!< SysTick CALIB: SKEW Mask */
|
|
|
+
|
|
|
+#define SysTick_CALIB_TENMS_Pos 0 /*!< SysTick CALIB: TENMS Position */
|
|
|
+#define SysTick_CALIB_TENMS_Msk (0xFFFFFFul << SysTick_VAL_CURRENT_Pos) /*!< SysTick CALIB: TENMS Mask */
|
|
|
+/*@}*/ /* end of group CMSIS_CM3_SysTick */
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+
|
|
|
+Нам там нужны имена битов. Вот они:
|
|
|
+SysTick_CTRL_CLKSOURCE_Msk, SysTick_CTRL_TICKINT_Msk, SysTick_CTRL_ENABLE_Msk.
|
|
|
+
|
|
|
+
|
|
|
+Конфигурация таймера на тик в 1ms, таким образом, будет выглядеть примерно
|
|
|
+так:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+#define F_CPU 72000000UL // Тактовая у нас 72МГЦ
|
|
|
+#define TimerTick F_CPU/1000-1 // Нам нужен килогерц
|
|
|
+
|
|
|
+SysTick->LOAD=TimerTick; // Загрузка значения
|
|
|
+SysTick->VAL=TimerTick; // Обнуляем таймеры и флаги. Записью, помните?
|
|
|
+
|
|
|
+SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk |
|
|
|
+ SysTick_CTRL_TICKINT_Msk |
|
|
|
+ SysTick_CTRL_ENABLE_Msk;
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+
|
|
|
+ *** Обработчик прерывания SysTick ***
|
|
|
+Где взять имя обработчика? Да из таблицы прерываний. Поглядеть, если кто
|
|
|
+не помнит, можно в STM32F10x.s
|
|
|
+
|
|
|
+Вот ее кусочек:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+; Vector Table Mapped to Address 0 at Reset
|
|
|
+
|
|
|
+ AREA RESET, DATA, READONLY
|
|
|
+ EXPORT __Vectors
|
|
|
+
|
|
|
+__Vectors DCD __initial_sp ; Top of Stack
|
|
|
+ DCD Reset_Handler ; Reset Handler
|
|
|
+ DCD NMI_Handler ; NMI Handler
|
|
|
+ DCD HardFault_Handler ; Hard Fault Handler
|
|
|
+ DCD MemManage_Handler ; MPU Fault Handler
|
|
|
+ DCD BusFault_Handler ; Bus Fault Handler
|
|
|
+ DCD UsageFault_Handler ; Usage Fault Handler
|
|
|
+ DCD 0 ; Reserved
|
|
|
+ DCD 0 ; Reserved
|
|
|
+ DCD 0 ; Reserved
|
|
|
+ DCD 0 ; Reserved
|
|
|
+ DCD SVC_Handler ; SVCall Handler
|
|
|
+ DCD DebugMon_Handler ; Debug Monitor Handler
|
|
|
+ DCD 0 ; Reserved
|
|
|
+ DCD PendSV_Handler ; PendSV Handler
|
|
|
+ DCD SysTick_Handler ; SysTick Handler
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+
|
|
|
+Имя есть. Осталось организовать прерывание:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+//SysTick Interrupt
|
|
|
+void SysTick_Handler(void)
|
|
|
+{
|
|
|
+ // Тут будем делать нечто полезное. Например, ставить бит B.05
|
|
|
+ GPIOB->BSRR = GPIO_BSRR_BS5; // Set bit
|
|
|
+}
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+
|
|
|
+А сбрасывать его будет в главном цикле. В результате мы получим иголки с
|
|
|
+частотой 1Кгц которые хорошо видно осциллографом :)
|
|
|
+
|
|
|
+
|
|
|
+Вот так выглядит полный код примера:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+#include "stm32f10x.h"
|
|
|
+#define F_CPU 72000000UL
|
|
|
+#define TimerTick F_CPU/1000-1
|
|
|
+
|
|
|
+void Delay(uint32_t Val);
|
|
|
+
|
|
|
+//SysTick Interrupt
|
|
|
+void SysTick_Handler(void)
|
|
|
+{
|
|
|
+ GPIOB->BSRR = GPIO_BSRR_BS5; // Set bit
|
|
|
+}
|
|
|
+
|
|
|
+int main(void)
|
|
|
+{
|
|
|
+ SystemInit();
|
|
|
+
|
|
|
+ RCC->APB2ENR |= RCC_APB2ENR_IOPBEN;
|
|
|
+ // Config CRL
|
|
|
+ GPIOB->CRL &= ~GPIO_CRL_CNF5; // Clear CNF bit 5. Mode 00 - Push-Pull
|
|
|
+ GPIOB->CRL |= GPIO_CRL_MODE5_0; // Set bit MODE0 for pin 5. Mode 01 = Max Speed 10MHz
|
|
|
+
|
|
|
+
|
|
|
+ SysTick->LOAD=TimerTick;
|
|
|
+ SysTick->VAL=TimerTick;
|
|
|
+ SysTick->CTRL= SysTick_CTRL_CLKSOURCE_Msk |
|
|
|
+ SysTick_CTRL_TICKINT_Msk |
|
|
|
+ SysTick_CTRL_ENABLE_Msk;;
|
|
|
+ while(1)
|
|
|
+ {
|
|
|
+ GPIOB->BSRR = GPIO_BSRR_BR5; // Clear bit
|
|
|
+ }
|
|
|
+}
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+
|
|
|
+ *** Функции CMSIS ***
|
|
|
+
|
|
|
+У Таймера, раз он часть ядра, есть функция конфигурации в CMSIS. Описана
|
|
|
+она в core_cm3.h и выглядит так:
|
|
|
+*------------------ File Begin -------------------*
|
|
|
+static __INLINE uint32_t SysTick_Config(uint32_t ticks)
|
|
|
+{
|
|
|
+ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
|
|
|
+
|
|
|
+ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
|
|
|
+ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
|
|
|
+
|
|
|
+ SysTick->VAL = 0; /* Load the SysTick Counter Value */
|
|
|
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
|
|
+ SysTick_CTRL_TICKINT_Msk |
|
|
|
+ SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
|
|
|
+ return (0); /* Function successful */
|
|
|
+}
|
|
|
+*------------------ File End -------------------*
|
|
|
+
|
|
|
+То же самое, что и мы сделали вручную. Только есть проверка на
|
|
|
+корректность значения и обрезка лишних битов. Возвращает 1 если данные
|
|
|
+некорректные. Ну и еще там приоритет ставится если ядро М0 (это кстати хз
|
|
|
+зачем? У M0 же должна быть своя версия CMSIS?)
|
|
|
+
|
|
|
+
|
|
|
+Так что таймер можно загрузить и следующей фигней:
|
|
|
+ SysTick_Config(TimerTick);
|
|
|
+
|
|
|
+Для LPC все совершенно аналогично. До последней буковки можно сказать.
|
|
|
+Т.к. это фича не STM32, а ядра и описана в CMSIS. Т.е. едина для всех.
|
|
|
+
|
|
|
+===============================================================================
|
|
|
+
|
|
|
+Для конфигурации таймера в файле core_cm3.h есть функция
|
|
|
+SysTick_Config(uint32_t ticks), в качестве аргумента которой передается
|
|
|
+коэффициент деления тактовой частоты для получения необходимой временной
|
|
|
+задержки.
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+static __INLINE uint32_t SysTick_Config(uint32_t ticks)
|
|
|
+{
|
|
|
+ if (ticks > SysTick_LOAD_RELOAD_Msk) return (1); /* Reload value impossible */
|
|
|
+
|
|
|
+ SysTick->LOAD = (ticks & SysTick_LOAD_RELOAD_Msk) - 1; /* set reload register */
|
|
|
+ NVIC_SetPriority (SysTick_IRQn, (1<<__NVIC_PRIO_BITS) - 1); /* set Priority for Cortex-M0 System Interrupts */
|
|
|
+ SysTick->VAL = 0; /* Load the SysTick Counter Value */
|
|
|
+ SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk |
|
|
|
+ SysTick_CTRL_TICKINT_Msk |
|
|
|
+ SysTick_CTRL_ENABLE_Msk; /* Enable SysTick IRQ and SysTick Timer */
|
|
|
+ return (0); /* Function successful */
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+Это значение заносится в регистр перезагрузки. В самом начале выполняется
|
|
|
+проверка на то, что данная величина не выходит за максимальный предел,
|
|
|
+поскольку счетчик 24-разрядный, а передаваемый аргумент функции является
|
|
|
+32-разрядным числом и необходимо об этом помнить.
|
|
|
+
|
|
|
+Далее в функции конфигурации SysTick_Config() задается уровень приоритета
|
|
|
+прерывания, обнуляется счетный регистр, разрешается генерация прерывания,
|
|
|
+задается источник тактирования и разрешается работа таймера – запускается
|
|
|
+счет.
|
|
|
+
|
|
|
+По умолчанию тактовая частота этого таймера будет равна системной тактовой
|
|
|
+частоте SYSCLK. Если же нужно задать частоту тактирования таймера как
|
|
|
+SYSCLK/8, то уже после этой функции инициализации можно вызвать функцию
|
|
|
+
|
|
|
+ SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8),
|
|
|
+
|
|
|
+которая находится в файле misc.c. Для этого к проекту необходимо
|
|
|
+подключить файлы misc.c и misc.h.
|
|
|
+
|
|
|
+
|
|
|
+В данных примерах таймер настраивается на генерацию прерывания через
|
|
|
+“базовый” промежуток времени, равный 1 миллисекунде. Затем, уже с помощью
|
|
|
+программного цикла формируется задержка, равная 1 секунде. Через каждую
|
|
|
+секунду происходит попеременное зажигание/гашение светодиодов платы, здесь
|
|
|
+я не стал особо мудрить, поскольку основной задачей была настройка
|
|
|
+системного таймера для генерации прерываний через определенный интервал.
|
|
|
+
|
|
|
+Для задания длительности между двумя последующими прерываниями от таймера,
|
|
|
+в регистр перезагрузки необходимо записать значение, которое
|
|
|
+рассчитывается по простой формуле:
|
|
|
+
|
|
|
+ * Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s), где
|
|
|
+ * Reload Value – величина перезагружаемого значения для таймера
|
|
|
+ * SysTick Counter Clock (Hz) – тактовая частота таймера
|
|
|
+ * Desired Time base (s) – желаемое время формируемой временной задержки между прерываниями
|
|
|
+
|
|
|
+Системная тактовая частота задается при начальной инициализации микроконтроллера.
|
|
|
+
|
|
|
+На плате STM32VL-DISCOVERY микроконтроллер конфигурируется на работу с
|
|
|
+внешним кварцем частотой 8 МГц, при этом его системная тактовая частота
|
|
|
+после начальной инициализации будет равна 24 МГц.
|
|
|
+
|
|
|
+На плате STM32L-DISCOVERY внешнего кварца нет и после начальной
|
|
|
+инициализации системная тактовая частота формируется внутренним источником
|
|
|
+MSI и равна 2,097 МГц.
|
|
|
+
|
|
|
+Расчет перезагружаемых значений приведен ниже, в комментариях примеров программ для этих плат.
|
|
|
+
|
|
|
+
|
|
|
+Код программы для платы STM32VL-DISCOVERY (контроллер STM32F100)
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+#include "stm32f10x.h"
|
|
|
+
|
|
|
+static __IO uint32_t TimingDelay;
|
|
|
+
|
|
|
+void Delay_ms(__IO uint32_t nTime);
|
|
|
+
|
|
|
+GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ /*Вызов функции конфигурации системного таймера SysTick.
|
|
|
+ Эта функция находится в файле core_cm3.h и:
|
|
|
+ --Задает источник тактирования системного таймера (по умолчанию это SYSCLK = 24 МГц,
|
|
|
+ другой возможный вариант - SysTick тактируется от SYSCLK/8);
|
|
|
+ --Задает уровень приоритета прерывания;
|
|
|
+ --Сбрасывает флаг ожидания прерывания, если он выставлен;
|
|
|
+ --Заносит в нужный регистр перезагружаемое значение для декрементирующего счетчика,
|
|
|
+ которое вычисляется по формуле:
|
|
|
+ Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s),
|
|
|
+ для базовой задержки длительностью 1 мс получим величину
|
|
|
+ Reload Value = 24 000 000 Гц х 0,001 с = 24 000
|
|
|
+ (Необходимо самостоятельно посчитать эту величину и вставить в качестве
|
|
|
+ параметра при вызове функции);
|
|
|
+ --Обнуляет счетчик
|
|
|
+ --Запускает счет системного таймера*/
|
|
|
+ SysTick_Config(24000);
|
|
|
+
|
|
|
+ //Включаем тактирование порта GPIOC
|
|
|
+ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE);
|
|
|
+ //Конфигурируем выводы, к которым подключены светодиоды платы
|
|
|
+ GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9; //Выбираем выводы PC8, PC9
|
|
|
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //Максимальная скорость работы
|
|
|
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP; //Выход Push-Pull
|
|
|
+ GPIO_Init(GPIOC, &GPIO_InitStruct); //Заносим заданные настройки в регистры порта
|
|
|
+
|
|
|
+ while(1)
|
|
|
+ {
|
|
|
+ GPIO_ResetBits(GPIOC, GPIO_Pin_9); //Гасим зеленый LED
|
|
|
+ GPIO_SetBits(GPIOC, GPIO_Pin_8); //Зажигаем синий LED
|
|
|
+ Delay_ms(1000); //Временная задержка на 1 с
|
|
|
+ GPIO_ResetBits(GPIOC, GPIO_Pin_8); //Гасим синий LED
|
|
|
+ GPIO_SetBits(GPIOC, GPIO_Pin_9); //Зажигаем зеленый LED
|
|
|
+ Delay_ms(1000); //Временная задержка на 1 с
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//Функция временной задержки
|
|
|
+void Delay_ms(__IO uint32_t nTime)
|
|
|
+{
|
|
|
+ TimingDelay = nTime;
|
|
|
+ while(TimingDelay != 0);
|
|
|
+}
|
|
|
+
|
|
|
+void TimingDelay_Decrement(void)
|
|
|
+{
|
|
|
+ if (TimingDelay != 0x00)
|
|
|
+ {
|
|
|
+ TimingDelay--;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//Обработчик прерывания системного таймера
|
|
|
+void SysTick_Handler(void)
|
|
|
+{
|
|
|
+ TimingDelay_Decrement();
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+
|
|
|
+Код программы для платы STM32L-DISCOVERY (контроллер STM32L152)
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+#include "stm32l1xx.h"
|
|
|
+
|
|
|
+static __IO uint32_t TimingDelay;
|
|
|
+
|
|
|
+void Delay_ms(__IO uint32_t nTime);
|
|
|
+
|
|
|
+GPIO_InitTypeDef GPIO_InitStruct;
|
|
|
+
|
|
|
+int main()
|
|
|
+{
|
|
|
+ /*Вызов функции конфигурации системного таймера SysTick.
|
|
|
+ Эта функция находится в файле core_cm3.h и:
|
|
|
+ --Задает источник тактирования системного таймера (по умолчанию это SYSCLK = 2.097 МГц,
|
|
|
+ другой возможный вариант - SysTick тактируется от SYSCLK/8);
|
|
|
+ --Задает уровень приоритета прерывания;
|
|
|
+ --Сбрасывает флаг ожидания прерывания, если он выставлен;
|
|
|
+ --Заносит в нужный регистр перезагружаемое значение для декрементирующего счетчика,
|
|
|
+ которое вычисляется по формуле:
|
|
|
+ Reload Value = SysTick Counter Clock (Hz) x Desired Time base (s),
|
|
|
+ для базовой задержки длительностью 1 мс получим величину
|
|
|
+ Reload Value = 2 097 000 Гц х 0,001 с = 2097
|
|
|
+ (Необходимо самостоятельно посчитать эту величину и вставить в качестве
|
|
|
+ параметра при вызове функции);
|
|
|
+ --Обнуляет счетчик
|
|
|
+ --Запускает счет системного таймера*/
|
|
|
+ SysTick_Config(2097);
|
|
|
+
|
|
|
+ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE); //Включаем тактирование GPIOB
|
|
|
+
|
|
|
+ //Конфигурируем выводы, к которым подключены светодиоды платы
|
|
|
+ GPIO_InitStruct.GPIO_Pin = (GPIO_Pin_6 | GPIO_Pin_7); //Выбираем выводы PB6, PB7
|
|
|
+ GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT; //Выводы порта в режиме выхода
|
|
|
+ GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //Выход Push-Pull
|
|
|
+ GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //Выход без подтягивающих резисторов
|
|
|
+ GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz; //Скорость порта максимальная
|
|
|
+ GPIO_Init(GPIOB, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOB
|
|
|
+
|
|
|
+ while(1)
|
|
|
+ {
|
|
|
+ GPIO_ResetBits(GPIOB, GPIO_Pin_7); //Гасим зеленый LED
|
|
|
+ GPIO_SetBits(GPIOB, GPIO_Pin_6); //Зажигаем синий LED
|
|
|
+ Delay_ms(1000); //Временная задержка на 1 с
|
|
|
+ GPIO_ResetBits(GPIOB, GPIO_Pin_6); //Гасим синий LED
|
|
|
+ GPIO_SetBits(GPIOB, GPIO_Pin_7); //Зажигаем зеленый LED
|
|
|
+ Delay_ms(1000); //Временная задержка на 1 с
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//Функция временной задержки
|
|
|
+void Delay_ms(__IO uint32_t nTime)
|
|
|
+{
|
|
|
+ TimingDelay = nTime;
|
|
|
+ while(TimingDelay != 0);
|
|
|
+}
|
|
|
+
|
|
|
+void TimingDelay_Decrement(void)
|
|
|
+{
|
|
|
+ if (TimingDelay != 0x00)
|
|
|
+ {
|
|
|
+ TimingDelay--;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+//Обработчик прерывания системного таймера
|
|
|
+void SysTick_Handler(void)
|
|
|
+{
|
|
|
+ TimingDelay_Decrement();
|
|
|
+}
|
|
|
+~~~~~~~~~~~~~~~~~~~~
|
|
|
+
|
|
|
+===============================================================================
|
|
|
+
|
|
|
+ *** Литература: ***
|
|
|
+
|
|
|
+Cortex-M3 Devices Generic User Guide
|
|
|
+Cortex-M3 Peripherals > System timer, SysTick
|
|
|
+4.4. System timer, SysTick
|
|
|
+http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0552a/Babieigh.html
|
|
|
+
|
|
|
+ARM. Учебный Курс. SysTick — Системный таймер
|
|
|
+http://easyelectronics.ru/arm-uchebnyj-kurs-systick-sistemnyj-tajmer.html
|
|
|
+
|
|
|
+STM32. Системный таймер SysTick.
|
|
|
+http://chipspace.ru/stm32-systick/
|