这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 活动中心 » 板卡试用 » 换逻辑分析仪_STM32F103_HAL库PWM呼吸灯

共2条 1/1 1 跳转至

换逻辑分析仪_STM32F103_HAL库PWM呼吸灯

工程师
2024-06-22 17:12:29   被打赏 23 分(兑奖)     打赏

使用 STM32F103 和 HAL 库实现 PWM 呼吸灯

硬件准备

STM32F103 微控制器开发板、LED 灯、连接线

软件准备

STM32CubeMX、Keil MDK 

知识PWM理解:

在PWM输出模式下,CNT为计数器当前值,ARR为自动重装载值,CCRx表示捕获/比较寄存器值。假定定时器工作在向上计数模式,当CNT小于CCRx时,TIMx_CHx通道输出低电平;当CNT等于或大于CCRx时,TIMx_CHx通道输出高电平。当CNT达到ARR值的时候,重新归零,然后重新向上计数,依次循环。从0~t2表示一个周期,即改变 ARR的值,就可以改变PWM输出的频率;t1~t2表示高电平占整个周期的时间,因此改变CCRx的值,就可以改变PWM输出的占空比。

image.png

下面开始步骤:

1. 配置 STM32CubeMX

创建新工程

打开 STM32CubeMX 并创建一个新工程。

选择 STM32F103 微控制器。

image.png


image.png

这里配有那个高速的就行,不用两个都配上。

在 RCC 配置中启用 HSE 和 PLL。

配置 GPIO


选择一个引脚用于 PWM 输出,PA7。

image.png

将其模式设置为 PWM Generation CH2。

配置 TIM3

image.png

启用 TIM3,启用中断。

设置 Prescaler 和 Counter Period。

Prescaler 设置为 7200-1,这将使定时器时钟降低到 1kHz。

Counter Period 设置为 1000-1,这将产生 10Hz 的 PWM 频率。

image.png

说明一下:

根据公式fclk=(Fcore/(Prescaler+1)/(Period+1),结合我的配置,得到fclk=72000000/(71+1)/(999+1)=1000HZ,这个频率不会有太明显的闪烁感。

PWM模式1(向上计数):计数器从0计数加到自动重装载值(TIMx_ARR),然后重新从0开始计数,并且产生-个计数器溢出事件。

PWM模式2(向下计数):计数器从自动重装载值(TIMx_ARR)减到0,然后重新从重装载值(TIMx_ARR)开始递减,并且产生一个计数器溢出事件。

Mode 选择PWM模式1

Pulse(占空比值) 先给0

Fast Mode PWM脉冲快速模式 :和我们配置无关,不使能· PWM 极性: 设置为低电平 PS:由于LED是低电平点亮,所以我们把极性设置为low

配置时钟

image.png

最后就是工程设置:

image.png

生成代码

点击“Project -> Generate Code”生成 Keil 或 STM32CubeIDE 工程。

下面看代码:

// 系统时钟配置函数  
void SystemClock_Config(void)  
{  
    // 定义并初始化RCC振荡器配置结构体  
    RCC_OscInitTypeDef RCC_OscInitStruct = {0};  
    // 定义并初始化RCC时钟配置结构体  
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};  
  
    // ------------------- RCC振荡器配置部分 --------------------  
    // 初始化RCC振荡器根据指定的RCC_OscInitTypeDef结构体参数  
      
    // 选择振荡器类型为HSE(高速外部振荡器)  
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;  
    // 打开HSE振荡器  
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;  
    // HSE预分频值为1(即不分频)  
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;  
    // 打开HSI振荡器(虽然在这里可能不会被使用,但通常作为备用时钟源)  
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;  
    // 打开PLL(相位锁定环)  
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;  
    // 设置PLL的源为HSE  
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;  
    // 设置PLL的倍频因子为9  
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;  
  
    // 使用HAL库函数配置振荡器  
    // 如果配置失败,则调用错误处理函数  
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)  
    {  
        Error_Handler();  
    }  
  
    // ------------------- RCC时钟配置部分 --------------------  
    // 初始化CPU、AHB和APB总线的时钟  
  
    // 设置要配置的时钟类型(HCLK: AHB时钟, SYSCLK: 系统时钟, PCLK1/PCLK2: APB1/APB2时钟)  
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK  
                                |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;  
    // 设置系统时钟源为PLL时钟  
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;  
    // AHB总线时钟与系统时钟不分频(即相同频率)  
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;  
    // APB1总线时钟是HCLK的1/2  
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;  
    // APB2总线时钟与HCLK相同  
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;  
  
    // 使用HAL库函数配置时钟  
    // 同时设置FLASH的延迟(根据时钟频率选择)  
    // 如果配置失败,则调用错误处理函数  
    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)  
    {  
        Error_Handler();  
    }  
}
int main(void)  
{  
  /* USER CODE BEGIN 1 */  
  // 定义一个16位无符号整数变量cnt_Pwm,用于PWM的计数值  
  uint16_t cnt_Pwm=0;  
  /* USER CODE END 1 */  
  
  /* MCU Configuration--------------------------------------------------------*/  
  
  /* 重置所有外设,初始化Flash接口和Systick。 */  
  HAL_Init();  
  
  /* USER CODE BEGIN Init */  
  // 这里是用户自定义的初始化代码区域,但在这个示例中它是空的  
  /* USER CODE END Init */  
  
  /* 配置系统时钟 */  
  SystemClock_Config(); // 调用系统时钟配置函数  
  
  /* USER CODE BEGIN SysInit */  
  // 这里是用户自定义的系统初始化代码区域,但在这个示例中它是空的  
  /* USER CODE END SysInit */  
  
  /* 初始化所有已配置的外设 */  
  MX_GPIO_Init(); // 调用GPIO初始化函数  
  MX_TIM3_Init(); // 调用TIM3定时器初始化函数  
  
  /* USER CODE BEGIN 2 */  
  // 启动TIM3的PWM通道2  
  HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);  
  /* USER CODE END 2 */  
  
  /* 无限循环 */  
  /* USER CODE BEGIN WHILE */  
  while (1)  
  {  
    /* USER CODE END WHILE */  
  
    /* USER CODE BEGIN 3 */  
    // 第一个循环:逐渐增加PWM的占空比  
    while (cnt_Pwm < 1000)  
    {  
      cnt_Pwm++; // 增加计数值  
      // 设置TIM3的PWM通道2的比较值(即占空比)  
      __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, cnt_Pwm);      
      HAL_Delay(1); // 等待1毫秒  
    }  
    HAL_Delay(100); // 等待100毫秒  
  
    // 第二个循环:逐渐减小PWM的占空比  
    while (cnt_Pwm)  
    {  
      cnt_Pwm--; // 减少计数值  
      // 设置TIM3的PWM通道2的比较值(即占空比)  
      __HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_2, cnt_Pwm);      
      HAL_Delay(1); // 等待1毫秒  
    }  
    HAL_Delay(100); // 等待100毫秒  
  /* USER CODE END 3 */  
  }  
}

