STM32启动代码分析、简化、实战

STM32启动代码分析、简化、实战
STM32启动代码分析、简化、实战

本文通过对STM32的官方固件库

STM32F10x_StdPeriph_Lib_V3.5.0

里的MDK启动文件分析,简化部分不需要的代码,

并从繁杂的固件库里,精炼出一个类似于“hello world”的入门实战小程序——点亮一个LED。该工程仅仅包含一个启动文件和一个有main函数的C文件。

本文初衷:不用固件库建立自己的工程!

实验软件:Keil uVision4

实验硬件:神舟IV号开发板

芯片型号:STM32F107VC

STM32启动代码分析、简化、实战

汇编基础:

1.伪指令:EQU

语法格式:名称EQU表达式{,类型}

EQU伪指令用于为程序中的常量、标号等定义一个等效的字符名称,类似于C语言的#define。其中EQU可以用“*”代替。

名称为EQU伪指令定义的字符名称,当表达式为32位的常量时,可以指定表达式的数据类型,可以有一下三种类型:

CODE16、CODE32和DA TA

2.伪指令:AREA

语法格式:AREA段名{,属性1}{,属性2}……

AREA命令指示汇编程序汇编一个新的代码段或数据段。段是独立的、指定的、不可见的代码或数据块,它们由链接程序处理。

段名:可以为段选择任何段名。但是,以一个数字开始的名称必须包含在竖杠号内,否则会产生一个缺失段名错误。例如,|1_DataArea|。

有些名称是习惯性的名称。例如:|.text|用于表示由C编译程序产生的代码段,或用于以某种方式与C库关联的代码段。

属性字段表示该代码段(或数据段)的相关属性,多个属性用逗号分隔。常用的属性如下:——CODE属性:用于定义代码段,默认为READONLY。

——DA TA属性:用于定义数据段,默认为READWRITE。

——READONLY属性:指定本段为只读,代码段默认为READONLY。

——READWRITE属性:指定本段为可读可写,数据段的默认属性为READWRITE。——ALIGN属性:使用方式为ALIGN表达式。在默认时,ELF(可执行连接文件)的代码段和数据段是按字对齐的,表达式的取值范围为0~31,相应的对齐方式为2表达式次方。——NOINIT属性:表示数据段是未初始化的或初始化为零。其只包含零初始化的空间保留命令SPACE或DCB、DCD、DCDU、DCQ、DCQU、DCW或DCWU。可以决定在链接时AREA是未初始化的还是零初始化的。

一个汇编语言程序至少要包含一个段,当程序太长时,也可以将程序分为多个代码段和数据段。

3.伪指令:SPACE用于分配一片连续的存储单元

启动代码分析:

定义栈段,不初始化

栈名:STACK

大小:Stack_Size

只分配空间不做初始化或者初始化为0:NOINIT

可读可写:READWRITE:

按8字节对齐:ALIGN=3

栈顶地址:__initial_sp

Stack_Size EQU0x00000400

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size

__initial_sp

定义堆段,不初始化

堆名:HEAP

大小:Heap_Size

只分配空间不做初始化或者初始化为0:NOINIT

可读可写:READWRITE:

按8字节对齐:ALIGN=3

堆起始地址:__heap_base

堆终止地址:__heap_limit

Heap_Size EQU0x00000200

AREA HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem SPACE Heap_Size

__heap_limit

4.伪指令:EXPORT

语法格式:EXPORT标号{[WEAK]}

EXPORT伪指令用于在程序中声明一个全局的标号,该标号可在其他的文件中引用。EXPORT可用GLOBAL代替。标号在程序中区分大小写,[WEAK]选项声明其他的同名标号优先于该标号被引用。

5.伪指令:DCD

语法格式:DCD(或DCDU)表达式

DCD(或DCDU)伪指令用于分配一片连续的字存储单元并用伪指令中指定的表达式初始化。其中,表达式可以为程序标号或数字表达式。DCD也可用“&”代替。

用DCD分配的字存储单元是字对齐的,而用DCDU分配的字存储单元并不严格字对齐。

PRESERVE8 ;指示编译器8字节对齐(keil编译器时需要加上)

THUMB ;指示编译器为THUMB指令

定义复位段(中断向量表),并初始化

段名:RESET

大小:__V ectors_Size

数据段:DA TA

只读:READONLY

按字节对齐:默认ALIGN

向量表起始地址:__V ectors

向量表终止地址:__V ectors_End

AREA RESET, DA TA, READONLY

EXPORT __V ectors

