历史上的今天
返回首页

历史上的今天

今天是:2024年12月29日(星期日)

2021年12月29日 | STM32F103单片机PWM单脉冲输出模式

2021-12-29 来源:eefocus

  通常输出PWM波形的时候是一直输出的。但是在电机控制中往往只需要输出一定个数的脉冲,不需要一直输出,那么这就需要每次输出PWM时,输出的脉冲个数可控。要实现这个功能,一般有三种方法。


  方法一:


void TIM1_PWM_Init(u16 arr, u16 psc)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    NVIC_InitTypeDef NVIC_InitStructure;


    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;

    TIM_OCInitTypeDef TIM_OCInitSturcture;


    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_TIM1, ENABLE);


    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);


    NVIC_InitStructure.NVIC_IRQChannel = TIM1_UP_IRQn;

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

    NVIC_Init(&NVIC_InitStructure);


    TIM_TimeBaseInitStructure.TIM_Period = arr;

    TIM_TimeBaseInitStructure.TIM_Prescaler = 71;

    TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;

    TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0x00;

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseInitStructure);


    TIM_OCStructInit(& TIM_OCInitSturcture);


    TIM_OCInitSturcture.TIM_OCMode = TIM_OCMode_PWM2;

    TIM_OCInitSturcture.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitSturcture.TIM_Pulse = 0;

    TIM_OCInitSturcture.TIM_OCPolarity = TIM_OCPolarity_Low;

    TIM_OC1Init(TIM1, &TIM_OCInitSturcture);


    TIM_OC1PreloadConfig(TIM1, TIM_OCPreload_Enable);

    TIM_CtrlPWMOutputs(TIM1, ENABLE); //主输出使能

    TIM_ARRPreloadConfig(TIM1, ENABLE);


    TIM_ITConfig(TIM1, TIM_IT_Update, ENABLE);

    TIM_Cmd(TIM1, ENABLE); //使能计数器

    TIM_SetCompare1(TIM1, arr / 2);

}


void TIM1_UP_IRQHandler(void)

{

    static  u16 y;

    if(TIM_GetITStatus(TIM1, TIM_IT_Update) != RESET)

    {

        TIM_ClearITPendingBit(TIM1, TIM_IT_Update );

        y++;

        if(y > 60) //设置输出脉冲数

        {

            y = 0;

            TIM_Cmd(TIM1, DISABLE);

        }

    }

}


  这个方法实现的原理最简单,就是开启PWM输出的更新中断功能,当计时器值重新加载一次时,就会产生一个中断,就代表输出了一个脉冲。这样每进一次中断,就统计一次中断次数,当中断的次数和需要的脉冲数相等时就关闭PWM的输出。这样也就实现了指定脉冲输出的功能。


  方法二:


void PWMS8_Init(u32 Cycle, u32 PulseNum)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    TIM_OCInitTypeDef  TIM_OCInitStructure;

   

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM8, ENABLE);

  

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC | RCC_APB2Periph_AFIO, ENABLE);

   

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOC, &GPIO_InitStructure);


    TIM_TimeBaseStructure.TIM_Period = Cycle; //频率

    TIM_TimeBaseStructure.TIM_Prescaler = 71; //分频值  72M/(71+1) = 1M 

    TIM_TimeBaseStructure.TIM_ClockDivision = 0;

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

    TIM_TimeBaseStructure.TIM_RepetitionCounter = PulseNum - 1;   //输出脉冲个数

    TIM_TimeBaseInit(TIM8, &TIM_TimeBaseStructure);


    TIM_GenerateEvent(TIM8, TIM_EventSource_Update);

    TIM_InternalClockConfig(TIM8);

    TIM_SelectOCxM(TIM8, TIM_Channel_2, TIM_OCMode_PWM2);


    /* PWM1 Mode configuration: Channel2 */

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;

    TIM_OCInitStructure.TIM_Pulse = Cycle / 2; // 低电平时间  占空比

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCNPolarity_Low;

    TIM_OC2Init(TIM8, &TIM_OCInitStructure);

    TIM_OC2PreloadConfig(TIM8, TIM_OCPreload_Enable);

    TIM_ARRPreloadConfig(TIM8, ENABLE);

    /* TIM8 enable counter */

    TIM_CtrlPWMOutputs(TIM8, ENABLE);


    TIM_SelectOnePulseMode(TIM8, TIM_OPMode_Single);

    TIM_Cmd(TIM8, ENABLE);

}


  在方法一中是通过代码自己统计ARR的装载次数,而单片机内部也自带了这个功能,方法二中就直接使用这个系统自带的功能。这个功能就是重复计数器。

image.png?imageView2/2/w/550
image.png?imageView2/2/w/550
image.png?imageView2/2/w/550

  在初始化时将要输出的脉冲个数写入到重复计数器中,这样系统就会自动统计输出PWM的脉冲个数,当输出脉冲个数完成后就会自动停止PWM输出。


  方法三:


/***********************TIM1初始化函数*************************/

/****参数:****************************************************/

/******u32 Cycle用于设定计数频率(计算公式:Cycle=1Mhz/目标频率)*/

