文章目录
- 前言
- 一、选择正点原子串口实验的工程
- 二、用AC6编译纯C语言代码
- 1.打开魔法棒选择default compiler version6
- 2.编译工程
- 3.更改包含头文件依赖
- 4.修改旧版代码
- 5.重新编译
- 6.烧录程序并查看效果
- 三、用C++编写代码
- 1.选择C++方式编译
- 2.修改代码并编译
- 3.用C++重写printf重定向
- 注意
- 1.AC6工程不要用中文路径
- 2.更换新版本的STD库
- 3.更多AC5转换到AC6的代码对应,可参考下图
- 工程下载链接
前言
一:请先确保keil5的版本为5.30版本以上,笔者这里是5.36版本:
二:F4标准库的pack包本版是2.9.0以上,笔者这里是2.15版本:
上述资源可在https://zhuanlan.zhihu.com/p/262507061找到
提示:本工程创建用例基于正点原子的F407标准库例程
一、选择正点原子串口实验的工程
工程如下图所示:
把工程拷贝一份新工程到纯英文路径下,新工程打开后,点击魔法棒发现编译器默认是ARM Compiler 5版本,此时能够正常编译工程
二、用AC6编译纯C语言代码
1.打开魔法棒选择default compiler version6
2.编译工程
不出意外的话,会有很多的错误:
主要的错误应该是这个,也就是未定义vfpcc:
3.更改包含头文件依赖
这里的解决主要是参考
比如我安装的是在D盘
方法二:删除工程CORE里面的.h文件,
再把\keil_V5\packs\ARM\CMSIS\5.8.0\CMSIS\Core\Include里的文件放到里面
(startup_stm32f40_41xxx.s不用动,因为我观察发现新旧版本的启动文件没有代码的变化,只是注释有变化)
方法三:先把原工程包含文件目录的CORE路径删除
然后点击Mange Run-Time Environment
把CMSIS/CORE打勾
4.修改旧版代码
此时重新编译会发现错误减少了,剩下的错误都是AC6不支持的语法代码了,我们要修改正点原子例程的代码来适配AC6
错误有 #pragma import(__use_no_semihosting) 、__asm void WFI_SET(void)、__FILE,这些都是旧版编译器AC5的特定语法,新版AC6编译器已经不支持了,分别要把原代码报错的部分如下
①
②
修改成如下格式同时兼容AC5和AC6编译器,其中__CC_ARM是AC5编译器定义的标识,GNUC 和__clang__是AC6定义的标识,由此判断编译器版本,这里主要参考了
超级无敌让stm32的printf兼容MDK各种编译器的方法
6.烧录程序并查看效果
把程序烧进板子后可看到MCU已经通过串口发送数据了
三、用C++编写代码
1.选择C++方式编译
之前我们做的只是把工程从AC5编译器更换到AC6,因为要体验完整的现代C++功能必须要升级到ARM Compiler 6,那么接下来我们就要把工程用C++编译了。
先右键main.c文件设置一下属性,选择Options for File ‘main.c’
然后改成C++文件
2.修改代码并编译
此时直接编译会有如下报错:
因为原工程都是按照C语言方式编写代码,所以要添加C语言的兼容性处理如下图所示:
然后重新编译就无报错了。
这里会有一个空循环的warning,虽然目前程序有无影响,但我尝试了更新了标准库版本,但还是有warning,不过既然没影响那就忽略,想了解怎么更换新版本标准库的,可参考下面的注意2.更换新版本的STD库
3.用C++重写printf重定向
按上图所示,此时虽然工程可以正常编译,但一旦在主函数中添加了iostream等库,会报错说__stdout重定义了
这是因为ac6里的BUG,具体原因我也不知道,大概是C++的iostream和stdio有冲突,所以必须要重写重定向函数,具体的解决方法我这里参考了STM32 C++编程系列2.5:让Keil MDK工程支持现代C++特性及填坑
打开Mange Run-Time Environment,进入Compiler->I/O,将里面的STDERR、STDIN、STDOUT勾选上,如下图所示:
然后在usart.c代码里重写半主机模式的重定义函数:
#if 1#ifdef __CC_ARM#pragma import(__use_no_semihosting)struct __FILE { int handle; }; FILE __stdout; //定义_sys_exit()以避免使用半主机模式 void _sys_exit(int x) { x = x; } #elif defined ( __GNUC__ ) || defined (__clang__)//__asm (".global __use_no_semihosting\n\t"); #endif//重定义fputc函数 int fputc(int ch, FILE *f){ while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 USART1->DR = (u8) ch; return ch;}#endif
其实就是把半主机模式删除了,因为官方已经自动添加进官方版本的重定向代码,我们只用保留重定向调用的fputc函数就行了,然后就能成功编译了,烧进板子里面可看到同样的效果。
注意
1.AC6工程不要用中文路径
Arm compiler 6对中文路径支持不够友好,如果工程建立在中文路径下,编译后右键点击Go To Definition of “xxxx”会无法跳转到相应函数的位置,必须要把工程建立在纯英文路径下。
2.更换新版本的STD库
如上面所说,当工程编译通过后会有个空循环的warning,这里我也不知道要不要处理,不知道对工程效果有没有影响
我怀疑是正点原子用的F4 pack包比较旧,以为他们用的是V1.4.0 固件库包的固件包:
现在已经更新到了V1.9.0版本了,所以从官网下载最新固件(可参考STM32标准外设库(标准库)官网下载方法,附带2021最新标准固件库下载链接)后把新版本标准库里面文件覆盖原工程源码里面(具体操作可参考正点原子的STM32F4开发指南-库函数版本_V1.2.pdf里面的3.32节新建模板工程)
我在这里也简单说一下,因为只是替换成新文件,不像新建工程那样麻烦
①STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Project\STM32F4xx_StdPeriph_Templates,把如图的四个文件覆盖到原工程的USER里面
②再进入STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\CMSIS\Device\ST\STM32F4xx\Include里把system_stm32f4xx.h 和stm32f4xx.h覆盖到原工程
③确保这六个文件都覆盖了之后
再进入标准库的STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\STM32F4xx_StdPeriph_Driver文件夹,把新的inc和src文件夹取代原工程的inc和src文件夹,这里建议先把原工程的文件夹里面的内容清空
④此时编译会有一个error
处理方法正点原子的教程里也有说明,先注释main.h头文件,然后再注释TimingDelay_Decrement()函数。
⑤再把PLL 第一级分频系数 M 修改为 8
⑥重新编译(Rebuild)后warning更多了,而且原来的空循环还存在
对此我也不知道为什么,也不知道对程序功能有没有影响,我会放出原工程供大家参考一下,有搞得原由的可评论区说一下
3.更多AC5转换到AC6的代码对应,可参考下图
(来自https://blog.csdn.net/weixin_43644424/article/details/125048889)
工程下载链接
stm32f4标准库C++与C混合开发工程