STM32 UART串口通信详解:接收与发送HEX与文本数据的代码实践
UART串口通信
一 UART通信原理
本章介绍UART原理与配置方式
1 UART基本介绍
(1) 原理
异步传输方式:UART通信采用异步传输
方式,即发送端和接收端不需要通过时钟线
来同步数据传输。双方只需约定相同的波特率(每秒传输的位数),就可以进行数据通信。
(2) 数据帧结构:
UART通信的数据帧通常由起始位
、数据位
、可选的奇偶校验位和停止位
组成。
8位
;(3) 通信过程
发送过程:当需要发送数据时,发送端首先将待发送的并行数据
转换为串行数据
,然后按照约定的波特率
将数据逐位发送到数据线上。在发送数据之前,发送端会先发送一个起始位
,表示数据帧的开始,然后依次发送数据位
、可选的奇偶校验位
和停止位
。数据发送完毕后,发送端会等待接收端的确认信号(如果有的话),或者继续发送下一个数据帧。
接收过程:接收端在接收数据时,会不断检测数据线上的信号变化。当检测到起始位
时,接收端开始以约定的波特率对数据进行采样
,并将采样得到的数据位存储起来。接收完所有数据位后,接收端会根据奇偶校验位(如果有的话)对数据进行校验
,以确保数据传输的正确性。如果校验通过,接收端将接收到的数据转换为并行数据,并交给后续的处理程序进行处理;如果校验失败,接收端可能会请求发送端重新发送数据帧。
(4) 应用场景
常用于简单的异步串口通信应用,如与外围设备的基本通信、蓝牙模块与微控制器通信、GPS模块
与计算机之间的数据传输、调制解调器与计算机之间的串行通信等,一种简单实用的异步串口通信协议,适合基本
的通信需求
。另外使用微控制器对外设进行控制调试时,有很大的帮助。
波特率:波特率表示单位时间内通过线路传输的二进制数据的位数,通常用bps(bits per second)表示。例如,如果波特率为9600bps,则每秒钟可以传输9600个比特位的数据。
2 配置方式
在STM32 中,使用串口通信
来控制外设
通常涉及以下几个步骤:初始化串口、配置中断、编写接收和发送数据的函数
接线比较简单,以USB转串口模块连接stm32f103c8t6为例:(不同开发板需要 对照引脚图,选择合适的引脚,合适的引脚也未必只有一对
,这里以A10A9为例)
STM32提供的RX TX接口 | 开发板 | USB转串口 |
---|---|---|
uart1_TX | A9 | RX |
uart1_RX | A10 | TX |
<1> 初始化串口配置
我们不需要从通信协议开始编写,使用stm32提供的串口设置进行更改,然后在各种串口助手软件中,对应参数修改一致即可成功连接。重点关于起始位,波特率,数据位,停止位
的设置。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX初始-A9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //RX初始-A10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART赋值结构体
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx| USART_Mode_Rx; //模式设置
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶效验
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据长度
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE); //选中串口
<2> 打开中断
使用串口通信进行调试时,更加方便。
/*中断输出配置*/
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接收数据的中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择配置NVIC的USART1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
二 收发数据函数编写
本章介绍如何实现向串口收发数据,并简单介绍printf重定向
1 向串口发送数据
标准库已提供:使用UART发送1字节数据函数
USART_SendData(USART1,Byte);
基于此可简单设计处发送:字节,数组,字符串,数字/变量
等基础操作,不在赘述。
STM32 提供
USART
模式,但USART 模块可以通过配置寄存器
来选择工作在 UART 模式还是 USART 模式
UART:仅支持异步通信模式,没有共享时钟信号
,发送方和接收方通过预设的波特率来保持同步。
USART:支持同步和异步两种通信模式,既可以像UART一样以异步方式工作,也可以在同步模式下通过共享时钟信号
来实现更精确的数据同步
2 调试优化之:printf重定向
本节简介重定向原因 与 可变参数列表知识
(1) 重定向原因
虽然由上一点可以设计出多个功能分离的发送函数,但分化太多会显得有点啰嗦,用起来并不方便。而如果能使用printf的输出方式,则非常的简单,一行语句就可以控制输出复杂的格式
,printf 是一个功能强大且使用广泛简单的格式化输出函数。
并且printf支持通过重写一些操作,把输出内容重定向
到串口
。于是就可以直接在串口调试助手
中查看
程序的运行结果
和变量的值。无需频繁地下载程序或使用其他复杂的调试工具,大大提高了调试效率。
重定向方法:通过重写fputc函数,将printf的输出重定向到UART串口。
注意:需要头文件 stdio,和stdarg
(2) 涉及stdarg.h宏简介
stdarg.h
头文件中提供了一些宏和类型定义,允许编写可接受可变数量参数
的函数。在stm32串口通信中,常常需要实现类似 printf 这样的可变参数函数,以便能够方便地输出各种不同类型的数据。通过使用 stdarg.h 中的宏,如 va_start
、va_arg
和 va_end
等,可以在函数内部获取和处理可变数量的参数,从而实现灵活的数据处理和输出。
va_list:用于声明一个指向可变参数列表的指针
类型变量
。该变量通常用于存储可变参数列表中的参数信息。
va_start:初始化va_list类型的变量,使其指向可变参数列表的第一个参数。它需要两个参数va_start(a,b),第一个是va_list类型
的变量,第二个是最后一个固定参数的地址。
va_arg:获取可变参数列表中的下一个参数
,并将其转换为指定类型。它需要两个参数,第一个是va_list类型的可变参数列表指针,第二个是要获取的参数的类型。调用va_arg后,可变参数列表指针会自动指向下一个参数。
va_end:结束
可变参数列表的访问
,清理va_list类型的变量,以便该变量可以被再次使用。
3 接收串口数据
(1) HEX模式:单个变量
可用于控制单个外设
的打开
与关闭
,如:收到串口数据0,关闭外设;收到1打开外设;亦或则是收到3打开更多模式等,有助于调试外设模块,比起来在单独接一个开关模块,要方便
并且稳定快速
的多,可供选择的模式也更加丰富。
核心代码:
//从串口接收一个数据,返回值类型为uint16_t
USART_ReceiveData(USART1);
将此代码放在中断函数中,每次收到数据后,将数据保存下来
即可,可以用全局变量保存,并写一个简单的函数,获取这个变量的值即可。
/*
功能:接受串口发送的单个整数数据,可以用串口控制外设
参数:串口HEX模式,输入一个值发送,可用该函数接收
解释:接收到串口数据的值,(文本格式也测试,但无法保存,仅能查看)
方便调试,如 0 关闭外设,1打开外设,简化接线
返回: 根据具体输入有关,若无输入,则-1表示无输入,常用01即可
**HEX模式请发送 2位数据,如发送0为:0x00 ,并非是整数格式,只是0x省略了而已**
*/
int Serial_RXInt(void){
if(receive_int!=-1){ //检测到输入
int tem=receive_int;
receive_int=-1;
return tem;
}
return -1; //未检测到输入
}
(2) HEX模式:一次接收一数组存储
当我们需要同时设置多个外设
的模式时,只发单个值已不能满足需求,可以自定义一种特殊的发送格式
,加上起始判断与结束位判断,保留中间从串口接收的数据,并将这些数据保存在一个全局数组中即可。对于多为数据的存储方式,使用不同的flag状态处理。(万能的fllag)。最后在设置一个全局标记,用于记录是获取到了串口数据,及时更新即可。
核心代码:
uint8_t receive[4]; //值:从串口接受的数组数据(限定4元素)
int receive_arry; //标记:是否从串口收到完整数组
static uint8_t RxState = 0;//状态标记
static uint8_t k = 0 ; //数组下标
//--------------------核心部分,此处在触发中断后执行-------------
if(RxState==0){
if(RX_data==0xFF){ //接受数组:数组RxState状态-012
RxState=1;
k=0;
}else
receive_int=RX_data; //单个数据 不需要状态
}else if(RxState==1){
receive[k++]=RX_data;
if(k>=4) //修改K最大的值与 receive 数组下标,可修改一次发送的数据量
RxState=2;
}else if(RxState==2){
if(RX_data==0xFE){ //次数必须有条件限制
RxState=0;
receive_arry=1;
}
}
根据标记值,判断是否收到数据:
/*
功能:确定串口是否发送了数组数据,数据保存在receive[]全局数组
参数:串口发送格式:FF开头,FE结尾,中间4个数,如:FF 00 01 02 03 FE
解释:方便多个外设调试,如FF 00 01 00 01 FE,一键设定4个外设状态
返回: 1表示输入完成存入receive数组,0表示未成功接收
**HEX模式请发送 2位数据,如发送0为:0x00 ,并非是整数格式,只是0x省略了而已**
*/
int Serial_RXArry(void){
if(receive_arry){ //检测到输入
receive_arry=0;
return 1;
}
receive_arry=0;//常态位0
return 0; //未检测到输入
}
(3) 文本模式:接收字符串
可以用一个字符口令
控制外设开关,如:Turn on
,Turn off
等等,更有利于观察理解。实现原理同上述数组,只不过开始标志与结束标志换成字符而已。核心代码:
uint8_t receive[4]; //值:从串口接受的数组数据(限定4元素)
int receive_arry; //标记:是否从串口收到完整数组
//----------------------中断函数内部-----------------------
if(RX_data == '@'){ //接受文本:状态-0 11 12 ,与数组区分
RxState=11;
k=0; //文本和数组,同时只有一个占用
}else if(RxState==11){
if (RX_data == '#') //以输入#判定结束,开始与结束不要相同
RxState = 12; //因为字符串没有长度限制,只能设定标记
else
text[k++] = RX_data;
}else if(RxState==12){
if (RX_data == '#'){ //*此处一定有条件限制,否则进入RxState12状态后
RxState=0; //会无限进入此处if语句
text[k]='\0';
receive_text = 1;
k=0;
}
}
同理,判断是否收到数据:
/*
功能:确定串口是否发送了文本数据,数据保存在字符数组text[]
参数:数组格式:@开头,##结尾,中间为文本内容,支持空格换行。如:@sample test@
解释:可以用英文口令控制外设开关,如:turn on,turn off,使用strcmp匹配判断相等
返回: 1表示输入完成存入text数组,0表示无输入
*/
int Serial_RXString(void){
if(receive_text){ //检测到输入
receive_text=0;
return 1;
}
receive_text=0;//常态为0
return 0; //未检测到输入
}
最后把接收
单个字符
,数组
,与文本
的判断全部组合在一起,互不影响就可以完成基础功能 完善的串口通信模板。
三 完整代码
按需取用
1 封装.h文件
#ifndef __SERIAL_H
#define __SERIAL_H
/*接线:
开发板 USB转串口
(uart1_TX) A9 -> RX
(uart1_RX) A10 -> TX
*/
//串口接收数据保存位置
extern uint8_t send[4]; //封装要发送的数组,Serial_SendPacket() 快速发送
extern uint8_t receive[4]; //从RX接收的4元素数组,方便调试多个外设
extern char text[100]; //从RX接收的字符串
//串口发送
void Serial_Init(void);
void Serial_SendByte(u8 Byte);
void Serial_SendArray(u8 *Array,u16 Length);
void Serial_SendPacket(void); //快速发送send[]数组,提供全局send[]数组
void Serial_SendString(char *String); //串口输出中文时,确定好UTF-8与GBK格式
u32 Serial_Pow(u32 X,u32 Y);
void Serial_SendNumber(u32 Number,u8 Length);
void Serial_Printf(char *format,...); //printf重定向,用法同printf
//串口接收
int Serial_RXInt(void); //收到单个HEX数据
int Serial_RXArry(void); //收到连续4个HEX数据,1表示receive已存入全局数组
int Serial_RXString(void); //收到文本数据
#endif
2 封装.c文件
#include "stm32f10x.h"
#include <stdio.h> //用于printf函数
#include <stdarg.h> //用于printf重定向
uint8_t send[4]; //向串口打包发送的数据
int receive_int; //值:从串口接受的单个数据
uint8_t receive[4]; //值:从串口接受的数组数据(限定4元素)
int receive_arry; //标记:是否从串口收到完整数组
char text[100]; //值:从串口收到的文本 (限定100长度)
int receive_text; //标记:是否从串口收到文本
//初始化引脚,与配置内部UART
void Serial_Init(void)
{
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1的时钟
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //TX初始
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure);
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //RX初始
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
//USART赋值结构体
USART_InitTypeDef USART_InitStructure;
USART_InitStructure.USART_BaudRate = 9600; //波特率
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Tx| USART_Mode_Rx; //模式设置
USART_InitStructure.USART_Parity = USART_Parity_No; //奇偶效验
USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//数据长度
USART_Init(USART1,&USART_InitStructure);
USART_Cmd(USART1,ENABLE); //选中串口
/*中断输出配置*/
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); //开启串口接收数据的中断
/*NVIC中断分组*/
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //配置NVIC为分组2
/*NVIC配置*/
NVIC_InitTypeDef NVIC_InitStructure; //定义结构体变量
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; //选择配置NVIC的USART1线
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //指定NVIC线路使能
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //指定NVIC线路的抢占优先级为1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //指定NVIC线路的响应优先级为1
NVIC_Init(&NVIC_InitStructure); //将结构体变量交给NVIC_Init,配置NVIC外设
}
//向串口发送数据,以字节发送
void Serial_SendByte(u8 Byte)
{
USART_SendData(USART1,Byte);
while (USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
/*下次写入数据寄存器会自动清除发送完成标志位,故此循环后,无需清除标志位*/
}
//数组名,长度
void Serial_SendArray(u8 *Array,u16 Length)
{
u16 i;
for ( i = 0; i < Length; i++)
{
Serial_SendByte(Array[i]);
}
}
//发字符串
void Serial_SendString(char *String)
{
u8 i;
for(i=0; String[i]!='\0'; i++) // 以'\0'位结尾
{
Serial_SendByte(String[i]);
}
}
//发数字,x的y次方
u32 Serial_Pow(u32 X,u32 Y) //2 3
{
u32 Result = 1;
while(Y--) //3--
{
Result *= X; //1*2 *2 *2 = 2^3
}
return Result;
}
//发一个数字,然后是数字位数
void Serial_SendNumber(u32 Number,u8 Length)
{
u8 i;
for ( i = 0; i < Length; i++)
{
/*
(Number / Serial_Pow(10,i) % 10) 1234/1%10=4 1234/10%10=3 1234/100%10=2
(Number / Serial_Pow(10, Length - i -1) % 10)
*/
Serial_SendByte((Number / Serial_Pow(10,Length - i - 1) % 10) + '0');
}
}
/*printf重定向,可通过重写fputc函数,将printf的输出重定向到USART串口。
(0) printf原理:用于向标准输出设备(通常是屏幕)打印格式化文本,带缓冲区。
(1) 头文件 stdio,和stdarg
(2) 通过重写fputc函数,将printf的输出重定向到USART串口
功能:将ch传递Serial_SendByte,发送到串口
参数1:要发送的字符。它是一个整数类型,但通常表示为一个字符(例如 'A'、'B' 等)
参数2:FILE *f: 这是一个指向文件结构体的指针。没用,为了符合标准库函数的格式签名
*/
int fputc(int ch,FILE *f)
{
Serial_SendByte(ch);
return ch;
}
/*实现可变参数列表
stdarg.h宏:va_list、va_start、va_arg和va_end,遍历并获取参数值
*/
void Serial_Printf(char *format,...)
{
char String[100];
va_list arg; //声明指针变量arg(可变参数列表)
va_start(arg,format); //初始化指针,指向初始位置
vsprintf(String,format,arg); //处理好后的文本存储到strring,arg引导下一项
va_end(arg); //结束访问
Serial_SendString(String);
}
/*
功能: 封装发数据包,设置一固定全局数组send,方便修改与发送
参数:-
解释:部分串口软件 HEX模式不方便换行,长度取一个4便于观察
FF 与 FE 一般 用不到,所以作开始和结束符号
*/
void Serial_SendPacket(void){
Serial_SendByte(0xFF); //开始
Serial_SendArray(send,4); //可修改调整send数组下标 与 该处数字4
Serial_SendByte(0xFE);
}
/*
功能:接受串口发送的单个整数数据,可以用串口控制外设
参数:串口HEX模式,输入一个值发送,可用该函数接收
解释:接收到串口数据的值,(文本格式也测试,但无法保存,仅能查看)
方便调试,如 0 关闭外设,1打开外设,简化接线
返回: 根据具体输入有关,若无输入,则-1表示无输入,常用01即可
**HEX模式请发送 2位数据,如发送0为:0x00 ,并非是整数格式,只是0x省略了而已**
*/
int Serial_RXInt(void){
if(receive_int!=-1){ //检测到输入
int tem=receive_int;
receive_int=-1;
return tem;
}
return -1; //未检测到输入
}
/*
功能:确定串口是否发送了数组数据,数据保存在receive[]全局数组
参数:串口发送格式:FF开头,FE结尾,中间4个数,如:FF 00 01 02 03 FE
解释:方便多个外设调试,如FF 00 01 00 01 FE,一键设定4个外设状态
返回: 1表示输入完成存入receive数组,0表示未成功接收
**HEX模式请发送 2位数据,如发送0为:0x00 ,并非是整数格式,只是0x省略了而已**
*/
int Serial_RXArry(void){
if(receive_arry){ //检测到输入
receive_arry=0;
return 1;
}
receive_arry=0;//常态位0
return 0; //未检测到输入
}
/*
功能:确定串口是否发送了文本数据,数据保存在字符数组text[]
参数:数组格式:@开头,##结尾,中间为文本内容,支持空格换行。如:@sample test@
解释:可以用英文口令控制外设开关,如:turn on,turn off,使用strcmp匹配判断相等
返回: 1表示输入完成存入text数组,0表示无输入
*/
int Serial_RXString(void){
if(receive_text){ //检测到输入
receive_text=0;
return 1;
}
receive_text=0;//常态为0
return 0; //未检测到输入
}
/*
功能:USART1中断函数
参数:无
解释:中断函数,无需调用,中断触发后自动执行,请确保函数名正确
*UART通信格式:USART_ReceiveData返回输入的值。
内含有对于RX数据的接收:含单个数据,4元素数组,与字符串文本
注意:在不同的RxState状态模式下,每当进入一个新的RxState状态,内部必须有条件限制
否则将会无限进入此状态分支,造成错误与延时
*/
void USART1_IRQHandler(void)
{
static uint8_t RxState = 0;//状态标记
static uint8_t k = 0 ; //数组下标
if(USART_GetITStatus(USART1, USART_IT_RXNE) == SET){ //判断是否是USART1的接收事件触发的中断
uint8_t RX_data = USART_ReceiveData(USART1); //存放接受的数据
if(RxState==0){
if(RX_data==0xFF){ //接受数组:数组RxState状态-012
RxState=1;
k=0;
}
else if(RX_data == '@'){ //接受文本:状态-0 11 12 ,与数组区分
RxState=11;
k=0; //文本和数组,同时只有一个占用
}else
receive_int=RX_data; //单个数据 不需要状态
}else if(RxState==1){
receive[k++]=RX_data;
if(k>=4) //修改K最大的值与 receive 数组下标,可修改一次发送的数据量
RxState=2;
}else if(RxState==2){
if(RX_data==0xFE){ //次数必须有条件限制
RxState=0;
receive_arry=1;
}
}else if(RxState==11){
if (RX_data == '#') //以输入#判定结束,开始与结束不要相同
RxState = 12; //因为字符串没有长度限制,只能设定标记
else
text[k++] = RX_data;
}else if(RxState==12){
if (RX_data == '#'){ //*此处一定有条件限制,否则进入RxState12状态后
RxState=0; //会无限进入此处if语句
text[k]='\0';
receive_text = 1;
k=0;
}
}
USART_ClearITPendingBit(USART1, USART_IT_RXNE); //清除标志位
}
}
3 main函数测试demo
#include "stm32f10x.h" // USE_STDPERIPH_DRIVER
#include "delay.h"
#include "Serial.h"
#include "OLED.h" //可不加
int main(void)
{
Serial_Init();
/*基本测试
//1 TX发送 测试
Serial_SendByte(127);
uint8_t a[]={1,2,3,4,5,6,7,8,9};
Serial_SendArray(a,3);
Serial_SendString("给我输中文,混蛋\r\n");
Serial_SendNumber(i,2);
for(int i=0; i<4;i++)
send[i]=i;
Serial_SendPacket(); //封装发送
//2 几种流输入输出
char c[20];
int a=1010,b=99;
printf("a=%d,b=%d\r\n",a,b); //一处
sprintf(c,"num3 a=%d,b=%d \r\n",a,b); //格式转化
Serial_SendString(c);
Serial_Printf("a=%d,b=%d \r\n",a,b); //重定位printf
Serial_Printf("如果我说你是我的太阳\r\n");
*/
while(1){
//串口输入测试
//HEX模式,串口软件中:直接输入单个数据,点击发送
int t1=Serial_RXInt(); //收到的单个HEX数据
if(t1!=-1)
Serial_SendByte(t1);
//HEX模式,串口软件中:输入一组4个数据,可用于控制多个外设
//格式:FF 01 02 03 04 FE
if(Serial_RXArry()){ //HEX数组4元素
Serial_SendByte(0xFF);
Serial_SendArray(receive,4);
Serial_SendByte(0xFE);
}
//文本模式, 输入字符串格式:@文本内容##
if(Serial_RXString()){ //文本
Serial_SendString("Text:");
Serial_SendString(text);
Serial_SendString("\r\n");
}
}
}
4 测试图
(1)接受串口发送的单个字符(收到后通过串口软作显示,下同)
(2) 接受来自串口的多个数据(点击了多次)
(3) 接收文本数据
作者:riversuer