ST MCU Finder
安装免费手机应用,
寻找理想的ST MCU

[STM32 H7] STM32H7 IAR函数形参影响程序功能 奇怪问题

[复制链接]
1232|39
 楼主 | 2019-12-5 17:07 | 显示全部楼层 |阅读模式
本帖最后由 FAQ 于 2019-12-5 17:46 编辑
  1. void IO_Config(void)
  2. {
  3.   GPIO_InitTypeDef  gpio_initstruct;
  4.   gpio_initstruct.Pin = GPIO_PIN_3;
  5.   gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
  6.   gpio_initstruct.Pull = GPIO_PULLUP;
  7.   gpio_initstruct.Speed = GPIO_SPEED_MEDIUM;
  8.   HAL_GPIO_Init(GPIOA, &gpio_initstruct);
  9.   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
  10. }
复制代码


  1. void IO_Config(uint8 i)
  2. {
  3.   GPIO_InitTypeDef  gpio_initstruct;
  4.   gpio_initstruct.Pin = GPIO_PIN_3;
  5.   gpio_initstruct.Mode = GPIO_MODE_OUTPUT_PP;
  6.   gpio_initstruct.Pull = GPIO_PULLUP;
  7.   gpio_initstruct.Speed = GPIO_SPEED_MEDIUM;
  8.   HAL_GPIO_Init(GPIOA, &gpio_initstruct);
  9.   HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3, GPIO_PIN_SET);
  10. }
复制代码


敲代码这么多年第一次遇到这个奇怪问题,上面的函数是初始化IO口为普通IO口,并且后续程序可以确定没有第二个地方引用或干扰这个IO,上面两个函数函数的区别是一个不带形参,一个带形参。

为什么不带形参的这个函数会影响到后面程序的功能,导致程序异常,反而这个带多余形参的函数却不会影响到后续程序功能,这个是什么情况。


芯片是STM32H750   IAR编译器






使用特权

评论回复

评论

FAQ 2019-12-5 18:02 回复TA
@mintspring :是啊,的确是多余的形参,的确啥也没干,后续功能就好了,反到如果没有这个形参会导致后续程序功能运行不正常。原本我的程序设计的意图是不需要形参的,但是调试过程中发现异常,无意间发现加个形参,并且这个形参地区啥也没干就后续程序功能就好了。汗颜。敲代码好几年了第一次遇到这种情况。汗颜死了。 
mintspring 2019-12-5 17:50 回复TA
带参数的那个没看到参数干啥了啊。? 
| 2019-12-5 17:23 | 显示全部楼层
贴的不科学,你怎么把格式符号贴来了,要选择无格式。。

使用特权

评论回复

评论

FAQ 2019-12-5 17:47 回复TA
奥,操作不熟悉,我给弄过来了 
| 2019-12-5 17:24 | 显示全部楼层
不带形参是引入了地址,直接对原来的那个变量或寄存器修改了。

使用特权

评论回复
| 2019-12-5 17:24 | 显示全部楼层
实参(argument):
  全称为"实际参数"是在调用时传递给函数的参数. 实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形参。 因此应预先用赋值,输入等办法使实参获得确定值。      

形参(parameter):
全称为"形式参数" 由于它不是实际存在变量,所以又称虚拟变量。是在定义函数名和函数体的时候使用的参数,目的是用来接收调用该函数时传入的参数.在调用函数时,实参将赋值给形参。因而,必须注意实参的个数,类型应与形参一一对应,并且实参必须要有确定的值。

形式参数:形参是函数被调用时用于接收实参值的变量。

根据实际需要可有可无。没有形参时,圆括号也不可省;多个参数之间应用逗号分隔。参数包括参数名和参数类型。

形参的类型说明可有如下两种格式:

  int max(int  a,int b)/*形参的类型在形参表中直接说明*/

    {  return (a>b?a:b);}     



   int max(a,b)

   inta,b;         /*形参的类型在函数体前、函数名后说明*/

   { return(a>b?a:b); }

前者为标准格式,后者为传统格式,通常用前者。



形参和实参的区别

