一、如何控制单片机?

单片机的内存映射图解析

这里以STM32F429芯片为例,讲解下单片机芯片内存映射图。从此图中可以看到芯片的外设被分配了512M的空间,然而真正的外设其实没有使用到512M的内存空间。然后我们操作外设时,只需要操作它对应的内存地址即可。更加详细的外设内存地址,可以参考芯片的用户手册(不是数据手册)的Memory map章节。

因为单片机是将外设映射到内存地址上,所以我们可以像操作内存一样来操作外设(写/读)。我们在操作内存时是通过地址来进行操作的,由于单片机已经将外设与内存进行了映射,所以我们在操作单片机外设时只需要操作外设映射的内存地址就行。

内存如何操作?

在C语言中操作内存,我们可以用指针来进行操作。在汇编语言中由于没有指针这个概念,所以我们在操作地址时只能用一些内存读写指令来完成。比如:LDR,STR

结构体操作与宏定义操作的对比

C语言——宏定义形式

#define GPIOA (*(volatile uint32_t *)(0x000800E0))
#define GPIOA_DR (*(volatile uint32_t *)(0x000800E4))
#define GPIOA_MR (*(volatile uint32_t *)(0x00080108))
#define GPIOA_TR (*(volatile uint32_t *)(0x00080108))

C语言——结构体操作

struct GPIOA_Reg{volatile uint32_t dr;volatile uint32_t mr;volatile uint32_t tr;
}GPIOA_REG

汇编语言操作内存

LDR r0, =0x00800010
MOV r1, #2
STR r1, [r0]

二、寄存器方式操作单片机

代码结构框架:

文件结构

一个芯片头文件:外设的地址宏定义以及外设相关的结构体定义

查看芯片的用户手册(注意:不是数据手册)中寄存器对应的相应地址。然后使用宏定义来将它们定义好,同时定义好结构体来更加方便的管理外设寄存器组。这里以STM32F1系列为例

一个启动文件:汇编编写的、中断向量表等

用户代码文件:剩余就是用户代码文件了

各个芯片的外设驱动函数编写(读/写、控制)、以及用户逻辑部分代码。

三、使用HAL库方式操作单片机

HAL库与固件库的区别

HAL全称Hardware abstract layer(硬件抽象层),这是一个大家公认并且遵守的一种函数名称命名、资源定义。因为是统一的命名规范,所以当用户更换芯片平台后由于函数命名与所使用的资源都与具体硬件没有关系,这样就不需要修改用户层代码了。而所谓的标准库其实就是芯片厂商公司内部自己命名与实现的库并且各个厂商的命名规则不一样,这样就会导致可移植性变差。当用户更换了芯片平台后由于它们各自的API函数不一样就会导致用户需要修改应用层代码。

HAL库设计

1. HAL框架设计

2. HAL资源命名规则

HAL函数命名规则
  通用型 相同类型的芯片 特定芯片
文件名称 芯片型号_hal_外设(c/h) 芯片型号_hal_外设_ex(c/h) 芯片型号_hal_外设_ex(c/h)
函数名称 HAL_PPP_Function
HAL_PPP_FeatureFunction
_MODE
HAL_PPPEx_Function
HAL_PPPEx_FeatureFunction_
MODE
HAL_PPPEx_Function
HAL_PPPEx_FeatureFunction_
MODE
句柄名称 PPP_HandleTypedef NA NA
初始化结构体名称 PPP_InitTypeDef NA PPP_InitTypeDef
枚举名称 HAL_PPP_StructnameType
Def
  NA

中断与时钟设置宏

中断与特定时钟控制宏
                                                          宏名称                      描述
