一、库函数版本
1.新建一个 led.h 文件
#ifndef _LED_H #define _LED_H #include "sys.h" #define LED0 PBout(5) // DS0 #define LED1 PEout(5) // DS1 void LED_Init(void); // LED接口初始化 #endif
这段代码里面最关键就是 2 个宏定义,通过位带操作 PB5 输出高低电平从而控制 LED0 。
LED0=1; //通过位带操作控制 LED0 的引脚 PB5 输出高电平
LED0=0; //通过位带操作控制 LED0 的引脚 PB5 输出低电平
同样也可以使用固件库操作和寄存器操作,来实现 IO 口操作。
GPIO_SetBits(GPIOB, GPIO_Pin_5); //设置 GPIOB.5 输出 1,等同 LED0=1;
GPIO_ResetBits (GPIOB, GPIO_Pin_5); //设置 GPIOB.5 输出 0,等同 LED0=0;
还可以通过直接操作寄存器,BRR 和 BSRR 的方式来操作 IO 口输出高低电平。
GPIOB->BRR=GPIO_Pin_5; //设置 GPIOB.5 输出 1,等同 LED0=1;
GPIOB->BSRR=GPIO_Pin_5; //设置 GPIOB.5 输出 0,等同 LED0=0;
2.新建一个 led.c文件
#include "led.h" void LED_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; // 使能GPIOB、GPIOE端口时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB|RCC_APB2Periph_GPIOE, ENABLE); // 配置GPIOB.5 推挽输出 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB, &GPIO_InitStructure); GPIO_SetBits(GPIOB, GPIO_Pin_5); // 配置GPIOE.5 推挽输出 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; GPIO_Init(GPIOE, &GPIO_InitStructure); GPIO_SetBits(GPIOE, GPIO_Pin_5); }
该函数的功能就是用来实现配置 PB5和 PE5 为推挽输出。这里需要注意的是:在配置 STM32 外设的时候,任何时候都要先使能该外设的时钟。GPIO 是挂载在 APB2 总线上的外设,在固件库中对挂载在 APB2 总线上的外设时钟使能是通过函数 RCC_APB2PeriphClockCmd()来实现的。
需要说明的是,因为 GPIOB 和 GPIOE 的 IO 口的初始化参数都是设置在结构体变量GPIO_InitStructure 中,因为两个 IO 口的模式和速度都一样,所以我们只用初始化一次,在GPIOE.5 的初始化的时候就不需再重复初始化速度和模式了。
3.编写main.c文件
#include "led.h" #include "delay.h" int main(void) { delay_init(); // 延时函数初始化 LED_Init(); // LED接口初始化 while(1) { LED0 = 1; LED1 = 0; delay_ms(1000); LED0 = 0; LED1 = 1; delay_ms(1000); } }
在固件库 V3.5 中,系统在启动的时候会调用 system_stm32f10x.c 中的函数 SystemInit()对系统时钟进行初始化,完毕之后会调用 main()函数,所以我们不需要再在 main()函数中调用 SystemInit()函数。
二、寄存器版本
1.启动文件修订
将startup_stm32f10x_hd.s的 Reset_Handler 函数部分代码进行注释,因为寄存器版本没有用到SystemInit函数,引用的话可能会报错。
Reset_Handler PROC EXPORT Reset_Handler [WEAK] IMPORT __main ;寄存器版本代码,因为没有用到SystemInit函数,所以注释掉以下代码为防止报错! ;库函数版本代码,建议加上这里(外部必须实现SystemInit函数),以初始化stm32时钟等。 ;IMPORT SystemInit ;LDR R0, =SystemInit ;BLX R0 LDR R0, =__main BX R0 ENDP
2.新建一个led.h文件
#ifndef _LED_H #define _LED_H #include "sys.h" #define LED0 PBout(5) //DS0 #define LED1 PEout(5) //DS1 void LED_Init(void); #endif
3.新建一个led.c文件
#include "led.h" void LED_Init(void) { // RCC->APB2ENR寄存器的第3位置1,使能端口B、E时钟 RCC->APB2ENR|=1<<3; RCC->APB2ENR|=1<<6; // GPIO->CRL寄存器的第20~23位清零,设置端口模式 GPIOB->CRL&=0XFF0FFFFF; GPIOB->CRL|=0X00300000; GPIOB->ODR|=1<<5; GPIOE->CRL&=0XFF0FFFFF; GPIOE->CRL|=0X00300000; GPIOE->ODR|=1<<5; }
首先要将PORTB 和 PORTE 的时钟使能,再设置端口管脚模式。APB2ENR 是 APB2 总线上的外设时钟使能寄存器,通过将位3和位6设为1,即可使能PORTB和PORTE时钟。
下步准备设置端口模式,由下图可以看出GPIO_Pin_5为CRL寄存器的20~23位,将该位清零设置为3。(推挽输出、50MHZ)
4.新建一个main.c文件
#include "sys.h" #include "usart.h" #include "delay.h" #include "led.h" int main(void) { Stm32_Clock_Init(9); //系统时钟设置 delay_init(72); //延时初始化 LED_Init(); while(1) { LED0=1; LED1=1; delay_ms(300); LED0=0; LED1=0; delay_ms(300); } }
这段main 函数先调用 Stm32_Clock_Init 函数,配置系统时钟为 9 倍频,也就是 8*9=72M(外部晶振是 8Mhz),然后调用 delay_init 函数,初始化延时函数。接着就是调用 LED_Init 来初始化 PE5 和 PB5 为输出。最后在死循环里面实现 LED0 和 LED1 交替闪烁,间隔为 300ms。