寄存器位读写,结构体位域定义,位域操作,位操作
1.2.3 添加位域结构体
1)增加位域定义
我们经常需要直接访问寄存器中的某个位域。C281x C/C++头⽂件及外设⽰例所涉及的位域结构体⽅法,为多数⽚上外设寄存器提供了位域定义。例如,可以为CPU 定时器(CPU-Timer)中的每个寄存器定义⼀个位域结构体类型。CPU 定时器(CPU-Timer)控制寄存器的位域定义如下所⽰:
[cpp]
1. //*****************************************************************************
2. //DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
3. //*****************************************************************************
4. struct TCR_BITS //定义⼀个TCR_BITS 结构体类型(不是变量)
5. { Uint16 rsvd1:4; //3:0 保留,从最低位开始,顺序取位到最⾼位。取低4 位
6. Uint16 TSS:1; //4 定时器开始/停⽌,取第5 位
7. Uint16 TRB:1; //5 定时器重装,取第6 位
8. Uint16 rsvd2:4; //9:6 保留,取第7 位到第10 位
9. Uint16 SOFT:1; //10 仿真模式,取第11 位
10. Uint16 FREE:1; //11 仿真模式,取第12 位
11. Uint16 rsvd3:2; //12:13 保留,取第13 位到第14 位
12. Uint16 TIE:1; //14 输出使能,取第15 位
13. Uint16 TIF:1; //15 中断标志,取第16 位
14. };
//*****************************************************************************
//DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
/
/*****************************************************************************
struct TCR_BITS //定义⼀个TCR_BITS 结构体类型(不是变量)
{ Uint16 rsvd1:4; //3:0 保留,从最低位开始,顺序取位到最⾼位。取低4 位
Uint16 TSS:1; //4 定时器开始/停⽌,取第5 位
Uint16 TRB:1; //5 定时器重装,取第6 位
Uint16 rsvd2:4; //9:6 保留,取第7 位到第10 位
Uint16 SOFT:1; //10 仿真模式,取第11 位
Uint16 FREE:1; //11 仿真模式,取第12 位
Uint16 rsvd3:2; //12:13 保留,取第13 位到第14 位
Uint16 TIE:1; //14 输出使能,取第15 位
Uint16 TIF:1; //15 中断标志,取第16 位
};
然后,通过共⽤体进⾏声明,以便访问位域结构体定义的各个成员或者16 位或32位寄存器的值。例如,定时器的控制寄存器共⽤体如下所⽰:
[cpp]
1. //*****************************************************************************
2. //DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
3. //*****************************************************************************
4. union TCR_REG //定义共⽤体类型TCR_REG(不是变量)
5. { Uint16 all;
6. struct TCR_BITS bit; //bit 是⼀个具有TCR_BITS 结构体类型的变量
7. };
8. //all 和bit 是共⽤体的两个成员,它们都是16 位结构,占⽤内存的同⼀单元
//*****************************************************************************
//DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
//*****************************************************************************
union TCR_REG //定义共⽤体类型TCR_REG(不是变量)
{ Uint16 all;
struct TCR_BITS bit; //bit 是⼀个具有TCR_BITS 结构体类型的变量
};
//all 和bit 是共⽤体的两个成员,它们都是16 位结构,占⽤内存的同⼀单元
⼀旦每个寄存器的位域结构体类型和共⽤体的定义都建⽴起来了,则在CPU 定时器(CPU-Timer)的寄存器结构体类型中,各个成员可通过采⽤共⽤体定义的形式重写:
[cpp]
1. //*****************************************************************************
2. //DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
3. //*****************************************************************************
4. struct CPUTIMER_REGS
5. { union TIM_GROUP TIM; //定时器计数寄存器,TIM 是⼀个具有 TIM_GROUP 共
6. //⽤体类型的变量
7. union PRD_GROUP PRD; //定时器周期寄存器
8. union TCR_REG TCR; //定时器控制寄存器
9. Uint16 rsvd1; //保留
10. union TPR_REG TPR; //定时器预定标寄存器低位
11. union TPRH_REG TPRH; //定时器预定标寄存器⾼位
12. };
/
/*****************************************************************************
//DSP281x_headers\include\DSP281x_CpuTimers.h CPU 定时器头⽂件
//*****************************************************************************
struct CPUTIMER_REGS
{ union TIM_GROUP TIM; //定时器计数寄存器,TIM 是⼀个具有 TIM_GROUP 共
//⽤体类型的变量
union PRD_GROUP PRD; //定时器周期寄存器
union TCR_REG TCR; //定时器控制寄存器
Uint16 rsvd1; //保留
union TPR_REG TPR; //定时器预定标寄存器低位
union TPRH_REG TPRH; //定时器预定标寄存器⾼位
};
现在,既可以通过C 代码以位域的⽅法访问CpuTimer 寄存器中的某位,也可以对整个寄存器进⾏访问:
[cpp]
1. //*****************************************************************************
2. //⽤户源⽂件
3. //*****************************************************************************
4. CpuTimer0Regs.TCR.bit.TSS = 1; //访问⼀个单独的位域的⽰例
5. CpuTimer0Regs.TCR.all = TSS_MASK; //访问整个寄存器的⽰例
//*****************************************************************************
//⽤户源⽂件
//*****************************************************************************
CpuTimer0Regs.TCR.bit.TSS = 1; //访问⼀个单独的位域的⽰例
CpuTimer0Regs.TCR.all = TSS_MASK; //访问整个寄存器的⽰例
采⽤位域结构体的⽅法具有以下优点:
(1)⽆须⽤户确定掩模值,就可对位域进⾏操作;
(2)可在CCS 观察窗中看到寄存器和位域的值;
(3)当使⽤CCS 时,编辑器会提供⼀张现有结构体/位域成员的列表以供选择。这⼀功能是CCS ⾃动完成的,它使编写代码变得更容易,⽽不必查阅寄存器和位域名⽂件。
掩模值是指位掩码(位屏蔽码),在下⾯的代码段中,常数TCR_MASK 是位掩码是⽤于置位或清除较⼤字段中的⼀个特殊位的常数值。
[cpp]
1. #define TCR_MASK 0x0010
2. …
3. CpuTimer0Regs.TCR.all = TCR_MASK;
#define TCR_MASK 0x0010
CpuTimer0Regs.TCR.all = TCR_MASK;
2)使⽤位域时,“读—修改—写”的注意事项当对寄存器中的单个位域进⾏写操作时,硬件将执⾏⼀个读—修改—写的操作,即读出寄存器中的内容,修改单个位域的值及回写整个寄存器。上述操作在F28x 上的单个周期内完成。当发⽣回写操作时,寄存器内的其他位将被写⼊读出时所读到的同⼀个数值。有些寄存器没有采⽤共⽤体定义,是因为不推荐采⽤这种⽅式访问,也存在⼀些例外情况,包括:
(1)具有写1 清除位的寄存器,如事件管理标志寄存器;
(2)⽆论在什么时候访问寄存器,都必须⽤特殊⽅式对位进⾏写⼊操作的寄存器,如看门狗控制寄存器。
没有位域结构体和共⽤体定义的寄存器,不使⽤*.bit 或*.all 名称进⾏访问,例如:
[cpp]
1. //*****************************************************************************
2. //⽤户源⽂件
3. //*****************************************************************************
4. SysCtrlRegs.WDCR = 0x0068;
//*****************************************************************************
//⽤户源⽂件
//*****************************************************************************
SysCtrlRegs.WDCR = 0x0068;
3)代码长度考量
采⽤位域定义访问寄存器,可使代码变得易读、易修改和易维护。当需要对寄存器中单独某位域进⾏
访问或者查询时,使⽤这种⽅法也⾮常有效。然⽽,值得注意的是:当对⼀个寄存器进⾏⼀定数量的访问时,使⽤*.bit 位域定义形式进⾏访问将导致⽐使⽤*.all 形式对寄存器进⾏写操作需要更多的代码,例如:
[cpp]
1. //*****************************************************************************
2. //⽤户源⽂件
3. //*****************************************************************************
c语言struct头文件
4. CpuTimer0Regs.TCR.bit.TSS = 1; //1 = 停⽌定时器
5. CpuTimer0Regs.TCR.bit.TRB = 1; //1 = 重装定时器
6. CpuTimer0Regs.TCR.bit.SOFT = 1; //当SOFT=1 且FREE=1 时,定时器⾃由运⾏
7. CpuTimer2Regs.TCR.bit.FREE = 1;
8. CpuTimer2Regs.TCR.bit.TIE = 1; //1 = 使能定时器中断
//*****************************************************************************
//⽤户源⽂件
//*****************************************************************************
CpuTimer0Regs.TCR.bit.TSS = 1; //1 = 停⽌定时器
CpuTimer0Regs.TCR.bit.TRB = 1; //1 = 重装定时器
CpuTimer0Regs.TCR.bit.SOFT = 1; //当SOFT=1 且FREE=1 时,定时器⾃由运⾏
CpuTimer2Regs.TCR.bit.FREE = 1;
CpuTimer2Regs.TCR.bit.TIE = 1; //1 = 使能定时器中断
采⽤上述的⽅法,可以得到可读性⾮常强并且易于修改的代码。不⾜是代码有些长。如果⽤户更加关⼼代码的长度,可使⽤*.all 结构对寄存器进⾏⼀次性的写操作。
[cpp]
1. CpuTimer0Regs.TCR.all = TCR_MASK; //TCR_MASK 可在⽂件头部⽤#define 定义
CpuTimer0Regs.TCR.all = TCR_MASK; //TCR_MASK 可在⽂件头部⽤#define 定义
1.2.4 共⽤体结构体位域的应⽤实例
【例】设count 是⼀个16 位的⽆符号整型计数器,最⼤计数为⼗六进制0xffff,要求将这个计数值以⼗六进制半字节的形式分解出来。
对于上述实例通常采⽤移位的⽅法求解,⽽采⽤共⽤体结构体位域的⽅法不需要通过移位运算。以下,对CCS 在头⽂件中⼤量使⽤的共⽤体结构体位域进⾏注解。
先定义⼀个共⽤体结构体位域:
[cpp]
1. Uint16 cont,g,s,b,q; //16 位⽆符号整型变量定义
2. cont=0xfedc; //对cont 赋值
3. …
4. union //共⽤体类型定义
5. { Uint16 i; //定义i 为16 位⽆符号整型变量
6. struct //结构体类型定义
7. {
8. Uint16 low:4; //最低4 位在前。从最低4 位开始,取每4 位构成半字节
9. Uint16 mid0:4;
10. Uint16 mid1:4;
11. Uint16 high:4; //最⾼4 位在后
12. }HalfByte; //HalfByte 为具有所定义的结构体类型的变量
13. }Count; //Count为具有所定义的共⽤体类型的变量