EXPORT __V ectors_End

EXPORT __V ectors_Size

__V ectors DCD __initial_sp ; Top of Stack

DCD Reset_Handler ; Reset Handler

DCD NMI_Handler ; NMI Handler

DCD HardFault_Handler ; Hard Fault Handler

DCD MemManage_Handler ; MPU Fault Handler

DCD BusFault_Handler ; Bus Fault Handler

DCD UsageFault_Handler ; Usage Fault Handler

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD SVC_Handler ; SVCall Handler

DCD DebugMon_Handler ; Debug Monitor Handler

DCD 0 ; Reserved

DCD PendSV_Handler ; PendSV Handler

DCD SysTick_Handler ; SysTick Handler

; External Interrupts

DCD WWDG_IRQHandler ; Window Watchdog

DCD PVD_IRQHandler ; PVD through EXTI Line detect

DCD TAMPER_IRQHandler ; Tamper

DCD RTC_IRQHandler ; RTC

DCD FLASH_IRQHandler ; Flash

DCD RCC_IRQHandler ; RCC

DCD EXTI0_IRQHandler ; EXTI Line 0

DCD EXTI1_IRQHandler ; EXTI Line 1

DCD EXTI2_IRQHandler ; EXTI Line 2

DCD EXTI3_IRQHandler ; EXTI Line 3

DCD EXTI4_IRQHandler ; EXTI Line 4

DCD DMA1_Channel1_IRQHandler ; DMA1 Channel 1

DCD DMA1_Channel2_IRQHandler ; DMA1 Channel 2

DCD DMA1_Channel3_IRQHandler ; DMA1 Channel 3

DCD DMA1_Channel4_IRQHandler ; DMA1 Channel 4

DCD DMA1_Channel5_IRQHandler ; DMA1 Channel 5

DCD DMA1_Channel6_IRQHandler ; DMA1 Channel 6

DCD DMA1_Channel7_IRQHandler ; DMA1 Channel 7

DCD ADC1_2_IRQHandler ; ADC1 and ADC2

DCD CAN1_TX_IRQHandler ; CAN1 TX

DCD CAN1_RX0_IRQHandler ; CAN1 RX0

DCD CAN1_RX1_IRQHandler ; CAN1 RX1

DCD CAN1_SCE_IRQHandler ; CAN1 SCE

DCD EXTI9_5_IRQHandler ; EXTI Line 9..5

DCD TIM1_BRK_IRQHandler ; TIM1 Break

DCD TIM1_UP_IRQHandler ; TIM1 Update

DCD TIM1_TRG_COM_IRQHandler ; TIM1 Trigger and Commutation

DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare

DCD TIM2_IRQHandler ; TIM2

DCD TIM3_IRQHandler ; TIM3

DCD TIM4_IRQHandler ; TIM4

DCD I2C1_EV_IRQHandler ; I2C1 Event

DCD I2C1_ER_IRQHandler ; I2C1 Error

DCD I2C2_EV_IRQHandler ; I2C2 Event

DCD I2C2_ER_IRQHandler ; I2C1 Error

DCD SPI1_IRQHandler ; SPI1

DCD SPI2_IRQHandler ; SPI2

DCD USART1_IRQHandler ; USART1

DCD USART2_IRQHandler ; USART2

DCD USART3_IRQHandler ; USART3

DCD EXTI15_10_IRQHandler ; EXTI Line 15..10

DCD RTCAlarm_IRQHandler ; RTC alarm through EXTI line

DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD TIM5_IRQHandler ; TIM5

DCD SPI3_IRQHandler ; SPI3

DCD UART4_IRQHandler ; UART4

DCD UART5_IRQHandler ; UART5

DCD TIM6_IRQHandler ; TIM6

DCD TIM7_IRQHandler ; TIM7

DCD DMA2_Channel1_IRQHandler ; DMA2 Channel1

DCD DMA2_Channel2_IRQHandler ; DMA2 Channel2

DCD DMA2_Channel3_IRQHandler ; DMA2 Channel3

DCD DMA2_Channel4_IRQHandler ; DMA2 Channel4

DCD DMA2_Channel5_IRQHandler ; DMA2 Channel5

DCD ETH_IRQHandler ; Ethernet

DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line

DCD CAN2_TX_IRQHandler ; CAN2 TX

DCD CAN2_RX0_IRQHandler ; CAN2 RX0

DCD CAN2_RX1_IRQHandler ; CAN2 RX1

DCD CAN2_SCE_IRQHandler ; CAN2 SCE

