【STM32】标准库的引入

news2024/11/12 10:17:23

一、为什么要会有标志外设库

1、传统单片机软件开发方式

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

2、外设库有什么价值

(1)外设库其实就是以前芯片公司提供的示例代码的标准化产物
(2)外设库简化了我们开发产品的2大工作量的第一个
(3)外设库以源码方式提供,这个源码本身写的很标准,可以用作学习素材

3、学习和使用外设库的难点

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

二、外设库的结构介绍和之后的学习方法

1.外设库的结构介绍

(1)最新版本库的下载和解压

官方网站:STM32标准外设软件库: 相关产品

(2)建立SourceInsight工程

1)先在盘符中建立一个文件夹,然后再sourceInsight中打开这个文件夹

(3)文件夹结构和主要文件的作用

1.Project

2.Libraries

CMSIS(STM32内部ARM核心相关内容)
    CM3(Cortex-M3)
        CoreSupport
            内核相关的一些设置的寄存器集合及其封装


        DeviceSupport
            ST
                STM32F10x
                    startup(起始文件)

https://www.cnblogs.com/amanlikethis/p/3989989.html
                    stm32f10x.h【STM32常见数据结构的封装】
                    system_stm32f10x.c
                    system_stm32f10x.h


STM32F10x_StdPeriph_Driver(外设驱动)
    inc(include,头文件,.h)
    src(source,源文件, .c)

2.system_stm32f10x.c

在这个文件中定义了2个函数和一个全局变量:时钟相关的

3、后续的学习方法

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

三、标准库对硬件信息的封装方法

1.寄存器地址的封装

1.手动操作寄存器地址

2.库文件中的寄存器地址(stm32f10x.h)

2.寄存器位定义的封装

1.直接通过移位操作位寄存器

2.使用宏定义进行位寄存器

不用直接写数字,而使用宏定义

3.外设操作的封装

1.自定义函数

2.使用库函数

.c文件对其进行封装

四、使用结构体方式访问寄存器的原理

1.最原始的方法

1)C语言访问寄存器的本质是c语言访问内存,本质思路是:

定义一个指针指向这块内存,然后*p=xx这种方式去解引用指针从而向没有标内存中写入内容。

2)缺陷:当寄存器多了之后每一个寄存器都要定义一套套路,很麻烦

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

2.使用结构体

结构体方式来访问寄存器和指针式访问寄存器,本质上其实是一样的,区别是c语言的封装不同。

TIM的

GPIO的

五、使用结构体方式访问寄存器的实践

1.原始方式

gpio.h

#define GPIOB_CRH		0x40010C04
#define GPIOB_CRL		0x40010C00
#define GPIOB_ODR		0x40010C0C
#define GPIOB_BSRR	0x40010C10
#define GPIOB_BRR		0x40010C14

#define RCC_APB2ENR		0x40021018

#define rGPIOB_CRH 		(*((unsigned int *)GPIOB_CRH))
#define rGPIOB_ODR 		(*((unsigned int *)GPIOB_ODR))
#define rGPIOB_BSRR 	(*((unsigned int *)GPIOB_BSRR))
#define rGPIOB_BRR 		(*((unsigned int *)GPIOB_BRR))
#define rRCC_APB2ENR 	(*((unsigned int *)RCC_APB2ENR))
	

void led_flash(void);

void led_init();
void delay();

gpio.c

/**
	点亮led灯
*/

#include "gpio.h"

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

void led_init(){
	rRCC_APB2ENR = 0x00000008;

	rGPIOB_CRH = 0x33333333;
	rGPIOB_ODR = 0x0000aa00;//全灭
	
}
void led_flash(void){
	unsigned int i=0;
	for(i=0;i<3;i++){
		rGPIOB_ODR = 0x00000000;//全亮
		delay();
		rGPIOB_ODR = 0x0000ff00;//全灭
		delay();
	} 
}
void main(void){
	led_init();
	led_flash();
}

2.使用结构体的方式对寄存器访问

注意点:

我们在定义相关寄存器的结构体的时候要注意顺序问题,一定要按照寄存器偏移量从低到高,要不然会出现问题。

3.两者对比

代码

gpio.h

#define GPIOB_BASE		0x40010C00
#define GPIOC_BASE		0x40011000

#define GPIOB_CRH		(GPIOB_BASE + 0x04)
#define GPIOB_ODR		(GPIOB_BASE + 0x0C)
#define GPIOB_BSRR		(GPIOB_BASE + 0x10)
#define GPIOB_BRR		(GPIOB_BASE + 0x14)

#define GPIOC_CRL		(GPIOC_BASE + 0x00)
#define GPIOC_ODR		(GPIOC_BASE + 0x0C)
#define GPIOC_BSRR		(GPIOC_BASE + 0x10)
#define GPIOC_BRR		(GPIOC_BASE + 0x14)


