如何将.a文件导入单片机程序导入元件中?

所以,就题主给出的情况,在算完低4位B+6 = 1,产生了进位,这时再算高4位,就不能再是对A不操作了,而是A+6 = 0,即正确答案01H。

仔细看下指令集的说明则不难做出以上回答。

为了顺利过渡到库开发,在STM32编程的开始,我们对照51点亮一个LED的方法,给大家演示一下STM32如何用操作寄存器的方法点亮一个LED,然后再慢慢讲解到底什么是库,让大家知道库跟寄存器的关系。

  在用STM32点亮一个LED之前,我们先来复习下用51如何点亮一个LED。

硬件上我们假设51单片机的P0口的第0位接了一个LED,负逻辑亮。如果我们要点亮这个LED,代码上我们会这么写:

这时候我们就把LED点亮了,如果要关掉LED ,则是:

这里面我们用的是总线操作的方法,即是对P0口的8个IO同时操作,但起作用的只是P0^0。

除了这种总线操作的方法,我们还学习过位操作,利用51编译器的关键字sbit,我们可以定义一个位变量:

为了让程序看起来见名知义,我们定义两个宏:

点亮和关闭LED的代码就变成了:

稍微整理一下代码,整体效果就是:

//假设51单片机的PO~0口接LED,负逻辑点亮

 

上面总线和位操作的的方法,学过51的朋友是非常熟悉的,也很容易理解。那么我们再说一下大家容易忽略的几个知识点。

在点亮 LED 的时候,我们都是用操作寄存器的方法来实现的,那大家是否想过,这个寄存器到底是什么?为什么我们可以直接操作P0口?

解答上面的问题之前,我们先简单介绍下51单片机的主要组成部分,这对我们学习其他单片机也有好处。

我们以国内的STC89C51为例,该单片机主要由51内核、外设IP、和总线这三大部分组成。内核是由 Intel 公司生产的,外设 IP 就是 STC 公司在内核的基础上添加的诸如定时器、串口、IO 口等这些东西,总线就是用来连接内核和外设的接口单元。Intel 在这里属于IP核设计公司,STC 属于 IC 设计公司。世界上能设计 IP 核的公司屈指可数。我们非常熟悉的ARM公司就属于IP核设计公司,ARM 给其他公司授权,其他IC公司就在ARM内核上设计出各具特色的MCU,我们后面要学习的STM32就是属于一中基于ARM内核的MCU。

寄存器则是内置于各个 IP 外设中,是一种用于配置外设功能的存储器,就是一种内存,并且有想对应的地址。学过C语言我们就知道,要操作这些内存就可以使用C语言中的指针,通过寻址的方式来操作这些具有特殊功能的内存一寄存器。比如 P0 口对应的地址是0X80,那么我们要修改 0X80 这个地址对应的内存的内容的话,按照常理可以这样操作:

可当我们编译的时候,编译器会报错,在51里面只能通过sfr和sbit这两个关键字来实现寄存器映象,不能直接操作寄存器对应的地址,这是51相较于STM32不同的地方。

51单片机的这些寄存器位于地址80H~FFH中,对应着128个地址,但不是每个地址都是有效的,51系列的单片机有21个,52系列的则有26个,其他的都是保留区。

  实际上我们在编程的时候并不是通过指针来操作寄存器的,而是直接给P0、P1这些端口寄存器赋值。那么这些外设资源是如何与地址建立一一对应的关系(寄存器映射定义),这得益与51特有的两个关键字:sfr和sbit,其他单片机没有,只能用其他的方式来实现寄存器映射。这两个关键字帮我们实现了所有寄存器的定义,所以我们才可以像操作普通变量一样来操作寄存器。其实我们一开始提到的点亮LED的代码,全貌应该是这样的:

为了方便起见,我们可以把寄存器映射全部写好封装在一个头文件里面,不用每用一个寄存器就定义一次。其实这方面的工作不用我们做,我们在编程的时候都会在开始的地方添加一个头文件:

