位寄存器定义
合集下载
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
struct TCR_BITS { // bits description Uint16 rsvd1:4; // 3:0 reserved Uint16 TSS:1; // 4 Timer Start/Stop Uint16 TRB:1; // 5 Timer reload Uint16 rsvd2:4; // 9:6 reserved Uint16 SOFT:1; // 10 Emulation modes Uint16 FREE:1; // 11 Uint16 rsvd3:2; // 12:13 reserved Uint16 TIE:1; // 14 Output enable Uint16 TIF:1; // 15 Interrupt flag }; 然后,定义一个 Union,允许该寄存器既可以按 bit 访问,也可以作为整体访问: union TCR_REG { Uint16 all; struct TCR_BITS bit; }; 在如此这样对每个寄存器都定义好后,重写 struct CPUTIMER_REGS 如下:
变量名是选择项, 可以不命名, 这样规定是为了排列需要。
例如: 下面定义了一个位结构。
struct{ unsigned incon: 8; /*incon 占用低字节的 0~7 共 8 位*/ unsigned txcolor: 4;/*txcolor 占用高字节的 0~3 位共 4 位*/ unsigned bgcolor: 3;/*bgcolor 占用高字节的 4~6 位共 3 位*/ unsigned blink: 1; /*blink 占用高字节的第 7 位*/
struct{
byte COPWAI :1;/* COP stops in WAIT mode */
byte RTIWAI :1;/* RTI stops in WAIT mode */
byte CWAI :1;/* CLK24 and CLK23 stop in WAIT mode */
byte PLLWAI :1;/* PLL stops in WAIT mode */
位段结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构比按位运算符更加方便。
位结构定义的一般形式为:
struct 位结构名{ 数据类型 变量名: 整型常数; 数据类型 变量名: 整型常数;
} 位结构变量;
其中: 整型常数必须是非负的整数, 范围是 0~15, 表示二进制位的个数, 即表示有多少位。
struct CPUTIMER_REGS { union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high }; 这时,每个寄存器都可以按 bit 或作为整体访问了。 这样的方式,对于程序员来说,更容易理解,程序也更容易维护。 这样做的坏处:产生的代码长度稍大一些。 另外,对于有些特殊的寄存器,如 WDCR,就没有定义 Bit field 和 Union。 上面讲了这么多,那么我们是否需要将这些寄存器全部自己定义呢?答案是不需 要。因为 TI 公司已经为我们提供了现成的.H 文件,为我们做好了这些工作。在 编程时,我们只需要搞清楚需要把那个头文件包含进来就行了
}ห้องสมุดไป่ตู้orkers;'
上例的结构定义了关于一个工从的信息。其中有两个位结构成员, 每个位结构成员只有一位, 因此只 占一个字节但保存了两个信息, 该字节中第一位表示工人的状态, 第二位表示工资是否已发放。由此可见 使用位结构可以节省存贮空间。
注意不要超过值限制
Typedef union{
byte Byte;
while (1) {
if (i) dosomething(); } }
/* Interrupt service routine. */ void ISR_2(void) {
i=1; }
程序的本意是希望 ISR_2 中断产生时,在 main 当中调用 dosomething 函数,但是,由于编 译器判断在 main 函数里面没有修改过 i,因此,可能只执行一次对从 i 到某寄存器的读操作, 然后每次 if 判断都只使用这个寄存器里面的“i 副本”,导致 dosomething 永远也不会被 调用。如果将将变量加上 volatile 修饰,则编译器保证对此变量的读写操作都不会被优化(肯 定执行)。此例中 i 也应该如此说明。 一般说来,volatile 用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加 volatile; 2、多任务环境下各任务间共享的标志应该加 volatile; 3、存储器映射的硬件寄存器通常也要加 volatile 说明,因为每次对它的读写都可能有不同意 义; 另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打 断了重写),在 1 中可以通过关中断来实 现,2 中可以禁止任务调度,3 中则只能依靠硬件的良好设计了。 3.这些宏定义的作用就是简单的替换而已。比如:
CLKSELSTR
=================================================================================
F2812 中有大量的外设寄存器, 在具体的应用中,要把这些寄存器根据实际需要进行配置。这也是程序在 初始化期间需要做的主要工作,在配置完成后,才可以进入正常的流程,即业务逻辑处理阶段。以我的应 用为例,F2812 主要完成下列工作:2 路 A/D 采样,2 路 PWM 输出,6 路 GPIO 输出。在此基础上,我将 进行运算处理,实现主要功能。 传统的寄存器访问方式,通过 Macro 定义实现。在 TI 提供的头文件中,提供了一种新的方式:bit field 和 struct 方式,即位域加结构的方式。在这种方式中,定义 struct 来表示与某个外设相关的一组寄存器, 然后由 Linker 程序负责将寄存器映射到内存中。如对于定时器寄存器,定义: struct CPUTIMER_REGS { Uint32 TIM; // Timer counter register Uint32 PRD; // Period register Uint16 TCR; // Timer control register Uint16 rsvd1; // reserved Uint16 TPR; // Timer pre-scale low Uint16 TPRH; // Timer pre-scale high
byte ROAWAI :1;/* Reduced Oscillator Amplitude in WAIT mode */
byte SYSWAI :1;/* System clocks stop in WAIT mode */
byte PSTP :1;/* Pseudo Stop */
byte PLLSEL :1;/* PLL selected for system clock */
#define CLKSEL_SYSWAI _CLKSEL.Bits.SYSWAI
#define CLKSEL_PSTP _CLKSEL.Bits.PSTP
#define CLKSEL_PLLSEL _CLKSEL.Bits.PLLSEL
解读: 1.寄存器 CLKSELSTR 是一个联合体,Byte 和 Bits 共用一个地址,如此一来,既可以给整 个 8 位同时赋值,也可以给某一位赋值。例如: CLKSELSTR.Byte=0x01;//给整个八位赋值 CLKSELSTR.Bits.PLLSEL=1;//给最低位赋值 (2)此语句定义寄存器的地址。REG_BASE 是一个寄存器的基址,后面是其偏移量。两个地 址相加,就是该寄存器的绝对地址。 寄存器当然是全局变量了,所以要加 extern. 那么 volatile 又是什么意思呢? volatile 是“易变的”意思。由于访问寄存器的速度要快过 RAM,所以编译器一般都会作减 少存取外部 RAM 的优化。比如: static int i=0; int main(void) { ...
} Bits;
} CLKSELSTR;
//(1)
Extern volatile CLKSELSTR _CLKSEL @(REG_BASE + 0x00000039);//(2)
#define CLKSEL _CLKSEL.Byte
// (3)
#define CLKSEL_COPWAI _CLKSEL.Bits.COPWAI
}; 这样,如果 DSP 内有多个定时器,则可以通过声明多个变量实现对三个定时器寄存器的访问,便于代码复 用。 利用编译器的 DATA_SECTION #pragma,为每个变量分配一个数据段。然后,通过在 cmd 文件,Linker 将每个数据段映射为内存中与该外设寄存器相对应的内存地址。 这时,还不能实现对寄存器,如 TIM 中的每一位的访问。需要对每个寄存器,为其定义位域,使每一位都 可以访问,如定义 TCR 的位域:
}ch;
位结构成员的访问与结构成员的访问相同。
例如: 访问上例位结构中的 bgcolor 成员可写成:
ch.bgcolor
位结构成员可以与其它结构成员一起使用。按位访问与设置,方便&节省
例如:
struct info{ char name[8]; int age; struct addr address; float pay; unsigned state: 1; unsigned pay: 1;
#define CLKSEL_RTIWAI _CLKSEL.Bits.RTIWAI
#define CLKSEL_CWAI _CLKSEL.Bits.CWAI
#define CLKSEL_PLLWAI _CLKSEL.Bits.PLLWAI
#define CLKSEL_ROAWAI _CLKSEL.Bits.ROAWAI
变量名是选择项, 可以不命名, 这样规定是为了排列需要。
例如: 下面定义了一个位结构。
struct{ unsigned incon: 8; /*incon 占用低字节的 0~7 共 8 位*/ unsigned txcolor: 4;/*txcolor 占用高字节的 0~3 位共 4 位*/ unsigned bgcolor: 3;/*bgcolor 占用高字节的 4~6 位共 3 位*/ unsigned blink: 1; /*blink 占用高字节的第 7 位*/
struct{
byte COPWAI :1;/* COP stops in WAIT mode */
byte RTIWAI :1;/* RTI stops in WAIT mode */
byte CWAI :1;/* CLK24 and CLK23 stop in WAIT mode */
byte PLLWAI :1;/* PLL stops in WAIT mode */
位段结构是一种特殊的结构, 在需按位访问一个字节或字的多个位时, 位结构比按位运算符更加方便。
位结构定义的一般形式为:
struct 位结构名{ 数据类型 变量名: 整型常数; 数据类型 变量名: 整型常数;
} 位结构变量;
其中: 整型常数必须是非负的整数, 范围是 0~15, 表示二进制位的个数, 即表示有多少位。
struct CPUTIMER_REGS { union TIM_GROUP TIM; // Timer counter register union PRD_GROUP PRD; // Period register union TCR_REG TCR; // Timer control register Uint16 rsvd1; // reserved union TPR_REG TPR; // Timer pre-scale low union TPRH_REG TPRH; // Timer pre-scale high }; 这时,每个寄存器都可以按 bit 或作为整体访问了。 这样的方式,对于程序员来说,更容易理解,程序也更容易维护。 这样做的坏处:产生的代码长度稍大一些。 另外,对于有些特殊的寄存器,如 WDCR,就没有定义 Bit field 和 Union。 上面讲了这么多,那么我们是否需要将这些寄存器全部自己定义呢?答案是不需 要。因为 TI 公司已经为我们提供了现成的.H 文件,为我们做好了这些工作。在 编程时,我们只需要搞清楚需要把那个头文件包含进来就行了
}ห้องสมุดไป่ตู้orkers;'
上例的结构定义了关于一个工从的信息。其中有两个位结构成员, 每个位结构成员只有一位, 因此只 占一个字节但保存了两个信息, 该字节中第一位表示工人的状态, 第二位表示工资是否已发放。由此可见 使用位结构可以节省存贮空间。
注意不要超过值限制
Typedef union{
byte Byte;
while (1) {
if (i) dosomething(); } }
/* Interrupt service routine. */ void ISR_2(void) {
i=1; }
程序的本意是希望 ISR_2 中断产生时,在 main 当中调用 dosomething 函数,但是,由于编 译器判断在 main 函数里面没有修改过 i,因此,可能只执行一次对从 i 到某寄存器的读操作, 然后每次 if 判断都只使用这个寄存器里面的“i 副本”,导致 dosomething 永远也不会被 调用。如果将将变量加上 volatile 修饰,则编译器保证对此变量的读写操作都不会被优化(肯 定执行)。此例中 i 也应该如此说明。 一般说来,volatile 用在如下的几个地方: 1、中断服务程序中修改的供其它程序检测的变量需要加 volatile; 2、多任务环境下各任务间共享的标志应该加 volatile; 3、存储器映射的硬件寄存器通常也要加 volatile 说明,因为每次对它的读写都可能有不同意 义; 另外,以上这几种情况经常还要同时考虑数据的完整性(相互关联的几个标志读了一半被打 断了重写),在 1 中可以通过关中断来实 现,2 中可以禁止任务调度,3 中则只能依靠硬件的良好设计了。 3.这些宏定义的作用就是简单的替换而已。比如:
CLKSELSTR
=================================================================================
F2812 中有大量的外设寄存器, 在具体的应用中,要把这些寄存器根据实际需要进行配置。这也是程序在 初始化期间需要做的主要工作,在配置完成后,才可以进入正常的流程,即业务逻辑处理阶段。以我的应 用为例,F2812 主要完成下列工作:2 路 A/D 采样,2 路 PWM 输出,6 路 GPIO 输出。在此基础上,我将 进行运算处理,实现主要功能。 传统的寄存器访问方式,通过 Macro 定义实现。在 TI 提供的头文件中,提供了一种新的方式:bit field 和 struct 方式,即位域加结构的方式。在这种方式中,定义 struct 来表示与某个外设相关的一组寄存器, 然后由 Linker 程序负责将寄存器映射到内存中。如对于定时器寄存器,定义: struct CPUTIMER_REGS { Uint32 TIM; // Timer counter register Uint32 PRD; // Period register Uint16 TCR; // Timer control register Uint16 rsvd1; // reserved Uint16 TPR; // Timer pre-scale low Uint16 TPRH; // Timer pre-scale high
byte ROAWAI :1;/* Reduced Oscillator Amplitude in WAIT mode */
byte SYSWAI :1;/* System clocks stop in WAIT mode */
byte PSTP :1;/* Pseudo Stop */
byte PLLSEL :1;/* PLL selected for system clock */
#define CLKSEL_SYSWAI _CLKSEL.Bits.SYSWAI
#define CLKSEL_PSTP _CLKSEL.Bits.PSTP
#define CLKSEL_PLLSEL _CLKSEL.Bits.PLLSEL
解读: 1.寄存器 CLKSELSTR 是一个联合体,Byte 和 Bits 共用一个地址,如此一来,既可以给整 个 8 位同时赋值,也可以给某一位赋值。例如: CLKSELSTR.Byte=0x01;//给整个八位赋值 CLKSELSTR.Bits.PLLSEL=1;//给最低位赋值 (2)此语句定义寄存器的地址。REG_BASE 是一个寄存器的基址,后面是其偏移量。两个地 址相加,就是该寄存器的绝对地址。 寄存器当然是全局变量了,所以要加 extern. 那么 volatile 又是什么意思呢? volatile 是“易变的”意思。由于访问寄存器的速度要快过 RAM,所以编译器一般都会作减 少存取外部 RAM 的优化。比如: static int i=0; int main(void) { ...
} Bits;
} CLKSELSTR;
//(1)
Extern volatile CLKSELSTR _CLKSEL @(REG_BASE + 0x00000039);//(2)
#define CLKSEL _CLKSEL.Byte
// (3)
#define CLKSEL_COPWAI _CLKSEL.Bits.COPWAI
}; 这样,如果 DSP 内有多个定时器,则可以通过声明多个变量实现对三个定时器寄存器的访问,便于代码复 用。 利用编译器的 DATA_SECTION #pragma,为每个变量分配一个数据段。然后,通过在 cmd 文件,Linker 将每个数据段映射为内存中与该外设寄存器相对应的内存地址。 这时,还不能实现对寄存器,如 TIM 中的每一位的访问。需要对每个寄存器,为其定义位域,使每一位都 可以访问,如定义 TCR 的位域:
}ch;
位结构成员的访问与结构成员的访问相同。
例如: 访问上例位结构中的 bgcolor 成员可写成:
ch.bgcolor
位结构成员可以与其它结构成员一起使用。按位访问与设置,方便&节省
例如:
struct info{ char name[8]; int age; struct addr address; float pay; unsigned state: 1; unsigned pay: 1;
#define CLKSEL_RTIWAI _CLKSEL.Bits.RTIWAI
#define CLKSEL_CWAI _CLKSEL.Bits.CWAI
#define CLKSEL_PLLWAI _CLKSEL.Bits.PLLWAI
#define CLKSEL_ROAWAI _CLKSEL.Bits.ROAWAI