Авг 172012
 

Данная статья – лишь небольшое дополнение к предыдущей части. Здесь рассмотрим настройки USART STM32 с использованием стандартных библиотек. Полный контроль над кодом программы и содержимым регистров на каждом шаге – это замечательно, но в данном случае использование библиотек тоже имеет положительные стороны.

Какие именно? Давайте заглянем в библиотечный исходник “stm32l1xx_usart.c”. Здесь есть функция, в которой заданы типовые настройки, можно просто вызвать ее и настройка модуля USART будет произведена с определенными параметрами:

void USART_StructInit(USART_InitTypeDef* USART_InitStruct)
{
  /* USART_InitStruct members default value */
  USART_InitStruct->USART_BaudRate = 9600;
  USART_InitStruct->USART_WordLength = USART_WordLength_8b;
  USART_InitStruct->USART_StopBits = USART_StopBits_1;
  USART_InitStruct->USART_Parity = USART_Parity_No ;
  USART_InitStruct->USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
  USART_InitStruct->USART_HardwareFlowControl = USART_HardwareFlowControl_None;  
}

Удобно конечно, но есть еще один нюанс. Обратите внимание на настройки скорости обмена в этой функции:

USART_InitStruct->USART_BaudRate = 9600;

Как видим, скорость обмена здесь прописывается прямо в бодах, а процедуру вычисления числа, заносимого в регистр USART_BRR ( содержит дробный коэффициент деления, на который делится тактовая частота для получения нужной скорости обмена), библиотечные функции берут на себя.

Представим исключительную ситуацию, когда пропал внешний тактовый сигнал микроконтроллера. Маловероятно что “отвалится” кварц, но ведь контроллер может тактироваться и внешним синхросигналом. А если этот сигнал вдруг пропадает или происходит сбой (помехи), что будет в этом случае? У внутренней схемы формирования тактовой частоты STM32 есть система защиты, в которой предусмотрен данный случай. Тогда STM32 перейдет на тактирование от собственного внутреннего генератора, отключив при этом внешний источник HSE, а заодно и PLL (см. STM32L. Система формирования тактовых частот Reset and Clock Control (RCC)). Теперь STM32 будет тактироваться от внутреннего источника, для STM32F это будет HSI с частотой 8 МГц, а для STM32L – MSI с частотой 2.097 МГц. А что произойдет с модулем USART в данном случае? При изменении частоты тактирования скорость передачи/приема USART тоже изменится, поскольку в регистре USART_BRR записано число, задающее скорость обмена для другой тактовой частоты. При такой неприятности система защиты выдаст прерывание, по которому можно заново вызвать функцию инициализации USART и требуемая скорость обмена будет восстановлена.

Удобно, конечно, но ознакомившись с библиотечным файлом “stm32l1xx_usart.c”, я разочаровался. Все таки они, библиотеки, недоделанные какие-то, “сырые”. Что сразу не понравилось. Во-первых, в последней библиотеке версии 1.1.1 есть модули USART4 и USART5, которых в STM32L152RBT6 нету (это чип с STM32L-DISCOVERY). А компилятор сразу выдает ошибки. Проблема конечно – мелочь, но заниматься адаптацией неохота. Есть предыдущая версия 1.1.0, которая была до появления новых чипов, там эти модули не прописаны, ее я и использовал. Для платы STM32L-DISCOVERY большего и не надо, все изменения введены из-за обновления линейки микроконтроллеров. Во-вторых, в функции передачи значения через USART не заметил проверки установки флага TC, сигнализирующего о завершении передачи предыдущего значения. Всего одну строку можно было прописать. И еще “баг” – иногда первым символом после сброса МК, программа Terminal почему-то принимает точку. Следующие символы идут именно те, что прописаны в программе. С этим вообще разбираться не стал, поскольку при настройках напрямую через регистры в порт шло только то, что было в программе и ничего лишнего. Дальше пока не копался, в ближайших планах статья о полноценном обмене данными через USART, где передача/прием будут настроены в обе стороны.

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

  • stm32l1xx_rcc.c
  • stm32l1xx_gpio.c
  • stm32l1xx_usart.c

Файлы исходников для IAR

В настройках проекта в секции C/C++ Compiler –> Preprocessor прописываем следующие значения в поле Defined symbols (см. рисунок):

Опции проекта с библиотеками

Первое значение задает нашу линейку STM32 (это необходимо только для последней версии библиотек), а второе сразу оптом подключит все необходимые заголовочные файлы — “хидеры”.

Далее текст программы с комментариями. Программа написана для отладочной платы STM32L-DISCOVERY, но и для серии STM32F отличия в коде будут несущественные, только в разделе инициализации порта. В ближайшее время возможно дополню эту статью кодом программы для серии STM32F.

#include "stm32l1xx.h"

//Структуры для инициализации GPIOA и USART1
GPIO_InitTypeDef    GPIO_InitStruct;
USART_InitTypeDef    USART_InitStruct;

void USART1_Send(uint8_t); //Объявление функции передачи символа

int main()
{
  //Инициализация вывода PA9 - USART1_TX
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //Включаем тактирование GPIOА
  
  //Для вывода PA9 выбираем альтернативную функцию работы с USART1
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  
  GPIO_InitStruct.GPIO_Pin = (GPIO_Pin_9); //Настройки будут производится для вывода PA9
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //Режим альтернативной функции
  GPIO_InitStruct.GPIO_OType = GPIO_OType_PP; //Выход Push-Pull
  GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL; //Выход без подтягивающих резисторов
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_40MHz; //Скорость порта максимальная
  GPIO_Init(GPIOA, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOА
  
  
  //Инициализация USART1
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //Включаем тактирование USART1
  
  USART_InitStruct.USART_BaudRate = 9600; //Скорость обмена 9600 бод
  USART_InitStruct.USART_WordLength = USART_WordLength_8b; //Длина слова 8 бит
  USART_InitStruct.USART_StopBits = USART_StopBits_1; //1 стоп-бит
  USART_InitStruct.USART_Parity = USART_Parity_No ; //Без проверки четности
  USART_InitStruct.USART_Mode = USART_Mode_Tx; //Включен только передатчик USART1
  USART_InitStruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
  USART_Init(USART1, &USART_InitStruct); //Заданные настройки сохраняем в регистрах USART1
  
  USART_Cmd(USART1, ENABLE); //Включаем USART1
  
  //Далее бесконечный цикл передачи символов "STM32"
  while(1)
  {
    //Вызываем фунуцию передачи символа
    USART1_Send('S');
    USART1_Send('T');
    USART1_Send('M');
    USART1_Send('3');
    USART1_Send('2');
    USART1_Send('n');
    USART1_Send('r');
    for(uint32_t i=0; i<0x0004FFFF; i++); //Временная задержка 
  }
}

//Функция передачи символа
void USART1_Send(uint8_t Data) 
{
  while(!(USART1->SR & USART_SR_TC)); //Проверяем установку флага TC - завершения предыдущей передачи 
  USART1->DR = Data; //Записываем значение в регистр данных - передаем символ
}

Готовый проект можно загрузить по ссылке:

Проект для USART STM32L с использованием стандартных библиотек

Другие статьи:

  7 Responses to “STM32. USART. Часть 3”

  1. «И еще “баг” – иногда первым символом после сброса МК, программа Terminal почему-то принимает точку.»
    Разобрался с причиной. Точка в UART вылазит при присвоении выводу порта альтернативной функции, вот в этом месте:

    //Для вывода PA9 выбираем альтернативную функцию работы с USART1
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);

    Перенес эту функцию до выполнения всех остальных операций по настройке вывода порта — «баг» исчез. При настройке непосредственно через регистры, без библиотек, такого не было. В тексте статьи и архиве с проектом тоже поправил.

  2. Я начал знакомиться с STM-семейством и прикупил STM32F4Discovery. В качестве IDE — CoCox.

    По дефолту (частота 16 МГц) все завелось без проблем, но при попытке вызвать SystemInit() — устанавливается частота камня 168 Мгц — и все сбивается — в терминал на ПК лезет мусор. Хотя я использую стандартные библиотеки, где по идее должен идти пересчет под текущую частоту…

    Подскажите пожалуйста что не так.

  3. здравствуйте, я загрузил ваш готовый проет, плата прошилась и все вроде бы нормально, но вот терминал принимает не понятные символы:
    WÊ26ÖÊ•-fÛÖÊ••-fÛÖÊ•-fÛÖÊ•-fÛÖÊ•-fÛÖÊ••-fÛÖÊ•-fÛÖÊ
    подскажите в чем может быть проблема, заранее спасибо.

  4. Может скорость не та, еще раз внимательно посмотрите все настройки. Точную причину на расстоянии сложно определить, тем более я с такой проблемой не сталкивался. А может с кодировкой что не так. Попробуйте посмотреть принятые символы в шестнадцатеричном коде, если это возможно, для проверки правильности приема.

  5. все проверял и не раз(скорость, стоповый и стартовый биты, а также паритета), а где можно посмотреть кодировку передачи? есть мнение что в IARе что то не то. заранее спасибо

    • А какие подозрения насчет IAR? Крякнутый что-ли?
      См. скриншот программы терминала в статье
      http://chipspace.ru/stm32-usart-1/
      там нужно переставить галку с ASCII в HEX.
      Преобразователь USB — UART работает нормально, есть уверенность? Если есть возможность, то посмотреть осциллографом сигналы на выходе платы Дискавери.