最新新闻:

单片机怎么转linux「单片机程序运行流程」

时间:2022-11-25 14:41:30来源:搜狐

今天带来单片机怎么转linux「单片机程序运行流程」,关于单片机怎么转linux「单片机程序运行流程」很多人还不知道,现在让我们一起来看看吧!

一 单片机启动流程概述

单片机上电后一直到准备好C语言运行环境并跳转到main函数执行总共经历了5个步骤:

1.内核初始化;

2.强制PC指针指向中断向量表的复位中断向量执行复位中断函数;

3.在复位中断函数中调用 SystemInit 函数,初始化时钟,配置中断向量表等

4.调用 __main 函数完成全局/静态变量的初始化和重定位工作,初始化堆栈和库函数

5.跳转到main函数中执行

二 内核初始化

在单片机上电后首先会进行一系列内核的初始化,关于这部分工作我们只需要了解即可,在内核初始化的过程中主要做了以下几件事情:

1.内核复位和NVIC寄存器部分清零;

2.内核设置堆栈:内核从向量表0地址读出堆栈地址,并设置主堆栈指针(SP_main);

3.设置PC和LR寄存器

a. LR设置未初始复位值0xFFFF FFFF

b. 单片机的内部硬件机制自动将PC指针定位到中断向量表的复位中断向量出,把复位中断函数Reset_Handler的地址赋值给PC指针,然后跳转执行Reset_Handler。

三 复位中断函数 Reset_Handler

在内核复位的最后一步,将PC指针指向了复位中断向量,而复位中断服务函数中的内容才是我们真正需要关心的内容。查看IAR环境中的* .s 单片机汇编启动文件有以下一段内容:

Reset_Handler PROC

EXPORT Reset_Handler [WEAK]

IMPORT __main

IMPORT SystemInit

LDR R0, =SystemInit ;加载SystemInit的地址到寄存器R0中

BLX R0 ;跳转R0中的地址执行(执行SystemInit函数)

LDR R0, =__main ;加载SystemInit的地址到寄存器R0中

BX R0 ;跳转R0中的地址执行(执行__main函数)

ENDP

1

2

3

4

5

6

7

8

9

上面的代码就是Reset_Handler的中断服务函数,可以看到在服务中断函数中先使用 IMPORT声明了两个函数 __main,SystemInit,然后顺序跳转执行SystemInit和**__main**函数。下面我们再来了解一下这两个函数具体干了些什么事情:

SystemInit 函数:

在system_stm32f4xx.c文件中我们可以看到该函数的定义,该函数主要干了以下两件事情:

1.初始化时钟:SYSCLK,HCLK,PCLK2 and PCLK1 prescalers

2.配置中断向量表:中断向量表的定位是在 FLASH 还是 SRAM,是否需要偏移)

注意:可以通过system_stm32f4xx文件中的宏定义修改系统时钟频率(通过设置锁相环的相关系数),中断向量表的地址(位于SRAM还是Flsah,是否偏移,偏移地址多少等参数)

__main()函数(在IAR中是 __iar_program_start ):

该函数被封装进了编译器的库中,所以不同的IDE该函数的名称有所区别,但所实现的功能大致类似:

1.完成全局变量/静态变量/常量的初始化和重定位工作:

a. 跳转进入__scatterload_rt2函数:通过设置四个寄存器来配置待copy内容(静态变量、全局变量、常量)的的加载域和运行域,设置待copy内容的大小,为后续__scatterload_cpy()函数服务。

b. 跳转进入__scatterload_cpy函数,完成静态变量、全局变量、常量的从flash到SRAM的重定位。

c. 跳转进入__scatterload_zeroinit函数,完成未初始化的全局变量的初始化。

2.初始化堆栈(这里指程序栈)和库函数:

跳转进入__user_steup_stackheap函数:调用**__user_libspac__user_libspace**为C库保持了静态数据。这是一个96字节,0初始化的数据块,该块由C库创建。在C库初始化期间可以用来当做临时栈。再调用 __user_initial_stackheap 用户的初始化堆栈函数,实现用户的堆栈的配置,调用 _fp_init 和 __rt_fp_status_addr (C库函数) 两个函数调用实现浮点运算的支持。

3.程序的跳转,进入main()函数:

跳转进入用户的main函数

注意:

未初始化和初始值为零的全局变量,静态变量一般在RAM中, 初始值不为零的全局变量/静态变量 一般在FLASH中。

因为Flash不能随机写(只能写0,不能写1),所以一般会在程序运行之前将初始值不为零的全局变量重定位到RAM中。

全局变量和常量的地址在编译时都已经被分配好了(所以能够在 .map 文件中看到), 而局部变量则是程序运行时在栈中创建的,栈空间大小可以在IDE中设置。

单片机启动时,不需要用将代码从ROM搬移到RAM ,而 ARM 则需要。单片机程序执行的过程分三个步骤:取执行->分析指令->执行指令。取指令的任务是:根据 PC的值从程序存储器读出指令,送到指令寄存器。然后分析执行执行。这样单片机就从内部程序存储器去代码指令,从 RAM 存取相关数据。要知道RAM取数的速度是远高于ROM的,但是单片机因为本身运行频率不高,所以从ROM取指令慢并不影响。而ARM不同,CPU运行的频率高,远大于从 ROM读写的速度,所以一般有大型的操作系统时,都需要将代码部分拷贝到RAM中再执行。

————————————————

版权声明:本文为CSDN博主「GWen9」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/aa386447225/article/details/109546384

声明:文章仅代表原作者观点,不代表本站立场;如有侵权、违规,可直接反馈本站,我们将会作修改或删除处理。

图文推荐

热点排行

精彩文章

热门推荐