完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
新建工程简单流程
首先,新建文件夹存放总的工程,如test,在test下新建文件夹分类存放工程里的各个文件,我个人分类如下:StartUp、User、Lib、Hardware、Obj 分别存放stm32启动文件,用户文件、库文件、硬件驱动文件、生成目标文件 新建好了文件夹,再复制进相应的文件,Lib直接把全部库文件复制进去也没事,到时候要用哪个就加哪个到工程里,主要是StartUp和User StartUp如下: 这些文件注意下载适合自己单片机的版本,如hd.s和md.s要分清。这些文件均与单片机启动时有关,文件的具体了解下面再讲,这里先讲流程 User如下: main.c自不用多说,下面四个文件也留到后面介绍 由于最后得编译烧录看下现象,用到个led,可以在Hardware中添加 以下操作只是作为笔记记下,所以只是简单写下。 打开软件,new project 选择路径到User即可,且把输出路径改为刚才新建的Obj,点击右边这个图标,将工程目录添加文件,如下 led相应的端口控制用到gpio库,gpio库又依赖rcc库,因此lib里加入了这两个 点击左边这个图标,点击c/c++ 设置define和include paths,后者就是把所有用到的.h文件的路径全部选择进去 前者如下:STM32F10X_HD,USE_STDPERIPH_DRIVER 其中STM32F10X_HD指明当前设备的存储容量为hd版,USE_STDPERIPH_DRIVER如果要使用官方提供的库函数则需定义(stm32f10x_conf.h include了所有库文件,而stm32f10x.h最后有一句 然后在led和main都include “stm32f10x.h” 就可以开始写代码了,我随便写了点烧录下没什么问题 main的代码: #include “stm32f10x.h” #include “led.h” void delay(unsigned int cnt) { unsigned int i,j; for(i=0;i《cnt;i++) for(j=0;j《5000;j++); } int main() { LED_Init(); while(1) { GPIO_SetBits(GPIOA,GPIO_Pin_8);//PA8?? GPIO_ResetBits(GPIOD,GPIO_Pin_2);//PB2?? delay(1000); GPIO_ResetBits(GPIOA,GPIO_Pin_8); GPIO_SetBits(GPIOD,GPIO_Pin_2); delay(1000); } return 0; } led的代码 #include “led.h” void LED_Init(void) { RCC-》APB2ENR|=1《《2; //ʹÄÜPORTAʱÖÓ RCC-》APB2ENR|=1《《5; //ʹÄÜPORTDʱÖÓ GPIOA-》CRH&=0XFFFFFFF0; GPIOA-》CRH|=0X00000003;//PA8 ÍÆÍìÊä³ö GPIOA-》ODR|=1《《8; //PA8 Êä³ö¸ß GPIOD-》CRL&=0XFFFFF0FF; GPIOD-》CRL|=0X00000300;//PD.2ÍÆÍìÊä³ö GPIOD-》ODR|=1《《2; //PD.2Êä³ö¸ß } 下面仔细讲讲这些启动文件 首先是startup_stm32f10x_hd.s,这应该是最先被执行的文件,下面讲讲其内容(参考:https://blog.csdn.net/wqx521/article/details/50925553) 先从头到尾了解 用到的指令 Stack_Size EQU 0x00000400;栈的大小 AREA STACK, NOINIT, READWRITE, ALIGN=3;分配名为STACK,不初始化,可读可写,8(2^3)字节对齐的1KB空间。 Stack_Mem SPACE Stack_Size;分配空间,栈为从高到低地址生长,即Stack_Mem到__initial_sp为最大栈顶和栈底,这里Stack_Mem为地址是我个人根据最后堆栈初始化的式子做的推测 __initial_sp ; 《h》 Heap Configuration ; 《o》 Heap Size (in Bytes) 《0x0-0xFFFFFFFF:8》 ; 《/h》 Heap_Size EQU 0x00000200 AREA HEAP, NOINIT, READWRITE, ALIGN=3 __heap_base Heap_Mem SPACE Heap_Size;分配空间,堆为从低到高生长 __heap_limit PRESERVE8;指定当前文件的堆栈按照 8 字节对齐。 THUMB;表示后面指令兼容 THUMB 指令。THUBM 是ARM 以前的指令集,16bit,现在 Cortex-M 系列的都使用 THUMB-2 指令集,THUMB-2 是32 位的,兼容 16 位和 32 位的指令,是 THUMB 的超级。 AREA RESET, DATA, READONLY;定义一个名为RESET,可读的数据段。并声明 __Vectors、__Vectors_End 和__Vectors_Size 这三个标号可被外部的文件使用。 EXPORT __Vectors EXPORT __Vectors_End EXPORT __Vectors_Size __Vectors DCD __initial_sp ; Top of Stack DCD Reset_Handler ; Reset Handler DCD NMI_Handler ; NMI Handler DCD HardFault_Handler ; Hard Fault Handler 。。。。。。。。 __Vectors_End 向量表从 FLASH 的 0 地址开始放置,以 4 个字节为一个单位,地址 0 存放的是栈顶地址,0X04 存放的是复位程序的地址,以此类推。后面的都是一些中断服务程序的地址 __Vectors_Size EQU __Vectors_End - __Vectors ;__Vectors 为向量表起始地址,__Vectors_End 为向量表结束地址,两个相减即可算出向量表大小。 AREA |.text|, CODE, READONLY;定义一个名为.text,可读的代码段 ; Reset handler 这里为复位程序的内容,先调用SystemInit函数,再调用_main函数,注意此_main和c中的main函数是不同的,具体下面讲 Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP ; Dummy Exception Handlers (infinite loops which can be modified) NMI_Handler PROC EXPORT NMI_Handler [WEAK] B 。 ENDP 。。。。。。。。 SysTick_Handler PROC EXPORT SysTick_Handler [WEAK] B 。 ENDP Default_Handler PROC EXPORT WWDG_IRQHandler [WEAK];声明函数 EXPORT PVD_IRQHandler [WEAK] EXPORT TAMPER_IRQHandler [WEAK] EXPORT RTC_IRQHandler [WEAK] 。。。。。。。。。 EXPORT DMA2_Channel2_IRQHandler [WEAK] EXPORT DMA2_Channel3_IRQHandler [WEAK] EXPORT DMA2_Channel4_5_IRQHandler [WEAK] WWDG_IRQHandler;定义空函数 PVD_IRQHandler TAMPER_IRQHandler RTC_IRQHandler FLASH_IRQHandler 。。。。。。。。。。。。 DMA2_Channel1_IRQHandler DMA2_Channel2_IRQHandler DMA2_Channel3_IRQHandler DMA2_Channel4_5_IRQHandler IF :DEF:__MICROLIB EXPORT __initial_sp EXPORT __heap_base EXPORT __heap_limit ELSE IMPORT __use_two_region_memory;使用双段模式--两区堆栈空间,堆和栈有各自的空间地址 EXPORT __user_initial_stackheap __user_initial_stackheap LDR R0, = Heap_Mem LDR R1, =(Stack_Mem + Stack_Size) LDR R2, = (Heap_Mem + Heap_Size) LDR R3, = Stack_Mem BX LR ALIGN ENDIF END 判断是否定义了__MICROLIB ,如果定义了则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。如果没有定义(实际的情况就是我们没定义__MICROLIB)则使用默认的 C 库,然后初始化用户堆栈大小,这部分有 C 库函数__main 来完成。 以上即为大致内容的了解,但是对于具体的执行流程还是有点乱,以下整体的讲讲 当STM32产生复位后,做的第一件事就是读取下列两个32位整数的值: 1、从地址0x0000,0000处取出MSP(主堆栈指针)的初始值放入MSP寄存器中; 2、从地址0x0000,0004处取出复位向量放入PC寄存器中,然后从PC中存取的地址出取指令并开始执行 也就是说,启动文件里最先被执行的是Reset_Handler函数,更具体的说,是执行SystemInit和_main函数,前者好说,可以直接goto看到内容(在system_stm32f10x.c中),但是_main据我百度知,当编译器发现定义了main函数,那么就会自动创建__main,所以无法goto来查看内容,其具体内容较为复杂,暂时只说明,启动文件里那些堆栈的规划最后是在这个函数里得到执行的,执行完后跳转到main。 |
|
|
|
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
求大神告知加热台的加热方式,是电阻丝加热吗?如果是请教一下具体的型号
9102 浏览 0 评论
偏置电路与宽带偏置电路(Bias-Tee)-----电感器比较与选择
7098 浏览 0 评论
7795 浏览 0 评论
5316 浏览 2 评论
7969 浏览 2 评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2025-2-24 06:27 , Processed in 0.461106 second(s), Total 73, Slave 57 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191