频率透过 TIMx->ARR 来调整。
DUTY透过 设定 TIMx->CCRx来产生。
TIMx->PSC 产生TIMX计算时基。
STM32系统版 TIM2 CH1 ~ CH4对应 PA0 ~ PA3, 测试很方便。
可以在相同频率下(共享PSC, ARR), 设定四个(CCRx)不同 DUTY的输出。
<图片撷自 STM RM0008 Reference Manual. >
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
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;
}
PS:
<笔记>天才脑袋比不上烂笔头, 写给自己看, 自用资料。
档案取自互联网!如有侵权或不适用情形, 请联系移除!
#STM32F103
#PWM
#Servo PWM