DCD OTG_FS_IRQHandler ; USB OTG FS

__V ectors_End

__V ectors_Size EQU__V ectors_End - __V ectors

6.过程定义伪指令:PROC、ENDP

语法格式:<过程名> PROC [类型]

……

RET

<过程名> ENDP

过程就是子程序。一个过程可以被其它程序所调用(用CALL指令),过程的最后一条指令一

般是返回指令(RET)。

7.伪指令:IMPORT

语法格式:IMPORT 标号{[WEAK]}

IMPORT伪指令用于通知编译器要使用的标号在其他源文件中定义,但是在当前源文件中引用,而且无论当前源文件是否引用该标号,该标号均会被加入到当前源文件的标号表中。

标号在程序中区分大小写,[WEAK]选项表示当所有的源文件都没有定义这样的一个标号时,编译器也不给出错误信息,在多数情况下将该标号置为0,若该标号为B或BL指令引用,则将B或BL指令置为NOP操作。

8.伪指令:LDR

语法格式:LDR{执行条件,如EQ、NE等} register,=expr/label_expr

大范围的地址读取伪指令LDR用于加载32位的立即数或一个地址值到指定寄存器,在汇编编译源程序时,LDR伪指令被编译器替换成一条合适的指令。若加载的常数未超出MOV 或MVN的范围,则使用MOV或MVN指令代替LDR伪指令,否则汇编器将常量放入字池,并使用一条程序相对偏移的LDR指令从文字池读出常量。

9.Thumb跳转指令:B、BL、BX

语法格式:B{执行条件,如EQ、NE等} label

带链接BL{执行条件,如EQ、NE等} label

带状态切换BX{执行条件,如EQ、NE等} label

定义代码段(异常处理函数),并初始化

段名:.text

代码段:CODE

只读:READONLY

按字节对齐:默认ALIGN

代码段起始地址:Reset_Handler

AREA|.text|, CODE, READONLY

Reset_Handler PROC

EXPORT Reset_Handler [WEAK]

IMPORT SystemInit

IMPORT__main

LDR R0, =SystemInit

BLX R0

LDR R0, =__main

BX R0

ENDP

10.内置变量:{PC} 或“.”当前指令地址

11.汇编语句格式规范:

ARM汇编中,所有标号必须在一行的顶格书写,其后面不要添加“:”,而所有指令均不能顶格书写。

ARM汇编器对标识符大小写敏感,书写标号及指令时字母大小写要一致,在ARM汇编程序中,一个ARM指令、伪指令、寄存器名可以全部为大写字母,也可以全部为小写字母,但不要大小写混合使用。

注释使用“;”,注释内容由“;”开始到此行结束,注释可以在一行的顶格书写。

源程序中允许有空行,适当地插入空行可以提高源程序代码的可读性。如果单行太长,可以

使用字符“\”将其分行,“\”后不能有任何字符,包括空格和制表符等。对于变量的设置,常量的定义,其标识符必须在一行的顶格书写。

异常处理函数(续1)

NMI_Handler PROC

EXPORT NMI_Handler [WEAK]

B.

ENDP

HardFault_Handler PROC

EXPORT HardFault_Handler [WEAK]

B.

ENDP

MemManage_Handler\

PROC

EXPORT MemManage_Handler [WEAK]

B .

ENDP

BusFault_Handler\

PROC

EXPORT BusFault_Handler [WEAK]

B .

ENDP

UsageFault_Handler\

PROC

EXPORT UsageFault_Handler [WEAK]

B .

ENDP

SVC_Handler PROC

EXPORT SVC_Handler [WEAK]

B .

ENDP

DebugMon_Handler\

PROC

EXPORT DebugMon_Handler [WEAK]

B .

ENDP

PendSV_Handler PROC

EXPORT PendSV_Handler [WEAK]

B .

ENDP

SysTick_Handler PROC

EXPORT SysTick_Handler [WEAK]

B .

ENDP

异常处理函数(续2)

这个默认的异常处理函数处理所有外部中断

Default_Handler PROC

EXPORT WWDG_IRQHandler [WEAK]

EXPORT PVD_IRQHandler [WEAK]

EXPORT TAMPER_IRQHandler [WEAK]

EXPORT RTC_IRQHandler [WEAK]

EXPORT FLASH_IRQHandler [WEAK]

EXPORT RCC_IRQHandler [WEAK]

EXPORT EXTI0_IRQHandler [WEAK]

EXPORT EXTI1_IRQHandler [WEAK]

