Advanced timer–outputs a specified number of PWMs

1. Routine function;

Output PWM through TIM8_CH1 (multiplexed by PC6). In order to indicate the output status of PWM, we use Dupont line
Connect PC6 and PB0 to realize PWM output control LED1 on and off. Power-on default output 5 PWM control LED1
On and off five times. Then press the button KEY0, and 5 PWMs will be output to control LED1 to turn on and off five times.

2. Development board type;

STM32F429IGT6.

3. Hardware resources;

1) LED light
LED0-PB1
LED1-PB0
2) Independent buttons
KEY0-PH3
3) Timer 8 uses TIM8 channel 1 and is multiplexed by PC6.

4. Implementation of logical functions;

4.1. LED light related codes.

#ifndef __LED_H
#define __LED_H

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"

/****************************************************** *******************************************/
/* pin definition */

#define LED0_GPIO_PORT GPIOB
#define LED0_GPIO_PIN GPIO_PIN_1
#define LED0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB port clock enable */

#define LED1_GPIO_PORT GPIOB
#define LED1_GPIO_PIN GPIO_PIN_0
#define LED1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PB port clock enable */

/****************************************************** *******************************************/

/* LED port definition */
#define LED0(x) do{ x ? \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_SET): \
                      HAL_GPIO_WritePin(LED0_GPIO_PORT, LED0_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0) /* LED0 = RED */

#define LED1(x) do{ x ? \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_SET): \
                      HAL_GPIO_WritePin(LED1_GPIO_PORT, LED1_GPIO_PIN, GPIO_PIN_RESET); \
                  }while(0) /* LED1 = GREEN */

/* LED negation definition */
#define LED0_TOGGLE() do{ HAL_GPIO_TogglePin(LED0_GPIO_PORT, LED0_GPIO_PIN); }while(0) /* LED0 = !LED0 */
#define LED1_TOGGLE() do{ HAL_GPIO_TogglePin(LED1_GPIO_PORT, LED1_GPIO_PIN); }while(0) /* LED1 = !LED1 */

/****************************************************** *******************************************/
/*External interface function*/
void led_init(void); /* Initialization */

#endif
#include "./BSP/led/led.h"
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"

/**
 * @brief Initialize the LED related IO port and enable the clock
 * @param none
 * @retval None
 */
void led_init(void)
{
    GPIO_InitTypeDef gpio_init_struct;
    
    LED0_GPIO_CLK_ENABLE(); /* LED0 clock enable */
    LED1_GPIO_CLK_ENABLE(); /* LED1 clock enable */

    gpio_init_struct.Pin = LED0_GPIO_PIN; /* LED0 pin */
    gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* push-pull output */
    gpio_init_struct.Pull = GPIO_PULLUP; /* pull up */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(LED0_GPIO_PORT, & amp;gpio_init_struct); /* Initialize LED0 pin */

    gpio_init_struct.Pin = LED1_GPIO_PIN; /* LED1 pin */
    HAL_GPIO_Init(LED1_GPIO_PORT, & amp;gpio_init_struct); /* Initialize LED1 pin */
    
    LED0(1); /* Turn off LED0 */
    LED1(1); /* Turn off LED1 */
}

4.2. Key related codes.

#ifndef __KEY_H
#define __KEY_H

#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"

/****************************************************** *****************************************/
/* pin definition */

#define KEY0_GPIO_PORT GPIOH
#define KEY0_GPIO_PIN GPIO_PIN_3
#define KEY0_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH port clock enable */

#define KEY1_GPIO_PORT GPIOH
#define KEY1_GPIO_PIN GPIO_PIN_2
#define KEY1_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOH_CLK_ENABLE(); }while(0) /* PH port clock enable */

#define KEY2_GPIO_PORT GPIOC
#define KEY2_GPIO_PIN GPIO_PIN_13
#define KEY2_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0) /* PC port clock enable */

#define WKUP_GPIO_PORT GPIOA
#define WKUP_GPIO_PIN GPIO_PIN_0
#define WKUP_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PA port clock enable */

/****************************************************** *****************************************/

#define KEY0 HAL_GPIO_ReadPin(KEY0_GPIO_PORT, KEY0_GPIO_PIN) /* Read KEY0 pin */
#define KEY1 HAL_GPIO_ReadPin(KEY1_GPIO_PORT, KEY1_GPIO_PIN) /* Read KEY1 pin */
#define KEY2 HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_GPIO_PIN) /* Read KEY2 pin */
#define WK_UP HAL_GPIO_ReadPin(WKUP_GPIO_PORT, WKUP_GPIO_PIN) /* Read WKUP pin */


