找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3867|回复: 7
收起左侧

STM32高级定时器 如何让通道和互补通道既可以输PWM波,也可以输出高电平

[复制链接]
ID:248175 发表于 2021-11-26 11:19 | 显示全部楼层 |阅读模式
大佬们 最近在做直流有刷电机的驱动,使用到STM32高级定时器TIM1的通道1和互补通道,电机的驱动模式采用单极模式,即驱动信号为1路的PWM,一路高电平,且这两种信号通过按钮可以交替实现电机的转向。
我看的视频是HAL库编写的驱动程序,使用的就是TIM1的通道1和互补通道,我编写的库函数版本跟BSP的结构大体相同,但是输出的波形不是我想要的
我根据参考手册将TIM1配置成MOE=1,,OSSR=1,然后用TIM_CCxNCmd()函数关闭互补通道,但是仿真输出的还是低电平(非ST-link仿真),跟参考手册说的这么不一样?请问大佬们问题出在哪里?感谢回答
1.png 2.png
初始化程序如下:
void TIM1_GPIO_init(void)
{
        /*查阅中文参考手册                  */
        /*TIM1通道1的    输出引脚为PA8      */
        /*TIM1通道1的互补输出引脚为PB13     */
       
        /*变量定义*/
        GPIO_InitTypeDef GPIO_InitTypeStructure;
       
        /*使能GPIO的时钟*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOB,ENABLE);
       
        /*使能GPIO的端口复用*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO ,ENABLE);
       
        /*初始化GPIOA*/

        GPIO_InitTypeStructure.GPIO_Pin    = GPIO_Pin_8;
        GPIO_InitTypeStructure.GPIO_Speed  = GPIO_Speed_50MHz;
        GPIO_InitTypeStructure.GPIO_Mode   = GPIO_Mode_AF_PP;//复用推挽输出
        GPIO_Init(GPIOA,&GPIO_InitTypeStructure);
       
        /*初始化GPIOB*/
        GPIO_InitTypeStructure.GPIO_Pin    = GPIO_Pin_13;
        GPIO_Init(GPIOB,&GPIO_InitTypeStructure);
}

void TIM1Init(void)
{
        /*相关变量申明*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseInitTypeStr;
        TIM_OCInitTypeDef TIM_OCInitTypeStr;
        TIM_BDTRInitTypeDef TIM_BDTRInitTypeStr;
       
        /*启动TIM1的时钟,CK_INT=72M*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1,ENABLE);
       
        /*设置时基结构体初始化*/
        TIM_TimeBaseInitTypeStr.TIM_Prescaler           =7199;                //CK_INT=72M,分频后频率为10k,时基周期为0.1ms
        TIM_TimeBaseInitTypeStr.TIM_CounterMode         =TIM_CounterMode_Up;  //向上计数
        TIM_TimeBaseInitTypeStr.TIM_Period              =4999;                //arr,定时器周期为5000个0.1ms,为500ms
        TIM_TimeBaseInitTypeStr.TIM_ClockDivision       =TIM_CKD_DIV1;
        TIM_TimeBaseInitTypeStr.TIM_RepetitionCounter   =0;                   //重复计数器的值,没用到不用管
        TIM_TimeBaseInit(TIM1,&TIM_TimeBaseInitTypeStr);
       
        /*输出比较结构体初始化*/
        TIM_OCInitTypeStr.TIM_OCMode        =TIM_OCMode_PWM1;                 //PWM mode1,计数值CNT<设定值CCRx,为有效电平
        TIM_OCInitTypeStr.TIM_OutputState   =TIM_OutputState_Enable;          //使能输出
        TIM_OCInitTypeStr.TIM_OutputNState  =TIM_OutputNState_Enable;         //使能互补输出
        TIM_OCInitTypeStr.TIM_Pulse         =1000;                            //默认20%的占空比
        TIM_OCInitTypeStr.TIM_OCPolarity    =TIM_OCPolarity_Low;             //极性为0(高电平有效),输出先为高电平,后低电平
        TIM_OCInitTypeStr.TIM_OCNPolarity   =TIM_OCNPolarity_Low;
        TIM_OCInitTypeStr.TIM_OCIdleState   =TIM_OCIdleState_Set;             //空闲模式(主输出为0的时候,如刹车的时候)下,为高电平有效
        TIM_OCInitTypeStr.TIM_OCNIdleState  =TIM_OCNIdleState_Set;            //空闲模式(刹车的时候)下,为低电平有效
        TIM_OC1Init(TIM1,&TIM_OCInitTypeStr);                                 //初始化TIM1通道1
       
        /*刹车和死区结构体初始化*/
        /*主要设置运行模式下(MOD=1),通道关闭后的输出电平*/
        TIM_BDTRInitTypeStr.TIM_OSSRState         =TIM_OSSRState_Enable;      //运行模式下关闭状态使能
        TIM_BDTRInitTypeStr.TIM_OSSIState         =TIM_OSSIState_Disable;     //空闲模式下关闭状态使能
        TIM_BDTRInitTypeStr.TIM_LOCKLevel         =TIM_LOCKLevel_1;           //锁定级别1
        TIM_BDTRInitTypeStr.TIM_DeadTime          =0;                         //设定死区时间,硬件自带死区
        TIM_BDTRInitTypeStr.TIM_Break             =TIM_Break_Disable;         //刹车通道使能
        TIM_BDTRInitTypeStr.TIM_BreakPolarity     =TIM_BreakPolarity_High;    //刹车通道为高电平时进行刹车
        TIM_BDTRInitTypeStr.TIM_AutomaticOutput   =TIM_AutomaticOutput_Enable;//刹车后自动复位,不使能则不会自动复位
        TIM_BDTRConfig(TIM1,&TIM_BDTRInitTypeStr);
       
        /*预装载arr*/
        TIM_ARRPreloadConfig(TIM1,ENABLE);
       
        /*使能TIM1*/
        TIM_Cmd(TIM1,ENABLE);
       
        /*使能TIM1主输出*/
        TIM_CtrlPWMOutputs(TIM1, ENABLE);
       
        /*失能TIM1互补输出引脚*/
//        TIM_CCxCmd(TIM1,TIM_Channel_1,TIM_CCx_Enable);
        TIM_CCxNCmd(TIM1,TIM_Channel_1,TIM_CCxN_Disable);
       
}

