STM8S+SDCC+SPL: ШИМ на таймере TIM2

разделы: STM8 , дата: 2 августа 2016г.

Из группы таймеров общего назначения (general purpose timers), в stm8s103f3p6 присутствует лишь TIM2, однако, его возможностей вкупе с TIM1, может оказаться вполне достаточно для большинства задач.

    В целом, устройство таймеров TIM2/TIM3 аналогично TIM4, рассмотренному ранее, но есть пара важных отличий:
  • Таймеры TIM2, TIM3, TIM5 являются 16-битными;
  • Таймеры имеют несколько каналов, которые могут работать как на вход, так и на выход;
  • Каналы настроенные на вход работают как каналы захвата;
  • Каналы настроенные на выход работают как каналы ШИМ.

Из-за этих каналов, группа регистров таймера TIM2 на первый взгляд может показаться раздутой, но если внимательно присмотреться и отбросить "канальные" регистры, то общая структура регистров будет схожа с набором регистров TIM4.

Правда не стоит забывать о том, что в корпусах с малым количеством выводов, некоторые каналы могут оказаться "альтернативными", т.е. включаться через Option bytes.

К примеру, на распиновке чипа stm8s103f3, в квадратных скобках, помечены альтернативные пины для каналов 1(AFR0) и 3(AFR1) таймера TIM2.

Регистры TIM2 в стандартной периферийной библиотеке(далее SPL) описываются следующей структурой:

typedef struct TIM2_struct
{
  __IO uint8_t CR1;   /*!< control register 1 */
#if defined(STM8S103) || defined(STM8S003)
        uint8_t RESERVED1; /*!< Reserved register */
        uint8_t RESERVED2; /*!< Reserved register */
#endif
  __IO uint8_t IER;   /*!< interrupt enable register */
  __IO uint8_t SR1;   /*!< status register 1 */
  __IO uint8_t SR2;   /*!< status register 2 */
  __IO uint8_t EGR;   /*!< event generation register */
  __IO uint8_t CCMR1; /*!< CC mode register 1 */
  __IO uint8_t CCMR2; /*!< CC mode register 2 */
  __IO uint8_t CCMR3; /*!< CC mode register 3 */
  __IO uint8_t CCER1; /*!< CC enable register 1 */
  __IO uint8_t CCER2; /*!< CC enable register 2 */
  __IO uint8_t CNTRH; /*!< counter high */
  __IO uint8_t CNTRL; /*!< counter low */
  __IO uint8_t PSCR;  /*!< prescaler register */
  __IO uint8_t ARRH;  /*!< auto-reload register high */
  __IO uint8_t ARRL;  /*!< auto-reload register low */
  __IO uint8_t CCR1H; /*!< capture/compare register 1 high */
  __IO uint8_t CCR1L; /*!< capture/compare register 1 low */
  __IO uint8_t CCR2H; /*!< capture/compare register 2 high */
  __IO uint8_t CCR2L; /*!< capture/compare register 2 low */
  __IO uint8_t CCR3H; /*!< capture/compare register 3 high */
  __IO uint8_t CCR3L; /*!< capture/compare register 3 low */
}
TIM2_TypeDef;

Здесь: CR1, SR1, SR2, IER, EGR, PSCR - уже знакомые регистры по TIM4. Так же как и регистры ARRH/ARRL и CNTRH/CNTRL, которые здесь раздвоены ввиду того, что таймер 16-битный.

Новыми здесь являются тройка регистров CCMR1/CCMR2/CCMR3, пара CCER1/CCER2 и три пары регистров CCRxx. Первые - СCMRx(Capture/Compare Mode Register), управляют режимами работы каналов. Вторые - CCERx(Capture/Compare Enable Register), включают/выключают функции каналов. CCRxx - регистры куда сбрасываются значения счетчика в том случае, если канал настроен на захват. Если же канал настроен на вывод ШИМ, то регистры CCRx содержат число с которым сравнивается значение счетчика CNTR.

Функцией TIM2_DeInit(), в эти регистры заносятся следующие значения:

#define TIM2_CR1_RESET_VALUE   ((uint8_t)0x00)
#define TIM2_IER_RESET_VALUE   ((uint8_t)0x00)
#define TIM2_SR1_RESET_VALUE   ((uint8_t)0x00)
#define TIM2_SR2_RESET_VALUE   ((uint8_t)0x00)
#define TIM2_EGR_RESET_VALUE   ((uint8_t)0x00)
#define TIM2_CCMR1_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCMR2_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCMR3_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCER1_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCER2_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CNTRH_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CNTRL_RESET_VALUE ((uint8_t)0x00)
#define TIM2_PSCR_RESET_VALUE  ((uint8_t)0x00)
#define TIM2_ARRH_RESET_VALUE  ((uint8_t)0xFF)
#define TIM2_ARRL_RESET_VALUE  ((uint8_t)0xFF)
#define TIM2_CCR1H_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCR1L_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCR2H_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCR2L_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCR3H_RESET_VALUE ((uint8_t)0x00)
#define TIM2_CCR3L_RESET_VALUE ((uint8_t)0x00)

Функционал модуля TIM2 в SPL реализуется следующим набором функций:

void TIM2_DeInit(void);
void TIM2_TimeBaseInit(TIM2_Prescaler_TypeDef TIM2_Prescaler, uint16_t TIM2_Period);
void TIM2_OC1Init(TIM2_OCMode_TypeDef TIM2_OCMode, TIM2_OutputState_TypeDef TIM2_OutputState, uint16_t TIM2_Pulse, TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_OC2Init(TIM2_OCMode_TypeDef TIM2_OCMode, TIM2_OutputState_TypeDef TIM2_OutputState, uint16_t TIM2_Pulse, TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_OC3Init(TIM2_OCMode_TypeDef TIM2_OCMode, TIM2_OutputState_TypeDef TIM2_OutputState, uint16_t TIM2_Pulse, TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_ICInit(TIM2_Channel_TypeDef TIM2_Channel, TIM2_ICPolarity_TypeDef TIM2_ICPolarity, TIM2_ICSelection_TypeDef TIM2_ICSelection,  TIM2_ICPSC_TypeDef TIM2_ICPrescaler, uint8_t TIM2_ICFilter);
void TIM2_PWMIConfig(TIM2_Channel_TypeDef TIM2_Channel, TIM2_ICPolarity_TypeDef TIM2_ICPolarity, TIM2_ICSelection_TypeDef TIM2_ICSelection,  TIM2_ICPSC_TypeDef TIM2_ICPrescaler, uint8_t TIM2_ICFilter);
void TIM2_Cmd(FunctionalState NewState);
void TIM2_ITConfig(TIM2_IT_TypeDef TIM2_IT, FunctionalState NewState);
void TIM2_InternalClockConfig(void);
void TIM2_UpdateDisableConfig(FunctionalState NewState);
void TIM2_UpdateRequestConfig(TIM2_UpdateSource_TypeDef TIM2_UpdateSource);
void TIM2_SelectOnePulseMode(TIM2_OPMode_TypeDef TIM2_OPMode);
void TIM2_PrescalerConfig(TIM2_Prescaler_TypeDef Prescaler, TIM2_PSCReloadMode_TypeDef TIM2_PSCReloadMode);
void TIM2_ForcedOC1Config(TIM2_ForcedAction_TypeDef TIM2_ForcedAction);
void TIM2_ForcedOC2Config(TIM2_ForcedAction_TypeDef TIM2_ForcedAction);
void TIM2_ForcedOC3Config(TIM2_ForcedAction_TypeDef TIM2_ForcedAction);
void TIM2_ARRPreloadConfig(FunctionalState NewState);
void TIM2_CCPreloadControl(FunctionalState NewState);
void TIM2_OC1PreloadConfig(FunctionalState NewState);
void TIM2_OC2PreloadConfig(FunctionalState NewState);
void TIM2_OC3PreloadConfig(FunctionalState NewState);
void TIM2_GenerateEvent(TIM2_EventSource_TypeDef TIM2_EventSource);
void TIM2_OC1PolarityConfig(TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_OC2PolarityConfig(TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_OC3PolarityConfig(TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_CCxCmd(TIM2_Channel_TypeDef TIM2_Channel, FunctionalState NewState);
void TIM2_SelectOCxM(TIM2_Channel_TypeDef TIM2_Channel, TIM2_OCMode_TypeDef TIM2_OCMode);
void TIM2_SetCounter(uint16_t Counter);
void TIM2_SetAutoreload(uint16_t Autoreload);
void TIM2_SetCompare1(uint16_t Compare1);
void TIM2_SetCompare2(uint16_t Compare2);
void TIM2_SetCompare3(uint16_t Compare3);
void TIM2_SetIC1Prescaler(TIM2_ICPSC_TypeDef TIM2_IC1Prescaler);
void TIM2_SetIC2Prescaler(TIM2_ICPSC_TypeDef TIM2_IC2Prescaler);
void TIM2_SetIC3Prescaler(TIM2_ICPSC_TypeDef TIM2_IC3Prescaler);
uint16_t TIM2_GetCapture1(void);
uint16_t TIM2_GetCapture2(void);
uint16_t TIM2_GetCapture3(void);
uint16_t TIM2_GetCounter(void);
TIM2_Prescaler_TypeDef TIM2_GetPrescaler(void);
FlagStatus TIM2_GetFlagStatus(TIM2_FLAG_TypeDef TIM2_FLAG);
void TIM2_ClearFlag(TIM2_FLAG_TypeDef TIM2_FLAG);
ITStatus TIM2_GetITStatus(TIM2_IT_TypeDef TIM2_IT);
void TIM2_ClearITPendingBit(TIM2_IT_TypeDef TIM2_IT);

В качестве примера использования таймера TIM2 в режиме ШИМ, подключим на вывод первого канала TIM2_CH1/PD4 светодиод, подадим на него ШИМ-сигнал, и с его помощью будем менять яркость светодиода.

Исходный код:

#include "stm8s.h"
#include "stm8s_gpio.h"
#include "stm8s_clk.h"
#include "stm8s_tim4.h"
#include "stm8s_tim2.h"

#define LED_PORT GPIOB
#define LED GPIO_PIN_5

#define TIM4_PERIOD       124

volatile uint16_t count;

INTERRUPT_HANDLER(IRQ_Handler_TIM4, 23)
{
  if (count)
    count--;

    TIM4_ClearITPendingBit(TIM4_IT_UPDATE);
}

void delay_ms(uint16_t ms)
{
        TIM4_Cmd(DISABLE);       // stop
        TIM4_TimeBaseInit(TIM4_PRESCALER_128, TIM4_PERIOD);
        TIM4_ClearFlag(TIM4_FLAG_UPDATE);
        TIM4_ITConfig(TIM4_IT_UPDATE, ENABLE);

        count = ms;

        TIM4_Cmd(ENABLE);       // let's go

  while(count);
}



ErrorStatus status = FALSE;


int main( void )
{

  // ----------- GPIO CONFIG -------------------
  GPIO_DeInit(LED_PORT);
  GPIO_Init(LED_PORT, LED, GPIO_MODE_OUT_PP_LOW_FAST);

  // ---------- CLK CONFIG -----------------------
  CLK_DeInit();

  CLK_SYSCLKConfig(CLK_PRESCALER_CPUDIV1);
  CLK_SYSCLKConfig(CLK_PRESCALER_HSIDIV1); // set 16 MHz for CPU

  TIM4_DeInit();
  // uncomment if use HSE on Quartz
  //status = CLK_ClockSwitchConfig(CLK_SWITCHMODE_AUTO, CLK_SOURCE_HSE, DISABLE,
  //                CLK_CURRENTCLOCKSTATE_DISABLE);

  TIM2_DeInit();

  TIM2_TimeBaseInit(TIM2_PRESCALER_1, 999);

  // PWM1 Mode configuration: Channel1
  TIM2_OC1Init(TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE,500, TIM2_OCPOLARITY_HIGH);
  TIM2_OC1PreloadConfig(ENABLE);

  TIM2_ARRPreloadConfig(ENABLE);

  TIM2_Cmd(ENABLE);

  enableInterrupts();


  for(;;)
  {
    // 90% PWM
    delay_ms(1000);
    TIM2_SetCompare1(900);
    GPIO_WriteHigh(LED_PORT, LED);
    delay_ms(1000);
    GPIO_WriteLow(LED_PORT, LED);

    // 50% PWM
    delay_ms(1000);
    TIM2_SetCompare1(500);
    GPIO_WriteReverse(LED_PORT, LED);
    delay_ms(1000);
    GPIO_WriteLow(LED_PORT, LED);

    // 10% PWM
    delay_ms(1000);
    TIM2_SetCompare1(100);
    GPIO_WriteReverse(LED_PORT, LED);
    delay_ms(1000);
    GPIO_WriteLow(LED_PORT, LED);
  }
}

В функции TIM2_BaseInit() устанавливается частота работы таймера. Как не сложно догадаться, она будет общая для всех каналов.

void TIM2_TimeBaseInit( TIM2_Prescaler_TypeDef TIM2_Prescaler,
                        uint16_t TIM2_Period)
{
  /* Set the Prescaler value */
  TIM2->PSCR = (uint8_t)(TIM2_Prescaler);
  /* Set the Autoreload value */
  TIM2->ARRH = (uint8_t)(TIM2_Period >> 8);
  TIM2->ARRL = (uint8_t)(TIM2_Period);
}

В данном, случае частота таймера составляет 16kHz.

Функция TIM2_OC1Init() устанавливает режим работы первого канала таймера:

void TIM2_OC1Init(TIM2_OCMode_TypeDef TIM2_OCMode,
                  TIM2_OutputState_TypeDef TIM2_OutputState,
                  uint16_t TIM2_Pulse,
                  TIM2_OCPolarity_TypeDef TIM2_OCPolarity)
{
  /* Check the parameters */
  assert_param(IS_TIM2_OC_MODE_OK(TIM2_OCMode));
  assert_param(IS_TIM2_OUTPUT_STATE_OK(TIM2_OutputState));
  assert_param(IS_TIM2_OC_POLARITY_OK(TIM2_OCPolarity));

  /* Disable the Channel 1: Reset the CCE Bit, Set the Output State , the Output Polarity */
  TIM2->CCER1 &= (uint8_t)(~( TIM2_CCER1_CC1E | TIM2_CCER1_CC1P));
  /* Set the Output State &  Set the Output Polarity  */
  TIM2->CCER1 |= (uint8_t)((uint8_t)(TIM2_OutputState & TIM2_CCER1_CC1E ) |
                           (uint8_t)(TIM2_OCPolarity & TIM2_CCER1_CC1P));

  /* Reset the Output Compare Bits  & Set the Ouput Compare Mode */
  TIM2->CCMR1 = (uint8_t)((uint8_t)(TIM2->CCMR1 & (uint8_t)(~TIM2_CCMR_OCM)) |
                          (uint8_t)TIM2_OCMode);

  /* Set the Pulse value */
  TIM2->CCR1H = (uint8_t)(TIM2_Pulse >> 8);
  TIM2->CCR1L = (uint8_t)(TIM2_Pulse);
}

Константы: TIM2_OCMODE_PWM1, TIM2_OUTPUTSTATE_ENABLE, TIM2_OCPOLARITY_HIGH, которые используются при вызове функции имеют следующие значения:

1) режимы работы:

typedef enum
{
  TIM2_OCMODE_TIMING     = ((uint8_t)0x00),
  TIM2_OCMODE_ACTIVE     = ((uint8_t)0x10),
  TIM2_OCMODE_INACTIVE   = ((uint8_t)0x20),
  TIM2_OCMODE_TOGGLE     = ((uint8_t)0x30),
  TIM2_OCMODE_PWM1       = ((uint8_t)0x60),
  TIM2_OCMODE_PWM2       = ((uint8_t)0x70)
}TIM2_OCMode_TypeDef;

2) фаза;

typedef enum
{
  TIM2_OCPOLARITY_HIGH               = ((uint8_t)0x00),
  TIM2_OCPOLARITY_LOW                = ((uint8_t)0x22)
}TIM2_OCPolarity_TypeDef;

3) состояние выхода:

 typedef enum
{
  TIM2_OUTPUTSTATE_DISABLE           = ((uint8_t)0x00),
  TIM2_OUTPUTSTATE_ENABLE            = ((uint8_t)0x11)
}TIM2_OutputState_TypeDef;

Как видно, через регистр TIM2->CCMR1 задается режим работы канала. Режимов всего шесть: TIMING, ACTIVE, INACTIVE, TOGGLE, PWM1, PWM2. Устанаваются они битами OC1M[2:0] регистра TIM2->CCMR1.

Биты регистра TIMx_CCMR1 имеют разное значение, в зависимости от того настроен канал на вход или на выход. Сейчас мы рассматриваем случай, когда канал настроен на выход. При этом младшие два бита регистра СС1Ы[1:0], должны быть сброшены в ноль. Бит OC1PE (Output compare preload enable) включает буферный/теневой регистр для TIMx_ССR1. При сброшенном в ноль значении, теневой регистр не используется и в него можно писать "на ходу".

В битах OC1M задается режим работы канала выхода. При работе таймера на увеличение, записью 110 в OC1M задается обычный ШИМ, здесь он называется PWM1. Записью 111 можно так же задать т.н. PWM2 - это ШИМ противоположный по фазе PWM1. Т.е. если в ARR записать 1000, а в регистр сравнения - CCR 900, то светодиод подключенный на выходе будет гореть на 10% яркости, а не на 90% как было бы при режиме PWM1.

Иначе говоря, при работе таймера от нуля до значения ARR, в режиме PWM1 на выходе канала OC1 будет высокий потенциал при значении счетчика CNTR меньшем, чем значение регистра сравнения CCR. При (CNTR > CCR) на выходе будет логический ноль.

При PWM2 все наоборот. При работе таймера от нуля до значения ARR, в режиме PWM2 на выходе канала OC1 будет высокий потенциал при значении счетчика CNTR большем, чем значение регистра сравнения CCR. При (CNTR < CCR) на выходе будет логический ноль.

Осталось разобраться с регистрами TIMx_CCER1/TIMx_CCER2, к которых всего по паре битов на канал:

Здесь биты CCxE включают/отключают вывод OCx от ножки микросхемы.

Биты CCxP меняют полярность сигнала. При сброшенном бите активным уровнем является логическая единица, а при установленном бите, активным уровнем является логический ноль.

Следующая используемая функция в программе TIM2_OC1PreloadConfig(FunctionalState NewState) включает теневой/буферный регистр для TIM2_CCRx

 void TIM2_OC1PreloadConfig(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONALSTATE_OK(NewState));

  /* Set or Reset the OC1PE Bit */
  if (NewState != DISABLE)
  {
    TIM2->CCMR1 |= (uint8_t)TIM2_CCMR_OCxPE;
  }
  else
  {
    TIM2->CCMR1 &= (uint8_t)(~TIM2_CCMR_OCxPE);
  }
}

То ж самое делает функция TIM2_ARRPreloadConfig(FunctionalState NewState) для регистра ARR через бит ARPE в TIM2_CR1 :

void TIM2_ARRPreloadConfig(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONALSTATE_OK(NewState));

  /* Set or Reset the ARPE Bit */
  if (NewState != DISABLE)
  {
    TIM2->CR1 |= (uint8_t)TIM2_CR1_ARPE;
  }
  else
  {
    TIM2->CR1 &= (uint8_t)(~TIM2_CR1_ARPE);
  }
}

Регистр TIMx_CR1 уже рассматривался ранее, он одинаков для всех таймеров:

Функция TIM2_Cmd(FunctionalState NewState) включает/выключает через бит CEN в регистре TIM2_CR1:

void TIM2_Cmd(FunctionalState NewState)
{
  /* Check the parameters */
  assert_param(IS_FUNCTIONALSTATE_OK(NewState));

  /* set or Reset the CEN Bit */
  if (NewState != DISABLE)
  {
    TIM2->CR1 |= (uint8_t)TIM2_CR1_CEN;
  }
  else
  {
    TIM2->CR1 &= (uint8_t)(~TIM2_CR1_CEN);
  }
}

Функция TIM2_SetCompare1(uint16_t Compare1) записывает новое значение в регистр сравнения первого канала - TIM2_CCR1 :

void TIM2_SetCompare1(uint16_t Compare1)
{
  /* Set the Capture Compare1 Register value */
  TIM2->CCR1H = (uint8_t)(Compare1 >> 8);
  TIM2->CCR1L = (uint8_t)(Compare1);
}

ШИМ на таймере TIM2 на примере чипа STM8L051F3 (добавлено 1 сентября 2016г.)

Таймеры в L-серии несколько отличаются от своих аналогов из S-серии.

Количество каналов в TIM1 - три вместо четырех. TIM2 и TIM5 имееют только по два канала, так же как TIM3.

STM8L051F3 вообще не имеет таймера TIM1, есть только парочка TIM2/TIM3, да TIM4.

В SPL для L-серии, таймеры TIM2/TIM3/TIM5 описываются одной структурой:

typedef struct TIM_struct
{
  __IO uint8_t CR1;    /*!< control register 1   */
  __IO uint8_t CR2;    /*!< control register 2   */
  __IO uint8_t SMCR;   /*!< Synchro mode control register */
  __IO uint8_t ETR;    /*!< external trigger register */
  __IO uint8_t DER;    /*!< DMA requests enable register */
  __IO uint8_t IER;    /*!< interrupt enable register*/
  __IO uint8_t SR1;    /*!< status register 1   */
  __IO uint8_t SR2;    /*!< status register 2   */
  __IO uint8_t EGR;    /*!< event generation register */
  __IO uint8_t CCMR1;  /*!< CC mode register 1      */
  __IO uint8_t CCMR2;  /*!< CC mode register 2      */
  __IO uint8_t CCER1;  /*!< CC enable register 1     */
  __IO uint8_t CNTRH;  /*!< counterregister  high  */
  __IO uint8_t CNTRL;  /*!< counterregister  low   */
  __IO uint8_t PSCR;   /*!< prescaler  register   */
  __IO uint8_t ARRH;   /*!< auto-reload register high  */
  __IO uint8_t ARRL;   /*!< auto-reload register low    */
  __IO uint8_t CCR1H;  /*!< capture/compare register 1 high   */
  __IO uint8_t CCR1L;  /*!< capture/compare register 1 low     */
  __IO uint8_t CCR2H;  /*!< capture/compare register 2 high   */
  __IO uint8_t CCR2L;  /*!< capture/compare register 2 low     */
  __IO uint8_t BKR;    /*!< Break Register */
  __IO uint8_t OISR;   /*!< Output idle register */
}
TIM_TypeDef;

Интерефейс модуля TIM2 в SPL описывается следующим набором функций:

/* Exported functions ------------------------------------------------------- */
/* TimeBase management ********************************************************/
void TIM2_DeInit(void);
void TIM2_TimeBaseInit(TIM2_Prescaler_TypeDef TIM2_Prescaler,
                       TIM2_CounterMode_TypeDef TIM2_CounterMode, uint16_t TIM2_Period);
void TIM2_PrescalerConfig(TIM2_Prescaler_TypeDef Prescaler,
                          TIM2_PSCReloadMode_TypeDef TIM2_PSCReloadMode);
void TIM2_CounterModeConfig(TIM2_CounterMode_TypeDef TIM2_CounterMode);
void TIM2_SetCounter(uint16_t Counter);
void TIM2_SetAutoreload(uint16_t Autoreload);
uint16_t TIM2_GetCounter(void);
TIM2_Prescaler_TypeDef TIM2_GetPrescaler(void);
void TIM2_UpdateDisableConfig(FunctionalState NewState);
void TIM2_UpdateRequestConfig(TIM2_UpdateSource_TypeDef TIM2_UpdateSource);
void TIM2_ARRPreloadConfig(FunctionalState NewState);
void TIM2_SelectOnePulseMode(TIM2_OPMode_TypeDef TIM2_OPMode);
void TIM2_Cmd(FunctionalState NewState);

/* Output Compare management **************************************************/
void TIM2_OC1Init(TIM2_OCMode_TypeDef TIM2_OCMode,
                  TIM2_OutputState_TypeDef TIM2_OutputState,
                  uint16_t TIM2_Pulse,
                  TIM2_OCPolarity_TypeDef TIM2_OCPolarity,
                  TIM2_OCIdleState_TypeDef TIM2_OCIdleState);
void TIM2_OC2Init(TIM2_OCMode_TypeDef TIM2_OCMode,
                  TIM2_OutputState_TypeDef TIM2_OutputState,
                  uint16_t TIM2_Pulse,
                  TIM2_OCPolarity_TypeDef TIM2_OCPolarity,
                  TIM2_OCIdleState_TypeDef TIM2_OCIdleState);
void TIM2_BKRConfig(TIM2_OSSIState_TypeDef TIM2_OSSIState,
                    TIM2_LockLevel_TypeDef TIM2_LockLevel,
                    TIM2_BreakState_TypeDef TIM2_BreakState,
                    TIM2_BreakPolarity_TypeDef TIM2_BreakPolarity,
                    TIM2_AutomaticOutput_TypeDef TIM2_AutomaticOutput);
void TIM2_CtrlPWMOutputs(FunctionalState NewState);
void TIM2_SelectOCxM(TIM2_Channel_TypeDef TIM2_Channel, TIM2_OCMode_TypeDef TIM2_OCMode);
void TIM2_SetCompare1(uint16_t Compare);
void TIM2_SetCompare2(uint16_t Compare);
void TIM2_ForcedOC1Config(TIM2_ForcedAction_TypeDef TIM2_ForcedAction);
void TIM2_ForcedOC2Config(TIM2_ForcedAction_TypeDef TIM2_ForcedAction);
void TIM2_OC1PreloadConfig(FunctionalState NewState);
void TIM2_OC2PreloadConfig(FunctionalState NewState);
void TIM2_OC1FastConfig(FunctionalState NewState);
void TIM2_OC2FastConfig(FunctionalState NewState);
void TIM2_OC1PolarityConfig(TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_OC2PolarityConfig(TIM2_OCPolarity_TypeDef TIM2_OCPolarity);
void TIM2_CCxCmd(TIM2_Channel_TypeDef TIM2_Channel, FunctionalState NewState);

/* Input Capture management ***************************************************/
void TIM2_ICInit(TIM2_Channel_TypeDef TIM2_Channel,
                 TIM2_ICPolarity_TypeDef TIM2_ICPolarity,
                 TIM2_ICSelection_TypeDef TIM2_ICSelection,
                 TIM2_ICPSC_TypeDef TIM2_ICPrescaler,
                 uint8_t TIM2_ICFilter);
void TIM2_PWMIConfig(TIM2_Channel_TypeDef TIM2_Channel,
                     TIM2_ICPolarity_TypeDef TIM2_ICPolarity,
                     TIM2_ICSelection_TypeDef TIM2_ICSelection,
                     TIM2_ICPSC_TypeDef TIM2_ICPrescaler,
                     uint8_t TIM2_ICFilter);
uint16_t TIM2_GetCapture1(void);
uint16_t TIM2_GetCapture2(void);
void TIM2_SetIC1Prescaler(TIM2_ICPSC_TypeDef TIM2_IC1Prescaler);
void TIM2_SetIC2Prescaler(TIM2_ICPSC_TypeDef TIM2_IC2Prescaler);

/* Interrupts, DMA and flags management ***************************************/
void TIM2_ITConfig(TIM2_IT_TypeDef TIM2_IT, FunctionalState NewState);
void TIM2_GenerateEvent(TIM2_EventSource_TypeDef TIM2_EventSource);
FlagStatus TIM2_GetFlagStatus(TIM2_FLAG_TypeDef TIM2_FLAG);
void TIM2_ClearFlag(TIM2_FLAG_TypeDef TIM2_FLAG);
ITStatus TIM2_GetITStatus(TIM2_IT_TypeDef TIM2_IT);
void TIM2_ClearITPendingBit(TIM2_IT_TypeDef TIM2_IT);
void TIM2_DMACmd(TIM2_DMASource_TypeDef TIM2_DMASource, FunctionalState NewState);
void TIM2_SelectCCDMA(FunctionalState NewState);

/* Clocks management **********************************************************/
void TIM2_InternalClockConfig(void);
void TIM2_TIxExternalClockConfig(TIM2_TIxExternalCLK1Source_TypeDef TIM2_TIxExternalCLKSource,
                                 TIM2_ICPolarity_TypeDef TIM2_ICPolarity,
                                 uint8_t ICFilter);
void TIM2_ETRClockMode1Config(TIM2_ExtTRGPSC_TypeDef TIM2_ExtTRGPrescaler,
                              TIM2_ExtTRGPolarity_TypeDef TIM2_ExtTRGPolarity,
                              uint8_t ExtTRGFilter);
void TIM2_ETRClockMode2Config(TIM2_ExtTRGPSC_TypeDef TIM2_ExtTRGPrescaler,
                              TIM2_ExtTRGPolarity_TypeDef TIM2_ExtTRGPolarity,
                              uint8_t ExtTRGFilter);

/* Synchronization management *************************************************/
void TIM2_SelectInputTrigger(TIM2_TRGSelection_TypeDef TIM2_InputTriggerSource);
void TIM2_SelectOutputTrigger(TIM2_TRGOSource_TypeDef TIM2_TRGOSource);
void TIM2_SelectSlaveMode(TIM2_SlaveMode_TypeDef TIM2_SlaveMode);
void TIM2_SelectMasterSlaveMode(FunctionalState NewState);
void TIM2_ETRConfig(TIM2_ExtTRGPSC_TypeDef TIM2_ExtTRGPrescaler,
                    TIM2_ExtTRGPolarity_TypeDef TIM2_ExtTRGPolarity,
                    uint8_t ExtTRGFilter);

/* Specific interface management **********************************************/
void TIM2_EncoderInterfaceConfig(TIM2_EncoderMode_TypeDef TIM2_EncoderMode,
                                 TIM2_ICPolarity_TypeDef TIM2_IC1Polarity,
                                 TIM2_ICPolarity_TypeDef TIM2_IC2Polarity);
void TIM2_SelectHallSensor(FunctionalState NewState);

Аналог вышеприведенной программы для stm8l051f3 будет выглядеть так:

#include "stm8l.h"
#include "stm8l_gpio.h"
#include "stm8l_clk.h"
#include "stm8l_tim4.h"
#include "stm8l_tim2.h"

#define PORT GPIOB
#define LED  GPIO_Pin_1
#define TIM4_PERIOD 124

volatile uint16_t count;

INTERRUPT_HANDLER(IRQ_Handler_TIM4, 25)
{
        if (count)
          count--;

        TIM4_ClearITPendingBit(TIM4_IT_Update);
}

void delay_ms(uint16_t ms)
{
        TIM4_Cmd(DISABLE);       // stop

        TIM4_TimeBaseInit(TIM4_Prescaler_128, TIM4_PERIOD);
        TIM4_ClearFlag(TIM4_FLAG_Update);
        TIM4_ITConfig(TIM4_IT_Update, ENABLE);

        count = ms;

        TIM4_Cmd(ENABLE);       // let's go

        while(count);
}

int main( void )
{
        // ---------   GPIO Config ---------------------------

        GPIO_DeInit(PORT);

        GPIO_Init(PORT, LED|GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Fast);

        // ---------- CLK Config -----------------------
        CLK_DeInit();
        CLK_SYSCLKDivConfig(CLK_SYSCLKDiv_1);
        CLK_PeripheralClockConfig(CLK_Peripheral_TIM4, ENABLE);
        CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE);

        // ---------- TIM 4 Init -----------------------------
        TIM4_DeInit();

        // ---------- TIM 2 Init -----------------------------
        TIM2_DeInit();
        TIM2_TimeBaseInit(TIM2_Prescaler_1, TIM2_CounterMode_Up, 999);
        TIM2_OC1Init(TIM2_OCMode_PWM1, TIM2_OutputState_Enable, 500, TIM2_OCPolarity_High, TIM2_OCIdleState_Set);
        TIM2_InternalClockConfig();

        TIM2_ARRPreloadConfig(ENABLE);
        TIM2_CtrlPWMOutputs(ENABLE);
        TIM2_Cmd(ENABLE);

        enableInterrupts();


        for(;;)
        {
                delay_ms(1000);
                GPIO_ToggleBits(PORT, LED);
                TIM2_SetCompare1(100);

                delay_ms(1000);
                GPIO_ToggleBits(PORT, LED);
                TIM2_SetCompare1(500);

                delay_ms(1000);
                GPIO_ToggleBits(PORT, LED);
                TIM2_SetCompare1(900);

        }


}

В отличии от варианта для S-серии, здесь кроме того что необходимо подключать таймер к шине тактирования командой CLK_PeripheralClockConfig(CLK_Peripheral_TIM2, ENABLE), еще необходимо настроить ножку на выход командой GPIO_Init(PORT, LED|GPIO_Pin_0, GPIO_Mode_Out_PP_Low_Fast).

Т.о. имеем два светодиода подключенным к ножкам B1 и B0. Первый периодически мигает, а второй меняет яркость с помощью ШИМ.

Скачать архив с полными исходниками можно здесь: скачать

поделиться: