简体   繁体   中英

STM32F030R8 RS485 Half Duplex not transmitting

I'm using an STM32F030R8 to perform RS485 communications connected to a AD3485. So far I've been able to get it to transmit just fine, but when I setup an interrupt handler it seems like the interrupt is being triggered by my chip's own transmissions and stops all further transmissions.

Have I missed setting or clearing a flag somewhere? Did I miss something in my RS485 init step? Should I be clearing a flag when my transmissions inevitably trigger the interrupt request?

Below I've included a very stripped down, but complete version of code I'm using for transmission of data, as well as a capture of data that I'm seeing come out of the RS485 chip that I have hooked up to pins A9 A10 and A12.

Here's the code:

#include "stm32f0xx_conf.h"
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_usart.h>

void SysTick_Handler(void) {

    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
    USART_SendData(USART1, 0xAC);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    USART_SendData(USART1, 0x44);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    USART_SendData(USART1, 0x04);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    USART_SendData(USART1, 0x53);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);

}

void RS485_Init(){
    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;

    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_12; // Pins 9 (TX) 10 (RX) 12 (DE) are used
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; // the pins are configured as alternate function so the USART peripheral has access to them
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; // this defines the IO speed and has nothing to do with the baudrate!
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; // this defines the output type as push pull mode (as opposed to open drain)
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP; // this activates the pullup resistors on the IO pins
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1); //
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_1);

    USART_InitStruct.USART_BaudRate = 38400 ; // the baudrate is set to the value we passed into this init function
    USART_InitStruct.USART_WordLength = USART_WordLength_8b; // we want the data frame size to be 8 bits (standard)
    USART_InitStruct.USART_StopBits = USART_StopBits_1; // we want 1 stop bit (standard)
    USART_InitStruct.USART_Parity = USART_Parity_No; // we don't want a parity bit (standard)
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // we don't want flow control (standard)
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; // we want to enable the transmitter and the receiver
    USART_Init(USART1, &USART_InitStruct);

    USART_HalfDuplexCmd(USART1, ENABLE);
    USART_DECmd(USART1, ENABLE);
    USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_SetDEAssertionTime(USART1, 0x4E2);
    USART_SetDEDeassertionTime(USART1, 0x4E2);
    USART_DEPolarityConfig(USART1, USART_DEPolarity_High);

    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct); //When I comment this out, I'm able to transmit normally, but without an ISR receiving bytes will be difficult

    USART_Cmd(USART1, ENABLE);

}

//This function handles USART1 global interrupt request.
void USART1_IRQHandler(void)
{

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
        unsigned char USART_Temp_Byte;
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        USART_Temp_Byte = (unsigned char) USART_ReceiveData(USART1); //receive a char
    }

}

int main(void)
{
    RS485_Init();
    SysTick_Config(SystemCoreClock/1000);
    while(1);
}

And here's a capture of when I have the interrupt enabled (first capture), vs when I comment out NVIC_Init(&NVIC_InitStruct); and don't have an ISR triggering:

RS485传输问题的逻辑捕获

This is one of the core principles of half/full duplex communications methods. RS485, which is a physical layer standard, allows transmitters to receive their own data. This is useful for other standards (software layer), such as J1708. Since there isn't a hard requirement for a single master and multiple slaves, each node can initiate a communication. If two modules start to talk at the same time, there needs to be a scheme to detect and handle bus contentions/collisions. With RS485, you have a dominate (driven) state and a recessive (non-driven) state. When the transmitter begins to transmit, you monitor to see if what you receive matches what you sent, if it doesn't, most likely another device was trying to transmit as the same time. This works because when you switch from a dominate state to recessive, the bus will either return to the recessive state (no collision), or remain in the dominate state due to another receiver holding the line (collision). When this happens, you stop any further transmission and either start receiving or monitor the bus for an idle state. Most protocols, like J1708, use a pseudo random generator based on your address to calculate a retry delay, which prevents the same two modules from constantly colliding. Long story short: the fact that you are receiving what you transmit is a good thing. I would suggest you use the interrupt to compare the byte just transmitted and the byte just received and if they match, send the next byte, else terminate and try again after the next idle state is detected. Since it's the same interrupt routine, you need to set a flag indicating when you are transmitting and steer the interrupt logic to handle the comparisons (Tx portion) or handle normal recieve (Rx portion)

I'm adding this answer as an update to getting half duplex comms working with this particular chip. With this configuration I was able to both transmit and receive. Special Thanks to Joe Thomas for putting me on the right track.

#include "stm32f0xx_conf.h"
#include <stm32f0xx_gpio.h>
#include <stm32f0xx_rcc.h>
#include <stm32f0xx_usart.h>

void Transmit(void){

    USART_Cmd(USART1, DISABLE);
    USART_DECmd(USART1, ENABLE);
    USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
    USART_ITConfig(USART1, USART_IT_RXNE, DISABLE);
    USART_Cmd(USART1, ENABLE);

    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    USART_SendData(USART1, 0xAC);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    USART_SendData(USART1, 0x44);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    USART_SendData(USART1, 0x04);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    USART_SendData(USART1, 0x53);
    while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);
    while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);

    USART_Cmd(USART1, DISABLE);
    USART_DECmd(USART1, DISABLE);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    USART_Cmd(USART1, ENABLE);

}

void SysTick_Handler(void) {

}

void RS485_Init(){

    GPIO_InitTypeDef GPIO_InitStruct;
    USART_InitTypeDef USART_InitStruct;
    NVIC_InitTypeDef NVIC_InitStruct;



    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE);

    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_12;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
    GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_1);

    USART_DeInit(USART1);
    USART_StructInit(&USART_InitStruct);
    USART_InitStruct.USART_BaudRate = 38400 ;
    USART_InitStruct.USART_WordLength = USART_WordLength_8b;
    USART_InitStruct.USART_StopBits = USART_StopBits_1;
    USART_InitStruct.USART_Parity = USART_Parity_No;
    USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_RTS;
    USART_InitStruct.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
    USART_Init(USART1, &USART_InitStruct);

    USART_HalfDuplexCmd(USART1, DISABLE);
    USART_DECmd(USART1, DISABLE);
    USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
    USART_SetDEAssertionTime(USART1, 0x4E2);
    USART_SetDEDeassertionTime(USART1, 0x4E2);
    USART_DEPolarityConfig(USART1, USART_DEPolarity_High);



    NVIC_InitStruct.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStruct.NVIC_IRQChannelPriority = 0;
    NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStruct);

    USART_ClearITPendingBit(USART1, USART_IT_RXNE);
    USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    USART_Cmd(USART1, ENABLE);

}

void USART1_IRQHandler(void)
{

    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET){
        unsigned char USART_Temp_Byte;
        USART_ClearITPendingBit(USART1, USART_IT_RXNE);
        USART_Temp_Byte = (unsigned char) USART_ReceiveData(USART1); //receive a char
        if(0x53 == USART_Temp_Byte){
            Transmit();
        }
    }

}

int main(void)
{
    RS485_Init();
    SysTick_Config(SystemCoreClock/1000);
    while(1){};
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM