0.前言
最近在做一個開源個人項目有用到STM32這款MCU,好久沒用Keil感覺各種不適應,遂嘗試能不能把STM32的開發環境部署到其他更強大的IDE,結果很圓滿,以下是配置Clion用于STM32開發的過程記錄,供大家參考~
做嵌入式開發的人對STM32這個平臺應該都是非常熟悉的,在國內尤其流行,很多產品里面都是基于這個平臺做的方案。多數人在開發STM32的時候用的都是Keil這個老牌IDE,很大一部分原因是因為大多數人最初是從51單片機學習過來的,51就是基于Keil去開發的,然后遷移到STM32的時候也就沿用下來了。
Keil開發環境界面
Keil操作簡單,容易上手,而且可以很方便地進行調試。但是對于以前不是做嵌入式開發的軟件開發人員來說,面對Keil這種上世紀風格的IDE(不只是UI)肯定是不太有好感的。在嘗試過STM32CubeIDE和TrueStudio等用Eclipse修改的IDE之后,總是覺得還是沒內味兒。
我平時工作中最常用的是Pycharm和Android Studio,都是Jetbrains系的IDE。用過Jetbrains系IDE的朋友肯定會被它強大的代碼補全、界面風格、各種插件、流暢性等眾多優點所吸引,毫無疑問這些是能夠極大提高開發效率的。而其中有一款CLion IDE就是專門面向C/C++開發的,所以本篇文章會介紹如何把STM32的編譯調試環境部署到CLion中,過程還是有很多坑值得注意的。
代碼的話大家以前用的基本上都是ST的標準庫,然后自己開發邏輯部分,或者在一些方便的地方直接操作寄存器。直接操作寄存器能提高代碼的執行效率,但是很難移植,后來ST開發了一款可以快速demo的平臺Cube MX,通過這個軟件配合ST的HAL庫,可以快速的搭建工程,并能生成跨芯片平臺的工程。HAL庫更容易進行移植,而且應用起來也更加方便,ST也正在加大對HAL庫的支持,并漸漸放棄標準庫。
本篇介紹的內容也是以基于HAL庫開發為準的。
1.環境及所需工具
軟件環境:
STM32CubeMX
Clion-2019
MinGW
OpenOCD
arm-none-eabi-gcc
硬件環境:
STM32F103VET6
自制的DapLink下載器(ST-Link/J-Link也是可以的)
工具安裝
STM32CubeMX
這個正常去官網下載最新版的安裝就行了:https://www.st.com/en/development-tools/stm32cubemx.html
OpenOCD
OpenOCD是用于對STM32進行下載仿真的工具,是一個開源軟件包,Windows版本下從這里下載,下載好解壓到一個目錄就行,后面會在Clion中鏈接這個目錄:
MinGW
Clion需要使用MinGW環境來配置工具鏈,安裝方法如下:
首先去MinGW主頁下載最新版本的MinGW: Minimalist GNU for Windows,這是MinGW的安裝器:
打開exe進行安裝,修改安裝目錄(最好不能有空格),安裝完成后進行組件下載:
如上圖中所示,把Basic Setup里面的組件全部勾選(也可也去掉不需要的語言編譯器比如Objective-C)。
配置系統的環境變量,在Path環境變量里面添加一條,指向MinGW的bin文件夾:
重啟電腦,然后在命令窗口中輸入下面的命令驗證安裝是否成功:
gcc -v
arm-none-eabi-gcc
Windows到這里下載:https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads ,選擇ZIP壓縮包形式的:
解壓到一個文件夾,并把安裝目錄下的bin文件夾添加到環境變量:
然后重啟使得環境變量生效之后可以在命令行里用以下語句測試:
arm-none-eabi-gcc -v
如果有信息輸出,那就是裝好了。
Clion配置
Clion是基于CMake來管理項目的,所以首選我們需要配置好預設的MinGW和CMake環境。
打開File-Settings-Build,Execution,Deployment選項卡,在Toolchains下面添加一個MinGW環境:
注意Debugger不要改,否則斷點調試的時候無法連接。
然后再CMake欄下確認一下工具鏈是否正確:
至此Clion環境配置完成,可以創建STM32項目了。
2.在Clion中創建STM32工程
創建CubeMX工程
在Clion中選擇File-New Project可以創建STM32CubeMX的項目:
點擊create后會生成一個.ioc文件,這個文件跟使用STM32CubeMX直接創建的是一樣的,點擊圖中的鏈接可以跳轉到STM32CubeMX中打開這個ioc文件:
默認選中的芯片型號是STM32F030F4Px,我們可以在CubeMX中重新選擇自己需要的芯片,一切操作都和使用Keil開發沒有區別。
只有一個地方需要注意一下,就是在下面的設置中項目名稱一定要和在Clion中建立的一致,這樣生成的工程文件才會覆蓋Clion中的文件,否則會另外生成一個文件夾,Clion就無法讀取了。
另外生成的IDE類型選擇是SW4STM32。
每次修改完點Generate之后,彈窗直接點Close,Clion里面會自動更新文件。
第一次設置完回到Clion會彈出一個板卡選擇窗口:
這些配置文件是跟OpenOCD下載程序有關的,里面的板子很可能是沒有我們自己要用的型號的,后面會介紹怎么自己建立這個配置文件,這里先點取消。
編譯工程
在IDE底欄的CMake選項卡中如果沒有提示錯誤,說明工程配置就沒問題了。
點擊這個按鈕可以更新CMake工程:
頂欄的這三個圖標分別是編譯、下載、調試:
點擊編譯,可以看到編譯輸出:
可以看到成功生成了用于燒寫的.bin和.hex文件。
燒錄程序 & 在線調試
在Keil里面我們燒錄程序的時候要指定使用的下載器(J-Link、ST-Link、CMSIS-DAP等),Clion燒錄程序之前通用需要進行一些設置。
點擊編譯按鈕旁邊的配置欄下拉,選Edit Configurations,打開配置窗口:
可以看到沒有設置板子的config文件所以出現警告錯誤,這個配置文件就是前面說的需要自己生成的文件。
我們在工程根目錄下新建一個文件夾config,在里面新建一個配置文件daplink.cfg(因為我這里使用的是自制DapLink作為仿真器),文件的內容如下:
# choose st-link/j-link/dap-link etc.
adapter driver cmsis-dap
transport select swd
# 0x10000 = 64K Flash Size
set FLASH_SIZE 0x20000
source [find target/stm32f1x.cfg]
# download speed = 10MHz
adapter speed 10000
前兩行設置了仿真器的類型和接口,下面幾行指定了Flash大小、芯片類型、下載速度等。
如果對自己的芯片不知道怎么設置,可以參考OpenOCD自帶的一系列配置文件,路徑在OpenOCD安裝目錄的share\openocd\scripts下:
只需要關注這幾個目錄:
board:板卡配置,各種官方板卡
interface:仿真器類型配置,比如ST-Link、CMSIS-DAP等都在里面
target:芯片類型配置,STM32F1xx、STM32L0XX等等都在里面
設置好配置文件之后,就可以點擊下載或者調試按鈕進行下載和在線調試了。
在配置文件中不要加reset_config srst_only這一句,會導致下載失敗,這一句是指示系統重啟的,刪除不影響下載。
CLion里面是支持全功能的單步斷點調試的,也能在代碼里直接觀察變量的值,非常舒服~
強大的代碼補全功能
單步調試和變量觀察功能
3.其他問題
編譯錯誤問題
如果移動了工程文件夾的話,最好打開.ioc文件重新Generate一下再編譯,可以解決很多錯誤。
printf重定向問題
在Keil里面為了使用printf函數我們需要重定向fputc函數:
int fputc (int ch, FILE *f)
{
(void)HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000);
return ch;
}
其中的FILE定義在stdio.h頭文件中,所以需要在項目中包含這個頭文件,但是經過測試發現,Keil里面包含的是MDK\ARM\ARMCC\include這個目錄下的stdio.h,而在Clion中是不會鏈接到這個文件的。因此如果在Clion中也按之前的方法進行重定向,會發現printf沒有任何輸出。
在Clion中鏈接的是GNU-Tools-ARM-Embedded\arm-none-eabi\include里面的stdio.h,如果仍然想使用printf函數功能,則需要進行如下操作:
新建一個retarget.h文件內容如下:
#ifndef _RETARGET_H__
#define _RETARGET_H__
#include “stm32f1xx_hal.h”
#include
#include
void RetargetInit(UART_HandleTypeDef *huart);
int _isatty(int fd);
int _write(int fd, char *ptr, int len);
int _close(int fd);
int _lseek(int fd, int ptr, int dir);
int _read(int fd, char *ptr, int len);
int _fstat(int fd, struct stat *st);
#endif //#ifndef _RETARGET_H__
再新建一個retarget.c文件內容如下:
#include 《_ansi.h》
#include 《_syslist.h》
#include
#include
#include
#include
#include
#if !defined(OS_USE_SEMIHOSTING)
#define STDIN_FILENO 0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2
UART_HandleTypeDef *gHuart;
void RetargetInit(UART_HandleTypeDef *huart)
{
gHuart = huart;
/* Disable I/O buffering for STDOUT stream, so that
* chars are sent out as soon as they are printed. */
setvbuf(stdout, NULL, _IONBF, 0);
}
int _isatty(int fd)
{
if (fd 》= STDIN_FILENO && fd 《= STDERR_FILENO)
return 1;
errno = EBADF;
return 0;
}
int _write(int fd, char *ptr, int len)
{
HAL_StatusTypeDef hstatus;
if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
{
hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return len;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _close(int fd)
{
if (fd 》= STDIN_FILENO && fd 《= STDERR_FILENO)
return 0;
errno = EBADF;
return -1;
}
int _lseek(int fd, int ptr, int dir)
{
(void) fd;
(void) ptr;
(void) dir;
errno = EBADF;
return -1;
}
int _read(int fd, char *ptr, int len)
{
HAL_StatusTypeDef hstatus;
if (fd == STDIN_FILENO)
{
hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
if (hstatus == HAL_OK)
return 1;
else
return EIO;
}
errno = EBADF;
return -1;
}
int _fstat(int fd, struct stat *st)
{
if (fd 》= STDIN_FILENO && fd 《= STDERR_FILENO)
{
st-》st_mode = S_IFCHR;
return 0;
}
errno = EBADF;
return 0;
}
#endif //#if !defined(OS_USE_SEMIHOSTING)
添加這兩個文件到工程,更新CMake,編譯之后會發現,有幾個系統函數重復定義了,被重復定義的函數位于Src目錄的syscalls.c文件中,我們把里面重復的幾個函數刪掉即可。
在main函數的初始化代碼中添加對頭文件的引用并注冊重定向的串口號:
#include “retarget.h”
RetargetInit(&huart1);
然后就可以愉快地使用printf和scanf啦:
char buf[100];
printf(“\r\nYour name: ”);
scanf(“%s”, buf);
printf(“\r\nHello, %s!\r\n”, buf);
-
STM32
+關注
關注
2266文章
10873瀏覽量
354832 -
稚暉君
+關注
關注
5文章
35瀏覽量
5133
發布評論請先 登錄
相關推薦
評論