单片机C代码嵌套汇编的一些方法
单片机开发或多或少都会接触一些汇编代码,今天就来说说关于汇编在C中的定义和调用,以及举例说明嵌套汇编代码。概 述有认真研究,或者说细心一点的读者应该都知道:C中定义汇编代码与编译器有关。
比如,你在core_cm4.h文件会看到如下的代码:
#if defined ( __CC_ARM )#define __ASM __asm /*!< asm keyword for ARM Compiler */#define __INLINE __inline /*!< inline keyword for ARM Compiler */#define __STATIC_INLINEstatic __inline
#elif defined ( __GNUC__ )#define __ASM __asm /*!< asm keyword for GNU Compiler */#define __INLINE inline /*!< inline keyword for GNU Compiler */#define __STATIC_INLINEstatic inline
#elif defined ( __ICCARM__ )#define __ASM __asm /*!< asm keyword for IAR Compiler */#define __INLINE inline /*!< inline keyword for IAR Compiler. Only available in High optimization mode! */#define __STATIC_INLINEstatic inline
#elif defined ( __TMS470__ )#define __ASM __asm /*!< asm keyword for TI CCS Compiler */#define __STATIC_INLINEstatic inline
#elif defined ( __TASKING__ )#define __ASM __asm /*!< asm keyword for TASKING Compiler */#define __INLINE inline /*!< inline keyword for TASKING Compiler */#define __STATIC_INLINEstatic inline
#elif defined ( __CSMC__ )#define __packed#define __ASM _asm /*!< asm keyword for COSMIC Compiler */#define __INLINE inline /*use -pc99 on compile line !< inline keyword for COSMIC Compiler */#define __STATIC_INLINEstatic inline#endif
如果你写过Keil C51,你还会发现有如下(通过预处理)嵌套汇编:
#pragma asm
; Assembler Code Here
#pragma endasm
所以,你会发现,不同的编译器,汇编代码还是有差异。当然,这里主要是说C中嵌套汇编与编译器有关。
C中嵌套汇编代码常见的两种定义:• 在C函数中定义一段汇编代码• 在C文件中定义一个汇编函数
当然,两个意思差不多,都是在C中嵌套汇编。
上面说了C中定义汇编代码与编译器有关,换句话说:不同编译器解析汇编代码的方式不同。
这里还是拿core_cm3.c来举例说明,定义一个__get_PSP函数。
在Keil MDK中定义:
__ASM uint32_t __get_PSP(void){mrs r0, pspbx lr}在IAR EWARM中定义:
uint32_t __get_PSP(void){__ASM("mrs r0, psp");__ASM("bx lr");}__asm(__ASM)关键字用于调用内联汇编程序,并且可在 C 或 C++ 语句合法时出现。
举 例下面举一些常见的例子。
1、FreeRTOS中portmacro.h文件下源代码:
static portFORCE_INLINE void vPortRaiseBASEPRI( void ){uint32_t ulNewBASEPRI = configMAX_SYSCALL_INTERRUPT_PRIORITY;
__asm{ /* Set BASEPRI to the max syscall priority to effect a critical section. */ msr basepri, ulNewBASEPRI dsb isb}}
2、FreeRTOS中port.c文件下源代码:
__asm void xPortPendSVHandler( void ){extern uxCriticalNesting;extern pxCurrentTCB;extern vTaskSwitchContext;
PRESERVE8
mrs r0, pspisb
ldrr3, =pxCurrentTCB /* Get the location of the current TCB. */ldrr2,
stmdb r0!, {r4-r11} /* Save the remaining registers. */str r0, /* Save the new top of stack into the first member of the TCB. */
stmdb sp!, {r3, r14}mov r0, #configMAX_SYSCALL_INTERRUPT_PRIORITYmsr basepri, r0dsbisbbl vTaskSwitchContextmov r0, #0msr basepri, r0ldmia sp!, {r3, r14}
ldr r1, ldr r0, /* The first item in pxCurrentTCB is the task top of stack. */ldmia r0!, {r4-r11} /* Pop the registers and the critical nesting count. */msr psp, r0isbbx r14nop}3、内核复位
这是之前分享过的一篇文章《一文弄懂STM32复位来源,以及系统与内核复位的区别》中的代码:
__asm void NVIC_CoreReset_a(void){LDR R0, =0xE000ED0CLDR R1, =0x05FA0001STR R1, deadloop_CoreB deadloop_Core}以上这些常见例子,可能还没有说透,但相信只要认真理解了都能明白。
作为低级语言汇编语言在单片机开发中有它不可取代的作用,比如每条指令可以精确的确定延时时间 在 C 文件中要嵌入汇编代码片以如下方式加入汇编代码:
#pragma ASM
; Assembler Code Here
#pragma ENDASM 一定要将c:\keil\C51下的STARTUP.A51文件加入项目 c文件和A51文件不能使用同一个文件名 在C51和汇编之间传递参数的方式有两种,一种是通过寄存器传递参数,C51中不同类型的实参会存入
相应的寄存器,在汇编中只需对相应寄存器进行操作,即达到传递参数的目的 有时候用到需要精确延时之类的子程序时,用C语言比较难控制,这时候就可以在C中嵌入汇编
页:
[1]