硬汉嵌入式论坛

 找回密码
 立即注册
查看: 5933|回复: 6
收起左侧

[UART] STM32H7的串口初始化函数HAL_UART_Init一个略坑的地方

[复制链接]

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
发表于 2018-11-14 01:19:20 | 显示全部楼层 |阅读模式
如果形参huart的结构体成员gState没有做初始状态,这个地方就是个大坑。特别是用户搞了一个局部变量UART_HandleTypeDef UartHandle

对于局部变量来说,这个参数就是一个随机值,如果是全局变量还好,一般MDK和IAR都会将全部变量初始化为0,而恰好这个 HAL_UART_STATE_RESET  = 0x00U

QQ截图20181114005949.png

解决办法有三
方法1:用户自己初始串口和涉及到的GPIO等。
方法2:定义UART_HandleTypeDef UartHandle为全局变量。
方法3;下面的方法
if(HAL_UART_DeInit(&UartHandle) != HAL_OK)
{
    Error_Handler();
}  
if(HAL_UART_Init(&UartHandle) != HAL_OK)
{
    Error_Handler();
}



回复

使用道具 举报

36

主题

2040

回帖

2148

积分

至尊会员

积分
2148
发表于 2018-11-14 10:28:51 | 显示全部楼层
Ever tried. Ever failed. No matter. Try Again. Fail again. Fail better.
回复

使用道具 举报

7

主题

102

回帖

123

积分

初级会员

积分
123
发表于 2018-11-14 10:49:45 | 显示全部楼层
不算坑,作为驱动这种写法没有问题。是输入参数的问题。既然gState都能随机,其他参数也是随机,就算gState通过了一样有可能有其他问题。编程人员必须自己能保证自己的输入参数正确才行。不然什么错误都可能,像上图,huart是malloc出来的话一样会出问题。甚至会assert。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
 楼主| 发表于 2018-11-14 11:02:51 | 显示全部楼层
eddy0317 发表于 2018-11-14 10:49
不算坑,作为驱动这种写法没有问题。是输入参数的问题。既然gState都能随机,其他参数也是随机,就算gState ...

你的理解欠妥。单单一个将此结构体变量做局部变量,不看函数源码,大家谁会注意到。

另外你说的malloc,基本在申请后,都会做null判断的。
回复

使用道具 举报

7

主题

102

回帖

123

积分

初级会员

积分
123
发表于 2018-11-14 14:29:41 | 显示全部楼层
null判断只是是否成功申请,非null不代表结构体占用的空间被初始化。往往跟局部变量一样,是随机数。

我的意思是,入口参数的结构体。在第一次使用时,都应该注意对其进行初始化。我说的不是单单这个函数,而是一种编程习惯。不管局部变量还是malloc出来的变量,不先初始化就用。很容易有问题,这个习惯不能养成。
回复

使用道具 举报

1万

主题

6万

回帖

10万

积分

管理员

Rank: 9Rank: 9Rank: 9

积分
106913
QQ
 楼主| 发表于 2018-11-14 14:31:59 | 显示全部楼层
eddy0317 发表于 2018-11-14 14:29
null判断只是是否成功申请,非null不代表结构体占用的空间被初始化。往往跟局部变量一样,是随机数。

我 ...

果然是理解有误,这个参数不是用户来初始化管理的,是HAL内部几个函数管理的。
回复

使用道具 举报

7

主题

102

回帖

123

积分

初级会员

积分
123
发表于 2018-11-14 17:27:52 | 显示全部楼层
好吧,就当我理解有误。UART_HandleTypeDef里面,部分变量的确不允许用户干预(如gState,RxState,ErrorCode等),都是各个函数管理的。但是其他一大堆(Init结构体,Instance等)还是要用户填的,这就意味着用户需要了解它的各个变量的定义及初值。其实,hal这种写法不对,既然部分变量不允许用户干预,就最好有一个函数来初始化这部分变量。

类似这种东西,我从来都是这样写:
xxx_init(xxx_type_t *ptr,xxx_init_type_t *init); //ptr内部变量不允许用户修改,这是使用这个指针前调用(而仅调用一次)
xxx_open(xxx_type_t *ptr); // 这个函数才等于hal的init

这样的结构体次才完全不需要用户去了解,也不用看函数源码。正因为hal的各种不完善的逻辑(至少我是这样认为),我才一直都很讨厌它。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2024-5-10 07:14 , Processed in 0.248370 second(s), 28 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表