简言之,关于脉冲输出的题目要求如下:
①默认低电平
②按下key4,切换低电平/脉冲信号
③输出脉冲器件LED2点亮,否则熄灭。
具体可以查阅STM32G4系列微控制器参考手册
28-31章均为时钟timer相关资料,我们可以向右方一样查找该类型定时器是否支持PWM,从而判断该定时器是否能调用引脚实现脉冲输出。【实际上只有第31章的定时器不支持PWM输出功能】
对于我们用户来说,各种输出都是来自于引脚,因此PWM的配置本质依旧是引脚配置
我们的可变亮度的台灯本质是利用了PWM输出,通过调节占空比,实现不同占空比下不同平均电压的输出,从而有了灭->暗->亮->晃眼睛。
该部分是第12届蓝桥杯最后一部分的题目内容,因此我们可以基于第六节的环境进行修改。
如何在CubeMX中判断哪些定时器支持PWM?
如图所示,众多的定时器channel中可以选择功能,仅需检查是否有PWM选项
但是本题对引脚做出了限制
因此选择PA7进行配置
实际上PWM是多路输出的,因此在定时器中会有许多通道,而我们仅需要选择其中一个channel即可,且实际上上面四个通道任选其一均可
如果题目没有指定某引脚,我们平时练习可以只固定一个熟练的引脚一直使用(我固定使用PA7的通道2)
①记得在该通道选定PWM generation
②配置时钟源(internal clock内部时钟)
操作实现了2K的输出频率
具体计算如下:
时钟频率: 80 M H z = 8 ∗ 1 0 7 H z 80MHz=8*10^7Hz 80MHz=8∗107Hz
预分频器分频: 8 ∗ 1 0 7 H z / 80 = 1 0 6 H z 8*10^7Hz/80=10^6Hz 8∗107Hz/80=106Hz
利用计数周期分频: 1 0 6 H z / 500 = 2 ∗ 1 0 3 H z = 2 K H z 10^6Hz/500=2*10^3Hz=2KHz 106Hz/500=2∗103Hz=2KHz
Prescaler:预分频器
Counter Period:计数周期,指计数多少次发生一次中断
操作实现占空比20%
上述Counter Period为一个周期计数500,那么占空比20%
说明要计数 500 ∗ 20 % = 100 500*20\%=100 500∗20%=100即100脉冲
在这里还有一个关于Mode的知识点,PWM的两种模式代表不同情况
在进行PWM信号输出时,有两种PWM模式:PWM1模式和PWM2模式。
这两种PWM模式和输出有效电平的极性共同决定了PWM信号的波形。
PWM1模式
递增计数时,当TIMx_CNT(计数值)< TIMx_CCR(捕获/比较值)时,输出为有效电平,否则为无效电平。递减计数模式则刚好相反。
PWM2模式
递增计数时,当TIMx_CNT(计数值)< TIMx_CCR(捕获/比较值)时,输出为无效电平,否则为有效电平。递减计数模式则刚好相反。
下面我们详细分析一下两种PWM模式的区别:
假设定时器设置为递增计数模式,输出有效电平的极性为高电平。
PWM1模式下的CCR用于控制高电平持续的时间;
PWM2模式下的CCR用于控制低电平持续的时间,两种模式下的PWM信号互为互补输出。
环境配置完毕
(1)头文件补充
(2)全局变量有没有遗漏
(3)函数声明
(4)主函数
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_USART1_UART_Init();
MX_TIM3_Init();
/* USER CODE BEGIN 2 */
LCD_Init();
control_led(LEDALL,OFF);
ParkingInit();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
HAL_UART_Receive_IT(&huart1, (uint8_t *)usart_rx,RxLen);
LCD_Clear(Black);
while (1)
{
/* USER CODE END WHILE */
lcd_proc();
key_proc();
led_proc();
busi_proc();
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
void key_proc(void)
{
char value = key_scan();
switch(value)
{
case 1:
/*切换LCD显示屏界面的操作*/
lcd_flag = (lcd_flag == 1 ? 0 : 1);
lcd_update_flag=1;
break;
case 2:
/*CNBR、VNBR费率增加0.5�??*/
cnbr += 0.5f;
vnbr += 0.5f;
lcd_update_flag=1;
break;
case 3:
/*CNBR、VNBR费率减少0.5�??*/
cnbr -= 0.5f;
vnbr -= 0.5f;
lcd_update_flag=1;
break;
case 4:
/*两种频率输出状态*/
pwm_flag = (lcd_flag == 1 ? 0 : 1);
break;
}
}
void pwm_proc(void)
{
if(pwm_flag)//低电平
{
HAL_TIM_PWM_Stop(&htim3,TIM_CHANNEL_2);
HAL_Delay(5);
}
else//高电平
{
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
HAL_Delay(5);
}
}
记得在整个文件开头进行函数声明:
代码中有两个函数,分别代表停止/开始PWM输出
开始输出的时候就是20%占空比2KHz,停止输出后便为低电平
两个函数位于如下图所示的位置
拓展:该函数的另一种实现方式
void pwm_proc(void)
{
if(pwm_flag)//低电平
{
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,0);//占空比0
HAL_Delay(5);
}
else//高电平
{
HAL_TIM_PWM_Start(&htim3,TIM_CHANNEL_2);
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100);//占空比100/500=20%
HAL_Delay(5);
}
}
__HAL_TIM_SetCompare(&htim3,TIM_CHANNEL_2,100) 是专门用来设置占空比的函数
最后一个参数的含义为我们的计数周期中有多少计数是脉冲
我们曾在CubeMX中设置计数周期为500,则500*0.2=100
对于这两种方式,我们都需要记住!!第二种方法尤为重要,通过这个甚至可以设计出我们生活中的可调亮度台灯
void led_proc(void)
{
if(idle>0)
{
control_led(LED1,ON);//LED1�??
}
else
{
control_led(LED1,OFF);
}
if(pwm_flag==1)
control_led(LED2,ON);
else
control_led(LED2,OFF);
}
实际上仅需在while循环中新增一行pwm_proc()即可
保存,编译,下载,观察不同按键下的板子状态。
至此第12届蓝桥杯省赛题目所有任务均完成,后续会更新一期完整的第12届蓝桥杯题目整体思路和流程