STM8S+SDCC+SPL: Использование встроенного бипера, калибровка LSI генератора, модуль автоматического пробуждения AWU

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

В STM8S имеется встроенный модуль для подключения пьезодинамика, который может генерировать звук с частотами 1, 2, 4 кГц. Он довольно простой, НО тактируется он от низкоскоростного генератора LSI, который перед использованием следует откалибровать, что уже не так просто.

В примерах стандартной периферийной библиотеке(далее SPL) имеется пример функции для калибровки LSI генератора, который может быть полезен всякий раз, когда требуется LSI.

Сам генератор LSI используется для тактирования низкоскоростной периферии, и первое что мне приходит в голову - это Auto Wakeup Unit (AWU) т.е. модуль автопробуждения. С помощью этого модуля можно пробуждать микроконтроллер из спящего режима по таймеру. Если здесь на примере attiny13a для подобной же цели использовался watchdog, то в STM8 имеется для этого специальный модуль AWU.

Но, обо всем по порядку. Устройство BEEP модуля представлено на картинке ниже:

Имеется всего один управляющий регистр непосредственно относящийся к BEEP модулю, в SPL он описан следующей структурой:

typedef struct BEEP_struct
{
  __IO uint8_t CSR; /*!< BEEP Control status register */
}

При инициализации в него записывается значение 0x1F:

#define BEEP_CSR_RESET_VALUE ((uint8_t)0x1F)

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

void BEEP_DeInit(void);
void BEEP_Init(BEEP_Frequency_TypeDef BEEP_Frequency);
void BEEP_Cmd(FunctionalState NewState);
void BEEP_LSICalibrationConfig(uint32_t LSIFreqHz);

Ниже приведен пример программы использующая BEEP-модуль:

#include "stm8s.h"
#include "stm8s_gpio.h"
#include "stm8s_clk.h"
#include "stm8s_tim4.h"
#include "stm8s_tim1.h"
#include "stm8s_awu.h"
#include "stm8s_beep.h"

#define LED_PORT GPIOB
#define LED GPIO_PIN_5

#define TIM4_PERIOD       124

volatile uint16_t count;
uint32_t LSIMeasurment(void);

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);

    // ------------- BEEP ------------------
    BEEP_LSICalibrationConfig(LSIMeasurment());

    enableInterrupts();


    for(;;)
    {

        // ---------- 1kHz ---------------
        GPIO_WriteLow(LED_PORT, LED);
        delay_ms(100);
        BEEP_Init(BEEP_FREQUENCY_1KHZ);
        BEEP_Cmd(ENABLE);
        GPIO_WriteHigh(LED_PORT, LED);
        delay_ms(1000);

        // ---------- 2kHz ---------------
        BEEP_Cmd(DISABLE);
        GPIO_WriteLow(LED_PORT, LED);
        delay_ms(100);
        BEEP_Init(BEEP_FREQUENCY_2KHZ);
        BEEP_Cmd(ENABLE);
        GPIO_WriteHigh(LED_PORT, LED);
        delay_ms(1000);

        // ---------- 4kHz ---------------
        BEEP_Cmd(DISABLE);
        GPIO_WriteLow(LED_PORT, LED);
        delay_ms(100);
        BEEP_Init(BEEP_FREQUENCY_4KHZ);
        BEEP_Cmd(ENABLE);
        GPIO_WriteHigh(LED_PORT, LED);
        delay_ms(1000);
        BEEP_Cmd(DISABLE);

    }
}



uint32_t LSIMeasurment(void)
{

  uint32_t lsi_freq_hz = 0x0;
  uint32_t fmaster = 0x0;
  uint16_t ICValue1 = 0x0;
  uint16_t ICValue2 = 0x0;

  /* Get master frequency */
  fmaster = CLK_GetClockFreq();

  /* Enable the LSI measurement: LSI clock connected to timer Input Capture 1 */
  AWU->CSR |= AWU_CSR_MSR;

#if defined (STM8S903) || defined (STM8S103) || defined (STM8S003)
  /* Measure the LSI frequency with TIMER Input Capture 1 */

  /* Capture only every 8 events!!! */
  /* Enable capture of TI1 */
  TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0);

  /* Enable TIM1 */
  TIM1_Cmd(ENABLE);

  /* wait a capture on cc1 */
  while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);
  /* Get CCR1 value*/
  ICValue1 = TIM1_GetCapture1();
  TIM1_ClearFlag(TIM1_FLAG_CC1);


  /* wait a capture on cc1 */
  while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);
  /* Get CCR1 value*/
  ICValue2 = TIM1_GetCapture1();
  TIM1_ClearFlag(TIM1_FLAG_CC1);

  /* Disable IC1 input capture */
  TIM1->CCER1 &= (uint8_t)(~TIM1_CCER1_CC1E);
  /* Disable timer2 */
  TIM1_Cmd(DISABLE);

