【散文诗】单片机程序基础

这篇具有很好参考价值的文章主要介绍了【散文诗】单片机程序基础。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、压栈、出栈

在单片机中,通常使用堆栈(或称为栈)来保存程序执行时的现场信息。堆栈是一种数据结构,在内存中按照“先进后出”的顺序进行操作。当程序执行到一个函数调用时,它会将当前的指令地址和寄存器等现场信息保存到堆栈中,并跳转到函数的入口处继续执行。当函数执行结束后,它会从堆栈中取回之前保存的现场信息,恢复程序执行的状态。

当发生函数调用、中断处理、缓冲区溢出、递归函数时会进行压栈,结束时会进行出栈。


二、函数调用

函数调用流程:保存现场 --> 函数调用 --> 执行函数 --> 返回结果 --> 恢复现场

保存现场后,进行函数调用时,以下内容依次会被保存到堆栈中:

  1. 函数返回地址:将下一条指令地址压入堆栈,以便在子程序执行完毕后能够正常返回。
  2. 函数参数:将调用函数时传递的参数压入堆栈中,参数从右往左按顺序排列。
  3. 执行环境信息:函数内部定义的局部变量、临时变量、寄存器状态等信息。

执行完后函数的返回值讲存放到之前预留的位置上,并恢复现场,恢复原来的指令地址和执行状态。


三、中断响应

在执行主程序时,突然接收到一个中断信号后,立即暂停当前的任务,转而去处理该中断信号所对应的中断服务函数任务。

 每个外设都有一个或多个中断请求引脚(IRQ),每个IRQ又对应一个特定的中断服务函数(ISR),当外设需要向CPU发出请求时,就改变IRQ引脚的电平状态。此时,在单片机中断系统硬件的支持下,CPU会立即停下来执行相对应的中断服务函数,以处理该中断请求。


四、回调函数和函数调用的区别

  • 回调函数:一般作为参数传入到其他函数中,在特定条件下被执行。如在主程序中传递一个函数指针,并且由另一个函数或事件触发后异步执行该函数。
  • 函数调用:在主程序中直接调用一个函数,,一般由程序员直接调用,并且在一般情况下,是同步的,也就是说,当函数被调用后,在该函数执行完毕前,程序会一直等待。

 回调函数的可重用性很高,因为它们不依赖于任何具体的环境。相反,普通的函数可能会涉及到环境变量和局部变量等问题。


五、回调函数和中断函数的区别

  • 回调函数:在程序中以普通函数的形式定义,并且可以在任何时候被调用。当回调函数作为参数传递至其他函数或事件处理器时,它既可以同步执行也可以异步执行。
  • 中断函数:由硬件或操作系统发起的一种机制,在特定的事件(例如外部设备请求、错误、时钟等)发生时被自动触发。中断函数通常需要快速响应,立即执行,并尽可能地短暂运行,因此其实现上有着很多限制。

 虽然回调函数和中断函数都是在事件发生时被调用的,但由于回调函数是普通的程序代码而非由硬件或操作系统直接触发,因此其实现上更加灵活和可控。


六、单片机的编译流程