#define RCC_APB2ENR		0x40021018

//-------------------------------------------------

#define rGPIOB_CRH 		(*((unsigned int *)GPIOB_CRH))
#define rGPIOB_ODR 		(*((unsigned int *)GPIOB_ODR))
#define rGPIOB_BSRR 	(*((unsigned int *)GPIOB_BSRR))
#define rGPIOB_BRR 		(*((unsigned int *)GPIOB_BRR))

#define rGPIOC_CRL 		(*((unsigned int *)GPIOC_CRL))
#define rGPIOC_ODR 		(*((unsigned int *)GPIOC_ODR))
#define rGPIOC_BSRR 	(*((unsigned int *)GPIOC_BSRR))
#define rGPIOC_BRR 		(*((unsigned int *)GPIOC_BRR))

#define rRCC_APB2ENR 	(*((unsigned int *)RCC_APB2ENR))
	

//用结构体的方式对寄存器访问
typedef struct{
	unsigned int CRL;
	unsigned int CRH;
	unsigned int IDR;
	unsigned int ODR;
	unsigned int BSRR;
	unsigned int BRR;
	unsigned int LCKR;
}GPIO_Typedef;


void led_flash(void);

void led_init();
void delay();

gpio.c

/**
	点亮led灯
*/

#include "gpio.h"

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

/*
原始方法
void led_init(){
	rRCC_APB2ENR = 0x00000008;

	rGPIOB_CRH = 0x33333333;
	rGPIOB_ODR = 0x0000aa00;//隔一个亮一个
	
}
void led_flash(void){
	unsigned int i=0;
	for(i=0;i<3;i++){
		rGPIOB_ODR = 0x00000000;//全亮
		delay();
		rGPIOB_ODR = 0x0000ff00;//全灭
		delay();
	} 
}
*/

void led_init(){
	GPIO_Typedef *p=(GPIO_Typedef *)GPIOB_BASE;
	
	//因为RCC部分还没有定义结构体,所以还是按照原来的方式去操作
	rRCC_APB2ENR = 0x00000008;
	
	//结构体只能使用【->】
	p->CRH=0x33333333;
	
	p->ODR=0x0000aa00;
}
void led_flash(void){
	GPIO_Typedef *p=(GPIO_Typedef *)GPIOB_BASE;
	unsigned int i=0;
	for(i=0;i<3;i++){
		p->ODR = 0x00000000;//全亮
		delay();
		p->ODR = 0x0000ff00;//全灭
		delay();
	} 
}



void main(void){
	led_init();
	led_flash();
}

4.小技巧

1.将基地址指针作为全局变量

因为在每一个函数开始之前,都要使用到基地址

2.结构体元素填充

我们前面提到说,在定义结构体的时候一定一定要按照寄存器的偏移量从小到大的顺序定义要不然出错,但是我们在一些地方可能空缺出来,没有寄存器,所以我们需要一个占位,将其补充,要不然后面的其他寄存器可能受到影响。

3.寄存器可操作位数不同

我们在学习RCC时钟的时候遇到一些寄存器可以操作32位,但是有一些只能操作16位。此时我们可以将其直接写入(不用管是否用足32位),也可以分成2个16位写入。

//用结构体的方式对寄存器访问
typedef struct{
	unsigned int CRL;
	unsigned int CRH;
	//unsigned int IDR;
	//将32位的IDR分为2个16位
	unsigned short IDR;
	unsigned short paddingIDR;//此16位用不到
	unsigned int ODR;
	unsigned int BSRR;
	unsigned int BRR;
	unsigned int LCKR;
}GPIO_Typedef;

六、使用标准库重写LED的程序

1.分析标准库自带的文件模板

1.完整目录

2.User,Driver

3.CMSIS.startup

4.配置注意点:

2.stm32f10x.h

选择芯片类型

在“stm32f10x.h”有可以查看,要修改可以在options--》c/c++中进行修改宏定义

2.宏定义的设置

3.外部晶振时钟设置

3.stm32f10x_conf.h

1.包含所有外设的头文件

这个头文件是标准库的模板中的,将所有需要使用到的头文件包含进去

所以在整个工程中,无论我们创建一个什么类型的.c文件,只要我们定义了

【“stm32f10x.h”】

则就等价于将所有的外设器件的.h文件包含进来了

2.assert_param(断言机制)

4.正式自己搭建文件目录

1.文件结构

2.文件导入

1.startup

2.CMSIS

3.stdperiph_driver

4.user

3.配置

自定义宏定义,在stm32f10x.h,stm32f10_conf.h文件中查找

4.出现问题

将配置中的”断言“去除

5.代码修改

#include "stm32f10x.h"

/**
	使用标准库重写LED的程序
*/


