stm32 pwm输出异常及解决过程

发布者:WhisperingWaves最新更新时间:2018-06-29 来源: eefocus关键字:stm32  pwm  输出异常 手机看文章 扫描二维码
随时随地手机看文章

pwm输出是stm32最常用的外设之一,我比较习惯使用库函数配置,我通常移植做过的工程中的程序的配置代码,然后改一改相应的参数,配置方法也十分简单,即使很简单,但对于初学者有时候还是很容易出错。有时候会一点波形没有输出,在找不到其他原因的情况下,这个时候以自己以前的经验来说,配置代码里面有一句GPIO_PinAFConfig(GPIOB,GPIO_PinSource1, GPIO_AF_TIM3);   (以stm32f4 time3 ch4为例)比较容易出错同时被忽略,其中的GPIO_PinSource1很容易稍不注意会写成GPIO_Pin_1这样子会导致引脚复用没有成功,同时输入捕获的配置的时候也有可能导致配置没有成功的情况,然后其中一个比较可能的原因也是这个参数的宏写错,因为这两个宏有点像,以上是我之前遇到的配置pwm或输入捕获的时候由于自己的粗心出现的问题,当时也查了比较久的时间,所以记录下来。


       但前阵子在写一个程序是出现了一个更加奇怪的现象,出现了类似积分电路的波形。改工程程序的描述如下


该工程中需要配置一些外部中断和pwm输出于是写了这两个一下两个函数


LimitSwitchInit();

PWM3_Configuration();//tim3ch4

两个函数的具体定义如下:

void LimitSwitchInit()

{

NVIC_InitTypeDef   NVIC_InitStructure;

EXTI_InitTypeDef   EXTI_InitStructure;

OutGPIOInit(); //外部中断IO初始化

RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);//使能SYSCFG时钟

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource2);//PA2 连接到中断线2

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource5);//PA5 连接到中断线5

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource6);//PA6 连接到中断线6

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource7);//PA7 连接到中断线7

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15);//PB15 连接到中断线15

SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource8);//PA8 连接到中断线8

/* 配置EXTI_Line2 */

EXTI_InitStructure.EXTI_Line = EXTI_Line2|EXTI_Line5|EXTI_Line6|EXTI_Line7|EXTI_Line8|EXTI_Line15;//LINE2,LINE5,LINE6,LINE7,LINE15,

EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;//中断事件

EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;//下降沿触发

EXTI_InitStructure.EXTI_LineCmd = ENABLE;//使能

EXTI_Init(&EXTI_InitStructure);//配置

 

//中断配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI2_IRQn;//外部中断2

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道

NVIC_Init(&NVIC_InitStructure);//配置

//

NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//外部中断7

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道

NVIC_Init(&NVIC_InitStructure);//配置

NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//外部中断7

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道

NVIC_Init(&NVIC_InitStructure);//配置

}

void PWM3_Configuration(void) //TIM3

{

GPIO_InitTypeDef          gpio;

TIM_TimeBaseInitTypeDef   tim;

TIM_OCInitTypeDef         oc;

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB,ENABLE);

RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //TIM1--TIM8使用内部时钟时,由APB2提供

 

gpio.GPIO_Pin = GPIO_Pin_1;

gpio.GPIO_Mode = GPIO_Mode_AF;

gpio.GPIO_Speed = GPIO_Speed_100MHz;

GPIO_Init(GPIOB,&gpio);

 

GPIO_PinAFConfig(GPIOB,GPIO_PinSource1, GPIO_AF_TIM3);      

tim.TIM_Prescaler = 12;

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

tim.TIM_Period = 260;   //25khz 计数周期

tim.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割,不为1的话会乘2

TIM_TimeBaseInit(TIM3,&tim);

oc.TIM_OCMode = TIM_OCMode_PWM2; //选择定时器模式

oc.TIM_OutputState = TIM_OutputState_Enable; //选择输出比较状态

oc.TIM_OutputNState = TIM_OutputState_Disable; //选择互补输出比较状态

oc.TIM_Pulse = 150; //设置待装入捕获比较器的脉冲值

oc.TIM_OCPolarity = TIM_OCPolarity_Low; //设置输出极性

oc.TIM_OCNPolarity = TIM_OCPolarity_High; //设置互补输出极性

oc.TIM_OCIdleState = TIM_OCIdleState_Reset; //选择空闲状态下的非工作状态

oc.TIM_OCNIdleState = TIM_OCIdleState_Set; //选择互补空闲状态下的非工作状态

TIM_OC4Init(TIM3,&oc); //通道4

TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);

TIM_Cmd(TIM3,ENABLE);

NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;

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

NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级0

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能

NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器、

}