形参出现在函数定义中,在整个函数体内都可以使用, 离开该函数则不能使用。

实参出现在主调函数中,进入被调函数后,实参变量也不能使用。

形参和实参的功能是作数据传送。发生函数调用时, 主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。

1.形参变量只有在被调用时才分配内存单元,在调用结束时, 即刻释放所分配的内存单元。因此,形参只有在函数内部有效。 函数调用结束返回

主调函数后则不能再使用该形参变量。

2.实参可以是常量、变量、表达式、函数等, 无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值, 以便把这些值传送给形

参。 因此应预先用赋值,输入等办法使实参获得确定值。

3.实参和形参在数量上,类型上,顺序上应严格一致, 否则会发生“类型不匹配”的错误。

4.函数调用中发生的数据传送是单向的。 即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值

发生改变,而实参中的值不会变化。

5.当形参和实参不是指针类型时,在该函数运行时,形参和实参是不同的变量,他们在内存中位于不同的位置,形参将实参的内容复制一份,在该

函数运行结束的时候形参被释放,而实参内容不会改变。

而如果函数的参数是指针类型变量,在调用该函数的过程中,传给函数的是实参的地址,在函数体内部使用的也是实参的地址,即使用的就是实参

本身。所以在函数体内部可以改变实参的值。

使用特权

评论回复
| 2019-12-5 17:51 | 显示全部楼层
看明白楼主意思了,如果函数参数没有被使用,会报错或警告的,楼主发现这个警告了吗

使用特权

评论回复
 楼主 | 2019-12-5 17:56 | 显示全部楼层
本帖最后由 FAQ 于 2019-12-5 17:57 编辑
mintspring 发表于 2019-12-5 17:51
看明白楼主意思了,如果函数参数没有被使用,会报错或警告的,楼主发现这个警告了吗 ...

这个问题的奇怪点在于:原本我设计的程序这个函数是不带形参的,但是我发现会影响到后续程序功能,再反复调试定位过程中,我无意间发现如果给这个函数添加一个形参,并且这个形参只是添加一个定义,后续并没有赋值或者引用,就这样后续程序功能居然好了。


好奇怪。

使用特权

评论回复
 楼主 | 2019-12-5 18:22 | 显示全部楼层
这个是汇编代码对比。

左边不带形参,右边带形参。

看得不是很懂,感觉好像是堆栈R寄存器出错了,另外我程序工程也没有开优化。

20191205181955.png


使用特权

评论回复
| 2019-12-5 19:06 | 显示全部楼层
楼主,这样试试,不把这个定义成一个函数,定义成一个宏,那些大括号里的用前面函数名当做宏。
这样就好比直接在程序里,写了那几行代码,而不是调用子函数,试试这样。

使用特权

评论回复
| 2019-12-5 19:07 | 显示全部楼层
752305de8e4f20b2d4.png
我看官方例子都是没有用子函数包含起来,而是直接用的。

使用特权

评论回复
| 2019-12-5 19:08 | 显示全部楼层
楼主也试试这个方法,去掉这个子函数调用,看看是不是也会变好。

使用特权

评论回复
| 2019-12-5 19:11 | 显示全部楼层
823915de8e5b2a316e.png
类似这种,你先把变量定义到程序外,然后在里面直接用,不要用子函数。。

使用特权

评论回复
 楼主 | 2019-12-5 19:21 | 显示全部楼层
mintspring 发表于 2019-12-5 19:07
我看官方例子都是没有用子函数包含起来,而是直接用的。

你发的这个应该是官方例子里的GPIO的例子吧,官方的GPIO例子是为了直观说明GPIO怎么初始化配置,所以才没有搞子函数调用,直接将初始化代码写在主函数里。如果是其它例子就不会这样把IO初始化配置代码直接写到主函数里。


我实测过,我这个程序照样不行。
也就是说无论是把子函数的内容直接写到主函数里,还是写成没有形参的的子函数然后再被主函数调用,都不行,必须写成带有形参,然后再被主函数调用才不会影响后续程序运行的结果。

我后续的程序是LCD屏幕刷屏。我看了这些资源无论软件还是硬件都不存在冲突和干扰。

现在情况是,异常了之后屏幕就不能显示了。

使用特权

评论回复
 楼主 | 2019-12-5 19:25 | 显示全部楼层
mintspring 发表于 2019-12-5 19:06
楼主,这样试试,不把这个定义成一个函数,定义成一个宏,那些大括号里的用前面函数名当做宏。
这样就好比 ...

你说的这些道理我都懂,我也验证过,都不行。

我自认为我也是老司机了,搞了好几年软硬件了,第一次遇到这么奇葩的问题,

我的直观感受是STM32H7 这种单片机好像陷阱很多一样,相比以前的F1单片机总觉得奇奇怪怪的感觉。

使用特权

评论回复
 楼主 | 2019-12-5 19:33 | 显示全部楼层
mintspring 发表于 2019-12-5 19:11
类似这种,你先把变量定义到程序外,然后在里面直接用,不要用子函数。。
...

不行哦,这种,我理解你意思,这个道理是全局变量保存在静态存储区会被默认初始化成固定值,生命周期长,直到整个程序结束,而局部变量在堆栈上好像,每次的值可能会不确定,这个道理我懂得。



这次遇到的这个问题感觉很典型,我感觉咱们俩沟通不出来结果。
如果后面能解决绝对受益匪浅。我再研究研究。

我连IAR的版本都换过,因为我担心我刚下载的IAR最新版有bug,但实际我换了老版本的一样情况。用了好几年IAR了还没发现一个BUG。



使用特权

评论回复
| 2019-12-5 19:47 | 显示全部楼层
听你这么讲,我也是觉得很奇怪,之前没遇到过类似情况。期待楼主研究出来是哪儿的问题。因为是H7比较新,会不会是编译器对于这个有BUG。。。

使用特权

评论回复
 楼主 | 2019-12-5 19:55 | 显示全部楼层
mintspring 发表于 2019-12-5 19:47
听你这么讲,我也是觉得很奇怪,之前没遇到过类似情况。期待楼主研究出来是哪儿的问题。因为是H7比较新,会 ...

最右边这个是最IAR官网最新的,我昨天下载的。和之前老版本做对比一样结果。所以应该不是IAR版本问题。
我还专门看了IAR里的设置,发现也是一样的。





QQ截图20191205195100.jpg



另外官网最新的ST-LINK Utility好像也有问题,就是能连接H7芯片但却不能连接F0的的芯片,必须用老的版本的ST-LINK Utility才能连接F0芯片,我把STLINK V2固件和电脑驱动也都切换过,感觉这个ST-LINK Utility也不让人省心啊。

20191205195433.png

1111.png

使用特权

评论回复
| 2019-12-6 15:17 | 显示全部楼层
编译器没有报错?

使用特权

评论回复
 楼主 | 2019-12-6 15:21 | 显示全部楼层
steelen 发表于 2019-12-6 15:17
编译器没有报错?

这两种写法都不算错误,所以没有报错。

使用特权

评论回复
| 2019-12-6 15:23 | 显示全部楼层
2个函数是一起用的?还是单独用的
IAR的优化有时候不靠谱的

使用特权

评论回复

评论

steelen 2019-12-6 15:25 回复TA
还有就是CACHE打开没有? 打开了也是一堆堆的问题 
 楼主 | 2019-12-6 15:28 | 显示全部楼层
steelen 发表于 2019-12-6 15:23
2个函数是一起用的?还是单独用的
IAR的优化有时候不靠谱的

两个函数独立测试,测试其中一个的时候会把另一个完全注释掉。

另外我写程序的习惯,在程序开始写的起初就会先把优化等级设置到不优化。以免后续遇到莫名其妙的问题。所以这个不是IAR优化设置问题。



使用特权

评论回复
扫描二维码,随时随地手机跟帖
您需要登录后才可以回帖 登录 | 注册

本版积分规则

我要发帖 投诉建议 创建版块 申请版主

快速回复

您需要登录后才可以回帖
登录 | 注册
高级模式

论坛热帖

在线客服 快速回复 返回顶部 返回列表