学uCOS的任务切换时涉及到汇编代码。为了能理解汇编代码,我在网上了解了Cortex-M3寄存器组、C与汇编的接口的知识,在这里分享给大家。
Cortex-M3拥有16个通用寄存器R0-R15。
R0-R12都是32位通用寄存器,用于数据操作。
R13是堆栈指针。在CM3处理器内核中共有两个堆栈指针,于是也就支持两个堆栈。当引用R13(SP)时,你引用到的是当前正在使用的那一个,另一个必须用特殊的指令来访问。两个堆栈指针分别是:
R14是连接寄存器(LR)。在函数调用时存储返回的地址。
R15是程序计数器(PC)。指向当前程序的地址。如果修改它的值,就会改变程序的执行顺序(很多高级操作都在这)。
让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后反了,不知道怎么正过来)