嵌入式单片机合集(第9期)——聚焦51C系列

我自己的原文哦~     https://blog.51cto.com/whaosoft/13884964

一、单片机中hex、bin文件的区别

单片机程序编译之后,除了生成hex文件之外还生成了bin文件,实际它们都是单片机的下载文件,下文介绍它们的区别。

Hex

   Hex文件包含地址信息。

    在用ISP方式烧写程序时,有这样的经验:

  • 选择单片机型号
  • 选择串口号
  • 设置波特率(或者默认)
  • 选择下载的文件
  • 点击下载按钮下载
  •     在串口工具中,操作如下图红框所示。

        经过这几步后,程序下载工作就完成了,在以上的步骤中我们并没有选择要把程序下载到单片机的哪块内存中,即不需要设置地址。因为HEX文件内部的信息已经包括了地址。

        单片机一般是下载hex文件。

    BIN

        BIN文件格式只包括了数据本身,没有包含地址。烧写BIN文件的时候,用户是一定需要指定地址信息的。

        所以在下载bin文件时需要选择内存的起始地址和终止地址,即要把bin文件下载到指定的内存空间。

        通常需要指定程序内存地址的芯片为ARM芯片和DSP芯片。

    文件大小    对于bin文件,通过右键属性查看到的文件的大小就是数据的实际大小。

        而对HEX文件而言,你看到的文件大小并不是实际的数据的大小。一是因为HEX文件是用ASCII来表示数据,二是因为HEX文件本身还包括别的附加信息。

    二、HEX文件的数据格式

    Intel HEX文件是由一行行符合Intel HEX文件格式的文本所构成的ASCII文本文件。在Intel HEX文件中,每一行包含一个HEX记录。这些记录由对应机器语言码和/或常量数据的十六进制编码数字组成。Intel HEX文件通常用于传输将被存于ROM或者EPROM中的程序和数据。大多数EPROM编程器或模拟器使用Intel HEX文件。

    ~HEX记录格式

    Intel HEX由任意数量的十六进制记录组成。每个记录包含5个域, 它们按以下格式排列​​[:LLAAAATT[DD…]CC]​​。每一组字母对应一个不同的域, 每一个字母对应一个十六进制编码的数字。每一个域由至少两个十六进制编码数字组成, 它们构成一个字节。

    详细解释如下:

    ​:​​每个Intel HEX记录都由冒号开头。

    ​LL​​是数据长度域,它代表记录当中数据字节(dd)的数量。

    ​AAAA​​是地址域,它代表记录当中数据的起始地址。

    ​TT​​是代表HEX记录类型的域,它可能是以下数据当中的一个:

    ​00​​ – 数据记录

    ​01​​ – 文件结束记录

    ​02​​ – 扩展段地址记录

    ​04​​ – 扩展线性地址记录

    ​DD​​ 是数据域,它代表一个字节的数据。一个记录可以有许多数据字节,记录当中数据字节的数量必须和数据长度域​​LL​​中指定的数字相符。

    ​CC​​是校验和域,它表示这个记录的校验和。校验和的计算是通过将记录当中所有十六进制编码数字对的值相加,以256为模进行以下补足。也就是说LLAAAATT[DD…]CC一共的校验和永远为0。

    ~数据记录格式

    Intel HEX文件由任意数量以回车换行符结束的数据记录组成.

    数据记录外观如下:

    ​[:10246200464C5549442050524F46494C4500464C33]​

    其中:

    ​10​​是这个记录当中数据字节的数量。

    ​2462​​ 是数据将被下载到存储器当中的地址。

    ​00​​是记录类型(数据记录)。

    ​464C…464C​​是数据。

    ​33​​ 是这个记录的校验和的补足码。

    ~扩展线性地址记录(HEX386)格式

    扩展线性地址记录也叫作32位地址记录或HEX386记录。这些记录包含数据地址的高16位。扩展线性地址记录总是有两个数据字节。

    外观如下:

    [:02000004FFFFFC]

    其中:

    ​02​​是这个记录当中数据字节的数量。

    ​0000​​是地址域,对于扩展线性地址记录,这个域总是0000。

    ​04​​是记录类型 04(扩展线性地址记录)。

    ​FFFF​​是地址的高16位。

    ​FC​​是这个记录的校验和的补足码。

    当一个扩展线性地址记录被读取,存储于数据域的扩展线性地址被保存,它被应用于从Intel HEX文件读取来的随后的记录。线性地址保持有效,直到它被另外一个扩展地址记录所改变。

    通过把记录当中的地址域与被移位(16位)的来自扩展线性地址记录的地址数据相加获得数据记录的绝对存储器地址。以下的例子演示了这个过程:

    来自数据记录地址域的地址                2462 扩展线性地址记录的数据域*10000H  +  FFFF0000 ——————— 绝对存储器地址                      FFFF2462

    ~扩展段地址记录(HEX86)

    扩展段地址记录也叫HEX86记录,它包括​​4-19​​位数据地址段。扩展段地址记录总是有两个数据字节。

    外观如下:

    ​[:020000021200EA]​

    其中:

    ​02​​ 是记录当中数据字节的数量。

    ​0000​​是地址域,对于扩展段地址记录,这个域总是0000。

    ​02​​是记录类型 ​​02(扩展段地址记录)​​。

    ​1200​​是地址段。

    ​EA​​是这个记录的校验和的补足码。

    当一个扩展段地址记录被读取,存储于数据域的扩展段地址被保存,它被应用于从Intel HEX文件读取来的随后的记录。段地址保持有效,直到它被另外一个扩展地址记录所改变。

    通过把记录当中的地址域与被移位(4位)的来自扩展段地址记录的地址数据相加获得数据记录的绝对存储器地址。以下的例子演示了这个过程:来自数据记录地址域的地址         2462

    扩展段地址记录数据域*10H    +   12000 —————– 绝对存储器地址               00014462

    ~文件结束(EOF)记录。

    Intel HEX文件必须以文件结束​​(EOF)​​记录结束。这个记录的记录类型域的值必须是01。EOF记录外观总是如下

    ​[:00000001FF]​

    其中:

    ​00​​是记录当中数据字节的数量。

    ​0000​​是数据被下载到存储器当中的地址。在文件结束记录当中地址是没有意义被忽略的。0000H是典型的地址。

    ​01​​是记录类型​​01(文件结束记录)​​。

    ​FF​​是这个记录的校验和的补足码。

    ~Intel HEX文件例子

    下面是一个完整的Intel HEX文件的例子:

    :10001300AC12AD13AE10AF1112002F8E0E8F0F2244
    :10000300E50B250DF509E50A350CF5081200132259
    :03000000020023D8
    :0C002300787FE4F6D8FD7581130200031D
    :10002F00EFF88DF0A4FFEDC5F0CEA42EFEEC88F016
    :04003F00A42EFE22CB
    :00000001FF

    看了这个例子,我自己也打开了之前写的51单片机的hex文件:

    :2000000002000E75210675225B75230200267B007C00900090758140758901758CF1758A45
    :2000200028D28C75A882758CF1758A280BBBFA157B00EC75F00A8485F020F5210CBC64027A
    :200040007C00120051C0E0C0D0120051D0D0D0E032E52193F580D2A2C2A27580FED2A3C29C
    :20006000A3120087E52093F580D2A2C2A27580FDD2A3C2A3120087227D327E287FF81151AA
    :1A008000DFFEDEF8DDF4227E047FF8DFFEDEFA223F065B4F666D7D077F6FBC
    :00000001FF

    ~英文原文

    QUESTION:What is the Intel HEX file format?
    ANSWER:
    8.1 The Intel HEX file is an ASCII text file with lines of text that follow theIntel HEX file format. Each line in an Intel HEX file contains one HEX record.These records are made up of hexadecimal numbers that represent machine language code and/or constant data. Intel HEX files are often used to transfer the program and data that would be stored in a ROM or EPROM. Most EPROM programmers or emulators can use Intel HEX files.
    8.2 Record Format.
    An Intel HEX file is composed of any number of HEX records. Each record is made up of five fields that are arranged in the following format:
    :LLAAAATT[DD…]CC
    Each group of letters corresponds to a different field, and each letter represents a single hexadecimal digit. Each field is composed of at least two hexadecimal digits-which make up a byte-as described below:
    8.2.1 : is the colon that starts every Intel HEX record.
    8.2.2 LL is the record-length field that represents the number of data bytes (dd) in the record.
    8.2.3 AAAA is the address field that represents the starting address for subsequent data in the record.
    8.2.4 TT is the field that represents the HEX record type, which may be one of the following:
    8.2.4.1 00 - data record
    8.2.4.2 01 - end-of-file record
    8.2.4.3 02 - extended segment address record
    8.2.4.4 04 - extended linear address record
    8.2.5 DD is a data field that represents one byte of data. A record may have multiple data bytes. The number of data bytes in the record must match the number specified by the ll field.
    8.2.6 CC is the checksum field that represents the checksum of the record. The checksum is calculated by summing the values of all hexadecimal digit pairs in the record modulo 256 and taking the two's complement.
    8.3 Data Records.
    The Intel HEX file is made up of any number of data records that are terminated with a carriage return and a linefeed. Data records appear as follows:
    :10246200464C5549442050524F46494C4500464C33
    where:
    8.3.1 10 is the number of data bytes in the record.
    8.3.2 2462 is the address where the data are to be located in memory.
    8.3.3 00 is the record type 00 (a data record).
    8.3.4 464C...464C is the data.
    8.3.5 33 is the checksum of the record.
    8.4 Extended Linear Address Records (HEX386).
    Extended linear address records are also known as 32-bit address records and HEX386 records. These records contain the upper 16 bits (bits 16-31) of the data address. The extended linear address record always has two data bytes and appears as follows:
    :02000004FFFFFC
    where:
    8.4.1 02 is the number of data bytes in the record.
    8.4.2 0000 is the address field. For the extended linear address record, this field is always 0000.
    8.4.3 04 is the record type 04 (an extended linear address record).
    8.4.4 FFFF is the upper 16 bits of the address.
    8.4.5 FC is the checksum of the record and is calculated as 01h + NOT(02h + 00h + 00h + 04h + FFh + FFh).
    8.4.6 When an extended linear address record is read, the extended linear address stored in the data field is saved and is applied to subsequent records read from the Intel HEX file. The linear address remains effective until changed by another extended address record.
    8.4.7 The absolute-memory address of a data record is obtained by adding the address field in the record to the shifted address data from the extended linear address record. The following example illustrates this process..
    Address from the data record's address field      2462
    
    Extended linear address record data field     FFFF
                                          -----------
    Absolute-memory address                 FFFF2462
    8.5 Extended Segment Address Records (HEX86).
    Extended segment address records-also known as HEX86 records-contain bits 4-19
    of the data address segment. The extended segment address record always has two
    data bytes and appears as follows:
    :020000021200EA
    where:
    8.5.1 02 is the number of data bytes in the record.
    8.5.2 0000 is the address field. For the extended segment address record, this field is always 0000.
    8.5.3 02 is the record type 02 (an extended segment address record).
    8.5.4 1200 is the segment of the address.
    8.5.5 EA is the checksum of the record and is calculated as 01h + NOT(02h + 00h + 00h + 02h + 12h + 00h).
    8.5.6 When an extended segment address record is read, the extended segment addressstored in the data field is saved and is applied to subsequent records read from the Intel HEX file. The segment address remains effective until changed by another extended address record.
    8.5.7 The absolute-memory address of a data record is obtained by adding the addressfield in the record to the shifted-address data from the extended segment address record. The following example illustrates this process.
    Address from the data record's address field       2462
    Extended segment address record data field      1200
                                             --------
    Absolute memory address                 00014462
    8.6 End-of-File (EOF) Records.
    An Intel HEX file must end with an end-of-file (EOF) record. This record must have the value 01 in the record type field. An EOF record always appears as follows:
    :00000001FF
    where:
    8.6.1 00 is the number of data bytes in the record.
    8.6.2 0000 is the address where the data are to be located in memory. The address in end-of-file records is meaningless and is ignored. An address of 0000h is typical.
    8.6.3 01 is the record type 01 (an end-of-file record).
    8.6.4 FF is the checksum of the record and is calculated as 01h + NOT(00h + 00h + 00h + 01h).
    8.7 Example Intel HEX File.
    Following is an example of a complete Intel HEX file:
    :10001300AC12AD13AE10AF1112002F8E0E8F0F2244
    :10000300E50B250DF509E50A350CF5081200132259
    :03000000020023D8
    :0C002300787FE4F6D8FD7581130200031D
    :10002F00EFF88DF0A4FFEDC5F0CEA42EFEEC88F016
    :04003F00A42EFE22CB
    :00000001FF

    三、SMT32的PWM波形输出配置

    STM32之PWM波形输出配置总结。

    1).   TIMER分类:

    STM32中一共有11个定时器,其中TIM6、TIM7是基本定时器;TIM2、TIM3、TIM4、TIM5是通用定时器;TIM1和TIM8是高级定时器,以及2个看门狗定时器和1个系统嘀嗒定时器。其中系统嘀嗒定时器是前文中所描述的SysTick。

    图片

    其中TIM1和TIM8是能够产生3对PWM互补输出,常用于三相电机的驱动,时钟由APB2的输出产生。TIM2-TIM5是普通定时器,TIM6和TIM7是基本定时器,其时钟由APB1输出产生。

    2)、PWM波形产生的原理:

    通用定时器可以利用GPIO引脚进行脉冲输出,在配置为比较输出、PWM输出功能时,捕获/比较寄存器TIMx_CCR被用作比较功能,下面把它简称为比较寄存器。

    这里直接举例说明定时器的PWM输出工作过程:若配置脉冲计数器TIMx_CNT为向上计数,而重载寄存器TIMx_ARR被配置为N,即TIMx_CNT的当前计数值数值X在TIMxCLK时钟源的驱动下不断累加,当TIMx_CNT的数值X大于N时,会重置TIMx_CNT数值为0重新计数。

    而在TIMxCNT计数的同时,TIMxCNT的计数值X会与比较寄存器TIMx_CCR预先存储了的数值A进行比较,当脉冲计数器TIMx_CNT的数值X小于比较寄存器TIMx_CCR的值A时,输出高电平(或低电平),相反地,当脉冲计数器的数值X大于或等于比较寄存器的值A时,输出低电平(或高电平)。

    如此循环,得到的输出脉冲周期就为重载寄存器TIMx_ARR存储的数值(N+1)乘以触发脉冲的时钟周期,其脉冲宽度则为比较寄存器TIMx_CCR的值A乘以触发脉冲的时钟周期,即输出PWM的占空比为 A/(N+1) 。

    3)、STM32产生PWM的配置方法:

    1、配置GPIO口:

      配置IO口的时候无非就是开启时钟,然后选择引脚、模式、速率,最后就是用结构体初始化。不过在32上,不是每一个IO引脚都可以直接使用于PWM输出,因为在硬件上已经规定了用某些引脚来连接PWM的输出口。下面是定时器的引脚重映像,其实就是引脚的复用功能选择:

      a.定时器1的引脚复用功能映像:

    图片

      b.定时器2的引脚复用功能映像:

    图片

      c.定时器3的引脚复用功能映像:

    图片

     d.定时器4的引脚复用功能映像:

    图片

    根据以上重映像表,我们使用定时器3的通道2作为PWM的输出引脚,所以需要对PB5引脚进行配置,对IO口操作代码:

    GPIO_InitTypeDef GPIO_InitStructure;//定义结构体
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB  | RCC_APB2Periph_AFIO, ENABLE);//使能GPIO外设和AFIO复用功能模块时钟
    GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); //选择Timer3部分重映像    
    //选择定时器3的通道2作为PWM的输出引脚TIM3_CH2->PB5    GPIOB.5
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //TIM_CH2
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;  //复用推挽功能
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化引脚

    2、初始化定时器:

    TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;//定义初始化结构体
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); //使能定时器3时钟
    //初始化TIM3
    TIM_TimeBaseStructure.TIM_Period = arr; //自动重装载寄存器的值
    TIM_TimeBaseStructure.TIM_Prescaler =psc; //TIMX预分频的值
    TIM_TimeBaseStructure.TIM_ClockDivision = 0; //时钟分割
    TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //向上计数
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据以上功能对定时器进行初始化

    3、设置TIM3_CH2的PWM模式,使能TIM3的CH2输出:

    TIM_OCInitTypeDef  TIM_OCInitStructure;//定义结构体
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2;//选择定时器模式,TIM脉冲宽度调制模式2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//比较输出使能
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//输出比较极性低
    TIM_OC2Init(TIM3, &TIM_OCInitStructure);//根据结构体信息进行初始化
    TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);  //使能定时器TIM2在CCR2上的预装载值

    4、使能定时器3:

    TIM_Cmd(TIM3, ENABLE);  //使能定时器TIM3

    经过以上的操作,定时器3的第二通道已经可以正常工作并输出PWM波了,只是其占空比和频率都是固定的,我们可以通过改变TIM3_CCR2,则可以控制它的占空比。修改占空比的函数为:

    TIM_SetCompare2(TIM3,n);  //n不同,占空比不同。

    5、修改pwm波形的占空比:

    编写一个函数:

    void TIM3_PWM_Init(u16 arr,u16 psc);

    将以上所有的代码都加进来这个函数中,只要在main函数中调用该函数进行初始化,然后使用TIM_SetCompare2()函数修改PWM的占空比就可以在PB5脚得到需要的PWM波形了。关于频率以及占空比的计算方法有以下例子:

    intmain(void)
    {
    TIM3_PWM_Init(9999,143);//频率为:72*10^6/(9999+1)/(143+1)=50Hz
    TIM_SetCompare2(TIM3,4999);//得到占空比为50%的pwm波形
    while(1);
    }

    四、认识ARM:汇编、架构、异常级别和安全状态

    01 ARM汇编指令

    操作系统中硬件相关的部分集中体现在汇编指令和对寄存器的操作中,因此我们对ARM体系结构的介绍也围绕ARMv8-A的汇编指令和寄存器来展开。

    处理器架构是处理器厂商为同一个系列的处理器规定的一个规范。ARM架构是一种精简指令集(RISC)架构,具有以下RISC架构特点:

  • 较大的通用寄存器堆。
  • load/store体系结构,其中数据处理操作仅对寄存器内容进行操作,而不是直接对内存内容。
  • 简单寻址模式,所有load/store地址由寄存器内容和指令确定。该体系结构定义了处理单元与内存(包括缓存)的交互,并包括内存地址翻译系统。它还描述了多个处理单元如何相互作用。面积小、性能强和非常低的功耗是ARM体系结构的关键特性。本小节主要以ARMv8-A架构为例来介绍ARM体系结构的基本特性。ARMv8-A体系结构的一个重要特性是向后兼容,可以支持诸多标准和应用场景下的最优设计。ARMv8-A架构支持64bit的执行模式(AArch64)和32bit的执行模式(AArch32),这一模式兼容之前的ARM架构。两种执行状态都支持SIMD和浮点指令。
  • 一、AMRv8架构概要

    ARM体系结构自推出以来已经有了显著的发展,并且ARM还在继续开发它。到目前为止,已经有八个主要版本,由版本号1到8表示。其中前三个版本现在已经过时了。

    通用名称AArch64和AArch32描述了64位和32位执行状态。AArch64是64位执行状态,意味着地址保存在64位寄存器中,并且基本指令集可以使用64位寄存器进行处理。AArch64支持A64指令集。AArch32是32位执行状态,这意味着地址保存在32位寄存器中,并且基本指令集使用32位寄存器进行处理。AArch32支持T32和A32指令集。

    ARM支持三种架构配置:

  • A系列,面向应用场景的架构(Application Profile)。该系列支持基于内存管理单元(MMU)的虚拟内存系统体系结构(VMSA)。它支持A64、A32和T32指令集。
  • R系列,面向实时场景的架构配置。该系列支持基于内存保护单元(MPU)的受保护内存系统体系结构(PMSA)。它支持A32和T32指令集。
  • M系列,面向微处理器的架构。该系列实现了一个为低延迟中断处理而设计的程序员模型(programmers’ model),该模型具有寄存器硬件堆栈和对中断处理程序的高级语言支持。它支持T32指令集的变种。
    (注:内存保护单元(MPU)是ARM中配备的有效保护系统资源的一种硬件,提供了内存区域保护功能。)
  • 二、ARMv8-A指令集

    在ARMv8-A中,可能的指令集取决于执行状态:

    1. AArch64:AArch64 state只支持A64指令集。这是一个固定长度的指令集,使用32位指令编码。
    2. Arch32:AArch32 state支持以下指令集:
  • A32:这是一个固定长度的指令集,使用32位指令编码。它是与ARMv7 ARM指令集兼容。
  • T32:这是一个可变长度指令集,它同时使用16位和32位指令编码。它与ARMv7 Thumb®指令集兼容。
  • ARM指令的基本格式如下[2]:

    <Opcode>{<Cond>}<S><Rd>,<Rn> {,<Opcode2>}

    其中各个部分的含义为:

  • Opcode:操作码,也就是助记符,说明指令需要执行的操作类型;
  • Cond:指令执行条件码;
  • S:条件码设置项,决定本次指令执行是否影响PSTATE寄存器相应状态位值;
  • Rd/Xt:目标寄存器,A32指令可以选择R0-R14,T32指令大部分只能选择RO-R7,A64指令可以选择X0-X30;
  • Rn/Xn:第一个操作数的寄存器,和Rd一样,不同指令有不同要求;
  • Opcode2:第二个操作数,可以是立即数,寄存器Rm和寄存器移位方式(Rm,#shit);
  • ARMv8-A指令集的条件码如下图所示:

    图片

    下面以A64指令集为例简要介绍ARMv8-A的指令体系。A64指令集中的指令主要分为控制指令、访存指令和计算指令。控制指令主要包括有条件分支指令、无条件分支指令、异常产生和返回指令、系统寄存器指令、系统指令、提示指令、同步指令和清除独占访问标志指令。访存指令主要有Load指令和Store指令,这两种指令有许多变种。计算指令包含算数指令、逻辑指令、MOVE指令、移位指令、位扩展指令和SIMD指令等等。以下列出了一些常用的控制指令的名称与用途。

    1. 控制指令:

  • 条件分支指令:
  • 图片

  • 无条件分支指令: 
  • 图片

  • 使用寄存器的无条件分支指令:
  • 图片

  •  异常产生指令:
  • 图片

  •  异常返回指令:
  • 图片

  •  系统寄存器指令:
  • 图片

  • 同步指令和独占状态清除指令:
  • 图片

    例如:

    图片

    2. 访存指令:

    ARMv8访存指令支持以下寻址模式:

  • 基址加上无符号立即数的寻址和基址加上有符号立即数的寻址;
  • 基址加上寄存器偏移值;
  • 基址加上扩展的寄存器偏移;
  • pre-index模式;
  • post-index模式;
  • PC相对寻址模式。
  • 具体情形见下表:

    图片

    其中对于A64指令集来说,64bit的基址来自通用寄存器X0-X30或来自栈指针SP,立即数或寄存器偏移值则是可选的,对寻址方式的解释如下:

  • 寄存器偏移寻址是指来自64bit基址寄存器的地址加上一个偏移值;
  • Pre-indexed模式是指寻址地址是64bit基址加上一个偏移值,这个计算和将会写入基址寄存器;
  • Post-indexed模式是指寻址地址是64bit的基址,但之后基址和偏移值的和将会写入基址寄存器;由此可见pre-indexed和post-indexed的区别在于使用的地址是先加上偏移值再使用还是先使用再加上偏移值;
  • PC相对寻址是指寻址地址是这条指令64bit的PC值加上一个19bit的有符号字偏移,这个地址在当前指令的PC值的 ±1MB范围内并且是4byte对齐的。使用PC相对寻址所load的数据大小至少为32bit并且只能用来预取指令,且PC值不能被其他寻址方式使用。
  • 一个立即数偏移可以为有符号的,也可以为无符号的,可以为scaled也可以为unscaled。当一个立即数偏移是scaled的时候,它被编码为传输数据大小的整数倍。虽然汇编程序总是使用byte对齐的偏移,但汇编器或反汇编器会做必要的转换工作,因此可用的byte偏移值取决于load/store指令类型和数据传输的大小。
  • 下面列出了一些load/store指令:

    图片

    例如Load寄存器指令:

    图片

    图片

    图片

    上表中指令的寻址方式有:

  • 基址加上12bit无符号scaled立即数偏移寻址;
  • 基址加上9bit有符号unscaled立即数偏移寻址;
  • 基址加上64bit寄存器偏移,可选为scaled;
  • 基址加上32bit可拓展寄存器偏移,可选为scaled;
  • 有unscaled9bit有符号立即数偏移的pre-indexed模式;
  • 有unscaled9bit有符号立即数偏移的post-indexed模式;
  • Load至少32bit数据的PC相对寻址模式。
  • 如果被load或store的指令的寻址模式会修改基址寄存器的内容,且被load/store寄存器恰好的是基址所在的寄存器,那么硬件的行为可能不确定。

    3.计算指令:

    在操作系统汇编语言中使用的计算指令主要是一些简单的算数计算指令,用于对寄存器的move操作和对地址的计算操作,一般计算指令既可以使用立即数作为操作数,也可以使用寄存器中的数作为操作数。下面简单列举了一些算数指令:

    使用立即数的简单算数指令:

    图片

    例如:

    图片

    图片

     使用寄存器的逻辑操作指令:

    图片

    例如:

    图片

    图片

    其中:

    图片

     寄存器移位指令:

    图片

     例如:

    图片

    02 ARM架构寄存器

    在处理器中,寄存器用于保存需要被快速访问的数据,在操作系统中需要特别注意的寄存器主要有栈指针寄存器(SP)、连接寄存器(LR)、程序计数器(PC)以及当前程序状态寄存器(CPSR)和保存程序状态寄存器(SPSR)。本小节主要以ARMv8-A为例介绍ARM架构的寄存器的基本情况。详情可参见文献[3],D1.6小节。

    在这一小节中,我们主要介绍ARMv8架构中AArch64执行状态下的寄存器使用情况。ARM架构中的寄存器主要有两类,一类用于提供系统控制与状态报告;另一类用于指令运行和异常处理。我们主要讨论第二类。

    通用寄存器主要用于基本指令集中的指令运行,通用寄存器共有31个,编号为R0-R31。这些通用寄存器可以被当成31个64bit的寄存器,编号为X0-X30;或者被作为31个32bit的寄存器,编号为W0-W30。

    在AArch64执行状态下,除了通用寄存器外,每一个异常级别都会有一个栈指针寄存器(StackPointer Register, SP),栈指针寄存器为SPEL0和SPEL1。异常级别用于区分指令的执行权限,我们将在本章的第四期介绍。如果处理器实现中包含EL2,那么还有SPEL2。如果处理器实现中包含EL3,那么还有SPEL3。详情可参考链接[5]。

    SIMD和浮点寄存器共用一系列寄存器,这些寄存器会用于浮点操作、向量操作和其它SIMD有关的标量操作。SIMD指令是能够复制多个操作数、并把它们打包在大型寄存器的一组指令集[3]。以加法指令为例,单指令单数据(SISD)的CPU对加法指令译码后,执行部件先访问内存,取得第一个操作数;之后再一次访问内存,取得第二个操作数;随后才能进行求和运算。而在SIMD型的CPU中,指令译码后几个执行部件同时访问内存,一次性获得所有操作数进行运算。浮点寄存器和SIMD寄存器共包含32个128bit位宽的寄存器,V0-V31。这些寄存器可以作为:

  • 32个双字(64bit)寄存器,D0-D31。
  • 32个单字(32bit)寄存器,S0-S31。
  • 32个半字(16bit)寄存器,H0-H31。
  • 32个单字(8bit)寄存器,B0-B31。
  • 程序状态寄存器(Current Program Status Register,CPSR) 在用户级编程时用于存储条件码。CPSR包含条件码标志,中断禁止位,当前处理器模式以及其他状态和控制信息。

    保存程序状态寄存器(SPSR,Saved Program StatusRegister)用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。在A64中,不再使用单一的CPSR寄存器,来保存当前处理器状态,而是用PSTATE来保存处理器状态,而在A32中依然使用CPSR。有关PSTATE和CPSR的详细信息可参考链接[4]。A64中SPSR 格式的示意图如下图所示:

    图片

    其中N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变,并且可以用于决定某条指令是否被执行,其含义如下表所示[8]:

    标志位

    含义

    N

    当两个有符号整数运算时:N=1表示运算的结果为负数;N=0表示运算的结果为正数或零。

    Z

    Z=1表示运算的结果为零,Z=0表示运算的结果非零。

    C

    可以有4种方法设置C的值:

  • 在加法指令中(包括比较指令CMP),当结果产生了进位,则C=1,表示无符号运算发生上溢出;其他情况C=0。
  • 在减法指令中(包括减法指令CMP),当运算中发生借位,则C=0,表示无符号运算数发生下溢出;其他情况下C=1。
  • 对于包含移位操作的非加减运算指令,C中包含最后一次溢出的位的数值。
  • 对于其他非加减运算指令,C位的值通常不受影响。
  • V

    对于加减运算指令,当操作数和运算结果为二进制的补码表示的带符号数时,V=1表示符号为溢出,通常其他指令不影响V位。

     M[3:0]则用来确定异常级别和SP:

    图片

    有关SPSR中各个位的详细信息可以参考文献[1] 1.6.4小节。

    连接寄存器LR(R14)的主要作用有两个:

    1. 保存子程序返回地址,用MOVE指令或BX指令可以用于实现返回,如MOV PC、LR或BXLR。若子程序中还需要调用子程序,则可以写为:

    ​​

    图片

    ​​

    第一条指令将LR中的内容入栈,最后一条将栈中保存的LR寄存器的内容存入PC中用于返回。

    2. 当异常发生时,异常模式的LR用于保存异常返回地址,将LR内容入栈可以处理嵌套中断。

    PC是程序计数器,其中保存的是正在被加载的指令,而不是正在被执行的指令。例如,若指令长度为4byte,则PC指向当前正在被执行的指令的地址+8byte的地址。关于LR和PC的详细内容可参考文献[6]和[7]。

    以下是异常级别EL3中使用的寄存器的例图:

    图片

    ARM架构中处理器有不同的运行模式,因此同一个功能的寄存器在不同的运行模式下可能对应不同的物理寄存器,这些寄存器被称为备份寄存器。如SPSR_svc表示svc模式下使用的SPSR寄存器。ARM架构中常用的运行模式如下表所示[9]:

    处理器模式

    描述

    用户模式(User, usr)

    正常程序执行的模式

    快速中断模式(FIQ, fiq)

    用于高速数据传输和通道处理

    外部中断模式(IRQ, irq)

    用于通常的中断处理

    特权模式(Supervisor, svc)

    供操作系统使用的一种保护模式

    数据访问中止模式(Abort, abt)

    当数据或指令预取中止时进入该模式,用于虚拟存储及存储保护

    未定义指令中止模式(Undefined, und)

    当执行未定义指令时进入该模式,用于支持通过软件仿真硬件的协处理器

    系统模式(System, sys)

    用于运行特权级的操作系统任务

    ARMv8-A架构还有Monitor(mon)工作模式,用于处理器安全状态与非安全状态的切换,Hypervisor(hyp)模式则用于对虚拟化有关功能的支持。有关安全状态的详细内容在后续的文章中会介绍。

    03 ARM架构中的执行状态

    ARMv8-A有两种执行模式,一种是AArch64执行模式,另一种是AArch32执行模式。执行状态定义处理单元(Processing Element, PE)的执行环境,包括以下内容:

    1. 支持的寄存器宽度
    2. 支持的指令集
    3. 异常模型
    4. 虚拟存储系统(Virtual Memory System Architecture, VMSA)架构
    5. 程序员模型

    AArch64为64位执行状态。对应上述内容,此执行状态:

    1. 提供31个64位通用寄存器,其中X30用作过程链接寄存器(ProcedureLink Register)。
    2. 提供64位程序计数器(PC)、堆栈指针(SP)和异常链接寄存器(ELRs)。
    3. 提供32个128位寄存器以支持SIMD矢量和标量浮点运算。
    4. 提供单一指令集A64。
    5. 定义ARMv8异常模型,该模型最多有四个异常级别EL0-EL3,它们提供执行权限层次结构。
    6. 支持64位虚拟寻址。
    7. 定义一系列与PSTATE相关的寄存器。A64指令集包括能直接操作各种PSTATE寄存器的指令。
    8. 使用后缀命名每个系统寄存器,该后缀指示可以访问寄存器的最低异常级别。

    AArch32为32位执行状态。对应上述内容,此执行状态:

    1. 提供13个32位通用寄存器和一个32位PC、一个32位SP寄存器和一个32位链接寄存器(Link Register,LR)。链接寄存器用作异常链接寄存器和过程链接寄存器。其中一些寄存器有多个备份寄存器,用于不同的处理器工作模式。我们在上一期提到过,同一个功能的寄存器在不同的处理器运行模式下可能对应不同的物理寄存器,这些寄存器被称为备份寄存器。
    2. 为从Hyp(hypervisor)模式返回的异常提供一个异常链接寄存器。
    3. 提供32个64位寄存器,用于对高级SIMD矢量和标量浮点计算的支持。
    4. 提供两个指令集,A32和T32。
    5. 支持基于处理器工作模式的ARMv7-A异常模型,并将其映射到基于异常级别的ARMv8异常模型。
    6. 使用32位虚拟地址。
    7. 使用单个当前程序状态寄存器(CPSR)保存处理器状态。
    8. 在AArch64和AArch32执行状态之间进行转换称为内部处理(interprocessing)。

    04 ARMv8-A架构的异常级别和安全状态

    ARMv8-A有四个异常级别,从EL0到EL3。对于异常级别ELn,整数n增加表示软件执行的特权权限变大了。EL0级别下的执行叫非特权执行(unprivileged execution)。EL1主要用于运行操作系统内核。EL2可以支持非安全操作的虚拟化。EL3则支持安全状态和非安全状态之间的转换。安全状态与ARM TrustZone技术有关[2]。安全状态可以运行可信执行环境(TEE, Trusted Execution Environment)及安全应用,用于保障隐私数据和程序运行环境的安全性。

    ARMv8-A架构并未直接指定哪些软件应该运行在哪些异常级别,但是在通常情况下,有如异常级别的使用模型:

    1.应用程序运行在EL0;

    2.操作系统内核和相关功能运行在EL1;

    3.Hypervisor[3]运行在EL2;

    4.安全世界状态和正常世界状态的切换在EL3完成。

    下图反映了ARM-v8A架构中的执行状态、安全状态和异常级别之间关系[1]:

    图片

    从图中我们可以看出,Hypervisor相关的支持特性主要是在EL2的非安全状态实现的。Hypervisor可以支持虚拟机之间的切换,而虚拟机主要被包含在EL1的非安全状态和EL0的非安全状态中。一些Guest OS可以运行在EL1状态里,每一个Guest OS可以运行在一个虚拟机上。而应用则运行在EL0的非安全状态中,同时也运行在Guest OS上。

    五、xxx

    六、xxx

    七、电容、电感产生的相位差

    对于正弦信号,流过一个元器件的电流和其两端的电压,它们的相位不一定是相同的。这种相位差是如何产生的呢?这种知识非常重要,因为不仅放大器、自激振荡器的反馈信号要考虑相位,而且在构造一个电路时也需要充分了解、利用或避免这种相位差。下面探讨这个问题。

        首先,要了解一下一些元件是如何构建出来的;其次,要了解电路元器件的基本工作原理;第三,据此找到理解相位差产生的原因;第四,利用元件的相位差特性构造一些基本电路。 

    电阻、电感、电容的诞生过程

        科学家经过长期的观察、试验,弄清楚了一些道理,也经常出现了一些预料之外的偶然发现,如伦琴发现X射线、居里夫人发现镭的辐射现象,这些偶然的发现居然成了伟大的科学成就。电子学领域也是如此。

        科学家让电流流过导线的时候,偶然发现了导线发热、电磁感应现象,进而发明了电阻、电感。科学家还从摩擦起电现象得到灵感,发明了电容。发现整流现象而创造出二极管也是偶然。

    元器件的基本工作原理

        电阻——电能→热能

        电感——电能→磁场能,&磁场能→电能

        电容——电势能→电场能,&电场能→电流

        由此可见,电阻、电感、电容就是能源转换的元件。电阻、电感实现不同种类能量间的转换,电容则实现电势能与电场能的转换。

    电阻

        电阻的原理是:电势能→电流→热能。

        电源正负两端贮藏有电势能(正负电荷),当电势加在电阻两端,电荷在电势差作用下流动——形成了电流,其流动速度远比无电势差时的乱序自由运动快,在电阻或导体内碰撞产生的热量也就更多。

        正电荷从电势高的一端进入电阻,负电荷从电势低的一端进入电阻,二者在电阻内部进行中和作用。中和作用使得正电荷数量在电阻内部呈现从高电势端到低电势端的梯度分布,负电荷数量在电阻内部呈现从低电势端到高电势端的梯度分布,从而在电阻两端产生了电势差,这就是电阻的电压降。同样电流下,电阻对中和作用的阻力越大,其两端电压降也越大。

        因此,用R=V/I来衡量线性电阻(电压降与通过的电流成正比)的阻力大小。

    对交流信号则表达为R=v(t)/i(t)。

        注意,也有非线性电阻的概念,其非线性有电压影响型、电流影响型等。

    电感

        电感的原理:电感——电势能→电流→磁场能,&磁场能→电势能(若有负载,则→电流)。

        当电源电势加在电感线圈两端,电荷在电势差作用下流动——形成了电流,电流转变磁场,这称为“充磁”过程。若被充磁电感线圈两端的电源电势差撤销,且电感线圈外接有负载,则磁场能在衰减的过程中转换为电能(如负载为电容,则为电场能;若负载为电阻,则为电流),这称为“去磁”过程。

        衡量电感线圈充磁多少的单位是磁链——Ψ。电流越大,电感线圈被冲磁链就越多,即磁链与电流成正比,即Ψ=L*I。对一个指定电感线圈,L是常量。

        因此,用L=Ψ/I表达电感线圈的电磁转换能力,称L为电感量。电感量的微分表达式为:L=dΨ(t)/di(t)。

        根据电磁感应原理,磁链变化产生感应电压,磁链变化越大则感应电压越高,即v(t)=d dΨ(t)/dt。

        综合上面两公式得到:v(t)=L*di(t)/dt,即电感的感应电压与电流的变化率(对时间的导数)成正比,电流变化越快则感应电压越高。

    电容

        电容的原理:电势能→电流→电场能,电场能→电流。

        当电源电势加在电容的两个金属极板上,正负电荷在电势差作用下分别向电容两个极板聚集而形成电场,这称为“充电”过程。若被充电电容两端的电源电势差撤销,且电容外接有负载,则电容两端的电荷在其电势差下向外流走,这称为“放电”过程。电荷在向电容聚集和从电容两个极板向外流走的过程中,电荷的流动就形成了电流。

        要特别注意,电容上的电流并不是电荷真的流过电容两个极板间的绝缘介质,而只是充电过程中电荷从外部向电容两个极板聚集形成的流动,以及放电过程中电荷从电容两个极板向外流走而形成的流动。也就是说,电容的电流其实是外部电流,而非内部电流,这与电阻、电感都不一样。

        衡量电容充电多少的单位是电荷数——Q。电容极板间电势差越大,说明电容极板被冲电荷越多,即电荷数与电势差(电压)成正比,即Q=C*V。对指定电容,C是常量。

        因此,用C=Q/V表达电容极板贮存电荷的能力,称C为电容量。

        电容量的微分表达式为:C=dQ(t)/dv(t)。

        因为电流等于单位时间内电荷数的变化量,即i(t)=dQ(t)/dt,综合上面两个公式得到:i(t)=C*dv(t)/dt,即电容电流与其上电压的变化率(对时间的导数)成正比,电压变化越快则电流越大。

    小结:v(t)=L*di(t)/dt

        表明电流变化形成了电感的感应电压(电流不变则没有感应电压形成)。

    i(t)=C*dv(t)/dt表明电压变化形成了电容的外部电流(实际是电荷量变化。电压不变则没有电容的外部电流形成)。

    元件对信号相位的改变

        首先要提醒,相位的概念是针对正弦信号而言的,直流信号、非周期变化信号等都没有相位的概念。

    电阻上的电压电流同相位

        因为电阻上电压v(t)=R*i(t),若i(t)=sin(ωt+θ),则v(t)=R* sin(ωt+θ)。所以,电阻上电压与电流同相位。

    电感上的电流落后电压90°相位

        因为电感上感应电压v(t)=L*di(t)/dt,若i(t)=sin(ωt+θ),则v(t)=L*cos(ωt+θ)。 所以,电感上电流落后感应电压90°相位,或者说感应电压超前电流90°相位。

        直观理解:设想一个电感与电阻串联充磁。从充磁过程看,充磁电流的变化引起磁链的变化,而磁链的变化又产生感应电动势和感应电流。根据楞次定律,感应电流方向与充磁电流相反,延缓了充磁电流的变化,使得充磁电流相位落后于感应电压。

    电容上的电流超前电压90°相位

        因为电容上电流i(t)=C*dv(t)/dt,若v(t)=sin(ωt+θ),则i(t)=L*cos(ωt+θ)。

    所以,电容上电流超前电压90°相位,或者说电压落后电流90°相位。

        直观理解:设想一个电容与电阻串联充电。从充电过程看,总是先有流动电荷(即电流)的积累才有电容上的电压变化,即电流总是超前于电压,或者说电压总是落后于电流。

        下面的积分方程能体现这种直观性:

    v(t)=(1/C)*∫i(t)*dt=(1/C)*∫dQ(t),即电荷变化的积累形成了电压,故dQ(t)相位超前v(t);而电荷积累的过程就是电流同步变化的过程,即i(t)与dQ(t)同相。因此i(t)相位超前于v(t)。

    元件相位差的应用

    RC文氏桥、LC谐振过程的理解

        无论RC文氏桥,还是LC的串联谐振、并联谐振,都是由电容或/和电感容元件的电压、电流相位差引起的,相关文章:还没搞懂电压、电流的超前与滞后?就像机械共振的节拍一样。

        当两个频率相同、相位相位的正弦波叠加时,叠加波的幅度达到最大值,这就是共振现象,在电路里称为谐振。

        两个频率相同、相位相反的正弦波叠加,叠加波的幅度会降到最低,甚至为零。这就是减小或吸收振动的原理,如降噪设备。

        当一个系统中有多个频率信号混合时,如果有两个同频信号产生了共振,那么这个系统中其它振动频率的能量就被这两个同频、同相的信号所吸收,从而起到了对其它频率的过滤作用。这就是电路中谐振过滤的原理。

        谐振需要同时满足频率相同和相位相同两个条件。电路如何通过幅度-频率特性选择频率的方法以前在RC文氏桥中讲过,LC串并联的思路与RC相同,这里不再赘述。

        下面我们来看看电路谐振中相位补偿的粗略估计(更精确的相位偏移则要计算)

    RC文氏桥的谐振(图1) 

        若没有C2,正弦信号Uo的电流由C1→R1→R2,通过R2上压降形成Uf输出电压。由于支路电流被电容C1移相超前Uo 90°,这超前相位的电流流过R2(电阻不产生相移!),使得输出电压Uf电压超前于Uo 90°。 

        在R2上并联C2,C2从R2取得电压,由于电容对电压的滞后作用,使得R2上电压也被强制滞后。(但不一定有90°,因为还有C1→R1→C2电流对C2上电压即Uf的影响,但在RC特征频率上,并联C2后Uf输出相位与Uo相同。) 

        小结:并联电容使得电压信号相位滞后,称为电压相位的并联补偿。

    图片

    LC并联谐振(图2) 

        若没有电容C,正弦信号u通过L感应到次级输出Uf,Uf电压超前于u 90°;在L初级并联电容C,由于电容对电压的滞后作用,使得L上电压也被强制滞后90°。因此,并联C后Uf输出相位与u相同。

    LC串联谐振(图3) 

        对于输入正弦信号u,电容C使得串联回路中负载R上的电流相位超前于u 90°,电感L则使得同一串联回路中的电流相位再滞后90°二者相位偏移刚好抵消。因此,输出Uf与输入u同相。

    总结

        注意,相位影响不一定都是90°,与其它部分相关,具体则要计算。 

  • 串联电容使得串联支路电流相位超前,从而影响输出电压相位。
  • 并联电容使得并联支路电压相位滞后,从而影响输出电压相位。
  • 串联电感使得串联支路电流相位滞后,从而影响输出电压相位。
  • 并联电感使得并联支路支路电压超前,从而影响输出电压相位。 
  •     更简洁的记忆: 

        在元件上的电流或电压,电容使电流相位超前,电感使电压相位超前。

    八、电压、电流的超前与滞后

    电压电流的超前与滞后这个概念是相对于电流和电压之间的关系而说的。也就是说,比如是容性负载(电容器),那么他会导致最终电流超前90度,如果是电感则产生最终电流超前-90度(即滞后90度) 反过来说,在平面直角坐标系中,假设电压为X轴水平方向,则是否超前则为Y轴垂直方向,当为容性负载时为Y正半轴部分,感性负载为Y负半轴部分 无论是正超前还是负超前(滞后)都会导致功率因数下降,而纯阻性负载其超前角是0度,这个时候功率因数为1 正因为容性和感性具有这种相反的性质,那么当使用电动机等感性负载时,会导致严重的负超前,这个时候就应当使用足够的电容器进行补偿,使其无限逼近0度,保证功率因数无限的逼近1。总之,功率因数下降,无论是正超前还是负超前都回导致下降,只有为0时才是最高的,而感性负载一应用就肯定是负的了。所以就要用电容补偿让他接近0。

        如下图,由于Sin[ωt]在求导或积分后会出现Sin[ωt±90°],所以对于接上了正弦波的电感、电容,横坐标为ωt时可以观察到波形超前滞后的现象,直接从静态的函数图上看不太容易理解,还是做成动画比较好。用红色表示电压,蓝色表示电流。如果接上理想的直流电压表、直流电流表,可以观察到电压的变化超前于电流,电流的变化滞后于电压。时间增加时,纵坐标轴及时间原点会随着波形一起往左移动。

    图片

        如果把波形画在矢量图右方,就是下面这种动画,但横坐标右方是过去存在的波形,指向过去,是-ωt。虽然波形反过来了,但电压的变化仍然超前于电流,电流的变化仍然滞后于电压。时间原点一直随着波形往右方移动,函数图中的纵坐标轴并未与横坐标交于原点,交点所代表的时间一直在增加。如果不注意,超前滞后的判断很容易出错。

    图片

        理解超前滞后这一概念用相量图是最好的,从测量数据来观察或者从静态波形上观察都不太直观而且容易出错。下图是电容的。电压的变化滞后于电流,电流的变化超前于电压。坐标系右方是未来,左方是过去。

    图片

        横坐标是-ωt时,电容的电压的变化仍然滞后于电流,电流的变化仍然超前于电压。因为此坐标系左方是未来,而右方是过去。

    图片

        下图是电阻的。电压函数电流函数同相。

    图片

        下图是三者串联的情况,没画相量图和波形图。但从指针的变化可以判断:电流相同时,电感和电容的电压函数反相。

        没画总电压,因为总电压有可能超前于总电流,也有可能滞后于总电流,也有可能两者同相,同相时为谐振状态。

    图片

        以前还做过这种,元件右边标的是电压电流的参考方向。用不同的颜色描述电压的大小,蓝色>黄色>红色;用不同的粗细和箭头描述电流的大小和方向,而且把电感、电容充能的效果也做进去了,电流最大时电感磁场能最大,电容电场能最小。

        但是,就解释超前滞后这一概念的话,指针表的动画更直观。

    图片

    图片

    九、xx

    作者:whaosoft-143

    物联沃分享整理
    物联沃-IOTWORD物联网 » 嵌入式单片机合集(第9期)——聚焦51C系列

    发表回复