STM32呼吸灯的PWM原理与代码实现

面包板社区 2021-08-28 20:06

用定时器生成PWM波

    PWM全称是Pulse Width Modulation,通过控制高频信号的占空比,眼睛当成低通滤波器,可以控制亮暗。再循环更改pwm的阈值,就弄出了呼吸的效果。

    这里采用一个比较简单的方法生成PWM波:设置定时器中断然后根据阈值判断置高和置低。

void TIM3_IRQHandler(void)  {        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);          if(counter==255)                        counter = 0;        else             counter +=1;        if(mode == 0){            if(counter < pwm)                              GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);             else                 GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1);            }        if(mode == 1)        {            if(counter < pwm)                              GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);             else                 GPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);             }          if(mode ==2){            if(counter < pwm)                              GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0);             else                 GPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0);         }}

程序流程

  • 开启外设时钟(GPIO和TIM)

void RCC_Configuration(void)                {     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE);                                                            RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4|RCC_APB1Periph_TIM3, ENABLE); }
  • 配置GPIO

  • 配置时钟, 使能中断(计数阈值,预分频,时钟分频,计数模式)

void tim3()                           //配置TIM3为基本定时器模式 ,约10us触发一次,触发频率约100kHz{TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   //定义格式为TIM_TimeBaseInitTypeDef的结构体的名字为TIM_TimeBaseStructure  TIM_TimeBaseStructure. TIM_Period =9;         //配置计数阈值为9,超过时,自动清零,并触发中断TIM_TimeBaseStructure.TIM_Prescaler =71;     //    时钟预分频值,除以多少TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;  // 时钟分频倍数TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 计数方式为向上计数TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);      //  初始化tim3TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中断标志TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); //  使能TIM3的溢出更新中断TIM_Cmd(TIM3,ENABLE);                     //           使能TIM3}
  • 配置中断优先级

void nvic()                                 //配置中断优先级{     NVIC_InitTypeDef NVIC_InitStructure;  //    //   命名一优先级变量 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);    //     将优先级分组方式配置为group1,有2个抢占(打断)优先级,8个响应优先级 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //该中断为TIM4溢出更新中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//打断优先级为1,在该组中为较低的,0优先级最高 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 响应优先级0,打断优先级一样时,0最高 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;        //  设置使能 NVIC_Init(&NVIC_InitStructure);                        //  初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一个Group NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//    打断优先级为1,与上一个相同,不希望中断相互打断对方 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;     //  响应优先级1,低于上一个,当两个中断同时来时,上一个先执行 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure);}
  • 写中断服务函数

代码实现

    为了方便按键检测,除了TIM3配置PWM波之外,TIM4用来检测是否有输入。由于使用开漏输出,这里使用5V电源。

#include "stm32f10x.h"#include "math.h"#include "stdio.h"
u8 counter=0; int pwm=100;int flag=0;int mode =0;int velocity =0;int turning=1;
void RCC_Configuration(void); //时钟初始化,开启外设时钟void GPIO_Configuration(void); //IO口初始化,配置其功能void tim3(void); //定时器tim4初始化配置void tim4(void); //定时器tim4初始化配置void nvic(void); //中断优先级等配置void exti(void); //外部中断配置void delay_nus(u32); //72M时钟下,约延时usvoid delay_nms(u32); //72M时钟下,约延时msvoid breathing(int velocity){ switch(velocity){ case 0: if(flag) pwm +=1; if(pwm>240) flag=0; if(flag == 0){ pwm -=1; if(pwm<10) flag=1; }                    break; case 1: if(flag) pwm +=2; if(pwm>240) flag=0; if(flag == 0){ pwm -=2; if(pwm<10) flag=1; }                    break; case 2: if(flag) pwm +=3; if(pwm>240) flag=0; if(flag == 0){ pwm -=3; if(pwm<10) flag=1; } break; }}

