最近又接手另外一个项目,用的是STM32。听说这份代码是大神写的。我粗略看了一下,云里雾里,好多好多的神技。有太多的代码写得令我惊怒交加,惊的是居然还能这么写代码,怒的是这写的实在太艰深难懂看得我想骂人。看完实在有太多想说的,今天先放一点出来分享一下,瞻仰一下大神的骚操作。
咱们就从一个中断服务函数开始,顺藤摸瓜来看看代码里怎么安排中断向量的。
ISR(USART2_IRQn)
{
uint8 data;
uint32 _if=USART2->ISR;
你没有看错,这就是中断服务函数的名字。我们来追踪一下这个ISR是个啥。在一个头文件里有如下的定义。可以看到ISR(USART2_IRQn)就等同于void ISR_NAME(USART2_IRQn)(void),ISR_NAME又等同于__ISR_NAME,__ISR_NAME又等同于__ISR_##A。这个就是最后的宏定义了,是个拼接宏。
#ifndef ISR_NAME
#define ISR_NAME(A) __ISR_NAME(A)
#define __ISR_NAME(A) __ISR_##A
#endif
#ifndef ISR_Extern
#define ISR_Extern(A) ISR(A)
#endif
#ifndef ISR_Implement
#define ISR_Implement(A) ISR(A)
#endif
#ifndef ISR_Define
#define ISR_Define(A) ISR(A)
#endif
#ifndef ISR
#define ISR(A) void ISR_NAME(A)(void)
#endif
也就说通过一层层的宏定义。ISR(USART2_IRQn)就等同于void __ISR_USART2_IRQn(void)。经常使用STM32的我们知道,串口的中断函数一般都是这个USART2_IRQHandler,并不是上面那个。那会不会是在中断服务函数里调用了上面那个函数的呢。我在整个项目范围内搜索了USART2_IRQHandler,并没有找到这个函数。
经过在项目文件里的一番查找,我找到了问题的答案。我在一个源文件里找到了这么一个数组的定义。__root的意思是不管这个数组有没有被其他文件用到,强制编译器编译放在编译后的文件中。@“.intvec"是告诉编译器,这个数组编译后放在.intvec段。这个.intvec段就是中断向量表存放的地方,代码这么写,就是说用这个数组覆盖中断向量表。这个数组里又是一层层的宏定义。
__root const intvec_elem __vector_table[] @".intvec"=
{
//======================================================================
//填充CM3系统异常/中断为默认值(放在最前面)
ISR_VAL_2_15_FILL_IN_VECT_TAB(_Deault_Handler),
//======================================================================
//堆栈指针,起始运行地址
[0].ptr = (uint32)__sfe( "CSTACK" ) - 32 ,
[1].handler = __iar_program_start,
//CM3系统异常/中断
ISR_VAL_IN_VECT_TAB(NonMaskableInt_IRQn,_Deault_Handler),
//ISR_VAL_IN_VECT_TAB(