摘要:
本文将基于串口通信的例程,分析基于标准库函数与基于HAL库函数的stm32编程方式的差异
一、简谈标准库函数和HAL库函数的区别
通过对正点原子的产品手册
的学习渐渐对这两个库有了更加清晰地认识,下面就谈谈两者的差别
🔥 标准库
这个就是ST以前推出的,哈哈,是不是有种感觉是随着时间推移,这个库函数会退出历史舞台?它的优势在于针对解决了寄存器版本的劣势,方便我们的使用。但是!它的劣势,也就是HAL的优势了!每次修改MCU功能,都要手动修改,自己修改也不能。在不同的MCU间移植性就不是很好了
🔥 HAL库
HAL库,HAL是Hardware Abstraction Layer的缩写,中文名称是:硬件抽象层,HAL库工程一般使用Cube软件来生成工程。HAL库是ST公司为STM32的MCU最新推出的抽象层嵌入式软件,更方便的实现跨STM32产品的最大可移植性。优势就是不需要开发工程师再关注所用MCU型号,只需要专注所以要的功能软件开发工作。而且是未来主推的方向,正在不断的推出更新。
所以 ,我们还是应该与时俱进,多多掌握HAL库
二、具体例子说明差异(串口通信)
下面代码均参考正点原子的代码
标准库
int main(void)
{
u16 t;
u16 len;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n\r\n");
for(t=0;t<len;t++)
{
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\r\n精英STM32开发板 串口实验\r\n");
printf("正点原子@ALIENTEK\r\n\r\n");
}
if(times%200==0)printf("请输入数据,以回车键结束\r\n");
if(times%30==0){LED0=!LED0; LED1=!LED1;}//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
HAL
int main(void)
{
u8 len;
u16 times=0;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(RCC_PLL_MUL9); //设置时钟,72M
delay_init(72); //初始化延时函数
uart_init(115200); //初始化串口
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
while(1)
{
if(USART_RX_STA&0x8000)
{
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("\r\n您发送的消息为:\r\n");
HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000); //发送接收到的数据
while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET); //等待发送结束
printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\r\nALIENTEK 精英STM32开发板 串口实验\r\n");
printf("正点原子@ALIENTEK\r\n\r\n\r\n");
}
if(times%200==0)printf("请输入数据,以回车键结束\r\n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
是不是乍一看主函数并没有什么不同
但是对比初始化函数
还是有很大不一样的,左图HAL,右图标准库
体现在非常重要的一点:
函数句柄
- 在STM32的标准库中,假设我们要初始化一个外设(这里以 USART为例)我们首先要初始化他们的各个寄存器。在标准库中,这些操作都是利用固件库结构体变量+固件库lnit函数实现的;可以看到,要初始化一个串口,需要对六个位置进行赋值,然后引用Init函数,并且 USART Initstructure并不是一个全局结构体变量,而是只在函数内部的局部变量。
USART_InitTypeDef USART_InitStructure;
函数内定义 - 而在HAL库中,同样是 USARTA初始化结构体变量,我们要定义为全局变量。
UART_HandleTypeDef UART1_Handler;
函数外定义。看其结构体定义,与标准库不同的是,该成员不仅包含了之前标准库就有的六个成员(波特率,数据、格式等),还包含过采样、(发送或接收的)数据存、数据指针、串口DMA相关的变量、各种标志位等等要在整个项目流程中都要设置的各个成员。回调函数只需要用函数句柄就好
三、总结
正如上面所谈到的,标准库函数的优点就是寄存器的缺点,而标准库函数的缺点就是HAL库的优点。这一块相比大家仔细看看代码也能发现这个道理。更好的移植性是HAL的特点而凭借这个特点在未来,HAL库将会越走越远。
参考
[1]https://blog.csdn.net/weixin_34417183/article/details/91683056?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1.control
[2]http://www.360doc.com/content/19/1225/17/38894361_882147885.shtml