__HAL_PPP_ENABLE_IT(__HANDLE__, __INTERRUPT__) 使能特定的外设中断
__HAL_PPP_DISABLE_IT(__HANDLE__, __INTERRUPT__) 禁用特定的外设中断
__HAL_PPP_GET_IT (__HANDLE__, __ INTERRUPT __) 获取特定外设中断状态
__HAL_PPP_CLEAR_IT (__HANDLE__, __ INTERRUPT __) 清除特定外设中断状态
__HAL_PPP_GET_FLAG (__HANDLE__, __FLAG__) 获取特定外设标志状态
__HAL_PPP_CLEAR_FLAG (__HANDLE__, __FLAG__) 清除特定外设标志状态
__HAL_PPP_ENABLE(__HANDLE__) 使能外设时钟
__HAL_PPP_DISABLE(__HANDLE__) 禁用外设时钟
__HAL_PPP_XXXX (__HANDLE__, __PARAM__) 特定的PPP HAL驱动宏
__HAL_PPP_GET_ IT_SOURCE (__HANDLE__, __INTERRUPT __) 检查中特定的断源
回调函数命名规则
回调函数 示例
HAL_PPP_MspInit() / _DeInit()

Ex: HAL_USART_MspInit()

在HAL_PPP_Init()函数中调用,此函数执行外设系统级初始化(GPIOs、时钟、DMA、中断)

HAL_PPP_ProcessCpltCallback

Ex: HAL_USART_TxCpltCallback

当处理完成后,被外设或者DAM中断句柄函数(中断服务函数)调用。

HAL_PPP_ErrorCallback

Ex: HAL_USART_ErrorCallback

当有错误发生时,被外设或者DMA中断句柄函数(中断服务函数)调用

3. 文件结构:

一个芯片头文件:外设的地址宏定义以及外设相关的结构体定义

查看芯片的用户手册(注意:不是数据手册)中寄存器对应的相应地址。然后使用宏定义来将它们定义好,同时定义好结构体来更加方便的管理外设寄存器组。这里以STM32F1系列为例

一个启动文件:汇编编写的、中断向量表等。

一个HAL库全局头文件:一些全局的宏定义以及包含其他外设头文件

HAL库文件:芯片外设的驱动函数

四、HAL库组成说明

1. HAL库的数据结构体

  • 外设句柄结构体
  • 初始化和配置结构体
  • 特定的处理结构体(读写/控制)

外设句柄结构体(跟硬件不相关):

比如:下面这个串口结构体

typedef struct
{
USART_TypeDef *Instance; /* USART registers base address */
USART_InitTypeDef Init; /* Usart communication parameters */
uint8_t *pTxBuffPtr;/* Pointer to Usart Tx transfer Buffer */
uint16_t TxXferSize; /* Usart Tx Transfer size */
__IO uint16_t TxXferCount;/* Usart Tx Transfer Counter */
uint8_t *pRxBuffPtr;/* Pointer to Usart Rx transfer Buffer */
uint16_t RxXferSize; /* Usart Rx Transfer size */
__IO uint16_t RxXferCount; /* Usart Rx Transfer Counter */
DMA_HandleTypeDef *hdmatx; /* Usart Tx DMA Handle parameters */
DMA_HandleTypeDef *hdmarx; /* Usart Rx DMA Handle parameters */
HAL_LockTypeDef Lock; /* Locking object */
__IO HAL_USART_StateTypeDef State; /* Usart communication state */
__IO HAL_USART_ErrorTypeDef ErrorCode;/* USART Error code */
}USART_HandleTypeDef;

初始化结构体(跟硬件相关):

比如:下面这个串口硬件相关的结构体

typedef struct
{
uint32_t BaudRate; /*!< This member configures the UART communication baudrate.*/
uint32_t WordLength; /*!< Specifies the number of data bits transmitted or received
in a frame.*/
uint32_t StopBits; /*!< Specifies the number of stop bits transmitted.*/
uint32_t Parity; /*!< Specifies the parity mode. */
uint32_t Mode; /*!< Specifies wether the Receive or Transmit mode is enabled or
disabled.*/
uint32_t HwFlowCtl; /*!< Specifies wether the hardware flow control mode is enabled
or disabled.*/
uint32_t OverSampling; /*!< Specifies wether the Over sampling 8 is enabled or
disabled,
to achieve higher speed (up to fPCLK/8).*/
}UART_InitTypeDef;

