STM32外设驱动库分析与实现!
来源:嵌入式大杂烩发布时间:2023-03-01407浏览
询问 AI
来源:https://blog.csdn.net/twx11213030422
一、如何控制单片机?
单片机的内存映射图解析
这里以STM32F429芯片为例,讲解下单片机芯片内存映射图。从此图中可以看到芯片的外设被分配了512M的空间,然而真正的外设其实没有使用到512M的内存空间。
然后我们操作外设时,只需要操作它对应的内存地址即可。更加详细的外设内存地址,可以参考芯片的用户手册(不是数据手册)的Memory map章节。

因为单片机是将外设映射到内存地址上,所以我们可以像操作内存一样来操作外设(写/读)。
我们在操作内存时是通过地址来进行操作的,由于单片机已经将外设与内存进行了映射,所以我们在操作单片机外设时只需要操作外设映射的内存地址就行。
内存如何操作?
在C语言中操作内存,我们可以用指针来进行操作。在汇编语言中由于没有指针这个概念,所以我们在操作地址时只能用一些内存读写指令来完成。比如:LDR,STR
结构体操作与宏定义操作的对比
C语言——宏定义形式
#defineGPIOA(*(volatileuint32_t*)(0x000800E0))
#defineGPIOA_DR(*(volatileuint32_t*)(0x000800E4))
#defineGPIOA_MR(*(volatileuint32_t*)(0x00080108))
#defineGPIOA_TR(*(volatileuint32_t*)(0x00080108))C语言——结构体操作
structGPIOA_Reg{
volatileuint32_tdr;
volatileuint32_tmr;
volatileuint32_ttr;
}GPIOA_REG汇编语言操作内存
LDRr0,=0x00800010
MOVr1,#2
STRr1,[r0]二、寄存器方式操作单片机
代码结构框架:

文件结构
一个芯片头文件:外设的地址宏定义以及外设相关的结构体定义
查看芯片的用户手册(注意:不是数据手册)中寄存器对应的相应地址。然后使用宏定义来将它们定义好,同时定义好结构体来更加方便的管理外设寄存器组。这里以STM32F1系列为例
•一个启动文件:汇编编写的、中断向量表等
•用户代码文件:剩余就是用户代码文件了
•各个芯片的外设驱动函数编写(读/写、控制)、以及用户逻辑部分代码。
三、使用HAL库方式操作单片机
HAL库与固件库的区别
HAL全称Hardware abstract layer(硬件抽象层),这是一个大家公认并且遵守的一种函数名称命名、资源定义。因为是统一的命名规范,所以当用户更换芯片平台后由于函数命名与所使用的资源都与具体硬件没有关系,这样就不需要修改用户层代码了。
而所谓的标准库其实就是芯片厂商公司内部自己命名与实现的库并且各个厂商的命名规则不一样,这样就会导致可移植性变差。当用户更换了芯片平台后由于它们各自的API函数不一样就会导致用户需要修改应用层代码。
HAL库设计
1. HAL框架设计

2. HAL资源命名规则
HAL函数命名规则:

中断与时钟设置宏:

回调函数命名规则:

3. 文件结构:
一个芯片头文件:外设的地址宏定义以及外设相关的结构体定义
查看芯片的用户手册(注意:不是数据手册)中寄存器对应的相应地址。然后使用宏定义来将它们定义好,同时定义好结构体来更加方便的管理外设寄存器组。这里以STM32F1系列为例
一个启动文件:汇编编写的、中断向量表等。
一个HAL库全局头文件:一些全局的宏定义以及包含其他外设头文件
HAL库文件:芯片外设的驱动函数
四、HAL库组成说明

