第十三届蓝桥杯嵌入式串口竞赛

目录

串口简介

区分UART、TTL、RS-232、RS-422、RS-485(客观题会考)

CUBMAX初始化

库函数讲解:(下面的好像是从b站小蜜蜂的视频里面截取下来的图片)

代码讲解: 

中断接收函数:

阻塞发送函数:

一些复杂一点的串口数据处理:

串口接收不定长数据

问题和注意事项:


串口简介

    串行通讯接口,简称串口。即数据在通信线上一次传输一位,按先后一定顺序传输。我们通常所说的单片机串口准确来说应该是串行异步收发传输器(Universal Asynchronous Receiver/Transmitter,UART),使用TTL电平。常用两根数据线,即TXD和RXD,配合GND至少需要三根线即可进行通信。以下除特殊说明,串口均指代单片机UART串口

    串口信息以数据线上的高低电平表示,高电平为1,低电平为0

图1 串口时序图

    图1为数据线上典型时序图,数据线空闲时为高电平,以一位低电平最为起始(除特殊说明,串口大部分都是一位起始位),而后以先传输低位,再传输高位的方式发送数据位,最后以高电平为数据停止位(常用1位停止位,也有2位和1.5位等)。数据位长度此处为8位,但不一定是8位,也会有7位、9位等,有时也会包含有奇偶校验位(校验位实际上就是数据的最后一位,但通常不算在数据位里)。上图所示即我们常用的8位数据位,无校验,一位停止位的串口格式

    最为异步通信接口,串口不具有时钟线,所以需要在通信双方设置数据位长度,即电平持续时间,其倒数为电平转换的频率,这一参数即为波特率(但注意,波特的概念并不是位的概念,此处按下不表)。例9600波特率即为电平改变频率为9600Hz,电平持续时间1/9600秒,则一秒最多传输9600/(1+8+1)=960个字节(不严谨,但差不多)

    因串口发送数据线与接收数据线分离,其为全双工接口,串口最少使用三根线即可完成通讯,但除这三根线外还可以有硬件流控RTS、CTS等,我没用到过,具体我也不是很清楚

区分UART、TTL、RS-232、RS-422、RS-485(客观题会考)

    UART即使用TTL电平的串口,TTL是电平形式,通常低于0.8V为低电平,高于2.4V为高电平,不是协议格式,但我们有时也常说TTL串口,以区分RS-232串口

    RS-232串口数据格式与上文介绍的UART串口基本一致,但是电平不一样,通常以-3V至-15V为逻辑1,3V-15V为逻辑0,与UART不可混接,有烧板子的风险

    RS-422常用4线制和2线制,4线制发送和接收均有两根线,两根线上为差分信号,增加传输距离,全双工。2线制的两根线上为差分信号,同时只能做为发或者收,半双工

    RS-485为422的改进版本,最少可用两根线通信,因为使用差分信号,不使用地线也可正常通信,但不建议,半双工

CUBMAX初始化

 串口需要配置的地方不多,Mode中间设置成异步通信,在配置一下波特率,停止位,效验位。一般来说只需要配置波特率就ok。

库函数讲解:(下面的好像是从b站小蜜蜂的视频里面截取下来的图片)

 *pData:发送的数据的地址

Size:发送的数据的大小

Timeout:发送数据最大时间

上图中是发送完成一半中断回调函数,不是一般。 

代码讲解: 

编写代码之前先讲几个我们需要用到的c函数;

sscanf:解析链接        可以将串口接收到的数据变成你想要的格式、样式

strcmp:解析链接        可以比较两个字符串是否一样(两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 \0 为止,所以最后需要流出一个空来告诉函数停止比较。)

memset:解析链接      可以用于将一个数组清除,比如串口接收缓存,我们接收结束就可以将他全部置0;

sprintf:解析链接          可以格式化输出

中断接收函数:

