【STM32单片机学习】第五课:STM32标准外设库(SPL 库)

本文详细介绍了STM32标准外设库的使用,包括库的结构、外设信息的封装方式、结构体访问寄存器的原理和实践。讲解了如何使用库重写LED程序,以及RCC和GPIO模块的全解析,阐述了面向对象思想在库中的体现。内容涵盖从外设库的价值到实际编程技巧,适合单片机开发者深入学习。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【朱老师课程总结】

第一部分、章节目录

3.5.1.为什么会有标准外设库

3.5.2_3.外设库的结构介绍和之后的学习方法1_2

3.5.4.标准库对硬件信息的封装方式

3.5.5.使用结构体方式访问寄存器的原理

3.5.6.使用结构体方式访问寄存器的实践

3.5.7_8.使用标准库重写LED的程序

3.5.9_10.RCC模块的标准库全解析

3.5.11.RCC模块的标准库全解析3

3.5.12.RCC模块的标准库全解析4

3.5.13.RCC模块的标准库全解析5

3.5.14_15.使用库重写时钟设置函数1_2

3.5.16_17.GPIO模块的标准库全解析1_2

3.5.18.使用GPIO库函数来点亮LED

3.5.19.标准库中的面向对象思想    

第二部分、随堂记录

3.5.1.为什么会有标准外设库

3.5.1.1、传统单片机软件开发方式
(1)芯片厂商提供数据手册、示例代码、开发环境
(2)单片机软件工程师面向产品功能,查阅数据手册,参考官方示例代码进行开发
(3)硬件操作的方式是用C语言对寄存器进行读写以操作硬件
(4)主要工作量:一是调通各种外设(可读写),二是实现产品功能
(5)在简单单片机(如51单片机)上这一套工作的很好,但是随着单片机变复杂就带来一些问题

3.5.1.2、外设库有什么价值
(1)外设库其实就是以前芯片公司提供的示例代码的标准化产物
(2)外设库简化了我们开发产品时的“调通各种外设”
(3)外设库以源码方式提供,这个源码本身写的很标准,可以用作学习素材

3.5.1.3、学习和使用外设库的难点
(1)要有规范化编程的意识和能力
(2)C语言功底要过关
(3)要有一定的框架和层次认识
(4)要会没有外设库时直接C语言操作寄存器的方式(看原理图、查数据手册、位操作等)

3.5.1.4、再次强调
(1)外设库只是帮助我们简化编程,简化的主要是劳动量
(2)外设库一定程度上降低了编程难度,但是只会库、离了库就不会编程、库函数调用出了问题就束手无策这种还是没戏。(难度降低是对所有人的,你并不能从中得到好处)

3.5.2_3.外设库的结构介绍和之后的学习方法1_2

3.5.2.1、外设库的结构介绍
(1)最新版本库的下载和解压 
官网下载链接
博客提供链接(百度网盘,解压密码:neu1)

(2)文件夹结构和主要文件的作用
在这里插入图片描述

  • _htmresc文件夹内是官方Logo图片,可以删掉。

  • Libraries 文件夹下面有 CMSIS 和 STM32F1xx_StdPeriph_Driver 两个目录,这两个目录包

    含固件库核心的所有子文件夹和文件,是代码移植的重头戏。CMSIS 文件夹存放的是符合 CMSIS 规范的一些文件, Driver 文件夹下是STM32F1 标准外设固件库源码文件和对应的头文件,说白了就是将寄存器封装好的函数接口。

  • Project 文件夹下面有STM32F1xx_StdPeriph_Examples 和STM32F1xx_StdPeriph_Template 两个文件夹,Examples文件夹下是固件示例源码,Template文件夹下是工程模板。这些源码的学习对以后的开发学习非常重要。

  • Utilities 文件夹下就是官方评估板的一些对应源码,可以忽略不看。

  • 根目录中还有一个固件库的帮助文档 stm32f1xx_dsp_stdperiph_lib_um.chm 文件。

(3)最重要的就是Libraries

CMSIS(STM32内部ARM核心相关内容)
    CM3(Cortex-M3)
        CoreSupport(内核相关的一些设置的寄存器集合及其封装)
        DeviceSupport
            ST
                STM32F10x
                    startup(内核相关的一些设置的寄存器集合及其封装)
                    stm32f10x.h(很重要)
                    system_stm32f10x.c
                    system_stm32f10x.h