/****返回值:**************************************************/

/******无*****************************************************/

void TIM1_config(u32 Cycle)

{

    GPIO_InitTypeDef GPIO_InitStructure;

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    TIM_OCInitTypeDef  TIM_OCInitStructure;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_TIM1 , ENABLE); //时钟使能

 

    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;                   //TIM1_CH1 PA10

    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;             //复用推挽输出

    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

    GPIO_Init(GPIOA, &GPIO_InitStructure);

 

    TIM_TimeBaseStructure.TIM_Period = Cycle-1;                 //使用Cycle来控制频率(f=72/(71+1)/Cycle)  当Cycle为100时脉冲频率为10KHZ                           

    TIM_TimeBaseStructure.TIM_Prescaler =71;         //设置用来作为TIMx时钟频率除数的预分频值                                                     

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     //设置时钟分割:TDTS= Tck_tim            

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式

    TIM_TimeBaseStructure.TIM_RepetitionCounter = 0;            //重复计数,一定要=0!!!(高级定时器特有)

    TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);                                       

 

    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;          //选择定时器模式:TIM脉冲宽度调制模式2     

    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能

    TIM_OCInitStructure.TIM_Pulse = Cycle/2-1;                    //设置待装入捕获寄存器的脉冲值(占空比:默认50%,这可也可以调节如果需要的话将它作为一个参数传入即可)                                   

    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;      //输出极性       

 

    TIM_OC3Init(TIM1, &TIM_OCInitStructure);               //使能通道1                                              

 

    TIM_SelectMasterSlaveMode(TIM1, TIM_MasterSlaveMode_Enable); //设置为主从模式

    TIM_SelectOutputTrigger(TIM1, TIM_TRGOSource_Update); //选择定时器1的触发方式(使用更新事件作为触发输出)

    

 

    TIM_OC3PreloadConfig(TIM1, TIM_OCPreload_Enable);               //使能通道1预装载寄存器               

    TIM_ARRPreloadConfig(TIM1, ENABLE);                             //使能TIM1在ARR上的预装载寄存器       

}

/***********************TIM2初始化函数*************************/

/****参数:****************************************************/

/******u32 PulseNum用于设定脉冲数量****************************/

/****返回值:*************************************************/

/******无*****************************************************/

void TIM2_config(u32 PulseNum)

{

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

    NVIC_InitTypeDef NVIC_InitStructure; 

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //使能定时器2的时钟

 

    TIM_TimeBaseStructure.TIM_Period = PulseNum;    //脉冲数

    TIM_TimeBaseStructure.TIM_Prescaler =0;    

    TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;     

    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);  

 

    TIM_SelectInputTrigger(TIM2, TIM_TS_ITR0); //选择定时器2的输入触发源(内部触发(TIM1))

 

    TIM2->SMCR|=0x07;                    //设置从模式寄存器(SMS[2:0]:111 外部时钟模式1) 

 

    TIM_ITConfig(TIM2,TIM_IT_Update,DISABLE); //更新中断失能

 

    NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;        

    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;     

推荐阅读

史海拾趣

Daito Communication Apparatus Co Ltd公司的发展小趣事

随着微电子学的快速发展,电子设备对元器件的要求也越来越高。Daito公司敏锐地捕捉到了这一市场趋势,决定对保险丝进行进一步的创新。在1995年,他们成功开发出了适用于电路板安装的高精度小型报警保险丝。这一产品的推出,不仅满足了市场对小型化、高精度保险丝的需求,也进一步巩固了Daito公司在电子行业中的领先地位。

随后,Daito公司又针对微电子学的进一步发展,推出了可以连续自动安装的方形微型保险丝。这一产品的推出,大大提高了生产效率,降低了成本,同时也为客户提供了更加便捷的使用体验。近年来,随着面安装技术的兴起,Daito公司又迅速推出了适用于面安装技术的片状保险丝,再次展示了他们在电子行业中的创新实力。

请注意,由于篇幅限制,以上仅为两个故事示例。如果需要更多故事,可以进一步深入研究和探索Daito公司在电子行业中的发展历程和创新实践。

Analog Modules Inc公司的发展小趣事

随着微电子学的快速发展,电子设备对元器件的要求也越来越高。Daito公司敏锐地捕捉到了这一市场趋势,决定对保险丝进行进一步的创新。在1995年,他们成功开发出了适用于电路板安装的高精度小型报警保险丝。这一产品的推出,不仅满足了市场对小型化、高精度保险丝的需求,也进一步巩固了Daito公司在电子行业中的领先地位。

随后,Daito公司又针对微电子学的进一步发展,推出了可以连续自动安装的方形微型保险丝。这一产品的推出,大大提高了生产效率,降低了成本,同时也为客户提供了更加便捷的使用体验。近年来,随着面安装技术的兴起,Daito公司又迅速推出了适用于面安装技术的片状保险丝,再次展示了他们在电子行业中的创新实力。

请注意,由于篇幅限制,以上仅为两个故事示例。如果需要更多故事,可以进一步深入研究和探索Daito公司在电子行业中的发展历程和创新实践。