运行程序之后的波形:


5.仿真调试


发现波形输出不是标准的方波,有点像是积分的波形,于是开始找原因,然后无意之间调换了LimitSwitchInit(); PWM3_Configuration();//tim3ch4这两个配置函数的位置即:


PWM3_Configuration();//tim3ch4

LimitSwitchInit();

结果输出波形就变得很正常:




于是很自然变想到了是第一个配置的外部中断影响到了正常的pwm输出,于是在这个方向上找了好久的原因,但是始终找不到外部中断有什么问题,同时外部中断的功能也很正常,而且还有一个很奇怪的问题,就是如果外部中断的配置影响了pwm的外设,那么应该是外部中断放在pwm后面才会出现问题,因为放在后面的pwm配置应该会覆盖原来的配置,但是实际情况刚好相反,pwm放在后面的时候便会出错,放在前面反而正常。

最后把void PWM3_Configuration(void)//TIM3这个函数的定义里面,配置gpio的gpio这个结构体放到了函数外面,变成一个全局变量,然后再次运行程序然后发现无论两个函数的配置位置是如何的都pwm输出都非常正常,到这里时问题就变得比较清晰了,我们应该知道局部变量和全局变量的区别,首先这两种类型的变量的作用域和生存期不同,局部变量作用域是该函数,生存期时这个函数的运行的时间,即函数返回,内存被回收利用,而全局变量的作用域是整个文件,生存期就是整个程序的运行时间内长期存在,内存不会被回收,其次他们还有另外一个问题就是,当定义一个全局变量的时候,分配的内存会全部清零,即所有的变量的初始值会是0,而当定义一个局部变量时,内存将不会清零。分配到的内存里面是什么数据,便是什么数据,也就说,局部变量不初始化的话,变量的值是很随机的。

回到之前的程序,由于我定义了一个局部变量GPIO_InitTypeDef  gpio;这个结构体,然后这个结构体的数据便是原先内存的数据,里面成员的值是比较随机的,通过打断点观察成员的数据得到

当LimitSwitchInit(); PWM3_Configuration();//tim3ch4这个顺序时GPIO_InitTypeDef  gpio里面的成员数据如左图,调换顺序之后变成右图:


可以发现后面的两个成员的数据改变了,查看原来void PWM3_Configuration(void)//TIM3函数的定义可以知道里面对这个结构体的赋值只有前三个成员而少了后两个成员,然后导致调换程序效果不同的原因是当前一个函数改变了某些内存,然后定义后面函数的局部变量的时候导致回收的内存里面的数据残留,造成了效果不同,至于是哪个变量不同呢,测试得到当补充配置gpio.GPIO_OType = GPIO_OType_PP;(推挽输出)时程序就没问题,当当配置为gpio.GPIO_OType = GPIO_OType_OD;(开漏输出)时便会出现那种异常波形。

以上得到的教训就是在定义了局部变量时,一定要把所有成员初始化一遍,不然会导致很多奇怪而又难以发现的问题,如以上遇到的问题。



关键字:stm32  pwm  输出异常 引用地址:stm32 pwm输出异常及解决过程

上一篇:STM32 自定义频率与占空比PWM输出的方法
下一篇:STM32 PWM简介及呼吸灯实验

推荐阅读最新更新时间:2024-03-16 16:07

用FPGA实现多路PWM输出的接口设计与仿真
  在许多嵌入式系统的实际应用中,需要扩展FP-GA(现场可编程门阵列)模块,将CPU实现有困难或实现效率低的部分用FPGA实现,如数字信号处理、硬件数字滤波器、各种算法等,或者利用FPGA来扩展I/O接口,如实现多路PWM(脉宽调制)输出、实现PCI接口扩展等。通过合理的系统软硬件功能划分,结合优秀高效的FPGA设计,整个嵌入式系统的效率和功能可以得到最大限度的提高。   在电机控制等许多应用场合,需要产生多路频率和脉冲宽度可调的PWM波形。本文用Altera公司FPGA产品开发工具QuartusⅡ,设计了6路PWM输出接口,并下载到FPGA,实现与CPU的协同工作。    1 FPGA概述   PLD(可编程逻辑器件)可
