STM32使用自建库编程点亮LED灯(二)

STM32函数库介绍

STM32固件库是ST公司针对STM32提供的函数接口,开发者可调用这些函数接口来配置STM32的寄存器,让开发人员脱离最底层的寄存器操作,有开发快速,容易阅读,维护成本低等优点。

stm32f10x.h文件

#ifndef _STM32F10X_H
#define _STM32F10X_H
typedef unsigned int      uint32_t;
typedef unsigned short    uint16_t;
/*片上外设基地址*/
#define PERIPH_BASE				((unsigned int)0x40000000) 
/*总线基础地址,GPIO都挂载在APB2上*/ 
#define APB2PERIPH_BASE			(PERIPH_BASE + 0x10000)
/*RCC挂载在AHB上*/
#define AHBPERIPH_BASE          (PERIPH_BASE + 0x20000) 
/*GPIO外设基地址*/
#define GPIOA_BASE              (APB2PERIPH_BASE + 0x0800)
#define GPIOB_BASE              (APB2PERIPH_BASE + 0x0c00)
#define GPIOC_BASE              (APB2PERIPH_BASE + 0x1000)
#define GPIOD_BASE              (APB2PERIPH_BASE + 0x1400)
#define GPIOE_BASE              (APB2PERIPH_BASE + 0X1800)
#define GPIOF_BASE              (APB2PERIPH_BASE + 0x1c00)
#define GPIOG_BASE              (APB2PERIPH_BASE + 0x2000)
/*RCC外设基础地址*/
#define RCC_BASE			    (AHBPERIPH_BASE + 0x1000)

要实现给结构体赋值就达到操作寄存器的效果,需要找到该寄存器的地址,把寄存器地址与结构体的地址对应起来。所以还需要找到外设的地址,根据实验一学习,可以把这些外设的地址定义成一个个宏,以实现外设储存器的映射。

起始地址外设总线
0x40010800-0x40010BFFGPIO端口AAPB2
0x40010C00-0x40010FFFGPIO端口BAPB2
0x40011000-0x400113FFGPIO端口CAPB2
0x40011400-0x400117FFGPIO端口DAPB2
0x40011800-0x40011BFFGPIO端口EAPB2
0x40011C00-0x40011FFFGPIO端口FAPB2
0x40012000-0x400123FFGPIO端口GAPB2
0x40021000-0x400213FFRCCAHB
/*GPIO外设声明*/
#define GPIOA   			((GPIO_TypeDef *)	GPIOA_BASE)
#define GPIOB				((GPIO_TypeDef *)	GPIOB_BASE)
#define GPIOC               ((GPIO_TypeDef *)	GPIOC_BASE)
#define GPIOD				((GPIO_TypeDef *)	GPIOD_BASE)
#define GPIOE				((GPIO_TypeDef *)	GPIOE_BASE)
#define GPIOF				((GPIO_TypeDef *)	GPIOF_BASE)
#define GPIOG               ((GPIO_TypeDef *)	GPIOG_BASE)
/*RCC外设声明*/
#define RCC					((RCC_TypeDef *)	RCC_BASE)
/*RCC的AHB1时钟使能寄存器地址,强制转换成指针*/
#define RCC_APB2ENR				*(unsigned int*) (RCC_BASE+0x18)

把外设的基地址强制类型转换成相应的外部寄存器结构体指针,然后把该指针声明成外设名,外设名就与外设的地址对应来,而且外设名还是一个该外设类型的寄存器结构体指针,通过该指针可以直接操作该外设的全部寄存器。

typedef struct
{
	uint32_t CRL;				//端口配置低寄存器
	uint32_t CRH;				//端口配置高寄存器
	uint32_t IDR;				//端口数据输入寄存器
	uint32_t ODR;				//端口数据输出寄存器
	uint32_t BSRR;				//端口位设置/清除寄存器
	uint32_t BRR;				//端口位清除寄存器
	uint32_t LCKR;				//端口配置锁存寄存器
}GPIO_TypeDef;