EXPORT EXTI2_IRQHandler [WEAK]

EXPORT EXTI3_IRQHandler [WEAK]

EXPORT EXTI4_IRQHandler [WEAK]

EXPORT DMA1_Channel1_IRQHandler [WEAK]

EXPORT DMA1_Channel2_IRQHandler [WEAK]

EXPORT DMA1_Channel3_IRQHandler [WEAK]

EXPORT DMA1_Channel4_IRQHandler [WEAK]

EXPORT DMA1_Channel5_IRQHandler [WEAK]

EXPORT DMA1_Channel6_IRQHandler [WEAK]

EXPORT DMA1_Channel7_IRQHandler [WEAK]

EXPORT ADC1_2_IRQHandler [WEAK]

EXPORT CAN1_TX_IRQHandler [WEAK]

EXPORT CAN1_RX0_IRQHandler [WEAK]

EXPORT CAN1_RX1_IRQHandler [WEAK]

EXPORT CAN1_SCE_IRQHandler [WEAK]

EXPORT EXTI9_5_IRQHandler [WEAK]

EXPORT TIM1_BRK_IRQHandler [WEAK]

EXPORT TIM1_UP_IRQHandler [WEAK]

EXPORT TIM1_TRG_COM_IRQHandler [WEAK]

EXPORT TIM1_CC_IRQHandler [WEAK]

EXPORT TIM2_IRQHandler [WEAK]

EXPORT TIM3_IRQHandler [WEAK]

EXPORT TIM4_IRQHandler [WEAK]

EXPORT I2C1_EV_IRQHandler [WEAK]

EXPORT I2C1_ER_IRQHandler [WEAK]

EXPORT I2C2_EV_IRQHandler [WEAK]

EXPORT I2C2_ER_IRQHandler [WEAK]

EXPORT SPI1_IRQHandler [WEAK]

EXPORT SPI2_IRQHandler [WEAK]

EXPORT USART1_IRQHandler [WEAK]

EXPORT USART2_IRQHandler [WEAK]

EXPORT USART3_IRQHandler [WEAK]

EXPORT EXTI15_10_IRQHandler [WEAK]

EXPORT RTCAlarm_IRQHandler [WEAK]

EXPORT OTG_FS_WKUP_IRQHandler [WEAK]

EXPORT TIM5_IRQHandler [WEAK]

EXPORT SPI3_IRQHandler [WEAK]

EXPORT UART4_IRQHandler [WEAK]

EXPORT UART5_IRQHandler [WEAK]

EXPORT TIM6_IRQHandler [WEAK]

EXPORT TIM7_IRQHandler [WEAK]

EXPORT DMA2_Channel1_IRQHandler [WEAK]

EXPORT DMA2_Channel2_IRQHandler [WEAK]

EXPORT DMA2_Channel3_IRQHandler [WEAK]

EXPORT DMA2_Channel4_IRQHandler [WEAK]

EXPORT DMA2_Channel5_IRQHandler [WEAK]

EXPORT ETH_IRQHandler [WEAK]

EXPORT ETH_WKUP_IRQHandler [WEAK]

EXPORT CAN2_TX_IRQHandler [WEAK]

EXPORT CAN2_RX0_IRQHandler [WEAK]

EXPORT CAN2_RX1_IRQHandler [WEAK]

EXPORT CAN2_SCE_IRQHandler [WEAK]

EXPORT OTG_FS_IRQHandler [WEAK]

;下面的全部异常处理函数标号都对应同一个地址,这个地址也是Default_Handler的地址WWDG_IRQHandler

PVD_IRQHandler

TAMPER_IRQHandler

RTC_IRQHandler

FLASH_IRQHandler

RCC_IRQHandler

EXTI0_IRQHandler

EXTI1_IRQHandler

EXTI2_IRQHandler

EXTI3_IRQHandler

EXTI4_IRQHandler

DMA1_Channel1_IRQHandler

DMA1_Channel2_IRQHandler

DMA1_Channel3_IRQHandler

DMA1_Channel4_IRQHandler

DMA1_Channel5_IRQHandler

DMA1_Channel6_IRQHandler

DMA1_Channel7_IRQHandler

ADC1_2_IRQHandler

CAN1_TX_IRQHandler

CAN1_RX0_IRQHandler

CAN1_RX1_IRQHandler

CAN1_SCE_IRQHandler EXTI9_5_IRQHandler

TIM1_BRK_IRQHandler

TIM1_UP_IRQHandler

TIM1_TRG_COM_IRQHandler TIM1_CC_IRQHandler

