一个二极管即可改造UART串口为一主多从总线 一对多通讯

内容节选自本人毕业论文,有改动。感谢追光拾忆者提供的思路,来自STM32普通串口一对多通信/USART无需添加485拓展_追光拾忆者的博客-CSDN博客_串口一对多

1.硬件层改造

        当我们使用的单片机uart接口不足,我们可以利用UART实现总线型一主多从通讯结构,如图所示。

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第1张图片

图1 UART总线型通讯结构

        如果直接将从机的TX连接到主机的RX,那么从机之间的TX引脚就连接在一起,如图2所示。当Slave1尝试向Master发送信息时,由于UART以低电平为起始标志,Slave1TX引脚为低电平,而Slave2TX引脚为高电平。此时电流由Slave2TX引脚流向Slave1TX引脚,Slave1TX引脚灌电流升高。由于器件存在内阻,电流增大导致节点p电压升高,最终我们看到Slave1TX引脚电平升高了。

        由于引脚电平升高,MasterRX端接收不到Slave1TX端发来的低电平,串口通信也就无从开始。

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第2张图片

图2 灌电流引起引脚电平升高

        解决方案的其中之一是将从机的通信引脚设置为开漏输出。在开漏输出模式下,引脚在高电平逻辑下既不输出高电平,也不输出低电平,而是高阻态,需要外接上拉电阻以输出高电平。由于上拉电阻的存在,灌电流非常小,也就避免了引脚电平升高的问题。但是,我们往往无法对从机进行二次开发,即无法改变其通信引脚的输出模式。

        图3展示了另外一种解决方案,此方案中,从机的TX引脚与二极管阴极相连,二极管阳极连接到主机的RX引脚。由于二极管的单向导通性,灌电流将被限制在一个极小的范围,相当于断路,从而避免了引脚低电平升高的问题。由于主机的RX引脚是一个上拉输入的状态,因此二极管截止的时候也不会影响高电平的采样。

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第3张图片

图3 使用二极管限制灌电流

        本人制作了一个简陋测试板来验证该设计(简陋得一,几分钟画完),原理图及3d示意图如下。

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第4张图片

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第5张图片

一个二极管即可改造UART串口为一主多从总线 一对多通讯_第6张图片

经验证,该方案可以实现一对多通讯。 实际上,根据原理,N+1个从机只需要N个二极管,这个就留给你们去验证吧。

测试板开源链接:uart总线 - 立创EDA开源硬件平台

2.线程通信保护

        在总线通讯中,通讯协议的重要性不容忽视,如果通讯节点不分主从,随意发送,可能出现多个节点同时发送信息的情况,那将是一场灾难。

1.主从区分

        通信保护的第一步,是将除了主设备以外的所有设备,改造为从机。从机总处于被动状态,只有主机向从机发送信息时,从机才能进行回应,其余时刻保持静默,由主机对所有从机根据需要进行轮询。

2.通信流程保护

        除了主从区分之外,我们希望对每个线程的单次收发流程进行保护。在一个线程使用UART通信的过程中,如果RTOS切换到另一个使用UART通信的线程,可能造成两个从机同时发送信息的情况,这是我们不愿意看到的。

        因此,我们在UART总线系统中,提供总线锁定与解锁接口uart_lock与uart_unlock,其原理为互斥量的获取与释放。代码如下:

int uart_lock(void)

{

    if (osOK != osMutexWait(uart_mutex_id, osWaitForever))

    {

        TRACE( 0 , "%s %d osMutexWait fail",__func__,__LINE__);

        return 0;

    }

return 1;

}

int uart_unlock(void)

{

    if (osOK != osMutexRelease(uart_mutex_id))

    {

        TRACE( 0 , "%s %d osMutexRelease fail",__func__,__LINE__);

        return 0;

    }

       return 1;

}

        线程在发送信息前使用uart_lock来锁定UART资源,一轮通信完成后使用uart_unlock解锁UART资源,以供其他线程使用。加入该互斥锁后,任一时刻,只能够有一个线程访问UART资源,实现了对单次通信过程的保护。

        互斥锁会带来一个死锁的问题。如果一个线程的通信过程出现故障,如某从机通信线路断开,该线程无法收到从机回应,将维持等待状态而不释放锁,其他线程也无法获取锁,UART系统将无法继续运行。为此,需要在每个可能持有锁的线程中为互斥锁增加一个保护措施,当某线程持有锁的时间过长,互斥锁将被释放。代码如下:

event = osMessageGet(_my_msg_id, 100);

if(event.osStatus != osOK)

{

       TRACE( 0 , "%s %d overtime",__func__,__LINE__);

       uart_unlock();

return;

}

你可能感兴趣的:(个人开发,单片机,stm32,arm)