文章目录

  • 前言
  • 一、选择正点原子串口实验的工程
  • 二、用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.hstm32f4xx.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混合开发工程