前言
一:請(qǐng)先確保keil5的版本為5.30版本以上,筆者這里是5.36版本:
二:F4標(biāo)準(zhǔn)庫(kù)的pack包本版是2.9.0以上,筆者這里是2.15版本:
上述資源可在https://zhuanlan.zhihu.com/p/262507061找到
提示:本工程創(chuàng)建用例基于正點(diǎn)原子的F407標(biāo)準(zhǔn)庫(kù)例程
一、選擇正點(diǎn)原子串口實(shí)驗(yàn)的工程
工程如下圖所示:
把工程拷貝一份新工程到純英文路徑下,新工程打開(kāi)后,點(diǎn)擊魔法棒發(fā)現(xiàn)編譯器默認(rèn)是ARM Compiler 5版本,此時(shí)能夠正常編譯工程
二、用AC6編譯純C語(yǔ)言代碼
1.打開(kāi)魔法棒選擇default compiler version6
2.編譯工程
不出意外的話(huà),會(huì)有很多的錯(cuò)誤:
主要的錯(cuò)誤應(yīng)該是這個(gè),也就是未定義vfpcc:
3.更改包含頭文件依賴(lài)
這里的解決主要是參考AC5編譯器 轉(zhuǎn)換到 AC6 編譯器 錯(cuò)誤 error: unknown register name vfpcc in asm的解決方法
這里有三種方法解決,要么更改頭文件路徑,要么把新版本CMSIS文件放到工程目錄里面,要么是在keil的Mange Run-Time Environment里面選上CMSIS/CORE ,后兩種比較適合工程移動(dòng)到其他PC運(yùn)行。
方法一:把工程頭文件路徑的\Core換成\keil_V5\packs\ARM\CMSIS\5.8.0\CMSIS\Core\Include
比如我安裝的是在D盤(pán)
方法二:刪除工程CORE里面的.h文件,
再把\keil_V5\packs\ARM\CMSIS\5.8.0\CMSIS\Core\Include里的文件放到里面
(startup_stm32f40_41xxx.s不用動(dòng),因?yàn)槲矣^察發(fā)現(xiàn)新舊版本的啟動(dòng)文件沒(méi)有代碼的變化,只是注釋有變化)
方法三:先把原工程包含文件目錄的CORE路徑刪除
然后點(diǎn)擊Mange Run-Time Environment
把CMSIS/CORE打勾
4.修改舊版代碼
此時(shí)重新編譯會(huì)發(fā)現(xiàn)錯(cuò)誤減少了,剩下的錯(cuò)誤都是AC6不支持的語(yǔ)法代碼了,我們要修改正點(diǎn)原子例程的代碼來(lái)適配AC6
錯(cuò)誤有 #pragma import(__use_no_semihosting) 、__asm void WFI_SET(void)、__FILE,這些都是舊版編譯器AC5的特定語(yǔ)法,新版AC6編譯器已經(jīng)不支持了,分別要把原代碼報(bào)錯(cuò)的部分如下
①
②
修改成如下格式同時(shí)兼容AC5和AC6編譯器,其中__CC_ARM是AC5編譯器定義的標(biāo)識(shí),GNUC 和__clang__是AC6定義的標(biāo)識(shí),由此判斷編譯器版本,這里主要參考了
超級(jí)無(wú)敵讓stm32的printf兼容MDK各種編譯器的方法
[keil5]從AC5到AC6的轉(zhuǎn)變
①
#if 1
#ifdef __CC_ARM
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
#elif defined ( __GNUC__ ) || defined (__clang__)
__asm (".global __use_no_semihosting\n\t");
#endif
FILE __stdout;
//定義_sys_exit()以避免使用半主機(jī)模式
void _sys_exit(int x)
{
x = x;
}
//重定義fputc函數(shù)
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循環(huán)發(fā)送,直到發(fā)送完畢
USART1->DR = (u8) ch;
return ch;
}
#endif
②
#ifdef __CC_ARM
__asm void WFI_SET(void)
{
WFI;
}
//關(guān)閉所有中斷(但是不包括fault和NMI中斷)
__asm void INTX_DISABLE(void)
{
CPSID I
BX LR
}
//開(kāi)啟所有中斷
__asm void INTX_ENABLE(void)
{
CPSIE I
BX LR
}
//設(shè)置棧頂?shù)刂?/span>
//addr:棧頂?shù)刂?/span>
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}
#elif defined ( __GNUC__ ) || defined (__clang__)
void WFI_SET(void)
{
__ASM volatile("WFI");
}
//關(guān)閉所有中斷(但是不包括fault和NMI中斷)
void INTX_DISABLE(void)
{
__ASM volatile("CPSID I");
__ASM volatile("BX LR");
}
//開(kāi)啟所有中斷
void INTX_ENABLE(void)
{
__ASM volatile("CPSIE I");
__ASM volatile("BX LR");
}
//設(shè)置棧頂?shù)刂?/span>
//addr:棧頂?shù)刂?/span>
void MSR_MSP(u32 addr)
{
__ASM volatile("MSR MSP, r0"); //set Main Stack value
__ASM volatile("BX r14");
}
#endif
5.重新編譯
此時(shí)可以看到編譯已經(jīng)通過(guò)了,可以燒到F407探索者板子里看效果了,因?yàn)槲沂诸^上還沒(méi)有板子,就不演示了
6.燒錄程序并查看效果
把程序燒進(jìn)板子后可看到MCU已經(jīng)通過(guò)串口發(fā)送數(shù)據(jù)了
三、用C++編寫(xiě)代碼
1.選擇C++方式編譯
之前我們做的只是把工程從AC5編譯器更換到AC6,因?yàn)橐w驗(yàn)完整的現(xiàn)代C++功能必須要升級(jí)到ARM Compiler 6,那么接下來(lái)我們就要把工程用C++編譯了。
先右鍵main.c文件設(shè)置一下屬性,選擇Options for File ‘main.c’
然后改成C++文件
2.修改代碼并編譯
此時(shí)直接編譯會(huì)有如下報(bào)錯(cuò):
因?yàn)樵こ潭际前凑誄語(yǔ)言方式編寫(xiě)代碼,所以要添加C語(yǔ)言的兼容性處理如下圖所示:
然后重新編譯就無(wú)報(bào)錯(cuò)了。
這里會(huì)有一個(gè)空循環(huán)的warning,雖然目前程序有無(wú)影響,但我嘗試了更新了標(biāo)準(zhǔn)庫(kù)版本,但還是有warning,不過(guò)既然沒(méi)影響那就忽略,想了解怎么更換新版本標(biāo)準(zhǔn)庫(kù)的,可參考下面的注意2.更換新版本的STD庫(kù)
3.用C++重寫(xiě)printf重定向
按上圖所示,此時(shí)雖然工程可以正常編譯,但一旦在主函數(shù)中添加了iostream等庫(kù),會(huì)報(bào)錯(cuò)說(shuō)__stdout重定義了
這是因?yàn)閍c6里的BUG,具體原因我也不知道,大概是C++的iostream和stdio有沖突,所以必須要重寫(xiě)重定向函數(shù),具體的解決方法我這里參考了STM32 C++編程系列2.5:讓Keil MDK工程支持現(xiàn)代C++特性及填坑
打開(kāi)Mange Run-Time Environment,進(jìn)入Compiler->I/O,將里面的STDERR、STDIN、STDOUT勾選上,如下圖所示:
然后在usart.c代碼里重寫(xiě)半主機(jī)模式的重定義函數(shù):
#if 1
#ifdef __CC_ARM
#pragma import(__use_no_semihosting)
struct __FILE
{
int handle;
};
FILE __stdout;
//定義_sys_exit()以避免使用半主機(jī)模式
void _sys_exit(int x)
{
x = x;
}
#elif defined ( __GNUC__ ) || defined (__clang__)
//__asm (".global __use_no_semihosting\n\t");
#endif
//重定義fputc函數(shù)
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循環(huán)發(fā)送,直到發(fā)送完畢
USART1->DR = (u8) ch;
return ch;
}
#endif
其實(shí)就是把半主機(jī)模式刪除了,因?yàn)楣俜揭呀?jīng)自動(dòng)添加進(jìn)官方版本的重定向代碼,我們只用保留重定向調(diào)用的fputc函數(shù)就行了,然后就能成功編譯了,燒進(jìn)板子里面可看到同樣的效果。
注意
1.AC6工程不要用中文路徑
Arm compiler 6對(duì)中文路徑支持不夠友好,如果工程建立在中文路徑下,編譯后右鍵點(diǎn)擊Go To Definition of "xxxx"會(huì)無(wú)法跳轉(zhuǎn)到相應(yīng)函數(shù)的位置,必須要把工程建立在純英文路徑下。
2.更換新版本的STD庫(kù)
如上面所說(shuō),當(dāng)工程編譯通過(guò)后會(huì)有個(gè)空循環(huán)的warning,這里我也不知道要不要處理,不知道對(duì)工程效果有沒(méi)有影響
我懷疑是正點(diǎn)原子用的F4 pack包比較舊,以為他們用的是V1.4.0 固件庫(kù)包的固件包:
現(xiàn)在已經(jīng)更新到了V1.9.0版本了,所以從官網(wǎng)下載最新固件(可參考STM32標(biāo)準(zhǔn)外設(shè)庫(kù)(標(biāo)準(zhǔn)庫(kù))官網(wǎng)下載方法,附帶2021最新標(biāo)準(zhǔn)固件庫(kù)下載鏈接)后把新版本標(biāo)準(zhǔn)庫(kù)里面文件覆蓋原工程源碼里面(具體操作可參考正點(diǎn)原子的STM32F4開(kāi)發(fā)指南-庫(kù)函數(shù)版本_V1.2.pdf里面的3.32節(jié)新建模板工程)
我在這里也簡(jiǎn)單說(shuō)一下,因?yàn)橹皇翘鎿Q成新文件,不像新建工程那樣麻煩
①STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Project\STM32F4xx_StdPeriph_Templates,把如圖的四個(gè)文件覆蓋到原工程的USER里面
②再進(jìn)入STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\CMSIS\Device\ST\STM32F4xx\Include里把system_stm32f4xx.h 和stm32f4xx.h覆蓋到原工程
③確保這六個(gè)文件都覆蓋了之后
再進(jìn)入標(biāo)準(zhǔn)庫(kù)的STM32F4xx_DSP_StdPeriph_Lib_V1.9.0\Libraries\STM32F4xx_StdPeriph_Driver文件夾,把新的inc和src文件夾取代原工程的inc和src文件夾,這里建議先把原工程的文件夾里面的內(nèi)容清空
④此時(shí)編譯會(huì)有一個(gè)error
處理方法正點(diǎn)原子的教程里也有說(shuō)明,先注釋main.h頭文件,然后再注釋TimingDelay_Decrement()函數(shù)
。
⑤再把PLL 第一級(jí)分頻系數(shù) M 修改為 8
⑥重新編譯(Rebuild)后warning更多了,而且原來(lái)的空循環(huán)還存在
對(duì)此我也不知道為什么,也不知道對(duì)程序功能有沒(méi)有影響,我會(huì)放出原工程供大家參考一下,有搞得原由的可評(píng)論區(qū)說(shuō)一下
3.更多AC5轉(zhuǎn)換到AC6的代碼對(duì)應(yīng),可參考下圖
(來(lái)自https://blog.csdn.net/weixin_43644424/article/details/125048889)文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-607817.html
工程下載鏈接
stm32f4標(biāo)準(zhǔn)庫(kù)C++與C混合開(kāi)發(fā)工程文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-607817.html
到了這里,關(guān)于【stm32f4 C++與C混合開(kāi)發(fā)】建立keil5的ARM Compiler 6(AC6)標(biāo)準(zhǔn)庫(kù)開(kāi)發(fā)工程的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!