STM32 usart на прерываниях на примере RS485

Итак что мы имеем — на моей плате USART3 это RS485 и т.к. он мне наиболее интересен, то речь пойдет о нем. Как уже писал для работы с RS485 надо иногда дрыгать ногами т.е. включать его на передачу а потом выключать дабы, что-то принять и наша нога для этого PB2. В прошлом примере это дрыганье делалось по задержке дабы не обрубать хвост посылке, сейчас это сделаем на прерывании ну и прием тоже.
Итак для использования прерываний нам надо их настроить с помощью структуры NVIC_InitTypeDef NVIC_InitStructure;
SetupUSART3(USART_InitStructure);
//после настройки усарта настраиваем прервания
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn; //канал
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //приоритет
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;//приоритет субгруппы
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //включаем канал
NVIC_Init(&NVIC_InitStructure); //инициализируем
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); //включаем нужное прерывание щас нам прием
и не забудем прописать обработчик void USART3_IRQHandler(void) -и то что в нем должно происходить. Как оказалось для нормальной работы прерываний наддо вручную сбрасывать их флаги например на прием -USART_ClearITPendingBit(USART3, USART_IT_RXNE) иначе оно так и будет висеть и пытаться попадать в обработчик (хотя по приему оно само как то сбрасывалось надо признаться — зато остальное нет). Дальше в этом обработчике мы примем байт в tmp и поставим признак того что мы что то имеем в буффере rx=1 да и еще один важный момент — обработка прерываний очень похожа на PIC — общий вектор с выбором по признаку т.е. мы попали в прерывание а почему оно произошло надо проверить:
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
rx=1;
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
tmp=USART_ReceiveData (USART3);
}
дальше мы проваливаемся в основной цикл смотрим что у нас есть символ который надо отправить назад отправляем и попутно выключаем прерывание наприем и включаем прерывание на окончание передачи и подаем высокий уровень на ногу которая у нас управляет передачей RS485:
if(rx)
{
rx=0;
tx_end=0;
USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);//выключение прерывания на прием
USART_ITConfig(USART3, USART_IT_TC, ENABLE); //включение на окончание передачи
GPIO_WriteBit(GPIOB,GPIO_Pin_2,Bit_SET);//нога на передачу rs485
GPIO_WriteBit(GPIOD,GPIO_Pin_10,Bit_SET); //светодиод
USART_SendData(USART3,tmp);//посылаем
}
Ну и естественно у нас срабатывает прерывание по окончанию передачи:
//Transmission complete interrupt
if(USART_GetITStatus(USART3, USART_IT_TC) != RESET)
{
USART_ClearITPendingBit(USART3, USART_IT_TC);//очищаем признак прерывания
tx_end=1; //признак окончания передачи для логики в главном цикле
}
И по признаку окончания прерывания снимем высокий потенциал с ног rs485 и светодиода, выключаем прерывание на окончание передачи и включаем на прием:
if(tx_end)
{
tx_end=0;
GPIO_WriteBit(GPIOB,GPIO_Pin_2,Bit_RESET);//выкл передачу у rs485
GPIO_WriteBit(GPIOD,GPIO_Pin_10,Bit_RESET);//выкл светодиода
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);//вкл прерывания на прием
USART_ITConfig(USART3, USART_IT_TC, DISABLE); //выкл на окончание передачи
}
Не забываем добавлять нужные компоненты из репозитария, нам нужен компонент MISC и USART кроме стандартных GPIO, RCC и компонентов CMSIS
Собственно все что хотел сказать. Не ясной темой для меня пока является NVIC — все вроде работает, но ищу внятного описания по приоритетам, подгруппам итп кто знает где найти поделитесь.
Зы я специально не стал убивать прототипы других уартов — возможно у кого то другая распиновка
Весь код:
#include "stm32f10x.h"
#include "stm32f10x_gpio.h"
#include "stm32f10x_rcc.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_conf.h"
#include "misc.h"
/***************************************************************************//**
* Declare function prototypes
******************************************************************************/
void SetupClock(void);
void SetupUSART1(USART_InitTypeDef USART_InitStructure);
void SetupUSART2(USART_InitTypeDef USART_InitStructure);
void SetupUSART3(USART_InitTypeDef USART_InitStructure);
USART_InitTypeDef USART_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
uint16_t tmp,rx,tx_end;
/***************************************************************************//**
* @brief Print symbols via USART3 -rs485
******************************************************************************/
void USART3_IRQHandler(void)
{
//Receive Data register not empty interrupt
if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
{
rx=1;
USART_ClearITPendingBit(USART3, USART_IT_RXNE);
tmp=USART_ReceiveData (USART3);
}
//Transmission complete interrupt
if(USART_GetITStatus(USART3, USART_IT_TC) != RESET)
{
USART_ClearITPendingBit(USART3, USART_IT_TC);
tx_end=1;
}
}
//*************************************************
int main(void)
{
SetupClock();
//setting parametrs common for all uarts
USART_InitStructure.USART_BaudRate = 9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
USART_InitStructure.USART_StopBits = USART_StopBits_1;
USART_InitStructure.USART_Parity = USART_Parity_No ;
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
//uarts inints
SetupUSART3(USART_InitStructure);
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); /* Enable Receive interrupts */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
/* Configure PB2 as rs485 tx select */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE);
/* Configure PD10 leds */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
GPIO_Init(GPIOD, &GPIO_InitStructure);
/* Output symbols on Hyperterminal using 3 ports 2 rs232 and rs485 */
while(1)
{
if(rx)
{
rx=0;
tx_end=0;
USART_ITConfig(USART3, USART_IT_RXNE, DISABLE);
USART_ITConfig(USART3, USART_IT_TC, ENABLE);
GPIO_WriteBit(GPIOB,GPIO_Pin_2,Bit_SET);
GPIO_WriteBit(GPIOD,GPIO_Pin_10,Bit_SET);
USART_SendData(USART3,tmp);
}
if(tx_end)
{
tx_end=0;
GPIO_WriteBit(GPIOB,GPIO_Pin_2,Bit_RESET);
GPIO_WriteBit(GPIOD,GPIO_Pin_10,Bit_RESET);
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE);
USART_ITConfig(USART3, USART_IT_TC, DISABLE);
}
}
}
/***************************************************************************//**
* @brief Setup clocks
******************************************************************************/
void SetupClock()
{
RCC_DeInit (); /* RCC system reset(for debug purpose)*/
RCC_HSEConfig (RCC_HSE_ON); /* Enable HSE */
/* Wait till HSE is ready */
while (RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);
RCC_HCLKConfig (RCC_SYSCLK_Div1); /* HCLK = SYSCLK */
RCC_PCLK2Config (RCC_HCLK_Div1); /* PCLK2 = HCLK */
RCC_PCLK1Config (RCC_HCLK_Div2); /* PCLK1 = HCLK/2 */
RCC_ADCCLKConfig (RCC_PCLK2_Div4); /* ADCCLK = PCLK2/4 */
/* PLLCLK = 8MHz * 9 = 72 MHz */
RCC_PLLConfig (RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
RCC_PLLCmd (ENABLE); /* Enable PLL */
/* Wait till PLL is ready */
while (RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);
/* Select PLL as system clock source */
RCC_SYSCLKConfig (RCC_SYSCLKSource_PLLCLK);
/* Wait till PLL is used as system clock source */
while (RCC_GetSYSCLKSource() != 0x08);
/* Enable USART1 and GPIOA clock */
// RCC_APB2PeriphClockCmd (RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
}
/***************************************************************************//**
* @brief Init USART1,2,3
******************************************************************************/
void SetupUSART1(USART_InitTypeDef USART_InitStructure)
{
GPIO_InitTypeDef GPIO_InitStructure;
//USART_InitTypeDef USART_InitStructure;
/* Enable GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1, ENABLE);
/* Configure USART1 Rx (PA10) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART1 Tx (PA9) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_Init(USART1, &USART_InitStructure);
USART_Cmd(USART1, ENABLE);
}
void SetupUSART2(USART_InitTypeDef USART_InitStructure)
{
/* Enable GPIOA clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
/* Configure USART2 Rx (PA3) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);
/* Configure USART2 Tx (PA2) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);
USART_Init(USART2, &USART_InitStructure);
USART_Cmd(USART2, ENABLE);
}
void SetupUSART3(USART_InitTypeDef USART_InitStructure)
{
/* Enable GPIOB clock */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
/* Configure USART3 Rx (PA11) as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOB, &GPIO_InitStructure);
/* Configure USART3 Tx (PA10) as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
USART_Init(USART3, &USART_InitStructure);
USART_Cmd(USART3, ENABLE);
}
- +3
- 19 августа 2011, 16:52
- GYUR22
Повесил на прерывание приема зажигание светодиода:
По принятию нужного символа, светодиод зажигается и сразу гаснет, хотя больше нигде его не трогаю. Причем, горит он не с постоянной длительностью. Что я делаю не так?
void USART1_IRQHandler(void)
{
if (USART_GetITStatus(USART1, USART_IT_RXNE) != (u16)RESET)
{
USART_ClearITPendingBit(USART1, USART_IT_RXNE);
int i = USART_ReceiveData(USART1);
if (i=='y')
{
GPIO_WriteBit(LED_PORT, LED_GREEN, Bit_SET);
}
else if (i=='n')
{
GPIO_WriteBit(LED_PORT,LED_GREEN, Bit_RESET);
}
}
}
По принятию нужного символа, светодиод зажигается и сразу гаснет, хотя больше нигде его не трогаю. Причем, горит он не с постоянной длительностью. Что я делаю не так?
кроме как по прерыванию, светодиодами нигде не управляю. А отладчик в кокосе чет тупит (stm32vl-discovery)
как показала жизнь — удобнее сначала запустить gdb сервер батником чтобы он просто висел и ждал коннекта, а потом при отладке к нему коннектиться (в командных строках ничего не писать только other & swd) только чтобы порт совпадал
Уже появилась 1.3 с поддержкой ST-Link
качается через CooCenter
www.coocox.org/Tools/CoCenter-1.4.5.exe
качается через CooCenter
www.coocox.org/Tools/CoCenter-1.4.5.exe
Или тут.
Забавно однако, что
1) Там, где упомянута 1.3.0 — 1.2.6 не упомянута вообще.
2) На главной страничке CoIDE предлагается слить 1.2.6, причем в качестве новинок указана как раз таки поддержка ST-Link.
Забавно однако, что
1) Там, где упомянута 1.3.0 — 1.2.6 не упомянута вообще.
2) На главной страничке CoIDE предлагается слить 1.2.6, причем в качестве новинок указана как раз таки поддержка ST-Link.
Вчера наткнулся на знатные грабли, оставлю тут на всякий случай:
Включение прерывания USART_IT_RXNE также автоматом включает прерывание по USART_FLAG_ORE (overrun error, переполнение приемного буфера, следующий байт пришел раньше, чем мы забрали предыдущий). Если его в прерывании не обработать, получим вечный цикл прерывания. Конечно, в нормальной ситуации такого происходить не должно, не такие уж высокие скорости по UART'у, но тем не менее. Долго искал баг, когда тестовый код, набитый лишней отладочной хренью в других прерываниях (для отладки кое-какой код запихнул прямо в прерывание от ADC), которая изредка (фиг отловишь с чего вдруг!) задерживала обработку приема байта и всё висло. Да ещё и под от отладчиком глюк не воспроизводился. Искал долго. В общем, лучше предусмотреть.
Включение прерывания USART_IT_RXNE также автоматом включает прерывание по USART_FLAG_ORE (overrun error, переполнение приемного буфера, следующий байт пришел раньше, чем мы забрали предыдущий). Если его в прерывании не обработать, получим вечный цикл прерывания. Конечно, в нормальной ситуации такого происходить не должно, не такие уж высокие скорости по UART'у, но тем не менее. Долго искал баг, когда тестовый код, набитый лишней отладочной хренью в других прерываниях (для отладки кое-какой код запихнул прямо в прерывание от ADC), которая изредка (фиг отловишь с чего вдруг!) задерживала обработку приема байта и всё висло. Да ещё и под от отладчиком глюк не воспроизводился. Искал долго. В общем, лучше предусмотреть.
Комментарии (20)
RSS свернуть / развернуть