嵌入式开发—串口通信

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需要多久的高/低电平表示。

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

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] = ' ';
	    }
		
		receEndFlag   = 0;   // 清除接收完成标志位
	    receCount = 0;   // 清零接收计数变量
	}
}

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

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

二土电子

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值