HAL_UART_Receive_IT(&huart1,Rx_Data,5);
开启中断接收函数,参数: *pData:接收的数据的存放地址        Size:接收的数据的大小
每当串口接收到Size个数据就会显示接收完成,进入中断。


unsigned char Rx_Data[20];
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	sprintf((char *)LCD_dispaly,"%5s",Rx_Data);
	 LCD_DisplayStringLine(Line4,LCD_dispaly);	
	HAL_UART_Receive_IT(&huart1,Rx_Data,5);
}

阻塞发送函数:

HAL_UART_Receive_IT(&huart1,Rx_Data,10);



unsigned char Tx_Data[20];
unsigned char Rx_Data[20];

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	sprintf((char *)LCD_dispaly,"%5s",Rx_Data);
	LCD_DisplayStringLine(Line4,LCD_dispaly);	
	
	sprintf((char *)Tx_Data,"%10s",Rx_Data);
	HAL_UART_Transmit(huart,Tx_Data,10,20);
	
	
	HAL_UART_Receive_IT(&huart1,Rx_Data,10);
}

将串口接收的数据发送到PC机

一些复杂一点的串口数据处理:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	sprintf((char *)LCD_dispaly,"%s",Rx_Data);
	LCD_DisplayStringLine(Line4,LCD_dispaly);	
	
	sscanf((char *)Rx_Data,"%3s%3s%4s",Tx_Data1,Tx_Data2,Tx_Data3);

//使用sscanf将串口接收到的数据Rx_Data里面的数据分配给Tx_Data1,Tx_Data2,Tx_Data3
//在第十二届主观题串口接收到车牌,停车时间这样多个内容的情况下就可以使用sscanf将内容分配给其他数组
	sprintf((char *)Tx_Data,"%s\r\n",Tx_Data1);
	HAL_UART_Transmit(huart,Tx_Data,5,20);
//将Tx_Data1的数据加上\r\n换行后发送到pc机,对应的Tx_Data1的数据也要加2.
	sprintf((char *)Tx_Data,"%s\r\n",Tx_Data2);
	HAL_UART_Transmit(huart,Tx_Data,5,20);
	sprintf((char *)Tx_Data,"%s\r\n",Tx_Data3);
	HAL_UART_Transmit(huart,Tx_Data,6,20);
	
	
	HAL_UART_Receive_IT(&huart1,Rx_Data,10);
}

如果我们需要连续发送数据,但是怕上一次发送的数据在Rx_Data里面残留着,会影响下一次的数据。我们就可以调用函数memset将Rx_Data清空置0;

memset(Rx_Data,0,sizeof(Rx_Data));

如果我们需要比较两个字符串的内容是否一样就可以调用strcmp函数;具体代码看上面的链接,十二届主观题比较车牌号是否一样。

需要注意的是两个字符串自左向右逐个字符相比(按 ASCII 值大小相比较),直到出现不同的字符或遇 \0 为止,所以最后需要流出一个空来告诉函数停止比较。

比如串口第一次接收到一个字符串为“ASCLL”,我们将它放到数组Rx_Data1里面,串口第一次接收到一个字符串为“world”,我们将它放到数组Rx_Data2里面,我们需要比较两个数组是不是一样的,我们需要定义数组Rx_Data1和Rx_Data2的大小是多少呢,不是5,是6。最后需要流出一个空来告诉函数停止比较。

如果我们需要对串口接收到的数字进行运算

串口接收到的数字是以ASCLL码的方式显示的,我们接收到’0‘,进行’0‘*3的时候,实际进行的操作是0x30*3。所以我们需要对接收到的数据进行处理。

u8 Data=Rx_Data[0]-'0';

对接收到的数字减去符号’0‘,得到的就是数字0~9; 

串口接收不定长数据

1.定时器

2.空闲中断+DMA

问题和注意事项:

串口接收到的数据是以askll码表示出来的

物联沃分享整理
物联沃-IOTWORD物联网 » 第十三届蓝桥杯嵌入式串口竞赛

发表评论