一、题目
利用PWM+滤波输出指定电平(使用PA1引脚),按键步进0.1V。
二、CubeMX 配置
设置 PA0 为按键输入,默认下拉,一端接 3.3V,这样检测到高电平的时候,就是按键按下的时候。
占空比等于 高电平持续时间 除以
d
u
t
y
=
C
C
R
A
R
R
+
1
duty = \frac{CCR}{ARR + 1}
duty=ARR+1CCR
三、代码编写
定义
/* USER CODE BEGIN PD */
#define VMAX 3.3f // 例如板上供电是 3.3V
#define VOLTAGE_STEP 0.1f // 按键每次步进 0.1V
#define VOLTAGE_MAX 3.3f // 输出电压上限,和 VMAX 相同也可以
/* USER CODE END PD */
/* USER CODE BEGIN PV */
static float currentVoltage = 0.0f; // 记录当前的目标电压
static uint32_t pwmPeriod = 100 - 1; // 自动重装载定时器的计数周期 ARR
/* USER CODE END PV */
主循环
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET){
HAL_Delay(20); //延时消抖
if(HAL_GPIO_ReadPin(KEY_GPIO_Port,KEY_Pin) == GPIO_PIN_SET){//再次判断按键是否按下
currentVoltage += VOLTAGE_STEP; // 电压步进
if (currentVoltage > VOLTAGE_MAX){ // 如果超过 3.2V,回到 0
currentVoltage = 0.0;
}
float duty = currentVoltage / VMAX; // 计算占空比
if (duty > 1.0f) duty = 1.0f;
if (duty < 0.0f) duty = 0.0f;
uint32_t ccr = (uint32_t)(duty * pwmPeriod);
__HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, ccr);
}
while (HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) == GPIO_PIN_SET);//按键是否松开
}
/* USER CODE END WHILE */
四、其他注意点
- 例如,本文中的
duty
变量在 debug 的时候显示not in scope
,添加 __IO 修饰不起作用,修改优化等级: - CubeMX 的文件名不能有加号
- 如果 CubeMX 打开是空白,可能是这部分需要上拉
- 在 PWM 输出接 10kOhm 和 22nF 的低通滤波器。
五、实验现象:
原始占空比 50%
更改占空比
滤波之后没有毛刺