写在前面
基于Renesas CS+CC编译器中RL78/G13芯片族 编程时对未操作时的错误进行追因,思考与总结的小发现和记录。
问题发现
在瑞萨官方的编译器CS+CC里进行编程中,无法识别我们常用的I/O位操作。例如流水灯实验中,需要频繁的对某个I/O进行位操作赋值来改变他的输出信号,但是编译器只识别整个I/O寄存器。
以下用代码段说明:
//以P11为例,我们希望编译器可以识别以下代码,方便理解与操作。
P11 = 1;
P1.1 = 1;
这两句都是我们常用的为P11
这位赋值输出高电平的写法,但是在CS+CC这个瑞萨自家的编译器中,并不识别这样的书写规则。
常见处理
以前面对这样的情况,我们往往要通过对整个端口寄存器进行移位赋值的操作。
P1 = P1|(1<<1);
但是代码操作符叠加复杂以及代码长度增加,简单的某一位赋值的操作变得繁琐又容易犯错。
追根溯源
在不断地跳转定义源头和头文件引用后,找到了根源,定义在一个叫iodefine.h
的文件中,(这个文件是在硬件资源配置完之后编译器生成的)。在这个文件中定义了像这样的结构体:
typedef struct
{
unsigned char no0:1;
unsigned char no1:1;
unsigned char no2:1;
unsigned char no3:1;
unsigned char no4:1;
unsigned char no5:1;
unsigned char no6:1;
unsigned char no7:1;
} __bitf_T;
#define P1 (*(volatile __near unsigned char *)0xFF01)
#define P1_bit (*(volatile __near __bitf_T *)0xFF01)
在上面的代码中,CS+CC编译器的iodefine.h文件中定义了一个8bit的结构体__bitf_T(如果是16位,或者32位只需要往上叠加对应个no个数即可),并定义了P5整个寄存器的地址,以及P5_bit这个__bitf_T型的结构体的地址,都指向PORT5的寄存器地址。此时,我们可以通过以下的简单操作即可实现对应I/O的位操作。
P1_bit.no1 = 1
如果是16位的寄存器,可以通过下面的结构体和配置去进行类似的访问与操作。
typedef struct
{
unsigned char no0:1;
unsigned char no1:1;
unsigned char no2:1;
unsigned char no3:1;
unsigned char no4:1;
unsigned char no5:1;
unsigned char no6:1;
unsigned char no7:1;
unsigned char no8:1;
unsigned char no9:1;
unsigned char no10:1;
unsigned char no11:1;
unsigned char no12:1;
unsigned char no13:1;
unsigned char no14:1;
unsigned char no15:1;
} __bitf_T2;
借用这个结构就可以完成对16位寄存器的单独位操作。
精益求精
- 如果这个位操作用的比较频繁,还可以进一步通过宏定义进行封装。
#define P11 P1_bit.no1
//这样就可以用最开始大家都习惯的写法来进行操作
P11 = 1;
- 还有一种封装思路
#define P11 (((volatile __near __bitf_T *)0xFF01)->no1)
P11 = 1;
#define P11 (((volatile __near __bitf_T *)0xFF01)->no1)
P11 = 1;
这种思路比上面的会少一层对头文件的引用依赖。