C,是否可以将宏指定给结构变量?

时间:2013-09-04 14:26:30

标签: c embedded c-preprocessor

我是嵌入式编程的新手。我有一个带有2个头文件的PIC单片机:pic.hTimer_peripheral.h

pic.h中,定时器配置寄存器定义为:

__extension__ typedef struct tagT1CONBITS {
union {
  struct {
    unsigned :1;
    unsigned TCS:1;
    unsigned TSYNC:1;
    unsigned :1;
    unsigned TCKPS:2;
    unsigned TGATE:1;
    unsigned :6;
    unsigned TSIDL:1;
    unsigned :1;
    unsigned TON:1;
  };

  struct {
    unsigned :4;
    unsigned TCKPS0:1;
    unsigned TCKPS1:1;
   };
};
} T1CONBITS;

并且在timer.h中,某些宏已被定义为:

/* Timer1 Control Register (T1CON) Bit Defines */

#define T1_ON               0xffff      /* Timer1 ON */
#define T1_OFF              0x7fff      /* Timer1 OFF */

与微控制器数据表相对应。 unsigned类型是16位。我尝试以这种方式将T1_ON分配给我的struct变量T1CONBITS

T1CONBITS=T1_ON   // which is wrong.

我知道我可以初始化一个结构,但是我想在我的main函数中做一个赋值,我不想使用结构成员来做它:

T1CONBITS.TCS=1; 
T1CONBITS.TSYNC=1;

有没有办法做到这一点?如果没有,为什么你认为timer.h中的这些宏已被定义?

感谢您的任何见解

4 个答案:

答案 0 :(得分:3)

这不起作用,因为您正在尝试为某个完全不相关的类型的变量分配数字。数字与结构的基础位模式匹配的事实是编译器并不关心的事情。

试试这个:

union BitsInt {
    struct tagT1CONBITS con;
    int bits;
};

T1CONBITS = ((union BitsInt){ .bits = T1_ON }).con;

您将一种类型的数据放入其中,您将获得与无关类型相同的数据。

(使用联合来转换位模式从最新的C标准开始有效。)

答案 1 :(得分:1)

预处理后

T1CONBITS=T1_ON;

就是这样:

T1CONBITS=0xffff;

struct变量只能分配相同类型的变量


您可以通过这样做轻松地将T1CONBITS设置为所有1

memset(&T1CONBITS, 0xff, sizeof(T1CONBITS));

答案 2 :(得分:1)

结构T1CONBITS的名称表示它用于访问T1CON的。是否有noat还定义了一个寄存器T1CON wherby,你可以写下面的内容吗?

T1CON = T1_ON ;

更好的是,您可以按原样使用T1CONBITS,并且完全不需要T1_ON和T1_OFF:

T1CONBITS.TON = 0 ; // Off
T1CONBITS.TON = 1 ; // On

通过直接分配T1CON,您将所有其他位设置为1,这可能不是您想要的任何情况。相反,你会读取 - 修改 - 写入,这实际上是位访问只是更容易出错,更清晰。

答案 3 :(得分:0)

根据我的经验,编译器为某个微控制器提供的预先制作的寄存器映射是繁重的,不可读的和不可移植的。无论你的特定代码是否有意义,都没有人知道,因为每个编译器都会以不同的方式实现位字段。

如果您可以自行编写寄存器定义,请执行此操作。例如:

#define T1CON (*(uint16_t*)0x1234u) // some address

#define T1CON_TCS    0x4000u
#define T1CON_TSYNC  0x2000u
...
#define T1CON_TCKPS  0x0C00u

然后用标准C编程位设置惯用语设置位:

T1CON |=  T1CON_TCS; // set this bit
T1CON &= ~T1CON_TCS; // clear this bit

设置属于同一组的多个位:

#define T1_ON  0x0C00u 
#define T1_OFF 0x0400u

T1CON |= (T1CON_TCKPS & T1_ON);

等等。

(虽然请注意这将是read-modify-write,这可能是你想要的也可能不是。如果你必须使用普通位集(特殊情况,清除标志寄存器等),你通常会忽略按位逻辑,只需写入T1CON = T1CON_TCS | TSYNC;并设置所有需要的位。但请注意,没有guartees,某个C代码是否提供读 - 修改 - 写或位设置是CPU和编译器相关的。反汇编以确保代码符合您的预期。)

这对于世界上的每个C编译器都是100%可移植的,并且每个使用嵌入式系统的C程序员都可以100%读取。