特定的处理结构体(跟硬件有关):

比如:下面这个ADC处理处理结构体

typedef struct
{uint32_t Channel;                /*!< Specifies the channel to configure into ADC regular group.This parameter can be a value of @ref ADC_channels */uint32_t Rank;                   /*!< Specifies the rank in the regular group sequencer.This parameter must be a number between Min_Data = 1 and Max_Data = 16 */uint32_t SamplingTime;           /*!< Sampling time value to be set for the selected channel.Unit: ADC clock cyclesConversion time is the addition of sampling time and processing time (12 ADC clock cycles at ADC resolution 12 bits, 11 cycles at 10 bits, 9 cycles at 8 bits, 7 cycles at 6 bits).This parameter can be a value of @ref ADC_sampling_timesCaution: This parameter updates the parameter property of the channel, that can be used into regular and/or injected groups.If this same channel has been previously configured in the other group (regular/injected), it will be updated to last setting.Note: In case of usage of internal measurement channels (VrefInt/Vbat/TempSensor),sampling time constraints must be respected (sampling time can be adjusted in function of ADC clock frequency and sampling time setting)Refer to device datasheet for timings values, parameters TS_vrefint, TS_temp (values rough order: 4us min). */uint32_t Offset;                 /*!< Reserved for future use, can be set to 0 */
}ADC_ChannelConfTypeDef;

2. HAL库公共资源

HAL Status:状态枚举

Typedef enum
{
HAL_OK = 0x00,
HAL_ERROR = 0x01,
HAL_BUSY = 0x02,
HAL_TIMEOUT = 0x03
} HAL_StatusTypeDef;

HAL Locked: 用于防止共享资源被意外访问

typedef enum
{
HAL_UNLOCKED = 0x00, /*!<Resources unlocked */
HAL_LOCKED = 0x01 /*!< Resources locked */
} HAL_LockTypeDef;

公共的宏定义:NULL 和 HAL_MAX_DELAY

#ifndef NULL
#define NULL (void *) 0
#endif
#define HAL_MAX_DELAY 0xFFFFFFFF

3. HAL库中断回调函数实现说明

1. 使用__weak定义好回调函数。如果用户自己重写了回调函数,那么编译器就会使用用户重写的这个回调函数。其中__weak这个关键字是编译器定义的。

2. 使用函数指针。定义一个全局的函数指针变量,在初始化函数时将我们自定义的回调函数赋值给这个全局的函数指针变量(这一步也叫做:注册)。然后再中断函数中通过这个全局的函数指针变量来调用我们自定义的回调函数

