1

背景

我正在学习嵌入式系统编程。在这个过程中,我了解到“指针”是嵌入式系统最常用的。指针是在 C 中声明的变量,其值是另一个变量的地址。我可以通过取消引用指针来操作/更改这个其他变量的值。

例子:

int *pt;    // Integer pointer variable declaration.

float *pf;  // Float pointer variable declaration.

int *pt表示这pt是一个指针变量,能够指向 int 类型的变量。另一方面,指针变量fp只能存储浮点类型变量的地址。

要将值(地址)分配给指针变量,&必须使用地址运算符 ( )。

int var = 20;   //Actual variable declaration
int *pt;        //Pointer Variable Declaration

pt = &var;      //Here with the ampersand (&)operator we denotes an 
                //address in memory to the pt pointer.

/*Changing the variable value from 20 to 79*/
*pt = 79;   //Dereference

printf (“Value of *pt variable: %d\n”, *pt); //Output:79
printf (“Value of var variable: %d\n”, var); //Output:79

这两个链接对我理解指针非常有帮助:

C中的指针基础

指针(计算机编程)

问题

当我遇到 Stellaris LM4F120H5QR 微控制器的头文件时,我的问题就出现了。该头文件定义了具有内存地址的寄存器位置,如下所示:

#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))

当我遇到这种语法时,我很困惑,如果确实“ (volatile unsigned long *)0x400253FC)”已被定义为指针并且整个句子可以解释如下图所示?

指针取消引用内存位置

如果这不正确,有人可以解释解释嵌入式系统头文件的寄存器定义的正​​确方法吗?

头文件的链接 -->这里

4

2 回答 2

0

这是一个正确的反抗!!如果您尝试它,它会工作得很好....让我帮助您理解这个陈述它是如何工作的

访问特定内存地址的解释

例如,如果您在内存中有一个特定地址(此地址0x400253FC)并且您想将(50)的值写入第一个字节,则以下代码将是错误的

// the following code is wrong
0x400253FC = 50 ;

上面的代码会给出一个编译错误..那么如何告诉编译器将这个(0x400253FC)作为内存地址??,只需借助强制转换来做到这一点

(unsinged char *)0x400253FC  // cast this number 0x400253FC as char pointer

现在您有一个指针,因此您可以取消引用它并将值写入内存(指针指向的位置),如下所示

*((unsinged char *)0x400253FC) = 50; // write the value 50 in address 0x400253FC

一些编译器在进行优化时会删除这行代码,为了防止编译器这样做,我们添加了volatile 说明符......所以表达式将是这样的

*((volatile unsinged char *)0x400253FC) = 50; // write the value 50 in address 0x400253FC

所以这是如何访问内存中的字节

如果您想访问内存中的 4 个字节,那么它将是这样的

//assuming your compiler consider the long variable as 4 byte
*((volatile unsinged long*)0x400253FC) = 50; // write the value 50 in 4 byte in memory start with address 0x400253FC
于 2020-07-28T20:09:18.077 回答
0
(*((volatile unsigned long *)0x400253FC)) = 0x12345678

初级C,只要解析出来。我想你不知道混乱在哪里。

我认为您了解类型转换

unsigned int x;  //a variable

x = 0x400253FC; //assign the variable a value

(volatile unsigned long *)x  //typecast x into a different type volatile unsigned long *

同样使用指针

volatile unsigned long *z;

(*z)=0x12345678; //at the address pointed to by z place the value 0x12345678;

把它分成几部分。

(
*
(
(volatile unsigned long *)0x400253FC
)
)


0x400253FC a value

(volatile unsigned long *)0x400253FC typecast that value into an unsigned long pointer

((volatile unsigned long *)0x400253FC)  enclose that pointer as a whole at this point it is a pointer, like z from above.

*((volatile unsigned long *)0x400253FC) dereference it one level, like *z above you can now use this to manipulate the unsigned long address.

(*((volatile unsigned long *)0x400253FC)) good idea to wrap defines in parens to not confuse the compiler.  doesn't hurt.

(*((volatile unsigned long *)0x400253FC)) = 0x12345678.  Like *z = 0x12345678 above, write/store 0x12345678 to the address 0x400253FC

#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))

GPIO_PORTF_DATA_R = 0x12345678; store/write 0x12345678 to the address 0x400253FC

unsigned long k; k = GPIO_PORTF_DATA_R; load/read from address 0x400253FC and save it in k

如果你有一个 8 位宽的寄存器,那么调整类型转换。

#define SOME_8BIT_REG  (*((volatile unsigned char *)0x5006789A))

SOME_8BIT_REG = 0x33;

你可以试试

#define GPIO_PORTF_DATA_R       (*((volatile unsigned long *)0x400253FC))
#define SOME_8BIT_REG  (*((volatile unsigned char *)0x5006789A))

void fun ( void )
{
    GPIO_PORTF_DATA_R = 0x12345678;
    SOME_8BIT_REG = 0x33;
}

00000000 <fun>:
   0:   e3a02033    mov r2, #51 ; 0x33
   4:   e59f1010    ldr r1, [pc, #16]   ; 1c <fun+0x1c>
   8:   e59f0010    ldr r0, [pc, #16]   ; 20 <fun+0x20>
   c:   e59f3010    ldr r3, [pc, #16]   ; 24 <fun+0x24>
  10:   e58103fc    str r0, [r1, #1020] ; 0x3fc
  14:   e5c3209a    strb    r2, [r3, #154]  ; 0x9a
  18:   e12fff1e    bx  lr
  1c:   40025000    
  20:   12345678    
  24:   50067800    

  10:   e58103fc    str r0, [r1, #1020] ; 0x3fc
  32 bit store (write) 0x12345678 to address 0x400253fc

  14:   e5c3209a    strb    r2, [r3, #154]  ; 0x9a
  8 bit store (write) 0x33 to address 0x5006789a

指令集无关紧要

0000000000000000 <fun>:
   0:   48 c7 04 25 fc 53 02    movq   $0x12345678,0x400253fc
   7:   40 78 56 34 12 
   c:   c6 04 25 9a 78 06 50    movb   $0x33,0x5006789a
  13:   33 
  14:   c3                      retq  

Disassembly of section .text:

00000000 <fun>:
   0:   123457b7            lui x15,0x12345
   4:   40025737            lui x14,0x40025
   8:   67878793            addi    x15,x15,1656 # 12345678 <fun+0x12345678>
   c:   3ef72e23            sw  x15,1020(x14) # 400253fc <fun+0x400253fc>
  10:   500687b7            lui x15,0x50068
  14:   03300713            li  x14,51
  18:   88e78d23            sb  x14,-1894(x15) # 5006789a <fun+0x5006789a>
  1c:   8082                    ret
于 2020-07-28T22:25:12.507 回答