void SD_GPIO_Init(void)
{
        /*变量定义*/
        GPIO_InitTypeDef GPIO_InitTypeStructure;
       
        /*使能GPIO的时钟*/
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOE,ENABLE);
       
        /*初始化GPIOE.8*/
        GPIO_InitTypeStructure.GPIO_Pin    = GPIO_Pin_8;
        GPIO_InitTypeStructure.GPIO_Speed  = GPIO_Speed_10MHz;
        GPIO_InitTypeStructure.GPIO_Mode   = GPIO_Mode_Out_PP;//推挽输出
        GPIO_Init(GPIOE,&GPIO_InitTypeStructure);
}

void motor_init(void)
{
        /*高级定时器输出引脚初始化,输出PWM波*/
        TIM1_GPIO_init();
       
        /*高级定时器初始化,设置PWM波*/
        TIM1Init();
       
        /*SD引脚初始化*/
        SD_GPIO_Init();
}



主函数:

int main(void)
{       
        motor_init();
  while(1)
        {

        }
}



硬件电路图:
3.png




回复

使用道具 举报

ID:248175 发表于 2021-11-26 11:25 | 显示全部楼层
红色是我希望的波形,实际上是下面的波形。
4.jpg
回复

使用道具 举报

ID:230742 发表于 2021-11-26 16:56 | 显示全部楼层
曾经看到过一个介绍,手推车单片机PWM输出高电平也不是很理想,在PWM的时候IO口是推挽的。索性直接加了个判断,需要高的时候直接来个IO=1;反正单片机速度又很快,完美解决了。具体我也不会,你可以研究一下。
回复

使用道具 举报

ID:248175 发表于 2021-11-26 17:10 | 显示全部楼层
啤酒瓶子老大 发表于 2021-11-26 16:56
曾经看到过一个介绍,手推车单片机PWM输出高电平也不是很理想,在PWM的时候IO口是推挽的。索性直接加了个判 ...

不只是加个判断那边简单,GPIO输出PWM是在复用模式下,而要推挽输出高电平需要再初始化一下GPIO。
我是想到用通道1和通道2,要高电平的时候吧占空比设置成100%。
但是我想知道通过互补通道能不能实现同样的效果以及如何实现,拓宽一下知识面
回复

使用道具 举报

ID:313048 发表于 2021-11-26 17:12 | 显示全部楼层
不同的初始化就可以了,在每次要用不同功能的时候进行不同的初始化
回复

使用道具 举报

ID:248175 发表于 2021-11-26 17:19 | 显示全部楼层

RE: STM32高级定时器 如何让通道和互补通道既可以输PWM波,也可以输出高电平

AUG 发表于 2021-11-26 17:12
不同的初始化就可以了,在每次要用不同功能的时候进行不同的初始化

好吧 大佬都这么做的吗 那我试试
只不过我看参考手册上有说只要把OSSR开启,然后关闭互补通道就可以输出高电平,我不知道我程序哪里错了
回复

使用道具 举报

ID:301191 发表于 2021-11-27 03:42 | 显示全部楼层
顶一下
回复

使用道具 举报

ID:674853 发表于 2022-1-12 15:47 | 显示全部楼层
TIM_OCInitTypeStr.TIM_OCNPolarity   =TIM_OCNPolarity_Low;
修改这句试一试,把这个极性换一下试试,但是注意互补的波形就变反了
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表