在文本处理中, CR, LF, CR/LF是不同操作系统上使用的换行符.
Dos和windows采用回车+换行CR/LF表示下一行,
而UNIX/Linux采用换行符LF表示下一行,
苹果机(MAC OS系统)则采用回车符CR表示下一行.
CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D;
LF使用'\n'符号表示, ASCII代码是10, 十六制为0x0A.
所以Windows平台上换行在文本文件中是使用 0d 0a 两个字节表示, 而UNIX和苹果平台上换行则是使用0a或0d一个字节表示.
一般操作系统上的运行库会自动决定文本文件的换行格式. 如一个程序在windows上运行就生成CR/LF换行格式的文本文件,而在Linux上运行就生成LF格式换行的文本文件.
在一个平台上使用另一种换行符的文件文件可能会带来意想不到的问题, 特别是在编辑程序代码时. 有时候代码在编辑器中显示正常, 但在编辑时却会因为换行符问题而出错.
很多文本/代码编辑器带有换行符转换功能, 使用这个功能可以将文本文件中的换行符在不同格式单互换.
程序功能:
编写程序初始化UART2和LED2,在PC端通过串口调试助手发送控制LED2的命令给开发板,开发板根据命令点亮或熄灭LED2。命令分别是:led2_on和led2_off,命令led2_on点亮LED2,命令led2_off熄灭LED2。(PC端发送命令时,勾选上发送新行)
串口接收和发送代码:
//发送字符
void putc(const char data)
{
while(!(UART2.UTRSTAT2 & 0X2));
UART2.UTXH2 = data;
if (data == '\n') //不需要,按实际字符发送即可
putc('\r');
}
//发送字符串
void puts(const char *pstr)
{
while(*pstr != '\0')
putc(*pstr++);
}
//接收字符
unsigned char getchar()
{
unsigned char c;
while(!(UART2.UTRSTAT2 & 0X1));
c = UART2.URXH2;
return c;
}
//接收字符串,PC端发送字符串时,选择了发送新行,4412端接收新行的顺序依次是0D 0A(16进制显示,分别表示回车符'\r'和换行符'\n'),下面的代码会导致换行符OA没有从串口接收缓存中取出,等下一次接收字符串时才被取出,放在最前面,从而导致比较控制命令时,和预定义的命令不符,使得LED2不受控。需要按照接收顺序修改程序!
void gets(char *p)
{
char data;
while((data = getchar())!= '\r')
*p++ = data;
if(data == '\r')
*p++ = '\n';
*p = '\0';
}
//比较字符串
int strcmp(const char *src, const char *des)
{
while(*src || *des)
{
if(*src > *des)
return 1;
else if(*src < *des)
return -1;
else
{
src++;
des++;
}
}
return 0;
}
int main()
{
char ch[20];
led2_init();
uart2_init();
char *q = "hello UART2!";
puts(q);
while(1)
{
gets(ch);
puts(ch);
if(!strcmp(ch, "led2_on\n")) //需要修改,预定义命令改为"led2_on\r\n"
GPX2.GPX2DAT |= 0x1 << 7; //Turn on LED2
if(!strcmp(ch, "led2_off\n")) //需要修改,预定义命令改为"led2_off\r\n"
GPX2.GPX2DAT &= ~(0x1 << 7); //Turn off LED2
}
return 0;
}
实际测试:
发送:led2_on
PC端串口助手接收窗口:
ASCII显示收到led2_on
16进制显示,第一次收到: 6C 65 64 32 5F 6F 6E 0A 0D
第二次收到:0A 0D 6C 65 64 32 5F 6F 6E 0A 0D(相比第一次前面多了OA OD),造成LED2不受控(存储的命令不对,有多余的字符OA OD)
回车符CR用符号'\r'表示, 十进制ASCII代码是13, 十六进制代码为0x0D; 换行符LF使用'\n'符号表示, ASCII代码是10, 十六制为0x0A.
发送led2_off也一样。
修改后代码:
//发送字符
void putc(const char data)
{
while(!(UART2.UTRSTAT2 & 0X2));
UART2.UTXH2 = data;
//if (data == '\n') //不需要,按实际字符发送即可
//putc('\r');
}
//接收字符串
void gets(char *p)
{
char data;
while((data = getchar())!= '\n') //在接收'\n'之前,已经接收了'\r',按实际的字符顺序接收
*p++ = data;
if(data == '\n')
*p++ = '\n';
*p = '\0';
}
或者改为:
//接收字符串
void gets(char *p)
{
char data;
while(1)
{
*p++ = getchar();
if (*(p-1) == '\n') //在接收'\n'之前,已经接收了'\r'
break;
}
*p = '\0';
}
int main()
{
char ch[20];
led2_init();
uart2_init();
char *q = "hello UART2!";
puts(q);
while(1)
{
gets(ch);
puts(ch);
if(!strcmp(ch, "led2_on\r\n")) //这里预定义命令做了修改,增加了'\r'
GPX2.GPX2DAT |= 0x1 << 7; //Turn on LED2
if(!strcmp(ch, "led2_off\r\n")) //这里预定义命令做了修改,增加了'\r'
GPX2.GPX2DAT &= ~(0x1 << 7); //Turn off LED2
}
return 0;
}
由于不同系统中对回车换行的处理不一样,所以容易弄错。这里可以将预定义命令改为“led2_on#”和“led2_off#”,在4412端只要判断有没有收到'#',若收到,则表明一条完整的控制命令结束;没收到,则继续从串口接收字符。这样就避免回车换行符的困扰。
评论0