#else
  /* Measure the LSI frequency with TIMER Input Capture 1 */

  /* Capture only every 8 events!!! */
  /* Enable capture of TI1 */
  TIM3_ICInit(TIM3_CHANNEL_1, TIM3_ICPOLARITY_RISING, TIM3_ICSELECTION_DIRECTTI, TIM3_ICPSC_DIV8, 0);

  /* Enable TIM3 */
  TIM3_Cmd(ENABLE);

        /* wait a capture on cc1 */
  while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1);
        /* Get CCR1 value*/
  ICValue1 = TIM3_GetCapture1();
  TIM3_ClearFlag(TIM3_FLAG_CC1);

  /* wait a capture on cc1 */
  while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1);
    /* Get CCR1 value*/
  ICValue2 = TIM3_GetCapture1();
        TIM3_ClearFlag(TIM3_FLAG_CC1);

  /* Disable IC1 input capture */
  TIM3->CCER1 &= (uint8_t)(~TIM3_CCER1_CC1E);
  /* Disable timer3 */
  TIM3_Cmd(DISABLE);
#endif

  lsi_freq_hz = (8 * fmaster) / (ICValue2 - ICValue1);

  /* Disable the LSI measurement: LSI clock disconnected from timer Input Capture 1 */
  AWU->CSR &= (uint8_t)(~AWU_CSR_MSR);

 return (lsi_freq_hz);
}

Здесь последовательно, в цикле, меняется тональность пъезодинамика: 1кГц, 2кГц, 4кГц.

Попробуем разобраться, с тем, что же делают используемые функции.

void BEEP_Init(BEEP_Frequency_TypeDef BEEP_Frequency)
{
  /* Check parameter */
  assert_param(IS_BEEP_FREQUENCY_OK(BEEP_Frequency));

  /* Set a default calibration value if no calibration is done */
  if ((BEEP->CSR & BEEP_CSR_BEEPDIV) == BEEP_CSR_BEEPDIV)
  {
    BEEP->CSR &= (uint8_t)(~BEEP_CSR_BEEPDIV); /* Clear bits */
    BEEP->CSR |= BEEP_CALIBRATION_DEFAULT;
  }

  /* Select the output frequency */
  BEEP->CSR &= (uint8_t)(~BEEP_CSR_BEEPSEL);
  BEEP->CSR |= (uint8_t)(BEEP_Frequency);
}

функция BEEP_Init() устанавливает значение BSEL в регистре BEEP_CSR, т.е. переключает частоту. Используемые константы:

#define BEEP_CSR_BEEPSEL ((uint8_t)0xC0) /*!< Beeper frequency selection mask */
#define BEEP_CSR_BEEPEN  ((uint8_t)0x20) /*!< Beeper enable mask */
#define BEEP_CSR_BEEPDIV ((uint8_t)0x1F) /*!< Beeper Divider prescalar mask */

typedef enum {
  BEEP_FREQUENCY_1KHZ = (uint8_t)0x00,  /*!< Beep signal output frequency equals to 1 KHz */
  BEEP_FREQUENCY_2KHZ = (uint8_t)0x40,  /*!< Beep signal output frequency equals to 2 KHz */
  BEEP_FREQUENCY_4KHZ = (uint8_t)0x80   /*!< Beep signal output frequency equals to 4 KHz */
}

регистр BEEP_CSR:

Т.е. здесь мы можем выставить частоту бипера по формуле: Частота_бипера=Частота_LSI/(8/2^BSEL * BDIV);
При этом BDIV не должен принимать значения 0x1F, а BSEL не должно быть более 0x10.

С BEEP_Cmd() думаю все понятно. Включает,выключает:

