【STM32】标准库的引入
一、为什么要会有标志外设库
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
相关文章:

【STM32】标准库的引入
一、为什么要会有标志外设库 1、传统单片机软件开发方式 (1)芯片厂商提供数据手册、示例代码、开发环境 (2)单片机软件工程师面向产品功能,查阅数据手册,参考官方示例代码进行开发 (3)硬件操作的方式是用C语言对寄存器进行读写以操作硬件 (4)主要工作量…...
Redis的淘汰策略
Redis是一种基于内存的高性能键值存储数据库,由于内存资源有限,当Redis中的数据量增大时,会导致内存占用过多,可能会影响系统的性能和稳定性。为了解决这个问题,Redis提供了一些淘汰策略来自动清理不再使用的key&#…...

Linux友人帐之日志与备份
一、日志 1.1概述 日志文件是重要的系统信息文件,其中记录了许多重要的系统事件,包括用户的登录信息、系统的启动信息、系统的安全信息、邮件相关信息、各种服务相关信息等。日志对于安全来说也很重要,它记录了系统每天发生的各种事情&#…...
git中如何在父仓库提交子仓库的修改
子仓库在父仓库中进行了修改,你需要按照以下步骤提交子仓库的修改: 切换到子仓库目录:使用cd命令进入子仓库所在的目录。拉取子仓库的最新更改:使用git pull命令拉取子仓库的最新更改,确保你的本地是最新的版本。提交…...
【【萌新的SOC学习之SD卡DMA回路读写大数据的实验】】
萌新的SOC学习之SD卡读写大数据的实验 记得先设定 FIFO 的位宽和深度 还有DMA 的大小 其他基本结构设计参照上一个SD卡读写小数据的实验 #include "xparameters.h" //包含vivado所导出的信息包含vivado的基地址 #include "xil_printf.h" //调用打印函…...
在k8s中 ,数据包是怎么从外部流转进入到pod的?
在 Kubernetes 中,当您创建 NodePort 类型的服务时,流量不会直接从主机的 IP 和端口转发到特定 Pod 的 IP 和端口。相反,流量被转发到集群中的一个节点,然后从那里转发到相应的 Pod。 1、当您创建 NodePort 类型的服务时…...