① 编译预处理:读取 C 源程序,对其中的伪指令(以#开头的指令)和特殊符号进行处理。

  1. 宏定义指令,如#define Name TokenString,#undef等。
    对于前一个伪指令,预编译所要做的是将程序中的所有Name用TokenString替换,但作为字符串常量的 Name则不被替换。对于后者,则将取消对某个宏的定义,使以后该串的出现不再被替换。
  2. 条件编译指令,如#ifdef,#ifndef,#else,#elif,#endif等。
    这些伪指令的引入使得程序员可以通过定义不同的宏来决定编译程序对哪些代码进行处理。预编译程序将根据有关的文件,将那些不必要的代码过滤掉
  3. 头文件包含指令,如#include "FileName"或者#include <FileName>等。
    在头文件中一般用伪指令#define定义了大量的宏(最常见的是字符常量),同时包含有各种外部符号的声明。
    采用头文件的目的主要是为了使某些定义可以供多个不同的C源程序使用。因为在需要用到这些定义的C源程序中,只需加上一条#include语句即可,而不必再在此文件中将这些定义重复一遍。预编译程序将把头文件中的定义统统都加入到它所产生的输出文件中,以供编译程序对之进行处理。
  4. 特殊符号,预编译程序可以识别一些特殊的符号。

② 编译器编译:编译器对预处理后的源代码进行语法分析、语义检查等操作,并将其翻译成汇编代码。

③ 汇编器汇编:将汇编代码转换成机器指令,生成目标文件(OBJ文件)。

④ 链接:将有关的目标文件彼此相连接,也即将在一个文件中引用的符号同该符号在另外一个文件中的定义连接起来,使得所有的这些目标文件成为一个能够诶操作系统装入执行的统一整体,一般有 elf、coff、mach-o 等格式。

⑤ 转换文件:最后生成可直接下载到芯片并且能够运行在芯片上的 hex 或 bin 文件。

Linux 下交叉编译流程

① ~ ③ 将 led.s 编译为对应的 .o 文件

arm-linux-gnueabihf-gcc -g -c led.s -o led.o

-g:产生调试信息
-c:编译源文件,但是不链接
-o:指定编译产生的文件名字

④ 将众多的 .o 文件链接到一个指定的链接位置,本实验链接地址为:0X87800000

arm-linux-gnueabihf-ld -Ttext 0X87800000 led.o -o led.elf

-Ttext:指定链接地址
-o:指定链接生成的 elf 文件名,命名为 led.elf

⑤ 将 .elf 文件转换为 .bin 文件

arm-linux-gnueabihf-objcopy -O binary -S -g led.elf led.bin

-O:指定以什么格式输出,“ binary”表示以二进制格式输出
-S:不要复制源文件中的重定位信息和符号信息
-g:不复制源文件中的调试信息


七、ARM 下的 elf 格式

elf 文件是一种可执行文件和可链接目标文件通用的二进制格式。它包含了程序代码、数据、符号表、重定位信息等重要的元素,可以在ARM平台上运行并与操作系统进行交互。

在ARM下,elf 文件有三种类型:

①:可重定位文件(Relocatable File):根据链接地址,确定代码和数据的位置、大小和属性等,最终将可执行文件拷贝到指定的链接地址进行执行。

②:可执行文件(Executable File):经过链接后生成的最终可执行文件。

③:共享库(Shared Object File):类似于Windows下的DLL(动态链接库),多个程序共享同一份代码和数据段。

elf 文件头部描述了文件类型、目标体系结构、入口地址等信息。在头部后面是各个段(Section)和段头表(Section Header Table),段是一个逻辑单元,描述了不同类型的内容。例如.text段包含编译器生成的指令代码,.data段包含静态数据等。每个段都有一个对应的段头表项来描述它们在内存中应该放置的位置和大小等信息。


八、ARM 下程序启动流程

在 ARM 下执行程序,一般是 ARM 处理器会先从烧入程序里读取 elf 文件头部(即可重定位文件,从中可得知链接地址,明确可执行文件该拷贝到 DDR、Flash 或 EEPROM 等非易失性存储器中的地址),ARM 处理器再进行可执行文件的拷贝,在拷贝过程中,ARM 处理器还需要处理一些细节,比如解压缩、填充空白区域等,以保证可执行文件能正确运行,然后跳至可执行文件启动烧入的程序,一般可执行文件的启动文件为汇编文件,在其设置中断向量表,初始化 sp 指针等操作后,再跳至 C 语言中的 main 函数。


九、ARM 下的汇编调用 C 语言函数传参

ARM 下的汇编调用 C 语言函数传参有两种方法:文章来源地址https://www.toymoban.com/news/detail-416586.html

  1. 参数依次存储在寄存器 r0、r1、r2 、r3中和栈中:前四个参数分别从左到右存储在 r0、r1、r2 和 r3 寄存器中,如果还有更多的参数,则需要将它们依次压入栈中。C 语言函数在执行时,可以通过访问 SP 寄存器来获取栈中的参数值。
  2. 参数全部存储在栈中:所有函数参数都按照从右到左的顺序压入栈中,然后 C 语言函数在执行时通过访问 SP 寄存器来获取栈中的参数值。

    C 语言函数的返回值一般存在r0寄存器中。

到了这里,关于【散文诗】单片机程序基础的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【全栈计划 —— 单片机】——Part_01 单片机数字电路基础+C51基础概念

    既然是搞硬件,面对的是开发板,肉眼可见的是电器元件和错综复杂的电路,那么具备一定的电路知识是必须的啦~。什么?以前学出心理阴影,害怕数电模电了,好巧嗷,我之前也是学出心理阴影了。 本篇博客只是浅浅的提一些基础的数电知识的,不会特别深奥喔~掌握我用

    2023年04月09日
    浏览(32)
  • 【单片机】51单片机串口的收发实验,串口程序

    这段代码是使用C语言编写的用于8051单片机的串口通信程序。它实现了以下功能: 引入必要的头文件,包括reg52.h、intrins.h、string.h、stdio.h和stdlib.h。 定义了常量FSOC和BAUD,分别表示系统时钟频率和波特率。 定义了一个发送数据的函数send,该函数将数据发送到串口,等待数据

    2024年02月14日
    浏览(37)
  • 51单片机电路基础

    单片机是一种数字集成芯片,数字电路中只有两种电平:高电平和低电平。 高电平: 5V 低电平: 0V TTL电平信号被利用的最多是因为通常数据表示采用二进制,5V等价于逻辑“1”,0V等价于逻辑“0”。 TTL电平规定高电平输出电压2.4V,低电平输出电压0.4V。 而计算机串口使用的是

    2024年02月02日
    浏览(35)
  • 嵌入式(二)单片机基础 | 单片机特点 内部结构 最小系统 电源 晶振 复位

    上一篇文章我们介绍了嵌入式系统 嵌入式系统(Embedded System)是一种特定用途的计算机系统,它通常嵌入在更大的产品或系统中,用于控制、监测或执行特定的任务。这些系统通常由硬件和软件组成,旨在满足特定的需求,如嵌入在家电、汽车、医疗设备、工业自动化、消费

    2024年02月02日
    浏览(98)
  • 【单片机基础】使用51单片机制作函数信号发生器(DAC0832使用仿真)

    单片机作为一个数字电路系统,当需要采集外界模拟量的使用需要进行AD转换,将模拟量转换成数字量,供单片机使用。51单片机需要外部配置一个AD转换芯片来进行模拟量的采集,如我之前写了一篇ADC0832的使用。高级的单片机如STC12和STM32已经集成了AD转换功能,只需简单配置

    2024年02月08日
    浏览(36)
  • 【单片机】51单片机,TLC2543,驱动程序,读取adc

    TLC2543 是一款 12 位精密模数转换器 (ADC)。 1~9、11、12——AIN0~AIN10为模拟输入端; 15——CS 为片选端; 17——DIN 为串行数据输入端;(控制字输入端,用于选择转换及输出数据格式) 16——DOUT为A/D转换结果的三态串行输出端;(A/D转换结果的输出端。) 19——EOC为转换结束端

    2024年02月14日
    浏览(37)
  • 单片机】51单片机,TLC2543,驱动程序,读取adc

    TLC2543 是一款 12 位精密模数转换器 (ADC)。 1~9、11、12——AIN0~AIN10为模拟输入端; 15——CS 为片选端; 17——DIN 为串行数据输入端;(控制字输入端,用于选择转换及输出数据格式) 16——DOUT为A/D转换结果的三态串行输出端;(A/D转换结果的输出端。) 19——EOC为转换结束端

    2024年02月14日
    浏览(44)
  • 32单片机基础:GPIO输入

    按键介绍: 两种方式,我们一般用下接的方式。 第一个图:注意点。当按键按下,PA0接地,被置为低电平, 但是一旦按键松手,PA0悬空,引脚电压不确定。所以无论怎么读引脚也不知道知否被按下,所以为了解决这个问题,所以必须要求PA0是上拉输入的模式,这样引脚悬空

    2024年02月22日
    浏览(33)
  • 32单片机基础:GPIO输出

    目录 简介: GPIO输出的八种模式 STM32的GPIO工作方式 GPIO支持4种输入模式: GPIO支持4种输出模式: 浮空输入模式 上拉输入模式 下拉输入模式 模拟输入模式: 开漏输出模式:(PMOS无效,就是开漏输出,) 开漏复用输出模式 (P-MOS和N-MOS都有效) 推挽输出模式 推挽复用输出模

    2024年02月21日
    浏览(33)
  • 单片机第一季:零基础2

    目录 1,第三章 2,第四章 51单片机发展史: 51单片机由Intel公司设计诞生 (1)1971年,Intel推出4位单片机Intel4004 (2)1972年,Intel推出8位单片机Intel8008 (3)期间还有别的公司如Motorola、Zilog等推出各自的单片机系列 (4)80年代初,Intel推出MCS-51系列单片机(即Intel8051) (5)后来Intel继续做

    2024年02月13日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包