STM32F10x_StdPeriph_Driver(STM32F1外设驱动
    inc(include,头文件,.h)
    src(source,源文件, .c)

目录树:



3.5.2.2、后续的学习方法
(1)先搞清楚库对STM32这个硬件的封装和表达方式
(2)再彻底理解库中使用的结构体式访问硬件寄存器的方式
(3)初步建立起面向对象式编程的概念并且去体会
(4)以模块为单位去研究这个模块的库函数,并且用库函数去编程,并且实验结果,并且分析代码,去体会去熟悉库函数使用的方法
(5)最终达到什么程度?眼里有库心中无库。用人话说就是:思维能够穿透库函数直达内部对寄存器的操作

3.5.4.标准库对硬件信息的封装方式

3.5.4.1、寄存器地址的封装
其实就是将寄存器在存储器中的地址,利用宏定义表示出来。(这里的地址是指在位带区内的地址,关于位带区和位带别名区请往后看)

  • 比如:外设总线APB1的基地址为:0x40000000,APB2的基地址为0x40010000
  • 因为APB1和APB2分别有不同的外设设备,所以基地址+偏移量,就可以把寄存器表示出来!
  • TIM5的地址是0x40000C00  = 0x40000000+0x0C00 = APB1基地值+偏移量



3.5.4.2、寄存器位定义的封装
就是对于寄存器每一位的操作,有很多种情况,直接利用宏定义将不同的复制情况进行封装。
比如说,打开HSE时钟时,要操纵寄存器RCC_CR,给第16位赋值1,就可以打开HSE时钟。


RCC_TypeDef是个结构体变量,里面封装这RCC的各个寄存器,RCC_BASE是RCC寄存器组的基地址,于是RCC就是一个结构体指针,指向RCC_BASE下的RCC寄存器组。

  • 按照之前:RCC_CR |= 0x00010000;
  • 用标准库:RCC->CR |= CR_HSEON_Set;

道理一样!这样的好处就是更加直观,代码可读性更强!


3.5.4.3、外设操作的封装
其实就是很多的函数,比如说配置外部时钟72MHz,需要配置HSE,操纵不同的寄存器,在SPL中,这些工作都给做好了!
比如说,下面配置HSE的子函数,只要RCC_HSE准备就绪,就可以打开HSE!

3.5.5.使用结构体方式访问寄存器的原理

(1)之前访问寄存器方式
C语言访问寄存器的本质是C语言访问内存
本质思路:

  • 定义一个指针(临时变量)指向这块内存,然后*p = xx这种方式去解引用指针从而向目标内存中写入内容。

缺陷:

  • 当寄存器多了之后每一个寄存器都要定义一套套路,很麻烦。

(2)解决思路:就是打包,批发式的定义,用结构体(想一下为什么不用数组?)的方式进行打包。
具体做法:
把整个一个模块的所有寄存器(地址是连接的)打包在一个结构体中,每个寄存器对应结构体中的一个元素,然后结构体基地址对应寄存器组的基地址,将来就可以通过结构体的各个元素来访问各个寄存器了。


(3)结构体方式来访问寄存器和指针式访问寄存器,本质上其实是一样的,区别是C语言的封装不同。
(4)volatile的作用

  • volatile修饰的变量从CPU寄存器中直接读取数值而不是从备份中读取。备份就是编译器自己拷贝的一个寄存器,它是一个软件寄存器相对于物理芯片内的寄存器来说。这个备份具体多少毫秒刷新一次我也不清楚,但是它被读取的速度相对于进程频繁的读取物理寄存器要快很多,这就是编译器为了效率对程序的优化。
  • 不加volatile,C编译器为了速度会把你的代码自动优化直接从备份中读取
  • 加了volatile就是明确告诉编译器这里不需要你自做聪明的优化给我直读,嵌入式中底板驱动编程尤为重要。

3.5.6.使用结构体方式访问寄存器的实践

程序下载

3.5.7_8.使用标准库重写LED的程序

3.5.7.1、分析标准库自带的工程模板
模板在"STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\MDK-ARM"下,用MDK软件双击project即可打开。

模板目录:

  • User文件夹

    存放用户自己写的main.c和用来存放中断服务函数的stm32f10x_it.c
  • StdPeriph_Driver文件夹

    存放\Libraries\STM32F10x_StdPeriph_Driver\src\下的与外设相关的.c文件
  • CMSIS文件夹

    存放时钟配置文件system_stm32f10x.c和内核相关的core_cm3.c
  • STM32_EVAL文件夹

    存放基于STM32100E开发板的一些官方的开发例程。
  • MDK-ARM

    里面放的是启动文件,会在Options中配置上需要哪个文件,比如上图,在Options的宏定义里规定使用STM32F10X_HD_VL,于是只有该选项没有被屏蔽掉!
  • Options中

3.5.7.2、建立自己的模板
1.创建My_Template文件夹

2.进入My_Template,复制\STM32F10x_StdPeriph_Lib_V3.5.0\Libraries\下的CMSIS、STM32F10x_StdPeriph_Driver到My_Template下

3.创建User、Project、Listings、Output文件夹

4.打开MDK,创建新Project(名字自定义),存放在My_Template/Project下

5.选择自己开发板的芯片,这里选择的是“STM32F103C8”,出来的Run-Time页面,直接关闭就行

6.添加各个文件夹到工程

7.添加启动文件组,启动文件在\My_Template\CMSIS\CM3\DeviceSupport\ST\STM32F10x\startup\arm\下,STM32F103C8属于md产品,所以我选择xx_md.s

8.添加CMSIS组,添加\My_Template\CMSIS\CM3\CoreSupport\下的core_cm3.c和\My_Template\CMSIS\CM3\DeviceSupport\ST\STM32F10x\下的system_stm32f10x.c

9.添加StdPeriph_Driver组,把\My_Template\STM32F10x_StdPeriph_Driver\src\下的所有文件添加进来

10.添加User组,在User文件夹下新建一个main.c文件,复制\STM32F10x_StdPeriph_Lib_V3.5.0\Project\STM32F10x_StdPeriph_Template\下的stm32f10x_conf.h、stm32f10x_it.c、stm32f10x_it.h到User文件夹下,通过MDK把这两个.c文件添加进来。


11.点OK,完成Group的创建,然后点击Options for Target。


12.Target选项,勾选上User MicroLIB

13.OutPut选项

14.Listing选项(可选)

15.C/C++选项
添加宏定义:STM32F10X_MD,USE_STDPERIPH_DRIVER
其中STM32F10X_MD要根据自己的板子的属性,和startup下的xx_md.s对应

添加include path:如下图

点OK。
16.编辑User\main.c文件,添加以下内容。

#include "stm32f10x."

int main(void)
{
	
	return 0;
}

17.点击Rebulid,如果不报错,说明模板创建完毕。
 

3.5.7.3、使用标准库方式操作点亮LED
1.复制My_Template文件夹,重命名为3.stdlib_led

2.打开Project/下的工程文件,修改main.c,粘贴下面的内容

#include "stm32f10x.h"


/*---------接线-------------

		PB8--PB15接到LED1--LED8

---------------------------*/

void led_flash(void);
void led_init(void);
void delay(void);

int main(void)
{
	led_init();
	led_flash(); //内部时钟8MHz
	
	while(1);
}

void led_init(void)
{

		//GPIO时钟使能
		RCC->APB2ENR = 0x00000008;
		
		//GPIOB设置成推挽输出模式,速度是50MHz
		GPIOB->CRH  = 0x33333333;
}

void led_flash(void)
{
	unsigned int i = 0;
	for(i = 0;i<5;i++)
	{
			GPIOB->ODR = 0x00000000;
			delay();
			GPIOB->ODR = ~GPIOB->ODR;
			delay();
	}
}

void delay(void)
{
	unsigned int i,j;
	for(i = 0;i<1000;i++)
		for(j = 0;j<1000;j++);
}

点击build,没有错误就可以烧录到板子上运行结果了。
 

3.5.9_10.RCC模块的标准库全解析1_2

1.一般模块都是成对存在(xxx.c+xxx.h)
一般在.h中是宏定义和函数的声明,.c中是函数的实现。

2.RCC.c和RCC.h里面都有宏定义,为什么不都放在RCC.h里面呢?
放在RCC.h里面的宏定义可以被RCC.c和其他文件使用,RCC.c里面的宏定义只用在RCC.c中,这是一个数据的封装,比较合理。

3.RCC.c中的位带别名区地址
(1)RCC的位带操作
不记得什么叫位带操作可以看一下这个链接:【ARM】---STM32位带操作总结---浅显易懂
我们只要记住下面这张图的公式即可:

外设位带别名区地址 = 0x42000000(PERIPH_BB_BASE) + 偏移量*32 + 位数*4
(2)RCC_OFFSET:RCC相对于外设位带区基地值的偏移量


(3)时钟控制寄存器(RCC_CR)的各个位在位带别名区的地址

  • CR寄存器的基地值和RCC的基地值一样,所以相对于外设位带区基地值偏移量 = RCC_OFFSET + 0x00
  • HSION是CR寄存器的第0位,所以n = 0x00
  • 代入公式,CR_HSION位的位带别名区地址CR_HSION_BB = 0x42000000(PERIPH_BB_BASE) + CR_OFFSET*32 + n*4 = 0x42000000 + 0x21000*32 + 0x00*4 = 0x42672000
  • 其他位的计算方法,和上面一样。PLLON是第24位,即第0x18位,CSSON是第19位,即第0x13位。


(4)时钟配置寄存器(RCC_CFGR)的各个位在位带别名区的地址

  • RCC_CFGR的偏移量是0x04个字节
  • USBPRE是RCC_CFGR的第22位,即第0x16位。

后面一直到116行都是上面的分析方法。

4.RCC.c中的位掩码
位掩码作用:利用Reset进行|=~运算给某一位清零,然后再Set利用&运算就可以设置某位为1了。

默认:SET--写1,RESET--写0
所以:ReSet---第n位写0,其他位写1,Set---第n位写1,其他位写0.

以CR寄存器的HSEBYP、HSEON、HSITRIM为例。HSEBYP的Reset为0xFFFBFFFF


其他的类似分析方法。

在193、194行有两个预分频的全局变量,等用到了再看

 

3.5.11.RCC模块的标准库全解析3

5.RCC.c里面的函数

(1)void RCC_DeInit(void)
作用:将 RCC 时钟配置重置为默认重置状态。平时用的比较少!

(2)void RCC_HSEConfig(uint32_t RCC_HSE)
作用:配置外部高速振荡器(HSE)
Note:如果 HSE 直接使用或通过 PLL 作为系统时钟,则不能关闭HSE时钟
参数:RCC_HSE:指定HSE的新状态。此参数可以是以下值之一:

  •  RCC_HSE_OFF:HSE振荡器关闭
  •  RCC_HSE_ON:HSE振荡器打开
  •  RCC_HSE_Bypass:HSE振荡器旁路外部时钟

(3)assert_param解析
assert叫断言,assert机制是C语言里用来判断一个东西是对的还是错的,并且如果是对的那就直接忽略过去,如果是错的就以某种方式告诉我们(warrning error)让我们去改。
断言机制使用最多的就是:库函数中用断言来检查用户调用该库函数时传参到底对不对

判断断言表达式是否对,如果对就正常运行,如果不对,就调用assert_failed函数,这个函数可以自己编辑,比如可以报错:xx行有变量值错误

(4)ErrorStatus RCC_WaitForHSEStartUp(void)
作用:等待 HSE 启动稳定
返回值:

  •  SUCCESS:HSE振荡器稳定并准备使用
  •  ERROR:HSE振荡器尚未准备好

3.5.12.RCC模块的标准库全解析4

5.(5)FlagStatus RCC_GetFlagStatus(uint8_t RCC_FLAG)
作用:检查指定的 RCC 标志是否设置。
(6)void RCC_HSICmd(FunctionalState NewState)
作用:启用或禁用内部高速振荡器 (HSI)。
NewState: HSI的新状态。此参数可以是:启用或禁用。使用最原始的给寄存器某一位写值的方式

  *(__IO uint32_t *) CR_HSION_BB = (uint32_t)NewState;

(7)void RCC_PLLConfig(uint32_t RCC_PLLSource, uint32_t RCC_PLLMul) 
作用:配置 PLL 时钟来源和倍频因子。
Note:此功能必须仅在 PLL 被禁用时使用。
RCC_PLLSource有三个来源:RCC_PLLSource_HSI_Div2、RCC_PLLSource_HSE_Div1、RCC_PLLSource_HSE_Div2
RCC_PLLMul:[2,16]
(8)void RCC_SYSCLKConfig(uint32_t RCC_SYSCLKSource)
作用: 配置系统时钟 (SYSCLK)
参数RCC_SYSCLKSource有三个来源:

  • RCC_SYSCLKSource_HSI
  • RCC_SYSCLKSource_HSE

  • RCC_SYSCLKSource_PLLCLK

3.5.13.RCC模块的标准库全解析5

5.(9)void RCC_HCLKConfig(uint32_t RCC_SYSCLK)
作用:配置AHB 时钟 (HCLK).
参数RCC_SYSCLK:/1,2,4,8,16,64,128,256,512
(10)void RCC_PCLK1Config(uint32_t RCC_HCLK)
作用:配置APB1 时钟 (PCLK1).
参数RCC_HCLK:/1,2,4,8,16
(11)void RCC_PCLK2Config(uint32_t RCC_HCLK)
作用:配置APB2 时钟 (PCLK2).
参数RCC_HCLK:/1,2,4,8,16
(12)void RCC_ITConfig(uint8_t RCC_IT, FunctionalState NewState)
作用:使能或者不使能 RCC中断,传入时钟源,当就绪之后,就使能触发中断。
参数RCC_IT:选择中断源:LSI、LSE、HSI、HSE、PLL
参数NewState:DISABLE / ENABLE
(13)后面依次是RCC_ADCCLKConfig、RCC_LSEConfig、RCC_LSICmd、RCC_RTCCLKConfig、RCC_RTCCLKCmd、RCC_GetClocksFreq......比较简单。

(14)1063行:void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState)
作用:用于使能AHB外设时钟
可以使能的外设如下图