typedef struct
{
	uint32_t CR;				//时钟控制寄存器			
	uint32_t CFGR;				//时钟配置寄存器
	uint32_t CIR;				//时钟中断寄存器
	uint32_t APB2RSTR;          //APB2外设中断寄存器
	uint32_t APB1RSTR;			//APB1外设中断寄存器
	uint32_t AHBENR;			//AHB外设时钟使能寄存器
	uint32_t APB2ENR;			//APB2外设时钟使能寄存器
	uint32_t APB1ENR;			//APB1外设时钟使能寄存器
	uint32_t BDCR;				//备份域控制寄存器
	uint32_t CSR;				//控制/状态图寄存器
}RCC_TypeDef;
#endif /*_STM32F10X_H*/
地址偏移(GPIOx外设)寄存器
0x00GPIOx_CRL
0x04GPIOx_CRH
0x08GPIOx_IDR
0x0CGPIOx_ODR
0x10GPIOx_BSRR
0x14GPIOx_BRR
0x18GPIOx_LCKR
地址偏移(RCC外设0x40021000)寄存器
0x00RCC_CR
0x04RCC_CFGR
0x08RCC_CIR
0x0CRCC_APB2RSTR
0x10RCC_APB1RSTR
0x14RCC_AHBENR
0x18RCC_APB2ENR
0x1CRCC_APB1ENR

stm32f10x_gpio.h文件

#ifndef _STM32F10X_GPIO_H
#define _STM32F10X_GPIO_H
#include "stm32f10x.h"
/*GPIO引脚定义*/
#define GPIO_Pin_0    ((uint16_t)0x0001)  /*!< 选择Pin0 */    //(00000000 00000001)b
#define GPIO_Pin_1    ((uint16_t)0x0002)  /*!< 选择Pin1 */    //(00000000 00000010)b
#define GPIO_Pin_2    ((uint16_t)0x0004)  /*!< 选择Pin2 */    //(00000000 00000100)b
#define GPIO_Pin_3    ((uint16_t)0x0008)  /*!< 选择Pin3 */    //(00000000 00001000)b
#define GPIO_Pin_4    ((uint16_t)0x0010)  /*!< 选择Pin4 */    //(00000000 00010000)b
#define GPIO_Pin_5    ((uint16_t)0x0020)  /*!< 选择Pin5 */    //(00000000 00100000)b
#define GPIO_Pin_6    ((uint16_t)0x0040)  /*!< 选择Pin6 */    //(00000000 01000000)b
#define GPIO_Pin_7    ((uint16_t)0x0080)  /*!< 选择Pin7 */    //(00000000 10000000)b

#define GPIO_Pin_8    ((uint16_t)0x0100)  /*!< 选择Pin8 */    //(00000001 00000000)b
#define GPIO_Pin_9    ((uint16_t)0x0200)  /*!< 选择Pin9 */    //(00000010 00000000)b
#define GPIO_Pin_10   ((uint16_t)0x0400)  /*!< 选择Pin10 */   //(00000100 00000000)b
#define GPIO_Pin_11   ((uint16_t)0x0800)  /*!< 选择Pin11 */   //(00001000 00000000)b
#define GPIO_Pin_12   ((uint16_t)0x1000)  /*!< 选择Pin12 */   //(00010000 00000000)b
#define GPIO_Pin_13   ((uint16_t)0x2000)  /*!< 选择Pin13 */   //(00100000 00000000)b
#define GPIO_Pin_14   ((uint16_t)0x4000)  /*!< 选择Pin14 */   //(01000000 00000000)b
#define GPIO_Pin_15   ((uint16_t)0x8000)  /*!< 选择Pin15 */   //(10000000 00000000)b
#define GPIO_Pin_All  ((uint16_t)0xFFFF)  /*!< 选择全部引脚*/ //(11111111 11111111)b

这些宏代表的参数是某位置为“1”其他位置位“0”的数值,其中最后一个“GPIO_Pin_ALL”是所有数据位都为“1”,所以用它可以一次设置整个端口的0~15,即所有引脚。

typedef struct
{
	uint16_t GPIO_Pin;
	uint16_t GPIO_Speed;
	uint16_t GPIO_Mode;
}GPIO_InitTypeDef;

typedef enum
{ 
  GPIO_Speed_10MHz = 0x1,              // 10MHZ        (01)b
  GPIO_Speed_2MHz = 0x02,              // 2MHZ         (10)b
  GPIO_Speed_50MHz = 0x03              // 50MHZ        (11)b
}GPIOSpeed_TypeDef;

