野火电子论坛

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 9469|回复: 2

关于高级定时器输出互补PWM带刹车的程序。

[复制链接]
发表于 2017-7-13 19:42:39 | 显示全部楼层 |阅读模式
火哥,今天学了那个高级定时器产生PWM的列程,我根据参考手册上配置的管脚,就是那个刹车引脚配置成了浮空输入,用示波器显示波形的时候会一直闪。但是根据你们给的列程是配置成了复用推挽输出。先不说模式的不同,连输入都变成了输出,这是为什么?虽然能够正确的显示出波形。求解。
回复

使用道具 举报

发表于 2017-7-17 14:14:52 | 显示全部楼层
当是第二功能只能是输出的时候,你配置输入或者输出是没有效果的。
回复 支持 反对

使用道具 举报

发表于 2023-3-28 23:00:57 | 显示全部楼层
本帖最后由 江瀚林 于 2023-3-28 23:24 编辑

野火哥好,大家好,我是来自2023年3月28日的硬件小菜鸡一枚,留爪爪
1、首先根据参数手册的建议将BKIN脚PB12配置为GPIO_Mode_IN_FLOATING(浮空输入),将BKIN脚PB12的检测极性改为高电平触发
实际调试发现定时器TIM1的CH1、CH1N输出波形不稳定,会有杂波,表现为隐约的0电平(此时示波器开启窄带宽20MHz,排除高频干扰,探头已提前校准)

static void ADVANCE_TIM_GPIO_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        GPIO_InitTypeDef GPIO_InitStructure;

        // 输出比较通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

        // 输出比较通道互补通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

        // 输出比较通道刹车通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // 上拉输入
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
}
static void ADVANCE_TIM_Mode_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        // 开启定时器时钟,即内部时钟CK_INT=72M
        ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK, ENABLE);

        /*--------------------时基结构体初始化-------------------------*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
        TIM_TimeBaseStructure.TIM_Period = ADVANCE_TIM_PERIOD; // 周期
        // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
        TIM_TimeBaseStructure.TIM_Prescaler = ADVANCE_TIM_PSC; // 分频
        // 时钟分频因子 ,配置死区时间时需要用到
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 对CK_INT的分频得到死区时钟的频率,该成员配置高级定时器不能省略
        // 计数器计数模式,设置为向上计数
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
        // 重复计数器的值,没用到不用管
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 不使用重复计数器
        // 初始化定时器
        TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

        /*--------------------输出比较结构体初始化-------------------*/
        TIM_OCInitTypeDef TIM_OCInitStructure;
        // 配置为PWM模式1
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                                // PWM1模式,默认递增模式下先输出1,计数到CCRx输出0
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;        // 输出使能
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出使能
        TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;                                // 设置占空比大小
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;                // 互补输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;                // 刹车BKIN起作用时输出通道的电平(刹车功能使用时会用到,idle_state学名是空闲状态)
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;        // 刹车BKIN起作用时互补输出通道的电平
        TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);                                        // 初始化通道1(注意CCRx不同,函数不一样)
        TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);                // 使能重装载功能(注意CCRx不同,函数不一样)

        /*-------------------刹车和死区结构体初始化-------------------*/
        // 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
        TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
        TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; // 运行模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; // 空闲模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;                // 锁定级别1
        // 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
        // 这里配置的死区时间为152ns
        TIM_BDTRInitStructure.TIM_DeadTime = 11;                                                                // 死区时间配置为152nS
        TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;                                                // 刹车功能使能
        TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;                // 当BKIN引脚检测极性配置,高电平的时候,输出比较信号被禁止,就好像是刹车一样
        TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // 通常配置为自动输出使能
        TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);                                        // 初始化BDTR

        TIM_Cmd(ADVANCE_TIM, ENABLE);                         // 使能计数器
        TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE); // 主输出使能,当使用的是通用定时器时,这句不需要
}

野火论坛202303282200428761..png 野火论坛202303282226206154..png
个人分析是因为PB12配置为浮空输入以后,且没有外置下拉/上拉电路,使得引入噪声(来源环境电磁干扰)
将PB12接3V3后,PWM波确实全部不输出(因为由于实际项目需要全部输出低电平,所以将CH1,CH1N的idle_state空闲状态都配置为0)
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;                // 刹车BKIN起作用时输出通道的电平(刹车功能使用时会用到,idle_state学名是空闲状态)
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;        // 刹车BKIN起作用时互补输出通道的电平
断开3V3后,PWM波输出自动恢复

总结:由于输出波形不稳定,所以不采用这个方法

2、野火哥的建议,配置BKIN脚PB12为GPIO_Mode_AF_PP(复用推挽输出),将BKIN脚PB12的检测极性改为高电平触发
static void ADVANCE_TIM_GPIO_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        GPIO_InitTypeDef GPIO_InitStructure;

        // 输出比较通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

        // 输出比较通道互补通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

        // 输出比较通道刹车通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
        GPIO_ResetBits(ADVANCE_TIM_BKIN_PORT, ADVANCE_TIM_BKIN_PIN);//// BKIN引脚默认先输出低电平
}
static void ADVANCE_TIM_Mode_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        // 开启定时器时钟,即内部时钟CK_INT=72M
        ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK, ENABLE);

        /*--------------------时基结构体初始化-------------------------*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
        TIM_TimeBaseStructure.TIM_Period = ADVANCE_TIM_PERIOD; // 周期
        // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
        TIM_TimeBaseStructure.TIM_Prescaler = ADVANCE_TIM_PSC; // 分频
        // 时钟分频因子 ,配置死区时间时需要用到
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 对CK_INT的分频得到死区时钟的频率,该成员配置高级定时器不能省略
        // 计数器计数模式,设置为向上计数
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
        // 重复计数器的值,没用到不用管
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 不使用重复计数器
        // 初始化定时器
        TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

        /*--------------------输出比较结构体初始化-------------------*/
        TIM_OCInitTypeDef TIM_OCInitStructure;
        // 配置为PWM模式1
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                                // PWM1模式,默认递增模式下先输出1,计数到CCRx输出0
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;        // 输出使能
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出使能
        TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;                                // 设置占空比大小
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;                // 互补输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;                // 刹车BKIN起作用时输出通道的电平(刹车功能使用时会用到,idle_state学名是空闲状态)
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;        // 刹车BKIN起作用时互补输出通道的电平
        TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);                                        // 初始化通道1(注意CCRx不同,函数不一样)
        TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);                // 使能重装载功能(注意CCRx不同,函数不一样)

        /*-------------------刹车和死区结构体初始化-------------------*/
        // 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
        TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
        TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; // 运行模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; // 空闲模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;                // 锁定级别1
        // 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
        // 这里配置的死区时间为152ns
        TIM_BDTRInitStructure.TIM_DeadTime = 11;                                                                // 死区时间配置为152nS
        TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;                                                // 刹车功能使能
        TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_High;                // 当BKIN引脚检测极性配置,高电平的时候,输出比较信号被禁止,就好像是刹车一样
        TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // 通常配置为自动输出使能
        TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);                                        // 初始化BDTR

        TIM_Cmd(ADVANCE_TIM, ENABLE);                         // 使能计数器
        TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE); // 主输出使能,当使用的是通用定时器时,这句不需要
}

烧录完成之后,此时的波形稳定干净,且接上3V3后,波形自动不输出
野火论坛202303282224267755..png 野火论坛202303282320339888..png


但是这个方法是有风险的!!!
由于推挽输出的驱动力很强,且默认输出低电平,实际测试短接3V3会有44.5mA的电流灌进PB12引脚!!!
虽然没有烧毁指南者芯片STM32F103VET6
野火论坛202303282234255164..png 野火论坛202303282253023040..png

3、自己尝试,配置BKIN脚PB12 GPIO_Mode_IPU(上拉输入),将BKIN脚PB12的检测极性改为低电平触发
达到同样效果,向外输出的电流也是最小的73.85uA!!!!效果最优,所以采用!!
static void ADVANCE_TIM_GPIO_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        GPIO_InitTypeDef GPIO_InitStructure;

        // 输出比较通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1_PORT, &GPIO_InitStructure);

        // 输出比较通道互补通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_CH1N_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_CH1N_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 复用推挽输出
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_CH1N_PORT, &GPIO_InitStructure);

        // 输出比较通道刹车通道 GPIO 初始化
        RCC_APB2PeriphClockCmd(ADVANCE_TIM_BKIN_GPIO_CLK, ENABLE);
        GPIO_InitStructure.GPIO_Pin = ADVANCE_TIM_BKIN_PIN;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // 上拉输入
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_Init(ADVANCE_TIM_BKIN_PORT, &GPIO_InitStructure);
}

