良许Linux教程网 干货合集 如何实现UART的分时复用

如何实现UART的分时复用

实际应用中经常会遇到微控制器(MCU)内置的UART个数不足的情况,通常有几种处理方式可供选择:

  1. 重新选择一款拥有更多UART的芯片,但这样做会增加成本。
  2. 外部添加接口转换芯片,例如SPI/I2C转UART芯片。这种方式需要对电路板进行修改,并且会增加成本。
  3. 选择使用RS485外设来替代RS232外设。这种方式需要进行软件修改,并且有可能改变外部的连接方式,增加了终端电阻。虽然电路板的成本几乎没有太大增加,但外设的成本可能会有所变化。
  4. 通过GPIO口加定时器的方式来模拟UART。这种方式的好处是可以将任意GPIO分配给芯片,并且不会增加成本。但需要进行软件修改,同时会增加CPU的负荷,特别是在发送/接收过程中,CPU会频繁进入中断,从而增加负荷。
  5. 利用MCU的引脚复用功能,将一个UART分时应用于不同的引脚,使其看起来像是多个串口。

本文主要介绍了第5种方法,通过这种方法,可以在UART个数受限的情况下,以较低的成本实现多个串口的数据收发。当然,这种方法有一些应用限制:

  1. MCU必须作为每个UART数据通信的发起者,也可以认为是UART协议的主设备,每次数据交换都由MCU发起。
  2. MCU在发送数据后,必须知道从设备回复数据的超时时间,否则无法判断是否由于数据丢失导致无法查询下一个UART。

以下以NXP Kinetis KW41为例,介绍如何使用UART的分时复用功能:

  1. 根据Datasheet选择可用的IO口,手册中的Table 52. KW41Z Pin Assignments提供了详细的描述。从图中可以看出,KW41只有一个LPUART0,但它可以复用到38、39、42、43、46、47这三组引脚上,这意味着我们最多可以复用出3个UART:
image-20231015222738452
image-20231015222738452
image-20231015222745530
image-20231015222745530
  1. 查看芯片管脚复用寄存器,KW41是通过PORTx_PCRn寄存器的MUX位域来进行设置的,但该寄存器写入0x01对应的IO为GPIO,写入0x04对应LPUART0功能:
image-20231015222750382
image-20231015222750382
  1. 修改软件代码,附件提供一个UART_TDM的例子,main函数中只需要调用初始化函数以及周期处理函数即可:
image-20231015222753406
image-20231015222753406
  1. UART_TDM_Init初始化函数中主要是初始化了LPUART:
image-20231015222756529
image-20231015222756529

5.UART_TDM_Process本质上是一个状态机,其中有5种状态,芯片复位后为等待状态,然后等待一个UART0的发送周期进入Send状态,发送数据完毕后,会进入Receive状态,接收完毕后进入Done状态,如果超时没有接收到数据,则进入ReceiveTimeOut状态,进行异常处理,处理完毕后继续进入Done状态,Done状态后会重新进入Wait状态,等待下一个UART口的周期时间,进入第二个串口的周期,依次循环:

typedef enum _uart_tdm_status
{
kUART_TDM_Wait = 0U, /*!

其中有几个用户参数是可以设置的:

#define BOARD_DEBUG_UART_BAUDRATE 115200  //设置波特率`
#define TDM_RING_BUFFER_SIZE 11 //设置Buffer大小以及发送数据的个数
g_u16ReceiveTimeout[UART_TDM_NUMBER] = {100, 100, 100}; //响应超时,Uint ms.
g_u16CycleTime[UART_TDM_NUMBER] = {500, 500, 500}; //访问周期,Uint ms.

g_u16ReceiveTimeout该变量用于判断串口接收是否超时,如果本串口发送完毕后100ms内数据没有接收完成,则认为判断为超时,数据接收完毕的标志在接收中断服务程序中置位,这里仅仅示例,用户可以根据自己协议设置:

image-20231015222817546
image-20231015222817546

g_u16CycleTime该变量用于判断各个串口的发送间隔,当UART0接收(或超时)后,等待g_u16CycleTime[1]的时间后,发送UART1,UART1接收(或超时)后,等待g_u16CycleTime[2]的时间发送UART2,UART2接收(或超时)后,等待g_u16CycleTime[0]的时间发送UART0

extern uint32_t g_u32Timer; 本示例使用PIT生成了1ms的中断,并在中断复位程序中使用g_u32Timer++记录1ms的时间,如果用户希望降低CPU的负荷,可以使用Systick来计算超时。

  1. 下载并运行程序,如果三个串口都接到PC端,可以在3个终端分别看到HelloUart1,HelloUart2,HelloUart3,如果PC端没有发送任何数据,那么MCU每周期都会进入kUART_TDM_ReceiveTimeOut状态,这样可以计算出每个串口的时间分别是500+100,500+100,500+100,总的周期是1800ms。

以上就是良许教程网为各位朋友分享的Linu系统相关内容。想要了解更多Linux相关知识记得关注公众号“良许Linux”,或扫描下方二维码进行关注,更多干货等着你 !

137e00002230ad9f26e78-265x300
本文由 良许Linux教程网 发布,可自由转载、引用,但需署名作者且注明文章出处。如转载至微信公众号,请在文末添加作者公众号二维码。
良许

作者: 良许

良许,世界500强企业Linux开发工程师,公众号【良许Linux】的作者,全网拥有超30W粉丝。个人标签:创业者,CSDN学院讲师,副业达人,流量玩家,摄影爱好者。
上一篇
下一篇

发表评论

联系我们

联系我们

公众号:良许Linux

在线咨询: QQ交谈

邮箱: yychuyu@163.com

关注微信
微信扫一扫关注我们

微信扫一扫关注我们

关注微博
返回顶部