STM32+CubeMX+Keil+HAL Library

 

Catalog

1. Set up GPIO:

2. printf redirection

3. Log information format

4. Personalized Output

5. CubeMX+HAL Open Serial Interrupt

6. Open external interrupt

7. Clock Tree Basic Operations

8. Universal timer configuration

9. CubeMX Configuration Timer

(1) Set the timer clock to 72M

(2) Select internal clock

(3) Configure timer

(4) Open interrupt

Timer interrupt callback function: (smoothing filter)

10. CubeMX Configuration pwm

11. CubeMX Configuration spwm

12. CubeMX Configuration ADC

(1) Polling

(2) DMA mode

13. IIC and SPI

STM32 Series Videos (CubeMX+MDK5+HAL Library+Library Functions One-stop Learning)_ Bell-Bell-Bell_ bilibili

1. Set up GPIO:

(1) Set PA8 as output, push-pull up, initial state is high level:

(2) Using User Label inside pin configuration, you can generate corresponding macros, improve code reuse, and facilitate portability.

In the corresponding project code, there are macro definitions as follows:

2. printf redirection

int fputc(int ch, FILE *f)
{
	uint8_t temp[1] = {ch};
	HAL_UART_Transmit(&huart1, temp, 1, 2);
	return ch;
}

3. Log information format

Refer to the current mainstream embedded, Android and other output methods:

[log level] File name: Log information
//Example: [info] main. C: init ok!
//Example: [debug] adc. C: adc_ GetValue -> 3.3V

(1) Conditional compilation can be used to decide whether to print Log information:

#Define Log 1 // Change to 0 if you don't want to print


#if Log
printf("[info]main.c:init!\r\n");
#endif

(2) Variable parameter macros

#define USER_MAIN_DEBUG


#ifdef USER_MAIN_DEBUG


#define user_main_printf(format, ...) printf( format "\r\n",##__VA_ARGS__)

#define user_main_info(format, ...) printf("[main]info:" format "\r\n",##__VA_ARGS__)

#define user_main_debug(format, ...) printf("[main]debug:" format "\r\n",##__VA_ARGS__)

#define user_main_error(format, ...) printf("[main]error:" format "\r\n",##__VA_ARGS__)

#else

#define user_main_printf(format, ...)

#define user_main_info(format, ...) 

#define user_main_debug(format, ...)

#define user_main_error(format, ...)

#endif

define a USER_when I need to print serial information MAIN_ DEBUG, comment it out when I don't need it.

4. Personalized Output

You can use this website to design characters: http://patorjk.com/software/taag/

printf(".__           .__  .__                            .__       .___");
printf("|  |__   ____ |  | |  |   ______  _  _____________|  |    __| _/");
printf("|  |  \\_/ __ \\|  | |  |  /  _ \\ \\/ \\/ /  _ _  __ \\  |   / __ | ");
printf("|   Y  \\  ___/|  |_|  |_(  <_> )     (  <_> )  | \\/  |__/ /_/ | ");
printf("|___|  /\\___  >____/____/\\____/ \\/\\_/ \\____/|__|  |____/\\____ |");
printf("     \\/     \\/                                               \\/");

5. CubeMX+HAL Open Serial Interrupt

 

6. Open external interrupt

In addition, the GPIO configuration for EXTI external interrupts is as follows: default drop-down, rise edge trigger.

Then write a callback function for the external interrupt.

eg: measure the frequency of pwm.

In 1s time, the number of rise edges is the frequency. That is, the number of times an external interrupt enters within a second is the frequency. Pwm_for each interrupt The value of value plus 1,1s is the frequency.

When there is a rising edge, entering an external interrupt will pwm_value plus 1.

int pwm_value = 0;

int main()
{
    pwm_value = 0;
    HAL_Delay(1000);   # Pwm_obtained after a delay of 1 s Value is the frequency value
    printf("[\tmain]info:pwm_value = %d\r\n", pwm_value);
}

# Callback function for external interruption
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    if(GPIO_Pin == PWM_Pin)     # Determine if triggered pins are defined pins   
    {
        pwm_value++;
    }
}

7. Clock Tree Basic Operations

(1) Enable external clock source

Generally, the internal clock is used by default in the generated project, so the external clock is enabled first.

(2) Then set the HCLK clock frequency to the maximum, for example, the maximum of f103 is 72M, and the maximum of f406 is 84M.

(3) Finally, on-demand frequency division for different peripherals.

8. Universal timer configuration

eg: Flip the LED at a specific time.

# Overflow Time
Tout = (arr+1)*(psc+1)/Tclk
 Frequency: Tclk/(psc+1) MHz

void Timer3_Init(uint16_t arr,uint16_t psc)
{
    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;
    NVIC_InitTypeDef  NVIC_InitStructure;	

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //Clock Enabling

	TIM_TimeBaseStructure.TIM_Period = arr; //Set the value of the auto reload register cycle for the next update event load activity 	  Count to 5000 to 500 ms
	TIM_TimeBaseStructure.TIM_Prescaler =psc; //Set the counting frequency of the pre-divided frequency value 10Khz used as the TIMx clock frequency divisor  
	TIM_TimeBaseStructure.TIM_ClockDivision = 0; //Set clock division: TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM Up Count Mode
	TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //According to TIM_ Unit of time base for initializing TIMx with parameters specified in TimeBaseInitStruct
	TIM_ITConfig(TIM3,TIM_IT_Update|TIM_IT_Trigger,ENABLE);   //Timer interrupt enable

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);	//Set NVIC interrupt grouping 2:2 bit preemption priority, 2 bit response priority
    NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //TIM3 Interruption
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;  //Priority Level 1
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;  //From Priority Level 3
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ Channel Enabled
	NVIC_Init(&NVIC_InitStructure);  //According to NVIC_ Parameters specified in InitStruct initialize peripheral NVIC registers

	TIM_Cmd(TIM3, ENABLE);  //Enable TIMx peripherals					 
}

