不含stm32 底层的代码
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
MyStm32Code/DOC/08_PWM.md

220 lines
6.2 KiB

## PWM
介绍了 STM32 的通用定时器 TIM3,用该定时器的中断来控制 DS1 的闪烁
TIM3_REMAP[1:0]重映射控制表, 查对应的引脚
TIM3_CH2 部分重映射可以对应 PB5, PB5 对应红色LED
### 配置
TIM_HandleTypeDef htim6;
三个结构体
TIM_ClockConfigTypeDef sClockSourceConfig = {0}; // 时钟源
TIM_MasterConfigTypeDef sMasterConfig = {0}; // 触发器模式
TIM_OC_InitTypeDef sConfigOC = {0}; //输出比较
sConfigOC.OCMode = TIM_OCMODE_PWM1;
sConfigOC.Pulse = 0;
sConfigOC.OCPolarity = TIM_OCPOLARITY_LOW;
sConfigOC.OCFastMode = TIM_OCFAST_ENABLE;
HAL_TIM_MspPostInit 可以候补配置使用的GPIO
#### 定义引脚 MspPostInit
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
```C
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(timHandle->Instance==TIM3)
{
/* USER CODE BEGIN TIM3_MspPostInit 0 */
/* USER CODE END TIM3_MspPostInit 0 */
__HAL_RCC_GPIOB_CLK_ENABLE();
/**TIM3 GPIO Configuration
PB5 ------> TIM3_CH2
*/
GPIO_InitStruct.Pin = PWM_TIM3_CH2_Pin;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(PWM_TIM3_CH2_GPIO_Port, &GPIO_InitStruct);
// __HAL_AFIO_REMAP_TIM3_PARTIAL(); // 部分重映射
// __HAL_AFIO_REMAP_TIM3_ENABLE(); // 完全映射
/* USER CODE BEGIN TIM3_MspPostInit 1 */
/* USER CODE END TIM3_MspPostInit 1 */
}
}
```
#### 时间计算
https://blog.csdn.net/weixin_44453694/article/details/122351580
设置分频系数为72,重装载值为500, 1us
自动重装载
PWM
mode: PWM1 : CNT << CCR 为有效电平
pulse: 0 占空比 这里设置为200则占空比为200/500(重装载值为)
output compare preload: 输出比较装载使能
Fastmode Enable
CH Polarity: Low 低电平有效
参数说明
Input capture direct mode 输入捕获直接模式
Input capture indirectmode 输入捕获间接模式
Input capture triggered by TRC 输入捕获触发器模式
Output compare no output 输出比较冻结模式000
Output compare CH3 输出比较(001)
PWM Generation No output PWM产生无输出
PWM Generation CH3 PWM输出到CH3
CH3 Combined channels 联合通道
xor activation 定时器输入异或模式
启动通道 PostMSP
HAL_TIM_PWM_Start(timHandle,TIM_CHANNEL_3);//启动通道3
HAL_TIM_PWM_Start(timHandle,TIM_CHANNEL_4);//启动通道4
TIM1 TIM8 可以在cubemx 看到互补引脚
#### CCRx
在向上计数 PWM模式
且当 CNT<CCRx 输出 0 CNT>=CCRx 时输出 1
所以:
当 CNT 值小于 CCRx 的时候, 输出低电平,
当 CNT 值大于等于 CCRx 的时候, 输出高电平,
当 CNT 达到 ARR 值的时候,重新归零,然后重新向上计数。
改变 CCRx 的值,就可以改变 PWM 输出的占空比
改变 ARR 的值,就可以改变 PWM 输出的频率
#### 输出模式
输出模式 : 不可以改变频率,改变 pulse
__HAL_TIM_SET_COMPARE(&htim2,TIM_CHANNEL_2,pwm_num); //设置pwm函数 Pulse 值
比较输出模式 : 可以改变频率, 改变 ARR 自动重装载值
### 捕获 CAP
输入捕获模式可以用来测量脉冲宽度或者测量频率。 捕获电平上升或下降沿中断
中间可能会有溢出, 需要配置溢出中断
HAL_TIM_Base_Start_IT(&htim5); // 开启中断
HAL_TIM_IC_Start_IT(&htim5, TIM_CHANNEL_1); // 开启捕获中断
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim) //溢出回调
捕获回调
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);//点灯
}
***通过分频,设置为1us***
```C
// 参考例程
//可以写在主函数,也可以在time.c
/*
sta当前的捕获状态:
[14]0x4000 =1表示捕获到了上升沿 现在待测量是高电平
[15]0x8000 =1表示捕获到了下降沿 现在待测量是低电平,此时第6位依然是1
[0~13] 用于记录计数器溢出次数
val记录计数器的值
*/
uint16_t tim5_ch1_cap_sta = 0;
uint32_t tim5_ch1_cap_val;
//定时器捕获中断回调函数
//第1次捕获的是上升沿
void HAL_TIM_IC_CaptureCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim5)
{
HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);//点亮或关闭DS1
if((tim5_ch1_cap_sta&0x8000) == 0)
{
if((tim5_ch1_cap_sta&0x4000))//捕获到了下降沿
{
tim5_ch1_cap_sta |= 0x8000;
//获取当前计数器的值
tim5_ch1_cap_val=HAL_TIM_ReadCapturedValue(&htim5,TIM_CHANNEL_1);
//清除之前的沿触发捕获模式
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);
//设置为上升沿触发
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_RISING);
}
else//捕获到了上升沿
{
/*重启定时器5*/
//关闭
__HAL_TIM_DISABLE(&htim5);
//计数器清0
__HAL_TIM_SET_COUNTER(&htim5,0);
//清除之前的沿触发捕获模式
TIM_RESET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1);
//定时器5通道1设置为下降沿捕获
TIM_SET_CAPTUREPOLARITY(&htim5,TIM_CHANNEL_1,TIM_ICPOLARITY_FALLING);
//使能定时器5
__HAL_TIM_ENABLE(&htim5);
tim5_ch1_cap_sta = 0;
tim5_ch1_cap_val = 0;
tim5_ch1_cap_sta |= 0x4000;
}
}
}
}
//计数器溢出中断回调函数(TIM5_CNT 只有16位)
//计数器记录的是自己的执行了多少个周期 如:1Mhz 1us计数器+1
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim == &htim5)
{
if((tim5_ch1_cap_sta&0x8000) == 0)
{
if((tim5_ch1_cap_sta&0x4000))
{
if((tim5_ch1_cap_sta&0x3fff) == 0x3fff)//记录溢出次数过多(高电平太长)
{
tim5_ch1_cap_sta |= 0x8000;//强行表示高电平结束
tim5_ch1_cap_val &= 0xffffffff;
}
else
{
tim5_ch1_cap_sta++;
}
}
}
}
}
/*主函数测试部分代码*/
long long temp;
while (1)
{
if((tim5_ch1_cap_sta&0x8000))//确认当前为低电平
{
u1_printf("Capture ok\r\n");
temp = tim5_ch1_cap_sta&0x3fff;
temp = temp*65535;
temp = temp + tim5_ch1_cap_val;
u1_printf("%.2lf s\r\n",(double)temp/(1000*1000));
HAL_Delay(1000);
break;
}
}
u1_printf("done\r\n");
```