现在人工智能非常火爆,一般的教程都是为博硕生准备的,太难看懂了,分享一个非常适合小白入门的教程,不仅通俗易懂而且还很风趣幽默,点☞这里☜进入传送门~
之前我们花了三篇文章介绍Linux下如何进行C语言编程:
这是为了给接下来的Linux下嵌入式开发打好基础,尽快熟悉Linux下c编程,但是在开发stm32的时候,编译工具链要使用gcc-arm-none-eabi,为什么不是gcc呢?这就要说到linux下的交叉编译了,因为我们要在PC机上编译出可以运行在ARM上的程序,使用gcc编译出的是在PC上运行的程序,所以我们要使用gcc-arm-none-eabi进行交叉编译~
gcc-arm-none-eabi是一个开源的ARM开发工具链,适用于Arm Cortex-M和Coretex-A系列处理器,包括GNU编译器(GCC),以及GDB,可用于Windows,Linux,MacOS上的交叉编译。
gcc-arm-none-eabi在ubuntu软件源仓库中就有,但是版本比较陈旧:
在此我们从ARM官方下载链接选择合适的版本下载(这里我选择Linux64):
解压下来是tar.ba2
格式包,使用命令tar -jxf <要解压的文件>
解压到我们要安装的目录:
share
目录的doc
下包含了大量的使用帮助文档,可以先略读一二,特别是readme.txt
:
接下来我们要将bin
目录添加到环境变量,这样可以直接在命令行输入要使用的工具名,然后系统就可以找到该工具,在此我们仅为当前用户添加环境变量,使用vim ~/.bashrc
编辑当前用户配置文件,在最后添加export PATH=$PATH:/home/mculover666/gcc-arm-none-eabi/bin
:
然后使用命令source ~/.bashrc
更新系统路径,使添加的环境变量立即生效:
然后输入命令arm-none
,然后按三下Tab
(一定不要输入全部),检查系统是否可以自动补全:
如果系统可以提示,说明环境变量配置成功,可以开心的使用arm-none-eabi工具链啦~
这里我使用的是野火霸道开发板,板载芯片为STM32F103ZET6
,下载器使用e-link
,这个下载器使用CMSIS-DAP下载程序,同时并带有一个串口,非常好用~
首先新建一个文件夹mkdir 00-template-reg
用来存放整个工程,然后整个工程包含三个文件:
startup_stm32f10x_hd.s
:从固件库中拷贝,注意不是arm
文件夹下的,因为truestudio
使用的是gcc编译器,所以我们选择truestudio
文件夹下的启动文件;stm32f10x.h
:空文件;main.c
:代码如下:#include "stm32f10x.h"
int main()
{
/* 开启GPIOB时钟 */
*(unsigned int*)(0x40021000+0x18) |= 1<<3;
/* 配置PB0为推挽输出 */
*(unsigned int*)(0x40010c00+0x00) |= 1<<(4*0);
/* PB0输出低电平,点亮绿色LED */
*(unsigned int*)(0x40010c00+0x0c) &= ~(1<<0);
while(1);
}
void SystemInit(void)
{
}
接下来就是激动人心的编译步骤了~编译的时候有两种文件,一种是汇编启动文件,一种是c源文件,接下来分别编译:
首先需要说明一些编译任何一个文件都需要带上的参数:
参数 | 说明 |
---|---|
-mthumb | 表明使用的指令集(必需) |
-mcpu=cortex-m3 | 表明芯片内核(必需) |
-g | 产生调试信息 |
启动文件一般是由汇编写成,此处需要注意的是,汇编文件的格式有.S
和.s
之分:
.S
:表明文件中含有预处理指令(比如#define
),需要先进行处理;.s
:表明文件不需要处理,可以直接编译;之前我们添加的启动文件是小写.s,所以直接进行编译,另外说一下,如果使用的是.S
文件,那么需要带上-x assembler-with-cpp
参数。
接下来说明一些汇编文件gcc编译器使用的参数
参数 | 说明 |
---|---|
-x assembler-with-cpp | 先对文件进行预处理 |
-Wa,option | 向汇编器Assembler传递参数 |
注:可以向汇编器传递的参数
参数 | 说明 |
---|---|
-W或–no-warn | 关闭所有告警 |
–fatal-warnings | 将所有的警告提示为错误 |
–warn | 正常提示告警信息 |
所以,接下来我们可以使用如下的参数组合来编译启动文件(不进行预处理,并且正常提示告警信息):
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m3 -g -Wa,--warn -o startup_stm32f10x_hd.o startup_stm32f10x_hd.s
因为main.c中没有特殊的东西,只是两个函数,所以简单的编译一下就可以了:
参数 | 描述 |
---|---|
-Wall | 允许输出所有警告 |
arm-none-eabi-gcc -c -mthumb -mcpu=cortex-m3 -g -Wall -o main.o main.c
链接重要的部分有两点:链接文件和传递给链接器的参数。
链接文件在固件库中给的示例工程中有,在下面这个目录:
其中stm32_flash.ld
是针对于STM32F103ZE的链接文件,如果是别的芯片,需要进行修改,将它复制到我们的工程中去:
然后就要让链接器开始根据stm32_flash.ld
这个文件对startup_stm32f10x_hd.o
和main.o
这两个文件开始链接,生成包含了调试信息的elf文件,同时,我们还需要给链接器传递一些参数:
参数 | 描述 |
---|---|
-T | 指定链接文件 |
arm-none-eabi-gcc -o test.elf main.o startup_stm32f10x_hd.o -mthumb -mcpu=cortex-m3 -T stm32_flash.ld -specs=nosys.specs -static -Wl,-cref,-u,Reset_Handler -Wl,-Map=test.map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group
利用arm-none-eabi-objcopy
工具可以将elf文件转化为适合于单片机的bin文件和hex文件,其中参数-O
(大写o)用于指定输出文件的格式(默认是bin格式)
arm-none-eabi-objcopy test.elf test.bin
arm-none-eabi-objcopy test.elf -Oihex test.hex
TARGET=test
CC=arm-none-eabi-gcc
OBJCOPY=arm-none-eabi-objcopy
RM=rm -f
CORE=3
CPUFLAGS=-mthumb -mcpu=cortex-m$(CORE)
LDFLAGS = -T stm32_flash.ld -Wl,-cref,-u,Reset_Handler -Wl,-Map=$(TARGET).map -Wl,--gc-sections -Wl,--defsym=malloc_getpagesize_P=0x80 -Wl,--start-group -lc -lm -Wl,--end-group
CFLAGS=-g -o
$(TARGET):startup_stm32f10x_hd.o main.o
$(CC) $^ $(CPUFLAGS) $(LDFLAGS) $(CFLAGS) $(TARGET).elf
startup_stm32f10x_hd.o:startup_stm32f10x_hd.s
$(CC) -c $^ $(CPUFLAGS) $(CFLAGS) $@
main.o:main.c
$(CC) -c $^ $(CPUFLAGS) $(CFLAGS) $@
bin:
$(OBJCOPY) $(TARGET).elf $(TARGET).bin
hex:
$(OBJCOPY) $(TARGET).elf -Oihex $(TARGET).hex
clean:
$(RM) *.o $(TARGET).*
make
编译生成elf文件;make bin
将elf文件转化生成bin文件;make hex
将elf文件转化生成hex文件;make clean
即可清除掉所有编译产生的文件。下一篇:Linux下开发stm32(二) | 使用openocd下载与调试