stm32hal库串口发送函数

stm32hal库串口发送函数【教程】手把手教你用Clion进行STM32开发【如何优雅の进行嵌入式开发】通过Clion进行嵌入式开发一、工具安装1、安装Clion因为众所周知的原因,Clion的安装就不解释了,有需要的同学自行检索2、安装STM32CubeMX正常去官网下载最新版的安装就

【教程】手把手教你用Clion进行STM32开发【如何优雅の进行嵌入式开发】   通过Clion进行嵌入式开发   一、工具安装   1、安装Clion   因为众所周知的原因,Clion的安装就不解释了,有需要的同学自行检索   2、安装STM32CubeMX   正常去官网下载最新版的安装就行了:https://www.st.com/en/development-tools/stm32cubemx.html   3、安装OpenOCD   OpenOCD是用于,是一个开源软件包,Windows版本下从这里下载,下载好解压到一个目录就行(建议不要有空格,不要有中文),后面会在Clion中链接OpenOCD和CubeMX。   4、在Clion中链接两个工具包   接下来我们进行链接,Clion设置如图所示
stm32hal库串口发送函数
stm32hal库串口发送函数在Clion中链接两个工具包   二、安装编译器   嵌入式开发大多数情况下使用C/C++,故我们需要C语言编译器,一般需要和,我们选择和   1、安装MinGW,通过MinGW安装gcc   在最新版的Clion中,已经内置了MinGW环境,所以理论上可以选择不安装,这里还是附上安装教程,供有需要的同学   安装 MinGW 的最简单方法是通过 mingw-get,它是一个图形用户界面 (GUI) 应用,可帮助你选择要安装哪些组件,并让它们保持最新。要运行它,请从项目主页下载 mingw-get-setup.exe。
stm32hal库串口发送函数
stm32hal库串口发送函数下载MinGW   打开EXE,修改安装目录(最好不要有空格),目前为止,你只安装了一个程序,更准确地说,这是一个称为 mingw-get 的专用的。启动 mingw-get 选择要在计算机上安装的 MinGW项目应用。
stm32hal库串口发送函数
stm32hal库串口发送函数安装mingw-gcc   安装完成后进行组件下载,把里面的组件全部勾选(也可也去掉不需要的语言编译器比如Objective-C)。   配置系统的环境变量,在Path环境变量里面添加一条,指向MinGW的bin文件夹:
stm32hal库串口发送函数
stm32hal库串口发送函数配置环境变量   随后打开终端(或者cmd),如果已经打开,可以尝试关闭再打开   输入,若得到如下输出,说明配置成功,若仍然有问题,可以尝试注销或者重启电脑   2、安装arm-none-eabi-gcc   Windows到这里下载:Downloads | GNU Arm Embedded Toolchain Downloads – Arm Developer   下载zip包
stm32hal库串口发送函数
stm32hal库串口发送函数下载arm-none-eabi-gcc   同理,解压到你指定的路径(建议不要有空格,不要有中文),随后配置环境变量,指向对应的bin目录
stm32hal库串口发送函数
stm32hal库串口发送函数配置环境变量   同理,通过再命令行输入进行测试,输出如下,则成功   3、在Clion中配置工具链   打开File->Settings->Build,Execution,Devlopment->ToolChains,输入MinGW的路径,Clion会自动识别,识别慢的话直接输入即可   建议自己新建一个环境,避免默认环境以后做C语言开发出现问题
stm32hal库串口发送函数
stm32hal库串口发送函数配置工具链注意Debugger不要改,否则断点调试的时候无法连接。BuildTool最新版Clion默认集成了MinGW,故Toolset部分理论上也可以不做修改,最新版Clion默认使用ninja,理论上应该也可以,如需使用make,修改路径即可。顺便介绍下ninja,在Unix/Linux下通常使用Makefile来控制代码的编译,但是Makefile对于比较大的项目有时候会比较慢,看看上面那副漫画,代码在编译都变成了程序员放松的借口了。所以这个Google的程序员在开发Chrome的时候因为忍受不了Makefile的速度,自己重新开发出来一套新的控制编译的工具叫作Ninja,Ninja相对于Makefile这套工具更注重于编译速度。除了Chrome现在还有一些其他的比较大的项目也在开始使用Ninja,比如LLVM。   然后再栏下确认一下工具链是否正确:
stm32hal库串口发送函数
stm32hal库串口发送函数确认是否正确   至此Clion环境配置完成,可以创建STM32项目了。   三、通过Clion进行标准库开发   1、创建CubeMX工程   
stm32hal库串口发送函数
stm32hal库串口发送函数创建CubeMX工程   最新版Clion第一次创建完项目,首先会启动CubeMX,提示要下载固件包,下载即可(忘截图了),随后会弹出板卡选择窗口:
stm32hal库串口发送函数
stm32hal库串口发送函数板卡选择   这些配置文件是跟OpenOCD下载程序有关的,里面的板子很可能是没有我们自己要用的型号的,后面会介绍怎么自己建立这个配置文件,这里先点取消。   随后会生成一个ioc文件,这个文件跟使用STM32CubeMX直接创建的是一样的,图中的链接可以跳转到STM32CubeMX中打开这个ioc文件:
stm32hal库串口发送函数
stm32hal库串口发送函数打开ioc文件   先选择芯片型号,默认芯片型号是,更改成你自己的芯片型号,CubeMX会根据对应的芯片生成对应的启动文件,到时候工程就使用它生成的启动文件。
stm32hal库串口发送函数
stm32hal库串口发送函数选择芯片型号
stm32hal库串口发送函数
stm32hal库串口发送函数选择芯片型号   由于我们不使用Hal库,所以不对芯片做任何配置,直接Project Manager
stm32hal库串口发送函数
stm32hal库串口发送函数Project Manager   要注意一下,就是在下面的设置中项目名称和路径一定要和在Clion中建立的一致,这样生成的工程文件才会覆盖Clion中的文件,否则会另外生成一个文件夹,Clion就无法读取了。   网上有教程选择的是SW4STM32,但是我们发现没有这个选项,根据网上的很多人都会要求把CubeMX降低到某个版本以下,但是一直使用低版本肯定不是解决问题的方法。其实在CLion文档里面就有解决方法。STM32CubeMX项目 |CLion 文档 (jetbrains.com)   Toolchain/IDE选择STM32CubeMX即可,右侧的勾,勾上   随后这里可以注意一下堆栈大小,一般0x200~0x400够用这部分与Keil中启动文件内的和段码对应   可能会提示缺少固件包,按提示下载即可(此部分未截图)
stm32hal库串口发送函数
stm32hal库串口发送函数下载固件包   随后按提示覆盖Clion默认创建的工程
stm32hal库串口发送函数
stm32hal库串口发送函数覆盖文件
stm32hal库串口发送函数
stm32hal库串口发送函数覆盖文件   等代码生成完成,我们直接关闭,并关闭CubeMX,回到Clion
stm32hal库串口发送函数
stm32hal库串口发送函数回到Clion   可以看到,已经重新生成了相关的HAL代码,并设置了对应的型号。
stm32hal库串口发送函数
stm32hal库串口发送函数型号选择完成   可能会再次弹出板卡选择窗口,我们先跳过(大概率没有我们想要的),后面会进行配置
stm32hal库串口发送函数
stm32hal库串口发送函数板卡选择   由于我们基于标准库进行开发,故需要进行调整   2、个人习惯建议   为了避免生成的代码main.c内太乱,建议勾上,让每个外设生成独立的文件
stm32hal库串口发送函数
stm32hal库串口发送函数代码生成习惯建议不勾:所有初始化代码都生成在main.c勾选:初始化代码生成在对应的外设文件。 如GPIO初始化代码生成在gpio.c中。   3、标准库的移植   由于我们不使用HAL库,所以先把他生成的Drivers、Core文件删除,然后从Keil标准库模板工程中导入这些文件,笔者这里以野火点灯程序为例
stm32hal库串口发送函数
stm32hal库串口发送函数删除不需要的文件   将野火的相关文件复制进Clion项目内
stm32hal库串口发送函数
stm32hal库串口发送函数标准库相关代码   复制后如图
stm32hal库串口发送函数
stm32hal库串口发送函数复制进项目后的代码结构   删掉不需要的文件(Keil生成的相关文件)
stm32hal库串口发送函数
stm32hal库串口发送函数删除不需要的部分   由于野火官方的库归类还不错,故按此进行简单整理,主要目的是将归入,将归入文件夹,或者和也行,看个人习惯,便于后面修改文件,笔者简单整理后如图(轻喷,也不算太标准)。
stm32hal库串口发送函数
stm32hal库串口发送函数整理代码   最后,将CubeMX生成的启动文件复制进来,并重命名覆盖,可以避免一些问题
stm32hal库串口发送函数
stm32hal库串口发送函数复制启动文件   后知后觉,如果不想覆盖的话,直接删除原来的启动文件,也可以刷新CMake,这样,后面的编译也可以通过,如图:
stm32hal库串口发送函数
stm32hal库串口发送函数刷新CMake习惯建议:在项目文件夹中添加文件夹,将启动文件放到里面,并修改,将这个文件夹路径放进里面,这也是后知后觉的,同样,通过刷新CMake,也可以通过编译,这部分后知后觉的补充内容可以先跳过,看完后面的部分再回来更容易理解。   4、修改CMakeList   CLion中组织编译规则都是基于CMakeLists.txt文件的,如果熟悉CMake应该会觉得很方便很强大,不熟悉的也没事,基本不需要额外修改什么,只需要知道怎么在这个文件里面添加源码目录和include文件夹的路径就行了:   笔者修改后如图,若修改后编译还是不通过,首先考虑这里添加的路径是否够全,特别是中添加的需要包含和,且要将所有包含文件的目录都添加进去,此外,考虑路径是否正确。
stm32hal库串口发送函数
stm32hal库串口发送函数在CMakeList中添加需要的文件做个小结:1. 需要用到的头文件,都要把路径写到cmake文件里面,编译器才能识别到。2. 把相关源文件和启动文件链接到编译器。使用GLOB命令使用通配符模式匹配来查找文件。file(GLOB SOURCES “src/*.*”)使用这个通配符,表示所有.*结尾的文件都会包含到这个SOURCES变量。   5、编译工程   编译工程,每个项目都需要先设置CMake,知乎markdown不支持页面内跳转,具体参考左侧目录【2.3 在Clion中配置工具链】的最后部分,后面需跳转的情况会使用【】表示,不再复述。   在编译前,我们需要打开,在里面加入两句话,这里的hi两个宏定义,一个代表标准库,一个是芯片型号   这两个宏定义在Keil里是在此处定义的,所以移植到Clion我们要手动加上
stm32hal库串口发送函数
stm32hal库串口发送函数Keil中的宏定义   否则编译会出现如下错误:
stm32hal库串口发送函数
stm32hal库串口发送函数不添加宏定义出现的问题   添加后如下图所示:
stm32hal库串口发送函数
stm32hal库串口发送函数手动添加宏定义   后面可能会出现,见招拆招,哪个地方定义有问题,就修改路径或者修改CMake文件   提供另外一种做法,如果不想修改源文件,也可以在中添加宏定义   如图所示,上面注释掉的,是默认CubeMX生成的HAL库宏定义,我们在下面添加宏定义的作用就类似Keil中的设置:
stm32hal库串口发送函数
stm32hal库串口发送函数在CMakeList中添加宏定义注:两者二选一即可,根据个人习惯来,若两边都做修改,就会有重新定义警告顺便提一嘴,针对标准库:- STM32F429_439xx 宏:为了告诉 STM32 标准库,我们使用的芯片是 STM32F429 型号,使 STM32 标准库根据我们选定的芯片型号来配置。- USE_STDPERIPH_DRIVER 宏:为了让 stm32f4xx.h 包含 stm32f4xx_conf.h 这个头文件。针对HAL库:- STM32F429xx 宏:为了告诉 STM32 HAL 库,我们使用的芯片是 STM32F429 型号,使 STM32 HAL 库根据我们选定的芯片型号来配置。- USE_HAL_DRIVER 宏:为了让 stm32F429xx.h 包含 stm32f4xx_hal_conf.h 这个头文件。   接下来的问题不同的人可能不一样,但是我们解决问题的思路基本是一样的,这里笔者进行记录   笔者接下来遇到的报错都是和相关的,如下:
stm32hal库串口发送函数
stm32hal库串口发送函数FSMC错误   这是由于笔者使用的STM32F429,标准库中需要使用的是FMC,Clion也很聪明,甚至能猜出来你可能需要使用其他定义(虽然不完全对,至少排除错误做参考足够了),故理论上删除掉不支持的FSMC相关外设头文件和源文件和即可通过编译,在Keil中对应的的做法则是通过右击文件来取消该文件参与编译:
stm32hal库串口发送函数
stm32hal库串口发送函数Keil中取消某个文件参与编译提一嘴FSMC和FMC:1. F1和F407使用的是FSMC(Flexible static memory controller),跟F429和H7带的FMC区别是不支持SDRAM,也就是差在字母static,使用FMC可以动态刷新SDRAM,来保持电量。2. FMC控制SRAM型存储器和NAND型存储器是异步控制,而控制SDRAM属于同步控制。同步和异步的区别是同步方式需要一个专门的时钟控制引脚。3. FMC配置中未用到引脚均可以继续用作通用I/O模式或者其它复用功能,仅需不配置FMC复用即可。   若删除后提示CMake缺少我们刚才删除的文件,无法通过编译,就刷新一下Cmake,再重新编译,如图:
stm32hal库串口发送函数
stm32hal库串口发送函数刷新CMake   最后编译成功!
stm32hal库串口发送函数
stm32hal库串口发送函数编译成功!   有时候重新打开项目可能会出现编译图标(锤子)灰色的问题,这里给出一种解决方案,即打开CMakeList文件,随后重新加载CMake项目,可以解决,最简单粗暴的办法就是修改CMakeList中的字段   随后重新加载   6、烧录程序   在里面我们烧录程序的时候要指定使用的下载器(J-Link、ST-Link、CMSIS-DAP等),烧录程序之前通用需要进行一些设置。   编译按钮旁边的配置栏下拉,选,添加一个OpenOCD下载配置,打开配置窗口:
stm32hal库串口发送函数
stm32hal库串口发送函数OpenOCD下载配置   可以看到没有设置板子的config文件所以出现警告错误,这个配置文件就是前面说的需要自己生成的文件。   我们在工程根目录下新建一个文件夹,在里面新建一个配置文件(因为我这里使用的是野火fireDap作为仿真器),文件的内容如下:   如果是用ST-Link的话:   前两行设置了仿真器的类型和接口,下面几行指定了Flash大小、芯片类型、下载速度等,具体根据参数根据手册或者开发板资料来确定,我这里是以野火标准版DAP为例。大概就是,引用了 OpenOCD 自带的配置,然后设置速度等,存起来后链接到 Board config file 即可。   如果对自己的芯片不知道怎么设置,可以参考OpenOCD自带的一系列配置文件,路径在OpenOCD安装目录的下:
stm32hal库串口发送函数
stm32hal库串口发送函数OpenOCD自带的一系列配置文件   只需要这几个目录:board:板卡配置,各种官方板卡interface:仿真器类型配置,比如ST-Link、CMSIS-DAP等都在里面target:芯片类型配置,STM32F1xx、STM32L0XX等等都在里面   设置好配置文件之后,就可以或者调试按钮进行下载和在线调试了。有时候,在配置文件中不要加这一句,会导致下载失败,这一句是指示系统重启的,删除不影响下载。而有时候,又需要加这句,否则会无法下载,例如笔者使用的野火Fire-Dap,就需要加上这句,作用类似于,否则有些情况下会出现下载失败的情况,如图:
stm32hal库串口发送函数
stm32hal库串口发送函数Keil调试器配置大家可以通过检索错误信息,灵活处理!   随后我们下载,成功点亮LED!(这里移植的是野火板子的标准库点亮LED例程)
stm32hal库串口发送函数
stm32hal库串口发送函数下载程序到开发板   7、调试程序   CLion里面是支持全功能的单步断点调试的,也能在代码里直接观察变量的值,非常舒服~
stm32hal库串口发送函数
stm32hal库串口发送函数断点调试   若需要查看寄存器的值,则需要导入SVD文件,想要SVD文件,进入Search – STMicroelectronics,搜索自己的芯片系列即可找到压缩包:
stm32hal库串口发送函数
stm32hal库串口发送函数下载SVD文件   在压缩包中,找到符合我们芯片型号的文件,解压到适当位置,随后打开
stm32hal库串口发送函数
stm32hal库串口发送函数找到我们需要的文件
stm32hal库串口发送函数
stm32hal库串口发送函数加载SVD文件   选中我们要观察的寄存器即可,为了方便,我这里直接全选了,大家根据实际需要来即可
stm32hal库串口发送函数
stm32hal库串口发送函数选择需要查看的寄存器   随后我们就可以很方便查看寄存器的值了,比如笔者这里的GPIOH模式为输出模式,即
stm32hal库串口发送函数
stm32hal库串口发送函数查看指定寄存器的值   8、解决串口问题   这里还是以为例(就在LED的基础上加了个串口)   先提一嘴,以下内容,包含笔者的踩坑记录,读者们根据自己的需求食用,若不想看这段“废话”,请直接跳转到解决方案部分,可以翻到本节的后半段或者左侧目录【3.10 更优雅的方法实现串口输入输出流】。   在Keil中开发的时候,为了使用,我们会将其重定向到串口,具体实现是通过重定义中的,并顺便重定向了,这部分同理,可通过重定义来实现。   野火的代码如下:   注意:需要包含头文件   原子的代码也同理,不过好像没有重定向,这里我也加上去:   注意:需要包含头文件   两者的代码整体上看起来都差不多,区别在于是否使用了,野火的因为使用了微库,不会使用半主机模式,故代码比较简洁,原子则不需要依赖微库,故重写的代码多了一点,多出的部分就是用于避免半主机的。   这里提一嘴微库和半主机模式:Keil官方对于微库的介绍如下:MicroLib 是一个高度优化的库,适用于基于 ARM 的嵌入式应用程序 用 C 语言编写。与 ARM编译器工具链,MicroLib提供了显着的代码大小优势,对于许多嵌入式系统来说,微库是很有有必要的。MicroLib和标准C库之间的主要区别是:- MicroLib专为深度嵌入式应用程序而设计。- MicroLib经过优化,与使用ARM标准库相比,使用的代码和数据存储器更少。- MicroLib被设计为在没有操作系统的情况下工作,但这并不妨碍它与任何操作系统或RTOS(如Keil RTX)一起使用。- MicroLib不包含文件I / O或宽字符支持。- 由于 MicroLib 已经过优化以最小化代码大小,因此某些函数的执行速度将比 ARM 编译工具中提供的标准 C 库例程慢。- MicroLib 和 ARM 标准库都包含在 Keil MDK-ARM 中。- 有关更多详细信息,请参阅与默认 C 库的区别微库的一些问题:- MicroLib 是缺省 C 库的备选库。 它用于必须在极少量内存环境下运行的深层嵌入式应用程序。 这些应用程序不在操作系统中运行。- MicroLib 不会尝试成为符合标准的 ISO C 库。- MicroLib 进行了高度优化以使代码变得很小。 它的功能比缺省 C 库少,并且根本不具备某些 ISO C 特性。某些库函数的运行速度也比较慢,例如,memcpy()。结合笔者查阅的资料,对于半主机,描述如下(不一定准确,若有问题,希望大佬们纠正):- 半主机是这么一种机制,它使得在ARM目标上跑的代码,如果主机电脑运行了调试器,那么该代码可以使用该主机电脑的输入输出设备。 – 开发初期,可能开发者根本不知道该 ARM 器件上有什么输入输出设备,而半主基机制使得你不用知道ARM器件的外设,利用主机电脑的外设就可以实现输入输出调试。- 要利用目标 ARM器件的输入输出设备(比如我们需要用到串口作为输入输出),首先要关掉半主机机制。然后再将输入输出重定向到 ARM 器件上,如printf()和scanf()。微库和半主机模式的关系(摘自网络):- printf()之类的函数,使用了半主机模式,使用标准库(这里的标准库指代编译环境的库)会导致程序无法运行- 通过使用微库,可以不使用半主机模式- 若使用标准库,则需要添加代码:   - 在独立应用程序中,不太可能支持半主机操作。 因此,必须确保您的应用程序中没有链接C库半主机函数。- 为确保没有从C库链接使用半主机的函数, 必须导入符号 __use_no_semihosting 。- 可在您工程的任何 C 或汇编语言源文件中执行此操作,如下所示:- 在 C 模块中,使用 #pragma 指令:#pragma import(__use_no_semihosting)- 在汇编语言模块中,使用 IMPORT 指令:IMPORT __use_no_semihosting- 如果仍然链接了使用半主机的函数,则链接器会报告错误。为什么要禁用半主机模式?- 在嵌入式的编程中避免不了使用printf、fopen、fclose等函数,但是因为嵌入式的程序中并没有对这些函数的底层实现,使得设备运行时会进入软件中断BAEB处,这时就需要__use_no_semihosting这 个声明,使程序遇到这些文件操作函数时不停在此中断处。关于半主机模式更多知识,可以阅读这篇博客   由于在Clion中没有微库来调用,我们尝试原子的代码,编译后出现一个:   我们先忽略,到主函数中尝试调用,再编译,问题就出来了:   很显然,直接在Clion中使用野火或者原子的代码重定向是行不通的,通过观察错误信息可以定位,很显然因为我们使用的是,而Keil是,两者的库不一样,缺少了这些定义导致这样重定向无法使用。   目前通过查阅资料,已知在中想要使用函数是需要重定向函数的(参照ARM Coretx-M4权威指南)。   怎么解决呢?这里给出解决方法:   我们可以从官方给的例子中寻找答案,标准库中没找到,随后在官方给的HAL库中,我们找到了相关的定义,都在一个叫做的文件中,我们可以尝试复制过来直接用,在这里贴出其内容,方便需要的读者:   在添加该文件并加入后,我们再编译,这次果然不报错了,尝试下载程序测试,仍然没起作用   接下来怎么办呢?我们继续查看官方给的例子,在文件中找到了相关的定义,这里省略掉无关的代码,并适当添加注释做解释:   看到这里我们就知道答案了,与在keil5中重定义函数不一样,在编译器中(stm32标准库)需要重定义的是,而这个函数,在,即中重写了函数。   在搞明白原理之后,我们只需用重定向 的部分源码替换掉原子或者野火在Keil中重定向的那部分代码,然后将syscalls.c文件添加到工程并添加到中,使其编译就可以正常使用函数了。这里其实不把 syscalls.c 整个文件拿过来只要重写 _write() 的那部分也可以,但是看在这个文件体积也不大的份上还是把他拿过来吧,万一以后用上也方便。   故在我们的项目中重写,同理,实现和:   关于半主机,通过以下方法禁用:在头部添加提醒编译器不使用半主机模式   或者通过下面代码包住相关代码段   若想直接重写和,建议在中对这两个函数添加弱定义,例如:   这样就可以避免重定义,并保留(原谅我的强迫症TAT),具体原理可以百度,这里简单提一嘴:- A,B两个模块,A模块调用了不确定B模块是否提供了函数,但是又不得不调用,这个时候在A模块中再申明一个弱符号函数,即用weak,如果外部提供了调用外部的,如果没提供调用申明的。   实测发现即使不禁用半主机也能正常使用,不知道具体什么原因,但还是建议禁止,若有大佬清楚,希望能帮忙答疑解惑!   此外,浮点数打印会有点问题,比如,串口调试助手看到只能精确到,其实这是因为C语言默认保留6位小数,可以通过添加小数点保留更多位,例如保留到小数点第八位,输出为,扯到C语言基础了23333。   看到不少文章提到需要到中添加编译参数,才能正常使用浮点数输出:   笔者发现,即使不添加,仍然能正常输出浮点数,若有大佬清楚,希望能帮忙答疑解惑!   还有个小问题,若打印字符串不添加,串口是无法输出的(可能复位后,没输出的这些内容,会哗的一下突然先出来,再正常执行程序),对于像我这种强迫症,查阅资料后,找到的解决方案如下:   在main函数开始的时候,执行如下代码,设置buffer缓存为0,这样一有数据就发送,不然会等到缓存满或有回车换行符才发送。如果没有这句,你的又没,log就会打不出来。   建议写在main的初始化最前面,或者初始化串口之前,写入这段代码还有另一种方式就是再打印后,跟一行代码,这样会强制刷新缓存,就可以正常输出了,但每次都这么操作比较麻烦,所以不推荐。   造成这样的原因为(摘录一段话):由于Unix上(GCC就是从这边过来的,感兴趣可以了解一下GUN发展史)标准输入输出都是带有缓存的,一般是行缓存。对于标准输出,需要输出的数据并不是直接输出到终端上,而是首先缓存到某个地方,当遇到行刷新标志或者该缓存已满的情况下,才会把缓存的数据显示到终端设备上。中定义换行符可以认为是行刷新标志。所以,函数没有带是不会自动刷新输出流,直至缓存被填满才会刷新输出流。强制刷新标准输出缓存; 放到缓冲区的内容中包含; 缓冲区已满; 需要从缓冲区拿东西到时候,如执行。   如果还是不行,别总想着问题是不是出在自己身上,换一个串口调试助手吧!微软应用商店的就不错!   PS:此处@伏特加(vofa+),可能给我喝多了吧,喜欢伏特加的界面,但万万没想到,加上零缓存代码后,不加一直不输出,能让我倒几杯伏特加,思考人生的问题,竟然和它有关!换个串口调试助手就正常了2333,希望伏特加官方能看到解决一下。。。   9、解决串口问题   试过的读者可能会发现确实正常了,但是和仍然有问题,在使用这两个函数的时候,STM32好像“卡死”了,笔者首先考虑是不是重定向函数编写出问题了,就单独拧出来测试了一下,写了一个函数:   放入主函数替换,发现能正常接收数据,这就奇怪了   HAL的比较全,查资料注意到HAL的处理方式如下:   开始我注意到这句话:,初步查阅资料说可能和串口溢出中断有关,对于标准库,笔者尝试了较长时间无果,感兴趣的可以查阅资料,如有大佬,也希望能够答疑!   第二天,出现转机,查阅资料时,偶然注意到这段话:Unfortunately, the default file automatically generated by STM32CubeIDE results in unexpected behavior when internal buffering of the input stream is enabled. The simplest solution to this issue is to disable buffering before any call to is made. Copy and paste the line of code provided in Listing 3 into the initialization section of the function.Listing 3: Disable internal buffering for the input stream setvbuf(stdin, NULL, _IONBF, 0);The function should now function properly for all but the floating point format specifiers. To enable those, continue on to the next step.   大概意思是,当启用输入流的内部缓冲时,STM32CubeIDE自动生成的默认文件(我的理解是)会导致意外行为,我们需要首先执行这段代码来禁用输入流内部缓冲。建议在main的初始化最前面,或者初始化串口之前,写入上面这段代码   添加代码后,问题解决!   除此以外,这篇文章还提到了,浮点数可能会出问题,需要加前面的编译选项,实际使用好像不加也没问题,希望知道的大佬能科普一下!   还有个问题就是通常用于接收字符或者字符串,若接收整数或者浮点数等数据时,可能再有些串口调试助手上无论怎么发送数据都没有反应,这里可能需要到串口调试助手上设置或者在后面跟一个再发送,因为是有终止条件的(又回到C语言基础了23333):函数接收输入数据时,遇以下情况结束一个数据的输入:- 遇空格、回车、跳格键;- 遇宽度结束;- 遇非法输入。   还有个小问题,Clion中使用可能会有警告,貌似是因为安全性问题,我们可以选择忽略,感兴趣的读者可以看看这篇博文   接下来就可以就可以愉快玩耍、、了!由于笔者能力有限,关于输入输出流缓冲的问题,感兴趣的读者可以自行查阅资料。   10、更优雅的方法实现串口输入输出流   上面踩了一系列坑,我们也大概知道是怎么去分析和实现重定向的了,接下来我们做一些封装操作,让其变得更优雅,当然笔者的代码不一定写的好,欢迎大佬们在评论区提出好的建议!若有更好的方法,也希望能够和大家分享!   首先是   随后是   把两个文件写入中即可,若编译不通过,缺少定义,请尝试添加到中,具体内容参照目录左侧章节【3.8 解决串口问题】的中间部分,或者+网页内搜索关键词。   可选项,禁用半主机,添加禁用半主机模式相关代码到相关部分,具体内容参照目录左侧章节【3.8 解决串口printf()问题】的中间部分,或者+网页内搜索关键词。   这样,我们在主函数中就可以愉快使用、、了!以下是部分关键代码示例:   前面说过,看到不少文章提到需要到中添加编译参数,才能正常使用浮点数输出:   笔者发现,即使不添加,仍然能正常输出浮点数,若有大佬清楚,希望能帮忙答疑解惑!   四、通过Clion进行HAL库开发   1、创建CubeMX工程   HAL库的开发相对就比较简单了,可以直接通过CubeMX图形化配置,然后生成初始化后的代码,我们再根据需要添加、移植功能即可   还是一样,我们以点灯为例,首先通过CLion创建CubeMX工程:
stm32hal库串口发送函数
stm32hal库串口发送函数创建CubeMX项目   随后会弹出板卡选择窗口:
stm32hal库串口发送函数
stm32hal库串口发送函数板卡选择   这些配置文件是跟OpenOCD下载程序有关的,里面的板子很可能是没有我们自己要用的型号的,后面会介绍怎么自己建立这个配置文件,这里先点取消。   随后会生成一个ioc文件,这个文件跟使用STM32CubeMX直接创建的是一样的,图中的链接可以跳转到STM32CubeMX中打开这个ioc文件:
stm32hal库串口发送函数
stm32hal库串口发送函数打开ioc文件   先选择芯片型号,默认芯片型号是,更改成你自己的芯片型号,CubeMX会根据对应的芯片生成对应的启动文件,到时候工程就使用它生成的启动文件。
stm32hal库串口发送函数
stm32hal库串口发送函数选择芯片型号
stm32hal库串口发送函数
stm32hal库串口发送函数选择芯片型号   接下来我们来进行简单的配置   首先确认时钟源,进入工程后打开 RCC 选项,选择 Crystal/Ceramic Resonator,即使用外部晶振作为 HSE 的时钟源,否则后面的时钟配置无法选中,配置如图:
stm32hal库串口发送函数
stm32hal库串口发送函数配置时钟源   接下来配置IO,大家根据自己的需要配置IO模式、速度等参数,下面仅仅是一个简单的例子,我们右下角搜索需要配置的IO口,随后该IO会闪烁(如果有这个IO的话),因为要控制LED,我们选择输出模式(图中的1、2、3步)。
stm32hal库串口发送函数
stm32hal库串口发送函数配置IO模式   接下来我们配置系统时钟:   以笔者使用的野火F429为例,开发板的外部晶振为 25MHz,我们填入 25;通道选择 HSE;PLLM 选择为/15;倍频系数 N 选择 为 x216;系统时钟选择 PLLCLK;系统时钟设定为 180Mz;APB1 分频系数选择为/4 即 PCLK1 位 45MHz;APB2 分频系数选择为/2 即 PCLK2 位 90MHz。如果嫌麻烦,简单粗暴的办法是,世界选中③HSE,并再⑦中填入180,随后CubeMX会自动调整最合适的参数。
stm32hal库串口发送函数
stm32hal库串口发送函数配置时钟树   随后进一步配置 IO 的具体属性,到左侧配置GPIO为推挽输出,上拉,速度等等,也可以通过右侧的,GPIO进入具体配置界面。
stm32hal库串口发送函数
stm32hal库串口发送函数进入GPIO具体界面   我们设置相关的参数,由于要控制LED,我们设置推挽输出,上拉模式,速度选择低速足矣,或者使用的默认电平,开漏输出,无上下 拉,低速模式也可以,引脚标签为 LED_R。   你以为这样就结束了吗?在配置工程前,我们还有最重要的一步,需要开启系统的调试接口,如图:
stm32hal库串口发送函数
stm32hal库串口发送函数开启调试接口   若不开启的话,可能出现的后果是:芯片被“锁”,本次下载以后将无法无法再下载程序!!!!!!!   这里声明一下,若出现这种问题,希望大家能自行搜索解决,此处就不给解决方案了,一方面,检索也是一种能力,另一方面,能增加你对的理解。笔者也是踩过坑的!   最后。   这部分和标准库创建CubeMX工程——最后部分内容基本一致,就不再赘述了,可由左侧目录跳转到【3.1 创建CubeMX工程】。   强调一下,设置中项目名称和路径一定要和在Clion中建立的一致,这样生成的工程文件才会覆盖Clion中的文件,否则会另外生成一个文件夹,Clion就无法读取了。   网上有教程选择的是SW4STM32,但是我们发现没有这个选项,根据网上的很多人都会要求把CubeMX降低到某个版本以下,但是一直使用低版本肯定不是解决问题的方法。其实在CLion文档里面就有解决方法。STM32CubeMX项目 |CLion 文档 (jetbrains.com)   Toolchain/IDE选择STM32CubeMX即可,右侧的勾,勾上   随后这里可以注意一下堆栈大小,一般0x200~0x400够用这部分与Keil中启动文件内的和段码对应   关于创建CubeMX的一些建议,参照3.2 个人习惯建议   2、添加自定义功能代码   此时我们回到Clion,就可以根据需要在主程序中添加自己需要的功能了,这里简单讲一下CubeMX生成代码   其中用于初始化刚才配置的GPIO,若配置其他外设,也会生成相应的初始化函数   我们的重点在于和中间部分,这里包含了自定义宏、自定义数据类型、枚举、自定义初始化函数、自定义功能代码等等,建议将自己的代码以及调用的函数、声明等等对号入座,这样以后重新配置CubeMX的时候,可以避免被覆盖(不建议这么做,不确保是否会被覆盖,且每次重新生成代码,会将CMakeList覆盖),这里需要在生成代码前勾上,默认已经勾上了。
stm32hal库串口发送函数
stm32hal库串口发送函数勾选Keep User Code when re-Generating   接着继续讲   如果要添加代码,同理,不过要吐槽一下的宏定义竟然出现在这里了,给人感觉有点乱。   随后我们添加自己的代码,来点亮我们的LED吧!由于CubeMX帮助我们完成了LED_R相关引脚的配置和定义,我们仅需到主循环中调用即可。   3、一些习惯建议   仅仅代表本人的习惯,不一定适合所有人,如有更好的习惯,或者有建议,欢迎评论区留言!   CubeMX生成的主函数和初始化相关的文件都在文件夹中,为了便于管理自己的项目,我一般会将自己的代码和CubeMX生成的代码解耦,自己创建一个文件夹,结构如下:   随后两种做法:一种是直接将和移动到和中,随后修改,再添加自己需要的代码另一种则是自己建立和,分别放入两个文件夹,随后像Arduino那样,在中定义和函数,并在中声明,修改,将这俩包含进随后填入CubeMX生成的对应位置,随后到这两个函数中实现自己的初始化和主循环逻辑。   4、编译工程   编译工程,每个项目都需要先设置CMake,具体参考左侧目录【2.3 在Clion中配置工具链】的最后部分。   这里就不用像前面标准库那么复杂了,我们直接小锤子,基本上CubeMX生成的代码,一下子就能通过编译,很快!   若遇到问题,可以考虑是否是自己添加的程序语法有问题,然后考虑CMakeList文件中是否将自己的代码和头文件包含进去了,这里参考左侧目录【3.4 修改CMakeList】。   5、烧录程序   参照目录左侧标准库部分【3.6 烧录程序】   6、调试程序   参照目录左侧标准库部分【3.7调试程序】   7、解决串口和问题   有了标准库的经验,这里就好办了,若有疑问可以参照左侧目录【3.8 串口printf()】。   这里就直接简单粗暴给出解决方案   创建,如下:   创建,如下:   示例,只给出关键代码:   前面说过,看到不少文章提到需要到中添加编译参数,才能正常使用浮点数输出: set(COMMON_FLAGS “-specs=nosys.specs -specs=nano.specs -u _printf_float -u _scanf_float”)笔者发现,即使不添加,仍然能正常输出浮点数,若有大佬清楚,希望能帮忙答疑解惑!   五、常见问题   1、最大文件字符数问题   有时候有些类型,变量或者常量已经定义,但是编译就是报错找不到,可能和最大文件字符数有关,设置大一点即可,如图:
stm32hal库串口发送函数
stm32hal库串口发送函数最大字符数问题   笔者最早默认是,移植标准库的时候,改到便解决了问题,随后使用HAL库的时候又遇到了这个问题,笔者又将其修改为解决了问题。   2、CMSIS-DAP command CMD_INFO failed.   按照经验,笔者的理解是,可能是端口被占用导致OpenOCD无法建立和调试器的通信,通过重新拔插DAP-Link的USB线,可解决。   3、所选平台不支持Thumb模式   有时候编译遇到过这样的问题:   分析:因为笔者比较懒,不想多次打开CubeMX重新配置,就直接将前面生成好的相关文件 了,此时文件中的配置还时默认的,笔者偷懒只修改了头文件、源文件相关的内容,其实还有很多需要注意的地方,导致这个问题的原因是一个编译参数:,指定的平台不同,指令集肯定会有区别,故导致此错误 add_compile_options(-mcpu=cortex-m0 -mthumb -mthumb-interwork) add_link_options(-mcpu=cortex-m0 -mthumb -mthumb-interwork)默认生成的为,而笔者的是,修改为即可,建议大家根据自己的实际平台进行修改: add_compile_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork) add_link_options(-mcpu=cortex-m4 -mthumb -mthumb-interwork)   顺便提一嘴Thumb:ARM的CPU运行的状态2种状态:ARM与THUMB。 1、CPU在不同状态运行不同的指令集。取决于 cpsr 寄存器其中的位。 2、thumb 指令集为 arm 指令集的子集。ARM指令4byte,32位,Thumb指令2byte(thumb中bl指令是4字节),16位。Thumb分为:分支指令、数据传送指令、单寄存器加载和存储指令以及多寄存器加载和存储指令。thumb指令集没有协处理器指令、信号量(semaphore)指令以及访问cpsr或spsr的指令。 3、两者区别。可将Thumb 指令看作ARM指令压缩形式的子集,它具有16位的代码密度,以空间换取效率。Thumb不是一个完整的体系结构,不能独立于ARM指令集单独使用。比如所有异常自动进入ARM状态。编写 Thumb 指令时,先要使用伪指令 CODE16 声明,且在ARM指令中要使用BX指令跳转到Thumb指令,以切换处理器状态。编写 ARM指令时则可使用伪指令CODE32声明。4、编译thumb指令集程序: ①、在makefile中添加选项” -mthumb “以供编译使用。 ②、汇编文件中指定thumb格式。” .code 32 “下的代码,使用arm指令集编译,” .code 16 “下面的代码,使用thumb指令集。 切换指令集使用bx命令,bx指向的寄存器末尾数字为1表示thumb,为0表示arm指令。若要跳转到thumb指令,需要在目标地址后手动” +1 “。 bx执行时先判断末尾数字,然后再执行” PC=<rx> AND 0xFFFFFFFE “进行对齐。 ARM指令是字对齐(指令的地址后两位为[1:0]=0b00),Thumb是半字对齐(指令的地址后两位为[1:0]=0bx0,x为0或1)。指令的地址的最后一位必为0。 ③、thumb指令不能直接向pc赋值( ldr pc, =main ),要先将伪指令赋给某寄存器,再把寄存器赋给pc ( ldr r0, =main ldr pc, r0 )。 ④、thumb指令集与变量初始化的冲突(memcpy问题)。可以把变量声明为静态的,无需修改的话还可以用const修饰。(或者自己实现memcpy。。。)——摘自简书   最后:笔者能力有限,所用的方法以及所写重定向代码考虑的不一定全面,若有问题,希望能和大家一起能补充,并提出解决方案   这里吐槽一些知乎的Markdown支持,不够友好,编辑起来有点费劲QAQ   本文参考的文章:   稚晖:配置CLion用于STM32开发【优雅の嵌入式开发】Clion实现Stm32标准库开发基于clion的野火stm32标准库开发(printf打印已解决)STM32CubeMX里面没有 CLion的SW4STM32选项(CLion修改单片机型号)【STM32H7教程】第47章 STM32H7的FMC总线基础知识和HAL库APIGralerfics:CLion 配合 CubeMX 使用 HAL 库的 STM32 开发流程简记24. 在STM32CubeIDE使用fireDAP调试 – [野火]STM32MP1-M4内核HAL库开发实战指南–基于STM32MP157开发板 文档Clion调试STM单片机_clion查看寄存器的值_啊权的博客-CSDN博客[野火]《STM32库开发实战指南》系列 – 野火产品资料下载中心 文档03.ARM – 两种指令运行模式(ARM/THUMB)MicroLib MDK-ARM LibrarySTM32程序不运行与MicroLIB讲解_The Road of Engineer的博客-CSDN博客半主机模式和_MICROLIB 库Stm32:半主机模式_半主机模式什么意思_flag的小鱼塘的博客-CSDN博客在STM32上使用printf的两种方法_stm32 printf函数_xyzjacky的博客-CSDN博客使用 VSCode 给STM32配置一个串口 printf 工程 – 路安达 – 博客园 (cnblogs.com)How to Use printf on STM32 – Shawn HymelHow to Use Semihosting with STM32 – Shawn HymelEasily Use printf on STM32Easily Use scanf on STM32stm32 use scanf with usart__attribute__((weak)) 简介及作用STM32串口接收中断溢出问题解决_usart_flag_ore_今天也迟到的博客-CSDN博客

2024最新激活全家桶教程,稳定运行到2099年,请移步至置顶文章:https://sigusoft.com/99576.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。 文章由激活谷谷主-小谷整理,转载请注明出处:https://sigusoft.com/84125.html

(0)
上一篇 2024年 7月 27日 下午8:36
下一篇 2024年 7月 27日 下午8:42

相关推荐

关注微信