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

В прошлой статье было описано как бороться с усартами в STM32 c помощью CooCox IDE 1.2.5, но сделано это было не совсем идеологически верно — без прерываний. В данном опусе хочу немного закрыть этот пробел на примере 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

Комментарии (20)

RSS свернуть / развернуть
Опередил! :-) Я было начал кропать статью с прерываниями и usart… Хотел написать, как с компа можно управлять мощной нагрузкой посредством ключиков mosfet
0
Напиши про использование RCC библиотеками подробнее, думаю, будет интересно
0
Я тут щас последнюю на ближайшее время статейку тисну про модбас и прекращу пока писательство
так что тебе все карты в руки про RCC.
0
Повесил на прерывание приема зажигание светодиода:
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);
			}
	}
}

По принятию нужного символа, светодиод зажигается и сразу гаснет, хотя больше нигде его не трогаю. Причем, горит он не с постоянной длительностью. Что я делаю не так?
0
в главном цикле — есть гашение светодиодов по окончанию предачи не совпадает ли оно по ногам с вашим светодиодом?
зы ваще конечно отладка рулит
0
кроме как по прерыванию, светодиодами нигде не управляю. А отладчик в кокосе чет тупит (stm32vl-discovery)
0
как показала жизнь — удобнее сначала запустить gdb сервер батником чтобы он просто висел и ждал коннекта, а потом при отладке к нему коннектиться (в командных строках ничего не писать только other & swd) только чтобы порт совпадал
0
Коннеект-то есть. Отлаживать невозможно. Либо это какие-то мегатормоза, либо что-то я туплю. Step into/over жмакаю и все. Отладчик уходит в глубокое задумчивое состояние
0
Это погода такая у меня сейчас eeprom не работает… вон ниид хелп написал может старшие пацаны че подскажут :)
шлите ваш код в личку
0
Обновился сооcox качаем www.coocox.org/Tools/CoIDE-1.2.6.exe
0
Уже появилась 1.3 с поддержкой ST-Link
качается через CooCenter
www.coocox.org/Tools/CoCenter-1.4.5.exe
0
Или тут.
Забавно однако, что
1) Там, где упомянута 1.3.0 — 1.2.6 не упомянута вообще.
2) На главной страничке CoIDE предлагается слить 1.2.6, причем в качестве новинок указана как раз таки поддержка ST-Link.
0
  • avatar
  • Vga
  • 10 сентября 2011, 03:20
качал 1.26 там нет st-link
0
и чето 1.3 не могу запустить с st-link…
0
Значится на win 7 64 CoIDE с ST-link у меня не запустился… если отдельно запустить coflash то он вешается при попытке программирвания

НО! На XP 32 все работает…
0
STM32 ST-LINK Utility спокойно качаеться и без проблем шьёт.
0
у вас кажется опечатка вкралась

«Ну и естественно у нас срабатывает прерывание по окончанию приема»
вместо «Ну и естественно у нас срабатывает прерывание по окончанию передачи»
0
  • avatar
  • Sarog
  • 10 октября 2011, 17:19
Спасибо поправил!
0
Нельзя ли схемку как канальный уровень был сделан?
развязки если есть, шунты, согласование на 3/3.3в, етс
0
  • avatar
  • valio
  • 29 октября 2011, 18:11
Вчера наткнулся на знатные грабли, оставлю тут на всякий случай:
Включение прерывания USART_IT_RXNE также автоматом включает прерывание по USART_FLAG_ORE (overrun error, переполнение приемного буфера, следующий байт пришел раньше, чем мы забрали предыдущий). Если его в прерывании не обработать, получим вечный цикл прерывания. Конечно, в нормальной ситуации такого происходить не должно, не такие уж высокие скорости по UART'у, но тем не менее. Долго искал баг, когда тестовый код, набитый лишней отладочной хренью в других прерываниях (для отладки кое-какой код запихнул прямо в прерывание от ADC), которая изредка (фиг отловишь с чего вдруг!) задерживала обработку приема байта и всё висло. Да ещё и под от отладчиком глюк не воспроизводился. Искал долго. В общем, лучше предусмотреть.
0
  • avatar
  • ACE
  • 14 марта 2014, 21:10
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.