typedef enum
{ 
  GPIO_Mode_AIN = 0x0,           // 模拟输入     (0000 0000)b
  GPIO_Mode_IN_FLOATING = 0x04,  // 浮空输入     (0000 0100)b
  GPIO_Mode_IPD = 0x28,          // 下拉输入     (0010 1000)b
  GPIO_Mode_IPU = 0x48,          // 上拉输入     (0100 1000)b
  //bit4是1表示输出,bit4是0表示输入
  GPIO_Mode_Out_OD = 0x14,       // 开漏输出     (0001 0100)b
  GPIO_Mode_Out_PP = 0x10,       // 推挽输出     (0001 0000)b
  GPIO_Mode_AF_OD = 0x1C,        // 复用开漏输出 (0001 1100)b
  GPIO_Mode_AF_PP = 0x18         // 复用推挽输出 (0001 1000)b
}GPIOMode_TypeDef;
void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin);
void GPIO_ResetBits( GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin );
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct);
#endif /* __STM32F10X_GPIO_H */

stm32f10x_gpio.c文件

#include "stm32f10x_gpio.h"

void GPIO_SetBits(GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin)
{
	GPIOx->BSRR |= GPIO_Pin;
}

void GPIO_ResetBits( GPIO_TypeDef *GPIOx,uint16_t GPIO_Pin )
{
	GPIOx->BRR |= GPIO_Pin;
}
/**
  *函数功能:初始化引脚模式
  *参数说明:GPIOx,该参数为GPIO_TypeDef类型的指针,指向GPIO端口的地址
  *GPIO_InitTypeDef:GPIO_InitTyeDef结构体指针,指向初始化变量
  */
void GPIO_Init(GPIO_TypeDef* GPIOx,GPIO_InitTypeDef* GPIO_InitStruct)
{
	  uint32_t currentmode = 0x00,currentpin = 0x00,pinpos = 0x00,pos = 0x00;
	  uint32_t tmpreg = 0x00,pinmask = 0x00;
	  /*GPIO配置*/	
	  currentmode = ((uint32_t)GPIO_InitStruct->GPIO_Mode) &
				 ((uint32_t)0x0F);//把输入参数GPIO_Mode的低4位暂存在currentmode
		if((((uint32_t)GPIO_InitStruct->GPIO_Mode) & 
			 ((uint32_t)0x10)) !=0x00)//bit4是1表示输出,bit4是0表示输入
		{   //若是输出模式,则要设置输出速度
			currentmode |= (uint32_t)GPIO_InitStruct->GPIO_Speed;
		}
		//GPIO CRL寄存器配置(pin0~pin7)
		if(((uint32_t)GPIO_InitStruct->GPIO_Pin & 
			((uint32_t)0x00FF)) != 0x00)
		{
			tmpreg = GPIOx->CRL;//先备份CRL寄存器的值
	                   	}
		for (pinpos = 0x00; pinpos < 0x08; pinpos++)
		{	//循环,从Pin0开始匹配对,找出具体的Pin
			pos = ((uint32_t)0x01) << pinpos;
			currentpin = (GPIO_InitStruct->GPIO_Pin) & pos;
			if (currentpin == pos)
			{	//找到使用的引脚
				pos = pinpos <<2;//乘以4,因为寄存器4位配置一个引脚
				pinmask = ((uint32_t)0x0F) << pos;
				tmpreg &= ~pinmask;//把控制这个引脚的4位寄存器位清零,其他寄存器位不变
				tmpreg |= (currentmode << pos);//向寄存器写入要配置的引脚模式
				//判断是否为下拉输入模式
				if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
				{	//若为下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
					GPIOx->BRR = (((uint32_t)0x01) << pinpos);
				}
				else//否则为上拉输入模式
				{
					if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPU)
					{	//若为上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
						GPIOx->BSRR = (((uint32_t)0x01) << pinpos);
					}		
				} 
			}
		}
		GPIOx->CRL = tmpreg;//把前面处理后的值暂存写入CRL寄存器中
