大家好,我是『芯知识学堂』的SingleYork,前一篇文章给大家介绍了“【STC15系列】SYK-0806-A2S1 工业自动化控制之【13-串口收发单个字符】”,
这一篇中,笔者继续给大家介绍“串口收发字符串”。
相信很多小伙伴对单个字符的收发是很熟悉了,那么如何实现字符串的收发呢?
首先,我们先来看一下字符串在单片机中是如何存储的。
比如,我们要存储一个字符串“Helloworld”到数组Arry[]中,那么,它在Arry[]这个数组中实际上是按如下方式来存储的:
Arry[0] = ‘H’;
Arry[1] = ‘e’;
Arry[2] = ‘l’;
Arry[3] = ‘l’;
Arry[4] = ‘o’;
Arry[5] = ‘w’;
Arry[6] = ‘o’;
Arry[7] = ‘r’;
Arry[8] = ‘l’;
Arry[9] = ‘d’;
Arry[10] = ‘\0’;
其中,’\0’就是字符串的结束符,也就是说,我们想要存储“Helloworld”到数组Arry[],实际上需要占用11个字节。
那么我们在定义数组Arry[]并赋值的时候,就应该是:Arry[11] = {“Helloworld”},
或者是不指定数组长度,直接这样写也是可以的:Arry[] = {“Helloworld”}。
明白了这一点,那就好办了!接下来我们分析一下单片机接收字符串需要注意些什么。
如果是接收指定长度的字符串,相信大家都知道该怎么处理,定义一个一维数组用来存放将要接收到的字符串,
从数组的0号元素开始存放,直到接收完指定个长度后接收完成。
这样比较简单,笔者就不多说了,笔者要跟大家介绍的是接收不定长度的字符串。那么这个不定长度的字符串要怎么处理呢?
我们一般的做法是,在字符串末尾加一个特定的结束符,一般是用“回车换行符”来作为结束符,
当然我们也可以用“空格”或其他特定符号来作为结束符,
本例中, 笔者是通过“回车换行符”来作为字符串的结束符。
废话不多说,我们直接来看代码,本例代码还是在上一讲基础上做修改,其他部分代码都不需要修改,只需要修改app.c里面的内容即可。
首先,因为我们后面有用到,strstr(char *str1, const char *str2)和memset(void *s, int ch, size_t n)这两个函数,
所以我们需要在app.c文件中添加string.h头文件:
- #include "app.h"
- #include "string.h"
复制代码
接下来,定义变量Uart1_RX_Finish 和Uart1_TX_EN,分别作为uart1数据接收完成标志和uart1发送数据使能标志:
- bit Uart1_RX_Finish = 0;//Uart1数据接收完成标志,1 为接收完成
- bit Uart1_TX_EN = 0;//Uart1发送数据使能标志
复制代码
然后,就是app_init()函数了,主要是对GPIO和UART的初始化:
- void app_init(void)
- {
- UART_config(); //UART初始化
- GPIO_Config(); //GPIO初始化
-
- EA = 1; //开启总中断
- }
-
复制代码
字符串接处理及接收完成的判断是在“UART1中断函数”中,笔者这里是以收到“回车换行符”来作为字符串结束判断:
- /********************* UART1中断函数************************/
- void UART1_int (void) interrupt UART1_VECTOR
- {
- if(RI)
- {
- RI = 0;
-
- if(COM1.RX_Cnt >= COM_RX1_Lenth) COM1.RX_Cnt = 0;
- RX1_Buffer[COM1.RX_Cnt++] = SBUF;
-
- if((RX1_Buffer[COM1.RX_Cnt-2]=='\r')&&(RX1_Buffer[COM1.RX_Cnt-1]=='\n'))
- {
- //以“回车换行符”为结束标志
- Uart1_RX_Finish = 1; //将接收完成标志位置1
- COM1.TX_write = 0;
- }
- }
-
- if(TI)
- {
- TI = 0;
- COM1.B_TX_busy = 0;
- }
- }
复制代码
当字符串接收完成后,将标志位Uart1_RX_Finish 置“1”,同时进入app_run()函数中处理接收到的数据:
- void app_run(void)
- {
- if(Uart1_RX_Finish)
- {
- if(!Uart1_TX_EN)
- {
- //根据收到的指令执行相应的动作
- if(strstr((char *)RX1_Buffer,"Y00_ON\r\n")!=NULL) //若两字符串相等
- {
- Y00 = OutputT_ON;
- }
- else if(strstr((char *)RX1_Buffer,"Y00_OFF\r\n")!=NULL)
- {
- Y00 = OutputT_OFF;
- }
- Uart1_TX_EN = 1;//uart1发送数据使能置“1”,准备开始发送数据
- }
-
- if(COM1.TX_write<COM1.RX_Cnt)
- {
- if(COM1.B_TX_busy == 0)
- {
- COM1.B_TX_busy = 1;
- SBUF = RX1_Buffer[COM1.TX_write++]; //发送接收到的字符
- }
- }
- else
- {
- COM1.RX_Cnt = 0;
- Uart1_RX_Finish = 0;
- Uart1_TX_EN = 0;//数据发送完成,uart1发送数据使能清“0”
-
- memset(RX1_Buffer,NULL,sizeof(RX1_Buffer));//清空RX1_Buffer数组
- }
- }
- }
复制代码
这部分代码主要分为两个功能,一部分就是对接收到的字符串执行相关的动作,比如:
在收到字符串"Y00_ON\r\n"时,Y00输出ON;
在收到字符串"Y00_OFF\r\n"时,Y00输出OFF;
- if(strstr((char *)RX1_Buffer,"Y00_ON\r\n")!=NULL) //若两字符串相等
- {
- Y00 = OutputT_ON;
- }
- else if(strstr((char *)RX1_Buffer,"Y00_OFF\r\n")!=NULL)
- {
- Y00 = OutputT_OFF;
- }
复制代码
这里用到了一个strstr(char *str1, const char *str2)函数,用来查找字符串,具体功能如下:
- 函数原型:
- extern char *strstr(char *str1, const char *str2);
-
- 语法:
- * strstr(str1,str2)
- str1: 被查找目标 string expression to search.
- str2: 要查找对象 The string expression to find.
- 返回值:若str2是str1的子串,则返回str2在str1的首次出现的地址;如果str2不是str1的子串,则返回NULL。
复制代码
第二部分的功能,就是将收到的字符串返回到串口助手,在发送完成之后,清零相关变量和数组:
- if(COM1.TX_write<COM1.RX_Cnt)
- {
- if(COM1.B_TX_busy == 0)
- {
- COM1.B_TX_busy = 1;
- SBUF = RX1_Buffer[COM1.TX_write++]; //发送接收到的字符
- }
- }
- else
- {
- COM1.RX_Cnt = 0;
- Uart1_RX_Finish = 0;
- Uart1_TX_EN = 0;//数据发送完成,uart1发送数据使能清“0”
-
- memset(RX1_Buffer,NULL,sizeof(RX1_Buffer));//清空RX1_Buffer数组
- }
复制代码
这部分有用到一个memset(void *s, int ch, size_t n)来快速清零数组RX1_Buffer,关于该函数的具体功能如下:
- void *memset(void *s, int ch, size_t n);
-
- 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
-
- memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 [1] 。
-
- memset()函数原型是extern void *memset(void *buffer, int c, int count)
- 其中,buffer:为指针或是数组,c:是赋给buffer的值,count:是buffer的长度.
复制代码
好了,关于使用本节内容笔者就介绍到这里了,有疑问的小伙伴们可以给笔者留言或者直接参与评论,
下一节笔者将继续给大家介绍“串口的基本使用”,详见“SYK-0806-A2S1 工业自动化控制之【15-串口收发十六进制数】”,感谢大家的支持!
本章附件:
【STC15系列】SYK-0806-A2S1- 14-串口收发字符串.rar
(70.16 KB, 下载次数: 2)
|