简体   繁体   English

STM32F030R8 RS485半双工不发送

[英]STM32F030R8 RS485 Half Duplex not transmitting

I'm using an STM32F030R8 to perform RS485 communications connected to a AD3485. 我正在使用STM32F030R8来执行连接到AD3485的RS485通信。 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? 我在RS485初始化步骤中错过了什么吗? 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. 下面,我提供了一个非常精简但完整的代码版本,用于传输数据,以及捕获的数据,这些数据我从连接到引脚A9的RS485芯片中看到A10和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); 这是我启用中断时的捕获(第一次捕获),与注释掉NVIC_Init(&NVIC_InitStruct)时的捕获; and don't have an ISR triggering: 并且没有ISR触发:

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. RS485是物理层标准,它允许发送器接收自己的数据。 This is useful for other standards (software layer), such as J1708. 这对于其他标准(软件层)(例如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. 使用RS485,您将具有主导(驱动)状态和隐性(非驱动)状态。 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. 像J1708这样的大多数协议,都根据您的地址使用伪随机数发生器来计算重试延迟,这可以防止相同的两个模块不断冲突。 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) 由于它是相同的中断例程,因此您需要设置一个标志来指示何时进行传输,并控制中断逻辑以处理比较(Tx部分)或正常接收(Rx部分)

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. 特别感谢Joe Thomas使我走上正轨。

#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){};
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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