信阳地区网站建设服务是否盈利?哪些公司是当地排名靠前的?
摘要:现在建网站赚钱吗,信阳网站建设公司排名,产品推广步骤,零基础网站建设教学培训前言 STM32F103系列的MCU,相比普通的51单片机,在输出硬件PWM这个功能上要强不少&
现在建网站赚钱吗,信阳网站建设公司排名,产品推广步骤,零基础网站建设教学培训前言
STM32F103系列的MCU#xff0c;相比普通的51单片机#xff0c;在输出硬件PWM这个功能上要强不少#xff0c;两者实现的方式都类似#xff0c;都是通过一个定时器来启用硬件PWM输出#xff0c;不过在输出PWM通道的数量上#xff0c;32F103要强上不少。仅通过一个高级…前言
STM32F103系列的MCU相比普通的51单片机在输出硬件PWM这个功能上要强不少两者实现的方式都类似都是通过一个定时器来启用硬件PWM输出不过在输出PWM通道的数量上32F103要强上不少。仅通过一个高级定时器1即TIM1就可以输出4路频率相同占空比独立的PWM信号这四路PWM还分别有互补通道且带死区和刹车功能。
利用TIM1来产生4路频率相同占空比不同的PWM信号
初始化的方法其实跟前面几篇文章初始化其他外设的步骤类似也是先定义一个结构体变量然后给这个结构体变量的成员配置好相应的初值最后调用初始化函数这样就完成外设初始化了。再通过调用开外设的函数就可以把外设功能使能。
首先定义一个结构体变量来初始化TIM1定义PWM信号的频率
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //配置时基结构体,声明一个结构体变量方便传参//时基初始化//
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //开TIMER1外设时钟TIM_TimeBaseStructure.TIM_Prescaler 72-1;
// 计数器计数模式
TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up;
TIM_TimeBaseStructure.TIM_Period 10000-1;// 时钟分频因子 - 一分频,配置死区时间需要用到
TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV4;// 重复寄存器的值,没有用到,不管
TIM_TimeBaseStructure.TIM_RepetitionCounter 0;TIM_TimeBaseInit(TIM1,TIM_TimeBaseStructure);我使用的是倍频到72M的时钟信号作为APB2的时钟总线然后我分频器选择的是72分频那么分频之后的周期就是1/1M即TIM1往上计数一次是1us然后计数周期我设置为了从0计数到9999即10000次耗时就是10ms。所以我设置的PWM频率就是100Hz的。
下一步开始设置PWM的结构体在手册中硬件PWM这部分内容是属于 高级定时器中的输出/比较模式 所以要配置PWM我们就要配置 输出/比较结构体。
TIM_OCInitTypeDef TIM_OCInitStructure; //配置输出比较结构体,声明一个结构体变量方便传参TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道1输出使能
TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; //互补通道使能
TIM_OCInitStructure.TIM_Pulse 4000; //占空比
TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效
TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效
TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平
TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平
TIM_OC1Init(TIM1,TIM_OCInitStructure); //初始化TIM1通道1输出PWMTIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道2输出使能
TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能
TIM_OCInitStructure.TIM_Pulse 6000; //占空比
TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效
TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效
TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平
TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平
TIM_OC2Init(TIM1,TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道3输出使能
TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能
TIM_OCInitStructure.TIM_Pulse 8000; //占空比
TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效
TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效
TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平
TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平
TIM_OC3Init(TIM1,TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道4输出使能
TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能
TIM_OCInitStructure.TIM_Pulse 9000; //占空比
TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效
TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效
TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平
TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平
TIM_OC4Init(TIM1,TIM_OCInitStructure);TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1 输出比较1的预装载使能 想要改变占空比 得先输出完当前周期的波形之后 到下个波形才按照新的占空比(更新事件发生后才改变占空比)TIM_Cmd(TIM1,ENABLE); //开启TIM1
TIM_CtrlPWMOutputs(TIM1,ENABLE); //开启PWM输出其实看起来内容多实际上都是重复的内容。高级定时器的每路PWM通道都通过一个库函数来初始化比如通道1就是调用TIM_OC1Init(TIM1,TIM_OCInitStructure); 前面这个形参是配置利用哪个定时器的通道1来产生PWM信号后面这个形参就是我们定义的结构体变量的首地址负责传入我们配置的相应参数。
除了高级定时器通用定时器也可以产生PWM信号但是基本定时器是无法产生PWM信号的基本定时器的功能只有下面这几个 回到正题配置完时基和输出/比较模式的PWM模式的寄存器之后再把PWM四个通道的IO配置一下
void AdvanceTim_GPIO_Config(void)
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);GPIO_InitTypeDef GPIO_InitStruct;GPIO_InitStruct.GPIO_Pin GPIO_Pin_8;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin GPIO_Pin_9;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin GPIO_Pin_10;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);GPIO_InitStruct.GPIO_Pin GPIO_Pin_11;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOA,GPIO_InitStruct);//刹车通道GPIO_InitStruct.GPIO_Pin GPIO_Pin_12;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB,GPIO_InitStruct);GPIO_ResetBits(GPIOB,GPIO_Pin_12); //默认为低电平,这个脚一旦被拉高证明刹车有效,立刻停止输出PWM//TIM1 CHANNEL1互补通道GPIO_InitStruct.GPIO_Pin GPIO_Pin_13;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB,GPIO_InitStruct);
}这里暂时只需要关注PA8、PA9、PA10、PA11这四个IO的配置其他的是后面做刹车和互补才需要用到的。 配置起来其实很简单但是要注意GPIO模式要配置为复用的推挽输出模式。
在设置完这些之后就可以去主函数里面调用了。 给前面我们写的初始化时基和PWM寄存器的代码写到同一个函数里
void AdvanceTim_Mode_Config(void)
{TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure; //配置时基结构体,声明一个结构体变量方便传参TIM_OCInitTypeDef TIM_OCInitStructure; //配置输出比较结构体,声明一个结构体变量方便传参//时基初始化//RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE); //开TIMER1外设时钟TIM_TimeBaseStructure.TIM_Prescaler 72-1;// 计数器计数模式TIM_TimeBaseStructure.TIM_CounterMode TIM_CounterMode_Up;TIM_TimeBaseStructure.TIM_Period 10000-1;// 时钟分频因子 - 一分频,配置死区时间需要用到TIM_TimeBaseStructure.TIM_ClockDivision TIM_CKD_DIV4;// 重复寄存器的值,没有用到,不管TIM_TimeBaseStructure.TIM_RepetitionCounter 0;TIM_TimeBaseInit(TIM1,TIM_TimeBaseStructure);////TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道1输出使能TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; //互补通道使能TIM_OCInitStructure.TIM_Pulse 4000; //占空比TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平TIM_OC1Init(TIM1,TIM_OCInitStructure); //初始化TIM1通道1输出PWMTIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道2输出使能TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能TIM_OCInitStructure.TIM_Pulse 6000; //占空比TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平TIM_OC2Init(TIM1,TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道3输出使能TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能TIM_OCInitStructure.TIM_Pulse 8000; //占空比TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平TIM_OC3Init(TIM1,TIM_OCInitStructure);TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道4输出使能TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Disable; //互补通道失能TIM_OCInitStructure.TIM_Pulse 9000; //占空比TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平TIM_OC4Init(TIM1,TIM_OCInitStructure);TIM_OC1PreloadConfig(TIM1,TIM_OCPreload_Enable); //使能TIM1 输出比较1的预装载使能 想要改变占空比 得先输出完当前周期的波形之后 到下个波形才按照新的占空比(更新事件发生后才改变占空比)TIM_Cmd(TIM1,ENABLE);TIM_CtrlPWMOutputs(TIM1,ENABLE);}在主函数中
int main(void)
{GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //禁用JTAGAdvanceTim_GPIO_Config();AdvanceTim_Mode_Config();while(1){}
}下载到板子上用逻辑分析仪抓取PA8/9/10/11这四个IO的波形可以观察到四路PWM信号的频率相同因为都是通过TIM1产生的但是四路PWM信号的占空比分别为40%、60%、80%、90%。这就实现了硬件PWM的输出。
输出TIM1通道1的互补信号
其实这个不用单独再拿出来讲在配置TIM1通道1的时候有几个结构体成员的值修改一下即可输出通道1的互补信号。
TIM_OCInitStructure.TIM_OCMode TIM_OCMode_PWM1; //PWM模式1
TIM_OCInitStructure.TIM_OutputState TIM_OutputState_Enable; //TIM1通道1输出使能
TIM_OCInitStructure.TIM_OutputNState TIM_OutputNState_Enable; //互补通道使能
TIM_OCInitStructure.TIM_Pulse 4000; //占空比
TIM_OCInitStructure.TIM_OCPolarity TIM_OCPolarity_High; //高电平有效
TIM_OCInitStructure.TIM_OCNPolarity TIM_OCPolarity_High; //互补通道也是高电平有效
TIM_OCInitStructure.TIM_OCIdleState TIM_OCIdleState_Reset; //空闲状态 低电平
TIM_OCInitStructure.TIM_OCNIdleState TIM_OCNIdleState_Reset; //互补通道空闲状态 低电平
TIM_OC1Init(TIM1,TIM_OCInitStructure); //初始化TIM1通道1输出PWMTIM_OutputNState 这个成员配置为TIM_OutputNState_Enable那么互补通道就使能了 TIM_OCNPolarity 这个成员是配置互补通道是什么电平有效 TIM_OCNIdleState_Reset 这个成员是配置互补通道的空闲状态应该是什么电平。 一般如果要用到互补模式的话互补通道的配置与通道1是相同的如果需要产生错相的两路PWM信号那么要用到中心对其模式才能做到硬件PWM是不具备输出错相PWM波的功能的。
配置了有关PWM的寄存器之后配置一下互补通道的GPIO也是配置为复用推挽输出模式。不过要注意的是每路PWM信号的输出脚和互补脚都有很多个我这边因为MCU脚位只有64个所以还不需要选择在哪个IO输出推测应该是如果把IO设置为了复用输出模式那么PWM就会从那个复用脚输出出来不需要再配置相应的寄存器了。
刹车功能的使用
这个功能我仅限于能使用一些较为深层次的原理和使用场景我就说不出来了。
在前面定义的AdvanceTim_Mode_Config(void)函数中多声明一个结构体成员并且调用初始化函数来初始化 刹车 和 死区寄存器。
TIM_BDTRInitTypeDef TIM_BDTRInitStructure; //配置有关刹车和死区结构体,声明一个结构体变量方便传参// TIM_BDTRInitStructure这个结构体配置的是 刹车和死区寄存器(TIMx_BDTR)
// 当 BKIN 引脚检测到低电平的时候输出比较信号被禁止就好像是刹车一样
TIM_BDTRInitStructure.TIM_OSSRState TIM_OSSRState_Enable; // 运行模式下的“关闭状态”选择 - 使能
TIM_BDTRInitStructure.TIM_OSSIState TIM_OSSIState_Enable; // 空闲模式下的关闭状态选择 - 使能
TIM_BDTRInitStructure.TIM_LOCKLevel TIM_LOCKLevel_1; // 锁定等级1
TIM_BDTRInitStructure.TIM_DeadTime 0xFF;
TIM_BDTRInitStructure.TIM_Break TIM_Break_Enable; // 刹车功能使能 - 开启刹车输入
TIM_BDTRInitStructure.TIM_BreakPolarity TIM_BreakPolarity_High; // 刹车信号 - 高电平刹车
TIM_BDTRInitStructure.TIM_AutomaticOutput TIM_AutomaticOutput_Enable; // 自动输出使能
TIM_BDTRConfig(TIM1,TIM_BDTRInitStructure);TIM_OSSRState 和 TIM_OSSIState 这两个成员配置的是 TIMx_BDTR寄存器里面的 OSSR位 和 OSSI位其他的成员互相之间是有关联的比如 TIM_LOCKLevel 锁定等级如果配置的是 2 或者 3那么 TIMx_BDTR这个寄存器在配置完之后有一些成员是没法再改变值的这是ST对这个功能的一些保护机制。后面的几个成员就比较好理解注释有写不再过多解释。 关于TIM_DeadTime 这个成员配置的是DTG[7:0]这七位数据这7位数据比较有意思手册是这样写的 5-7位填入不同的值Tdtg的值不同Tdts是我们在配置时基那里配置的我为了让死区时间更加明显所以我配置的都比较久Tdts我配置为了TIM1时钟的四分频我的TIM1时钟配置为了1M那么Tdts就是250Khz 的频率Tdtg16/250Khz在乘以(32(0-4位配置的数值))。
配置了BDTR寄存器之后配置一下刹车通道的输入这里是我当时比较疑惑的我不太明白为什么刹车通道也是配置为复用推挽输出模式。反正按照这样设置完之后把PB12这个IO一拉高所有的硬件PWM信号全部停止输出会全部回到空闲状态我配置的那个电平状态。
//刹车通道GPIO_InitStruct.GPIO_Pin GPIO_Pin_12;GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_PP;GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz;GPIO_Init(GPIOB,GPIO_InitStruct);GPIO_ResetBits(GPIOB,GPIO_Pin_12); //默认为低电平,这个脚一旦被拉高证明刹车有效,立刻停止输出PWM到这TIM1的PWM输出、互补输出、死区、刹车这几个功能就全都实现了。
