目录
[(2)STM32CubeMX 软件配置](#(2)STM32CubeMX 软件配置)
一、PWM
(1)资源介绍
PWM(Pulse Width Modulation)脉冲宽度调制,是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术,广泛应用在从测量、通信到功率控制与变换的许多领域中。
图1 PWM周期与脉宽
其中,脉宽时间即高电平时间;
单片机的 IO 口输出的是数字信号,其仅能输出高电平和低电平这两种状态,假设高电平为 5V ,低电平为 0V 。当我们需要输出不同的模拟电压时,就会用到 PWM 技术。其原理是通过改变 IO口输出方波的占空比,以此来获取由数字信号模拟而成的模拟电压信号。
图2 有效电压
- PWM是在合适的信号频率下,通过一个周期里改变占空比的方式来改变输出的有效电压;
- PWM频率越高,响应越快;
以上资料来源于:
PWM原理 PWM频率与占空比详解-CSDN博客https://blog.csdn.net/as480133937/article/details/103439546 在蓝桥杯物联网竞赛实训平台中,提供了两个电机接口 P1 和 P2 ,由达林顿管 ULN2803 驱动。因为达林顿管是反向驱动,所以在调节占空比时,需要注意取值。
图3 板极资源
(2)STM32CubeMX 软件配置
🔅"工程建立、时钟树配置、Debug 串行线配置、代码生成配置" 在下文中有讲解,这里不再赘述❗️
1️⃣配置引脚 PA0 为 TIM2_CH1 ,引脚 PA1 为 TIM2_CH2 ;(此时引脚呈黄色状态)
点击**"Timers"** → 点击**"TIM2"** →将**"Clock Source"** 配置为**"Internal Clock"** → 将**"Channel1"** 和**"Channel2"** 分别配置为 "PWM Generation CH1" 和 "PWM Generation CH2" ;(此时引脚呈绿色状态);
修改参数:
- Counter Settings - Prescaler:31(32 分频,使定时器时钟为1MHz);
- Counter Settings - Counter Period:9999(计数值10000 ,即PWM 频率为100kHz);
2️⃣配置OLED;
3️⃣生成代码即可;
(3)代码编写
🟢️main 函数
cpp
/* USER CODE BEGIN PV */
uint8_t cnt_key;
uint8_t cnt_oled;
uint8_t puc_oled[17]; // oled显示缓存区
uint8_t pwm_duty; // pwm占空比
/* USER CODE END PV */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_I2C3_Init();
MX_TIM2_Init();
/* USER CODE BEGIN 2 */
OLED_Init();
/* PWM启动 */
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_1);
HAL_TIM_PWM_Start(&htim2, TIM_CHANNEL_2);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
Task_Key();
Task_OLED();
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void Task_Key(void)
{
uint8_t key_temp, key_down;
static uint8_t key_old = 0;
if(cnt_key < 10) return;
cnt_key = 0;
key_temp = Key_Read();
key_down = key_temp & (key_temp ^ key_old);
key_old = key_temp;
if(key_down)
{
/* 按键按下,占空比+5 */
pwm_duty += 5;
if(pwm_duty > 100)
pwm_duty = 0;
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, pwm_duty * 100);
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, pwm_duty * 100);
}
}
void Task_OLED(void)
{
if(cnt_oled < 200) return;
cnt_oled = 0;
sprintf((char*)puc_oled, "PWM_DUTY:%d ", pwm_duty);
OLED_ShowString(0, puc_oled);
}
(4)实验现象
按键按下后,测得 PA0 和 PA1引脚输出有变动;
二、PWM接口函数封装
🟡️修改自动重载值和比较值函数
cpp
/* 设置TIM2自动重装值 */
void TIM2_SetReload(uint16_t usData)
{
__HAL_TIM_SET_AUTORELOAD(&htim2, usData);
}
/* 设置TIM2比较值1 */
void TIM2_SetCompare1(uint16_t usData)
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_1, usData);
}
/* 设置TIM2比较值2 */
void TIM2_SetCompare2(uint16_t usData)
{
__HAL_TIM_SET_COMPARE(&htim2, TIM_CHANNEL_2, usData);
}
三、踩坑日记
(1)PWM输出测量不准
🔅这个可能与达林顿管有一定关系,在单片机设计与开发赛道中,同样会有这个问题;
(2)PWM模式
🔅PWM有两个模式:
- 模式1:**TIMX_CNT<TIMX_CCRX,**输出有效电平;
- 模式2:**TIMX_CNT>TIMX_CCRX,**输出有效电平;
可以通过调节PWM 模式和有效电平极性输出不同的PWM波,适应不同电路;
(3)实训平台PWM测量困难
🔅一般检验PWM 波,需要使用示波器,一根接地线,一根接PWM波线;
在实训平台上,PWM 产生引脚处,旁边是5V电压,而地线需要从拓展接口引出,操作较为麻烦;后续新的实训平台解决了这一问题;