1.9 数组、字符串与指针 |
|
大量单片机应用系统设计中都会使用到数组定义,例如,下面的数组SEG_CODE定义了0~9的七段数码管段码表:
由于在程序运行过程中SEG_CODE的数据保持不变,因此上述语句中将存储类型设为code。如果将code改为data也不会影响程序的运行,只是在程序运行时数组会被分配到数据RAM,而不是仅占用Falsh程序空间。在Small模式下,省略code相当于将程序存储类型设为默认的data类型。
在编写单片机C语言程序时,如果定义的数组元素是动态变化的,它必须被定义在数据RAM中。但由于data类型仅允许使用128B内存,如果编译时提示数据RAM空间不够,可尝试将data改为idata,例如:
另外,存储类型code、data和idata还可以放到数据类型前面。
字符串类型在单片机C程序设计中也会被大量使用,例如,下面的字节串定义:
这3种定义是完全相同的,它们都占用20B空间,实际串长为16个字符,最后未明确赋值的4B全部为0x00(即'\0'),在液晶屏上显示这类字符串时,可用以下方法:
要注意的是,如果字符串长为16,而字符数据空间也只固定给出了16B,那么上述方法中的后两种就不可靠了,因为最后一个字符后面不一定是字符串结束标志'\0'(0x00)。
字符串还可以这样定义:
这两种定义也是相同的,其串长均为16个字符,所占用的字节空间均为17B,因为字符串末尾被自动附加了结束标志字节0x00('\0')。
在已知串长时,上述三种字符串显示方法均可使用,在字符串长未知时可使用上述方法中的后两种,另外,上述显示方法还可以改写成:
在编写C语言程序时,除了常使用字符数组(字符串)以外,还会使用到字符串数组,例如:
如果要在液晶上显示“Counter:”这个字符串,可用以下语句实现:
在英文字符液晶上显示数值时需要将待显示数据转换为字符串,这时可用此前提到的数据位分解方法,先分解出各位数字,然后加上0x30('0')得到对应数字的ASCII编码。
另一种更为简单的方法是使用sprintf函数,示例代码如下:
上述语句运行后,Buf会被以下字节填充:
这些字节代表字符串'-123.45',跟踪运行效果如图1-6所示。该字符串可直接送液晶屏显示。
图1-6 Keil C跟踪Buf的填充效果
如果已经有语句:
语句sprintf(Buf + 7 , '%8.2f' , x)会使Buf中的字符串会变为'Result: -123.45',此外还可以使用下面的语句得到同样的结果:
另外,C语言还提供了与字符串有关的数据转换函数atoi、atol、atof、strtod、strtol、strtoul,在程序设计中涉及数据输入/输出及运算与显示时可以恰当使用这些函数。
指针是C语言的重要特色之一,对于语句:
pd指向数组d中的第0个字节,显示数组内容可使用下面的代码:
但是不能使用下面的代码:
因为数组名d虽然也是第0个字节的地址,但它不能在运行过程中改变,也正是因为数组名同样也是数组中第0个元素的指针。因此,某些函数定义中的形参为数组,调用函数时给出的实参常为指向同类型数据的指针,反之形参为指针,实参为数组名也很常见。
此前讨论的字符串示例中也出现了指针应用,这些应用同样要熟练掌握。
由于8051及其派生系列具有独特结构,Keil C51支持以下两种不同类型的指针。
(1)通用指针
上述示例INT8U *pd中的pd就是通用指针,指针声明与标准C语言完全一样,其特点是总用3字节来存储指针,第一字节表示存储器类型,第二、三字节分别是指针所指向数据地址的高字节和低字节。这种定义很方便但速度较慢,在所指向的目标空间不明确时普遍使用。
(2)存储器指针
这种指针在定义时指明了存储器类型,并且指针总是指向特定的存储器空间(片内数据RAM、片外数据RAM或程序ROM),例如:
由于定义中已经指明了存储器类型,因此,相对于通用指针而言,指针第一字节省略,对于data、bdata、idata存储器类型,指针仅需要1字节。因为它们的寻址空间都在256字节以内,而code和xdata存储类型则需要2字节指针,因为它们的寻址空间最大为64KB。
使用存储器指针比使用通用指针效率高,指针所占空间小,速度更快。在存储器空间明确时,建议使用存储器指针,如果存储器空间不明确则使用通用指针。