1. HAL库的数据结构体
•外设句柄结构体
•初始化和配置结构体
•特定的处理结构体(读写/控制)
** 外设句柄结构体(跟硬件不相关):**
比如:下面这个串口结构体
typedefstruct
{
USART_TypeDef*Instance;/*USARTregistersbaseaddress*/
USART_InitTypeDefInit;/*Usartcommunicationparameters*/
uint8_t*pTxBuffPtr;/*PointertoUsartTxtransferBuffer*/
uint16_tTxXferSize;/*UsartTxTransfersize*/
__IOuint16_tTxXferCount;/*UsartTxTransferCounter*/
uint8_t*pRxBuffPtr;/*PointertoUsartRxtransferBuffer*/
uint16_tRxXferSize;/*UsartRxTransfersize*/
__IOuint16_tRxXferCount;/*UsartRxTransferCounter*/
DMA_HandleTypeDef*hdmatx;/*UsartTxDMAHandleparameters*/
DMA_HandleTypeDef*hdmarx;/*UsartRxDMAHandleparameters*/
HAL_LockTypeDefLock;/*Lockingobject*/
__IOHAL_USART_StateTypeDefState;/*Usartcommunicationstate*/
__IOHAL_USART_ErrorTypeDefErrorCode;/*USARTErrorcode*/
}USART_HandleTypeDef;初始化结构体(跟硬件相关):
比如:下面这个串口硬件相关的结构体
typedefstruct
{
uint32_tBaudRate;/*!<ThismemberconfigurestheUARTcommunicationbaudrate.*/
uint32_tWordLength;/*!<Specifiesthenumberofdatabitstransmittedorreceived
inaframe.*/
uint32_tStopBits;/*!<Specifiesthenumberofstopbitstransmitted.*/
uint32_tParity;/*!<Specifiestheparitymode.*/
uint32_tMode;/*!<SpecifieswethertheReceiveorTransmitmodeisenabledor
disabled.*/
uint32_tHwFlowCtl;/*!<Specifieswetherthehardwareflowcontrolmodeisenabled
ordisabled.*/
uint32_tOverSampling;/*!<SpecifieswethertheOversampling8isenabledor
disabled,
toachievehigherspeed(uptofPCLK/8).*/
}UART_InitTypeDef;特定的处理结构体(跟硬件有关):
比如:下面这个ADC处理处理结构体
typedefstruct
{
uint32_tChannel;/*!<SpecifiesthechanneltoconfigureintoADCregulargroup.
Thisparametercanbeavalueof@refADC_channels*/
uint32_tRank;/*!<Specifiestherankintheregulargroupsequencer.
ThisparametermustbeanumberbetweenMin_Data=1andMax_Data=16*/
uint32_tSamplingTime;/*!<Samplingtimevaluetobesetfortheselectedchannel.
Unit:ADCclockcycles
Conversiontimeistheadditionofsamplingtimeandprocessingtime(12ADCclockcyclesatADCresolution12bits,11cyclesat10bits,9cyclesat8bits,7cyclesat6bits).
Thisparametercanbeavalueof@refADC_sampling_times
Caution:Thisparameterupdatestheparameterpropertyofthechannel,thatcanbeusedintoregularand/orinjectedgroups.
Ifthissamechannelhasbeenpreviouslyconfiguredintheothergroup(regular/injected),itwillbeupdatedtolastsetting.
Note:Incaseofusageofinternalmeasurementchannels(VrefInt/Vbat/TempSensor),
samplingtimeconstraintsmustberespected(samplingtimecanbeadjustedinfunctionofADCclockfrequencyandsamplingtimesetting)
Refertodevicedatasheetfortimingsvalues,parametersTS_vrefint,TS_temp(valuesroughorder:4usmin).*/
uint32_tOffset;/*!<Reservedforfutureuse,canbesetto0*/
}ADC_ChannelConfTypeDef;2. HAL库公共资源
HAL Status:状态枚举
Typedefenum
{
HAL_OK=0x00,
HAL_ERROR=0x01,
HAL_BUSY=0x02,
HAL_TIMEOUT=0x03
}HAL_StatusTypeDef;HAL Locked:用于防止共享资源被意外访问
typedefenum
{
HAL_UNLOCKED=0x00,/*!<Resourcesunlocked*/
HAL_LOCKED=0x01/*!<Resourceslocked*/
}HAL_LockTypeDef;公共的宏定义:NULL 和 HAL_MAX_DELAY
#ifndefNULL
#defineNULL(void*)0
#endif
#defineHAL_MAX_DELAY0xFFFFFFFF3. HAL库中断回调函数实现说明
(1)使用 __ weak 定义好回调函数。如果用户自己重写了回调函数,那么编译器就会使用用户重写的这个回调函数。其中__ weak这个关键字是编译器定义的。
(2)使用函数指针。定义一个全局的函数指针变量,在初始化函数时将我们自定义的回调函数赋值给这个全局的函数指针变量(这一步也叫做:注册)。然后再中断函数中通过这个全局的函数指针变量来调用我们自定义的回调函数。
本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
在公众号聊天界面回复1024,可获取嵌入式资源;回复m,可查看文章汇总
新闻来源:嵌入式大杂烩,文中所述为作者独立观点,不代表icspec立场。更多精彩资讯请下载icspec App。如对本稿件有异议,请联系微信客服specltkj。

