打印
[技术手册]

单片机启动&库函数构成

[复制链接]
316|15
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wwppd|  楼主 | 2024-9-21 10:03 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
第一部分 默认时钟和启动文件
单片机内部基本由内核、总线、外设组成,这三部分作为数字电路,都需要开发者提供时钟信号才能正常工作。所谓时钟信号,就是周期脉冲信号,由电路分析可知RC振荡电路可以产生稳定的脉冲,故单片机的时钟信号可以由RC振荡器提供。但是RC振荡器提供的时钟信号质量不高,而晶体振荡器依靠压电效应提供稳定的、高质量的时钟信号。以CW32F030C8T6单片机为例,他拥有2个内部振荡器,并且可以使用外部振荡器输入的脉冲信号作为时钟。先说内部振荡器,有HSI(高速-high speed、内部-internal)和LSI两个震荡器,这两个振荡器均为RC振荡器,可以通过配置相关的寄存器来调整输出频率,一般单片机启动的时候都会使用内部振荡器提供的时钟,这种RC振荡器启动速度很快,价格低廉,非常时候作为启动时钟。内部低速振荡器一般不作为内核运行的时钟,而是作为部分外设的时钟,如rtc定时器(实时时钟)和看门狗。对于此款单片机,可以通过下述办法来判断单片机上电之后的行为,提示:一般单片机上电之后都会配置主要的时钟参数,但配置之后工作状态不同,后文会有对比。
1.找到单片机的启动文件,启动文件以“.s”后缀出现,意为start_up。
2.启动文件由汇编语言编写,单片机启动一定会从启动文件开始,而不是C语言下的main函数。
3.下图为启动文件截图。
4.在上方文件中找到那个叫SystemInit的东西,这是个函数名字,一般来讲都可以在厂商提供的库函数中找到,cw32的在下面这个图的文件里
1.在执行完SystemInit函数的这三行代码之后,单片机会正常跳转到main函数开始执行,就像启动文件里面写的那样。
至此,启动文件主要部分及系统默认的上电时钟已讲解完。
如果你看不懂C语言,那就去补习C语言。
如果你看不懂为什么这是在操作寄存器,下一部分会教你如何看寄存器。
第二部分 库函数和寄存器
我们都知道计算机编程最早使用的是机器语言,也就是用打点纸带来编程,后续出现了汇编语言,使用助记符来辅助编程,再到后来的C语言,高级语言诞生,软件开发变得更加简单。但是到计算机这一层,他依然是使用的数字电路来工作的,至少,开发者需要操作的东西就算不是数字电路,也是个寄存器。计算机发展中,寄存器被人们用“地址”这个东西来标号,翻开编程手册(单片机至少有三个手册是开发者需要看的,分别是:data_sheet \user_program_guide \core_program_guide),你会发现每个寄存器都会有一个地址,到目前为止,32位单片机拥有非常多的寄存器,这些寄存器地址已经不会再用最直接的地址累加形式显示出来(如0x00,0x01,0x02........)。稍微高级一些的单片机都会使用基地址+地址偏移量的形式指示寄存器的地址,如下图所示:
如果开发者想要使用位于SYSCTRL这个寄存器组下的分寄存器,如总线时钟或是PLL时钟,就需要用基地址+地址偏移量的方式找到这个寄存器,并赋值寄存器来配置。所谓地址偏移量,就是这个寄存器有多少字节的容量,32位单片机就是4字节,所以地址偏移量基本上就是4字节步进来累加的,某些情况会有多个寄存器一起负责一个功能的情况,这个时候偏移量要酌情理解。那地址代表了寄存器,地址和库函数有什么联系?C语言最精髓的东西是什么?那必然是指针,指针就用的是这种“以地址指示参数位置”的办法,所以你可以在库函数看到如下一系列的宏定义:

