记得有两三次有工程师反映 STM8S库函数GPIO_ReadInputDataBit()不好用,主要体现在对返回值做 ‘SET’检测时会出错。
先看看这个函数原型:

BitStatus GPIO_ReadInputPin(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
    return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
}

该函数用来读取某一个GPIO脚的电平,本意是希望被读取的IO口为低电平时就返回RESET,
高电平返回SET。再看看SET\RESET的定义:

typedef enum {RESET = 0, SET = !RESET}  BitStatus,;

显然,通过枚举定义了SET/RESET,具体落实到这个定义,枚举变量的值就只有0和1。

函数GPIO_ReadInputDataBit()的返回值是将(GPIOx->IDR & (uint8_t)GPIO_Pin)的结果进行
强转为BitStatus变量,既然这样,按理说只能是0或1.实际上呢函数结果除0和1外,还有可能是2,4,8,
0x10,0x20,0x40,0x80(这些值都是对应某个高电平脚位)。

当(GPIOx->IDR & (uint8_t)GPIO_Pin)的结果是0或1以外的值时【可能是0x02,0x04,0x08,0x10,
0x20,0x40,0x80】,强转无效,那些值没法在枚举定义的元素值里找到对应的数据,因为函数的结果表
达式的值超出了枚举范围。 如果此时查验是否等于SET就可能会出错,因为的确可能很多脚位
虽出现高电平而函数返回结果不等于1(比如是0x04)被误判该脚是”0”! ,即低电平。假如这样写判断代码:

If (GPIO_ReadInputDataBit==SET)
{// do something while pinx==1;}   // ‘1’ branch
Else 
{// do something while pinx==0;}   //  ‘0’ branch

当测试除PORTx 0口以外的高电平脚时就一定会出错,因为他们虽然高电平,但读出的结果比1大,
而又不等于‘1’。按上面代码判断就会就判为进‘0’的分支。

如果你换个写法,上面问题就可以避免,这样写:

If (GPIO_ReadInputDataBit==RESET)
{// do something while pinx==0;}    //  ‘0’ branch
Else 
{// do something while pinx==1;}   // ‘1’ branch

很明显,(GPIOx->IDR & (uint8_t)GPIO_Pin)的结果经过强转后,[即使部分没法在枚举元素中找到对应
的值],最后结果要么0,要么非 0,非0对应的就是管脚电平为高的情况。那按上面写法,是‘0’就低电平
分支,非‘0’就进高电平分支,不会发生混乱。

那么为了解决这个问题,除了只用RESET检测可以回避外,也可以将stm8 库函数代码修改下.比如将
函数GPIO_ReadInputDataBit()修改为:

BitStatus GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin)
{
  //return ((BitStatus)(GPIOx->IDR & (uint8_t)GPIO_Pin));
  if( (GPIOx->IDR & (uint8_t)GPIO_Pin) == 0)
    return RESET;
  else 
    return SET;
}

总体来看,该库函数应该说有些不严谨,问题主要出在强转那个地方,被强转的变量无法在相关枚举元素表
里找到对应数据。但从该函数的功能讲,完全够用、够解决问题了,无非判断一个脚的高低电位。使用者可
以自行变通处理。

Last modification:November 5, 2023
If you think my article is useful to you, please feel free to appreciate