单片机如何从上电复位执行 到 mai n 函数?
\\
\
插播一条:文章末尾有惊喜
哟
~///
从事嵌入式开发的搭档可能会思考过一个问题,我们一般都是使用芯片厂商提供的驱动库和初始化文件,直接 从 mai n 函数初始写程序,那么系统上电之后,程序怎么引导 进 mai n 函数执行的呢?还有,系统上电之 后 RA M 的数据是随机的,那么定义的全局变量的初始值又是怎么实现的呢?
下面我将带着这两个问题, 以 Cortex- M 架构为例,采 用 IAR EWAR M 作为编译工具链,从系统上电之后执行的第一条代码初始,梳理系统的启动过程,了解编译器在此期间所做的工作。其他的工具链, 如 Kei l 和 GC C 在系统初始化过程所做的工作也是相似的,但详细的实现有所差异。
1 、启动文件
芯片厂商提供的启动文件,一般是采用汇编语言编写,少数 用 C 语言。在启动文件中一般至少存在下面两个局部内容:
1 、向量表
2 、默认的中断和异常处理程序
向量表实际上是一个数组,放置在存储器的零地址,每个元素存储的是各个中断或异常处理程序的入口地址。 以 STM32F10 7 芯片基 于 IA R 工具的启动文件为例:
文件的开头定义了一个名 为 __vector_tabl e 的全局符号, “ DATA ” 的作用是在代码段中定义一个数据区,用作向量表。数据区的内容是使 用 DC D 指令定义 的 3 2 位宽度常量,除了第一 个 sfe(CSTACK ) 比较特殊以为,其他的常量都是异常和中断效劳程序的地 址 ( 在编译时函数名会被替换成函数的入口地 址 ) 。 sfe(CSTACK ) 是 IA R 汇编器段操作,用于获取 段 (section ) 的完毕地址,在这里意欲何为呢?
实际上这是获取堆栈基地址的操作 。 IA R 在链接器脚 本 (*.icf ) 文件中定义堆栈,实际是定义了一个名为 “ CSTACK ” 的空闲 块 (block ) ,如下图的脚本命令所示。所谓的块就是保留一段不间断的地址空间,用来作为堆栈或者堆。当然,块也能够是用内容的,例如能够用来管理段,但不在今天的探讨范围。
我们知 道 Cortex- M 架构的堆栈模型是满减栈,堆栈从高地址向低地址增长,因此堆栈的基地址 是 CSTAC K 的完毕地址。
向量表的第一个元素是栈基址这是 由 Cortex- M 架构定义的。系统上电后硬件自动从向量表中获取,并设置主堆栈指 针 MS P ,而不是像其 他 AR M 架构,堆栈指针须要通过软件来设置。
向量表中第二个元素是复位异 常 (Reset_Handler ) 的入口地址。系统上电后,硬件自动 从 __vector_table + 4 的位置读取,并从读取到的地址初始执行。系统上电 后 CP U 执行的第一条 是 Reset_Handle r 函数的第一条语句。
上面 的 THUM B 命令表示接下来的代码采 用 THUM B 模 式 (Cortex- M 只支 持 Thumb- 2 指令 集 ) ; SECTIO N 用于定义一个段,段名为 “ .ResetHandler ” ,段的类型是代 码 (CODE ) ; REODE R 指示用给定的名称开启一个新的段 ; ROO T 指示链接器,当段内的符号没有被引用,链接器也不能够丢弃这个段。
PUBWEA K 是弱定义,假如用户在其他位置编写了中断处理函数,在连接时实际链接用户所编写的,启动文件中用汇编写的效劳函数会忽略。之所以要在启动文件中以弱定义的方式编写全部的异常和中断效劳函数,是为了防止用户在没有编写效劳函数的情况下开启并触发了中断,导致系统的不确定。
2 、系统初始化过程
在 EWAR M 的工 程 Options > Debugger > Setu p 中将 “ Run to ” 勾选取消,这样在进入调试之后就会停第一条要执行的代码的位置:
进入调试之后会停在启动文 件 Reset_Handle r 函数第一条汇编指令位置:
此时,通过寄存器观察窗口查 看 S P 的值 为 0x2000982 0 。通过链接时生成 的 ma p 文件,查 看 CSTAC K 的地址范围 , 0x2000982 0 正好 是 CSTAC K 的完毕地址。有 了 MS P , C 代码就能运行了。
ystemIni t 函数是芯片厂商依 据 AR M 的 CMSI S 规范提供的一个系统根底配置函数,配置根底的时钟系统和向量表重定位等。这里 的 LD R 是伪指令,它 将 SystemIni t 函数的地址加载到寄存 器 R 0 ,实际上是通 过 P C 偏移寻址来获 取 SystemIni t 的地址。
从上面的图能够发现一个问题,在反汇编窗口能够观察 到 SystemIni t 的地址 是 0x2000015 0 ,但加载 到 R 0 寄存器后却 是 0x2000015 1 。这是由于在使用跳转指令更 新 P C 时,须要 置 P C 的 LS B 为 1 ,以表 示 THUM B 模式,由 于 Cortex- M 不支 持 AR M 模式,因 此 LS B 总 是 1 。
执行完芯片厂商提供 的 SystemIni t 函数之后,跳转 到 __iar_program_star t ,这 是 IA R 编译器提供的初始化代码的入口。
__iar_program_star t 首先会执行两个函数 : __iar_init_cor e 和 __iar_init_vf p ,能够完成一 些 CP U 和 FP U 相关的初始化操作,在某 些 AR M 架构打包好的运行时库会有这两个函数,用户也能够重写这两个函数来自己实现一些相关的操作。
之后,跳转 到 __cmai n 函数执行。 在 __cmai n 中调用了一 个 __low_level_ini t 函数,该函数专门用于提供给用户编写一个初阶的初始化操作,它在全局变量初始化之前执行,例如可用 在 __low_level_ini t 中初始 化 SDRA M ,这样就能够将全局变量定义 到 SDRA M 中使用。
__low_level_ini t 能够在任意 的 C 文件中编写,注意它的返回值,假如返 回 0 ,后续就会跳过变量初始化操作,正常一般都是返 回 1 。
3 、全局变量的初始化
此后进入 到 __iar_data_init 3 函数,在这里会完成所有具有初始值的全 局 / 静态变量的赋值,以及零初始化全 局 / 静态变量的清零操作,分别调 用 __iar_copy_init 3 和 __iar_zero_init 3 ,将保存 在 RO M 区由链接器生成的变量初始值复制到变量的地址。注意,新 的 EWAR M 版本默认变量初始化操作可能会采用压缩算法,实际变量初始化调用的函数可能有区别。
在全局变量未初始化之前,通 过 watc h 窗口能够看到,变量的值都是随机数。
在 __iar_data_init 3 执行完成后,全部变量的初值赋值已经完成。
在 __cmai n 函数的最后,跳转到用户 的 mai n 函数,最终初始用户的代码执行。
了解了编译器所提供的初始化过程和处理器架构,我们能够依据自己的需求定制系统的初始化。
例如,在进 入 __iar_program_star t 之前,就能够执行必要的硬件初始化操作,能够用汇编写,也能够 用 C 写。还能够手动控制变量的初始化操作,自己实现变量的初始化。甚至,完全不采 用 IA R 编译器提供的初始化操作,自己从复位序列引导 至 mai n 函数那也是能够的。
硬件开发工具:
Altium Designer 17.1
编程开发工具:
KEIL 4
程序*载下**工具:
STC-ISP
串口驱动:
CH341SER
单片机最小系统介绍
单片机 ( Microcontroller s )是一种集成电路芯片,是采用超大规模集成电路技术把具有数据处理才能的中央处理 器 CP U 、随机存储 器 RA M 、只读存储 器 RO M 、多 种 I/ O 口和中断系统、定时 器 / 计数器等功能(可能还包括显示驱动电路、脉宽调制电路、模拟多路转换器 、 A/ D 转换器等电路)集成到一块硅片上构成的一个小而完善的微型计算机系统,在工业控制领域广泛应用。从上世 纪 8 0 年代,由当时 的 4 位 、 8 位单片机,开展到此时 的 300 M 的高速单片机。本文的单片机特 指 5 1 单片机,详细芯片型号 是 STC89C52R C 。需注 意 STC89C51,STC89C5 2 , AT89C51,AT89C5 2 都 是 5 1 单片机的一种详细芯片型号。
最小系统组成:
5 1 单片机最小系统:单片机、复位电路、晶振(时钟)电路、电源
最小系统用到的引脚
1 、主电源引脚 ( 2 根)
VC C :电源输写,接 + 5 V 电源
GN D :接地线
2 、外接晶振引脚 ( 2 根)
XTAL 1 :片内振荡电路的输写端
XTAL 2 :片内振荡电路的输出端
3 、控制引脚 ( 4 根)
RST/VP P :复位引脚
电源
设计使用的电源接口 是 DC 5 V 。 US B 座能够查到手机充电口,电 脑 US B 端取电。接好线路后,按下电源开关,单片机即可初始工作。
输写电源及启动按键
DC 5 V 连接线
复位电路
复位电路
在电路图中,电容的的大小 是 10u f ,电阻的大小 是 10 k 。
在 5 V 正常工作 的 5 1 单片机中小 于 1.5 V 的电压信号为低电平信号,而大 于 1.5 V 的电压信号为高电平信号。能够算出电容充电到电源电压 的 0. 7 倍,即电容两端电压 为 3.5 V 、电阻两端电压 为 1.5 V 时,须要的时长约 为 T=RC=10K*10UF=0.1 S 。
也就是说在单片机上电启动 的 0.1 S 内,电容两端的电压 从 0-3.5 V 不断增加,这个时 候 10 K 电阻两端的电压为 从 5-1.5 V 不断减少(串联电路各处电压之和为总电压),所 以 RS T 引脚所接管到的电压 是 5V-1.5 V 的过程,也就是高电平到低电平的过程。
单片 机 RS T 引脚是高电平有效,即复位;低电平没效,即单片机正常工作。所以在开 机 0.1 S 内,单片机系 统 RS T 引脚接管到了时长 为 0.1 S 左右的高电平信号,所以实现了自动复位。
在单片机启 动 0.1 S 后,电 容 C 两端的电压持续充电 为 5 V ,这是时 候 10 K 电阻两端的电压接近 于 0 V , RS T 处于低电平所以系统正常工作。当按键按下的时候,开关导通,这个时候电容两端构成了一个回路,电容被短路,所以在按键按下的这个过程中,电容初始释放之前充的电量。随着时长的推移,电容的电压 在 0.1 S 内, 从 5 V 释放到变为 了 1.5 V ,甚至更小。依据串联电路电压为各处之和,这个时 候 10 K 电阻两端的电压 为 3.5 V ,甚至更大,所 以 RS T 引脚又接管到高电平。单片机系统自动复位。
晶振电路
晶振电路
晶振根本概 念 晶振全名叫晶体振荡器,每个单片机系统里都有晶振,晶振是由石英晶体经过加工并镀上电极而做成的,主要的特性就是通电后会产生机械震荡,能够给单片机提供稳定的时钟源,晶振提供时钟频次越高,单片机的运行速度也就越快 。 晶振用一种能把电能和机械能互相转化的晶体在共振的状态下工作,以提供稳定,精确的单频振荡。
晶振起振后 , 产生的振动信号会通 过 XTAL 1 引脚 , 依次经过振荡器和时钟发生器的处理,得到机器周期信号,作为指令操作的依据 。 5 1 单片机常用的晶振 是 12 M 和 11.0592M
元器件清单及样机焊接
元器件清单
Comment Description Designator Footprint LibRef Quantity
30P 陶瓷电容 C2, C3 CAP-2.54 Cap 2
10uF/16V 直插电解电容 CE1 CAP 1.5*4*8 CE 1
CON9 直插排 阻 10K J0 R SIP9-2.54 CON9 1
CON2 2 Pin 排针 J4 HDR2.54-LI-2P CON2 1
HEADER 4 4 Pin 排针 JP3, P6 HDR2.54-LI-4P HEADER 4 2
红色 直 插 5mm LED LED1, LED2 LED 5MM-R LED-5MM 2
CON8 4 Pin 排针 P0, P1, P2, P3 HDR2.54-LI-8P CON8 4
KEY 自锁按键 POWER_BUTTON SW-8X8X8 HEADER 3X2 1
DC 5 V 电源 DC 5 V 插座 PW_5V DC05 HEADER 3 1
10K 电阻 R1 AXIAL0.3 RES2 1
2K 电阻 R2, R3 AXIAL0.3 RES2 2
SW-PB 轻触按键 S1 SW-0606 SW-PB 1
STC89C52RC 8-Bit Microcontroller with 4K Flash ROM U1 DIP40 AT89C51 1
11.0592M 晶振 Y1 OSC HC-49S CRYSTAL 1
假如不想直接焊芯片到板子,能够买个下图黑色的紧锁座。规格 选 DIP40
PC B 板制作
方 法 1 :学校实验室常用 的 DI Y 腐蚀电路板制作(略)
方 法 2 :外发给专业 的 PC B 工厂。举荐嘉立 创 https://www.jlc.com/#
可代发,须要请私信
空板正反面:
空板
焊接注意事项
直插电解电容, 和 LE D 灯是有正负极之分的。
电解电容正负极分辨:
1 . 看实物套管
2 . 看引脚长短:
电解电容正极引线比较长、负极稍短
LE D 灯正负极分辨:
1 . 引脚长短也能够看出来,发光二极管的正负极,引脚长的为正极,短的为负极。
2 . 万用表打到二极管档,分别短 接 LE D 灯引脚,假如亮,红表笔接的是正极。
最终实物:
焊接好的实物如图
程序烧录及测试
测试用 的 5 1 单片机型号 是 STC89C52R C ,是国产品牌宏晶科 技 ST C 量产 的 805 1 单片机。
测试代码
#include
#include
/ / 数据类型定义
typedef unsigned char uchar;
typedef unsigned int uint;
uchar flag1s = 0;
uint one_sec_flag = 0;
sbit TEST_LED=P1^0;
void main()
{
EA=1; / / 开总中断
TMOD=0X01;//T 0 的工作模式为模 式 1
TH0=0X4C;
TL0=0X00;//11.0592 M 晶 振 50m s 定时初值
ET0=1; / / 允许定时 器 1 中断
TR0=1;/ / 启动定时 器 0
while(1)
{
if(flag1s) / / 一秒刷新一次
{
TEST_LED = 0;
}else{
TEST_LED = 1;
}
}
}
void Timer0() interrupt 1
{
TH0=0XBB;
TL0=0X00;
if(++one_sec_flag
return;/ / 提前完毕函数
}
if(flag1s)
{
flag1s = 0;
}else{
flag1s = 1;
}
one_sec_flag=0;
}
编译之后产 生 test.he x 烧录文件。
*载下**器及*载下**驱动
STC89C5 2 单片机*载下**器实际上就 是 US B 转 TT L 串口,如下图所示
某宝上的*载下**器
驱动:压缩包中 的 CH341SER.EXE
先安装驱动才能*载下**代码到单片机中。
程序*载下**
硬件准备:
*载下**器 的 RX D 连接芯片 的 TXD(P30) , *载下**器 的 TX D 连接芯片 的 RXD(P31) , 本设计引出了芯片 的 RX D 和 TX D ,如上图所示连接即可。
软件准备:
STC-ISP.ex e 双击翻开,*载下**步骤
1 选择选择单片机型号
2 . 选择*载下**器的串口
3 . 翻开编译生成 的 HE X 文件
4 . 点击*载下**
*载下**界面
等待
此时,按下电源开关给单片机上电,*载下**软件会识别出单片机,然后自动*载下**程序。*载下**成功后会有提醒。
烧写成功
测试效果:测 试 LE D 灯一秒间隔闪烁。
新一代烧写工 具 - STM32CubeProgrammer
STM32CubeProgramme r ( STM32CubePro g ) 是 STM3 2 微控制器的专用编程工具 。 STM3 2 用户都知道,当完成程序调试,须要对芯片进行程序代码烧录编程,一般会有三个选择 : 通过调试接口 【 JTAG/SW D 】 ?
A I 电堂发表 于 STM32...
进 修 STM3 2 单片机,绕不开的串口
刚初始学单片机的你,是不是会因用程序 把 LE D 点亮而感到高兴,会因用程序把数码管点亮而感到高兴。这是好事,这也是想继续进修下去的动力 。 但是数据相关的实验是进修单片机 和 STM3 2 的一道 坎 ?
SugarlesS
MCS-5 1 系列单片机串口通讯实 验 ( 2)
1 . 实验目 标 1) 掌 握 5 1 单片机串行通讯调试方 法 2) 会简略的串行通讯协议编 写 2 . 实验器 材 1 ) Widow s 操作系统的电脑 。 2) 调试软 件 kei l 仿真实验 版 kei l 外挂串口调试工具软 件 --ssco m 虚拟调试串口
彩蛋:最近有同学跟我要单片机的资料,我特意花几个月时间,总结了我 1 0 年产品研发经验,资料包几乎覆盖 了 C 语言、单片机、模电数电、原理图 和 PC B 设计、单片机高级编程等等,非常适合初学者入门和进阶。除此以外,再含泪分享我压箱底 的 2 2 个热门开源项目,包含源 码 + 原理 图 +PCB + 说明文档,不是市面上打包卖的那种课程,我认为教程多未必是好事 , 1 0 年前我自学快,除了自身执行力以外,还有就是教程少。不要害羞做伸手*党**,等你一个小红点。后期我也会组建一些纯技术交流的小圈子,让大家能认识更多的大佬,有个好的圈子,你对行业的认知一定是最前沿的。
