以下内容均大部分参考自下面几位大佬的文章,但是文章中有一些问题并未涉及,于是我把没有涉及的部分加入进来融合为一篇文章,如果安装的过程中出现任何问题大家也可以看一下几位大佬的原文:
配置CLion用于STM32开发【优雅の嵌入式开发】
配置过程
一、白嫖申请教育优惠
首先,Clion是JetBrains家的一款C/C++编辑器,正常的使用是要支付不菲的费用的,而且还不是买断制的,不过JetBrains推出了教育优惠,只要我们还是学生,就可以每年使用我们的教育邮箱申请一年的免费使用权限,传送门在这。
填写完个人信息之后再打三个勾,申请一下即可(邮箱一定要用教育邮箱!如果你没有收到激活邮件请移步其他邮件的垃圾箱中查看,如果垃圾箱中也没有,请耐心等待。)
二、下载和安装
1.Clion下载:下载后正常安装即可
2.OpenOCD下载:下载后解压到存放的目录,记住存放路径留待后面使用。
3.MinGW下载:下载后正常安装即可(安装路径不要有中文或空格)
安装后我们会得到一个 名为 "MinGW Installer Manager" 的软件 ,打开它。
勾选如图的两项后选择 Installation -> Apply Changes ,在弹出的对话框中选择Apply后耐心等待安装完成。
4.GNU Arm Embedded Toolchain下载:下载后正常安装即可(尽量不要安装到C盘,且安装路径不要有中文或空格),注意要勾选添加到环境变量否则需要手动添加
5.(非必须)ST-Link v2驱动下载由于想要使用Jlink的话需要修改Jlink驱动,所以现在手中有未完成工程还想更换开发环境的建议先用ST-Link做一下过渡(若需要其他版本驱动请到ST官网自行寻找下载)。
附手动添加MinGW环境变量方法:
系统设置->高级系统设置->环境变量->(双击)Path->新建->添加MinGW安装目录中的bin文件夹到环境变量中(如图),例如:
D:\SoftWare\MinGW\bin(该路径因人而异)
结束后一路确定杀回设置。
验证是否安装成功
按下Win+R打开运行窗口,输入cmd回车,分别输入:
gcc -v
arm-none-eabi-gcc -v
输出如下说明安装成功:
C:\Users\ZheWana>gcc -v
Using built-in specs.
COLLECT_GCC=gcc
COLLECT_LTO_WRAPPER=d:/software/mingw/bin/../libexec/gcc/mingw32/9.2.0/lto-wrapper.exe
Target: mingw32
Configured with: ../src/gcc-9.2.0/configure --build=x86_64-pc-linux-gnu --host=mingw32 --target=mingw32 --disable-win32-registry --with-arch=i586 --with-tune=generic --enable-static --enable-shared --enable-threads --enable-languages=c,c++,objc,obj-c++,fortran,ada --with-dwarf2 --disable-sjlj-exceptions --enable-version-specific-runtime-libs --enable-libgomp --disable-libvtv --with-libiconv-prefix=/mingw --with-libintl-prefix=/mingw --enable-libstdcxx-debug --disable-build-format-warnings --prefix=/mingw --with-gmp=/mingw --with-mpfr=/mingw --with-mpc=/mingw --with-isl=/mingw --enable-nls --with-pkgversion='MinGW.org GCC Build-2'
Thread model: win32
gcc version 9.2.0 (MinGW.org GCC Build-2)
C:\Users\ZheWana>arm-none-eabi-gcc -v
Using built-in specs.
COLLECT_GCC=arm-none-eabi-gcc
COLLECT_LTO_WRAPPER=d:/software/10\ 2020-q4-major/bin/../lib/gcc/arm-none-eabi/10.2.1/lto-wrapper.exe
Target: arm-none-eabi
Configured with: /mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/src/gcc/configure --build=x86_64-linux-gnu --host=i686-w64-mingw32 --target=arm-none-eabi --prefix=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw --libexecdir=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/lib --infodir=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/share/doc/gcc-arm-none-eabi/info --mandir=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/share/doc/gcc-arm-none-eabi/man --htmldir=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/share/doc/gcc-arm-none-eabi/html --pdfdir=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/share/doc/gcc-arm-none-eabi/pdf --enable-languages=c,c++ --enable-mingw-wildcard --disable-decimal-float --disable-libffi --disable-libgomp --disable-libmudflap --disable-libquadmath --disable-libssp --disable-libstdcxx-pch --disable-nls --disable-shared --disable-threads --disable-tls --with-gnu-as --with-gnu-ld --with-headers=yes --with-newlib --with-python-dir=share/gcc-arm-none-eabi --with-sysroot=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/install-mingw/arm-none-eabi --with-libiconv-prefix=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-gmp=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-mpfr=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-mpc=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-isl=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-libelf=/mnt/workspace/workspace/GCC-10-pipeline/jenkins-GCC-10-pipeline-48_20201124_1606180641/build-mingw/host-libs/usr --with-host-libstdcxx='-static-libgcc -Wl,-Bstatic,-lstdc++,-Bdynamic -lm' --with-pkgversion='GNU Arm Embedded Toolchain 10-2020-q4-major' --with-multilib-list=rmprofile,aprofile
Thread model: single
Supported LTO compression algorithms: zlib
gcc version 10.2.1 20201103 (release) (GNU Arm Embedded Toolchain 10-2020-q4-major)
Clion中文界面配置
打开Clion,根据提示登录我们的白嫖账号。
选择Plugins->Marketplace->搜索“Chinese”,选择Chinese(Simplified) Language Pack/中文语言包
安装后重启即可。
软件配置
打开Clion->自定义->所有设置...->嵌入式开发
在OpenOCD位置中选择openocd.exe所在的位置;
在Stm32CubeMX位置中选择STM32CubeMX.exe所在的位置。
完成后可以点击测试来测试一下是否成功配置。
来试着建立我们的第一个工程
打开Clion,选择新建项目;
选择嵌入式一栏中的STM32CubeMX,新建一个文件夹用来存储Clion的工程(名字里面不要带有中文或空格),路径的最后一个文件名称要改为当前工程的名称,须要记住。
完成后点击创建。
一番加载之后会出现这样的界面:
点击中间的:
就会自动运行CubeMX了,不过初始的芯片并不是我们想要的芯片,可以通过点击更换我们想要的芯片:
我们仍以STM32F401CCU6为例来进行操作,配置的过程和正常使用芯片的时候几乎完全一致,需要注意的有这么三点:
1.工程名必须与之前的名字一致:
2.工程路径要和之前的路径是一样的:
3.ToolChain中要在这两项中任选一个并勾选右侧的Generate Under Root:
配置完成之后点击生成代码,会提示是否要覆盖已存在的工程,选择Yes。
完成后点击Close,回到Clion。
界面会变成这个样子:
紧接着会提示选择配置文件,因为这里没有我们需要的配置文件,所以我们点击取消,后面我们会自己写适合我们自己的配置文件。
至此,工程建立完毕,可以开始愉快的写代码了!
PS:主函数文件在“Core\Src\main.c”
函数库文件在“Driver\STM32F4xx_HAL_Driver\Src\xxx.c”
随便写一段代码,发现似乎代码补全并没有很好用?那我们来更改一下设置:
Ctrl+Alt+S打开设置界面:
(什么?你打开了QQ录屏?咳咳咳)
它其实在这里:
点击编辑器->常规->代码完成(其实应该是代码补全咳咳)->取消匹配大小写前面的勾选(记得按应用)
回去敲一段代码就可以享受到丝滑的代码补全了:
其实使用了一段时间之后发现完全不需要这么麻烦的新建工程,完全可以如下操作:
先使用CubeMX新建一个工程,然后直接右键新建的工程文件夹,选择“Open Folder As Clion Project”即可。
配置文件的书写
考虑到随着开发过程的延长,我们用到的调试器会逐渐增多,所以我们在Clion工程文件夹中新建一个Config文件夹专门用来存放各种配置文件。
在文件夹中右键新建一个文本文档,后把文档的名字连同后缀改为“STlink.cfg”。
这里说一下配置文件书写的格式:
#前面带有“#”的是注释
#下方xxxxxx选择调试器型号,对应的配置文件在openocd文件夹路径\share\scripts\interface中,从中选择需要的即可。
source [find interface/xxxxxx.cfg]
#下方xxxxxx选择调试接口,可选项包括:
#jtag、aice_jtag、swd、stlink_swim、hla_jtag、hla_swd
transport select xxxxxx
#选择目标芯片种类,对应的配置文件在openocd文件夹路径\share\scripts\target中,从中选择需要的即可。
source [find target/xxxxxx.cfg]
# 不使用复位接口
reset_config none
例如J-Link的配置文件内容如下:
source [find interface/jlink.cfg]
transport select swd
source [find target/stm32f4x.cfg]
reset_config none
ST-Link的配置文件内容如下:
source [find interface/stlink-v2.cfg]
transport select hla_swd
source [find target/stm32f4x.cfg]
reset_config none
接下来点击上方配置界面:
选择编辑配置,
在面板配置文件中选择自己对应的调试器的配置文件即可(别忘了点击应用)。
如果现在手中有未完成工程还想更换开发环境的此处建议使用ST-Link,因为J-Link需要更改驱动,这将导致你的Keil在换回原来的驱动之前无法使用J-link,而ST-Link则不存在这样的问题。
关于硬件浮点运算单元
在CMake模板文件中将硬件浮点运算注释掉了,这会导致如果我们使用这部分就会报错,因此需要把这部分取消注释。
我们进入CMake的模板文件:
将下面的代码取消注释:
#Uncomment for hardware floating point
add_compile_definitions(ARM_MATH_CM4;ARM_MATH_MATRIX_CHECK;ARM_MATH_ROUNDING)
add_compile_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
add_link_options(-mfloat-abi=hard -mfpu=fpv4-sp-d16)
J-Link驱动修改(非必须,看个人需要)
接下来我们来修改一下J-Link驱动。
下载Zadig并打开
插上J-Link
点击Options->在List All Devices前面打勾
然后在下拉列表中选择这个驱动:
在下方更改为WinUSB:
点击安装即可修改驱动。
简单的界面功能介绍以及一点小小的适应性修改
首先就是最常用的快捷键:
什么,你想用快捷键但是觉得Clion的快捷键风格不适合你?我们可以改下快捷键的风格:
进入设置->键盘映射,可以在这里将快捷键风格改为Visul Studio风格:
这样我们就可以在调试的时候按下F10下一步,按下F11进入函数了。
改完键盘快捷键再说一个代码风格不好的小朋友的福音:代码格式化
如果你更改了VS风格的快捷键,那么你可以用“Ctrl+Alt+Enter”来实现当前文件代码的格式化。
具体的细节方面设置可以在设置->编辑器->代码样式->C/C++中进行设置:
如果你觉得右上角的报错怪怪的并不是你所需要的,
进入设置找到下图设置项,先把上方配置文件从项目默认改成全局默认:
取消endless loop后面的勾选:
在下面的设置项中找到校对->拼写错误,取消勾选:
点击应用、确定。
调试界面:
由于Clion进入调试模式就会自动运行程序而不是像keil一样在main函数停下来,所以建议调试前在main前下断点。
点击虫子图标进入调试界面,功能菜单在下面:
关于功能键的介绍:
点击变量窗口的“+”可以添加监视变量(可以是表达式,似乎输入函数还可以监视函数的返回值):
此外,代码窗口中的箭头不仅有指示代码执行位置的作用,还可以通过拖动箭头来强制执行语句:
关于F4调试过程中的一些问题(只有F4有类似的问题):
我们进入调试之后运行代码,然后暂停会发现一件奇怪的事:
代码停在了错误处理的死循环中:
这是由于openocd的配置文件修改了我们的核心频率,导致HAL库在配置时钟树的时候会检测到时钟频率不是我们要配置的频率而进入ErrorHandler。由于进入调试的时候openocd的配置文件被运行了一次所以会产生这个问题。
由于复位会重置我们的时钟频率,所以如果不在意的话只要每次进入调试都复位一下即可解决问题:
当然,解决办法也很简单:
在target文件夹中找到stm32f4x.cfg文件打开,用“#”将下面内容注释:
笔者说:虽说这个问题理论上是可以通过修改配置文件来解决,但是本着简单粗暴的原则,我们直接将不必要的代码注释掉即可。
# $_TARGETNAME configure -event reset-init {
# # Configure PLL to boost clock to HSI x 4 (64 MHz)
# mww 0x40023804 0x08012008 ;# RCC_PLLCFGR 16 Mhz /8 (M) * 128 (N) /4(P)
# mww 0x40023C00 0x00000102 ;# FLASH_ACR = PRFTBE | 2(Latency)
# mmw 0x40023800 0x01000000 0 ;# RCC_CR |= PLLON
# sleep 10 ;# Wait for PLL to lock
# mmw 0x40023808 0x00001000 0 ;# RCC_CFGR |= RCC_CFGR_PPRE1_DIV2
# mmw 0x40023808 0x00000002 0 ;# RCC_CFGR |= RCC_CFGR_SW_PLL
#
# # Boost JTAG frequency
# adapter_khz 8000
# }
接下来就可以开心地进行调试了。
关于查看寄存器配置
进入调试,点击外设:
后点击中间的加载.svd文件
由于我们安装过keil,故我们有现成的寄存器文件,路径如下:
...\Keil5\Packs\Keil\STM32F4xx_DFP\2.15.0\CMSIS\SVD\STM32F40x.svd
其他.svd文件也在相同路径下。
选择后出现下面窗口:
可以根据需要选择需要查看的寄存器,也可以为了方便直接全选。
后续可以点击配置键重新配置选择的寄存器:
关于GDB调试
网上关于GDB调试的内容有很多,这里就列出一些简单的命令供大家使用:
命令 | 命令缩写 | 命令说明 |
---|---|---|
list | l | 显示多行源代码 |
break | b | 设置断点,程序运行到断点的位置会停下来 |
info | i | 描述程序的状态 |
display | disp | 跟踪查看某个变量,每次停下来都显示它的值 |
step | s | 执行下一条语句,如果该语句为函数调用,则进入函数执行其中的第一条语句 |
next | n | 执行下一条语句,如果该语句为函数调用,不会进入函数内部执行(即不会一步步地调试函数内部语句) |
p | 打印内部变量值 | |
continue | c | 继续程序的运行,直到遇到下一个断点 |
set var name=v | 设置变量的值 | |
start | st | 开始执行程序,在main函数的第一条语句前面停下来 |
kill | k | 终止正在调试的程序 |
watch | 监视变量值的变化 | |
quit | q | 退出GDB环境 |
具体用法可以参考这篇文章。
关于printf重定向问题
在使用Clion时无法正常进行串口重定向。
对此我们提供一种解决方法:
//头文件包含如下:
#include <stdio.h>
#include <stdarg.h>
//重定向函数内容如下,使用时直接调用即可:
int UART_printf(UART_HandleTypeDef *huart, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
int length;
char buffer[128];
length = vsnprintf(buffer, 128, fmt, ap);
HAL_UART_Transmit(huart, (uint8_t *)buffer, length, HAL_MAX_DELAY);
va_end(ap);
return length;
}
关于多文件工程的组建
在使用的过程中还会遇到的问题就是关于多文件项目找不到包含文件的问题,为了解决这种问题我们给出两种方法:
首先是最简单粗暴的方法:
将需要使用的头文件(.h)丢进Inc文件夹,把源文件(.c)放进Src文件夹,然后在主函数include一下就可以用了。
不过这种简单粗暴的方法往往不能让我们的工程变得井井有条,故我们有下面这个优雅的方法:
由于Clion是使用CMake进行工程组建的,所以我们在导入外部源文件的时候需要对CMake配置文件做点手脚。
PS:CMakeLists.txt是根据模板文件生成的,所以我们应该更改模板文件而不是这个文件,否则所作更改会在重新生成CMake文件的时候被覆盖。
此处以DMP库的导入为例:
首先在工程目录下新建一个文件夹并命名为“DMP”;
接下来将我们需要用到的文件复制到该文件夹下;
接下来打开我们项目列表中的CmakeLists_template.txt文件,我们开始改写CMake模板文件:
我们在文件中搜索“include_directories”可以看到如下语句:
include_directories(${includes})
我们在这句话的下方加一句:
include_directories(DMP)
然后将下方的这个语句做一点小小的更改:
#更改前:
file(GLOB_RECURSE SOURCES ${sources})
#更改后:
file(GLOB_RECURSE SOURCES ${sources} "DMP/*.*")
完成后右击(.ioc)文件,选择“使用CubeMX更新CMake项目”:
回到主函数文件编译,此时应该没有问题了。
至此全部教程完成,如有问题可与我本人联系,内容中如果有任何形式的任何错误,欢迎大佬指出。
以上