TIM2_IRQHandler

TIM3_IRQHandler

TIM4_IRQHandler

I2C1_EV_IRQHandler

I2C1_ER_IRQHandler

I2C2_EV_IRQHandler

I2C2_ER_IRQHandler

SPI1_IRQHandler

SPI2_IRQHandler

USART1_IRQHandler USART2_IRQHandler USART3_IRQHandler

EXTI15_10_IRQHandler RTCAlarm_IRQHandler

OTG_FS_WKUP_IRQHandler TIM5_IRQHandler

SPI3_IRQHandler

UART4_IRQHandler

UART5_IRQHandler

TIM6_IRQHandler

TIM7_IRQHandler

DMA2_Channel1_IRQHandler DMA2_Channel2_IRQHandler DMA2_Channel3_IRQHandler DMA2_Channel4_IRQHandler DMA2_Channel5_IRQHandler ETH_IRQHandler

ETH_WKUP_IRQHandler CAN2_TX_IRQHandler

CAN2_RX0_IRQHandler

CAN2_RX1_IRQHandler

CAN2_SCE_IRQHandler OTG_FS_IRQHandler

B . ENDP

初始化堆栈段

由于前面只是定义了堆栈段并没有初始化,这里对堆栈段进行初始化。就像定义了:int a; 初始化a = 1;也可以像代码段一样定义的同时就初始化:int b = 2;

下面代码中有个__MICROLIB,对应后面MDK截图的Use MicroLIB,如果选了勾选了Use MicroLIB,IF就为真,否则为假。

ALIGN

IF :DEF:__MICROLIB

EXPORT __initial_sp

EXPORT __heap_base

EXPORT __heap_limit

ELSE

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR R0, =Heap_Mem

LDR R1, = (Stack_Mem + Stack_Size)

LDR R2, = (Heap_Mem + Heap_Size)

LDR R3, = Stack_Mem

BX LR

ALIGN

ENDIF

END

+++++++++++启动代码分析到此结束++++++++++++++

简化后的启动代码

1.去掉外部中断,去掉__MICROLIB判断,如果需要可以手动添加

2.去掉SystemInit,系统初始化可以在main函数里进行

3.去掉[WEAK],如果用户自己想定义内部中断服务程序可以加上[WEAK]

;定义栈

Stack_Size EQU 0x00000400

AREA STACK, NOINIT, READWRITE, ALIGN=3

Stack_Mem SPACE Stack_Size

__initial_sp

;定义堆

Heap_Size EQU 0x00000200

AREA HEAP, NOINIT, READWRITE, ALIGN=3

__heap_base

Heap_Mem SPACE Heap_Size

__heap_limit

;MDK关键字

PRESERVE8

THUMB

;定义并初始化中断向量表

AREA RESET, DA TA, READONLY

EXPORT __V ectors

EXPORT __V ectors_End

EXPORT __V ectors_Size

__V ectors DCD __initial_sp ; Top of Stack

DCD Reset_Handler ; Reset Handler

DCD NMI_Handler ; NMI Handler

DCD HardFault_Handler ; Hard Fault Handler

DCD MemManage_Handler ; MPU Fault Handler

DCD BusFault_Handler ; Bus Fault Handler

DCD UsageFault_Handler ; Usage Fault Handler

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD 0 ; Reserved

DCD SVC_Handler ; SVCall Handler

DCD DebugMon_Handler ; Debug Monitor Handler

DCD 0 ; Reserved

DCD PendSV_Handler ; PendSV Handler

DCD SysTick_Handler ; SysTick Handler

__V ectors_End

__V ectors_Size EQU __V ectors_End - __V ectors

;定义并初始化代码段,程序正真的入口

AREA |.text|, CODE, READONLY

Reset_Handler PROC

;__main为运行时库提供的函数,会调用下面定义的__user_initial_stackheap,初始化堆栈。

IMPORT __main

LDR R0, =__main

BX R0 ;进入main

ENDP

;异常服务程序,对应同一个死循环的地址

NMI_Handler

HardFault_Handler

MemManage_Handler

BusFault_Handler

UsageFault_Handler

SVC_Handler

DebugMon_Handler

PendSV_Handler

SysTick_Handler PROC

B .

ENDP

;初始化堆栈

ALIGN

IMPORT __use_two_region_memory

EXPORT __user_initial_stackheap

__user_initial_stackheap

LDR R0, = Heap_Mem

LDR R1, = (Stack_Mem + Stack_Size)

LDR R2, = (Heap_Mem + Heap_Size)