void BEEP_Cmd(FunctionalState NewState)
{
  if (NewState != DISABLE)
  {
    /* Enable the BEEP peripheral */
    BEEP->CSR |= BEEP_CSR_BEEPEN;
  }
  else
  {
    /* Disable the BEEP peripheral */
    BEEP->CSR &= (uint8_t)(~BEEP_CSR_BEEPEN);
  }
}

В BEEP_LSICalibrationConfig(uint32_t LSIFreqHz) рассчитывается и устанавливается BDIV:

void BEEP_LSICalibrationConfig(uint32_t LSIFreqHz)
{
  uint16_t lsifreqkhz;
  uint16_t A;

  /* Check parameter */
  assert_param(IS_LSI_FREQUENCY_OK(LSIFreqHz));

  lsifreqkhz = (uint16_t)(LSIFreqHz / 1000); /* Converts value in kHz */

  /* Calculation of BEEPER calibration value */

  BEEP->CSR &= (uint8_t)(~BEEP_CSR_BEEPDIV); /* Clear bits */

  A = (uint16_t)(lsifreqkhz >> 3U); /* Division by 8, keep integer part only */

  if ((8U * A) >= ((lsifreqkhz - (8U * A)) * (1U + (2U * A))))
  {
    BEEP->CSR |= (uint8_t)(A - 2U);
  }
  else
  {
    BEEP->CSR |= (uint8_t)(A - 1U);
  }
}

Функция LSIMeasurment(void) вычисляет рабочую частоту LSI, используя для этого таймер TIM1 в качестве частотометра.

В самом начале функции, через регистр AWU_CSR, тактовая шина LSI подключается к входу канала захвата таймера TIM1, затем замеряется интервал между тактами LSI, на основании чего вычисляется реальная частота LSI.

Сам регистр AWU_CSR выглядит так:

Кроме MSR, здесь еще есть бит AWUEN, который включает режим авто-пробуждения, и AWUF - флаг который сигнализирует о том, что произошло прерывание по AWU вектору.

Раз уже речь зашла о AWU, приведу пример использования этого модуля:

(ДОБАВЛЕНО 15.04.18. Далее идет исправленная версия программы. В оригинале отсутствовал обработчик прерывания AWU

#include "stm8s.h"
#include "stm8s_gpio.h"
#include "stm8s_clk.h"
#include "stm8s_tim4.h"
#include "stm8s_tim1.h"
#include "stm8s_awu.h"

#define LED_PORT GPIOB
#define LED GPIO_PIN_5

#define TIM4_PERIOD       124

volatile uint16_t count;
uint32_t LSIMeasurment(void);

INTERRUPT_HANDLER(IRQ_Handler_AWU, 1)
{
__asm
    bres 0x50f0, #5     ;   Clear AWUF bit for AWU_CSR
__endasm;
}

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);

    // ------------- AWU ------------------
    AWU_LSICalibrationConfig(LSIMeasurment());
    AWU_Init(AWU_TIMEBASE_1S);

    enableInterrupts();


    for(;;)
    {
        GPIO_WriteLow(LED_PORT, LED);
        delay_ms(1000);

        GPIO_WriteHigh(LED_PORT, LED);
        halt();
    }
}



uint32_t LSIMeasurment(void)
{

  uint32_t lsi_freq_hz = 0x0;
  uint32_t fmaster = 0x0;
  uint16_t ICValue1 = 0x0;
  uint16_t ICValue2 = 0x0;

  /* Get master frequency */
  fmaster = CLK_GetClockFreq();

  /* Enable the LSI measurement: LSI clock connected to timer Input Capture 1 */
  AWU->CSR |= AWU_CSR_MSR;

#if defined (STM8S903) || defined (STM8S103) || defined (STM8S003)
  /* Measure the LSI frequency with TIMER Input Capture 1 */

  /* Capture only every 8 events!!! */
  /* Enable capture of TI1 */
  TIM1_ICInit(TIM1_CHANNEL_1, TIM1_ICPOLARITY_RISING, TIM1_ICSELECTION_DIRECTTI, TIM1_ICPSC_DIV8, 0);

  /* Enable TIM1 */
  TIM1_Cmd(ENABLE);

  /* wait a capture on cc1 */
  while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);
  /* Get CCR1 value*/
  ICValue1 = TIM1_GetCapture1();
  TIM1_ClearFlag(TIM1_FLAG_CC1);


  /* wait a capture on cc1 */
  while((TIM1->SR1 & TIM1_FLAG_CC1) != TIM1_FLAG_CC1);
  /* Get CCR1 value*/
  ICValue2 = TIM1_GetCapture1();
  TIM1_ClearFlag(TIM1_FLAG_CC1);

  /* Disable IC1 input capture */
  TIM1->CCER1 &= (uint8_t)(~TIM1_CCER1_CC1E);
  /* Disable timer2 */
  TIM1_Cmd(DISABLE);

