|
楼主 |
发表于 2019-7-31 23:57:39
|
显示全部楼层
本帖最后由 huaweiwx 于 2019-8-1 16:50 编辑
第三部分:引脚编号, arduino for 51 采用格式为 Pa_b,其中 a是端口号,b 是bit位号,如 P0_1
arduino 采用对全部引脚按 序数 1,2,3,....这样的方式,优点是封装端口及bit位,让使用者在应用层面和硬件层作了隔离,应用时可以不管端口和位,但缺点是明显的:
1 需要保存一个数字(脚号)和对应实际端口的对照表,这样既要多开销存储空间,也要多开销查表所需的机器时间,而且对我们学习者来说有时想知道是那个端口和bit还需要查相应的文档,最为致命的是不同的板子对同一个脚还编号是不同的。
2 对于arduino官方板子来说,这样的方法还算可行,已经把这个编号标在板子上了,但对非官方板子来说,这简直是多此一举,毫无意义,因为我们板子上根本没有1,2,3,....,到是有着PA0,PC13这样好记又有具体含义的名称,在51中,通常对于一个具体的引脚我们表示为 Pa.b,a为端口号,b为bit位号, 如:
P0.1 表示 P0端口bit1脚;
在 51 构架中,该脚是可位寻址读写的,因此,头文件中通常对该脚通过类型修饰符sbit进行了定义:
sbit P01 = P0^1; // 规则1 Pab
这里 P01 也可以用其他合法的符号,如我们也可以定义为:
sbit P0_1 = P0^1; //规则2 Pa_b
这里 a 是端口号,51 构架通常用 0,1,2 数字来表示,而 avr stm等 则用 A,B,C 这样的字母来表示;
b 是位号 0~7 对应 8位端口的最低位至最高位;
大多数芯片厂给出的头文件是以上述规则1来命名,但也有些厂商采用的是规则2 如 silicon的 C8051 头文件,对于这样的不同规则,在我们这个sduino51 系统中必须统一,否则会造成混乱,因此我采用了规则1 来定义位寻址变量,所以对所有C8051头文件均作了这样的替换(C8051老用户要注意);
现在,在arduino for 51 所有gpio sbit 的脚名称 均统一 用 Pab来表示,51 相对 avr 和 stm8/32来说都要简单,读写访问的是同一个地址, 我们仍然能够用这样的语句来设置该脚的电平高低,如程序中可用:
P01 = 1; // set P0.1
P01 = 0; //reset P0.1
而读取电平是
v = P01; //get P0.1 level
因此 Pab 是系统 sbit类型的变量名称,而arduino脚号则是一个数字序数,因此我们仍需要对此定义,为了好记,我们采用这样的表示:
Pa_b;
对应上面P0.1脚,系统有这样的宏定义:
#define P0_1 0x01 /*端口号对应的hex 数字,是不是很好记*/
对于每个芯片(板子)都有一个定义文件pins_arduino.h ,位置在 variants对应的文件夹中。
我没有像 官方arduino那样从0开始连续编号,而是用个8位整数类 uint8_t, 其高4位表示端口号 低4位表示位号(由于只有8位,实际只用低3位),显然,这样有以下好处:
1 不需要专门设置个对照表来建立 数字 0, 1,2,3,....所对应的物理引脚了,编程时 我们一眼就能判断出端口和bit位;在程序中我们只要通过:
pin & 0x0f 屏蔽高4位,就知道是那个bit了;而
pin >> 4; 取高4位,就是端口号;
2 按这个方案 只要未定义 P0_1 (如STC12C54), 程序编译时 用到这个符号就会发出错误信息,因此我们还可简化非法引脚编号的检查,对51资源不足的芯片上,减少了代码开销是有实际意义的;
上面出现三种格式,分别是用P0.1 / P01 /P0_1 这样的格式来表示,对于初学者来说,也许有点混乱,有必要对此做个小结:
第一个 P0.1 因为对C的变量符号来说,符号中含小数点是非法的;因此这通常只有出现在数据表文档或程序注释中;
第二个 P01 是一个 51 专有的预定义sbit类型变量,实际上代表了该位寻址的地址;
第二个 P0_1 才是arduino系统预定义该引脚的arduino编号(可以是C变量或宏定义),是个8位整数类型(uint8_t)常数;
尽管这三个助记符对我们来说都表示了端口 0 的bit1 位,但系统中只出现后两种,并且含义是不同的:具体在对应在宏/函数中用到它,如果是sfr/sbit类型,就用 P01,而如果需要的是一个数表示arduino脚号,则用P0_1;
第四部份 SDUINO 系统简介:
一、 语言和工具链
现有所有arduino ide 支持的移植版本均采用了支持 C++ 的工具链如 GCC ,对51这个古老的构架,根本不在GCC 开发者的支持计划中,虽然 IAR 集成环境支持 51 C++代码,但也只是有限支持,我试过,IAR 连接时只能选 c库,如选择 连接 c++库会出现找不倒库文件的错误提示,因此支持有限,更主要的问题是
a. IAR 不是免费的;
b. IAR 是集成环境,不支持命令行操作;
上述两点导致我们没有现成的C++工具链来支持 arduino ide 环境;
因此我们退一步,采用有个专门针对小设备 c 的开源工具链 SDCC ,支持 stm8/mcs 51/ pic/z80,通过一些小技巧集成到arduino ide中;正因为如此,sduino和 arduino由于采用编程语言不同,而导致使用上的差异;
二、 sdcc 和 gcc 及 keil c51 的主要差异:
sdcc 是个优秀的编译器,支持到最新的ISO C17标准,因此,基本兼容于keil C51,c风格也基本兼容于GCC;但针对目标mcu为51的应用和keil C51仍然有些差异,主要是:
a.指定不同内存区域的修饰词,sdcc 需加双下划线:
keil idata
pdata
xdata
code
bit
sdcc __idata
__pdata
__xdata
__code
__bit
b.修饰词位置:sdcc则需要将修饰词前置
keil uint8_t xdata val;
sdcc xdata uint8_t val;
c.sfr寄存器寻址变量/sbit位寻址变量定义格式不同:
keil sfr P0 = 0x80;
sbit P01 = P0^1;
sdcc __sfr __at(0x80) P0;
__sbit __at(0x80+1) P01;
d.中断矢量定义格式不同:
keil void name(void) interrupt vector;
void name(void) interrupt vector using regnum;
sdcc void name(void) __interrupt(vector);
void name(void) __interrupt(vector) __using (regnum);
另外,中断处理代码函数必须在main.c 声明,否则不会被连接!
三、 sdcc 和 arduino 官方采用的gcc差异,这两个编译器针对的目标不同,功能也相差太大不是一个数量级的,因此放在一起比较是不合适的,但如果仅从C角度来看,差异并不大,但gcc支持C++代码,而arduino 核心部分就是用C++写成的,因此这部分在sduino中无法实现或是只能有限部分实现,核心(core)部分主要是:
1 String 类: 这是通用arduino 字符串支持C++类,sduino不支持,替代方案是用c方法来处理字符串,如用c vprintf 来格式化字符串,用printf来格式化并输出字符串;
2 Stream/Print: 输入输出IO流控制,不支持,好在对51来说,人机接口和文件处理不是主要的,
3 HardwareSerial/Serial: 这是串口输出,也是玩单片机最重要的部分,用来观察运行结果或输入指令数据控制单片机运行,但arduino该模块是C++写成的类结构,并且继承了Stream/Print基础类,因此是移植的难点,现在采用部分兼容和替代方案;C++支持同一函数的不同类型和数量的参数,但在C是不合法的;因此原来arduino:
Serial.print(x,x) 及Serial.println(x,x) 使用了一组函数替代,它们是:
Serial_print_s
Serial_print_sn
Serial_print_i
Serial_print_u
Serial_print_ib
Serial_print_ub
Serial_print_fd
和
Serial_println_s
Serial_println_sn
Serial_println_i
Serial_println_u
Serial_println_ib
Serial_println_ub
Serial_println_fd
另外干脆直接用c标准输出输入库(stdio)的 printf含数;
为了便于移植及和其他核心的arduino 应用代码兼容,对Serial 增加了一个运行代码的指针结构,从而使其具有arduino的风格(style),为了不至于耗费过多的资源,仅包含:
Serial.avalible();
Serial.read();
Serial.write(unsigned char);
Serial.printf(fmt,...);
其中 Serial.printf(fmt,...)等价于直接调用printf(fmt,...);用来替代arduino Serial.print() 和 Serial.println();
4 arduino 库:
和内核一样,由于大部分arduino库都是由C++写成,因此基本不能直接使用,但只要不是反复建立在C++类基础上的库,还是可以很方便地移植到sduino,其中libraries有多个这方面的例子;以后我会祥述,并移植一些;
5 实际上用C语言为SDUINO写成的库,只要不要硬件依赖的,都可以在ARDUINO/gcc下运行,反之则不行!
|
打赏
-
查看全部打赏
|