Cortex-M3寄存器组&汇编与C的接口

学uCOS的任务切换时涉及到汇编代码。为了能理解汇编代码,我在网上了解了Cortex-M3寄存器组、C与汇编的接口的知识,在这里分享给大家。

先来介绍Cortex-M3寄存器组:

Cortex-M3拥有16个通用寄存器R0-R15。

R0-R12都是32位通用寄存器,用于数据操作。

R13是堆栈指针。在CM3处理器内核中共有两个堆栈指针,于是也就支持两个堆栈。当引用R13(SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问。两个堆栈指针分别是:

  1. 主堆栈指针(MSP):这是缺省的堆栈指针,它由OS内核、异常服务程序及需要特权访问的应用程序代码来使用。
  2. 进程堆栈指针(PSP):用于常规的应用程序代码。

R14是连接寄存器(LR)。在函数调用时存储返回的地址。

R15是程序计数器(PC)。指向当前程序的地址。如果修改它的值,就会改变程序的执行顺序(很多高级操作都在这)。

接下来介绍汇编与C的接口:

让C程序与汇编程序互相交互时,我们必须知道参数是如何传递的,以及值是如何返回的,这样才能在主调函数与子程序之间协调工作。这些交互机制在ARM中有明确的规定,由文档《ARM Architecture Procedure Call Standard(AAPCS,Ref5)》(我没有看过)给出。虽然没看官方的文档,我还是在百度上看了一下C与汇编混合编程,并做以下总结:

1、发生函数调用时,入口参数依次通过R0-R3寄存器传递,其中R0传递第一个,R1传递第2个……,当超过4个参数时,其他参数通过栈传递。函数的返回值通过R0寄存器返回。在函数被调用前,R0-R3中的值会自动入栈。

2、R4-R11为普通的通用寄存器,发生函数调用时,其中的数据不会自动入栈,如果被调函数需要使用这些寄存器,则需要由被调函数先将这些寄存器中数据入栈保存再使用这些寄存器。被调函数返回前,需要先将数据出栈回复R4-R11的值,然后再返回主调函数。

3、R12(IP)可以记录对子程序的调用。

R13-R15的作用在前一部分介绍过了,不再啰嗦。

最后,我用C和汇编写了一个流水灯的程序,以此演示C语言调用汇编函数,其中LED亮灭的切换由汇编代码实现。以下附上部分代码:  代码下载地址:https://download.csdn.net/download/qdchenxr/10887924

/******************led.h*******************/
#ifndef __LED_H
#define __LED_H  
#include "stm32f10x.h"

void LED_Init(void);//GPIO初始化
void LED_Change(unsigned char index);//汇编函数在C语言头文件中的声明
                            
#endif
/******************main.c*******************/
#include "delay.h"
#include "led.h"
 int main(void)
 {  
    unsigned char index=1;
    delay_init();      
    LED_Init();       
    while(1)
    {
        LED_Change(index);//调用汇编函数,传递一个参数
        index=!index;
        delay_ms(300);
    }
 }
/******************led.s*******************/
;全局函数
    EXPORT LED_Change           ;该文件定义的函数
;常量
GPIOB_BASE EQU 0x40010C00       ;GPIOB的基地址
GPIOB_BRR  EQU GPIOB_BASE+0x14  ;GPIOB_BRR寄存器的地址
GPIOB_BSRR EQU GPIOB_BASE+0x10  ;GPIOB_BSRR寄存器的地址   
GPIOE_BASE EQU 0x40011800       ;GPIOE的基地址
GPIOE_BRR  EQU GPIOE_BASE+0x14  ;GPIOE_BRR寄存器的地址
GPIOE_BSRR EQU GPIOE_BASE+0x10  ;GPIOE_BSRR寄存器的地址   
LED_LIGHT  EQU 0x0020
;代码产生指令
    PRESERVE8
    THUMB
        
    AREA CODE, CODE, READONLY       
;LED切换函数
LED_Change
    CBZ R0, LED1_Light  ;一个参数由R0传递,判断R0,如果值为0就跳转到LED1_Light
    
LED2_Light
;点亮LED2 
    LDR R1, =GPIOE_BRR  ;R1=GPIOE_BRR;//R1中存GPIOE_BRR寄存器的地址
    LDR R2, =LED_LIGHT  ;R2=0x0020;
    STR R2, [R1]         ;*R1=R2;
;熄灭LED1
    LDR R1, =GPIOB_BSRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
    BX LR               ;函数返回
    
LED1_Light
;点亮LED1 
    LDR R1, =GPIOB_BRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
;熄灭LED2
    LDR R1, =GPIOE_BSRR
    LDR R2, =LED_LIGHT
    STR R2, [R1]
    BX LR               ;函数返回

    NOP 
    END                 ;汇编文件结束

 效果如下:(转成GIF后反了,不知道怎么正过来)

发布了8 篇原创文章 · 获赞 18 · 访问量 5230

猜你喜欢

转载自blog.csdn.net/QDchenxr/article/details/85454062
今日推荐