#define KEY0_PRES 1 /* KEY0 pressed */
#define KEY1_PRES 2 /* KEY1 pressed */
#define KEY2_PRES 3 /* KEY2 pressed */
#define WKUP_PRES 4 /* KEY_UP pressed (i.e. WK_UP) */

void key_init(void); /* key initialization function */
uint8_t key_scan(uint8_t mode); /* key scan function */

#endif


#include "./BSP/key/key.h"
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"


/**
 * @brief key initialization function
 * @param None
 * @retval None
 */
void key_init(void)
{
    GPIO_InitTypeDef gpio_init_struct; /* GPIO configuration parameter storage variables */
    KEY0_GPIO_CLK_ENABLE(); /* KEY0 clock enable */
    KEY1_GPIO_CLK_ENABLE(); /* KEY1 clock enable */
    KEY2_GPIO_CLK_ENABLE(); /* KEY2 clock enable */
    WKUP_GPIO_CLK_ENABLE(); /* WKUP clock enable */

    gpio_init_struct.Pin = KEY0_GPIO_PIN; /* KEY0 pin */
    gpio_init_struct.Mode = GPIO_MODE_INPUT; /* input */
    gpio_init_struct.Pull = GPIO_PULLUP; /* pull up */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(KEY0_GPIO_PORT, & amp;gpio_init_struct); /* KEY0 pin mode setting, pull-up input */

    gpio_init_struct.Pin = KEY1_GPIO_PIN; /* KEY1 pin */
    gpio_init_struct.Mode = GPIO_MODE_INPUT; /* input */
    gpio_init_struct.Pull = GPIO_PULLUP; /* pull up */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(KEY1_GPIO_PORT, & amp;gpio_init_struct); /* KEY1 pin mode setting, pull-up input */

    gpio_init_struct.Pin = KEY2_GPIO_PIN; /* KEY2 pin */
    gpio_init_struct.Mode = GPIO_MODE_INPUT; /* input */
    gpio_init_struct.Pull = GPIO_PULLUP; /* pull up */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(KEY2_GPIO_PORT, & amp;gpio_init_struct); /* KEY2 pin mode setting, pull-up input */

    gpio_init_struct.Pin = WKUP_GPIO_PIN; /* WKUP pin */
    gpio_init_struct.Mode = GPIO_MODE_INPUT; /* input */
    gpio_init_struct.Pull = GPIO_PULLDOWN; /* Pull down */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(WKUP_GPIO_PORT, & amp;gpio_init_struct); /* WKUP pin mode setting, pull-down input */

}

/**
 * @brief key scanning function
 * @note This function has response priority (press multiple keys at the same time): WK_UP > KEY2 > KEY1 > KEY0!!
 * @param mode:0 / 1, the specific meaning is as follows:
 * @arg 0, continuous pressing is not supported (when the key is pressed and held, only the first call will return the key value,
 * Must be released before pressing again to return to other key values)
 * @arg 1, supports continuous pressing (when the key is pressed and held, the key value will be returned each time the function is called)
 * @retval key value, defined as follows:
 * KEY0_PRES, 1, KEY0 pressed
 * KEY1_PRES, 2, KEY1 pressed
 * KEY2_PRES, 3, KEY2 pressed
 * WKUP_PRES, 4, WKUP pressed
 */
uint8_t key_scan(uint8_t mode)
{
    static uint8_t key_up = 1; /* Key press and release flag */
    uint8_t keyval = 0;

    if (mode) key_up = 1; /* Support double-click */

    if (key_up & amp; & amp; (KEY0 == 0 || KEY1 == 0 || KEY2 == 0 || WK_UP == 1)) /* The key release flag is 1, and any key is pressed */
    {
        delay_ms(10); /* debounce */
        key_up = 0;

        if (KEY0 == 0) keyval = KEY0_PRES;

        if (KEY1 == 0) keyval = KEY1_PRES;

        if (KEY2 == 0) keyval = KEY2_PRES;

        if (WK_UP == 1) keyval = WKUP_PRES;
    }
    else if (KEY0 == 1 & amp; & amp; KEY1 == 1 & amp; & amp; KEY2 == 1 & amp; & amp; WK_UP == 0) /* No keys are pressed, mark the keys as released */
    {
        key_up = 1;
    }

    return keyval; /* Return key value */
}

