单片机交流
直播中

邓长生

10年用户 883经验值
擅长:可编程逻辑
私信 关注
[问答]

如何使用stm32F051R8T6单片机的引脚来输出pwm波形?

pwm所需的相关配置有哪些?配置代码是什么?
如何使用STM32F051R8T6单片机的带有定时器输出功能的引脚来输出pwm波形?

回帖(1)

魏天霞

2021-7-16 14:50:21
概述:stm32的每个引脚都有其自带的特殊功能,有定时器输出功能的引脚可以输出pwm。如果没有的也可以io口模拟输出,如果非要较真的话,理论上可以算是每个引脚都能输出PWM,但一般我们都使用带定时器输出功能的io。此文章来详述使用stm32F051R8T6型号单片机,带有定时器输出功能的引脚来输出pwm波形,同理其他型号的单片机也可实现。并同时来控制直流电机转速,本文以adda公司生产的AD0212DB-G50直流风扇为例讲述。
1.硬件条件
保证单片机输出IO可以支持定时器功能。我板子上连接风扇的引脚为PC9,根据单片机手册PC9引脚带有定时器功能

同理如下图的几个引脚都可以

再次就不一一列举了,在是用不同型号的单片机时,参考单片机手册。
2.stm32固件库

上图分别是stm32定时器相关的库函数,和相关调用的定时器驱动子函数,用户自己定义。
软硬件条件都准备好了,接下来就是pwm所需的相关配置。
1.首先是输出管脚的IO口设置,PWM输出,自然会采用到IO口作为输出端口,在STM32F051系列中,IO端口可以复用为TIM定时器输出通道。
采用PC9的复用功能AF1作为TIM3定时器的第4通道输出。
2.设置定时器的参数,配置出频率为17.57 KHz的PWM波
考虑time定时器的时钟频率。如果我们设置分频数为0,也就是说time定时器等于系统时钟,system_stm32f0xx.c中已经把系统频率设置在48MHZ,在startup_stm32f0xx.s中,首先运行了systemInit函数,因此可以确定time定时器运行在48MHZ。
定时器产生的PWM的频率可以按照下面的公式进行计算:
预定标的值TIM1_Period = (time定时器频率 / pwm的频率) - 1
预定标的值实际上就是定时器运行多少次算一个PWM周期,这个在设置pwm频率中重要的参数。
配置完整代码如下:
/*============================================================================== 函数名 : Fan_PWMConfigInit 功能 : 风扇控制引脚输出pwm控制风扇转速 输入参数说明: 无 返回值说明 : 无 ------------------------------------------------------------------------------*/ void Fan_PWMConfigInit(void) { GPIO_InitTypeDef GPIO_InitStructure; TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; TIM_OCInitTypeDef TIM_OCInitStructure; s32 TimerPeriod, Channel1Pulse; /* 使能GPIO时钟 */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE); /* 配置GPIO管脚参数设置*/ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOC, &GPIO_InitStructure); /* GPIO管脚复用设置*/ GPIO_PinAFConfig(GPIOC, GPIO_PinSource9, GPIO_AF_1); /*计算预定标 的值,也就是多少个时钟计数为一个周期*/ TimerPeriod = (SystemCoreClock / 17570 ) - 1; /*计算CCR1 跳转值 在占空比为50%时*/ Channel1Pulse = (u16)(((u32)5 * (TimerPeriod - 1)) / 10); /* TIM3 时钟使能 */ RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); /* Time 定时基础设置*/ TIM_TimeBaseStructure.TIM_Prescaler = 0; TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; /* Time 定时设置为上升沿计算模式*/ TIM_TimeBaseStructure.TIM_Period = TimerPeriod; TIM_TimeBaseStructure.TIM_ClockDivision = 0; TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); /* 频道1的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_OCPolarity = TIM_OCPolarity_Low; TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High; TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Set; TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Reset; TIM_OCInitStructure.TIM_Pulse = Channel1Pulse; TIM_OC4Init(TIM3, &TIM_OCInitStructure); /* TIM3 计算器使能*/ TIM_Cmd(TIM3, ENABLE); /* TIM3 主输出使能 */ TIM_CtrlPWMOutputs(TIM3, ENABLE); } 在需要改变风扇转速时,只需要改变占空比即可。
/* 风扇控制 */ static s32 CmdFanCtrl (TCmdTbl *cmdtp, s32 argc, s8 *argv[]) { u8 byCmd; s32 Channel1Pulse; if (argc 《 2) return -1; byCmd = strtoul(argv[1], NULL, 0); switch(byCmd){ case 1: Channel1Pulse = (u16)(((u32)875 * 2730) / 1000); break; case 2: Channel1Pulse = (u16)(((u32)75 * 2730) / 100); break; case 3: Channel1Pulse = (u16)(((u32)625 * 2730) / 1000); break; case 4: Channel1Pulse = (u16)(((u32)5 * 2730) / 10); break; case 5: Channel1Pulse = (u16)(((u32)375 * 2730) / 1000); break; case 6: Channel1Pulse = (u16)(((u32)25 * 2730) / 100); break; case 7: Channel1Pulse = (u16)(((u32)125 * 2730) / 1000); break; case 8: Channel1Pulse = (u16)(((u32)1 * 2730) / 100); break; } TIM_SetCompare4(TIM3, Channel1Pulse); return 0; } TIM_SetCompare4(TIM3, Channel1Pulse);该函数是改变对应TIM定时器对应通道占空比的函数,其中的2370是根据系统时间计算出来。使用不同的定时器和通道,可在stm32f0xx_tim.c中查找不同的库函数。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分