void TIM3_IRQHandler(void)   //TIM3 Interruption
{
    static uint8_t cnt = 0;    //Static variable
	if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //Check whether the specified TIM interrupt occurs or not: TIM interrupt source 
    {
        /*Interrupt operation*/
        cnt++;
		TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //Clear interrupt pending bits for TIMx: TIM interrupt source 
	}
    if(cnt == 10)
    {
        LED = ~LED;
        cnt = 0;
    }
}

9. CubeMX Configuration Timer

(1) Set the timer clock to 72M

(2) Select internal clock

(3) Configure timer

Main configurations: Timing time, and whether to reset the timer.

Timer frequency = Timer clock /(Pre-frequency + 1)/(Count value + 1) Hz.

Timing time = 1/Timing frequency s.

(4) Open interrupt

Basic timer:

Advanced timer:

Timer interrupt callback function: (smoothing filter)

eg: Smooth Filter - Let the sampled value be filtered all the time by another "thread" and take its value directly when needed.

void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    if(htim->Instance == htim1.Instance)
    {
        pwm_sum += pwm_value * 10;  //pwm_sum accumulation
        pwm_sum -= pwm_avg;         //pwm_sum minus the last average
        pwm_avg = pwm_sum * 1.0 / 5; //Update the average of pwm
        pwm_value_final = pwm_avg;   //pwm_value_final is the current pwm frequency
        pwm_value = 0;               //Will pwm_value empty, recalculate
    }
}

10. CubeMX Configuration pwm

(1) Enabling PWM channels

Here, the Channel1 of TIM2 is set as the PWM output channel.

(PWM Generation CHx Forward, PWM Generation CHxN Reverse, PWM Generation CHx CHxN Pair Complementary pwm Output)

(2) Configuration frequency and duty cycle

Frequency = Timer Clock/ (Prescaler + 1) / (Cound Period + 1) Hz

Duty Cycle = Pulse / Cound Period Count%

(3) Subordinate code implements a process where the pwm duty cycle gradually increases to 1 and then becomes 0.

int main(void)
{
    int pwm = 0;
  
    HAL_Init();

  /* Configure the system clock */
    SystemClock_Config();

  /* Initialize all configured peripherals */
    MX_GPIO_Init();
    MX_TIM1_Init();

    # Channel 1 enabling Tim 1
    HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

    while (1)
    {
        HAL_Delay(5);
        # Modify the PWM comparison value of channel 1 of tim1 to pwm++, i.e. modify the duty cycle
        __HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, pwm++);
        pwm = (pwm > 999) ? 0:pwm;
    }
}

11. CubeMX Configuration spwm

On the basis of PWM, SPWM makes the duty cycle of PWM change sinusoidally.

STM32 Series Videos (CubeMX+MDK5+HAL Library+Library Functions One-stop Learning)_ Bell-Bell-Bell_ bilibili

Omitted.

12. CubeMX Configuration ADC

Typically 12 bits with a precision of 3.3/4096 v.

Read ADC by polling, DMA.

(1) Polling

The CH0 of ADC1 is configured first and enables continuous collection.

while(1)
{
    HAL_ADC_Start(&hadc1);//Start ADC Loading
    HAL_ADC_PollForConversion(&hadc1, 50);//Waiting for conversion to complete, the second parameter represents the time-out, in ms.
    if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc1), HAL_ADC_STATE_REG_EOC))
    { 
        AD_Value = HAL_ADC_GetValue(&hadc1);//Read ADC conversion data, 12 bits
        printf("[\tmain]info:v=%.1fmv\r\n",AD_Value*3300.0/4096);//Print Log
    }
}

(2) DMA mode

1. Initialize two ADC channels

(2) Configuration

Enables Continuous Conversion Mode;

The number of conversion channels selected by the ADC rule group is 2 (Number Of Conversion);

Configure the input channels of Rank to convert channel 0 and channel 1, respectively.

3. Add DMA

Set to continuous transmission mode, data length is word.

(4) Sample code

The data of array even subscript is channel 0, and the data of array odd subscript is channel 1.

In the program, the even subscript data of the array is added together to find the average value, and then the data is converted to the voltage value, that is, the voltage value of the PA0 pin. The same is true for another channel.

uint32_t ADC_Value[100];  //Data Cache Array
uint8_t i;
uint32_t ad1, ad2;  //ad1 stores the voltage value of PA0; ad2 stores the voltage value of PA1

int main(void)
{
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_USART1_UART_Init();
  MX_TIM1_Init();
  MX_DMA_Init();
  MX_ADC1_Init();

  HAL_TIM_Base_Start_IT(&htim1);
# Turn on ADC conversion by DMA. The second parameter is the starting address of the data store, and the third parameter is the length of the data transmitted by DMA.
  HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_Value, 100);  
  while (1)
  {
    HAL_Delay(500);
    for(i = 0,ad1 =0,ad2=0; i < 100;)
    {
        ad1 += ADC_Value[i++];
        ad2 += ADC_Value[i++];
    }
    ad1 /= 50;
    ad2 /= 50;
    printf("\r\n********ADC-DMA-Example********\r\n");
    printf("[\tmain]info:AD1_value=%1.3fV\r\n", ad1*3.3f/4096);
    printf("[\tmain]info:AD2_value=%1.3fV\r\n", ad2*3.3f/4096);
  }

13. IIC and SPI

Keywords: Embedded system Single-Chip Microcomputer stm32 HAL

Added by sgbalsekar on Sat, 26 Feb 2022 19:21:01 +0200