结构体成员初始化不完整从而受到栈污染导致奇怪bug

电子说

1.3w人已加入

描述

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只是将寄存器的值恢复到默认,不能清栈数据。

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分