void assert_failed(uint8_t* file, uint32_t line){ printf("Wrong parameters value: file %s on line %d\r\n", file, line); while(1);}
void TIM4_IRQHandler(void) //TIM4的溢出更新中断响应函数 ,读取按键输入值,根据输入控制pwm波占空比{ u8 key_in1=0x01,key_in2=0x01;        TIM_ClearITPendingBit(TIM4,TIM_IT_Update);//     清空TIM4溢出中断响应函数标志位 key_in1= GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_12); // 读PC12的状态        key_in2= GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_13);// 读PC13的状态        if(key_in1 && key_in2) turning =1;        breathing(velocity); if(key_in1==0 && turning){ turning =0; velocity = (velocity + 1) % 3;    }//调速度 if(key_in2==0 && turning){ turning =0; mode = (mode + 1) % 3; }//调颜色}

void TIM3_IRQHandler(void) // //TIM3的溢出更新中断响应函数,产生pwm波{        TIM_ClearITPendingBit(TIM3,TIM_IT_Update);  //   //  清空TIM3溢出中断响应函数标志位 if(counter==255) //counter 从0到255累加循环计数,每进一次中断,counter加一 counter = 0; else             counter +=1; if(mode == 0){ if(counter < pwm) //当counter值小于pwm值时,将IO口设为高;当counter值大于等于pwm时,将IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); //将PC14 PC15置为高电平 else GPIO_ResetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1); // 将PC14 PC15置为低电平        } if(mode == 1) { if(counter < pwm) //当counter值小于pwm值时,将IO口设为高;当counter值大于等于pwm时,将IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2); //将PC14 PC15置为高电平 else                         GPIO_ResetBits(GPIOA,GPIO_Pin_1|GPIO_Pin_2);     // 将PC14 PC15置为低电平        }   if(mode ==2){ if(counter < pwm) //当counter值小于pwm值时,将IO口设为高;当counter值大于等于pwm时,将IO口置低 GPIO_SetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); //将PC14 PC15置为高电平 else GPIO_ResetBits(GPIOA,GPIO_Pin_2|GPIO_Pin_0); // 将PC14 PC15置为低电平 }}

int main(void){ RCC_Configuration(); GPIO_Configuration(); tim4(); tim3();  nvic();  while(1) {     }   }
void delay_nus(u32 n) //72M时钟下,约延时us{ u8 i; while(n--) { i=7; while(i--); }}

void delay_nms(u32 n) //72M时钟下,约延时ms{ while(n--) delay_nus(1000);}

void RCC_Configuration(void) //使用任何一个外设时,务必开启其相应的时钟{ RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //使能APB2控制外设的时钟,包括GPIOC, 功能复用时钟AFIO等, RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4|RCC_APB1Periph_TIM3, ENABLE); //使能APB1控制外设的时钟,定时器tim3、4,其他外设详见手册 }

void GPIO_Configuration(void) //使用某io口输入输出时,请务必对其初始化配置{ GPIO_InitTypeDef GPIO_InitStructure; //定义格式为GPIO_InitTypeDef的结构体的名字为GPIO_InitStructure                                           //typedef struct { u16 GPIO_Pin; GPIOSpeed_TypeDef GPIO_Speed; GPIOMode_TypeDef GPIO_Mode; } GPIO_InitTypeDef; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置IO口的工作模式为上拉输入(该io口内部外接电阻到电源) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的输出速率为50M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12|GPIO_Pin_13; //配置被选中的管脚,|表示同时被选中    GPIO_Init(GPIOC, &GPIO_InitStructure);                  //初始化GPIOC的相应IO口为上述配置,用于按键检测 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; //配置IO口工作模式为 推挽输出(有较强的输出能力) GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //配置IO口最高的输出速率为50M GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2; //配置被选的管脚,|表示同时被选中 GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA的相应IO口为上述配置 GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); //失能STM32 JTAG烧写功能,只能用SWD模式烧写,解放出PA15和PB中部分IO口}

