11.2字符数组和字符指针11.2.1常量和符号常量在程序运行过程中,其值不能被改变的量称之为常量。常量分为不同的类型,有整型常量如1、2、3、100;浮点型常量3.14、0.56、-4.8;字符型常量‘a’、‘b’、‘0’;字符串常量“a”、 “abc”、“1234”、“1234abcd”等。 整型和浮点型常量直接写的数字,字符型常量用单引号来表示一个字符,用双引号来表示一个字符串,尤其要注意‘a’和“a”是不一样的,后边会详细介绍。 常量一般有两种表现形式。 直接常量:直接以值的形式表示的常量称之为直接常量。上述举例都是直接常量。 符号常量:用标识符命名的常量称之为符号常量,就是为上面的直接常量再取一个名字。使用符号常量一是方便理解,提高程序可读性,更重要的是方便程序的后续维护,习惯上符号常量用大写字母和下划线来命名。 比如,可以把3.14取名为PI(即π)。再比如,前边的串口程序采用的波特率是9600,如果用符号常量来进行提前声明的话,那要修改成其它速率的话,就不用在程序中找9600修改了,直接修改声明处就可以了,两种方法举例说明。 1.用const声明。比如在程序开始位置定义一个符号常量BAUD。 定义形式是:const 类型 符号常量名字=常量值; 如const unsigned int BAUD = 9600; /*注意结尾有个分号*/ 就可以在程序中直接把9600全部采用BAUD替换,这样如果要改波特率的话,直接在程序开头位置改一下这个值就可以了。 2.用预处理命令#define来完成。 定义形式是:#define 符号常量名 常量值 如#define BAUD 9600 /*注意结尾没有分号*/ 这样定义以后,只要在程序中出现BAUD的话,意思就是完全替代了后边的9600这个数字。之前定义数码管真值表的时候,用了一个code关键字。 unsigned char code LedChar[] = { //数码管显示字符转换表 0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E }; 当时说加了code之后,这个真值表的数据只能被使用,不能被改变,如果直接写LedChar[0] = 1;这样就错了。实际上code这个关键字是51单片机特有的,如果是其它类型的单片机需要写成const unsigned char LedChar[]={},自动保存到FLASH里,而51单片机只用const而不加code的话,这个数组会保存到RAM中,而不会保存到FLAHS中。 整型常量和浮点型常量比较简单,整型直接写数字,十进制如128,前边0x开头的表示是十六进制0x80,浮点型直接写带小数点的数据就可以了。 字符型常量是由一对单引号括起来的单个字符。它分为两种形式,一种是普通字符,一种是转义字符。 普通字符就是那些可以直接书写直接看到的有形的字符,比如阿拉伯数字0~9,英文字符A~z,以及标点符号等。它们都是ASCII码表中的字符,而它们在单片机中都占用一个字节的空间,其值就是对应的ASCII码值。比如‘a’的值是97,‘A’的值是65,‘0’的值是48,如果定义一个变量unsigned char a = ‘a’,那么变量a的值就是97。 除了上述这些字符之外,还有一些特殊字符,它们一些是无形的,像回车符、换行符这些都是看不到的,还有一些像’\’这类字符它们已经有特殊用途了。针对这些特殊符号,为了可以让它们正常进入到程序代码中,C语言就规定了转义字符,它是以反斜杠(\)开头的特定字符序列,让它们来表示这些特殊字符,比如用\n来代表换行。用一个简单表格来说明一下常用的转义字符的意思,如表11-1所示。 表11-1 常用转义字符及含义 字符串常量是用双引号括起来的字符序列,一般称之字符串。如“a”、“1234”、 “welcome to www.qdkingst.com”等都是字符串常量。字符串常量在内存中按顺序逐个存储字符串中的字符的ASCII码值,并且特别注意,最后还有一个字符‘\0’,‘\0’字符的ASCII码值是0,它是字符串结束标志,在写字符串的时候,这个‘\0’是隐藏的,虽然看不到,但是实际却是存在的。所以“a”就比‘a’多了一个 ‘\0’,“a”的就占了2个字节,而 ‘a’只占一个字节。 还有就是字符串中的空格,也是一个字符,比如“welcome to www.qdkingst.com”一共占了28个字节的空间。其中23个字母,2个‘.’,2个 ‘ ’(空格字符)以及一个‘\0’。 11.2.2字符和字符串数组实例定义4个数组,通过演示程序对比字符串、字符数组、常量数组的区别。 unsigned char array1[] = "1-Hello!\r\n"; unsigned char array2[] = {'2', '-', 'H', 'e', 'l', 'l', 'o', '!', '\r', '\n'}; unsigned char array3[] = {51, 45, 72, 101, 108, 108, 111, 33, 13, 10}; unsigned char array4[] = "4-Hello!\r\n"; 在串口调试助手下,发送十六进制的1、2、3、4,使用字符形式显示,分别往电脑上送这4个数组中对应的那个数组。程序只在起始位置做了区分,其它均没有区别。一方面通过串口调试助手观察,另外通过逻辑分析仪进行对比。 此外还要说明一点,数组1和数组4,数组1发完整的字符串,而数组4仅仅发送数组中的字符,没有发结束符号。串口调试助手用字符形式显示是没有区别的,但是如果改用十六进制显示,会发现数组1比数组4多了一个字节‘\0’的ASCII值00。 #include <reg52.h> bit cmdArrived = 0; //命令到达标志,即接收到上位机下发的命令 unsigned char cmdIndex = 0; //命令索引,即与上位机约定好的数组编号 unsigned char cntTxd = 0; //串口发送计数器 unsigned char *ptrTxd; //串口发送指针 unsigned char array1[] = "1-Hello!\r\n"; unsigned char array2[] = {'2', '-', 'H', 'e', 'l', 'l', 'o', '!', '\r', '\n'}; unsigned char array3[] = {51, 45, 72, 101, 108, 108, 111, 33, 13, 10}; unsigned char array4[] = "4-Hello!\r\n"; void ConfigUART(unsigned int baud); void main() { EA = 1; //开总中断 ConfigUART(9600); //配置波特率为9600 while (1) { if (cmdArrived) { cmdArrived = 0; switch (cmdIndex) { case 1: ptrTxd = array1; //数组1的首地址赋值给发送指针 cntTxd = sizeof(array1); //数组1的长度赋值给发送计数器 TI = 1; //手动方式启动发送中断,处理数据发送 break; case 2: ptrTxd = array2; cntTxd = sizeof(array2); TI = 1; break; case 3: ptrTxd = array3; cntTxd = sizeof(array3); TI = 1; break; case 4: ptrTxd = array4; cntTxd = sizeof(array4) - 1; //字符串实际长度为数组长度减1 TI = 1; break; default: break; } } } } /* 串口配置函数,baud-通信波特率 */ void ConfigUART(unsigned int baud) { SCON = 0x50; //配置串口为模式1 TMOD &= 0x0F; //清零T1的控制位 TMOD |= 0x20; //配置T1为模式2 TH1 = 256 - (11059200/12/32)/baud; //计算T1重载值 TL1 = TH1; //初值等于重载值 ET1 = 0; //禁止T1中断 ES = 1; //使能串口中断 TR1 = 1; //启动T1 } /* UART中断服务函数 */ void InterruptUART() interrupt 4 { if (RI) //接收到字节 { RI = 0; //清零接收中断标志位 cmdIndex = SBUF; //接收到的数据保存到命令索引中 cmdArrived = 1; //设置命令到达标志 } if (TI) //字节发送完毕 { TI = 0; //清零发送中断标志位 if (cntTxd > 0) //有待发送数据时,继续发送后续字节 { SBUF = *ptrTxd; //发出指针指向的数据 cntTxd--; //发送计数器递减 ptrTxd++; //发送指针递增 } } } 采用逻辑分析仪将4次收发数据全部抓出来,其中串口助手下发用HEX模式,而接收用文本模式,也就是ASCII码格式显示,逻辑分析仪也是这样配置,如图11-2所示。 图11-2 逻辑分析仪抓取串口字符和字符串信息 从图11-2可以看出,1比2、3、4多了一个结束符,其他内容4组数据是完全一致的。(CR就是\r,LF就是\n)
|