嵌入式开发—串口通信

1 概述

1.1 串口通信是什么

串口通信是指外部设备与主控芯片之间,通过数据信号线、地线等,按位进行数据传输的一种通信方式,属于串行通信方式。串行通信是指使用一条数据线依次逐位传输数据,每一位数据占据固定长度的时间。可以看一下简单的串行通信示意图。

串行通信示意图

串口通信只需几条线即可在两个系统间交换信息,特别适用于计算机与计算机、计算机与外设之间的通信,常用的串口通信接口标准有很多,比如RS-232C、RS-232、RS-485等。

但是放在单片机开发里,最简单的串口通信就是用四根线VCC、GND、TXD和RXD实现通信。

串口通信接线图
一般串口通信是一种异步半双工的通信方式,当然也有同步的,也有全双工的。至于这些都是什么意思,大家可以自行搜索一下。

1.2 波特率

引用专业的说法,波特率表示单位时间内传送的码元符号的个数,它是对符号传输速率的一种度量。其实意思就是波特率表示1s内传输码元的个数。在单片机中数字都是二进制的01表示的,所以波特率可以说是1s内传输01的个数。常见的波特率有38400、9600和115200等。

1.3 串口通信的用途

串口通信的用途有很多,这里只是简单分享一下博主接触到的用途。首先就是最简单的单片机与外设的通信,其次上位机与单片机的通信也可以通过串口通信。比如利用上位机通过串口给单片机烧写程序。其他还有接触到串口转高速红外,利用红外给单片机烧写程序。

2 串口收发

2.1 波特率发生器

串口要想实现收发首先要有波特率发生器,网上介绍波特率发生器的作用是输入时钟转换出需要的波特率CLK。个人理解,波特率发生器就是提供一个时钟,这样才能发送出正确波特率的信息,比如1和0需要多久的高/低电平表示。

在串口通信时如果收发双方波特率不相同会导致通信失败,要么是接收不到,要么是接收到的是乱码。

扫描二维码关注公众号,回复: 15258728 查看本文章

2.2 收发FIFO

其实FIFO可以理解成一个水管,先进先出,后进后出,用来存储要发送或者接收的信息。或者干脆拿数组做收法内容的存储也可以。

博主接触到的芯片收发FIFO是共用的。比如CPU想通过串口发送信息给外设,需要发送的内容会先送进FIFO,然后发送给外设。通常会有FIFO非空中断、FIFO全满中断或者FIFO半满中断这些,用来告知CPU某一时刻FIFO的状态。

2.3 DMA

其实在串口收发是DMA算是老朋友了。主要原因是使用DMA不需要CPU的干预,这样CPU就可以去处理别的事务,可以提高系统的效率。

通常在准备发送数据时会可以触发DMA,DMA将需要发送的数据直接搬运到发送的寄存器。在需要接收时会触发接收中断,也可以配置DMA,直接将接收数据搬运到内存。也可以根据DMA中的TCNT寄存器来观察数据是否搬运完成。但是值得注意的是,DMA搬运完成并不代表接收或者发送完成,个人觉得还是要看FIFO的状态才能判断此时是否收发完成。

3 串口收发程序设计

这里以STM32为例简单介绍一下串口收发的程序设计。

3.1 串口发送数据

//串口发送函数
void USART1_Send(u8*str)
{
    
    
	u8 index=0;
	do
	{
    
    
		USART_SendData(USART1,str[index++]);
		while(USART1,str[index++]);
		while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET);
	}
	while(str[index]!=0);
}

其实这里最根本的USART_SendData()本质就是将数据搬运到串口发送的寄存器。

当然除了直接用发送函数发送,也可以直接重定向之后用printf发送,这里就不详细介绍了,有需要的友友可以直接去看普中或者正点的教程视频。

3.2 串口接收

串口接收一般是在中断中进行,比如接收到消息时会有一个串口接收中断,此时会在接收中断的中断服务函数中接收数据。

u32 receCount = 0;   // 接收计数变量
u32 clearCount = 0;   // 清空接收数组计数变量
u8 receFifo[1500];   // 接收数组
u8 receEndFlag = 0;   // 接收完成标志位

void USART1_IRQHandler(void)  
{
    
    
	if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)   //接收到一个字节  
	{
    
    
		receFifo[receCount++] = USART_ReceiveData(USART1);
	}
	else if(USART_GetITStatus(USART1,USART_IT_IDLE) != RESET)   //接收到一帧数据
    {
    
    
		USART1->SR;//先读SR
		USART1->DR;//再读DR
		
		receEndFlag = 1;   // 接收完成标志置1 
    }  
}

需要注意的是在解析完接收函数后要对接收数据进行清0。

void Uart_Rece_Pares(void)   // 串口接收内容解析函数
{
    
    
	if (receEndFlag  == 1)   // 如果接收完成
	{
    
    
		// 解析接收内容
	}
	
	// 清空接收数组
	for (clearCount = 0;clearCount < receCount;clearCount ++)
	{
    
    
		receFifo[clearCount] = ' ';
	}
		
	receCount = 0;   // 清零接收计数变量
}

在解析接收帧时可以自己定义帧结构,比如简单的帧头帧尾判断这种。

猜你喜欢

转载自blog.csdn.net/qq_45217381/article/details/129466623