4.3. Advanced timer related code.

#ifndef ATIM_H
#define ATIM_H


#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"


/****************************************************** *************/
/* Timer definition */

#define ATIM_TIMX_PWM TIM8
#define ATIM_TIMX_PWM_IRQn TIM8_UP_TIM13_IRQn
#define ATIM_TIMX_PWM_IRQHandler TIM8_UP_TIM13_IRQHandler
#define ATIM_TIMX_PWM_CH TIM_CHANNEL_1
#define ATIM_TIMX_NPWM_CHY_CCRX TIM8->CCR1 /* Output comparison register of channel Y */
#define ATIM_TIMX_PWM_CLK_ENABLE() do{ __HAL_RCC_TIM8_CLK_ENABLE(); }while(0) /* TIM8 clock enable*/


/****************************************************** *************/
/* Pin definition */

#define ATIM_TIMX_GPIO_PORT GPIOC
#define ATIM_TIMX_GPIO_PIN GPIO_PIN_6
#define ATIM_TIMX_GPIO_AF GPIO_AF3_TIM8
#define ATIM_TIMX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOC_CLK_ENABLE(); }while(0)



/****************************************************** *************/
/* External function definition */

void atim_init(uint16_t per, uint16_t pod); /* Basic parameter initialization*/
void atim_timx_npwm_chy_set(uint32_t npwm); /* Set the number of output PWMs */


#endif
#include <stdio.h>
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/atim/atim.h"


TIM_HandleTypeDef atim_hanldle_init; /* timer handle */

/* g_npwm_remain indicates how many pulses are left to send.
 * Send up to 256 pulses each time
 */
static uint32_t g_npwm_remain = 0;


/*
 * Function name: atim_init
 * Function: TIM basic parameter initialization
 * Function parameters: prr prescaler value
 * pod reload value
 * Function return value: void
 */

void atim_init(uint16_t per, uint16_t pod)
{
    TIM_OC_InitTypeDef atim_oc_init_struct = {0}; /* PWM pipeline configuration structure class pointer */
    
    atim_hanldle_init.Instance = ATIM_TIMX_PWM; /* Select TIM8 */
    atim_hanldle_init.Init.CounterMode = TIM_COUNTERMODE_UP; /* Count up */
    atim_hanldle_init.Init.Prescaler = per; /* prescaler value */
    atim_hanldle_init.Init.Period = pod; /* Reload value */
    atim_hanldle_init.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; /* Enable ARR as cache */
    atim_hanldle_init.Init.RepetitionCounter = 0; /* Set the repetition counter value to 0 */
    HAL_TIM_PWM_Init( & amp;atim_hanldle_init); /* PWM initialization */
    
    atim_oc_init_struct.OCMode = TIM_OCMODE_PWM1; /* Select PWM1 mode*/
    atim_oc_init_struct.Pulse = pod/2; /* Occupancy ratio */
    atim_oc_init_struct.OCPolarity = TIM_OCPOLARITY_HIGH; /* Output polarity high */
    HAL_TIM_PWM_ConfigChannel( & amp;atim_hanldle_init, & amp;atim_oc_init_struct, ATIM_TIMX_PWM_CH); /* PWM pipeline configuration */
}


/*
 * Function name: HAL_TIM_PWM_MspInit
 * Function: Initialization of pins, clocks, NVIC, etc.
 * Function parameters: timer handle
 * Function return value: void
 */

void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
    GPIO_InitTypeDef atim_gpio_init_struct;
    
    ATIM_TIMX_GPIO_CLK_ENABLE();
    ATIM_TIMX_PWM_CLK_ENABLE();
    
    atim_gpio_init_struct.Pin = ATIM_TIMX_GPIO_PIN;
    atim_gpio_init_struct.Mode = GPIO_MODE_AF_PP; /* Multiplex push-pull output*/
    atim_gpio_init_struct.Pull = GPIO_PULLUP; /* pull-up */
    atim_gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    atim_gpio_init_struct.Alternate = ATIM_TIMX_GPIO_AF; /* Port multiplexing */
    HAL_GPIO_Init(ATIM_TIMX_GPIO_PORT, & amp;atim_gpio_init_struct); /* GPIO initialization */
    
    HAL_NVIC_SetPriority(ATIM_TIMX_PWM_IRQn, 1, 3); /* Set priority */
    HAL_NVIC_EnableIRQ(ATIM_TIMX_PWM_IRQn); /* Enable interrupt */
    
    __HAL_TIM_ENABLE_IT( & amp;atim_hanldle_init, TIM_IT_UPDATE); /* Enable update interrupt */
    HAL_TIM_Base_Start( & amp;atim_hanldle_init); /* Start PWM channel */
}