/*
//原始代码
void led_init(){
	//GPIO_Typedef *p=(GPIO_Typedef *)GPIOB_BASE;
	
	//因为RCC部分还没有定义结构体,所以还是按照原来的方式去操作
	rRCC_APB2ENR = 0x00000008;
	
	//结构体只能使用【->】
	//p->CRH=0x33333333;
	pGPIOB->CRH=0x33333333;
	
	//p->ODR=0x0000aa00;
	pGPIOB->ODR=0x0000aa00;
}
*/

//第一步:先去”stm32f10x.h"文件中查找相关的寄存器
//				比如RCC,GPIO
//第二步:找到相关的寄存器的宏定义,将其直接复制过来

//使用HAL库
void led_init(){
	//GPIO_Typedef *p=(GPIO_Typedef *)GPIOB_BASE;
	
	//因为RCC部分还没有定义结构体,所以还是按照原来的方式去操作
	RCC->APB2ENR = 0x00000008;
	
	//结构体只能使用【->】
	//p->CRH=0x33333333;
	GPIOB->CRH=0x33333333;
	
	//p->ODR=0x0000aa00;
	GPIOB->ODR=0x0000aa00;
}

int main(){
	
	led_init();
	return 0;
}


七、RCC模块的标准库全解析

【STM32】RCC时钟模块(使用HAL库)-CSDN博客

八、CPIO模块的标准库全解析

【STM32】GPIO控制LED(HAL库版)-CSDN博客

九、标准库中的面向对象思想

1、面向对象介绍

(1)一种编程思想(面向过程、面向对象)
(2)什么是对象
(3)面向对象三大特征:封装、继承、多态
(4)面向对象编程思想和面向对象语言是两码事

2、标准库的面向对象特征

(1)各种数据类型结构体就是一种封装
(2)标准库是为了被复用
(3)GPIO的编程模式是典型的面向对象式编程

典型面向对象的编程模式:

第1步:先构建对象(可以理解为定义一个结构体类型)
第2步:用对象构造实例(可以理解为用结构体类型来定义结构体变量)malloc
第3步:填充实例(其实就是给结构体的各个元素赋值)
第4步:使用实例(其实就是把结构体变量作为参数传给某个函数使用)
第5步:销毁实例(其实就是把前面第2步定义的机构体变量给销毁掉)free

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1132913.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

揭秘提升远程团队协作效率的秘密武器:这款在线白板工具不容错过!

说到出色的远程团队协作工具&#xff0c;任何已经完善了远程/混合工作模式的公司都使用了大量的在线协作软件。TrustRadius进行的一项调查显示&#xff0c;三分之二的企业正在投资于网络会议软件。 对于任务跟踪、协作工作或员工互动&#xff0c;市场上有许多工具可供选择。不…

2023年【电工(技师)】证考试及电工(技师)模拟考试题库

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 电工&#xff08;技师&#xff09;证考试根据新电工&#xff08;技师&#xff09;考试大纲要求&#xff0c;安全生产模拟考试一点通将电工&#xff08;技师&#xff09;模拟考试试题进行汇编&#xff0c;组成一套电工…

Redis数据类型——set类型数据交并差操作

1.业务场景 2.求两个set集合中交并补的操作

电流源,恒流源,直流电子负载

四个并联比一个电阻噪声小 ADI方案

HuggingFace 国内下载 阿里云盘下载速度20MB/s

文章目录 效果展示思路阿里云盘API工具 aligo安装aligoaligo教程实战 保存模型到阿里云盘海外服务器下载模型装包aligo的上传代码 国内下载其他方式 效果展示 Huggingface被屏蔽了&#xff0c;根本下载不了。 阿里云盘下载速度最高可达20MB/s&#xff0c;平均17MB/s左右。【注…

充气膜建筑的形体设计

建筑体量、形象、材料、色彩等都对应同周围环境协调。建筑设计构思要把客观存在的“境”与主管构思的“意”融合起来。一方面要分析环境对建筑可能产生的影响&#xff0c;另一方面要分析设想中的建筑在自然环境中的地位。因地制宜&#xff0c;结合地形的 高低起伏&#xff0c;利…

UG\NX二次开发 在资源栏(左侧面板)中添加按钮

文章作者:里海 来源网站:王牌飞行员_里海_里海NX二次开发3000例,里海BlockUI专栏,C\C++-CSDN博客 感谢粉丝订阅 感谢 apolloryd 订阅本专栏,非常感谢。 简介 UG\NX二次开发 在资源栏(左侧面板)中添加按钮,下面提供了帮助说明,在 UGOPEN 文件夹下有示例。 C++语言在UG二次…

选择合适的项目管理系统来支持专业产品研发团队

