c - 如何更改当前代码以直接从 IDR 寄存器读取

标签 c embedded stm32 gpio

修改ReadJoystick()代码,直接读取关联端口的IDR寄存器 通过操纵杆输入。目的是尽量减少寄存器的读取次数。代码在 模板对每个输入引脚进行单独调用,即使某些引脚是 在相同的端口上。 您可以引用 HAL 代码来获取灵感。使用 HAL 中定义的值进行寻址 注册而不是创建新的。

给我的示例代码

GPIO_PinState HAL_GPIO_ReadPin(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin)
{
    GPIO_PinState bitstatus;
     /* Check the parameters */
    assert_param(IS_GPIO_PIN(GPIO_Pin));
if ((GPIOx->IDR & GPIO_Pin) != (uint32_t)GPIO_PIN_RESET)
{
    bitstatus = GPIO_PIN_SET;
}
else
{
    bitstatus = GPIO_PIN_RESET;
}
return bitstatus;

}

<小时/>

我需要更改的代码

//将以下代码替换为您的解决方案

uint8_t
ReadJoystick ()
{
  uint8_t JoystickPosition = 0;

  // Get current joystick value
  if (HAL_GPIO_ReadPin (JOY_A_GPIO_Port, JOY_A_Pin) == GPIO_PIN_RESET)
  {
    JoystickPosition = 'L';
  }
  else if (HAL_GPIO_ReadPin (JOY_B_GPIO_Port, JOY_B_Pin) == 
GPIO_PIN_RESET)
  {
JoystickPosition = 'U';
  }
  else if (HAL_GPIO_ReadPin (JOY_C_GPIO_Port, JOY_C_Pin) == 
 GPIO_PIN_RESET)
   {
     JoystickPosition = 'D';
   }
   else if (HAL_GPIO_ReadPin (JOY_D_GPIO_Port, JOY_D_Pin) == 
 GPIO_PIN_RESET)
    {
      JoystickPosition = 'R';
    }
   else if (HAL_GPIO_ReadPin (JOY_CTR_GPIO_Port, JOY_CTR_Pin) == 
GPIO_PIN_RESET)
  {
    JoystickPosition = 'C';
  }

  return JoystickPosition;
 }

所以我知道我当前的代码正在读取每个引脚,尽管我被要求更改它以直接从 IDR 寄存器读取。我对嵌入式系统编程非常陌生,只是想找人指导我更改此代码

最佳答案

在发布我的解决方案之前,我需要建议不要直接从寄存器读取。给你这个任务的人都想成为一个自作聪明的人,并认为调用 HAL_GPIO_ReadPin 函数会导致某种难以忍受的开销,这绝对不是真的。事实上,如果从 JOY_A_GPIO_Port 到 JOY_CTR_GPIO_Port 的所有端口定义都不同并且打开了优化,那么编译器很可能会生成最佳代码。此外,用直接寄存器读取替换函数调用会降低应用程序代码的重用能力。

无论如何,让我们应用一些更改...

让我们从使用直接寄存器访问的 1:1 转换开始:

uint8_t ReadJoystick() 
{
  uint8_t JoystickPosition = 0u;

  // Get current joystick value
  if ((JOY_A_GPIO_Port->IDR & JOY_A_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'L';
  else if ((JOY_B_GPIO_Port->IDR & JOY_B_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'U';
  else if ((JOY_C_GPIO_Port->IDR & JOY_C_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'D';
  else if ((JOY_D_GPIO_Port->IDR & JOY_D_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'R';
  else if ((JOY_CTR_GPIO_Port->IDR & JOY_CTR_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'C';

  return JoystickPosition;
}

如果您还没有完全理解代码:

  • xxx_Port->IDR读取整个端口的输入数据寄存器
  • 按位 & 屏蔽输入并仅给出我们所在的特定引脚 寻找

正如我之前提到的,这不会带来任何性能改进。

但是,如果某些端口定义相同并指向相同的内存地址,我们可能会稍微改进代码。在实践中,这种情况很常见,因为嵌入式设计人员通常热衷于将外部设备的 IO 引脚连接到单个端口上。例如。假设 JOY_A_GPIO_Port == JOY_B_GPIO_Port,那么我们可以将该端口的输入数据寄存器读取一次到局部变量中,如下所示:

uint8_t ReadJoystick() 
{
  uint8_t JoystickPosition = 0;

  // Read input data register for AB once
  uint32_t ab_port = JOY_AB_GPIO_Port->IDR;

  // Get current joystick value
  if ((ab_port & JOY_A_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'L';
  else if ((ab_port & JOY_B_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'U';
  else if ((JOY_C_GPIO_Port->IDR & JOY_C_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'D';
  else if ((JOY_D_GPIO_Port->IDR & JOY_D_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'R';
  else if ((JOY_CTR_GPIO_Port->IDR & JOY_CTR_Pin) == GPIO_PIN_RESET)
    JoystickPosition = 'C';

  return JoystickPosition;
}

这有效地为我们节省了一次寄存器读取。当然,单个端口上的操纵杆引脚越多越好。

/编辑 ST 提供了一个替代函数来读取其“LL”库中的整个端口:

__STATIC_INLINE uint32_t LL_GPIO_ReadInputPort(GPIO_TypeDef *GPIOx)
{
  return (uint32_t)(READ_REG(GPIOx->IDR));
}

关于c - 如何更改当前代码以直接从 IDR 寄存器读取,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56351072/

相关文章:

c - 键盘中断处理程序给出空值

ide - Sublime Text 作为 IAR EWB 的外部编辑器

c - 在嵌入式系统中,周界锁定主要是什么?

c - 用 printf() 进行二进制打印可以这样吗?

gcc - STM32H743 微 Controller (Cortex-M7) 的此链接描述文件中是否使用了所有 RAM 部分?

c - 将 20 位输入压缩为 5 位输出的哈希函数

c - 这个熟悉的函数在 C 中是如何实现的呢?

cortex-m3 - 有人知道任何非常基本的 stm32 教程吗?

c - 访问未对齐的结构成员

c - FreeRTOS:osDelay 与 HAL_delay