STM32F030R8 RS485 Полудуплекс не передает
Я использую STM32F030R8 для связи RS485, подключенной к AD3485. До сих пор я был в состоянии заставить его передавать просто отлично, но когда я настраиваю обработчик прерываний, кажется, что прерывание запускается собственными передачами моего чипа и останавливает все дальнейшие передачи.
Я пропустил установку или снятие флажка где-нибудь? Я что-то пропустил на этапе инициализации RS485? Должен ли я очищать флаг, когда мои передачи неизбежно вызывают запрос прерывания?
Ниже я включил очень урезанную, но полную версию кода, который я использую для передачи данных, а также для сбора данных, которые я вижу, поступающие с чипа RS485, который я подключил к выводам A9. А10 и А12.
Вот код:
#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);
}
И вот захват, когда у меня включено прерывание (первый захват), против того, когда я закомментирую NVIC_Init(&NVIC_InitStruct); и не имеют запуска ISR:
2 ответа
Я добавляю этот ответ как обновление для получения полудуплексной связи, работающей с этим конкретным чипом. С этой конфигурацией я смог как передавать, так и получать. Отдельное спасибо Джо Томасу за то, что он поставил меня на правильный путь.
#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){};
}
Это один из основных принципов полудуплексных методов связи. RS485, который является стандартом физического уровня, позволяет передатчикам получать свои собственные данные. Это полезно для других стандартов (программный уровень), таких как J1708. Поскольку нет жестких требований для одного главного и нескольких ведомых устройств, каждый узел может инициировать связь. Если два модуля начинают говорить одновременно, должна существовать схема для обнаружения и обработки конфликтов / коллизий шины. С RS485 у вас есть доминирующее (управляемое) состояние и рецессивное (не управляемое) состояние. Когда передатчик начинает передавать, вы контролируете, чтобы увидеть, соответствует ли то, что вы получаете, тому, что вы отправили, если нет, скорее всего, другое устройство пыталось передать в то же время. Это работает, потому что когда вы переключаетесь из доминирующего состояния в рецессивное, шина либо возвращается в рецессивное состояние (без коллизий), либо остается в доминирующем состоянии из-за другого приемника, удерживающего линию (коллизия). Когда это происходит, вы прекращаете любую дальнейшую передачу и начинаете получать или отслеживаете шину для состояния ожидания. Большинство протоколов, таких как J1708, используют генератор псевдослучайных данных, основанный на вашем адресе, для расчета задержки повтора, которая предотвращает постоянное столкновение одних и тех же двух модулей. Короче говоря: тот факт, что вы получаете то, что вы передаете, - это хорошо. Я бы посоветовал вам использовать прерывание для сравнения только что переданного байта и только что полученного байта, и если они совпадают, отправьте следующий байт, иначе завершите работу и повторите попытку после обнаружения следующего состояния простоя. Поскольку это та же самая процедура прерывания, вам нужно установить флаг, указывающий, когда вы передаете, и управлять логикой прерывания, чтобы обрабатывать сравнения (часть Tx) или обрабатывать нормальное получение (часть Rx)