This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

cc2530中UART转RS485,RS485通讯方向的控制问题

如图所示,P0.0控制RS485的收发.。高电平发送数据,低电平接收数据。

UART转RS485的方法是发送前将P0.0置为高电平,发送完成后置为低电平。

我是在DMA发送完成的中断里加入的P0.0置低控制  P0 &= ~0x01;(见下面的图)

现在的问题是数据还没有发完,P0.0就变成低电平了,这样就导致了UART上的数据不能从RS485总线上发送出去。

P0 &= ~0x01;这一句究竟应该放在哪里?希望得到各位的帮助

ZIGBEE协议栈用的是2.3.0-1.4.0

  • 你好,

    如果在Tx Done的中断里面不加 P0 &= ~0x01的话,应该是可以把数据发送完成的对吧?

    把DMA传输的MOSI信号和P0.0信号都放在示波器上看,应该在DMA一次发送过程中P0.0的信号一直为高的,对吗?还是说一次发送还没完成,P0.0就变低了?

    比方说你传输10个字节,P0.0的变低是在什么位置?

    关于DMA的配置是否有问题?

  • 你好,谢谢你的回答。

    不管在Tx Done的中断里加不加P0 &=~0x01,数据都是可以发送的。(uart波特率设置的9600)

    把P0 &=~0x01加到Tx Done的中断里,在示波器上测发送引脚P0.3和485控制引脚P0.0,P0.0的高电平在数据还没发出时就变低了,如下图所示:

    如果中断里不加P0 &=~0x01这句,P0.0就不会有电平变化,说明中断是执行了。我现在觉得这个中断是DMA将待发送到数据搬运到UART的BUFFER中产生的,但UART模块还没有将数据发送出去,但是DMA的中断却将P0.0提前变低了。不知道我理解的对不对?所以我认为要找的应该是UART发送完成的中断,但UART好像又没有设置中断,所以现在该如何解决这个问题,没有头绪了。

    DMA的配置如下:

    /******************************************************************************
    * @fn HalUARTInitDMA
    *
    * @brief Initialize the UART
    *
    * @param none
    *
    * @return none
    *****************************************************************************/
    static void HalUARTInitDMA(void)
    {
    halDMADesc_t *ch;

    P2DIR &= ~P2DIR_PRIPO;
    P2DIR |= HAL_UART_PRIPO;

    #if (HAL_UART_DMA == 1)
    PERCFG &= ~HAL_UART_PERCFG_BIT; // Set UART0 I/O to Alt. 1 location on P0.
    #else
    PERCFG |= HAL_UART_PERCFG_BIT; // Set UART1 I/O to Alt. 2 location on P1.
    #endif
    PxSEL |= UxRX_TX; // Enable Tx and Rx peripheral functions on pins.
    ADCCFG &= ~UxRX_TX; // Make sure ADC doesnt use this.
    UxCSR = CSR_MODE; // Mode is UART Mode.
    UxUCR = UCR_FLUSH; // Flush it.

    // Setup Tx by DMA.
    ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_TX );

    // The start address of the destination.
    HAL_DMA_SET_DEST( ch, DMA_UDBUF );

    // Using the length field to determine how many bytes to transfer.
    HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );

    // One byte is transferred each time.
    HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_BYTE );

    // The bytes are transferred 1-by-1 on Tx Complete trigger.
    HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE );
    HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_TX );

    // The source address is incremented by 1 byte after each transfer.
    HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_1 );

    // The destination address is constant - the Tx Data Buffer.
    HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_0 );

    // The DMA Tx done is serviced by ISR in order to maintain full thruput.
    HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_ENABLE );

    // Xfer all 8 bits of a byte xfer.
    HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );

    // DMA has highest priority for memory access.
    HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );

    // Setup Rx by DMA.
    ch = HAL_DMA_GET_DESC1234( HAL_DMA_CH_RX );

    // The start address of the source.
    HAL_DMA_SET_SOURCE( ch, DMA_UDBUF );

    // Using the length field to determine how many bytes to transfer.
    HAL_DMA_SET_VLEN( ch, HAL_DMA_VLEN_USE_LEN );

    /* The trick is to cfg DMA to xfer 2 bytes for every 1 byte of Rx.
    * The byte after the Rx Data Buffer is the Baud Cfg Register,
    * which always has a known value. So init Rx buffer to inverse of that
    * known value. DMA word xfer will flip the bytes, so every valid Rx byte
    * in the Rx buffer will be preceded by a DMA_PAD char equal to the
    * Baud Cfg Register value.
    */
    HAL_DMA_SET_WORD_SIZE( ch, HAL_DMA_WORDSIZE_WORD );

    // The bytes are transferred 1-by-1 on Rx Complete trigger.
    HAL_DMA_SET_TRIG_MODE( ch, HAL_DMA_TMODE_SINGLE_REPEATED );
    HAL_DMA_SET_TRIG_SRC( ch, DMATRIG_RX );

    // The source address is constant - the Rx Data Buffer.
    HAL_DMA_SET_SRC_INC( ch, HAL_DMA_SRCINC_0 );

    // The destination address is incremented by 1 word after each transfer.
    HAL_DMA_SET_DST_INC( ch, HAL_DMA_DSTINC_1 );
    HAL_DMA_SET_DEST( ch, dmaCfg.rxBuf );
    HAL_DMA_SET_LEN( ch, HAL_UART_DMA_RX_MAX );

    // The DMA is to be polled and shall not issue an IRQ upon completion.
    HAL_DMA_SET_IRQ( ch, HAL_DMA_IRQMASK_DISABLE );

    // Xfer all 8 bits of a byte xfer.
    HAL_DMA_SET_M8( ch, HAL_DMA_M8_USE_8_BITS );

    // DMA has highest priority for memory access.
    HAL_DMA_SET_PRIORITY( ch, HAL_DMA_PRI_HIGH );
    }

  • 又用示波器测试了一下,测试结果如下:

    1.发送一个字节时

    2.发送两个字节时

    3.发送四个字节

    4.发送更多数据时

  • 哪位大神出来指点一下

  • 您好!请问您的MAX485控制问题解决了吗?我也遇到同样问题。还希望您多多赐教。我的邮箱puyunxk@163.com.QQ879882500

  • DMA的方式没能解决,后来改成中断的方式就可以了

  • 我也遇到了类似的问题,我的是无法接收,改用中断单独写程序可以接收,在协议栈中就不知道如何入手了,楼主可以指点一下吗?谢谢 qq372160080

  • 你也是用的485芯片吗?最好先排除485的问题,绕过485测试一下2530芯片串口输入引脚的波形是否正常。

  • 刚开始是3485的问题,后来改好了,不用协议栈单独写发送接收程序都可以,协议栈不知道往哪里写程序,实现不了。。

  • 像HalUARTWrite,HalUARTRead是协议栈基本的函数,直接用就可以了。如果这个也不知道的话恐怕别人也不知道怎么帮助你。

  • 这个知道  但是这打不开_hal_uart_isr.c,是没有吗?

  • 协议栈中默认使能的DMA方式,要使能中断方式需要在配置文件中修改宏定义。选择使能中断后_hal_uart_isr.c才会加入工程。

    但我建议你首先在协议栈默认方式下(即DMA方式)先调通串口通讯。

  • 谢谢你的建议,现在情况是这样的,我使用DMA方式只能使用HalUARTWrite函数发送数据,使用HalUARTRead却接收不到任何数据,方向控制位也是跟你说的一样在那里修改的。

  • 建议你先测试不用485时通讯是否正常,正常后再往后进行。

    使用DMA进行485通信中可以在DMA中断加延时如下:

  • 谢谢了 ,我再试试。

  • 你用的dma模式还是中断模式?我用的dma现在能收到数据,但是收到的是乱码。接收使能以后,发送之前是不是还得发送使能,还有发送以后是不是又要接收使能?

  • 对比 4L 的图片

    应该是因为UART 有2字节有效缓冲( 缓冲寄存器和移位寄存器 )的原因,需要延时2个字节耗时再设置P0.0

    因为 倒数第二个字节 进入发送移位寄存器时,倒数第一个字节就会被DMA送到缓冲寄存器里面,DMA就完成所有数据传输,产生计数完成中断。

    但实际上需要 2个字节 (2x10xBaud) 时间 后才真正完全把数据通过UART发送完成, 才能设置 P0.0口关闭485

    例如

    发送10个字节,发完第8个字节就会产生DMA中断

    发送100个字节,发完第98个字节就会产生DMA中断

  • 你好,请问协议栈的485通信实现了吗,我现在在解决这个问题,想从你那了解一下,QQ:329337977
  • 您好,请问使用中断的方式,收发控制线电平拉低应该放在什么位置