微信小程序设置 wx.showModal 提示框中 确定和取消按钮的颜色
wx官方提供的 showModal 无疑是个非常优秀的选择提示工具 但是 我们还可以让他的颜色更贴近整体的小程序风格 cancelColor 可以改变取消按钮的颜色 confirmColor 则可以控制确定按钮的颜色 参考代码如下 wx.showModal({cancelColor: #0000FF,confirmColor: #45B250,content:…...

【Chrome】使用k8s、docker部署无头浏览器Headless,Java调用示例
什么是无头浏览器? 无头浏览器是一种没有图形用户界面的浏览器。无头浏览器不通过其图形用户界面(GUI)控制浏览器的操作,而是使用命令行。 为什么要用Chrome无头? Chrome Headless用于抓取(谷歌)、测试(开发者)和黑客(黑客)。搜索引擎&…...
springmvc http请求,支持get,post,附件传输和参数传输
主要解决http请求支持get,post,put,delete等常规方法,支持RequestParam,RequestBody,PathVariable等参数格式传输,支持传输附件同时传递参数等,主体代码如下: package mes.client.action;import cn.hutool.crypto.digest.DigestUt…...

linux性能分析(七)CPU性能篇(二)怎么理解平均负载
一 怎么理解平均负载 ① 如何查看平均复杂 查看系统负载的命令: top、uptime、w、cat /proc/loadavg、tload /proc/loadavg 思考: uptime每列输出的含义?重点: 当前时间、系统运行时间、正在登录用户数、平均负载 ② 思考࿱…...

PostgreSQL12中浮点数输出算法优化带来的小问题
最近碰到同事发来这样两个SQL,开发反馈输出的结果异常。 bill# select 0.1284*100::float;?column? --------------------12.839999999999998 (1 row)bill# select (0.1284*100)::float;float8 --------12.84 (1 row) 乍一看其实能看出明显的区别,由于…...

Hive安装配置笔记
版本说明 hadoop-3.3.6(已安装) mysql-8(已安装) hive-3.1.3 将hive解压到对应目录后做如下配置: 基本配置与操作 1、hive-site <configuration><!-- jdbc连接的URL --><property><name>ja…...

前端数据可视化之【Echarts下载使用】
目录 🌟下载🌟浏览器引入🌟模块化引入 🌟使用🌟基本使用步骤 🌟绘制一个简单的图表🌟写在最后 🌟下载 🌟浏览器引入 官网下载界面:官方网站 或 Echarts中文…...
本机计算机上的mysql启动后停止
本机计算机上的mysql启动后停止 原因:mysql5.0和mysql8.0配置不同 把my.ini改成以下设置然后再重新 mysqld --initialize-insecure --usermysql然后再启动 net start mysqlmysql8.0 下面的路劲可自定义 [client] default-character-setutf8 [mysql] default-cha…...
Java中ReentrantLock测试线程的安全
使用场景 当需要在多线程环境下保证共享资源的安全访问时,可以使用Java中的ReentrantLock来实现线程安全。ReentrantLock是一个可重入的互斥锁,它提供了与synchronized关键字类似的功能,但更加灵活和扩展性强。 下面是一个使用ReentrantLoc…...
Vue-dvadmin-d2-crud-plus-常用配置-row-handle-columns-options
文章目录 1.row-handle columnHeader width minWidth fixed align renderHeader edit view remove remove.confirm remove.confirmTitle remove.confirmText custom 范例1 范例2 2.columns title key width minWidth fixed renderHeader sortable sortMethod sortBy sortOrders…...

【OpenCV实现图像的算数运算,性能测试和优化,改变颜色空间】
文章目录 OpenCV功能概要图像的算数运算性能测试和优化改变颜色空间对象追踪 OpenCV功能概要 OpenCV(Open Source Computer Vision Library)是一个开源的计算机视觉和机器学习库,提供了丰富的图像处理和计算机视觉算法。它支持多种编程语言&…...

多级缓存入门
文章目录 什么是多级缓存JVM进程缓存环境准备安装MySQL导入Demo工程导入商品查询页面 初识Caffeine Lua语法初识Lua第一个lua程序变量和循环Lua的数据类型声明变量循环 条件控制、函数函数条件控制 多级缓存安装OpenRestyOpenResty快速入门反向代理流程OpenResty监听请求编写it…...
CentOS卸载LVM磁盘的方法
在客户环境上遇到一个问题,本身的磁盘满了,需要把没有用的lvm逻辑卷卸载掉,然后挂上去,下面记录一下过程。 卸载原磁盘 umount /data # 如果/data目录正在被其他进程使用中,则使用fuser强制关闭,然后Umou…...
ChatGPT:Spring Boot和Maven——Java应用开发的关键工具和区别
ChatGPT:Spring Boot和Maven——Java应用开发的关键工具和区别 Springboot是什么? ChatGPT: Spring Boot是一个用于构建Java应用程序的开源框架,它是Spring Framework的一部分,但旨在简化Spring应用程序的开发。Sprin…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查
在对接支付宝API的时候,遇到了一些问题,记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...

黑马Mybatis
Mybatis 表现层:页面展示 业务层:逻辑处理 持久层:持久数据化保存 在这里插入图片描述 Mybatis快速入门  B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...

【力扣数据库知识手册笔记】索引
索引 索引的优缺点 优点1. 通过创建唯一性索引,可以保证数据库表中每一行数据的唯一性。2. 可以加快数据的检索速度(创建索引的主要原因)。3. 可以加速表和表之间的连接,实现数据的参考完整性。4. 可以在查询过程中,…...

【入坑系列】TiDB 强制索引在不同库下不生效问题
文章目录 背景SQL 优化情况线上SQL运行情况分析怀疑1:执行计划绑定问题?尝试:SHOW WARNINGS 查看警告探索 TiDB 的 USE_INDEX 写法Hint 不生效问题排查解决参考背景 项目中使用 TiDB 数据库,并对 SQL 进行优化了,添加了强制索引。 UAT 环境已经生效,但 PROD 环境强制索…...

【CSS position 属性】static、relative、fixed、absolute 、sticky详细介绍,多层嵌套定位示例
文章目录 ★ position 的五种类型及基本用法 ★ 一、position 属性概述 二、position 的五种类型详解(初学者版) 1. static(默认值) 2. relative(相对定位) 3. absolute(绝对定位) 4. fixed(固定定位) 5. sticky(粘性定位) 三、定位元素的层级关系(z-i…...

Redis数据倾斜问题解决
Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中,部分节点存储的数据量或访问量远高于其他节点,导致这些节点负载过高,影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...