//配置端口高8位,即Pin8~Pin15
 if (GPIO_InitStruct->GPIO_Pin > 0X00FF)
{	//先备份CRH寄存器的值
	tmpreg = GPIOx->CRH;
	for(pinpos = 0x00; pinpos < 0x08;pinpos++)
	{	//循环,从Pin8开始配对,找出具体的Pin
		pos = (((uint32_t)0x01) << (pinpos + 0x08));
		currentpin = ((GPIO_InitStruct->GPIO_Pin) & pos);
		if (currentpin == pos)//若currentpin=pos,则找到使用引脚
		{
			pos = pinpos <<2;//乘以4,因为寄存器4位配置一个引脚
			pinmask = ((uint32_t)0x0F) << pos;
			tmpreg &= ~pinmask;//把控制这个引脚的4位寄存器位清零,其他寄存器位不变
			tmpreg |= (currentmode << pos);//向寄存器写入要配置的引脚模式
			//判断是否为下拉输入模式
			if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
				{	//若为下拉输入模式,引脚默认置0,对BRR寄存器写1可对引脚置0
					GPIOx->BRR = (((uint32_t)0x01) << pinpos + 0x08);
				}
				//否则为上拉输入模式
			if (GPIO_InitStruct->GPIO_Mode == GPIO_Mode_IPD)
			{	//若为上拉输入模式,引脚默认值为1,对BSRR寄存器写1可对引脚置1
				GPIOx->BSRR = (((uint32_t)0x01) << (pinpos + 0x08));
			}
		}
	}
	GPIOx->CRH = tmpreg;//把前面处理后的值暂存写入CRH寄存器中
}
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

端口配置低寄存器(GPIOx_CRL)(x=A…E)

在这里插入图片描述

位 31:10
27:26
23:22
19:18
15:14
11:10
7:6
3:2
CNFy[1:0]:端口x配置位(y=0…7)
软件通过这些位配置相应的I/O端口
在输入模式(MODE[1:0]=00):
00:模拟输入模式
01:浮空输入模式(复位后的状态)
10:上拉/下拉输入模式
11:保留
在输出模式(MODE[1:0]>00):
00:通用推挽输出模式
01:通用开漏输出模式
10:复用功能推挽输出模式
11:复用功能开漏输出模式
位29:28
25:24
21:20
17:16
13:12
9:8
5:4
1:0
MODEy[1:0]:端口x的模式位(y=0…7)软件通过这些位配置相应的I/O端口
00:输入模式(复位后的状态)
01:输出模式,最大速度10MHz
10:输出模式,最大速度2MHz
11:输出模式,最大速度50MHz

main.c文件


#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
void Delay(uint32_t count)
{
	for( ; count !=0; count-- );
}
void SystemInit(void)
	{
	
	}
int main (void)
{

GPIO_InitTypeDef GPIO_InitStructure_R;
GPIO_InitTypeDef GPIO_InitStructure_B;
GPIO_InitTypeDef GPIO_InitStructure_G;
RCC_APB2ENR |= (1<<3);
GPIO_InitStructure_G.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure_G.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure_G.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure_G);

GPIO_InitStructure_B.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure_B.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure_B.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure_B);	

GPIO_InitStructure_R.GPIO_Pin = GPIO_Pin_5;
GPIO_InitStructure_R.GPIO_Mode= GPIO_Mode_Out_PP;
GPIO_InitStructure_R.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure_R);	


while (1)
{ 
	GPIO_ResetBits(GPIOB,GPIO_Pin_0);
	Delay(0xFFFF);
	GPIO_SetBits(GPIOB,GPIO_Pin_0);
	Delay(0xFFFF);
	GPIO_ResetBits(GPIOB,GPIO_Pin_1);
	Delay(0xFFFF);
	GPIO_SetBits(GPIOB,GPIO_Pin_1);
	Delay(0xFFFF);
	GPIO_ResetBits(GPIOB,GPIO_Pin_5);
	Delay(0xFFFF);
	GPIO_SetBits(GPIOB,GPIO_Pin_5);
	Delay(0xFFFF);
}

}

LED电路连接图

在这里插入图片描述

程序下载验证:

在这里插入图片描述

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DS.小青龙

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值