【问题标题】:#define statement for address of memory#define 内存地址语句
【发布时间】:2020-01-08 14:37:01
【问题描述】:

这个#define 语句有什么作用?它用于定义内存地址。但我不明白 (uint32_t *) 部分

#define GPxDAT (uint32_t *) 0x6FC0 

【问题讨论】:

  • 鉴于缺乏上下文,所有可以说的就是它用(uint32_t *) 0x6FC0替换代码中每次出现的GPxDAT
  • (uint32_t *) 强制 0x6FC0 成为 uint32_t 的地址。
  • (uint32_t *) 将该十六进制数转换为指向uint32_t的指针
  • 可能在嵌入式系统中,GPxDAT 旨在用作*GPxDAT = some_value;,将some_value 写入内存位置0x6FC0,或content = *GPxDAT,从内存中读取值位置0x6FC0,将该值解释为uint32_t 类型。在任何情况下,最好将宏定义中的表达式完全括起来,例如:#define GPxDAT ((uint32_t *) 0x6FC0)

标签: c pointers signal-processing


【解决方案1】:

通常用于访问映射到地址空间的硬件寄存器,或者一些特定的内存地址

硬件寄存器应定义为volatile,因为寄存器可以在没有任何程序活动的情况下更改(因为它们是由硬件更改的)。

#define GPIOREGA ((volatile uint32_t *) 0x6FC0) 

然后你可以分配或读取这个内存位置(*GPIOREGA = something; something = *GPIOREGA

有时以这种方式使用更复杂的数据结构(来自 STM32 标头的示例)

#define __IO volatile

typedef struct
{
  __IO uint32_t MODER;    /*!< GPIO port mode register,               Address offset: 0x00      */
  __IO uint32_t OTYPER;   /*!< GPIO port output type register,        Address offset: 0x04      */
  __IO uint32_t OSPEEDR;  /*!< GPIO port output speed register,       Address offset: 0x08      */
  __IO uint32_t PUPDR;    /*!< GPIO port pull-up/pull-down register,  Address offset: 0x0C      */
  __IO uint32_t IDR;      /*!< GPIO port input data register,         Address offset: 0x10      */
  __IO uint32_t ODR;      /*!< GPIO port output data register,        Address offset: 0x14      */
  __IO uint32_t BSRR;     /*!< GPIO port bit set/reset register,      Address offset: 0x18      */
  __IO uint32_t LCKR;     /*!< GPIO port configuration lock register, Address offset: 0x1C      */
  __IO uint32_t AFR[2];   /*!< GPIO alternate function registers,     Address offset: 0x20-0x24 */
} GPIO_TypeDef;

#define PERIPH_BASE           0x40000000U /*!< Peripheral base address in the alias region                                */

#define AHB1PERIPH_BASE       (PERIPH_BASE + 0x00020000U)
#define GPIOA_BASE            (AHB1PERIPH_BASE + 0x0000U)

#define GPIOA               ((GPIO_TypeDef *) GPIOA_BASE)

你可以像任何普通指针一样使用它

GPIOA -> MODER |= (1 << 15);

【讨论】:

  • 很好的答案,但我认为你可以用一两个词来澄清关于没有任何程序活动的寄存器更改的一点 - 它可能会让初学者感到困惑(“怎么会发生这种情况?”),即此答案的目标人群。
【解决方案2】:

(uint32_t *) 部分是所谓的cast,它将整数0x6FC0转换为指针(地址)到unsigned整数, 32 位宽(这是uint32_t 类型所代表的内容。)基本上是类型转换为指向无符号整数的指针。在我看来,这种表达方式并不完全安全。虽然强制转换运算符具有高优先级,但它应该写成:

#define  GPxDAT ((uint32_t *) 0x6FC0)

用括号将整个表达式四舍五入,这样它就不会失败,无论你把它放在哪里。

编写这种定义,您可以在地址0x6fc0处访问GPxDAT[0]作为一个32位无符号整数,GPxDAT[1]作为下一个32位地址(在前一个地址之上),所有这些都基于由表示的地址号码。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-10-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-23
    • 2012-01-29
    相关资源
    最近更新 更多