[安防电子]
使用KEIL5进行STM32开发时常见的三个错误
1.用keil5编译提示 warning: #1-D: last line of file ends without a newline最后行回车不管用 最后一行回车后还要保证是在第一列,新的一行不能有空格等空字符才能不出此警告 2.定义头文件时总是在界面上出现类似 X #include led.h ,但编译没有出现错误和警告 打开keil5的option for target -- c/c++ -- Include Paths ,不进行任何操作,直接OK,然后退出 3.使用MDK调试的时候,出现一下错误: error: #268: declaration may not appear after execu
[单片机]
stm32——串口1和串口2初始化
void USART1_Initialise(u32 bound) { //GPIO端口设置 GPIO_InitTypeDef GPIO_InitStructure; USART_InitTypeDef USART_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA|RCC_APB2Periph_AFIO, ENABLE); //USART1_TX PA.9 GPIO_InitStructur
[单片机]
msp430和stm32 dht11驱动程序
最近使用msp430f5529读取dht11的温度和湿度数据,记录下驱动程序,需要可移植。 dht11模块是一块温湿度传感器模块,可以采集温度和湿度信息转化为数据发送出来,模块介绍如下: 概述:DHT11 是广州奥松有限公司生产的一款湿温度一体化的数字传感器。该传感器包括一个电阻式测湿元件和一个 NTC 测温元件,并与一个高性能 8 位单片机相连接。通过单片机等微处理器简单的电路连接就能够实时的采集本地湿度和温度。DHT11 与单片机之间能采用简单的单总线进行通信,仅仅需要一个I/O 口。传感器内部湿度和温度数据 40Bit 的数据一次性传给单片机,数据采用校验和方式进行校验,有效的保证数据传输的准确性。DHT11 功耗很低,
[单片机]
msp430和<font color='red'>stm32</font> dht11驱动程序
STM32的入门总结和学习步骤
一、入门总结 1.1为什么要把时间花在“犹豫”上? 每当我们在入门之前(ARM是这样,DSP也一样),总会有很多疑问,会有很多顾虑。我们渴望知道学习STM32前景如何?需要啥基础?难不难?适不适合我?但是什么时候能心潮澎湃地、相当着急地开始学STM32?日子在一天一天过去!你开始行动了吗?没有行动的思索,永远都不可能入门!把这些时间用来看书吧,效果能好一万倍。 大家可能是从51单片机过来的,回想一下,我们之前学单片机时如何入门呢?实际上都是先看书(理论),再玩板子(实践)。严格地说,应该是模仿实验。熟悉之后才会自己写程序代码实现某个功能。因此,如果你正在咨询STM32;如果你正对STM32心潮澎湃;如果你想入门STM32;
[单片机]
<font color='red'>STM32</font>的入门总结和学习步骤
STM32单片机智能电饭煲系统设计方案
一、功能简介 本项目使用Proteus8.12仿真STM32单片机控制器,使用继电器加热/保温模块、数码管模块、按键模块、LED指示灯、蜂鸣器模块等。 主要功能: 系统运行后,数码管默认不显示,当按下K5键选择功能模式,此时数码管会显示对应模式所需时间,且LED指示灯工作,系统默认有煮饭、煮粥、蒸、煲汤四种功能,还可按下K6键设置预约时间,通过K2和K3键修改时间,当设置好时间后,按下K4键开始,预约时间开始倒计时,当时间达到后,继电器开启加热,在所选功能时间倒计时结束后停止加热,开启保温。若不需要保温,可按下K1键关闭。 主要功能如下: (1)功能:煮饭、煮粥、蒸、煲汤; (2)按键:开始、取消、功能、加减、预约; 二、
[单片机]
<font color='red'>STM32</font>单片机智能电饭煲系统设计方案
STM32 USB学习笔记1
主机环境:Windows 7 SP1 开发环境:MDK5.14 目标板:STM32F103C8T6 开发库:STM32F1Cube库和STM32_USB_Device_Library 之前在STM32论坛里领取过一块STM32开发板,本来以为是带有USB模块接口的,最后发现NUCLEO里是没有把USB模块外接出来的,所以就自个儿掏钱买了一块单板,如下图所示: 单板很简单,单纯是为了学习一下STM32的USB模块,之所以选择这个是因为它便宜,而且ST官方有提供USB模块库方便开发。 USB开发博大精深,比之串口,SPI,I2C来说多了很多东西,一个很简单的例子就是串口,SPI,I2C都可以使用通用IO口
[单片机]
<font color='red'>STM32</font> USB学习笔记1
基于STM32对DS1302的驱动
// 程序名: STM32驱动DS1302 //头文件 #include “stm32f10x.h” #include “usart.h” #define uchar unsigned char #define uint unsigned int ////DS1302引脚定义,可根据实际情况自行修改端口定义 #define RST PAout(5) #define IO PAout(6) #define SCK PAout(7) //DS1302地址定义 #define ds1302_sec_add 0x80 //秒数据地址 #define ds1302_min_add 0x82 //分数据地址 #define ds1302_
[单片机]
小广播
添点儿料...
无论热点新闻、行业分析、技术干货……
设计资源 培训 开发板 精华推荐

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

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

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