static void ADVANCE_TIM_Mode_Config(void) // 加上static表示只能在Advanced_Tim.c中调用
{
        // 开启定时器时钟,即内部时钟CK_INT=72M
        ADVANCE_TIM_APBxClock_FUN(ADVANCE_TIM_CLK, ENABLE);

        /*--------------------时基结构体初始化-------------------------*/
        TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
        // 自动重装载寄存器的值,累计TIM_Period+1个频率后产生一个更新或者中断
        TIM_TimeBaseStructure.TIM_Period = ADVANCE_TIM_PERIOD; // 周期
        // 驱动CNT计数器的时钟 = Fck_int/(psc+1)
        TIM_TimeBaseStructure.TIM_Prescaler = ADVANCE_TIM_PSC; // 分频
        // 时钟分频因子 ,配置死区时间时需要用到
        TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 对CK_INT的分频得到死区时钟的频率,该成员配置高级定时器不能省略
        // 计数器计数模式,设置为向上计数
        TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 向上计数
        // 重复计数器的值,没用到不用管
        TIM_TimeBaseStructure.TIM_RepetitionCounter = 0; // 不使用重复计数器
        // 初始化定时器
        TIM_TimeBaseInit(ADVANCE_TIM, &TIM_TimeBaseStructure);

        /*--------------------输出比较结构体初始化-------------------*/
        TIM_OCInitTypeDef TIM_OCInitStructure;
        // 配置为PWM模式1
        TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;                                // PWM1模式,默认递增模式下先输出1,计数到CCRx输出0
        TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;        // 输出使能
        TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable; // 互补输出使能
        TIM_OCInitStructure.TIM_Pulse = ADVANCE_TIM_PULSE;                                // 设置占空比大小
        TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;                // 输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_High;                // 互补输出通道电平极性配置,通常配置有效电平=1
        TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;                // 刹车BKIN起作用时输出通道的电平(刹车功能使用时会用到,idle_state学名是空闲状态)
        TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Reset;        // 刹车BKIN起作用时互补输出通道的电平
        TIM_OC1Init(ADVANCE_TIM, &TIM_OCInitStructure);                                        // 初始化通道1(注意CCRx不同,函数不一样)
        TIM_OC1PreloadConfig(ADVANCE_TIM, TIM_OCPreload_Enable);                // 使能重装载功能(注意CCRx不同,函数不一样)

        /*-------------------刹车和死区结构体初始化-------------------*/
        // 有关刹车和死区结构体的成员具体可参考BDTR寄存器的描述
        TIM_BDTRInitTypeDef TIM_BDTRInitStructure;
        TIM_BDTRInitStructure.TIM_OSSRState = TIM_OSSRState_Enable; // 运行模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_OSSIState = TIM_OSSIState_Enable; // 空闲模式下“关闭状态”选择,通常使能
        TIM_BDTRInitStructure.TIM_LOCKLevel = TIM_LOCKLevel_1;                // 锁定级别1
        // 输出比较信号死区时间配置,具体如何计算可参考 BDTR:UTG[7:0]的描述
        // 这里配置的死区时间为152ns
        TIM_BDTRInitStructure.TIM_DeadTime = 11;                                                                // 死区时间配置为152nS
        TIM_BDTRInitStructure.TIM_Break = TIM_Break_Enable;                                                // 刹车功能使能
        TIM_BDTRInitStructure.TIM_BreakPolarity = TIM_BreakPolarity_Low;                // 当BKIN引脚检测极性配置,高电平的时候,输出比较信号被禁止,就好像是刹车一样
        TIM_BDTRInitStructure.TIM_AutomaticOutput = TIM_AutomaticOutput_Enable; // 通常配置为自动输出使能
        TIM_BDTRConfig(ADVANCE_TIM, &TIM_BDTRInitStructure);                                        // 初始化BDTR

        TIM_Cmd(ADVANCE_TIM, ENABLE);                         // 使能计数器
        TIM_CtrlPWMOutputs(ADVANCE_TIM, ENABLE); // 主输出使能,当使用的是通用定时器时,这句不需要
}
经过实际测试,波形如下
野火论坛202303282322346049..png 野火论坛202303282324022747..png
野火论坛202303282258453894..png 野火论坛202303282300336387..png









回复 支持 反对

使用道具 举报

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

本版积分规则

联系站长|手机版|野火电子官网|野火淘宝店铺|野火电子论坛 ( 粤ICP备14069197号 ) 大学生ARM嵌入式2群

GMT+8, 2024-3-29 02:15 , Processed in 0.042036 second(s), 26 queries , Gzip On.

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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