(15)void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
作用:用于使能APB2外设时钟
可以使能的外设如下图

(16)void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState)
作用:用于使能APB1外设时钟
可以使能的外设如下图

3.5.14_15.使用库重写时钟设置函数1_2

哪一行取消注释,上电后,默认以什么频率工作。
main函数
 

#include "stm32f10x.h"


/*---------接线-------------

		PB8--PB15接到LED1--LED8

---------------------------*/

void led_flash(void);
void led_init(void);
void delay(void);
void Set_SysClockTo72M(void);

int main(void)
{
	led_init();
	led_flash(); 	//内部时钟8MHz
	
	Set_SysClockTo72M();
	led_flash();	外部时钟72MHz
	
	while(1);
}

void led_init(void)
{

		//GPIO时钟使能
		RCC->APB2ENR = 0x00000008;
		
		//GPIOB设置成推挽输出模式,速度是50MHz
		GPIOB->CRH  = 0x33333333;
}

void led_flash(void)
{
	unsigned int i = 0;
	for(i = 0;i<5;i++)
	{
			GPIOB->ODR = 0x00000000;
			delay();
			GPIOB->ODR = ~GPIOB->ODR;
			delay();
	}
}

void delay(void)
{
	unsigned int i,j;
	for(i = 0;i<1000;i++)
		for(j = 0;j<1000;j++);
}

