STM32F103点亮流水灯 寄存器方式和标准外设库方式

一、寄存器方式点亮LED流水灯

STM32点亮LED的操作过程是:CPU给指令->GPIO收到指令->配置内部寄存器->配置IO口模式->控制LED亮灭

STM32开发板中包含较多寄存器,实现流水灯操作需要对相应的引脚进行如下操作:

  1. 时钟配置
  2. 输入输出模式设置
  3. 最大速率设置
  4. 编写程序
  5. 烧录运行
    在STM32F103C8T6上通过初始化GPIO点亮LED,通过将其初始化控制片外引脚即I/O口拉高降低输出高低电平,以控制LED灯的亮灭即可。

1.时钟配置

查阅手册:

  • 时钟使能寄存器映射基地址:
    在这里插入图片描述
  • 端口偏移地址以及对应端口所在位置
    在这里插入图片描述
    可以看到外设时钟使能寄存器偏移量为0x18,起始地址为0x4002 1000,因此该寄存器的地址为0x4002 1018
//APB2时钟使能寄存器
#define RCC_APB2ENR *((unsigned volatile int*)0x40021018);

手册中提到,RCC_APB2ENR(APB2外设时钟使能寄存器)的位3是IOPBEN,即IO端口B时钟使能,将该端口置1就是开启GPIO时钟.

RCC->APB2ENR|=1<<2;  //APB2-GPIOA外设时钟使能
RCC->APB2ENR|=1<<3;  //APB2-GPIOB外设时钟使能
RCC->APB2ENR|=1<<4;  //APB2-GPIOC外设时钟使能

2.输入输出模式设置、最大速率设置

本次实验采用通用推挽输出模式,最高输出时钟频率2Mhz。分别用到GPIOA-5、GPIOB-9、GPIOC-14 三个引脚。其中A4属于端口配置低寄存器偏移地址为0x00,B9、C14属于端口配置高寄存器偏移地址为0x04。
在这里插入图片描述
在这里插入图片描述

  • GPIO端口基地址
    在这里插入图片描述
  • 配置对应引脚寄存器,寄存器地址=基地址+偏移量
//GPIOA配置寄存器
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
//GPIOB配置寄存器 
#define GPIOB_CRH		*((unsigned volatile int*)0x40010C04)
//GPIOC配置寄存器
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
  • 设置推挽模式输出,输出速度位2MHz
  1. 将GPIOA-5配置成推挽模式输出,且最大速度为2MHz,根据数据手册可以知道它属于端口配置低寄存器模块,CNF5和MODE5位为0,其余位为F,即GPIOB_CRH&=0xFF0FFFfF;又因为其为推挽模式输出,其最大速度为2MHz,所以4位寄存器的配置就是CNF5【00】MODE5【10】,【0010】换算为十进制为【2】,因此GPIOB_CRH|=0x00200000。

  2. 将GPIOB-9配置成推挽模式输出,且最大速度为2MHz,根据数据手册可以知道它属于端口配置高寄存器模块,CNF9和MODE9位为0,其余位为F,即GPIOB_CRH&=0xFFFFFF0F;又因为其为推挽模式输出,其最大速度为2MHz,所以4位寄存器的配置就是CNF9【00】MODE9【10】,【0010】换算为十进制为【2】,因此GPIOB_CRH|=0x00000020。

  3. 将GPIOC-14配置成推挽模式输出,且最大速度为2MHz,根据数据手册可以知道它属于端口配置高寄存器模块,CNF14和MODE14位为0,其余位为F,即GPIOB_CRH&=0xF0FFFFFF;又因为其为推挽模式输出,其最大速度为2MHz,所以4位寄存器的配置就是CNF14【00】MODE14【10】,【0010】换算为十进制为【2】,因此GPIOB_CRH|=0x02000000。

GPIOA_CRL&=0xFFF0FFFF;		//设置位清零	
GPIOA_CRL|=0X00200000;		//PA5推挽输出,把第23、22、21、20位变为0010
GPIOA->ODR|=1<<5;			//设置PA5初始灯为灭
  
GPIOB_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOB_CRH|=0x00000020;		//PB9推挽输出,把第7、6、5、4变为0010
GPIOB->ODR|=0x1<<9;			//设置初始灯为灭
   
GPIOC_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOC_CRH|=0x02000000;		//PC14推挽输出,把第27、26、25、24变为0010
GPIOC->ODR|=0x1<<14;		//设置初始灯为灭	

3.编程并烧录运行

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
//APB2时钟使能寄存器
#define RCC_APB2ENR		*((unsigned volatile int*)0x40021018)

//GPIOA配置寄存器
#define GPIOA_CRL		*((unsigned volatile int*)0x40010800)
#define	GPIOA_ODR		*((unsigned volatile int*)0x4001080C)
  
