PWM使用 Compare Output mode.
HAL/ StdLib 有点云来雾去的, 看了一下文件, 把TIM Registers捋一捋, 笔记笔记。
免得急用, 有虫查不出来, 浪费时间.
思路
频率透过 TIMx->ARR 来调整。
DUTY透过 设定 TIMx->CCRx来产生。
TIMx->PSC 产生TIMX计算时基。
STM32系统版 TIM2 CH1 ~ CH4对应 PA0 ~ PA3, 测试很方便。
可以在相同频率下(共享PSC, ARR), 设定四个(CCRx)不同 DUTY的输出。
<图片撷自 STM RM0008 Reference Manual. >
Example 1:
Timer Clock = 72MHz.
PWM 频率20KHz, 20KHz period = 50us.
简单运算, 将TIMX计算时基设定成 0.5us
TIMx->PSC = 72/2 – 1 = 35 ;
所以,
TIMx-> ARR = 50x2 -1 = 99;
Duty 0 ~ 100
TIMx->CCRx = Duty; // 0 ~ 100
Example 2: ( Servo Control )
Timer Clock = 72MHz.
PWM 频率50Hz , 50Hz period = 20ms.
将TIMX计算时基设定成 1us
TIMx->PSC = 72 – 1 = 71 ;
TIMx->ARR = 20000 -1;
Duty Time ( 500us ~ 2500us ) // 0 ~ 180 degree
TIMx->CCRx = Duty Time-1 ; // 499 ~ 2499 .
Example Code: TIM2 Init
void vPWMonGPIO_A0(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_10MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
}
/*******************************************************************************
* Function Name : void vServoPWMInit(void)
* Description : PWM @TIM2 Init
* Return : n/a
* By Jason Lu. 2024/01/22
********************************************************************************/
#define PERIOD 20000
void vServoPWMInit(void)
{
RCC_APB1PeriphClockCmd( RCC_APB1Periph_TIM2, ENABLE);
TIM2->CR1 = 0x0004; // Up mode, ARR PreLoad enable
TIM2->CCMR1 = 0x0064; // Individual Output mode, CCR1 PreLoad enable
TIM2->PSC = 72-1; // 1 us base @SYSTEMCLK=72MHz
TIM2->ARR = PERIOD-1; // Set PWM period, FREQ
TIM2->CCR1 = 1500-1; // Duty time 1.5ms = 90 degree, center
TIM2->CCER = 0x0003; // OC1/CC1 Enable, CC1P=1 Acitve High.
TIM2->EGR |= 0x0001; // UG=1 -> CNT=0, Preloaded
TIM2->SR = 0; // Clear pending flags
TIM2->CR1 |= TIM_CR1_CEN; // Enable TIM2 PWM
}
Duty Control
/*******************************************************************************
* Function Name : void uSetPWMDuty( uint16_t uDuty)
* Description : Set PWM CCR1 as duty time
* Praameters : uDuty duty cycle = 0 ~ 100
* Return : n/a
* By Jason Lu. 2024/01/22
********************************************************************************/
void uSetPWMDuty( uint16_t uDuty) // Duty 0 ~ 100
{
if( 0 == uDuty) { TIM2->CCR1 = PERIOD; return;} // Always Low
if( 100 <= uDuty) { TIM2->CCR1 = 0; return;} // Always High
uint16_t CCR1Value = PERIOD - ((uint32_t)PERIOD * uDuty/100);
TIM2->CCR1 = --CCR1Value;
}
划重点:
- TIM 设定成 Center Mode 时 (CR1= 0x006x), 因PWM信号连续, 量测频率=1/2 FREQ。
- PWM输出为 TIMx AFIO, 要设定 GPIO 为 GPIO_AF_PP or GPIO_AF_OD, 才会输出。
- PSC值设定可以简化计算和理解, 但是会影响分辨率, 要依实际状况取舍。
- ARR/ CCR1 pre-load 可以避免因值更新时造成的频率飘移过界and DUTY跳动。
- 伺服舵机可以用1 x TIM 对 4 channels, 减少资源耗用。
- 500Hz, 点高亮LED, DUTY 1% 就会亮, DUTY 30%之后就达到亮度80%以上,用在电池上,妥妥的。
<笔记>
天才脑袋比不上烂笔头, 写给自己看, 自用资料。
档案取自互联网! 如有侵权或不适用情形, 请联系移除!
请勿转载! 不建议 Ctrl-C + Ctrl-V 请自行考虑!
#STM32F103
#PWM
#Servo PWM