嵌入式STM32学习笔记(3)——pwm波及呼吸灯

发布者:BlossomSunrise最新更新时间:2020-06-16 来源: eefocus关键字:STM32  pwm波  呼吸灯 手机看文章 扫描二维码
随时随地手机看文章

写pwm波函数可以调用stm32固件库函数直接生成,也可以通过中断来写pwm波;下面就介绍这两种方法,这里先说一下呼吸灯,其原理就是让LED灯由暗变亮再由亮变暗循环,类似呼吸的效果,亮-暗是一个大周期,而LED灯亮或暗是由其刷新的占空比决定,高电平时间占比长则亮,反之则暗;


stm32 的定时器除了 TIM6 和 7。其他的定时器都可以用来产生 PWM 输出。其中高级定时器 TIM1 和 TIM8 可以同时产生多达 7 路的 PWM 输出。而通用定时器也能同时产生多达4路的 PWM 输出,这样, STM32 最多可以同时产生 30 路 PWM 输出。关于映射及原理大家可查手册吧,这里不做具体叙述了;个人见解:很多知识用到再仔细研究是节省精力的好办法,工程实验做多了,就会发现有些细微的知识可能一直都不需要了解。


补充一下关于stm32 TIMx的管脚映射,每个定时器的通道都有特定的引脚,其可以通过如下两个函数映射跟换引脚:


GPIO_PinRemapConfig(GPIO_PartialRemap_TIMx, ENABLE);  //重映射引脚

GPIO_PinRemapConfig(GPIO_FullRemap_TIMx, ENABLE);     //完全重映

但可更换的引脚也是固定的,具体如下表:

下面代码包含软件版本pwm波和固件库函数pwm波,具体如下:


1.编译器IAR8,系统win10;


2.板子:STM32F103C8T6核心板,如下:

3.下载器:ST-LINK/V2仿真下载器;


4.板子上LED对应的引脚是GPIOC, GPIO_Pin_13;在IAR对应的stm32F103X模板DRIVER目录下添加:led.c,led.h,timer.c,timer.h文件,如下:

5.led.c 代码如下:


#include "led.h"

 

/*LED_G 驱动 GPIO 初始化函数*/

void led_gpio_config(void)

{

  GPIO_InitTypeDef GPIO_InitStructure; //调用GPIO结构体

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //配置RCC时钟,使得引脚使能

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; //设置的引脚

  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //设置引脚速度

  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //设置引脚模式,推挽式输出

  GPIO_Init(GPIOC, &GPIO_InitStructure); //初始化引脚

}

6.led.h的代码:


#ifndef _LED_H

#define _LED_H

 

/*包含相关的头文件*/

#include "stm32f10x.h"

#include "stm32f10x_gpio.h"

#include "stm32f10x_rcc.h"

void led_gpio_config(void);//声明,初始化LED对应引脚

 

#endif

7.timer.c代码:


#include "timer.h"

__IO uint32_t TimingDelay; //计数变量,加要加“_IO”,不然会被编译优化

__IO uint32_t TimingDelay2; //计数变量2

 

u8 breath_pwm_high;

u8 breath_pwm_step;

u8 breath_pwm_flag;

u8 breath_circle;

 

/*SystemCoreClock / 1000000  -------   1us*/

/*SystemCoreClock / 100000   -------   10us*/

/*SystemCoreClock / 10000    -------   100us*/

/*SystemCoreClock / 1000     -------   1ms*/

 

 

//////////////////////////

//设置系统滴答中断延时程序//

/////////////////////////

 

void Systick_Init(void)

{

  //装载系统时钟中断计数值,系统时钟累计达到72000时候溢出产生中断

    if (SysTick_Config(72000))

    { 

      /* Capture error */ 

      while (1);

    }

}

 

//延时计数函数,如果不是0,每个系统滴答中断周期自减

void TimingDelay_Decrement(void)

{

    if (TimingDelay != 0x00)

    {

        TimingDelay--;

    }

}

 

//延迟函数,设置为 US

void delay_ms(__IO uint32_t nTime)

{

    TimingDelay = nTime;//自减初始值

    while(TimingDelay != 0);

}

 

//中断事件函数,原函数在stm32f10x_it.c里面,复制到这里后要将原位置里的注释掉,不然报错

