?作者:良知猶存
轉載授權以及圍觀:歡迎添加微信:Allen-Iverson-me-LYN
前言
最近想開發一段單片機的代碼,代碼本身有很多的重復元素,這重復定義的一些結構體使用起來有些繁瑣,所以就想用C++開發,C++的繼承 模板類可以很容易的解決這些問題,因為在單片機運行,習慣用MDK或者IAR這些軟體,但是這些軟體都是默認C開發的,用C++開發需要重新配置,有些麻煩,但是我還是試了試,做了一個小demo供大家參考,
代碼檔案我傳到我的github中去了,大家有興趣可以參考一下
https://github.com/conscience-still/MDK-Cplusplus--LED
一、STM32CubeMX生成底層代碼
?
因為是做一個demo,不需要很復雜,就用cubemx生成了一個簡單的串口和IO控制的MDK代碼,用了精簡的LL庫,具體實作就不講了,詳細操作可以看我博客CubeMX配置的一些文章,我的博客名是:良知猶存
二、進行IDE的C++配置(去掉C環境的配置)
?
1.首先打開MDK軟體,去掉use microlib 勾選,這個一個C的依賴庫,但比標準的庫小,它可以減少C代碼的大小,CubeMX生成的檔案默認選擇此項,因為這個精簡庫不支持C++,所以我們需要去掉此項功能,
?
2.Options for Target 再點C/C++ 在下邊的Misc Controls 中輸入—cpp
?
3.去掉C99 mode選項
?
三、代碼中C++的撰寫注意
?
1. IDE中的編譯器的這個工程時候,當檔案后綴是C的時候IDE會使用C編譯器進行編譯,如果檔案后綴是CPP則IDE使用C++編譯器進行編譯,工程包含的頭檔案是使用C++編譯器進行編譯的,不過頭檔案宣告的還是C檔案的符號,所以IDE會無法正確編譯鏈接,此時我們應該將頭檔案所有宣告C符號的部分用預編譯宏加extern "C" { }的形式包含起來,告訴編譯器該段要使用C編譯器進行編譯,只包含需要進行C編譯的部分即可
#ifndef __MAIN_H#define __MAIN_H?#ifdef __cplusplusextern "C" {#endif?/* Includes ------------------------------------------------------------------*/#include "stm32f0xx_ll_crs.h"#include "stm32f0xx_ll_rcc.h"#include "stm32f0xx_ll_bus.h"#include "stm32f0xx_ll_system.h"#include "stm32f0xx_ll_exti.h"#include "stm32f0xx_ll_cortex.h"#include "stm32f0xx_ll_utils.h"#include "stm32f0xx_ll_pwr.h"#include "stm32f0xx_ll_dma.h"#include "stm32f0xx_ll_usart.h"#include "stm32f0xx_ll_gpio.h"?#ifdef __cplusplus}#endif
2.設定需要C++編譯的檔案,這時候有兩種方法實作,
1>.在代碼檔案的界面,選擇檔案右擊選擇Option for Files "你點擊的檔案",然后設定file type為需要的C++
?
2>.直接將檔案改為.cpp檔案,重新添加,此時候IDE自動進行C++編譯
第二種方法簡單快捷,但是第一種方法雖然麻煩,但是有個好處,我們不需要修改檔案名稱,這樣STM32CubeMX下一次生成代碼就不會在生成相應名稱的C代碼了,
3.將中斷服務函式添加 extern "C" 的標識,因為C++中無法直接識別中斷函式,所以用C的方法進行設備編譯,而在Cpp檔案中引入C的部分代碼,需要進行extern "C" { }進行修飾,否則不能通過編譯鏈接,
四、C++實作時候遇到的情況
? 1.寫了個類沒有注意到寫成了虛函式,其他處也沒有繼承定義這個虛函式,導致編譯錯誤,為什么把這個問題寫出來呢,就是因為MDK中C++的報錯沒怎么遇到過,我查了挺長時間,才發現這個問題的,
?
?
c++test\c++test.axf: Error: L6218E:Undefined symbol vtable for STM32_TEST::TestGPIO (referred from main.o).
把類中的虛函式改為定義好的函式即可,
2.因為我把串口初始化都放在類中實作,我想進行類的構造的時候進行串口資料的列印,但是網上查詢得知,MDK不支持std的流列印輸出,所以我就用sub和super補丁函式,進行系統main函式執行前進行串口的初始化,
這是一種特殊模式:用于有一個已經存在且不能被改變的函式 的情況,使用這兩個模式可以幫原函式打補丁,如存在一個函式foo();
$Sub$ $foo :定義的新功能函式,在foo()函式之前/后使用$Sub$$foo 可以添加一些新的程式代碼,
$Super$ $foo :就是原始的未修補的foo函式,使用這個$Super$ $foo函式將直接跳轉到foo()函式,
具體教程可以看ARM官網的資料學習哈,http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0377g/pge1362065967698.html,
?
因為super與sub函式屬于c所以我們在cpp檔案下需要添加extern“C”進行編譯才行,否則就要出現如下問題了,這些我都遇到過,給大家把雷趟了一遍,
?
3.最后的一個bug,STDIO的初始化,
本來一個簡單的C++程式就寫完了,主要就是運行環境,但是程式收錄進去之后無法作業,并且在硬體除錯下明顯看到系統到了__main之后不知道跑哪里去了,F5全速執行幾次程式才有機會正常運行,這就很奇怪了,后來在網上找資料,終于找到問題所在了,在以為博主的文章看到,他最后找到問題原來是:
事實上本人也找了近兩天的時間才找到解決辦法,一開始認為是heap和stack沒有初始化好,嘗試了好久均未成功,后來在網上得到啟發,這個問題是出在STDIO初始化上,
如果要使用C/C++標準庫就要對其STDIO進行Retarget的,很簡單,但卻是非常關鍵的一步,就是這么一回事啦,
我按照他的操作然后程式就可以正常運行了,下載ARM官方的retarget檔案,并加入到工程當中,下載鏈接:
http://infocenter.arm.com/help/topic/com.arm.doc.faqs/attached/3844/retarget.c
?
然后將里面的串口讀寫按照我現有的硬體需求進行重寫就可以了,如下代碼所示:
char UART_read(void);void UART_write(char ch);char UART_read(void){return 0;}void UART_write(char ch){while(!(USART2->ISR & USART_ISR_TXE)){};USART2->TDR = ch;}
五、最后測驗的一些體驗與感想
?
剛開始想用C++在MDK中開發是因為,有些個需求的功能C++特別符合,但是在除錯這個demo程序中,發現使用的單片機容量太小,一個<iostream>頭檔案的包含就讓一個只有串口加幾組IO控制的最小程式代碼膨脹到了32K,而去掉該頭檔案,代碼縮小到了5K,
?
代碼過大是c++的依賴項過多,而C++ 中模板類 、虛擬繼承 、STL庫等精華由于依賴的問題都不建議在單片機中用,代碼膨脹的時候單片機吃不住,所以C++雖好,可不一定適合小容量的單片機,大家需要按照自己的功能進行有效的使用C++,精簡使用的依賴,這個可以通過每次編譯的生成的.map檔案進行增該刪,其次對于C++中記憶體以及代碼擴增一些基礎知識需要熟悉,負責很容易代碼膨脹,導致我們的程式無法在單片機使用,
這就是我分享的在MDK用C++開發的demo,里面代碼是實踐過的,如果大家有什么更好的思路,歡迎分享交流哈,
?
更多分享,掃碼關注我
微信:Allen-Iverson-me-LYN
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/4951.html
標籤:嵌入式