LDR R3, = Stack_Mem

BX LR

ALIGN

END

;*************************END OF FILE**********************************

启动代码实战(点亮一个LED)1.打开Keil,新建工程,命名LED保存。

2.选择芯片型号STM32F107VC,点击OK

3.是否要默认启动代码,点击否

4.新建启动文件,保存为start_up.s,并添加到工程中。

5.新建C程序文件,保存为main.c,并添加到工作中

6.拷贝启动代码到start_up.s中,并保存。

7.拷贝C程序到main.c中,并保存。(C程序在最后)

8.勾选Create HEX File

9.编译链接,产生hex文件。

10.下载到开发板上运行。

11.运行结果

/*************************************************************************/

/* 本程序精炼自STM32官方固件库,留下必要的代码,并做了详细说明*/

/*************************************************************************/

/* 定义时钟结构体*/

typedef struct

{

volatile unsigned int CR;

volatile unsigned int CFGR;

volatile unsigned int CIR;

volatile unsigned int APB2RSTR;

volatile unsigned int APB1RSTR;

volatile unsigned int AHBENR;

volatile unsigned int APB2ENR;

volatile unsigned int APB1ENR;

volatile unsigned int BDCR;

volatile unsigned int CSR;

volatile unsigned int AHBRSTR;

volatile unsigned int CFGR2;

} RCC_TypeDef;

/* 定义时钟结构体的指针变量*/

#define RCC ((RCC_TypeDef *)0x40021000)

/* memory mapped structure for System Control Block (SCB) */

typedef struct

{

volatile unsigned int CPUID;

volatile unsigned int ICSR;

volatile unsigned int VTOR; /* 存放中断向量表的起始地址的寄存器*/ volatile unsigned int AIRCR;

volatile unsigned int SCR;

volatile unsigned int CCR;

volatile unsigned int SHP[12];

volatile unsigned int SHCSR;

volatile unsigned int CFSR;

volatile unsigned int HFSR;

volatile unsigned int DFSR;

volatile unsigned int MMFAR;

volatile unsigned int BFAR;

volatile unsigned int AFSR;

volatile unsigned int DFR;

volatile unsigned int ADR;

volatile unsigned int MMFR[4];

volatile unsigned int ISAR[5];

} SCB_Type;

#define SCB ((SCB_Type *)0xE000ED00) /* 定义对应结构体指针变量*/

/* 定义GPIO结构体*/

typedef struct

{

volatile unsigned int CRL; /*配置寄存器GPIOx_CRL,偏移地址00*/

volatile unsigned int CRH; /*配置寄存器GPIOx_CRH,偏移地址04*/

volatile unsigned int IDR; /*数据寄存器GPIOx_IDR,偏移地址08 */

volatile unsigned int ODR; /*数据寄存器GPIOx_ODR,偏移地址0C*/

volatile unsigned int BSRR; /*置位寄存器GPIOx_BSRR,偏移地址10*/

volatile unsigned int BRR; /*复位寄存器GPIOx_BRR,偏移地址14*/

volatile unsigned int LCKR; /*锁定寄存器GPIOx_LCKR,偏移地址18*/

} GPIO_TypeDef;

/* 定义GPIO结构体指针变量*/

#define GPIOD ((GPIO_TypeDef *)0x40011400)

/*************************************************************************/ /* main函数*/ /*************************************************************************/ int main(void)

{

/* 初始化系统时钟*/

RCC->CR |= (unsigned int)0x00000001;

RCC->CFGR &= (unsigned int)0xF8FF0000;

RCC->CR &= (unsigned int)0xFEF6FFFF;

RCC->CR &= (unsigned int)0xFFFBFFFF;

RCC->CFGR &= (unsigned int)0xFF80FFFF;

RCC->CR &= (unsigned int)0xEBFFFFFF;

RCC->CIR = 0x00FF0000;

RCC->CFGR2 = 0x00000000;

/* V ector Table Relocation in Internal SRAM.*/

SCB->VTOR = ((unsigned int)0x20000000);

/* 打开GPIOD口时钟*/

RCC->APB2ENR |= 0x20;

/* 设置GPIOD第2脚为推挽输出模式,速率为50MHz */

GPIOD->CRL &= 0xFFFFF0FF;

GPIOD->CRL |= 0x00000300;

/* 点亮PD2口的LED */

GPIOD->BRR &= 0xFFFFFFFB;

while (1)

{

}

}

/**************************** *****END OF FILE**********************/

相关主题
相关文档
最新文档