EUCHNER公司的发展小趣事

EUCHNER公司一直将产品创新视为其核心竞争力。公司不断投入研发资源,推出了一系列具有创新性的产品,如安全限位开关CES-CMFS系列、机械式安全开关MGB系列以及多光束安全栅ESPE系列等。这些产品在汽车制造、轨道交通、环保监测等领域得到了广泛应用,并赢得了客户的广泛赞誉。通过产品创新和市场拓展,EUCHNER公司的市场份额逐年提升。

CYMBET公司的发展小趣事

CYMBET公司成立于2000年,专注于微电子系统固态储能解决方案的研发与生产。在早期,公司就凭借其创新技术——可充电固态电池芯片(EnerChip)在行业中崭露头角。这种电池芯片使用标准半导体集成电路工艺和独特的构造技术,提供了环保、生物相容的嵌入式电源功能。EnerChip的推出不仅打破了传统电池的局限,还为医疗、传感器、RFID、工业控制等领域带来了革命性的变化。

Digitron公司的发展小趣事

Digitron公司始终将创新作为企业发展的核心驱动力。公司投入大量资金用于研发新技术和新产品,不断提升产品的性能和功能。XXXX年,Digitron公司成功研发出一款具有无线传输功能的数据记录器,用户可以通过手机或电脑实时查看和监控数据。这一创新产品受到了市场的热烈欢迎,为Digitron公司带来了显著的增长。

Antelec公司的发展小趣事

随着技术的不断成熟和产品的不断完善,Antelec公司开始积极寻求市场拓展。公司通过与国内外知名企业和研究机构建立合作关系,将产品成功应用于多个领域,如通信、半导体制造和航空航天等。同时,公司还积极参加各类行业展会和论坛,加强了与行业内外的交流与合作。

问答坊 | AI 解惑

i2c总线问题——起始停止条件

大家好,现在学习实践I2C总线方面的知识。这个过程中遇到的问题还希望能够得到大家的指教,谢谢! 下面这段话摘自“I2C总线规范”, “在SCL线是高电平时SDA线从高电平向低电平切换,这个情况表示起始条件。 在SCL线是高电平时SDA线由低电平向 ...…

查看全部问答>

USB CCID

最近在做usb,ccid部分的东西,每次在读入ccid descriptor的内容后电脑就会自动重启,很费解,有哪位朋友做过类似的东西希望能指点一下! 谢谢!…

查看全部问答>

这里挺好

想学点东西这里挺不错的…

查看全部问答>

VMware+RH9+skyeye1.2 仿真lcd出现segmentation fault

VMware+RH9+skyeye1.2 仿真lcd出现segmentation fault 配置文件内容: cpu: arm720t mach: ep7312 mem_bank: map=M, type=R,  addr=0x0, size=0xC0000 mem_bank: map=M, type=R,  addr=0x000C0000, size=0x00340000, fil ...…

查看全部问答>

PPC2003问题若干

  小弟毕业设计就快完了,搞的是PPC2003软件设计。在开发过程中,现在还留了点问题下来。 一、有没有能够实现将某个文件中所有的EXE文件,文件名及文件路径存入一个表中的操作或是函数; 二、我用的是VS2005自带的仿真上的数据库,没有另外安装 ...…

查看全部问答>

at+cipstart无法用域名的形式访问网络?

我使用sim3000的gprs模块,昨天已经可以用ip地址访问我在花生壳上注册的地址了.然后我尝试用域名的形式访问网络.先 at+cipshut,关闭连接 然后 配置dns服务器 at+cdnscfg=\"202.96.128.56\" 然后设置为域名访问方式at+cdnsorip=1 最后使用域名访 ...…

查看全部问答>

请问EVC能不能用USB口进行下载 在线调试

现在我用的是网口调试,经常出现下了一半就下不下去了 重起一次机器就好了 这样用就太不稳定了 想用USB的方法进行在线调试 但不知道怎么下手 麻烦各位大侠指点指点了 小女子先谢谢了哈…

查看全部问答>

使用51单片机与pc串口通信中数据不一致问题

我用51单片机与pc机进行串口通讯,上位机软件用的是出口调试助手3.0,下位机是我自己编的,主要目的是pc向单片机发个数据,单片机接收后向p2口输出,之后再把接收到的数据发给pc。但是我发现pc上发出与收到的数据总是不一致。例如,我用pc输出字符 ...…

查看全部问答>

2440中断按键检测

最近在学linux驱动开发,在做中断程序的时候不知道为什么就是进不了中断服务函数,下面贴出源码,希望各位大侠们给点帮助,不胜感激~ //s3c2440_key.c(底层驱动程序) //#include #include #include #include #include //#include # ...…

查看全部问答>

tms320vc5509A做25MHz带宽的软件无线电处理能力够不?

tms320vc5509A做25MHz带宽的软件无线电处理能力够不?以下哪种方式比较好?通过5509的usb接口和外部进行数据通讯,5509自带的adc接音频输入。不知道下面一种通过什么算法可以实现单边带?上面一种好像找不到那么低速的IQ输出的dds。另希望论坛能支 ...…

查看全部问答>