//GPIOB配置寄存器
#define GPIOB_CRH		*((unsigned volatile int*)0x40010C04)
#define	GPIOB_ODR		*((unsigned volatile int*)0x40010C0C)
  
//GPIOC配置寄存器
#define GPIOC_CRH		*((unsigned volatile int*)0x40011004)
#define	GPIOC_ODR		*((unsigned volatile int*)0x4001100C)

//函数声明

void A_LED_LIGHT(void);
void B_LED_LIGHT(void);
void C_LED_LIGHT(void);

//控制灯亮灭
void A_LED_LIGHT()
  {
  GPIOA_ODR=0x0<<5;		//PA5低电平
  GPIOB_ODR=0x1<<9;		//PB9高电平
  GPIOC_ODR=0x1<<14;	//PC14高电平	
}
void B_LED_LIGHT()
  {
  GPIOA_ODR=0x1<<5;		//PA5高电平
  GPIOB_ODR=0x0<<9;		//PB9低电平
  GPIOC_ODR=0x1<<14;	//PC14高电平
}
void C_LED_LIGHT()
  {
  GPIOA_ODR=0x1<<5;		//PA5高电平
  GPIOB_ODR=0x1<<9;		//PB9高电平
  GPIOC_ODR=0x0<<14;	//PC14低电平
}

//------------------------主函数--------------------------
int main(){

  RCC_APB2ENR|=1<<2;			//APB2-GPIOA外设时钟使能
  RCC_APB2ENR|=1<<3;			//APB2-GPIOB外设时钟使能	
  RCC_APB2ENR|=1<<4;			//APB2-GPIOC外设时钟使能

  

GPIOA_CRL&=0xFFF0FFFF;		//设置位清零	
GPIOA_CRL|=0X00200000;		//PA5推挽输出,把第23、22、21、20位变为0010
  
GPIOB_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOB_CRH|=0x00000020;		//PB9推挽输出,把第7、6、5、4变为0010
   
GPIOC_CRH&=0xFF0FFFFF;		//设置位清零	
GPIOC_CRH|=0x02000000;		//PC14推挽输出,把第27、26、25、24变为0010

  GPIOA_ODR |= (1<<5);  
  GPIOB_ODR |= (1<<9);      //设置灯的初始状态为灭
  GPIOC_ODR |= (1<<14); 
  
  while(1)
  	{
  	  A_LED_LIGHT();
  	  Delay_ms(500);
  	  B_LED_LIGHT();
  	  Delay_ms(500);
  	  C_LED_LIGHT();
  	  Delay_ms(500);
  }

}

4.实现成果展示:

在这里插入图片描述

二、标准外设库方式

引入标准外设库之后,先了解一下需要用到的函数。

1. RCC 外设时钟控制函数:第一个参数选择外设,第二个参数使能或失能。

在这里插入图片描述

2. GPIO库函数

在这里插入图片描述
第一个函数可以复位指定的GPIO外设
第二个函数复位AFIO外设
第三个函数,用结构体参数初始化GPIO口
第四个函数给结构体变量赋一个默认值
后面四个都是GPIO口的读取函数
再后面四个都是GPIO口的实现函数

3.实现过程:

  • 打开GPIOA时钟
  • 选择输出方式
  • 选择引脚并设置输出速度
  • 编写程序并烧录运行
#include "stm32f10x.h"                  // Device header
#include "Delay.h" 						//延时器

int main(void)
	
	{
		
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//打开GPIOA的时钟
		
		GPIO_InitTypeDef GPIO_InitStructure;
		GPIO_InitStructure.GPIO_Mode= GPIO_Mode_Out_PP;		//选择输出方式 这里是推挽输出 
															//推挽输出就是可以输出高低电频,直接驱动小功耗器件
		GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0|GPIO_Pin_3|GPIO_Pin_5;	//选择引脚 初始化
		GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;	//选的50MHz的输出速度
		
		GPIO_Init(GPIOA,&GPIO_InitStructure);				//把GPIO_InitStructure放在GPIO_Init函数的第二个参数上,初始化就完成了
		
		while(1){
			
			GPIO_Write(GPIOA,GPIO_Pin_0);		
			Delay_ms(500);		
			GPIO_Write(GPIOA,GPIO_Pin_3);		
			Delay_ms(500);	
			GPIO_Write(GPIOA,GPIO_Pin_5);	
			Delay_ms(500);	
	
		}
		
	}
	

4.遇到的问题

流水灯的循环点亮部分的代码原本的写法是这样的:

			GPIO_Write(GPIOA,~0x0001);		
			Delay_ms(500);		

老师指出标准的写法是直接写引脚名:

			GPIO_Write(GPIOA,GPIO_Pin_0);		
			Delay_ms(500);	

5.实现成果展示:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值