#else
  /* Measure the LSI frequency with TIMER Input Capture 1 */

  /* Capture only every 8 events!!! */
  /* Enable capture of TI1 */
  TIM3_ICInit(TIM3_CHANNEL_1, TIM3_ICPOLARITY_RISING, TIM3_ICSELECTION_DIRECTTI, TIM3_ICPSC_DIV8, 0);

  /* Enable TIM3 */
  TIM3_Cmd(ENABLE);

        /* wait a capture on cc1 */
  while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1);
        /* Get CCR1 value*/
  ICValue1 = TIM3_GetCapture1();
  TIM3_ClearFlag(TIM3_FLAG_CC1);

  /* wait a capture on cc1 */
  while ((TIM3->SR1 & TIM3_FLAG_CC1) != TIM3_FLAG_CC1);
    /* Get CCR1 value*/
  ICValue2 = TIM3_GetCapture1();
        TIM3_ClearFlag(TIM3_FLAG_CC1);

  /* Disable IC1 input capture */
  TIM3->CCER1 &= (uint8_t)(~TIM3_CCER1_CC1E);
  /* Disable timer3 */
  TIM3_Cmd(DISABLE);
#endif

  lsi_freq_hz = (8 * fmaster) / (ICValue2 - ICValue1);

  /* Disable the LSI measurement: LSI clock disconnected from timer Input Capture 1 */
  AWU->CSR &= (uint8_t)(~AWU_CSR_MSR);

 return (lsi_freq_hz);
}

Здесь обычный blink, где задержка при свечении светодиода формируется через таймер TIM4, а в потухшем состоянии, через AWU, при котором чип уходит в спящий режим.

Кроме константы AWU_TIMEBASE_1S, можно также использовать следующие значения:

typedef enum
{
  AWU_TIMEBASE_NO_IT  = (uint8_t)0,    /*!< No AWU interrupt selected */
  AWU_TIMEBASE_250US  = (uint8_t)1,    /*!< AWU Timebase equals 0.25 ms */
  AWU_TIMEBASE_500US  = (uint8_t)2,    /*!< AWU Timebase equals 0.5 ms */
  AWU_TIMEBASE_1MS    = (uint8_t)3,    /*!< AWU Timebase equals 1 ms */
  AWU_TIMEBASE_2MS    = (uint8_t)4,    /*!< AWU Timebase equals 2 ms */
  AWU_TIMEBASE_4MS    = (uint8_t)5,    /*!< AWU Timebase equals 4 ms */
  AWU_TIMEBASE_8MS    = (uint8_t)6,    /*!< AWU Timebase equals 8 ms */
  AWU_TIMEBASE_16MS   = (uint8_t)7,    /*!< AWU Timebase equals 16 ms */
  AWU_TIMEBASE_32MS   = (uint8_t)8,    /*!< AWU Timebase equals 32 ms */
  AWU_TIMEBASE_64MS   = (uint8_t)9,    /*!< AWU Timebase equals 64 ms */
  AWU_TIMEBASE_128MS  = (uint8_t)10,   /*!< AWU Timebase equals 128 ms */
  AWU_TIMEBASE_256MS  = (uint8_t)11,   /*!< AWU Timebase equals 256 ms */
  AWU_TIMEBASE_512MS  = (uint8_t)12,   /*!< AWU Timebase equals 512 ms */
  AWU_TIMEBASE_1S     = (uint8_t)13,   /*!< AWU Timebase equals 1 s */
  AWU_TIMEBASE_2S     = (uint8_t)14,   /*!< AWU Timebase equals 2 s */
  AWU_TIMEBASE_12S    = (uint8_t)15,   /*!< AWU Timebase equals 12 s */
  AWU_TIMEBASE_30S    = (uint8_t)16    /*!< AWU Timebase equals 30 s */
} AWU_Timebase_TypeDef;