/*
 * Function name: atim_timx_npwm_chy_set
 * Function: Set the number of output PWM
 * Function parameters: npwm Number of PWMs
 * Function return value: void
 */

void atim_timx_npwm_chy_set(uint32_t npwm)
{
    if (npwm == 0) return;

    g_npwm_remain = npwm; /* Save the number of pulses */
    HAL_TIM_GenerateEvent( & amp;atim_hanldle_init, TIM_EVENTSOURCE_UPDATE); /* Generate an update event and process pulse output in the interrupt */
    __HAL_TIM_ENABLE( & amp;atim_hanldle_init); /* Enable timer TIMX */
}


/*
 * Function name: ATIM_TIMX_PWM_IRQHandler
 * Function: Interrupt service function
 * Function parameters: void
 * Function return value: void
 */

void ATIM_TIMX_PWM_IRQHandler(void)
{
    uint16_t npwm = 0;
    
    if(__HAL_TIM_GET_FLAG( & amp;atim_hanldle_init,TIM_FLAG_UPDATE) != RESET)
    {
        if(g_npwm_remain >= 256)
        {
            g_npwm_remain = g_npwm_remain-256;
            npwm = 256;
        }else if(g_npwm_remain < 256)
        {
            npwm = g_npwm_remain%6;
            g_npwm_remain = 0;
        }
        
        if(npwm)
        {
            ATIM_TIMX_PWM->RCR = npwm-1; /* Set the value of the repetition register to npwm-1, that is, npwm pulses */
            HAL_TIM_GenerateEvent( & amp;atim_hanldle_init,TIM_EVENTSOURCE_UPDATE); /* Generate an update event and process pulse output in the interrupt */
            __HAL_TIM_ENABLE( & amp;atim_hanldle_init); /* Enable timer */
        }else{
            ATIM_TIMX_PWM->CR1 & amp;= ~(1 << 0); /* Turn off the timer TIMX, using HAL Disable will clear the PWM channel information, not used here */
        }

        __HAL_TIM_CLEAR_FLAG( & amp;atim_hanldle_init,TIM_FLAG_UPDATE); /* Clear flag */
    }
}

4.4. Main function function implementation.

#include <stdio.h>
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/atim/atim.h"
#include "./BSP/key/key.h"
#include "./BSP/led/led.h"


int main(void)
{
    uint8_t key = 0;
    uint8_t t = 0;
    GPIO_InitTypeDef gpio_init_struct;
    
    HAL_Init(); /* HAL library initialization */
    sys_stm32_clock_init(360, 25, 2, 8); /* The system clock is set to 180Mhz */
    delay_init(180); /* Delay function initialization */
    usart_init(115200); /* Serial port initialization */
    led_init(); /* led initialization */
    key_init(); /* key initialization */
    atim_init(9000-1,10000-1); /* Advanced timer initialization */
    
    gpio_init_struct.Pin = LED1_GPIO_PIN;
    gpio_init_struct.Mode = GPIO_MODE_INPUT; /* LED1 reselects the floating input mode to avoid conflict with PC6 */
    gpio_init_struct.Pull = GPIO_PULLUP; /* pull up */
    gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* high speed */
    HAL_GPIO_Init(LED1_GPIO_PORT, & amp;gpio_init_struct);
    
    atim_timx_npwm_chy_set(5); /* Output 5 PWM waves (control TIM8_CH1, that is, PC6 outputs 5 pulses) */
    
    while(1)
    {
        key = key_scan(1); /* key scan*/
        
        if(key == KEY0_PRES) /* If key KEY0 is pressed */
        {
            atim_timx_npwm_chy_set(5); /* Output 5 PWM waves (control TIM8_CH1, that is, PC6 outputs 5 pulses) */
        }
        
        t + + ;
        if(t > 50)
        {
            LED0_TOGGLE(); /* Invert the status of light LED1 */
        }
    }
}

5. Download verification.

After downloading the code, you can see that LED1 lights up and off five times, and then every time we press the button KEY0, LED1 lights up and off five times. LED0 turns on and off once after a while, indicating that the program is running normally.