PWM的实现
单片机硬件基础与其计数原理
通用定时器
累加计数(向上计数)
交替计数
PWM占空比的设置
pwm.c
#include "pwm.h"
void TIM3_PWM_Init(u16 arr,u16 psc){ //TIM3 PWM初始化 arr重装载值 psc预分频系数
GPIO_InitTypeDef GPIO_InitStrue;
TIM_OCInitTypeDef TIM_OCInitStrue;
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStrue;
//分别打开定时器,GPIO与复用接口的时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);//使能TIM3和相关GPIO时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);//使能GPIOB时钟(LED在PB0引脚)
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);//使能AFIO时钟(定时器3通道3需要重映射到BP5引脚)
GPIO_InitStrue.GPIO_Pin=GPIO_Pin_0; // TIM_CH3
GPIO_InitStrue.GPIO_Mode=GPIO_Mode_AF_PP; // 复用推挽
GPIO_InitStrue.GPIO_Speed=GPIO_Speed_50MHz; //设置最大输出速度
GPIO_Init(GPIOB,&GPIO_InitStrue); //GPIO端口初始化设置
// GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //映射,重映射只用于64、100、144脚单片机
// 复用功能的重映射一般是指
// “在对应引脚被占用时,通过设置重映射RemapConfig的值来改变计时器(或其他设备)对应使用的引脚的值”
//当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1
//当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1 (GPIO_PartialRemap_TIM3)
//当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9 (GPIO_FullRemap_TIM3)
TIM_TimeBaseInitStrue.TIM_Period=arr; //设置自动重装载值(计数溢出值)
TIM_TimeBaseInitStrue.TIM_Prescaler=psc; //预分频系数(一频的周期数)
TIM_TimeBaseInitStrue.TIM_CounterMode=TIM_CounterMode_Up; //计数器向上溢出
// #define TIM_CounterMode_Up ((uint16_t)0x0000) 累加计数
// #define TIM_CounterMode_Down ((uint16_t)0x0010) 向下/累减计数
// #define TIM_CounterMode_CenterAligned1 ((uint16_t)0x0020) 交替计数,并在ARR处溢出
// #define TIM_CounterMode_CenterAligned2 ((uint16_t)0x0040) 交替计数,并在CNT=0处溢出
// #define TIM_CounterMode_CenterAligned3 ((uint16_t)0x0060) 交替计数,并在ARR和CNT=0处溢出
TIM_TimeBaseInitStrue.TIM_ClockDivision=TIM_CKD_DIV1; //时钟的分频因子,起到了一点点的延时作用,一般设为TIM_CKD_DIV1(不稳定就用TIM_CKD_DIV2)
TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStrue); //TIM3初始化设置(设置PWM的周期)
TIM_OCInitStrue.TIM_OCMode=TIM_OCMode_PWM1; // PWM模式1:CNT < CCR时输出有效电平
// #define TIM_OCMode_Timing ((uint16_t)0x0000)
// #define TIM_OCMode_Active ((uint16_t)0x0010)
// #define TIM_OCMode_Inactive ((uint16_t)0x0020)
// #define TIM_OCMode_Toggle ((uint16_t)0x0030)
// #define TIM_OCMode_PWM1 ((uint16_t)0x0060)
// #define TIM_OCMode_PWM2 ((uint16_t)0x0070)
TIM_OCInitStrue.TIM_OCPolarity=TIM_OCPolarity_High;// 设置极性-有效电平为:高电平
TIM_OCInitStrue.TIM_OutputState=TIM_OutputState_Enable;// 输出使能
TIM_OC3Init(TIM3,&TIM_OCInitStrue); //TIM3的通道3 PWM 模式设置
TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable); //使能预装载寄存器
TIM_Cmd(TIM3,ENABLE); //使能TIM3
}
设置时钟
设置接口
将结构体中的装载值,分频系数与计数方式载入函数
设置高/低电平有效
使能寄存器与时钟
main.c实现对SG90的控制
int main (void){//主程序
delay_ms(500); //上电时等待其他器件就绪
RCC_Configuration(); //系统时钟初始化
RELAY_Init();//继电器初始化
I2C_Configuration();//I2C初始化
OLED0561_Init(); //OLED初始化
OLED_DISPLAY_8x16_BUFFER(0," YoungTalk "); //显示字符串
OLED_DISPLAY_8x16_BUFFER(3," SG90 TEST2 "); //显示字符串
TOUCH_KEY_Init();//按键初始化
TIM3_PWM_Init(59999,23); //设置频率为50Hz,公式为:溢出时间Tout(单位秒)=(arr+1)(psc+1)/Tclk 20MS = (59999+1)*(23+1)/72000000
//Tclk为通用定时器的时钟,如果APB1没有分频,则就为系统时钟,72MHZ
//PWM时钟频率=72000000/(59999+1)*(23+1) = 50HZ (20ms),设置自动装载值60000,预分频系数24
while(1){
if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_A)){ //读触摸按键的电平
OLED_DISPLAY_8x16_BUFFER(6," Angle 0 "); //显示字符串
TIM_SetCompare3(TIM3,1500); //改变比较值TIM3->CCR2达到调节占空比的效果(1500为0度)
//void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3)通过设置Compare3来设置占空比
}
if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_B)){ //读触摸按键的电平
OLED_DISPLAY_8x16_BUFFER(6," Angle 45 "); //显示字符串
TIM_SetCompare3(TIM3,3000); //改变比较值TIM3->CCR2达到调节占空比的效果
}
if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_C)){ //读触摸按键的电平
OLED_DISPLAY_8x16_BUFFER(6," Angle 90 "); //显示字符串
TIM_SetCompare3(TIM3,4500); //改变比较值TIM3->CCR2达到调节占空比的效果
}
if(!GPIO_ReadInputDataBit(TOUCH_KEYPORT,TOUCH_KEY_D)){ //读触摸按键的电平
OLED_DISPLAY_8x16_BUFFER(6," Angle 180 "); //显示字符串
TIM_SetCompare3(TIM3,7500); //改变比较值TIM3->CCR2达到调节占空比的效果
}
}
}