void tim4() //配置TIM4为基本定时器模式,约10ms触发一次,触发频率约100Hz{    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   //定义格式为TIM_TimeBaseInitTypeDef的结构体的名字为TIM_TimeBaseStructure   TIM_TimeBaseStructure. TIM_Period =9999; // 配置计数阈值为9999,超过时,自动清零,并触发中断    TIM_TimeBaseStructure.TIM_Prescaler =71;         //  时钟预分频值,除以多少 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频倍数    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; // 计数方式为向上计数 TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); // 初始化tim4 TIM_ClearITPendingBit(TIM4,TIM_IT_Update); //清除TIM4溢出中断标志 TIM_ITConfig(TIM4,TIM_IT_Update,ENABLE); // 使能TIM4的溢出更新中断 TIM_Cmd(TIM4,ENABLE); // 使能TIM4}

void tim3() //配置TIM3为基本定时器模式 ,约10us触发一次,触发频率约100kHz{    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;   //定义格式为TIM_TimeBaseInitTypeDef的结构体的名字为TIM_TimeBaseStructure   TIM_TimeBaseStructure. TIM_Period =9; //配置计数阈值为9,超过时,自动清零,并触发中断    TIM_TimeBaseStructure.TIM_Prescaler =71;     //    时钟预分频值,除以多少 TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; // 时钟分频倍数    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  // 计数方式为向上计数 TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); // 初始化tim3 TIM_ClearITPendingBit(TIM3,TIM_IT_Update); //清除TIM3溢出中断标志 TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE); // 使能TIM3的溢出更新中断 TIM_Cmd(TIM3,ENABLE); // 使能TIM3}

void nvic() //配置中断优先级{      NVIC_InitTypeDef NVIC_InitStructure;  //    //   命名一优先级变量 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); // 将优先级分组方式配置为group1,有2个抢占(打断)优先级,8个响应优先级 NVIC_InitStructure.NVIC_IRQChannel = TIM4_IRQn; //该中断为TIM4溢出更新中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;//打断优先级为1,在该组中为较低的,0优先级最高 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 响应优先级0,打断优先级一样时,0最高 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // 设置使能     NVIC_Init(&NVIC_InitStructure);                        //  初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //要用同一个Group NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 溢出更新中断 NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;// 打断优先级为1,与上一个相同,不希望中断相互打断对方 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; // 响应优先级1,低于上一个,当两个中断同时来时,上一个先执行 NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;     NVIC_Init(&NVIC_InitStructure);}


免费开发工具申请


更多精彩干货,点击下方关注查看



关注『面包板社区』,后台回复"关键词"领取300 G学习资料包如:电源、电机、嵌入式、信号系统、模电、华为、电子学、电路、c语言...)



#推荐阅读#

  • 美国工程师拆解中国制造LED灯泡:EMI做得不错

  • 讲解的真的很牛逼!一分钟视频告诉你开关电源原理

  • 常见内部总线介绍:IIC、IIS、SPI、UART、JTAG、CAN、SDIO、GPIO

  • 电子工程师常用的42款工具,你最爱用哪一个?

  • MOS管驱动电路设计,如何让MOS管快速开启和关闭?

  • 施耐德PLC内部拆解,看起来相当过瘾!

  • 电感工作原理动画视频

  • 保护电路的TVS管为什么经常损坏

  • 超详细USB Type-C引脚信号及PCB布局布线介绍


点击阅读原文,下载《STM32Cube学习笔记 (十六篇全)》