专业产品研发团队的公司离不开其严谨的管理和高效的研发流程&#xff0c;为了进一步提升研发效率和管理水平&#xff0c;产研团队需要一个全流程的项目管理系统来支持其研发团队的协同合作。 一、系统需求 IT行业的研发工作涵盖了从立项、项目变更到项目的进程计划等多个环节。…

Windows server部署filebeat到kafka

需求&#xff1a;Windows dhcp日志需要实时传输到elk或者其他告警平台。 1、filebeat下载地址&#xff1a;https://www.elastic.co/cn/downloads/beats/filebeat 2、下载后解压后配置filebeat.yml文件&#xff0c; 3、README.md文件中有运行的操作方法&#xff1a;cmd上进入f…

基于springboot财务管理系统

基于springboot财务管理系统 系统主要包括首页&#xff0c;个人中心&#xff0c;员工管理&#xff0c;部门管理&#xff0c;员工工资管理&#xff0c;工资调整管理&#xff0c;资产类别管理&#xff0c;固定资产管理&#xff0c;经营信息管理&#xff0c;序时账管理&#xff0c…

从0到1配置TensorRT环境

根据博文&#xff1a;TensorFlow2.x模型转onnx、TensorRT给出的环境来配置。 以下是该博文中给出的版本信息 TensorFlow 2.4 CUDA 11.1 CUDNN 8 TensorRT 8.2.1.8 tf2onnx 1.13.0 onnx 1.12.0 下载地址 包下载地址TensorRT 8.2.1.8https://developer.nvidia.com/nvidia-tenso…

代码随想录 Day27 贪心02中 LeetCode T55跳跃游戏

LeetCode T55 跳跃游戏 题目链接:55. 跳跃游戏 - 力扣&#xff08;LeetCode&#xff09; 题目思路: 这题我们可以换一个思想,将跳跃问题转换为覆盖问题,我们每遇到一个元素就跳到这个元素可以覆盖到的最大位置,当能覆盖下整个数组的时候,就说明能达到,返回true,否则返回false …

机关事务管理局数字化平台,让数据纵向直报,业务横向打通

机关事务管理局的核心职能是实现对机关事务的管理、保障、服务&#xff0c;是面向政府机关部门的“后勤服务”部门。 主要职能有&#xff1a;推进国有资产管理、公务用车管理、办公用房管理、公共机构节能管理、后勤管理等。党和政府“过紧日子”的要求为机关事务工作提出了更…

1600*C. Remove Adjacent(贪心字符串)

Problem - 1321C - Codeforces 解析&#xff1a; 贪心&#xff0c;从z到a遍历&#xff0c;每次循环减去符合题意的字符。 #include<bits/stdc.h> using namespace std; signed main(){int n;string s;cin>>n>>s;for(char iz;i>a;i--){for(int j0;j<s.…

使用SPSS进行重复测量方差分析-包括数据正态性检验

最近在处理重复测量数据&#xff0c;新学了重复测量方差分析、广义估计方程这两个方法&#xff0c;都是在SPSS中进行的。只有数据服从正态分布才可以用重复测量方差分析&#xff0c;如果不符合可以用广义估计方程或者其它方法&#xff0c;这次先介绍重复测量方差分析 具体的操…

ubuntu 22.04 设置 apt 代理 配置 清华源 add-apt-repository 代理

另一种临时代理 export http_proxyhttp://<proxy>:<port> export https_proxyhttp://<proxy>:<port> sudo -E add-apt-repository ppa:linaro-maintainers/toolchainhttps://askubuntu.com/questions/53146/how-do-i-get-add-apt-repository-to-work-…

SpringBoot集成ES、使用Java API对其进行简单的测试

文章目录 版本信息记录使用Java API配置ES客户端实现集成pom.xml添加相关的Dependency使用javaConfig构建RestHighLevelClient对象 给ES中存储文档数据,当然也可以更新文档数据search API:搜索 address 中包含mill的所有人的年龄分布以及平均年龄search API:按照年龄聚合&#…

如何通过卖虚拟资料月入10万?看这几个卖资料案例

我微信好友里&#xff0c;有近4000个是做创业博主的同行。 你可能会好奇&#xff0c;其中60%的人都通过卖虚拟资料起家&#xff0c;这到底说明了什么呢&#xff1f; 嗯&#xff0c;事实上&#xff0c;这就意味着这些人选择了网络赚钱的首选项目&#xff0c;那就是销售各种资料…

UI 自动化测试框架:PO模式+数据驱动

1. PO 设计模式简介 什么是 PO 模式&#xff1f; PO&#xff08;PageObject&#xff09;设计模式将某个页面的所有元素对象定位和对元素对象的操作封装成一个 Page 类&#xff0c;并以页面为单位来写测试用例&#xff0c;实现页面对象和测试用例的分离。 PO 模式的设计思想与…

【C语言基础】函数的参数是指针

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…