logo资料库

基于STM32的SPWM源代码.doc

第1页 / 共4页
第2页 / 共4页
第3页 / 共4页
第4页 / 共4页
资料共4页,全文预览结束
1、TIMER 输出 PWM 基本概念 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制,是利用微处理器的 数字输出来对模拟电路进行控制的一种非常有效的技术。简单一点,就是对脉冲宽度的控制。一般用来控 制步进电机的速度等等。STM32 的定时器除了 TIM6 和 TIM7 之外,其他的定时器都可以用来产生 PWM 输出,其中高级定时器 TIM1 和 TIM8 可以同时产生 7 路的 PWM 输出,而通用定时器也能同时产生 4 路 的 PWM 输出。 1.1 PWM 输出模式 STM32 的 PWM 输出有两种模式,模式 1 和模式 2,由 TIMx_CCMRx 寄存器中的 OCxM 位确定的(“110” 为模式 1,“111”为模式 2)。模式 1 和模式 2 的区别如下:110:PWM 模式 1-在向上计数时,一旦 TIMx_CNTTIMx_CCR1 时通道 1 为无效电平(OC1REF=0),否则为有效电平(OC1REF=1)。111:PWM 模 式 2-在向上计数时,一旦 TIMx_CNTTIMx_CCR1 时通道 1 为有效电平,否则为无效电平。由此看来,模式 1 和模式 2 正 好互补,互为相反,所以在运用起来差别也并不太大。而从计数模式上来看,PWM 也和 TIMx 在作定时 器时一样,也有向上计数模式、向下计数模式和中心对齐模式,关于 3 种模式的具体资料,可以查看《STM32 参考手册》的“14.3.9 PWM 模式”一节,在此就不详细赘述了。 1.2 PWM 输出管脚 PWM 的输出管脚是确定好的,具体的引脚功能可以查看《STM32 参考手册》的“8.3.7 定时器复用 功能重映射”一节。在此需要强调的是,不同的 TIMx 有分配不同的引脚,但是考虑到管脚复用功能,STM32 提出了一个重映像的概念,就是说通过设置某一些相关的寄存器,来使得在其他非原始指定的管脚上也能 输出 PWM。但是这些重映像的管脚也是由参考手册给出的。比如说 TIM3 的第 2 个通道,在没有重映像 的时候,指定的管脚是 PA.7,如果设置部分重映像之后,TIM3_CH2 的输出就被映射到 PB.5 上了,如果 设置了完全重映像的话,TIM3_CH2 的输出就被映射到 PC.7 上了。 1.3 PWM 输出信号 PWM 输出的是一个方波信号,信号的频率是由 TIMx 的时钟频率和 TIMx_ARR 预分频器所决定的, 具体设置方法在前面一个学习笔记中有详细的交代。而输出信号的占空比则是由 TIMx_CRRx 寄存器确定 的。其公式为“占空比=(TIMx_CRRx/TIMx_ARR)*100%”,因此,可以通过向 CRR 中填入适当的数来输 出自己所需的频率和占空比的方波信号。 2、TIMER 输出 PWM 源代码 #include "stm32f10x.h" /* Private typedef -----------------------------------------------------------*/ GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; TIM_BDTRInitTypeDef TIM_BDTRInitStructure; NVIC_InitTypeDef NVIC_InitStructure; /* Private define ------------------------------------------------------------*/ /* Private macro -------------------------------------------------------------*/ /* Private variables ---------------------------------------------------------*/ u16 TimerPeriod = 7200; u16 DutyFactor = 50;
/* Private function prototypes -----------------------------------------------*/ /* Private functions ---------------------------------------------------------*/ void RCC_Configure(); void GPIO_Configure(); void TIM_Configure(); void PWM_Configure(); void NVIC_Configure(); /** * @brief Main program. * @param None * @retval None */ void RCC_Configure() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4 | RCC_APB1Periph_TIM3,ENABLE); } void GPIO_Configure() { /* GPIOA 配置:通道 PA.6 和 PA.7 为 输出引脚*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); } void TIM_Configure() { /* Time Base configuration 这里配置的就是 PWM 的周期,pwm 还真是比 AVR 的强劲*/ TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //计数方 式 TIM_TimeBaseStructure.TIM_Period = TimerPeriod - 1; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //这边是普通定时器的初始化和中断申请 TIM_DeInit(TIM4); TIM_TimeBaseStructure.TIM_Period=1; TIM_TimeBaseStructure.TIM_Prescaler= 3599; TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1; //采样分频 TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;//计数方式 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //自动重装载寄存器的值 //时钟预分频数
TIM_ClearFlag(TIM4, TIM_FLAG_Update); //清除溢出中断标志 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 计数溢出时触发中断 } void PWM_Configure() { /* 通道 1,2 和 3 配置在 PWM 模式 */ TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; TIM_OCInitStructure.TIM_Pulse = DutyFactor * 7200 / 100;//设置占空比 TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//这里的 4 行代码就是设置 PWM 的空闲电平、波形方式的!一开始自己一不小心搞成了都高的死区,这里是都低电平的死区~ TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OC1Init(TIM3, &TIM_OCInitStructure); TIM_OC2Init(TIM3, &TIM_OCInitStructure); PWM //初始化两组互补的 /* 自动输出使能,中断,死区相关的设置*/ TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1; TIM_BDTRInitStructure.TIM_DeadTime = 12;//死区时间为 12/SYSTEMCLK (ns) TIM_BDTRInitStructure.TIM_Break = TIM_Break_Disable;//关闭外部 break 功能,当然在产品中最 好加入这个保护,蛮好用的。 TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High; TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; TIM_BDTRConfig(TIM3, &TIM_BDTRInitStructure); TIM_CtrlPWMOutputs(TIM3, ENABLE); /* 主输出启用 */ } void NVIC_Configure() { NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //通道 TIM3 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;//占优先级 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //副优先级 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); } int main(void) { RCC_Configure(); GPIO_Configure(); TIM_Configure(); PWM_Configure();
NVIC_Configure(); TIM_Cmd(TIM3, ENABLE); TIM_Cmd(TIM4, ENABLE); while (1); } /* TIM3 的计数器使能 */ /* TIM4 的计数器使能 */ 放在 system32_it.c 里执行 void TIM4_IRQHandler(void) { static vu16 sign = 0; static vu16 Counter_sine=0; static vu16 Duty_Cycle_sinewavetable[128]={0x0,0x83,0x105,0x187,0x209,0x28A,0x30A,0x38A,0x409,0x486,0x502,0x57 D,0x5F7,0x66F,0x6E5,0x75A,0x7CC,0x83D,0x8AB,0x917,0x981,0x9E8,0xA4D,0xAAF,0xB0E,0xB6B,0xBC4, 0xC1B,0xC6E,0xCBE,0xD0B,0xD54,0xD9A,0xDDD,0xE1C,0xE57,0xE8F,0xEC3,0xEF3,0xF1F,0xF48,0xF6C,0 xF8D,0xFA9,0xFC2,0xFD6,0xFE6,0xFF3,0xFFB,0xFFF,0xFFF,0xFFB,0xFF3,0xFE6,0xFD6,0xFC2,0xFA9,0xF8 D,0xF6C,0xF48,0xF1F,0xEF3,0xEC3,0xE8F,0xE57,0xE1C,0xDDD,0xD9A,0xD54,0xD0B,0xCBE,0xC6E,0xC1 B,0xBC4,0xB6B,0xB0E,0xAAF,0xA4D,0x9E8,0x981,0x917,0x8AB,0x83D,0x7CC,0x75A,0x6E5,0x66F,0x5F7, 0x57D,0x502,0x486,0x409,0x38A,0x30A,0x28A,0x209,0x187,0x105,0x83,0x0}; if ( TIM_GetITStatus(TIM4 , TIM_IT_Update) == SET) { if(sign == 0) { TIM_SetCompare1(TIM3,Duty_Cycle_sinewavetable[Counter_sine]); TIM_SetCompare2(TIM3,0); Counter_sine++; if(Counter_sine==100) { //半周期采样 100 个点 Counter_sine=0; sign = 1; } }else{ TIM_SetCompare1(TIM3,0); TIM_SetCompare2(TIM3,Duty_Cycle_sinewavetable[Counter_sine]); Counter_sine++; if(Counter_sine==100) { Counter_sine=0; sign = 0; } } } TIM_ClearITPendingBit(TIM4 , TIM_FLAG_Update); }
分享到:
收藏