:::: MENU ::::

Примеры использования StdPeriph — USART

В данной серии статей будут приведены примеры работы с периферией STM32L с помощью библиотеки, предоставляемой ST — StdPeriph. Перед использованием примеров не забывайте включать, соответствующие файлы библиотеки в проект.

USART

GPIO_InitTypeDef GPIO_InitStruct;
USART_InitTypeDef USART_InitStruct;
    
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //вкл тактирования USARTx 
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //вкл тактирования портов ножек USARTx
    
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //(указать ножки USART)
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //(AF - альтернативная функция ножек)
GPIO_InitStruct.GPIO_Speed = GPIO_Speed_10MHz; //(max частота тактирования ножек)
GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //(_PP - push/pull output, _OD - open drain output)
GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
GPIO_Init(GPIOA, &GPIO_InitStruct);
    
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
    
USART_InitStruct.USART_BaudRate = 9600; 
USART_InitStruct.USART_WordLength =  USART_WordLength_8b; //(_9b)
USART_InitStruct.USART_StopBits = USART_StopBits_1; //(_0_5, _2, _1_5)
USART_InitStruct.USART_Parity = USART_Parity_No; //(_Even, _Odd)
USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; 
USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //(_RTS, _CTS, _RTS_CTS)
USART_Init(USART1, &USART_InitStruct);
USART_Cmd(USART1, ENABLE);

while(!USART_GetFlagStatus(USART3, USART_FLAG_RXNE)); // прием
x = USART_ReceiveData(USART3);

USART_SendData(USART3, x); // передача
while(!USART_GetFlagStatus(USART3, USART_FLAG_TC));

// передача последовательных данных
float Temp; 
unsigned char* ptr;// 8 бит, для передачи (адрес)

ptr = (unsigned char *) &Temp; // float более 8 бит поэтому приводим к 8 битам и поэтапно передаем

data_usart = *ptr;

USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
            
data_usart = *(ptr+1);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
            
data_usart = *(ptr+2);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));
            
data_usart = *(ptr+3);
USART_SendData(USART1, data_usart);
while(!USART_GetFlagStatus(USART1, USART_FLAG_TC));

прерывание USART

// настройка прерывания по usart
void USART_1_nvic(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
    
  /* Configure the NVIC Preemption Priority Bits */
  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);
    
  /* Enable the USART2 Interrupt */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
  NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  
  NVIC_Init(&NVIC_InitStructure);
    
  // включение прерывания по приему и по передачи
  USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
  //USART_ITConfig(USART1, USART_IT_TXE, ENABLE); при передаче разрешить
}

void USART1_IRQHandler(void)
{
    /* Прерывание по приему байта по USART */
    if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {
        USART_ClearFlag(USART1, USART_IT_RXNE);
                // func(); - функция обработчик
    }
    if(USART_GetITStatus(USART1, USART_IT_TXE) != RESET)
    {
        USART_ClearFlag(USART1, USART_IT_TXE);
                // func(); - функция обработчик
    }
}

Прерывания от TXE — буфер передачи USART пуст, происходит сразу после разрешения данного прерывания, конечно, если вы ничего не передаете в данный момент. Поэтому, для того что-бы передать данные вы создаете буфер с данными, которые надо передать. Разрешаете прерывание USART_IT_TXE:

USART_ITConfig(USART1, USART_IT_TXE, ENABLE);

В функции обработчика прерывания на передачу, передаете данные из буфера на USART:

USART_SendData(USART1, send_buf[i]);

После того как вы передали все необходимые данные, не забудьте отключить прерывания. Иначе, поскольку буфер передачи USART будет пуст, прерывания будут происходить постоянно.

USART_ITConfig(USART1, USART_IT_TXE, DISABLE);

Прием прост — при приеме данных по USART происходит прерывание и в его обработчике вы складываете данные в приемный буфер:

rec_buf[i] = USART_ReceiveData(USART1);


Note: небольшая заметка об USART:

Запись 8-N-1, значит 8 бит данных, нет проверки четности и 1 стоп бит.

USART_sign

Стоп битов может быть 1, 1.5, 2. Кроме того, если стоит проверка четности/нечетности, то перед стоп битом вставляется этот бит проверки. Информационных бит тоже может быть меньше 8.

Нет сообщения — высокий уровень.
Сообщение появляется — передатчик опускает линию (1 бит всегда старт бит) — старт бит.

В стандарте RS232 логическая единица передается напряжением -12В.
12Vs


  • Руслан Александрович

    А что нам дает функция USART_1_nvic()? Для чего в данном случае нужно настраивать NVIC?

    • badembed

      C USART можно работать через:

      — прерывания;

      — в основном цикле программы проверяя флаги конца передачи/приема.

      USART_1_nvic — настраивает прерывания (в STM32, этот модуль называется NVIC — Nested Vectored Interrupt Controller).
      А сам вектор прерывания от USART1 указывает на функцию USART1_IRQHandler. Таким образом по прерыванию от USART1 будет вызываться эта функция, в ней проверяются флаги (по какой причине произошло прерывание, т.к. причин > 1, а вектор прерывания только 1), и вызываются соответствующие действия. Таким образом, весь прием и передачу можно вынести в прерывания.

      Если же работаешь без прерываний, то можно читать и писать в USART, как в первом примере.

      USART_SendData(USART1, data_usart);
      while(!USART_GetFlagStatus(USART1, USART_FLAG_TC)); // передача

      while(!USART_GetFlagStatus(USART3, USART_FLAG_RXNE)); // прием
      x = USART_ReceiveData(USART3);

      • Руслан Александрович

        Спасибо за ответ.
        А что, если из всех настроек NVIC исполшьзовать только строчку:
        NVIC_EnableIRQ(USART1_IRQn);
        ?

        • badembed

          Все должно работать и если нет необходимости заморачиваться с приоритетами можно так.

          Просто, тогда приоритет прерывания USART1, будет тот который стоял по умолчанию (при сбросе МК) в регистре NVIC->IP. По умолчанию там нули, а значит приоритет этого прерывания будет самый высокий.

          • Руслан Александрович

            Спасибо. Теперь все ясно.