新建clock.c,放在User下!

#include "stm32f10x.h"

#define PLL_STARTUP_TIMEOUT   ((uint16_t)0x1000)

//等待PLL倍频后输入稳定
ErrorStatus RCC_WaitForPLLStartUp(void)
{
  __IO uint32_t StartUpCounter = 0;
  ErrorStatus status = ERROR;
  FlagStatus PLLStatus = RESET; //没就位
  
  /* Wait till PLL is ready and if Time out is reached exit */
  do
  {
    PLLStatus = RCC_GetFlagStatus(RCC_FLAG_PLLRDY);
    StartUpCounter++;  
  } while((StartUpCounter != PLL_STARTUP_TIMEOUT) && (PLLStatus == RESET));
  
  if (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) != RESET)
  {
    status = SUCCESS;
  }
  else
  {
    status = ERROR;
  }  
  return (status);
}


void Set_SysClockTo72M(void)
{
	ErrorStatus sta = ERROR; //HSE就绪标志位
	
	/*上电复位RCC_CR*/
	 RCC->CR = 0x00000083; 
		
	/*开启外部时钟HSE*/
	RCC_HSEConfig(RCC_HSE_OFF);
	RCC_HSEConfig(RCC_HSE_ON);
	
	//等待HSE稳定	
	sta = RCC_WaitForHSEStartUp();
	
	if(sta == SUCCESS) //HSE准备就绪
	{
		/*启用半周期访问、两个等待状态,当 48MHz < SYSCLK ≤ 72MHz*/
		FLASH->ACR |= 0x10;
		FLASH->ACR &= (~0x03);
		FLASH->ACR |= (0x02);
		
		
		/*选择HSE不分频作为PLL的输入时钟,HSE = 8M,设置PLL倍频系数为9倍*/
		RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);
		
		/*AHB、APB2不分频,APB1二分频*/
		RCC_HCLKConfig(RCC_SYSCLK_Div1);
		RCC_PCLK1Config(RCC_HCLK_Div2);
		RCC_PCLK2Config(RCC_HCLK_Div1);
		
		/*---开启PLL时钟---*/
		RCC_PLLCmd(ENABLE);
		
		sta = ERROR;
		/*--等待PLL稳定--*/
		sta = RCC_WaitForPLLStartUp();
		
		if(sta == SUCCESS)
		{
			/*---设置PLL为系统时钟来源---*/
			
			RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
		}
		else
		{
			while(1);	//PLL配置超时
		}

		/***检查SWS位,等待PLL作为SYSCLK时钟启动成功***/
		while(RCC_GetSYSCLKSource()!=0x08)
		{
		}
	}
	else
	{
		while(1);	//HSE配置超时
	}
}


 

