stm32 pwm输出异常及解决过程

来源:互联网 发布:哪里有卖校管家软件 编辑:程序博客网 时间:2024/06/05 00:49

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 连接到中断线2SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource5);//PA5 连接到中断线5SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource6);//PA6 连接到中断线6SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOA, EXTI_PinSource7);//PA7 连接到中断线7SYSCFG_EXTILineConfig(EXTI_PortSourceGPIOB, EXTI_PinSource15);//PB15 连接到中断线15SYSCFG_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;//外部中断2NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道NVIC_Init(&NVIC_InitStructure);//配置//NVIC_InitStructure.NVIC_IRQChannel = EXTI9_5_IRQn;//外部中断7NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道NVIC_Init(&NVIC_InitStructure);//配置NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn;//外部中断7NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x01;//子优先级2NVIC_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的话会乘2TIM_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);//通道4TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_Cmd(TIM3,ENABLE);NVIC_InitTypeDef NVIC_InitStructure;NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;//抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority =0;//子优先级0NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能NVIC_Init(&NVIC_InitStructure);//根据指定的参数初始化VIC寄存器、}

运行程序之后的波形:


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

PWM3_Configuration();//tim3ch4LimitSwitchInit();

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



于是很自然变想到了是第一个配置的外部中断影响到了正常的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;(开漏输出)时便会出现那种异常波形。

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


原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 被nlp课程洗脑了怎么办 手上张了个鸡眼怎么办 手上长了个鸡眼怎么办 6岁儿童手指脱皮怎么办 手指骨折后关节僵硬怎么办 手指外伤后关节肿大僵硬怎么办 胳膊骨折了手肿怎么办 耳朵被肘了耳鸣怎么办 耳朵鼓膜外显的怎么办 耳膜破了怎么办为好 耳朵的鼓膜破了怎么办 被打耳鼓膜穿孔怎么办 两只耳朵嗡嗡响怎么办 耳朵长了个脓包怎么办 胸一个大一个小怎么办 把耳朵掏出血了怎么办 掏耳朵戳出血了怎么办 耳朵戳伤流血了怎么办 耳朵挖破出血了怎么办 耳朵让耳屎堵了怎么办 手被牙齿划破了怎么办 耳朵掏伤了很痛怎么办 掏伤耳朵发炎了怎么办 耳朵被掏发炎了怎么办 打的耳洞化脓了怎么办 打了耳洞流脓了怎么办 打了耳洞发炎怎么办 打了耳洞化脓了怎么办 3岁宝宝耳朵流脓怎么办 耳朵里面是湿的怎么办 耳朵里天天很痒怎么办 身上长湿疹很痒怎么办 嗓子干疼耳朵痒怎么办 上火了耳朵嗡嗡响怎么办 太阳凹颧骨外扩怎么办 4岁儿童脊柱侧弯怎么办 瘦的人得多囊怎么办 智齿刚长出来该怎么办 宝宝耳朵睡尖了怎么办 睡觉压的耳朵疼怎么办 月子里奶水越来越少怎么办