使用寄存器点亮第一个LED
时间:2023-08-23 01:07:00
一、硬件设计
- 网络标号相同它们是连接在一起的,所以 DS0、DS1 发光二极管阴极连接 STM32 的 PB5、PE5 管脚上。
- 如果要使 DS0 指示灯亮,只需要控制 PB5 管脚输出低电平,如果要使 DS0 只需控制指示灯熄灭 PB5 输出高电平。 LED 同样的控制方法。如果使用其他板连接 LED 管脚不同于极性,所以只需要在程序中修改对应的 GPIO 管脚和输出电平状态可以,原则是一样的。
- 点亮 DS0 发光二极管,即让 STM32 的 PB5 管脚输出低电平。
二、软件设计
2.1、 startup_stm32f10x_hd.s 启动文件
- 在启动文件中用汇编语言写基本程序,当 STM32 当芯片上电启动时,这里的汇编程序将首先执行,以建立 C 语言运行环境。因此,它被称为启动文件。文件中使用的汇编指令是 Cortex-M3 可参考内核支持的指令《Cortex-M3 《中文权威指南》指令集章节。
- startup_stm32f10x_nd.s 文件(普中STM32F10x教程中的名称)由 ST 官方提供的,一般需要在官方的基础上修改,不会自己完全重写。该文件可以从 KEIL5 找到安装目录,也可以从 ST 在库中找到,找到文件后,将启动文件添加到项目中。不同类型的芯片和不同编译环境中使用的汇编文件不同,但功能相同。
- 启动文件的主要功能
- 初始化堆栈指针 SP。
- 初始化程序计数器指针 PC。
- 设置堆、栈的大小。
- 设置中断向量表的入口地址。
- 配置外部 SRAM 作为数据存储器(这是由用户配置的,一般开发板没有外部 SRAM)。
- 调用 SystemInit() 函数配置 STM32 系统时钟。
- 设置 C 库分支入口 __main最后用来调用 main 函数) 。
Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main IMPORT SystemInit LDR R0, =SystemInit BLX R0 LDR R0, =__main BX R0 ENDP
- 128 行是程序注释,在汇编中注释是; C 语言的“ //注释符。
- 129行定义了一个子程序: Reset_Handler。 PROC 子程序定义伪指令。这相当于 C 一个函数在语言中被定义,函数被称为 Reset_Handler。
- 130行 EXPORT 表示 Reset_Handler 其他模块可以调用此子程序。 相当于 C 语言函数声明。关键字[WEAK] 这意味着弱定义。如果编译器发现同名函数在其他地方定义,则在链接时使用其他地址进行链接。如果没有定义其他地方,编译器也不会报告错误。如果您不理解此地址的链接 WEAK,那就忽略它吧。
- 131行和132行 IMPORT 说明 __main 和 SystemInit 在其他文件中,这两个标号需要在链接时找到其他文件。 C 在语言中,函数声明是从其他文件中引入的。以调用以下外部函数。
- SystemInit 我们需要自己实现,也就是说,我们需要编写一个具有该名称的函数来初始化 STM32 芯片时钟,一般包装括初始化 AHB、 APB 等待各总线的时钟,需要一系列配置 STM32 只有这样稳定运行的状态。__main 其实不是我们定义的(不要和) C 语言中的 main 函数混淆),编译器编译时,只要遇到这个标号,就会定义这个函数。该函数的主要功能是负责初始化栈、堆、系统环境配置和准备 C 语言最终跳转到用户自定义 main 函数,从现在开始 C 的世界。
- 133行把 SystemInit 将地址加载到寄存器 R0。
- 跳转到134行程序 R0 地址执行程序,即执行 SystemInit 函数的内容。
- 135 行把__main 将地址加载到寄存器 R0。
- 136 跳转行程序 R0 地址执行程序,即执行__main 函数执行后即可进入 main 函数。
- 137 行表示子程序的结束。
结论:我们需要在外部定义一个SystemInit 函数设置 STM32 的时钟;STM32 上电后,将执行 SystemInit 函数,最后,执行我们 C 语言中的 main 函数。
2.1.1、startup_stm32f10x_md.s启动文件
;******************** (C) COPYRIGHT 2011 STMicroelectronics ******************** ;* File Name : startup_stm32f10x_md.s ;* Author : MCD Application Team ;* Version : V3.5.0 ;* Date : 11-March-2011 ;* Description : STM32F10x Medium Density Devices vector table for MDK-ARM ;* toolchain. ;* This module performs: ;* - Set the initial SP ;* - Set the initial PC == Reset_Handler ;* - Set the vector table entries with the exceptions ISR address ;* - Configure the clock system ;* - Branches to __main in the C library (which eventually ;* calls main()). ;* After Reset the CortexM3 processor is in Thread mode, ;* priority is Privileged, and the Stack is set to Main. ;* <<< Use Configuration Wizard in Context Menu >>> ;******************************************************************************* ; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS ; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME. ; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT, ; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE ; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING ; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS. ;******************************************************************************
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; Stack Configuration
; Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Stack_Size EQU 0x00000400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; Heap Configuration
; Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
;
Heap_Size EQU 0x00000800
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
PRESERVE8
THUMB
; Vector Table Mapped to Address 0 at Reset
AREA RESET, DATA, READONLY
EXPORT __Vectors
EXPORT __Vectors_End
EXPORT __Vectors_Size
__Vectors 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_2
DCD USB_HP_CAN1_TX_IRQHandler ; USB High Priority or CAN1 TX
DCD USB_LP_CAN1_RX0_IRQHandler ; USB Low Priority or 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 ; I2C2 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 USBWakeUp_IRQHandler ; USB Wakeup from suspend
__Vectors_End
__Vectors_Size EQU __Vectors_End - __Vectors
AREA |.text|, CODE, READONLY
; Reset handler
Reset_Handler PROC
EXPORT Reset_Handler [WEAK]
IMPORT __main
IMPORT SystemInit
LDR R0, =SystemInit
BLX R0
LDR R0, =__main
BX R0
ENDP
; Dummy Exception Handlers (infinite loops which can be modified)
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
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 USB_HP_CAN1_TX_IRQHandler [WEAK]
EXPORT USB_LP_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 USBWakeUp_IRQHandler [WEAK]
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
USB_HP_CAN1_TX_IRQHandler
USB_LP_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
USBWakeUp_IRQHandler
B .
ENDP
ALIGN
;*******************************************************************************
; User Stack and Heap initialization
;*******************************************************************************
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
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
2.2、main.c文件
/*stm32f10x.h 头文件,在这个头文件中我们定义的都是寄存器,
因此如果要在其他文件中使用这些寄存器就需要把这个头文件包含进来,否则编
译就会报错。*/
#include "stm32f10x.h"
/*SystemInit 函数,程序运行的时候
先进入这个函数进行 STM32 的初始化,如果不写这个函数编译器就会报错。*/
void SystemInit()
{
}
int main()
{
RCC_APB2ENR |= 1<<3; // 开启GPIOB端口时钟 通过或运算使位3置1 其他位则不会受到干扰
GPIOB_CRL &= ~( 0x0F<< (4*5)); //4*5 每4位控制一个引脚 0x0F二进制为1111 取反变为0000 &与运算
GPIOB_CRL |= (3<<4*5);
GPIOB_BSRR=(1<<(16+5));
while(1)
{
}
}
2.3、stm32f10x.h文件
/*
APB1总线基地址 0x4000 0000 相对外设基地址的偏移0x0
APB2总线基地址 0x4001 0000 相对外设基地址的偏移0x0001 0000
AHB总线基地址 0x4001 8000 相对外设基地址的偏移0x0001 8000
*/
/*
APB1总线基地址 即 挂在APB1总线上首个外设的基地址
每条总线上都会挂接着很多的外设,这些外设也会有自己的地址范围,XXX外设的首个地址即最低地址就是 XXX 外设的基地址,也称作 XXX 边界地址
*/
#define PERIPH_BASE ((unsigned int)0x40000000) // 定义外设基地址
/* APB2总线基地址= APB1总线基地址 + 相对外设基地址(偏移量)*/
#define APB2PERIPH_BASE (PERIPH_BASE +0x0001 0000)
/*GPIOB 外设基地址0x40010 0C00
定义GPIOB外设基地址
*/
#define GPIOB_BASE (APB2PERIPH_BASE+0x0C00) // #define GPIOB_BASE(PERIPH_BASE+0x00000C00)
//定义寄存器地址
//定义端口配置低寄存器
#define GPIOB_CRL *(unsigned int*)(GPIOB_BASE+0x00)
//定义端口配置高寄存器
#define GPIOB_CRH *(unsigned int*)(GPIOB_BASE+0x04)
// 端口输入数据寄存器
#define GPIOB_IDR *(unsigned int*)(GPIOB_BASE+0x08)
//端口输出数据寄存器
#define GPIOB_ODR *(unsigned int*)(GPIOB_BASE+0x0c)
//端口位设置/清除寄存器
#define GPIOB_BSRR *(unsigned int*)(GPIOB_BASE+0x10)
//端口位清除寄存器
#define GPIOB_BRR *(unsigned int*)(GPIOB_BASE+0x14)
//端口配置锁定寄存器
#define GPIOB_LCKR *(unsigned int*)(GPIOB_BASE+0x18)
// AHB外设基地址
#define AHBPERIPH_BASE (PERIPH_BASE+0x20000)
//RCC外设地址 0x4002 1000
#define RCC_BASE (AHBPERIPH_BASE+0x1000)
//APB2外设时钟使能寄存器(RCC_APB2ENR)
#define RCC_APB2ENR *(unsigned int*)(RCC_BASE+0x18)