基地址。
地址强制转换为结构体指针
上面那个东西又会被定义成开发者可以直接操作的寄存器有朋友肯定会问,这里只有一个基地址,为什么可以用CW_SYSCTRL->REG的形式操作很多寄存器呢?由于每个寄存器都是32位的,也就是4字节,由C语言联合体和结构体的特性,内部的地址是基地址累加的,只需要一个寄存器累加固定的偏移量,就能把结构体成员和单片机内的寄存器一一对应起来,这就是寄存器与库函数的联系。一旦想通寄存器和库函数是怎么联系起来的,单片机编程就会变成一个非常简单的事情,因为库函数本质上就是在用地址操作去赋值、改写寄存器,全世界的单片机库函数都是如此。在任何时候,开发者都可以通过直接赋值寄存器的办法去完成自己期望的配置。现在我们回头看cw32系统初始化函数的最后两行,最开始的就是基地址指针,这个是一个结构体指针,结构体由很多联合体构成,指针选择结构体成员,结构体成员是联合体,所以用‘.’的方式选择了TRIM成员进行赋值,赋的值就是等号右边的部分。细说等号右边的含义。RCC是一个十六进制数,他被强制转化为了16位指针类型,并在赋值之前解引用被变成了本身的值,即前文提到的十六进制数,根据编程手册,这个十六进制数表示了RC振荡器对应48MHz输出的校准值。
至此,关于第二部分的寄存器-库函数联系已讲解完成,如有错误或遗漏,欢迎指正和补充。
总结:
1.单片机启动并不是从main函数开始执行的,而是从启动文件规定的函数开始执行的
2.大部分单片机都会上电自动配置时钟保证单片机能够正常工作
3.寄存器和库函数通过地址这个东西联系在一起,库函数本质就是在操作寄存器

使用特权

评论回复
沙发
szt1993| | 2024-9-23 17:04 | 只看该作者
很详细的启动程序讲解

使用特权

评论回复
板凳
小夏天的大西瓜| | 2024-9-26 19:40 | 只看该作者
一般单片机上电之后都会配置主要的时钟参数

使用特权

评论回复
地板
星辰大海不退缩| | 2024-10-12 11:08 | 只看该作者
main函数是程序员设计程序的开始

使用特权

评论回复
5
AdaMaYun| | 2024-10-13 17:06 | 只看该作者
一般单片机上电之后都会配置主要的时钟参数,但配置之后工作状态不同

使用特权

评论回复
6
t1ngus4| | 2024-10-16 15:33 | 只看该作者
单片机的启动过程和库函数构成是理解其工作原理和开发应用的基础

使用特权

评论回复
7
d1ng2x| | 2024-10-16 16:40 | 只看该作者
单片机的启动过程通常包括上电复位,当单片机上电时,内部复位电路会自动复位,将所有寄存器和状态位恢复到初始状态。复位信号通常由外部复位电路(如RC电路)或内部复位电路产生

使用特权

评论回复
8
q1d0mnx| | 2024-10-16 17:42 | 只看该作者
初始化后单片机会执行初始化代码,设置时钟、中断、外设等。初始化代码通常位于启动文件(如startup_xxx.s)中

使用特权

评论回复
9
tax2r6c| | 2024-10-16 18:46 | 只看该作者
正常来说单片机会跳转到主程序的入口地址(通常是main函数)。主程序是用户编写的代码,负责实现具体的功能。

使用特权

评论回复
10
l1uyn9b| | 2024-10-16 19:55 | 只看该作者
单片机开始执行main函数中的代码,实现用户定义的功能。主程序可以调用库函数、配置外设、处理中断等。

使用特权

评论回复
11
p0gon9y| | 2024-10-16 21:04 | 只看该作者
单片机的库函数通常由启动文件组成,启动文件通常是一个汇编文件(如startup_xxx.s),负责初始化单片机的寄存器和堆栈。启动文件还会定义中断向量表,指定中断服务程序的入口地址

使用特权

评论回复
12
w2nme1ai7| | 2024-10-16 22:10 | 只看该作者
系统初始化函数(如SystemInit)负责初始化单片机的时钟系统、外设时钟等

使用特权

评论回复
13
suw12q| | 2024-10-17 09:00 | 只看该作者
这些函数通常在启动文件中被调用。

使用特权

评论回复
14
q1ngt12| | 2024-10-17 11:20 | 只看该作者
外设驱动函数(如GPIO、UART、SPI、I2C等)提供了对外设的配置和操作接口。

使用特权

评论回复
15
zhizia4f| | 2024-10-17 13:05 | 只看该作者
标准库函数(如stdio.h中的函数)提供了常用的C语言标准库函数,如字符串处理、数**算等。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

44

主题

2742

帖子

2

粉丝