ДОБАВЛЕНО 6 сентября 2016г.

Без функции LSIMeasurment(), легко можно обойтись, если точность работы генератора LSI неважна. В этом случае в калибровочные функции: BEEP_LSICalibrationConfig()/AWU_LSICalibrationConfig(), вместо функции LSIMeasurment(), достаточно будет указать номинальную частоту генератора. Для чипов STM S-серии это будет 128000.

Для примера, первая программа без использования функции калибровки будет выглядеть так:

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

#define LED_PORT GPIOB
#define LED GPIO_PIN_5

#define TIM4_PERIOD       124

volatile uint16_t count;
uint32_t LSIMeasurment(void);

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);

      // ------------- BEEP ------------------
      BEEP_LSICalibrationConfig((uint32_t)128000);

      enableInterrupts();

      for(;;)
      {

              // ---------- 1kHz ---------------
              GPIO_WriteLow(LED_PORT, LED);
              delay_ms(100);
              BEEP_Init(BEEP_FREQUENCY_1KHZ);
              BEEP_Cmd(ENABLE);
              GPIO_WriteHigh(LED_PORT, LED);
              delay_ms(1000);

              // ---------- 2kHz ---------------
              BEEP_Cmd(DISABLE);
              GPIO_WriteLow(LED_PORT, LED);
              delay_ms(100);
              BEEP_Init(BEEP_FREQUENCY_2KHZ);
              BEEP_Cmd(ENABLE);
              GPIO_WriteHigh(LED_PORT, LED);
              delay_ms(1000);

              // ---------- 4kHz ---------------
              BEEP_Cmd(DISABLE);
              GPIO_WriteLow(LED_PORT, LED);
              delay_ms(100);
              BEEP_Init(BEEP_FREQUENCY_4KHZ);
              BEEP_Cmd(ENABLE);
              GPIO_WriteHigh(LED_PORT, LED);
              delay_ms(1000);
              BEEP_Cmd(DISABLE);

      }
}

LSI генератор в L-серии чипов STM8

В L-серии все устроено немного по другому. LSI генератор имеет рабочую частоту 38KHz вместо 128KHz, а функции Auto Wakeup доступны только через RTC модуль.

В BEEP модуле тоже есть изменения:

Если в S-серии в качестве генератора мог использоваться высокочастотный HSI, то в L-серии только низкочастотные LSI или LSE.

"Завести" BEEP модуль на stm8l051f3 мне к сожалению не удалось, но я все же оставлю здесь набросок программы в надежде профиксить ее в дальнейшем:

//////////////////////////////////////////////////////////
//   THIS IS NOT WORKING VERSION                        //
//   ЭТО НЕ РАБОЧАЯ ВЕРСИЯ                              //
//////////////////////////////////////////////////////////

#include "stm8l.h"
#include "stm8l_gpio.h"
#include "stm8l_clk.h"
#include "stm8l_tim4.h"
#include "stm8l_beep.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_Mode_Out_PP_Low_Fast);

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

        CLK_BEEPClockConfig(CLK_SYSCLKSource_LSI);
        CLK_LSICmd(ENABLE);

        // ---------- TIM4 Init -----------------------------
        TIM4_DeInit();

        BEEP_DeInit();
        BEEP_LSICalibrationConfig(38000);

        enableInterrupts();


        for(;;)
        {
              GPIO_ToggleBits(PORT, LED);
              delay_ms(1000);
              BEEP_Init(BEEP_Frequency_1KHz);
              BEEP_Cmd(ENABLE);
              GPIO_ToggleBits(PORT, LED);
              delay_ms(1000);

              BEEP_Cmd(DISABLE);
              GPIO_ToggleBits(PORT, LED);
              delay_ms(1000);
              BEEP_Init(BEEP_Frequency_2KHz);
              BEEP_Cmd(ENABLE);
              GPIO_ToggleBits(PORT, LED);
              delay_ms(1000);
              BEEP_Cmd(DISABLE);
        }

}

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

поделиться: