04、按键+PWM
功能:使用B1和B2按键调整PA6,PA7两个GPIO口输出PWM波的占空比。PA6输出频率固定为100Hz,PA7输出频率为200Hz。短按+10,长按+20,范围在10-90之间。
将上一个博客例程复制并命名为Ag_03。打开.ioc文件,配置相应GPIO。分别配置为TIM16_CH1和TIM17_CH1。
在Timers菜单栏配置定时器。关于频率配置的计算方式参考蓝桥杯电子类嵌入式(STM32G431)备赛学习记录(三)。同样,将TIM17也配置完成后,点击生成代码。
这里注意,一定要设置这个占空比,可以随便设置为10,后面的程序里可以改。
打开工程文件。先在main.c中打开PWM波信号,库函数是:
HAL_StatusTypeDef HAL_TIM_PWM_Start(TIM_HandleTypeDef* htim,uint32_t Channel)
这里,我们可以优化一下代码。先注释掉之前主函数中while循环里的代码。在main.c中,将按键过程定义为一个函数,显示界面定义为一个函数,则主函数通过调用这两个函数实现功能,代码更简洁。而具体的实现已经在之前的例程中写好了,这里只需摘取需要的代码。
按键过程:
void key_pro(void) //按键函数
{
if(key_state[0].short_flag==1) //判断如果为短按B1
{
pwm_1+=10; //占空比增加10%,这里因为频率设置的是100Hz,所以以10为计就是增减百分之十
if(pwm_1>=90) //如果超过90,则从新重10开始增长
{
pwm_1=10;
}
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, pwm_1); //通过这个函数来将PWM的占空比按照变量值来改变
key_state[0].short_flag=0;
}
if(key_state[0].long_flag==1) //判断如果为长按B1
{
pwm_1+=20; //占空比增加20%
if(pwm_1>=90) //如果超过90,则从新重10开始增长
{
pwm_1=10;
}
__HAL_TIM_SetCompare(&htim16, TIM_CHANNEL_1, pwm_1); //通过这个函数来将PWM的占空比按照变量值来改变
key_state[0].long_flag=0;
}
if(key_state[1].short_flag==1) //判断如果为短按B2
{
pwm_2+=10; //占空比增加10%
if(pwm_2>=90) //如果超过90,则从新重10开始增长
{
pwm_2=10;
}
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, pwm_2); //通过这个函数来将PWM的占空比按照变量值来改变
key_state[1].short_flag=0;
}
if(key_state[1].long_flag==1) //判断如果为长按B2
{
pwm_2+=20; //占空比增加20%
if(pwm_2>=90) //如果超过90,则从新重10开始增长
{
pwm_2=10;
}
__HAL_TIM_SetCompare(&htim17, TIM_CHANNEL_1, pwm_2); //通过这个函数来将PWM的占空比按照变量值来改变
key_state[1].long_flag=0;
}
}
显示过程:
void dis_pro(void)
{
char dis[20]; //定义一个内存为20的数组
char dis_1[20];
char dis_2[20];
sprintf(dis,"PWM:"); //将字符串传到指定数组中
LCD_DisplayStringLine(Line1,(unsigned char *)dis); //在第一行显示
sprintf(dis_1,"PWM:",pwm_1);
LCD_DisplayStringLine(Line5,(unsigned char *)dis_1);
sprintf(dis_2,"PWM:",pwm_2);
LCD_DisplayStringLine(Line6,(unsigned char *)dis_2);
}
要注意的是,这两个函数要先声明哦。在按键过程里有一个库函数用来按值修改占空比,这个函数可以记一记,在HAL库里没有搜到,隶属于另一个头文件。
05、输入捕获
上一个例程我们写了如何生成PWM波以及如何通过按键控制占空比。接下来可以通过输入捕获程序来验证我们所配置的两个GPIO口是不是输出的100Hz和200Hz的固定频率。
同样,打开cube,根据芯片手册配置PA15和PB4为TIM8_CH1和TIM3_CH1。并将Channel1设置为Input Capture direct mode,分频系数设置为80,然后开启中断即可。
接下来写捕获中断回调函数。我们的核心思想是,通过库函数读取捕获的时间,用80MHz来除以我们配置时设置的80的分频系数,再除以这里捕获的时间即可得到固定频率。
首先,我们需要在interrupt.c中定义两个变量分别记录时间和频率。
uint ccrl_val_1=0; //PA15捕获时间
uint ccrl_val_2=0; //PB4捕获时间
uint frq_1=0; //PA15口的频率
uint frq_2=0; //PB4口的频率
接下来编写捕获中断回调函数
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef * htim) //捕获中断回调函数
{
if(htim->Instance==TIM2) //判断是否为TIM2的中断
{
ccrl_val_1=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1); //读取定时器的计时值
__HAL_TIM_SetCounter(htim,0); //将值置零
frq_1=(80000000/80)/ccrl_val_1; //计算频率
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1); //重新开启定时器
}
if(htim->Instance==TIM3)
{
ccrl_val_2=HAL_TIM_ReadCapturedValue(htim,TIM_CHANNEL_1);
__HAL_TIM_SetCounter(htim,0);
frq_2=(80000000/80)/ccrl_val_2;
HAL_TIM_IC_Start(htim,TIM_CHANNEL_1);
}
}
记得写好回调函数后,在.h文件中将函数声明。然后在main.c中引用这两个变量。注意,这里又用到了TIM2定时器,但是在之前的按键中,我们也是用的TIM2定时器来周期扫描按键。所以,这里有了冲突,要恢复按键功能的话可以重新在cube里设置一个定时器用于按键扫描,然后在定时器溢出回调函数中,将第一行逻辑判断改为新设置的TIM,在主函数中将开定时器中断的库函数参数改为htim4。记得写好回调函数后,在.h文件中将函数声明。然后在main.c中引用这两个变量。
extern uint frq_1,frq_2;
接下来在main.c中打开定时器
HAL_TIM_IC_Start_IT(&htim2,TIM_CHANNEL_1); //打开定时器中断
HAL_TIM_IC_Start_IT(&htim3,TIM_CHANNEL_1);
在显示函数中将显示的数值改为频率
sprintf(dis_1,"PWM:%d",frq_1);
LCD_DisplayStringLine(Line5,(unsigned char *)dis_1);
sprintf(dis_2,"PWM:%d",frq_2);
LCD_DisplayStringLine(Line6,(unsigned char *)dis_2);
编译无误,下载完成!
要验证PA6和PA7频率是否为100Hz和200Hz,将J9和J10两个跳帽摘下,用导线连接这两个引脚即可。