这个头文件已经实现了全部寄存器的定义,该文件是keil自带,在安装目录:
  Keil\C51\INC下可以找到。这个文件实现了字节寄存器和位寄存器的定义。

  还有一个就是启动代码,这个也是很多初学者容易忽略的地方,对于这部分我们主要总结下它的功能,不详解讲解里面的代码。

单片机在上电复位后,首先执行的是启动文件一STARTUP.A51,而不是我们通常看到的main函数。我们新建51工程的时候会有一个提示:是否拷贝启动代码到当前的工程,我们一般选择是。

启动代码用汇编语言编写,主要实现了以下功能:

  清除内部数据存储器、清除外部数据存储器、清除外部页储存器、初始化small模式下的可重入栈和指针、初始化large模式下可重入栈和指针、初始化compact模式下的可重入栈和指针、初始化8051硬件栈指针、传递初始化全局变量的控制命令或者在没有初始化全局变量时给main函数传递命令。然后程序就跳转到main函数,来到我们熟知的C世界。

  用KEIL5新建一个工程,把工程放在一个事先建好的文件夹内,工程命名为REG后保存。然后在工程目录下添加启动文件:startup_stm32fl0x_hd.s,该文件可以从KEIL5安装目录找到,也可以从ST库里面找到,然后把启动文件添加到工程里面。

启动文件由汇编语言编写,具体功能跟51里面的启动文件:STARTUP.A51差不多。

STM32的启动文件主要实现了:

3、设置向量表入口地址,并初始化向量表。

5、跳转到标号_main,最终来到C的世界。

这里我们先去除繁枝细节,挑重点的讲,主要理解第4和第5点,在启动文件的147~155行,是复位处理函数,代码如下:

这里我们简单介绍下这10行代码。

第1行是程序注释,在汇编里面注释用的是“;”,跟C语言不一样。

第2行是定义了一个子程序:Reset_Handler。PROC是子程序定义伪指令。一般用法为:

  其中NEAR和FAR是属性词。

  NEAR属性(段内近调用):调用程序和子程序在同一代码段中,只能被相同代码段的其他程序调用。

  FAR属性(段间远调用):调用程序和子程序不在同一代码段中,可以被相同或不同代码段的程序调用。

第3行EXPORT表示Reset_Handler这个子程序可供其他模块调用。关键字[WEAK]表示弱定义,如果编译器发现在别处定义了同名的函数,则在链接时用别处的地址进行链接,如果其它地方没有定义,编译器也不报错,以此处地址进行链接。

第4行和第5行IMPORT说明Systemlnit和__main这两个标号在其他文件,在链接的时候需要到其他文件去寻找。

  Systemlnit在库文件system_stm32f10x.c实现,用来初始化STM32的一系列时钟,把系统时钟设置为72MHZ。STM32的时钟比51单片机复杂,需要经过一系列的配置才能达到稳定运行的状态。

  __main其实不是我们定义的,当编译器编译时,只要遇到这个标号就会定义这个函数,该函数的主要功能是:负责初始化栈、堆,配置系统环境,并在最后跳转到用户自定义的main函数,从此来到C的世界。

第7行程序跳转到R0中的地址执行程序,之后系统的时钟就被设置成72MHZ。

第8行把__main的地址加载到寄存器R0。

第9行程序跳转到R0中的地址执行程序,执行完毕之后就去到我们熟知的C世界。

第10行表示子程序的结束。

总结下就是,Reset_Handler这个函数执行了两个函数调用,一个是Systemlnit,把系统时钟设置成72M,另一个是__main,初始化好系统环境,最终调用C的main,从此去到C的世界。

__main函数由编译器生成,负责初始化栈、堆等,并在最后跳转到用户自定义的main()函数,来到C的世界。

我爱方案网回答.a一般只是静态库文件,不是可执行文件。需要写程序然后调用.a中的函数完成相应功能,最后编译成单片机的二进制执行文件才能烧录到单片机中运行。
将文件导入单片机中,可以采用编程方式将文件读入指定内存中,只是这种方式在断电后,信息会丢失,必须每上电一次就做一次读入操作;

我要回帖

更多关于 单片机程序导入元件 的文章

 

随机推荐