一、工程文件的建立
1、我们建立一个”工程模板“文件夹,在它下面在新建4个文件夹
Listing | 存放编译器编译适合产生的C/汇编/链接的列表信息 |
Project | 存放工程 |
Output | 存放编译产生的调用信息、hex文件、预览信息、封装库等 |
User | 存放用户编写的驱动文件 |
2、打开keil5点击Project新建一个工程放到我们刚建的”工程模板“文件夹中的Project中命名按喜好来就行,这里建议使用英文。
3、 在弹出的界面中我们选中F1系列中103中的任意一款芯片,这里我选的STM31F103R6,因为我们用的Proteus仿真中有这款芯片,等下可以仿真。
4、我们在Project视图栏里对Source Group 1 右击我们的鼠标Add New一个c文件名字随意就好这里建议英文。
5、我们到keil5的根目录下找到此路径下的启动文件夹这里看你安装在哪里了
我这里就不详细介绍这些启动文件了这里给张表想要更深的了解这些东西关注我后面我会更新STM32启动文件详解。
启动文件 | 区别 |
startup_stm32f10x_ld.s | ld:low-density 小容量,Flash容量为16 ~ 32K |
startup_stm32f10x_md.s | md:medium-density中容量,Flash容量为64 ~ 128K |
startup_stm32f10x_hd.s | hd:high-density大容量,Flash容量为256 ~ 512K |
startup_stm32f10x_xl.s | xl:超大容量,Flash容量为512K ~ 1024K |
以上4种都属于基本型 |
startup_stm32f10x_cl.s | cl:connectivity line devices 互联型 |
startup_stm32f10x_ld_vl.s | vl:value line devices 超值型系列 |
startup_stm32f10x_md_vl.s |
startup_stm32f10x_hd_vl.s |
6、这里我用的是startup_stm32f10x_ld.s,把他复制到我们建立的工程文件夹中的User文件夹并在我们的工程里添加它。
7、我们可以看看这个启动文件,详细的我会在后面更新的STM32启动文件详解中介绍这里我们只看我们等下需要的部分,找到这个函数Reset_Handler
129行定义了一个子程序:Reset_Handler。 PROC是子程序定义伪指令。这里就相当于C语言中定义了一个函数,函数名是Reset_Handler。
130行EXPORT表示Reset_Handler这个子程序可以被其他模块调用。相当于C语言中对函数进行声明。[WEAK]表示弱定义,如果编译器发现在别的地方定义了同名的函数,则在链接时用别处的地址进行链接。
131、132行的TMPORT表示定义的标号在其他文件中,在链接的时候需要到其他文件中去寻找。用C语言来解释从其他文件引入函数声明。以便下面对外部函数调用。
SystemInit是需要我们自己实现,需要编写一个同名称的函数,用来初始化STM32的时钟,用来时STM32达到稳定运行。这个函数固件库里有但我们寄存器编程的化还是要写的(但这个函数只要写个空的同名函数就行了,只要骗过编译器我们已经写了,里面可以不用写东西。STM32在我们没有配置时钟的时候会自己使用内部的系统时钟)关注我在后面更新的时钟章节会详细介绍
_main不用我们定义(不要与C语言中的主函数main混淆了)这是一个C库函数,该函数主要功能是:初始化栈、堆,配置系统环境,并在函数最后调用用户编写的主函数,从此进入C的环境。
133行把SystemInit的地址写入到寄存器R0。
134行程序跳转到R0中执行程序,就是执行SystemInit函数。
135行吧_main的地址写入到寄存器R0。
136行程序跳转到R0中执行程序,就是执行_main函数。
137程序结束。
8、看完启动文件我们就可以开始写我们的代码了,哪我们该怎么动手呢,看过我前篇文章STM32-存储器和寄存器中知道,寄存器就是就是给一个已经分配好地址的特殊内存空间的一个别名,既然是地址那么我们就可以用C语言中的指针来操作它。那么我们来实现寄存器映射(不知到什么意思可以翻看我前面STM32-存储器和寄存器文章)。
stm32f10x.h头文件
#ifndef _STM32F103_H_
#define _STM32F103_H_
/*片上外设基地址*/
#define PERIPH_BASE ((unsigned int) 0x40000000)
/*总线基地址,GPIO挂再在APB2上,详情可以看STM的手册*/
#define APB2PERIPH_BASE (PERIPH_BASE+0x10000)
/*AHB总线基地址*/
#define AHBPERIPH_BASE ((unsigned int)0x40020000)
/*GPIOB外设的基地址*/
#define GPIOB_PERIPH_BASE (APB2PERIPH_BASE+0x0c00)
/*RCC外设基地址*/
#define RCC_BASE (AHBPERIPH_BASE+0x1000)
/*GPIOB寄存器地址*/
#define GPIO_CRL *(unsigned int*)(GPIOB_PERIPH_BASE+0x00)
#define GPIO_ODR *(unsigned int*)(GPIOB_PERIPH_BASE+0x0c)
#define GPIO_BSRR *(unsigned int*)(GPIOB_PERIPH_BASE+0x10)
#define GPIO_BRR *(unsigned int*)(GPIOB_PERIPH_BASE+0x14)
/*RCC的使能寄存器地址*/
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)
#endif
这里我吧手册中的存储器印象地址放这里详情可以查看手册STM32FXX手册 https://pan.baidu.com/s/1sk1_DSbL5ZV33I7zqzJEsg
提取码:pyj1
寄存器的地址就是在外设GPIOB的地址上加上地址偏移,可以在手册中查看比如CRL(端口配置低寄存器)就是GPIOB_PERIPH_BASE(GPIOB外设基地址)+0x00(偏移地址)后面几个寄存器以此类推。
main主函数
#include "stm32f103.h"
int main()
{
/*开启GPIOB端口的时钟,详情可看下文1*/
RCC_APB2ENR|=((1)<<3);
/*清空控制PB0的端口位*/
GPIO_CRL&=~((0x0f)<<(4*0));
/*配置PB0为通用推挽输出,速度为10MHz,详情可看下文2*/
GPIO_CRL|=((1)<<(4*0));
/*PB0输出低电平,详情可看下文3*/
GPIO_ODR |= (0<<0);
}
void SystemInit() /*骗过编译器我们已经编写了,详情可以看上面关于启动文件的介绍*/
{
}
1、开启GPIO端口时钟
2、 配置PB0为通用推挽输出,速度为10MHz
3、 PB0输出低电平
9、编译后我们来看看仿真结果可以看出来LED已经被点亮了
其实寄存器编程和固件库编程本质上都一样都是配置各种寄存器,可以看我前面的文章STM32-固件库编程点亮LED对照的看一下,关注我后面我会更新STM32所有特色外设的介绍,STM32时钟篇章
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)