单片机串口uart学习

发布于:2024-07-01 ⋅ 阅读:(12) ⋅ 点赞:(0)

参考文章

https://blog.csdn.net/Reed_redd/article/details/126098506

https://blog.csdn.net/AriesPIG/article/details/119840979

前言

OK,又是新一期的温故而知新!串口UART想必大家都用过,我记得我最早的时候用它来打印单片机的调试数据,是直接使用printf(经过重定向后的),当时一直搞不懂其中的奥秘,直到前几天终于开始认真学习串口了才发现用了这么多年的串口还有这么多知识不懂的。

串口的简要介绍

通用异步接收器/发送器,通常称为UART,是一种广泛应用于嵌入式领域的串行、异步、全双工通信协议。例如我们常用的485 232 TTL这些电平接口,他们都是串口在不同电平规定下的实现,其本质上还是一样的。

  • 单工:数据传输只支持数据在一个方向上传输。(只收不发或者只发不收,模式固定)
  • 单双工:允许数据在两个方向上传输,但是在某一时刻,只允许数据在一个方向上传输。(能发能收,但不能同时进行
  • 全双工:允许数据同时在两个方向上传输。(能发能收,且能同时进行
  1. 同步通信:带时钟同步信号传输,如SPI、IIC通信等
  2. 异步通信:不带时钟同步信号,如UART(通用异步收发器)、单总线等。

串口的作用

使用串口的作用是什么呢?显而易见,它的作用非常多,像是打印调试信息、设备之间的通信、设备和PC之间的通信……,总之我们可以使用串口来实现的事情非常多。

配置过程

基本参数

基本需要配置的参数

1.起始位

​ 当未有数据发送时,数据线处于逻辑“1”状态;先发出一个逻辑“0”信号,表示开始传输字符。

2.数据位

​ 紧随起始位之后,数据位表示真正要发送或接收的信息,位数一般有8位或9位

3.奇偶校验位

​ 数据位末尾可以选择是否添加奇偶校验位,用于检测数据传输是否正确

4.停止位

​ 代表信息传输结束的标志位,可以是1位,1.5位或2位。停止位的位数越多,数据传输的速率也越慢。

5.波特率设置

波特率表示每秒钟传输码元的个数,是衡量数据传输速率的指标,单位Baud。另外有个名词叫比特率,比特率表示每秒钟传输二进制位bit的个数,单位 bit/s。

代码示例

void atk_ms53l0m_uart_init(uint32_t fu32_Baudrate)
{
	
    g_uart_handle.Instance = UART2;
    g_uart_handle.Init.BaudRate   = fu32_Baudrate;
    g_uart_handle.Init.WordLength = UART_WORDLENGTH_8B;
    g_uart_handle.Init.StopBits   = UART_STOPBITS_1;
    g_uart_handle.Init.Parity     = UART_PARITY_NONE;
    g_uart_handle.Init.Mode       = UART_MODE_TX_RX;
    g_uart_handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE;

    HAL_UART_Init(&g_uart_handle);
		
}

配置好上面的,基本上你就可以使用这个串口了。当然还需要把我们需要对外的串口引脚给使能一下

中断参数

玩了单片机这么久,发现最重要还是需要学会使用中断,就像我上篇文章,使用输入捕获也要使用到中断,所以玩裸机的话中断一定要弄透。

    /* Enable RX and RTI interrupt */
    SET_BIT(g_uart_handle.Instance->IE,UART_IE_RXI|UART_IE_RTI); 
    /* Clear RXI Status */
    g_uart_handle.Instance->ICR = UART_ICR_RXI;
    /* FIFO Enable */
    SET_BIT(g_uart_handle.Instance->LCRH, UART_LCRH_FEN);
	/*FIFO Select*/
	MODIFY_REG(g_uart_handle.Instance->IFLS, UART_IFLS_RXIFLSEL, UART_RX_FIFO_7_8);  

上面主要是接收和发送中断的使能,这两个我们都很熟悉基本上都能懂,但是FIFO中断是个什么东西呢?这个东西之前也用过,但是也一直没有搞懂,在查阅了一些资料以后才懂得了他的大致作用。

首先查阅芯片手册,发现的确是有这个东西的拥有16个字节的FIFO(First In First Out),FIFO我们可以简单理解为一个队列,也就是先进先出的这么一个硬件资源。为什么要使用这个资源呢?我们知道有时候我们数据处理会在中断里面进行,但是中断又是很吃资源的,所以频繁进入中断会增加我们单片机的负担,为了减轻这个负担单片机的设计师想到了使用FIFO这么一个硬件资源来存储我们的到的数据,当数据满了或者空的时候再进中断进行数据处理。查看一下这部分的寄存器,如下所示。

大致就是上面这些,所以我们可以选择一个触发条件,然后在进行处理。

这里我选择的是 RXIFLSEL 100 在接收到14个数据后进入中断,这里大家可能会有一个疑惑,如果我的数据寄存器接收的数量不是所设置的个数的整数倍岂不是会有一部分数据滞留在FIFO中?当然是不会的,单片机设计师显然是要比我们这些使用者考虑的更加周到,这里会有一个超时中断来供我们使用。

所以当几个周期内没有数据传输过来后就会触发这个中断,我们就可以进中断里面取数据进行处理,当然这也可以作为我们准备接收完成的一个标志位。例如下面代码就是从机处理发送完成最后几个字节,然后进入中断处理。

		else if(huart->Instance->RIS & UART_RIS_RTI)                               //长时间未接受到中断
		{
			/*clear RTI Status */
			SET_BIT(huart->Instance->ICR ,UART_ICR_RTI);

			while(!READ_BIT(huart->Instance->FR, UART_FR_RXFE))
			{
				HAL_UART_Receive(huart, &tmp, 1, HAL_MAX_DELAY);           /* UART接收数据 */
				if (g_uart_rx_frame.sta.len < (ATK_MS53L0M_UART_RX_BUF_SIZE - 1))   /* 判断UART接收缓冲是否溢出
																					 * 留出一位给结束符'\0'
																					 */
				{
					g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
					g_uart_rx_frame.sta.len++;                                      /* 更新接收到的数据长度 */
				}
				else                                                                /* UART接收缓冲溢出 */
				{
					g_uart_rx_frame.sta.len = 0;                                    /* 覆盖之前接收的数据 */
					g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;             /* 将接收到的数据写入缓冲 */
					g_uart_rx_frame.sta.len++;                                      /* 更新接收到的数据长度 */
				}
				
			}

好了以上就是我再一次学习串口所获得的收获