主要的功能:

  1. 初始化MCU(微控制器)和相关的外设(GPIO和TIM3定时器)。

  2. 配置TIM3定时器的PWM通道2,并使其开始工作。

  3. 在一个无限循环中,逐渐增加PWM的占空比(从0到1000),等待一段时间,然后逐渐减小PWM的占空比(从1000到0),再次等待一段时间。这个过程不断重复,产生了一个PWM信号的变化效果。

void MX_TIM3_Init(void)  
{  
  /* USER CODE BEGIN TIM3_Init 0 */  
  // 用户可以在这里添加TIM3初始化之前的自定义代码  
  /* USER CODE END TIM3_Init 0 */  
  
  // 定义TIM3时钟配置结构体变量  
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};  
  // 定义TIM3主输出配置结构体变量  
  TIM_MasterConfigTypeDef sMasterConfig = {0};  
  // 定义TIM3输出通道配置结构体变量  
  TIM_OC_InitTypeDef sConfigOC = {0};  
  
  /* USER CODE BEGIN TIM3_Init 1 */  
  // 用户可以在这里添加TIM3初始化之前的其他自定义代码  
  /* USER CODE END TIM3_Init 1 */  
  
  // 初始化htim3变量,指向TIM3硬件实例  
  htim3.Instance = TIM3;  
  
  // 设置TIM3的基本配置  
  htim3.Init.Prescaler = 71;           // 预分频器值  
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP; // 向上计数模式  
  htim3.Init.Period = 999;             // 自动重载寄存器的周期值  
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1; // 时钟分频因子  
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE; // 使能自动重载预装载  
  
  // 初始化TIM3基本定时器  
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)  
  {  
    // 如果初始化失败,调用错误处理函数  
    Error_Handler();  
  }  
  
  // 配置TIM3的时钟源  
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL; // 使用内部时钟  
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)  
  {  
    // 如果时钟源配置失败,调用错误处理函数  
    Error_Handler();  
  }  
  
  // 初始化TIM3的PWM模式  
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)  
  {  
    // 如果PWM初始化失败,调用错误处理函数  
    Error_Handler();  
  }  
  
  // 配置TIM3的主输出和主从模式  
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET; // 触发输出复位  
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE; // 禁用主从模式  
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)  
  {  
    // 如果主输出和主从模式配置失败,调用错误处理函数  
    Error_Handler();  
  }  
  
  // 配置TIM3的PWM输出通道2  
  sConfigOC.OCMode = TIM_OCMODE_PWM1; // PWM模式1  
  sConfigOC.Pulse = 0;                // 初始脉冲值(这里设置为0,实际PWM值由__HAL_TIM_SetCompare设置)  
  sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW; // 输出极性为低  
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE; // 禁用快速模式  
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_2) != HAL_OK)  
  {  
    // 如果PWM通道配置失败,调用错误处理函数  
    Error_Handler();  
  }  
  
  /* USER CODE BEGIN TIM3_Init 2 */  
  // 用户可以在这里添加TIM3初始化之后的其他自定义代码  
  /* USER CODE END TIM3_Init 2 */  
  
  // 调用HAL库提供的MspPostInit函数,用于初始化与外设相关的GPIO和NVIC(如果需要)  
  HAL_TIM_MspPostInit(&htim3);  
}
MX_TIM3_Init函数用于初始化TIM3定时器,并配置其PWM输出通道2。

在函数内部,首先定义了一些配置结构体变量,并设置了TIM3的基本参数、时钟源、PWM模式、主输出和主从模式以及PWM输出通道的配置。

如果任何一步的初始化或配置失败,都会调用Error_Handler函数来处理错误。此外,还为用户提供了在初始化前后添加自定义代码的区域。

调用了HAL_TIM_MspPostInit函数,这个函数通常在自动生成的代码中定义,用于初始化与外设相关的GPIO和NVIC。

KEIL下载程序到开发板:

image.png

要确保可以找到单片机,才能正常下载程序。


视频效果:










高工
2024-06-23 11:07:07     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]