STM32外设驱动库分析与实现相关推荐

  1. 这款开源的STM32外设驱动库,可以直接拿来用!

    软件一行,经常需要用到很多重复的代码,我们有必要花一些时间整理一些常用的.通用的代码,等到用到的时候就可以直接拿来用了.如果没有精力自己去整理,也可以用一些网上比较成熟的代码. 比如本次介绍的基于ST ...

  2. 一份很棒的外设驱动库!(基于STM32F4)

    关注.星标公众号,直达精彩内容 来源:https://www.lmlphp.com/user/1774/article/item/19294/ 编辑整理:技术让梦想更伟大 | 李肖遥 本次分享一份基于 ...

  3. 外设驱动库开发笔记13:MLX90614红外温度传感器驱动

    红外温度传感器一般用于非接触式的温度检测.在我们的系统中经常会有这样的需求.所以我们将其设计为通用的驱动库以备复用.这一篇我们将讲述MLX90614红外温度传感器驱动的设计与实现. 1.功能概述 ML ...

  4. STM32的HAL库分析及使用

    STM32的三种开发方式 通常新手在入门STM32的时候,首先都要先选择一种要用的开发方式,不同的开发方式会导致你编程的架构是完全不一样的.一般大多数都会选用标准库和HAL库,而极少部分人会通过直接配 ...

  5. 外设驱动库开发笔记54:外设库驱动设计改进的思考

      不知不觉中我们已经发布了五十多篇外设驱动的文章.前段时间有一位网友提出了一些非常中肯的建议,这也让我们开始考虑怎么优化驱动程序设计的问题.在这一篇中我们将来讨论这一问题. 1.问题分析   首先我 ...

  6. 外设驱动库开发笔记0:EPD总体设计

    在产品开发过程中,不可避免需要使用很多外部的元件及传感器,这些元器件也许是板载的,也许是板外的,但不管怎样,为其开发驱动程序都是必须的.每次都需要为这些元器件编写驱动程序.但每次重复编写调试很麻烦,于 ...

  7. 外设驱动库开发笔记52:PM3003S激光粉尘仪驱动

      空气质量是现代日常生活中人们所关注的事情,也是生存环境好坏的一种体现.其中粉尘数量监测更是空气质量检测中最常见的对象,在我们的检测设备中也经常会有这种需求.检测手段也是多种多样,这一篇中,我们就来 ...

  8. 外设驱动库开发笔记15:DHT11温湿度传感器驱动

    与DS18B20一样DHT11也是采用单总线,但所不同的是DHT11可同时实现温度和湿度的检测.在我们的产品中经常使用它来检测环境的温湿度信息.这一篇我们将设计并封装DHT11的驱动程序,以方便重复使 ...

  9. 外设驱动库开发笔记43:GPIO模拟SPI驱动

      SPI总线是我们常用的串行设备接口,一般情况下我们都会适应硬件SPI接口,但有些时候当硬件端口不足时,我们也希望可以使用软件来模拟SPI硬件接口,特别是要求不是很高的时候.在这一篇中我们将来讨论如 ...

  10. 外设驱动库开发笔记34:OLED显示屏驱动

      现在OLED显示屏在嵌入式系统中应用的越来越多.对于一些显示信息不太复杂,以显示信息为主的需求,我们一般会选择OLED显示屏.在这一篇中,我们将讨论OLED显示屏驱动的设计与实现. 1.功能概述 ...

最新文章

  1. OpenCV读写视频文件解析
  2. 置顶java[常用]-[语法]-[基础操作]
  3. 装X数学:高雅的数学表示
  4. 一文了解贪心算法和回溯算法在前端中的应用
  5. 走迷宫(信息学奥赛一本通-T1252)
  6. 不能使用zsh或myzsh创建/切换 包含#的分支名(zsh: bad pattern: #xxx)
  7. 使用wget命令镜像网站
  8. 分享常见的视频加密算法原理及其优缺点
  9. 计算机组装电源的位置在哪,计算机组装之机箱和ATX电源
  10. 【再聚乌镇】百余家大数据企业齐聚,发布七大榜单两大产业地图,共览大数据产业全景!...
  11. uniapp授权登录微信支付宝小程序获取code和基础信息
  12. Frenetic Python实验(三)
  13. CCS_3.3.83.20的安装步骤
  14. HTML5 自定义视频播放器
  15. 项目经理的专业面试10条经验总结
  16. 别让用户发呆—设计中的防呆策略
  17. TCP连接,三次握手问题
  18. 【75】颜色分类--荷兰国旗问题
  19. 微信公众平台商业模式探索
  20. Uni-app学习过程(1)

热门文章

  1. 解决warning: cast to pointer from integer of different size [-Wint-to-pointer-cast]
  2. 中国人在发表英文论文时汉字姓名究竟应该如何写?
  3. 解决OneNote for Windows 10 不能打开onedrive上已有笔记本问题
  4. 魏俊妮《支持业务发展为核心的HR六大模块体系构建》课程大纲
  5. 八个机器学习非常重要的应用领域,每个领域都影响着我们的生活
  6. python乱码怎么办_python中urllib.unquote乱码的原因与解决方法
  7. c# WPF中通过双击编辑DataGrid中Cell的示例(附源码)
  8. 基于云开发的成语答题小程序
  9. qpython 3h下载_【分享】QPython 3H3.0.0 一个伟大的脚本编辑器!
  10. 传输层协议 ——— UDP协议