灵思科电子科技—新唐 Cortex - m0 RS-485的使用

时间:2024-03-28 17:02:21
最近在完成一个modbus网关的项目需要将服务端下发的数据流用485接口和从机进行通讯。

灵思科电子科技—新唐 Cortex - m0 RS-485的使用
带485接口的物联网网关

 作为一枚入行两年的资深小白,开发的第一步当然是打开Demo,拷贝它学习它。   



从注释来看样例程序使用的是自动方向控制模式(AUD)。再看一下DataSheet的介绍,我了解到IC的UART控制器本身支持的模式共三种:RS-485 普通多点操作模式(NMM),RS-485 自动地址识别模式(AAD),还有本文将要介绍的自动方向控制模式。



想继续看懂DataSheet中专业的寄存器描述,我们需要先热热身--了解一下什么是485。

灵思科电子科技—新唐 Cortex - m0 RS-485的使用

485原理图

首先485不是一种软件协议而是一种硬件上的串行通讯标准。



485的电气特性为逻辑"1":+(2v~6v)压差,逻辑"0":-(2v~6v)压差。RS485有两种接线一种是四线制一种是两线制。原因在于485的传输信号为差分信号,即使在某时刻单向传输也需要两个引脚共同作用,想要全双工就得比RS232多两根线用四线制。



除了两个引脚产生差分信号,485通信过程中还需要两个引脚进行流控制。这两个引脚的功能相当于门卫。它们一个负责放行自己人外出,大名CTS(clear to send,发送允许);一个允许别人进入,名号RTS(require to send,发送请求)。CTS是输入信号,CTS检测到有效电平时说明本设备可发送数据出去;RTS为输出信号,RTS输出有效电平来告知其他设备自己可以接受数据。

灵思科电子科技—新唐 Cortex - m0 RS-485的使用

笔者调试用的485转USB

了解到这里再查看一下手册就可以写代码了,下面贴出我的代码。

 首先是初始化:

/* 使能UART_1 时钟*/

CLK_EnableModuleClock(UART1_MODULE);

/* 选择UART_1 时钟源 */

CLK_SetModuleClock(UART1_MODULE, CLK_CLKSEL1_UART_S_HXT, CLK_CLKDIV_UART(1));  

/* 设置UART_1 复用引脚 */

SYS->GPB_MFP &= ~(SYS_GPB_MFP_PB4_Msk | SYS_GPB_MFP_PB5_Msk | 

SYS_GPB_MFP_PB6_Msk | SYS_GPB_MFP_PB7_Msk);

SYS->GPB_MFP |= SYS_GPB_MFP_PB4_UART1_RXD | SYS_GPB_MFP_PB5_UART1_TXD |

SYS_GPB_MFP_PB6_UART1_nRTS | SYS_GPB_MFP_PB7_UART1_nCTS;

/设置中断优先级/

NVIC_SetPriority(UART02_IRQn,1);

/复位UART_1/

SYS_ResetModule(UART1_RST);

/开启UART_1/

UART_Open(UART1, u1_baudrate);

/使能UART_1中断/

UART_EnableInt(UART1, (UART_IER_RDA_IEN_Msk | UART_IER_TOUT_IEN_Msk));

/* 选择自动方向控制模式 */

UART_SelectRS485Mode(UART1, UART_ALT_CSR_RS485_AUD_Msk, 1);

/* Set RTS pin active level as high level active */

UART1->MCR &= ~UART_MCR_LEV_RTS_Msk;

UART1->MCR |= UART_RTS_IS_HIGH_LEV_ACTIVE;

/counting clock = baud/

/* Set TX delay time */

UART1->TOR = 0x2000;

/* Set RX delay time */

UART1->TOR |= 0x28;

发送函数:

void RS485_SendDataByte(uint8_t *pu8TxBuf, uint32_t u32WriteBytes)

{

/* Set UART parity as SPACE and skip baud rate setting */

UART_SetLine_Config(UART1, 0, UART_WORD_LEN_8, UART_PARITY_NONE, UART_STOP_BIT_1);



/* Send data */

UART_Write(UART1, pu8TxBuf, u32WriteBytes);

//printf(" ! 485_Snd_over.\r\n");

}

接受中断:

void UART1_IRQHandler()

{

uint8_t u8InChar = 0xFF;

uint32_t u32IntSts = UART1->ISR;

if(u32IntSts & UART_ISR_RDA_INT_Msk)

{

    /* Get all the input characters */

    while(UART_IS_RX_READY(UART1))

    {

        /* Get the character from UART Buffer */

        u8InChar = UART_READ(UART1);

        /* Check if buffer full */

        if(u1_rcv_tail < U1_RXBUFSIZE)

        {

        /* Enqueue the character */

        u1_rcv_buf[u1_rcv_tail] = u8InChar;

        //printf("_u1_0x%02x\r\n",u8InChar);

        u1_rcv_tail = (u1_rcv_tail == (U1_RXBUFSIZE - 1)) ? 0 : (u1_rcv_tail + 1);

        }

    }

}

}

定时器判断一帧数据结束:

//FrameOver_1 在主轮询中清零

void Uart_1_RxMonitor(void)

{

static uint8_t idletmr = 0;

if(u1_rcv_tail){

    if(u1_rcv_tail != old_u1_rcv_tail){

        old_u1_rcv_tail = u1_rcv_tail;

         idletmr = 0;

    }

    else if(++idletmr > U1_IDLE_TIM )

        FrameOver_1 = 1;

}

}

灵思科电子科技—新唐 Cortex - m0 RS-485的使用
物联网信息交流群 QQ:985441916