0

我是嵌入式编程的新手。我有一个带有 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 位。我试图以T1CONBITS这种方式将 T1_ON 分配给我的结构变量:

T1CONBITS=T1_ON   // which is wrong.

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

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

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

感谢您的任何见解

4

4 回答 4

3

这不起作用,因为您试图将一个数字分配给某个完全不相关类型的变量。数字与结构的底层位模式匹配的事实是编译器并不关心的事情。

尝试这个:

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

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

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

(使用联合来转换位模式在最新的 C 标准中是有效的。)

于 2013-09-04T14:51:34.203 回答
1

结构 T1CONBITS 的名称表明它旨在访问 T1CON 的。有没有noat也定义了一个寄存器T1CON wherby你可以写如下?

T1CON = T1_ON ;

更好的是,您可以按预期简单地使用 T1CONBITS 并避免完全需要 T1_ON 和 T1_OFF:

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

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

于 2013-09-05T11:02:55.183 回答
1

对此进行预处理后

T1CONBITS=T1_ON;

会是这样的:

T1CONBITS=0xffff;

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


您可以通过这样做轻松设置T1CONBITS为 all 1s:

memset(&T1CONBITS, 0xff, sizeof(T1CONBITS));
于 2013-09-04T14:46:58.153 回答
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);

等等。

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

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

于 2013-09-06T12:14:41.760 回答