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

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

为了顺利过渡到库开发,在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的世界。

软件类型:国产软件 授权方式:共享软件 界面语言:简体中文 软件大小:0.14 MB 文件类型:.zip 演示网址:http:// 下载次数:

每一年的这个时候我都会将前一年的实验收获总结一遍,并重新打造这个mini 系列。

快三年了,主体线路图并未有过太大改变,依然保持着简洁的特点,变化最大的则是PCB的排版及布线技术。

回顾一下第一版的mini吧,不知道可否有朋友记得它?可曾记得可爱的扫帚标志?

这个是我第一款成功的MINI系列DAC,本坛的老朋友应该都见过。
它还有3个后续开发的附件

受网络的影响,我也曾经菜菜过,以为加一个时钟就能换取性能的提高,但后来事实证明,
这个时钟并不是那么简单实用的。它带来的高频失真倒是个不小的麻烦。

记得9X年的时候,某某报刊书籍都有说DAC并联提高精度之类的云云,我也是从那些书籍的指导中成长起来的,
因此也曾对此深信不疑,并制造了这个东西。

在我讲它接上去的瞬间,哇塞!好猛烈的低频啊……我不由得被自己的聪明创造所感动!兴奋的拿去给朋友们欣赏,
当时大家对DAC的认识都还比较肤浅,也都异常的兴奋,但……兴奋过后,
慢慢的我发现这一切只是强烈感官刺激后所带来的幻觉,低频的量感是强了,却失去了弹性,没了活力,
死气沉沉,毫无生气,高频暗淡无光,像是黑夜中被乌云遮去的月色一般……越听越难受,
于是我放弃了这个并联架构,使它成为了寿命最短的附件。

嫁接在mini TDA1541 DAC OS上的一个庞然大物,通过CPLD芯片修改数据及时序,
将7220输出的信号送给TDA1540这个古老的14bit芯片做DA转换,让这枚老爷车级别的芯片重新焕发青春,
唱响新时代的乐章。个人觉得这个是我设计得最好的一个附件,至少在国内互联网上,
它应该是唯一……声音表现尚可,唯独低噪偏大,这个是因为架构的问题导致的,比较遗憾,
这也凸显了升级接口设计的重要性。

从这一个版本开始,我深刻的体会到了PCB布线的重要性,通过改良走线,带来的听感上的改变是出乎意料的,
和换元件带来的听感变化不同,这种改变是很有趣的。

也是从这一版本开始,我开始对音响设备有了新的认识,也更多的花时间去了解音乐去听,去欣赏,去接受各种不同烧友给我提出的意见,在这些过程中,慢慢的,我进化了,我的DAC也进化了,我开始明白音乐是什么,设备和音乐的关系又是什么。从那时起,设备突然开始有了灵性,而我则化为了塑造这种灵性的操手。

MINI TDA1541 DAC OS 2在过去的一年里,随我游历了多位烧友的听音室,在不同的设备环境下进行了回放的测试,也参加了多次烧友聚会,每次活动之后都收获到了宝贵的改进资料,并在这段过程中不断的改进器件的选用和搭配,甚至切割线路板……仅为提高那一点点的性能。

最终它累了,走到了尽头,无法再进行改动了,拖着残破的身体,回到了它应有的归宿(一个崭新的机壳),成为了一台将永久保留在我设备架上的机器。 

这是它现在最终的样子,很龊,但很优秀!很残,但也挺美。讨了个55VA的牛媳妇,住在黑匣子里,挺乐~

BTW:这台随身的机器进行了多次修改,背面已满是伤痕,性能已不是它诞生时可比了,尽管它已经降级成连A标都没有的最普通的TDA1541。

当OS 2已成往事,那谁来接替扫帚MINI TDA1541 DAC的旗帜?我一直在想。

随着年龄的增长,经验的积累,以及心态的变化,我越发感觉到应该纠正过往设计的缺陷和错误,应该尽自己所能将mini TDA1541 DAC发挥得更好,这种想法一直在脑子里回荡。

终于……OS 3的实体摆在了我的面前。

这个板子延续了“OS 2 改”的声音风格,趋向于平衡、更自然地听感,而不再一味的突出1541的中频优势,高频顺滑,低频则扎实。
主体电路依然没有改变,调整了一下稳压电路及PCB布线,PCB的尺寸和它前两代时一样的,这也是我一贯的设计作风,通过改良线路来提高性能。

以上就是过往设计过的mini TDA1541 DAC,哦 对了还少了一份,就是由个附属品的mini 尺寸也一样。但仅仅做了几套的板子。

这是我迄今为止唯一的一台有配套外壳mini TDA1541 DAC

嗯 秀完了,该回到正题,OS 3。

目前正在调整测试阶段,一会上测试资料吧

困了 未完 待续。。。。

篇外话:mini的 前世今生

既然发帖子了,索性就继续写下去。

时间是2004年末,我对1541的了解是从论坛的第一版1541DAC开始的。

当年小钳子友情赠送了一套PCB给我,(至今仍然非常感激,遗憾的是没装完。。。 ),

那一年我还在大学校园里傻楞傻楞的……稀里糊涂的遇到了我的第一个PCB老师——创梦站长(C-Dream),于是开始的我的创造之路。。。。。

时间:2005年,这个是我们第一个版本的TDA1541……它还算不上mini,设计和布局还有些幼稚,很DIY的感觉。

当时我还不会使用PCB制图软件,所以这个板子是由我的老师代笔完成的。

线路结构大体和论坛早期的类似,NOS结构、二级稳压LM317+TL431,增加了时钟电路,信号输入选择电路,电阻IV+一阶LPF+运放放大输出。很搞笑的是当年选的制版厂不怎么好,居然搞出了几个短路点,一上电这个板子就烟花了……

而当年的形而上学,未真正了解电路,因此造出的机器稳定性不佳,TL431的应用在此成为了败笔。

随后我们还出了这个改进的版本。。。相比之前的是稳定得多了。声音表现也还行。

遗憾的是没有更多的照片留底,随着计算机硬盘的报废而报废了。。。仅得几张。

时间过得很快……我的学习也慢慢进步到可以自己绘制线路板的阶段了。在这个时期,我是疯狂的,妄想的,自以为是的。

其实并不像某些人说我只会做小板子,只会追求性价比之类的说法。实际上我一开始就是一个烧坏脑子的疯子。我第一张作品就是大板,而且很奢侈的找了一家为摩托罗拉代工的厂家帮打造了电路板,贵。。。。很贵。。。。把我的压岁钱挥霍掉了大半。 而且还疯狂的收集TDA1541的芯片,各个年代,不同产地,从最早的1541到双皇冠,我统统都买了回来,现在回头想想,够疯狂,够神经,一个人怎么去玩那几百片的芯片呢?狂晕自己!

见图吧,这个是我个人真正的第一套独立设计的PCB,很不幸。。它有bug。。。 

 实际上很想重新做这第一套板子,但……无奈已经没有了动力。)

这个板子在这个世界上仅有5套,现在一套都不在我身边。。。有些想召回它们。

我要回帖

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

 

随机推荐