面包板社区 面包板社区——中国第一电子人社交平台 面包板社区是Aspencore旗下媒体,整合了电子工程专辑、电子技术设计、国际电子商情丰富资源。社区包括论坛、博客、问答,拥有超过250万注册用户,加入面包板社区,从菜鸟变大神,打造您的电子人脉社交圈!
评论
  • 1月7日-10日,2025年国际消费电子产品展览会(CES 2025)盛大举行,广和通发布Fibocom AI Stack,赋智千行百业端侧应用。Fibocom AI Stack提供集高性能模组、AI工具链、高性能推理引擎、海量模型、支持与服务一体化的端侧AI解决方案,帮助智能设备快速实现AI能力商用。为适应不同端侧场景的应用,AI Stack具备海量端侧AI模型及行业端侧模型,基于不同等级算力的芯片平台或模组,Fibocom AI Stack可将TensorFlow、PyTorch、ONNX、
    物吾悟小通 2025-01-08 18:17 73浏览
  • 根据环洋市场咨询(Global Info Research)项目团队最新调研,预计2030年全球中空长航时无人机产值达到9009百万美元,2024-2030年期间年复合增长率CAGR为8.0%。 环洋市场咨询机构出版了的【全球中空长航时无人机行业总体规模、主要厂商及IPO上市调研报告,2025-2031】研究全球中空长航时无人机总体规模,包括产量、产值、消费量、主要生产地区、主要生产商及市场份额,同时分析中空长航时无人机市场主要驱动因素、阻碍因素、市场机遇、挑战、新产品发布等。报告从中空长航时
    GIRtina 2025-01-09 10:35 77浏览
  • 在智能网联汽车中,各种通信技术如2G/3G/4G/5G、GNSS(全球导航卫星系统)、V2X(车联网通信)等在行业内被广泛使用。这些技术让汽车能够实现紧急呼叫、在线娱乐、导航等多种功能。EMC测试就是为了确保在复杂电磁环境下,汽车的通信系统仍然可以正常工作,保护驾乘者的安全。参考《QCT-基于LTE-V2X直连通信的车载信息交互系统技术要求及试验方法-1》标准10.5电磁兼容试验方法,下面将会从整车功能层面为大家解读V2X整车电磁兼容试验的过程。测试过程揭秘1. 设备准备为了进行电磁兼容试验,技
    北汇信息 2025-01-09 11:24 82浏览
  • 光伏逆变器是一种高效的能量转换设备,它能够将光伏太阳能板(PV)产生的不稳定的直流电压转换成与市电频率同步的交流电。这种转换后的电能不仅可以回馈至商用输电网络,还能供独立电网系统使用。光伏逆变器在商业光伏储能电站和家庭独立储能系统等应用领域中得到了广泛的应用。光耦合器,以其高速信号传输、出色的共模抑制比以及单向信号传输和光电隔离的特性,在光伏逆变器中扮演着至关重要的角色。它确保了系统的安全隔离、干扰的有效隔离以及通信信号的精准传输。光耦合器的使用不仅提高了系统的稳定性和安全性,而且由于其低功耗的
    晶台光耦 2025-01-09 09:58 63浏览
  • 在过去十年中,自动驾驶和高级驾驶辅助系统(AD/ADAS)软件与硬件的快速发展对多传感器数据采集的设计需求提出了更高的要求。然而,目前仍缺乏能够高质量集成多传感器数据采集的解决方案。康谋ADTF正是应运而生,它提供了一个广受认可和广泛引用的软件框架,包含模块化的标准化应用程序和工具,旨在为ADAS功能的开发提供一站式体验。一、ADTF的关键之处!无论是奥迪、大众、宝马还是梅赛德斯-奔驰:他们都依赖我们不断发展的ADTF来开发智能驾驶辅助解决方案,直至实现自动驾驶的目标。从新功能的最初构思到批量生
    康谋 2025-01-09 10:04 75浏览
  • 一个真正的质量工程师(QE)必须将一件产品设计的“意图”与系统的可制造性、可服务性以及资源在现实中实现设计和产品的能力结合起来。所以,可以说,这确实是一种工程学科。我们常开玩笑说,质量工程师是工程领域里的「侦探」、「警察」或「律师」,守护神是"墨菲”,信奉的哲学就是「墨菲定律」。(注:墨菲定律是一种启发性原则,常被表述为:任何可能出错的事情最终都会出错。)做质量工程师的,有时会不受欢迎,也会被忽视,甚至可能遭遇主动或被动的阻碍,而一旦出了问题,责任往往就落在质量工程师的头上。虽然质量工程师并不负
    优思学院 2025-01-09 11:48 98浏览
  •  在全球能源结构加速向清洁、可再生方向转型的今天,风力发电作为一种绿色能源,已成为各国新能源发展的重要组成部分。然而,风力发电系统在复杂的环境中长时间运行,对系统的安全性、稳定性和抗干扰能力提出了极高要求。光耦(光电耦合器)作为一种电气隔离与信号传输器件,凭借其优秀的隔离保护性能和信号传输能力,已成为风力发电系统中不可或缺的关键组件。 风力发电系统对隔离与控制的需求风力发电系统中,包括发电机、变流器、变压器和控制系统等多个部分,通常工作在高压、大功率的环境中。光耦在这里扮演了
    晶台光耦 2025-01-08 16:03 87浏览
  • HDMI 2.2 规格将至,开启视听新境界2025年1月6日,HDMI Forum, Inc. 宣布即将发布HDMI规范2.2版本。新HDMI规范为规模庞大的 HDMI 生态系统带来更多选择,为创建、分发和体验理想的终端用户效果提供更先进的解决方案。新技术为电视、电影和游戏工作室等内容制作商在当前和未来提供更高质量的选择,同时实现多种分发平台。96Gbps的更高带宽和新一代 HDMI 固定比率速率传输(Fixed Rate Link)技术为各种设备应用提供更优质的音频和视频。终端用户显示器能以最
    百佳泰测试实验室 2025-01-09 17:33 92浏览
  • 在当前人工智能(AI)与物联网(IoT)的快速发展趋势下,各行各业的数字转型与自动化进程正以惊人的速度持续进行。如今企业在设计与营运技术系统时所面临的挑战不仅是技术本身,更包含硬件设施、第三方软件及配件等复杂的外部因素。然而这些系统往往讲究更精密的设计与高稳定性,哪怕是任何一个小小的问题,都可能对整体业务运作造成严重影响。 POS应用环境与客户需求以本次分享的客户个案为例,该客户是一家全球领先的信息技术服务与数字解决方案提供商,遭遇到一个由他们所开发的POS机(Point of Sal
    百佳泰测试实验室 2025-01-09 17:35 82浏览
  • 职场是人生的重要战场,既是谋生之地,也是实现个人价值的平台。然而,有些思维方式却会悄无声息地拖住你的后腿,让你原地踏步甚至退步。今天,我们就来聊聊职场中最忌讳的五种思维方式,看看自己有没有中招。1. 固步自封的思维在职场中,最可怕的事情莫过于自满于现状,拒绝学习和改变。世界在不断变化,行业的趋势、技术的革新都在要求我们与时俱进。如果你总觉得自己的方法最优,或者害怕尝试新事物,那就很容易被淘汰。与其等待机会找上门,不如主动出击,保持学习和探索的心态。加入优思学院,可以帮助你快速提升自己,与行业前沿
    优思学院 2025-01-09 15:48 72浏览
  • 故障现象一辆2017款东风风神AX7车,搭载DFMA14T发动机,累计行驶里程约为13.7万km。该车冷起动后怠速运转正常,热机后怠速运转不稳,组合仪表上的发动机转速表指针上下轻微抖动。 故障诊断 用故障检测仪检测,发动机控制单元中无故障代码存储;读取发动机数据流,发现进气歧管绝对压力波动明显,有时能达到69 kPa,明显偏高,推断可能的原因有:进气系统漏气;进气歧管绝对压力传感器信号失真;发动机机械故障。首先从节气门处打烟雾,没有发现进气管周围有漏气的地方;接着拔下进气管上的两个真空
    虹科Pico汽车示波器 2025-01-08 16:51 111浏览
我要评论
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