完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
无论是最简单的51单片机,还是复杂的ARM、DSP等,最简单的操作莫过于IO口的高、低电平控制了,本章以前面讲述的库函数为基础,通过一个经典的跑马灯程序,带大家开始SWM320的学习之旅,通过本章的学习,你将掌握SWM320的GPIO口作为输出使用的方法。在本章实现跑马灯时,我们加入了一个名为“system_SWM320.c”的汇编文件,这个文件起什么作用呢?这章将给出简单的讲述。 6.1跑马灯的实现过程前面几章,讲述库函数的过程时,我们简单提到了点亮一个LED小灯的过程,但是没有说明为何是控制GPIOP端口的几个位,这里我们先上原理图,再来解释其原理。 6.1.1LED小灯的硬件电路设计对于LED来说,总共两个引脚,在电路设计上没有难度,这里以FSSW32开发板上的原理图来做讲解。通常情况下,LED内部需要通过一定的电流且存在一定的压差(也即压降)才能使得其发光。通常使用的LED的工作电流为3~20mA左右,但二极管本身的内阻又比较小,所以不能直接将两端接电源和GND,而需要加一个限流电阻(阻值读者可通过欧姆定律计算得到),限制通过LED的电流不要太大,LED原理图如图6-1所示。D2在核心板上,LED标号接SWM320的GPIOP.22;D8在底板上,LED_R、LED_G、LED_B分别接GPIOM.5、GPIOM.0、GPIOP.12,由于FSSW32板载资源比较丰富,这些端口有复用,读者可以不用理会,以后项目中用到SDRAM、NorFlash等外设时,LED可能会出现不规则的闪烁,读者知道是怎么回事就好。 注意:电路设计中,标号相同,表示物理连接。 该方式的LED驱动电路是将正极接在3.3V(高电平)上,负极再串联一个47O欧姆的限流电阻,再接到单片机的I/O口上,只需给LED小灯所对应的I/O口上低电平,就可以点亮LED;还有一种接法是将LED的正极接单片机的I/O口,再通过一限流电阻,将负极接地,单片机输出高电平,就可以点亮LED,但是需要将I/O设置为强推挽输出模式,具体情况依设计者的爱好和需求而定。 经上述分析,LED两端只要有一合适的压差和电流,就会点亮LED。那么单片机又是如何控制的呢。举个例子,要有水流,必须有水压差,同样,要有电流,就得有电压差,结合上图,LED的正极已经接了高电平,如果LED所对应的单片机端口也为高电平(LED小灯熄灭),则LED的左右两端电平都是高电平(3.3V),就没有压差,LED就不会亮,相反,若单片机端口为低电平,从而LED两端则会有压差,这样LED灯就会被点亮(LED小灯点亮)。接下来就是通过软件控制LED小灯对应的端口实现周期性的高、低电平变化,就可以实现LED小灯的跑马灯效果。 6.1.2跑马灯的软件设计在设计之前,读者需要建立完整的跑马灯工程,这里我们建立了三个Group,分别为“CMSIS”、“USER”和“SWMLib”,CMSIS下包含两个文件,分别为“startup_SWM320.s”、“system_SWM320.c”,这两个文件是华芯微特官方提供的,至于来源前面有述;USER中就一个读者很熟悉main.c文件,里面的内容是我们实现跑马灯的源码,源码的内容稍后讲述;SWMLib中包括了“SWM320_gpio.c”、“SWM320_port.c”两个文件,同样是官方提供的库函数。工程的建立过程当然还包括文件路径的设置、下载算法RAM大小的修改等,详细的建立过程请读者参考3.2节的内容,建立好的工程如图6-2所示。 工程建立好之后,5个文件我们只需编写main.c文件,其源码如下,剩余的4个只需添加即可。 图6-2 跑马灯工程框架图 1. #include "SWM320.h" 2. 3. void Delay(void) 4. { 5. for(uint16_ti = 0; i < 5000; i++) 6. { 7. for(uint16_tj = 0; j < 1000; j++); 8. } 9. } 10. 11. intmain(void) 12. { 13. SystemInit(); 14. 15. GPIO_Init(GPIOM, PIN0, 1, 0, 0); // 输出, 接LED 16. GPIO_Init(GPIOM, PIN5, 1, 0, 0); // 输出, 接LED 17. GPIO_Init(GPIOP, PIN12, 1, 0, 0); // 输出, 接LED 18. GPIO_Init(GPIOP, PIN22, 1, 0, 0); // 输出, 接LED 19. 20. while(1) 21. { 22. GPIO_ClrBit(GPIOM, PIN0); // 点亮LED小灯 23. Delay(); 24. GPIO_SetBit(GPIOM, PIN0); // 熄灭LED小灯 25. GPIO_ClrBit(GPIOM, PIN5); // 点亮LED小灯 26. Delay(); 27. GPIO_SetBit(GPIOM, PIN5); // 熄灭LED小灯 28. GPIO_ClrBit(GPIOP, PIN12); // 点亮LED小灯 29. Delay(); 30. GPIO_SetBit(GPIOP, PIN12); // 熄灭LED小灯 31. GPIO_ClrBit(GPIOP, PIN22); // 点亮LED小灯 32. Delay(); 33. GPIO_SetBit(GPIOP, PIN22); // 熄灭LED小灯 34. } 35. } 如果前面的内容读者都已经很好的掌握了,这几十行程序应该不难理解,如果读者没有掌握,那接下来笔者为读者简单分析一下这35行语句。 第1行,包含SWM320的头文件,只有包含了这个头文件,才能正确运用库函数,前面讲解库函数的时候和读者有讲述,其各个寄存器的映射地址、结构体指针等都包含在这个头文件中。还有“SWM320_gpio.c”、“SWM320_port.c”两个文件的头文件包含,都是在第1行这个头文件中被包含进来的,如果读者想深入研究,可以选中头文件,右键单击,再选中第二个选项打开该头文件,仔细研读这几千行代码,笔者不建议这么做哈。 第3~9行,是一个简单的延时函数,这个我们在学习51的时候经常用,原理这里不赘。 第13行,这是系统的时钟初始化函数,函数的原型在“system_SWM320.c”中,这个函数我们在后面为读者讲述,这里读者可理解为“空气”。 第15~18行,这个函数我们在5.4节做了详细的讲述,目的是将接LED小灯的4个端口设置为输出端口,而且不使能上、下拉电阻。 第22行,使GPIOM.0端口输出低电平,这样在LED小灯两端形成压差,即可点亮LED小灯。函数原型在“SWM320_gpio.c”中,具体内容后面再述。 第24行,使GPIOM.0端口输出高电平,这样LED小灯两端电平一样,没有压差,LED小灯熄灭。函数原型在“SWM320_gpio.c”中,细节后面再述,剩余行同理,读者自行理解。 6.1.3下载验证待上面的程序编写好之后,编译、下载到FSSW32开发板上,这时可观察到开发板上的4颗LED小灯每隔一定的时间会轮流点亮、熄灭,看起来有点跑马的意思。 6.2启动代码在上面的跑马灯实验中,我们加入了一个“startup_SWM320.s”文件,这个文件俗称启动代码,也即BootLoader。这个代码也是由IC官方编写的,我们只需应用即可,但是这里还是有必要为读者讲述一下,如果读者暂时觉得学起来有点吃力,可以暂时搁置,待学习一段时间的SWM320之后,再结合ARM公司的《M4权威指南》来理解这个启动代码。 6.2.1启动代码的作用概述启动代码由汇编语言编写,是系统上电复位之后第一个执行的程序,主要的功能有以下几点。 (1)堆和栈的初始化 包括堆栈的大小,MSP(main stack pointer)值等,MSP的初始值在复位阶段取自存储区的第一个字(即0地址处的值)。 栈Stack:由编译器自动分配和释放,存放函数的参数值、局部变量的值等,其操作方式类似于数据结构中的栈,向低地址扩展。 堆Heap:一般由程序员分配和释放,若程序员不释放,程序结束时可能由操作系统回收。分配方式类似于数据结构中的链表,向高地址扩展。 (2)向量表定义 定义MSP初值以及各个中断服务程序(ISR)的入口地址。 (3)中断服务程序 CPU根据中断号从向量表中获取入口地址后,跳转至对应的ISR中。 (4)设置系统时钟频率 SWM320的启动代码没有时钟设置,时钟设置在“system_SWM320.c”中。如果读者想把SystemInit()函数添加到服务程序中,可采用如下的方式来实现。 1. Reset_Handler PROC 2. EXPORT Reset_Handler [WEAK] 3. IMPORT SystemInit 4. LDR R0, =SystemInit 5. BLX R0 6. ENDP (5)中断寄存器的初始化 (6)跳转到C应用程序 在复位中断服务程序即Reset_Handler中实现进入C程序。 6.2.2启动代码的详解双击跑马灯工程中的“startup_SWM320.s”文件,浏览发现,启动代码总共有500行左右,此时读者可能无从下手,这里按上面概述的几点将其分类,一点一滴为读者介绍,同时便于讲解,将其堆和栈分开讲述。 1. 栈Stack1. Stack_Size EQU 0x00000400 2. 3. AREA STACK, NOINIT, READWRITE, ALIGN=3 4. Stack_Mem SPACE Stack_Size 5. __initial_sp 分配0x400(也即1K)个连续字节的栈,名称为STACK,NOINT即不初始化,可读可写,8(23)字节对齐,几个指令解释如下。 EQU:宏定义的伪指令,可理解为等于,和C语言中的define类似; AREA:告诉汇编器汇编一个新的代码段或者数据段。STACK表示段名,这个可以任意命名;NOINIT表示不初始化;READWRITE表示可读可写,ALIGN=3,表示按照8(23)字节对齐。 SPACE:用于分配一定大小的内存空间,单位为字节。这里指定大小等于Stack_Size。标号__initial_sp紧挨着SPACE语句放置,表示栈的结束地址,即栈顶地址,栈是由高向低生长的。 栈的作用是用于局部变量,函数调用,函数形参等的开销,栈的大小不能超过内部SRAM 的大小。如果编写的程序比较大,定义的局部变量很多,那么就需要修改栈的大小。如果某一天,读者写的程序出现了莫名奇妙的问题,并进入了硬件fault的时候,就需要考虑是不是栈不够大,已经溢出了。 2. 堆Heap1. Heap_Size EQU 0x00000200 2. 3. AREA HEAP, NOINIT, READWRITE, ALIGN=3 4. __heap_base 5. Heap_Mem SPACE Heap_Size 6. __heap_limit 7. 8. PRESERVE8 9. THUMB 开辟0x200(512B)个字节的堆,名字为HEAP,NOINIT即不初始化,可读可写,8(23)字节对齐。__heap_base表示对的起始地址,__heap_limit表示堆的结束地址。堆是由低向高生长的,跟栈的生长方向相反。堆主要用来动态内存的分配,类似于malloc()函数申请的内存的过程。 PRESERVE8:指定当前文件的堆栈按照8字节对齐。 THUMB:表示后面指令兼容THUMB指令。THUBM是ARM以前的指令集,为16bit,现在 Cortex-M系列的都使用THUMB-2(这里的2可理解为2倍于THUBM指令集)指令集,THUMB-2是32位的,兼容16位和32位的指令,是THUMB的超级。 3. 中断向量表定义1. ; Vector Table Mapped toAddress 0 at Reset 2. AREA RESET, DATA, READONLY 3. EXPORT __Vectors 4. EXPORT __Vectors_End 5. EXPORT __Vectors_Size 6. 7. __Vectors DCD __initial_sp ; Top of Stack 8. DCD Reset_Handler ; Reset Handler 9. DCD NMI_Handler ; NMI Handler 10. DCD HardFault_Handler ; Hard Fault Handler 11. DCD MemManage_Handler ; MPU Fault Handler 12. DCD BusFault_Handler ; Bus Fault Handler 13. DCD UsageFault_Handler ; Usage Fault Handler 14. DCD 0 ; Reserved 15. DCD 0 ; Reserved 16. DCD 0 ; Reserved 17. DCD 0 ; Reserved 18. DCD SVC_Handler ; SVCall Handler 19. DCD DebugMon_Handler ; Debug Monitor Handler 20. DCD 0 ; Reserved 21. DCD PendSV_Handler ; PendSV Handler 22. DCD SysTick_Handler ; SysTick Handler 23. 24. ; External Interrupts 25. DCD GPIOA0_Handler 26. DCD GPIOA1_Handler 27. DCD GPIOA2_Handler 28. DCD GPIOA3_Handler 29. DCD GPIOA4_Handler 30. DCD GPIOA5_Handler 31. DCD GPIOA6_Handler 32. DCD GPIOA7_Handler 33. DCD GPIOB0_Handler 34. DCD GPIOB1_Handler 35. DCD GPIOB2_Handler 36. DCD GPIOB3_Handler 37. DCD GPIOB4_Handler 38. DCD GPIOB5_Handler 39. DCD GPIOB6_Handler 40. DCD GPIOB7_Handler 41. DCD GPIOC0_Handler 42. DCD GPIOC1_Handler 43. DCD GPIOC2_Handler 44. DCD GPIOC3_Handler 45. DCD GPIOC4_Handler 46. DCD GPIOC5_Handler 47. DCD GPIOC6_Handler 48. DCD GPIOC7_Handler 49. DCD GPIOM0_Handler 50. DCD GPIOM1_Handler 51. DCD GPIOM2_Handler 52. DCD GPIOM3_Handler 53. DCD GPIOM4_Handler 54. DCD GPIOM5_Handler 55. DCD GPIOM6_Handler 56. DCD GPIOM7_Handler 57. DCD DMA_Handler 58. DCD LCD_Handler 59. DCD NORFLC_Handler 60. DCD CAN_Handler 61. DCD PULSE_Handler 62. DCD WDT_Handler 63. DCD PWM_Handler 64. DCD UART0_Handler 65. DCD UART1_Handler 66. DCD UART2_Handler 67. DCD UART3_Handler 68. DCD 0 69. DCD I2C0_Handler 70. DCD I2C1_Handler 71. DCD SPI0_Handler 72. DCD ADC0_Handler 73. DCD RTC_Handler 74. DCD ANAC_Handler 75. DCD SDIO_Handler 76. DCD GPIOA_Handler 77. DCD GPIOB_Handler 78. DCD GPIOC_Handler 79. DCD GPIOM_Handler 80. DCD GPION_Handler 81. DCD GPIOP_Handler 82. DCD ADC1_Handler 83. DCD FPU_Handler 84. DCD SPI1_Handler 85. DCD TIMR0_Handler 86. DCD TIMR1_Handler 87. DCD TIMR2_Handler 88. DCD TIMR3_Handler 89. DCD TIMR4_Handler 90. DCD TIMR5_Handler 91. 92. __Vectors_End 93. 94. __Vectors_Size EQU __Vectors_End - __Vectors 第1行为注释,汇编的注释有别于C语言。 第2行定义一个复位向量段,名字为RESET,只读。 第3~5并声明__Vectors_Size、__Vectors_End和__Vectors三个标号具有全局属性,可供外部的文件调用。EXPORT:声明一个标号可被外部的文件使用,使标号具有全局属性。 当内核响应了一个发生的异常后,对应的异常服务例程(ESR)就会执行。为了决定ESR的入口地址,内核使用了―向量表查表机制。这里使用一张向量表。向量表其实是一个WORD(32位整数)数组,每个下标对应一种异常,该下标元素的值则是该ESR的入口地址。向量表在地址空间中的位置是可以设置的,通过NVIC中的一个重定位寄存器来指出向量表的地址。在复位后,该寄存器的值为0。因此,在地址0(即FLASH地址0)处必须包含一张向量表,用于初始时的异常分配。要注意的是这里有个另类:0号类型并不是什么入口地址,而是给出了复位后MSP的初值。 第7~90行,都定义了中断向量的地址。DCD:分配一个或者多个以字为单位的内存,以四字节对齐,并要求初始化这些内存。在向量表中,DCD分配了一堆内存,并且以ESR的入口地址初始化它们。向量表从FLASH的0地址开始放置,以4个字节为一个单位,地址0存放的是栈顶地址,0X04存放的是复位程序的地址,以此类推。从代码上看,向量表中存放的都是中断服务函数的函数名,可我们知道C语言中的函数名就是一个地址。 第94行,__Vectors为向量表起始地址,__Vectors_End为向量表结束地址,两个相减即可算出向量表大小。 4. 复位程序1. AREA |.text|, CODE, READONLY 2. 3. Reset_Handler PROC 4. EXPORT Reset_Handler [WEAK] 5. IMPORT __main 6. LDR R0, =__main 7. BX R0 8. ENDP 第1行,定义一个名称为.text的代码段,可读。 第3~8,复位子程序是系统上电后第一个执行的程序,调用C库函数_mian,最终调用main函数去到C的世界里。除了代码外,笔者再为读者解释一下这些陌生的命令。 WEAK:表示弱定义,如果外部文件优先定义了该标号则首先引用该标号,如果外部文件没有声明也不会出错。这里表示复位子程序可以由用户在其他文件重新实现,这里并不是唯一的。 IMPORT:表示该标号来自外部文件,其作用和C语言中的“extern”关键字类似。这里表示__main函数来自外部的文件。 __main是一个标准的C库函数,主要作用是初始化用户堆栈,最终调用main函数去到C的世界里。这就是为什么我们写的程序都有一个main函数的原因。读者此时可能会问到,能不能不调用__main,用SWM_main呢?答案当然是肯定的。我们只需修改主函数的名称,然后在IMPORT里写自己的主函数名称即可,实例代码如下。 1. AREA |.text|, CODE, READONLY 2. 3. Reset_Handler PROC 4. EXPORT Reset_Handler [WEAK] 5. IMPORT SWM_main 6. LDR R0, = SWM_main 7. BX R0 8. ENDP 那么C世界里的代码就如下: 1. int SWM_main(void) 2. { 3. SystemInit(); 4. 5. while(1) 6. { 7. } 8. } 其中LDR、BLX、BX等内核的指令,请读者参阅《M4权威指南》。 5. 中断服务程序1. NMI_Handler PROC 2. EXPORT NMI_Handler [WEAK] 3. B . 4. ENDP 5. 6. HardFault_Handler PROC 7. EXPORT HardFault_Handler [WEAK] 8. B . 9. ENDP 10. 11. MemManage_Handler PROC 12. EXPORT MemManage_Handler [WEAK] 13. B . 14. ENDP 15. 16. BusFault_Handler PROC 17. EXPORT BusFault_Handler [WEAK] 18. B . 19. ENDP 20. 21. UsageFault_Handler PROC 22. EXPORT UsageFault_Handler [WEAK] 23. B . 24. ENDP 25. 26. SVC_Handler PROC 27. EXPORT SVC_Handler [WEAK] 28. B . 29. ENDP 30. 31. DebugMon_Handler PROC 32. EXPORT DebugMon_Handler [WEAK] 33. B . 34. ENDP 35. 36. PendSV_Handler PROC 37. EXPORT PendSV_Handler [WEAK] 38. B . 39. ENDP 40. 41. SysTick_Handler PROC 42. EXPORT SysTick_Handler [WEAK] 43. B . 44. ENDP 45. 46. GPIOA0_IRQHandler PROC 47. EXPORT GPIOA0_IRQHandler [WEAK] 48. B . 49. ENDP 50. 51. GPIOA1_IRQHandler PROC 52. EXPORT GPIOA1_IRQHandler [WEAK] 53. B . 54. ENDP 55. 56. GPIOA2_IRQHandler PROC 57. EXPORT GPIOA2_IRQHandler [WEAK] 58. B . 59. ENDP 60. 61. GPIOA3_IRQHandler PROC 62. EXPORT GPIOA3_IRQHandler [WEAK] 63. B . 64. ENDP 65. 66. GPIOA4_IRQHandler PROC 67. EXPORT GPIOA4_IRQHandler [WEAK] 68. B . 69. ENDP 70. 71. GPIOA5_IRQHandler PROC 72. EXPORT GPIOA5_IRQHandler [WEAK] 73. B . 74. ENDP 75. 76. GPIOA6_IRQHandler PROC 77. EXPORT GPIOA6_IRQHandler [WEAK] 78. B . 79. ENDP 80. 81. GPIOA7_IRQHandler PROC 82. EXPORT GPIOA7_IRQHandler [WEAK] 83. B . 84. ENDP 85. 86. GPIOB0_IRQHandler PROC 87. EXPORT GPIOB0_IRQHandler [WEAK] 88. B . 89. ENDP 90. 91. GPIOB1_IRQHandler PROC 92. EXPORT GPIOB1_IRQHandler [WEAK] 93. B . 94. ENDP 95. 96. GPIOB2_IRQHandler PROC 97. EXPORT GPIOB2_IRQHandler [WEAK] 98. B . 99. ENDP 100. 101. GPIOB3_IRQHandler PROC 102. EXPORT GPIOB3_IRQHandler [WEAK] 103. B . 104. ENDP 105. 106. GPIOB4_IRQHandler PROC 107. EXPORT GPIOB4_IRQHandler [WEAK] 108. B . 109. ENDP 110. 111. GPIOB5_IRQHandler PROC 112. EXPORT GPIOB5_IRQHandler [WEAK] 113. B . 114. ENDP 115. 116. GPIOB6_IRQHandler PROC 117. EXPORT GPIOB6_IRQHandler [WEAK] 118. B . 119. ENDP 120. 121. GPIOB7_IRQHandler PROC 122. EXPORT GPIOB7_IRQHandler [WEAK] 123. B . 124. ENDP 125. 126. GPIOC0_IRQHandler PROC 127. EXPORT GPIOC0_IRQHandler [WEAK] 128. B . 129. ENDP 130. 131. GPIOC1_IRQHandler PROC 132. EXPORT GPIOC1_IRQHandler [WEAK] 133. B . 134. ENDP 135. 136. GPIOC2_IRQHandler PROC 137. EXPORT GPIOC2_IRQHandler [WEAK] 138. B . 139. ENDP 140. 141. GPIOC3_IRQHandler PROC 142. EXPORT GPIOC3_IRQHandler [WEAK] 143. B . 144. ENDP 145. 146. GPIOC4_IRQHandler PROC 147. EXPORT GPIOC4_IRQHandler [WEAK] 148. B . 149. ENDP 150. 151. GPIOC5_IRQHandler PROC 152. EXPORT GPIOC5_IRQHandler [WEAK] 153. B . 154. ENDP 155. 156. GPIOC6_IRQHandler PROC 157. EXPORT GPIOC6_IRQHandler [WEAK] 158. B . 159. ENDP 160. 161. GPIOC7_IRQHandler PROC 162. EXPORT GPIOC7_IRQHandler [WEAK] 163. B . 164. ENDP 165. 166. GPIOM0_IRQHandler PROC 167. EXPORT GPIOM0_IRQHandler [WEAK] 168. B . 169. ENDP 170. 171. GPIOM1_IRQHandler PROC 172. EXPORT GPIOM1_IRQHandler [WEAK] 173. B . 174. ENDP 175. 176. GPIOM2_IRQHandler PROC 177. EXPORT GPIOM2_IRQHandler [WEAK] 178. B . 179. ENDP 180. 181. GPIOM3_IRQHandler PROC 182. EXPORT GPIOM3_IRQHandler [WEAK] 183. B . 184. ENDP 185. 186. GPIOM4_IRQHandler PROC 187. EXPORT GPIOM4_IRQHandler [WEAK] 188. B . 189. ENDP 190. 191. GPIOM5_IRQHandler PROC 192. EXPORT GPIOM5_IRQHandler [WEAK] 193. B . 194. ENDP 195. 196. GPIOM6_IRQHandler PROC 197. EXPORT GPIOM6_IRQHandler [WEAK] 198. B . 199. ENDP 200. 201. GPIOM7_IRQHandler PROC 202. EXPORT GPIOM7_IRQHandler [WEAK] 203. B . 204. ENDP 205. 206. DMA_IRQHandler PROC 207. EXPORT DMA_IRQHandler [WEAK] 208. B . 209. ENDP 210. 211. LCD_IRQHandler PROC 212. EXPORT LCD_IRQHandler [WEAK] 213. B . 214. ENDP 215. 216. NORFLC_IRQHandler PROC 217. EXPORT NORFLC_IRQHandler [WEAK] 218. B . 219. ENDP 220. 221. CAN_IRQHandler PROC 222. EXPORT CAN_IRQHandler [WEAK] 223. B . 224. ENDP 225. 226. TIMR_IRQHandler PROC 227. EXPORT TIMR_IRQHandler [WEAK] 228. B . 229. ENDP 230. 231. WDT_IRQHandler PROC 232. EXPORT WDT_IRQHandler [WEAK] 233. B . 234. ENDP 235. 236. PWM_IRQHandler PROC 237. EXPORT PWM_IRQHandler [WEAK] 238. B . 239. ENDP 240. 241. UART0_IRQHandler PROC 242. EXPORT UART0_IRQHandler [WEAK] 243. B . 244. ENDP 245. 246. UART1_IRQHandler PROC 247. EXPORT UART1_IRQHandler [WEAK] 248. B . 249. ENDP 250. 251. UART2_IRQHandler PROC 252. EXPORT UART2_IRQHandler [WEAK] 253. B . 254. ENDP 255. 256. UART3_IRQHandler PROC 257. EXPORT UART3_IRQHandler [WEAK] 258. B . 259. ENDP 260. 261. I2C0_IRQHandler PROC 262. EXPORT I2C0_IRQHandler [WEAK] 263. B . 264. ENDP 265. 266. I2C1_IRQHandler PROC 267. EXPORT I2C1_IRQHandler [WEAK] 268. B . 269. ENDP 270. 271. SPI0_IRQHandler PROC 272. EXPORT SPI0_IRQHandler [WEAK] 273. B . 274. ENDP 275. 276. ADC0_IRQHandler PROC 277. EXPORT ADC0_IRQHandler [WEAK] 278. B . 279. ENDP 280. 281. RTC_IRQHandler PROC 282. EXPORT RTC_IRQHandler [WEAK] 283. B . 284. ENDP 285. 286. ANAC_IRQHandler PROC 287. EXPORT ANAC_IRQHandler [WEAK] 288. B . 289. ENDP 290. 291. SDIO_IRQHandler PROC 292. EXPORT SDIO_IRQHandler [WEAK] 293. B . 294. ENDP 295. 296. GPIOA_IRQHandler PROC 297. EXPORT GPIOA_IRQHandler [WEAK] 298. B . 299. ENDP 300. 301. GPIOB_IRQHandler PROC 302. EXPORT GPIOB_IRQHandler [WEAK] 303. B . 304. ENDP 305. 306. GPIOC_IRQHandler PROC 307. EXPORT GPIOC_IRQHandler [WEAK] 308. B . 309. ENDP 310. 311. GPIOM_IRQHandler PROC 312. EXPORT GPIOM_IRQHandler [WEAK] 313. B . 314. ENDP 315. 316. GPION_IRQHandler PROC 317. EXPORT GPION_IRQHandler [WEAK] 318. B . 319. ENDP 320. 321. GPIOP_IRQHandler PROC 322. EXPORT GPIOP_IRQHandler [WEAK] 323. B . 324. ENDP 325. 326. ADC1_IRQHandler PROC 327. EXPORT ADC1_IRQHandler [WEAK] 328. B . 329. ENDP 330. 331. FPU_IRQHandler PROC 332. EXPORT FPU_IRQHandler [WEAK] 333. B . 334. ENDP 335. 336. SPI1_IRQHandler PROC 337. EXPORT SPI1_IRQHandler [WEAK] 338. B . 339. ENDP 在启动文件里面已经帮我们写好了所有中断的中断服务函数,跟我们平时写的中断服务函数不一样的就是这些函数都是空的,真正的中断复服务程序需要我们在外部的C文件里面重新实现,这里只是提前抢占了一个位置而已。如果我们在使用某个外设的时候,开启了某个中断,但是又忘记编写配套的中断服务程序或者函数名写错,那当中断来临的时,程序就会跳转到启动代码中预先写好空的中断服务程序里,并且在这个空函数中无线循环,这样程序就会死在这里。 B:跳转到一个标号。这里跳转到一个‘.’,即表示无线循环,有点类似于C语言中的while(1)。 6. 用户堆栈初始化1. ALIGN 2. 3. ;************************************************************************** 4. ; User Stack and Heapinitialization 5. ;************************************************************************** 6. IF :DEF:__MICROLIB 7. 8. EXPORT __initial_sp 9. EXPORT __heap_base 10. EXPORT __heap_limit 11. 12. ELSE 13. 14. IMPORT __use_two_region_memory 15. EXPORT __user_initial_stackheap 16. 17. __user_initial_stackheap 18. 19. LDR R0, = Heap_Mem 20. LDR R1, =(Stack_Mem + Stack_Size) 21. LDR R2, = (Heap_Mem + Heap_Size) 22. LDR R3, = Stack_Mem 23. BX LR 24. 25. ALIGN 26. 27. ENDIF 28. 29. END 第1行,ALIGN:对指令或者数据存放的地址进行对齐,后面会跟一个立即数。缺省表示4字节对齐。 第6~27行,判断是否定义了__MICROLIB,如果定义了则赋予标号__initial_sp(栈顶地址)、__heap_base(堆起始地址)、__heap_limit(堆结束地址)全局属性,可供外部文件调用。如果没有定义(实际的情况就是我们没定义__MICROLIB)则使用默认的C库,然后初始化用户堆栈大小,这部分由C库函数__main来完成,当初始化完堆栈之后,就调用main函数去到C的世界。 DEF:XXX,表示XXX定了则为真,否则为假。类似于C语言中的“#define”。 |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
75个成员聚集在这个小组
加入小组【深入浅出Cortex M4-SWM320 第六章】跑马灯与启动文件
7217 浏览 0 评论
5183 浏览 2 评论
4263 浏览 9 评论
320浏览 0评论
391浏览 0评论
280浏览 0评论
328浏览 0评论
323浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-12-2 22:22 , Processed in 0.612676 second(s), Total 72, Slave 54 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号