void SysTick_Handler(void)

{

    TimingDelay_Decrement();

}

 

//////////////////////////

//设置定时器中断延时程序//

/////////////////////////

 

//配置嵌套中断控制器 NVCI

void tim2_nvic_config(void)

{

    NVIC_InitTypeDef NVIC_Init_Struct; //调用NVCI结构体

    

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0); //设置组优先级

    

    NVIC_Init_Struct.NVIC_IRQChannel = TIM2_IRQn; //设置定时器 2 中断

    NVIC_Init_Struct.NVIC_IRQChannelPreemptionPriority = 0; //设置抢占优先级

    NVIC_Init_Struct.NVIC_IRQChannelSubPriority = 0; //设置子优先级

    NVIC_Init_Struct.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断

    NVIC_Init(&NVIC_Init_Struct); //初始化NVIC

}

 

 

//定时器初始化配置

void tim2_config(void)

{

    TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct; //调用定时器结构体

    

    tim2_nvic_config(); //加载嵌套中断控制器 NVCI

    

    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE); //配置RCC时钟,使得中断使能

    TIM_DeInit(TIM2); //将外设 TIMx 寄存器重设为缺省值,复位寄存器

    

    /*

定时计数计算方法如下:

发生中断时间 = (TIM_Prescaler+1)* (TIM_Period+1)/FLK

以定时 1s 为例 TIM_Period=2000-1, TIM_Prescaler=(36000-1)

         FLK=72M

    */   

    

    //设置36*10/72000000=0.000005s=5us

    TIM_TimeBaseInitStruct.TIM_Prescaler = 36-1; //时钟预先分频数

    TIM_TimeBaseInitStruct.TIM_Period = 10-1;  //自动重装载寄存器的值

    TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数模式,向上计数方式

    TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //采样分频

    TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);    //初始化TIM2配置

    TIM_ClearFlag(TIM2,TIM_FLAG_Update); //清除溢出中断标志

    TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能或者失能指定的 TIM 中断

    TIM_Cmd(TIM2,ENABLE); //开启时钟

}

 

 

 

 

//延时计数函数2,如果不是0,每个系统滴答中断周期自减

void TimingDelay_Decrement2(void)

{

    if (TimingDelay2 != 0x00)

    {

        TimingDelay2--;

    }

}

 

//延迟函数,设置为 US

void delay_us2(__IO uint32_t nTime2)

{

    TimingDelay2 = nTime2;//时钟滴答数

    while(TimingDelay2 != 0);

}

 

//装载初始值,及呼吸循环检测

 void breath_circle_change()

{

    //判断呼吸周期是否到了,上限值代表呼吸周期时间

    if(breath_circle>=80)

    {

        //判断占空比分割点,是否已经超过99%占比

if(breath_pwm_high>99) 

  {

      breath_pwm_flag=1;//添加标记,准备自减

  }

 

//判断占空比分割点,是否小于2%占比

  if(breath_pwm_high<2)

  {

      breath_pwm_flag=0;//添加标记,准备自加

  }

//修改占空比,设置自加或自减,当占比低于2%时候自加,否则自减

  if(breath_pwm_high<100 && breath_pwm_flag==0)

  {

       breath_pwm_high++;

  }

  else

  {

       breath_pwm_high-=2;//快呼慢吸,自减1的话就是1:1呼吸

       //breath_pwm_high--;//快呼慢吸,自减1的话就是1:1呼吸

  }

     

breath_circle=0;//呼吸循环置零,重新装载检测

      }

      

 

}

 

//定时器2,中断事件函数

void TIM2_IRQHandler(void)