3.5.16_17.GPIO模块的标准库全解析1_2

和RCC分析一样,我们也是着重分析.c和.h文件
1.GPIO的位带操作
和RCC分析一样,就是套公式。

2.函数
(1)void GPIO_DeInit(GPIO_TypeDef* GPIOx)
作用:将 GPIOx(x=A:G) 外围寄存器降级到其默认重置值
GPIO_TypeDef是一个结构体类型:

(2)void GPIO_AFIODeInit(void)
作用:将 AFIO外围寄存器降级到其默认重置值
(3)void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
作用:根据参数GPIO_InitStruct来初始化GPIOx的外设
GPIO_InitTypeDef也是一个结构体类型:

  • 引脚选择:
  • 引脚输出速率(只有输出时需要配置)
  • 引脚输入输出模式
  • 小结一下
    GPIOx有GPIOA--GPIOG这7个端口
    每个端口都有CRL、CRH、IDR、ODR..寄存器
    每个端口都有16个引脚
    每个引脚都可以配置自己的速率和输入输出模式。
    所以在初始化GPIO时,一般都是先配置某个引脚再去选端口。

(4)void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct)
作用:用默认值填充每个GPIO_InitStruct成员。

(5)uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
作用:读取指定的输入端口引脚的值。
返回值:读取的值
(6)uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx)
作用:读取指定GPIO输入端口的值。
返回值:读取的值
(7)uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
作用:读取指定的输出端口引脚的值。
返回值:读取的值
(8)uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx)
作用:读取指定GPIO输出端口的值。
返回值:读取的值
(9)void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
作用:给指定端口的指定引脚置1
(10)void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
作用:给指定端口的指定引脚置0
(11)void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal)
作用:设置或清除选定的数据端口位。和上面重复了!
(12)void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal)
作用:给端口赋值
(13)void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
作用:锁定GPIO引脚配置寄存器。
(14)void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
作用:AFIO选定指定引脚作为事件输出。
(15)void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState) ★
作用:更改指定管脚的映射。
(16)void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)

作用:选择用作EXTI线的GPIO引脚。和中断相关。

3.5.18.使用GPIO库函数来点亮LED

代码下载:下载地址

3.5.19.标准库中的面向对象思想    

3.5.19.1、面向对象介绍
(1)一种编程思想(面向过程、面向对象)
(2)什么是对象
(3)面向对象三大特征:封装、继承、多态
(4)面向对象编程思想和面向对象语言是两码事
3.5.19.2、标准库的面向对象特征
(1)各种数据类型结构体就是一种封装
(2)标准库是为了被复用
(3)GPIO的编程模式是典型的面向对象式编程
典型面向对象的编程模式:
第1步:先构建对象(可以理解为定义一个结构体类型)
第2步:用对象构造实例(可以理解为用结构体类型来定义结构体变量)malloc
第3步:填充实例(其实就是给结构体的各个元素赋值)
第4步:使用实例(其实就是把结构体变量作为参数传给某个函数使用)
第5步:销毁实例(其实就是把前面第2步定义的机构体变量给销毁掉)free

本节课结束!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

搞IC的小冯

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

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

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

打赏作者

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

抵扣说明:

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

余额充值