电子说
1.原因源于大家平时对网上大量不规范的例程的拷贝使用
2.比如在配置定时器输出pwm时候,一般网上抄的例程如下:
//4、初始化输出比较模式、配置输出比较模式的结构体参数
TIM_OCStructInit(&TIM_OCInitStruct);//配置输出比较结构体的参数
TIM_OCInitStruct.TIM_Pulse=50; //配置CCR寄存器,控制占空比
TIM_OCInitStruct.TIM_OCMode=TIM_OCMode_PWM1; //配置输出比较模式
TIM_OCInitStruct.TIM_OCPolarity=TIM_OCPolarity_High;//控制输出的极性
TIM_OCInitStruct.TIM_OutputState=TIM_OutputState_Enable;//输出使能
TIM_OC1Init(TIM2,&TIM_OCInitStruct);
这里是有问题的,因为结构体TIM_OCInitStruct的成员不止这几个,如果不写全,那其他几个的值是栈里面的数据,栈数据是之前的函数执行后留下的,这样其他几个没写出来的成员就成了栈污染的受害者了。此时如果就这么初始化了,有时候会出现奇怪的BUG:比如通道关闭后IO仍然维持高电平。
3.正确的做法, 写全所有的结构体成员 :
//初始化TIM8 Channel3 PWM模式
/*
在PWM模式(模式1或模式2)下, TIMx_CNT和TIMx_CCRx始终在进行比较,
(依据计数器的计数方向)以确 定是否符合TIMx_CCRx≤TIMx_CNT或者TIMx_CNT≤TIMx_CCRx。
*/
TIM_OCInitStructure.TIM_OutputNState = TIM_OutputState_Disable; //所有成员初始化,否则数据不确定
TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCPolarity_High; //所有成员初始化,否则数据不确定
TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCIdleState_Set; //所有成员初始化,否则数据不确定
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
// TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性高
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset; //输出空闲状态是互补输出和死区插入那一节里面的知识,这里没影响
TIM_OCInitStructure.TIM_Pulse=0;
TIM_OC1Init(TIM8, &TIM_OCInitStructure); //根据指定的参数初始化外设TIM8 OC3
TIM_OC1PreloadConfig(TIM8, TIM_OCPreload_Enable); //CH1预装载使能,预装载值在更新事件到来时被加载至当前寄存器中
4.辩论:
1)不明写,编译器也会给局部变量赋为0
答:
(1)或许有的编译器会将未幅值的局部变量赋0,但不能保证每个编译器都这么做。总之未幅值其值是不确定的(很容易验证:搞两个函数执行打印一下实测出来)
(2)在单片机程序里面,没写的寄存器不等于就是要赋0,所以即使编译器帮忙赋0了,也是不对的
2)可以用类似stm32单片机库函数中的deinit规避栈污染
答:
deinit只是将寄存器的值恢复到默认,不能清栈数据。
全部0条评论
快来发表一下你的评论吧 !