{

    if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//固件库函数,判断是否发生TIM2中断

    {

//      TimingDelay_Decrement2(); //调用延时计数函数

      

      //呼吸分割步长step  

      breath_pwm_step++;   

      //设置步长小于分割点时候点亮灯

      if(breath_pwm_step      {

        GPIO_SetBits(GPIOC, GPIO_Pin_13);    //将PB13设置成高电平

      }

      //设置分割点后,熄灭灯

      else if(breath_pwm_step<100)

      {      

      GPIO_ResetBits(GPIOC, GPIO_Pin_13);   //将PB13设置成低电平

      }

      else

      {

breath_pwm_step=0;//置0,重新计数

breath_circle++;//计算呼吸循环,调整分割点

 

      }

       

           

      

    }

    TIM_ClearITPendingBit(TIM2,TIM_FLAG_Update);//标志位清除,固件库函数

}

 

 

 

//////////////////////////

////定时器3,通过固件函数产生PWM波

////////////////////////

 

 

//定时器3初始化

void TIM3_Int_Init(u16 arr,u16 psc)

{

   

      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

      

      TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//调用TIM结构体       

      TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载周期值

      TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置预分频值 不分频

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

      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数

      TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIMx

//      TIM_ClearFlag(TIM3,TIM_FLAG_Update); //清除溢出中断标志

      TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //使能或者失能指定的 TIM3 中断

      TIM_Cmd(TIM3,ENABLE); //开启时钟

      

      

      NVIC_InitTypeDef NVIC_InitStructure;//调用NVCI结构体

      NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;  //设置定时器 23中断

      NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;  //设置抢占优先级

      NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;  //设置子优先级

      NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //使能IRQ中断

      NVIC_Init(&NVIC_InitStructure);  //初始化NVIC           

       

}

 

//定时器3,中断事件函数

void TIM3_IRQHandler(void)   

{

if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //固件库函数,判断是否发生TIM3中断 

{

TIM_ClearITPendingBit(TIM3, TIM_IT_Update  );  //清除TIMx 的中断待处理位

// LED1=!LED1;

}

}

 

 

//PWM波初始化函数

void TIM3_PWM_Init(u16 arr,u16 psc)

{   

//全部映射,将TIM3_CH2映射到PB5

//根据STM32中文参考手册2010中第第119页可知:

//当没有重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PA6,PA7,PB0,PB1

//当部分重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PB4,PB5,PB0,PB1

//当完全重映射时,TIM3的四个通道CH1,CH2,CH3,CH4分别对应PC6,PC7,PC8,PC9

    

        //1.开启时钟,配置引脚复用形式,产生PWM波

GPIO_InitTypeDef  GPIO_InitStructure;//GPIO结构体

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //时钟使能

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA

      |RCC_APB2Periph_GPIOB

      |RCC_APB2Periph_GPIOC

      |RCC_APB2Periph_AFIO, ENABLE);//使能GPIO外设及ADIO

// GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //   重映射引脚,TIM3_CH2->PB5   

// GPIO_PinRemapConfig(GPIO_FullRemap_TIM3, ENABLE);//完全重映

// GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4|GPIO_Pin_5; //TIM_CH1和TIM_CH2,重映射引脚后

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_7; //TIM_CH1和TIM_CH2

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

GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIO

// GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO化G

  

//2.设置通用定时器,分频及初始化

TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//调用TIM结构体          

TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载周期值

[1] [2]
关键字:STM32  pwm波  呼吸灯 引用地址:嵌入式STM32学习笔记(3)——pwm波及呼吸灯

上一篇:STM32通用定时器TIM实现PWM波配置步骤
下一篇:STM32定时器控制led灯亮灭

推荐阅读最新更新时间:2024-11-12 14:20

基于W5500+STM32的SNMP协议应用
概述 工具: PC W5500EVB Net-SNMP软件包编译环境:Keil4 &IAR功能:通过网络管理协议SNMP及基本的控制命令实现简单的LED控制 一、W5500简介 韩国WIZnet公司生产的以太网控制芯片W5500整合了五层结构中的前四层,即物理层、数据链路层、网络层和传输层,并在内部利用硬件实现了TCP/IP协议栈。开发者无需专业的网络知识,使用W5500如同控制外部存储器一样简单,为用户提供了最简单的网络接入方法。全硬件TCP/IP协议栈完全独立于主控芯片,可以降低主芯片负载且无需移植繁琐的TCP/IP协议栈,便于产品实现网络化更新。以太网控制芯片W5500具有以下特点: 1、W5500支持硬件TCP/IP
[单片机]
修改STM32库函数中的晶振值
STM32F407的库文件中默认晶振值为25MHz,若外接晶振8MHz,则需修改以下几个地方: 1)修改HSE_VALUE的值 将#define HSE_VALUE ((uint32_t)25) /*! Value of the External oscillator in Hz */ 修改为 #define HSE_VALUE ((uint32_t)8) /*! Value of the External oscillator in Hz */ 2)修改PLL_M的值 将#define PLL_M 25修改为 #define PLL_M 8 3)修改STM32F407工程的Options设置 在Option for t
[单片机]
意法半导体升级STM32软件开发工具套件
通过使最新的STM32 PMSM FOC软件开发套件(SDK)支持STM32Cube开发生态系统,意法半导体进一步简化在STM32* 微控制器上开发先进的高能效电机驱动器的难度。此举为空调、家电、无人机、楼宇自动化、机床、医疗设备、电动车等产品设备工程师研发先进电机驱动带来更多机会,而且无需专门的研发经验。 基于意法半导体上一代永磁同步电机(PMSM)矢量控制(FOC)SDK,5.0 新版固件库结合STM32Cube硬件抽象层(HAL)和底层(LL)架构,简化电机驱动电路的开发、定制和调试过程。此外,免费使用源代码让开发人员能够按照市场需求灵活地设计应用方案,加强电机的控制和定制功能。 作为MC-Workbench 5
[半导体设计/制造]
使用STM32定时器输出任意相位差的方波
方法十分简单,不用说明,看图即知(这里画了2路输出,同样道理可以产生3路甚至4路输出)
[单片机]
使用<font color='red'>STM32</font>定时器输出任意相位差的方波
STM32学习002_固件库介绍
STM32利用库函数编程 库函数是STM32生产厂家封装好的函数库,方便用户编程。 USART 库函数 USART库函数包括三种初始化函数,1—缺省值初始化,2—普通初始化,3—结构体类初始化,一般情况下,我们选择第三种初始化方式 第一步:配置使能位(包括波特率,数据位,停止位,校验位) 先定义一个结构体变量:USART_InitTypeDef USART_InitStructure , 然后根据该结构体的相关配置参数,配置实际需要的参数。 USART_InitStructure.USART_BaudRate = 9600; //波特率设置为9600 USART_InitStructure.USART_WordLeng
[单片机]
STM32系列第22篇--I2C
简介: I2C(IIC,Inter-Integrated Circuit),两线式串行总线,由PHILIPS公司开发用于连接微控制器及其外围设备。 它是由数据线SDA和时钟SCL构成的串行总线,可发送和接收数据。在CPU与被控IC之间、IC与IC之间进行双向传送,高速IIC总线一般可达400kbps以上,IIC是半双工通信方式。多主机I2C总线系统结构 需要将SDA和SCL两根线接上拉电阻拉高。 I2C协议: 空闲状态+开始信号+停止信号+应答信号+数据的有效性+数据传输 (1)空闲状态 I2C总线总线的SDA和SCL两条信号线同时处于高电平时,规定为总线的空闲状态。 (2)起始信号与停止信号 起始信号:当SCL为高期间,SDA
[单片机]
<font color='red'>STM32</font>系列第22篇--I2C
stm32使用LWIP实现DHCP客户端
LWIP是一款开源的嵌入式网络协议栈,支持的功能很多,而且能在多任务环境下和单任务裸机环境下跑,今天说说他的移植过程,芯片为STM32,网卡为ENC28J60,无操作系统 首先下载LWIP的源代码,我下载的是1.4.1的源码,下载后解压,文件结构如图 将这四个目录中的文件全部拷贝到工程中,API是一些socket通讯的接口,需要在多任务的环境下实现,core里面存放的内核源码,我们主要使用IPV4,include目录下是需要包含的目录,lwip只要求我们包含include目录,里面的内层目录会自动找到,最后建立的工程目录如下 好了,此时源码已经做好,还有需要做的,在include目录下新建一个文件夹,必须
[单片机]
<font color='red'>stm32</font>使用LWIP实现DHCP客户端
STM32串口中断使用
简介:STM32串口中断使用:配置串口时钟在void Rcc_Configuration(void)函数中实现,配置串口管脚在void UsartGPIO_Configuration(void)中实现;初始化参数设置串口中断配置。 以提高CPU的利用率。在程序中处理流程如下: 一:串口初始化 1.配置串口时钟 在void Rcc_Configuration(void)函数中实现 1.void Rcc_Configuration(void) 1.{ 2. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,ENABLE); 3.
[单片机]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved