Авг 192012
 

В завершающей части рассмотрены примеры работы с модулем USART микроконтроллеров серий STM32F и STM32L, и, в данном случае уже осуществляется двунаправленный обмен данными между компьютером и микроконтроллером. Изменения в настройках будут небольшие – всего лишь разрешим работу приемника USART и сконфигурируем под него нужный вывод GPIO. Ниже будут приведены примеры программ, проверенные на двух отладочных платах:

  • STM32L-DISCOVERY (серия STM32L) и
  • STM32VL-DISCOVERY (серия STM32F),

а также в конце статьи можно загрузить готовые проекты в IAR.

В предыдущих примерах к преобразователю USB<—>UART, собранному на микросхеме FT232RL, подключался только один вывод микроконтроллера USART1_Tx, поскольку там выполнялась передача данных только в направлении микроконтроллер STM32 –> компьютер. Теперь же будет задействован еще один вывод — USART1_Rx, через него микроконтроллер будет принимать данные от компьютера.

USART_Rx_Tx

Для включения приемника USART1 необходимо выполнить следующие операции:

  • Настроить вывод PA10 на работу в качестве входа для USART1. Это должен быть вход без подтягивающих резисторов (Floating Input) и в режиме альтернативной функции.
  • Разрешить работу приемника USART1. Физически это выполняется установкой бита RE — Receiver enable в управляющем регистре USART_CR1.

Алгоритм программы будет следующий:

  • Инициализация периферии: включение тактирования нужных модулей, настройка выводов порта, настройка приемопередатчика USART1
  • После инициализации шлем компьютеру сообщение о готовности к работе
  • Ожидаем поступления данных от компьютера – это бесконечный цикл, в нем проверяем состояние бита RXNE регистра USART_SR. Установка этого бита означает, что регистр данных не пустой, в него поступили данные
  • Если бит RXNE установлен, считываем данные
  • Эти же данные отправляем обратно

Ниже приведены тексты программ для двух серий – STM32L и STM32F. Отличия в них минимальные и касаются только настроек задействованных выводов портов, поскольку порты GPIO в этих сериях имеют некоторые отличия, в особенности это касается их регистров. Настройки USART будут абсолютно одинаковы, даже выводы портов используются те же самые, так как в данном случае эти устройства STM32 являются pin-to-pin совместимыми.

Пример кода для серии STM32F (проверен на плате STM32VL-DISCOVERY):

#include "stm32f10x.h"

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

void Init(void); //Объявление функции инициализации периферии
void Usart1_Send_symbol(uint8_t); //Объявление функции передачи символа
void Usart1_Send_String(char* str); //Объявление функции передачи строки

char* str;
uint8_t data;


int main()
{
  Init(); //Вызов функции инициализации периферии
  //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
  Usart1_Send_String("I'm ready");
  while(1)
  {
    if((USART1->SR & USART_SR_RXNE)) //Проверяем поступление данных от компьютера
    {
      data = USART1->DR; //Считываем принятые данные
      Usart1_Send_symbol(data); //И тут же отсылаем их обратно
    }
  }
}

//Функция инициализации периферии
void Init()
{
  //Включаем тактирование GPIOA, USART1 и альтернативных функций AFIO 
  RCC_APB2PeriphClockCmd((RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO), ENABLE);
  
  //Инициализации вывода PA9 - USART1_Tx
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9; //Настройки вывода PA9
  GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz; //Скорость порта максимальная
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP; //Режим альтернативной функции, выход Push-Pull
  GPIO_Init(GPIOA, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOА
  
  //Инициализации вывода PA10 - USART1_Rx
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //Настройки вывода PA10
  GPIO_InitStruct.GPIO_Mode  = GPIO_Mode_IN_FLOATING; //Input floating
  GPIO_Init(GPIOA, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOА
  
  
  //Инициализация 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_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Включен передатчик и приемник USART1
  USART_Init(USART1, &USART_InitStruct); //Заданные настройки сохраняем в регистрах USART1
  
  USART_Cmd(USART1, ENABLE); //Включаем USART1
}

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

//Функция передачи строки через USART
void Usart1_Send_String(char* str)
{
  uint8_t i=0;
  while(str[i])
  {
    Usart1_Send_symbol(str[i]);
    i++;
  }
  Usart1_Send_symbol('n');
  Usart1_Send_symbol('r');
}

Пример кода для серии STM32L (проверен на плате STM32L-DISCOVERY):

#include "stm32l1xx.h"

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

void Init(void); //Объявление функции инициализации периферии
void Usart1_Send_symbol(uint8_t); //Объявление функции передачи символа
void Usart1_Send_String(char* str); //Объявление функции передачи строки

char* str;
uint8_t data;

int main()
{
  Init(); //Вызов функции инициализации периферии
  //Передаем строку, сообщающую о готовности микроконтроллера к обмену данными
  Usart1_Send_String("I'm ready");
  while(1)
  {
    if((USART1->SR & USART_SR_RXNE)) //Проверяем поступление данных от компьютера
    {
      data = USART1->DR; //Считываем принятые данные
      Usart1_Send_symbol(data); //И тут же отсылаем их обратно
    }
  }
}

//Функция инициализации периферии
void Init()
{
  //Инициализация выводов: PA9 - USART1_TX, PA10 - USART1_RX
  RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //Включаем тактирование GPIOА
  
  //Для выводов PA9, PA10 выбираем альтернативную функцию работы с USART1
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
  
  //Инициализации вывода PA10 - USART1_Rx По умолчанию он Input floating
  GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10; //Настройки вывода PA10 
  GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF; //Режим альтернативной функции
  GPIO_Init(GPIOA, &GPIO_InitStruct); //Заданные настройки сохраняем в регистрах GPIOА
  
  //Инициализации вывода PA9 - USART1_Tx
  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_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
  USART_InitStruct.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Включен передатчик и приемник USART1
  USART_Init(USART1, &USART_InitStruct); //Заданные настройки сохраняем в регистрах USART1
  
  USART_Cmd(USART1, ENABLE); //Включаем USART1
}


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


//Функция передачи строки через USART
void Usart1_Send_String(char* str)
{
  uint8_t i=0;
  while(str[i])
  {
    Usart1_Send_symbol(str[i]);
    i++;
  }
  Usart1_Send_symbol('n');
  Usart1_Send_symbol('r');
}

Подключаем железо, запускаем программу Terminal. В программе Terminal устанавливаем галочку в поле CR в секции передатчика, она находится внизу окна. При этом к передаваемой строке в конце добавляется управляющий символ, это дает нам возможность осуществлять автоматический перевод строки при пересылке тех же данных обратно в компьютер. Далее коннектимся к виртуальному порту, запускаем в IAR загрузку программы в плату, а затем её выполнение. Должны увидеть в Terminal прием строки “I’m ready” – микроконтроллер настроен и готов к обмену данными. В текстовом поле передатчика (внизу окна) набираем текст посылки и жмем кнопку Send. Не оригинальничая, я набрал там текст “Hello World!!!”. После каждого нажатия кнопки Send мы должны наблюдать отправку и прием этих символов в соответствующих полях программы Terminal, как видно на картинке ниже:

Terminal_usart_4

Максимальную скорость обмена “выжал” 256000 бод для STM32VL-DISCOVERY и 128000 бод для STM32L-DISCOVERY. Это потому, что на плате STM32L-DISCOVERY нет внешнего кварца и при настройках по дефолту тактирование будет от внутреннего источника MSI с частотой всего лишь 2,097 МГц.

Ну, вот и все. Архивы с проектами в IAR можно скачать по ссылкам:

Пример для платы STM32VL-DISCOVERY (серия STM32F)

Пример для платы STM32L-DISCOVERY (серия STM32L)

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

 

  52 Responses to “STM32. USART. Часть 4 — Финал”

  1. Nosferatu

    Чего то у меня с «STM32L-DISCOVERY», в терминале отображается только то, что я отправляю, а строка “I’m ready” не отображается.
    В двух проектах из предыдущих статей тоже нечего не отображается, ошибок при этом ни каких не выдаёт.

    • Проекты именно мои не работают, загруженные с сайта? Предлагаю перейти на форум, там можно картинки прикрепить. Хотелось бы скриншот программы Терминал посмотреть.
      Схема один в один воспроизведена? Линии Rx < --> Tx не перепутаны?
      Светодиоды на FT232 запаяны? По ним можно контролировать прием-отправку с этой микросхемы.
      А вообще именно с этой платой пришлось больше всего поплясать с бубном при настройке UART, а также бутлодера. Что на плате stm32vl-discovery, что на макетке с stm32f103 все с полпинка запустилось.

  2. В проекте на (серия STM32L) поправь вот эту строчку.У Вас там восклицательный знак упущен.
    while(!(USART1->SR & USART_SR_TC)); //Проверяем установку флага TC — завершения предыдущей передачи

  3. Спасибо, поправлю.

  4. здравствуйте, я Вам писал в предыдущей статье о передачи не понятных символов с платы Stm32l, теперь я тоже самое сделал и с этими готовым проектом только зашил всё это на другую плату, а точнее на Stm32-H103, проект скомпелировался, но проблема осталась та же, подскажите чего делать?

  5. Надо разобраться все же в причине неверного приема с платы STM32L-DISCOVERY. У меня нет платы STM32-H103, проверить я на ней не могу. Да и таких проблем, как у вас, у меня не было. Разбираться все-таки вам придется самому, мне просто невозможно проверить что у вас пошло не так, я не экстрасенс.
    Либо высылайте полную информацию:
    — схема подключения (полностью, все мельчайшие детали), не на словах, а именно рисунок;
    — используемая программа терминала (высылайте саму программу);
    — настройки терминала во всех подробностях, можно скриншоты.
    — какой преобразователь USB-UART используете, с какими драйверами.

  6. 1. Программа терминала скачана с вашего сайта, по ссылке в одной из четырех частей статьи об USART.
    2. настройка терминала полностью совпадает с вашим скриншотом терминала.
    3. преобразователь USB-UART использую, однако сегодня проверял на осцилографе, передача даннных с компьютера через преобразователь выходит верной, но после приема на плату и передачи обратно на ком-порт еще до преоразователя, получается чушь, также подключал ножки ввода/вывода самой платы к ком-порту тоже самое.
    4. передвал «1» по таблице ASCII, это в HEX должно 031, на выходе из преобразователя USB-USART или на входе платы, посмотрел осцилографом, все нормально, а вот IAR в HEX показывает 067.

    • Вы опять же даете мне только результат, и никакой информации более. Если все точь в точь как у меня, то повторюсь, я не сталкивался с такой проблемой. Рад бы помочь, но как? Может быть я подобное видел при несовпадении скорости, точно не помню. Может все же что-то сделано не совсем так, как у меня?
      Я повторюсь, надо больше информации:
      — схема
      — осциллограф цифровой? можно записать осциллограммы?
      — скриншоты IAR с принятыми данными
      Здесь важно все до мелочей. На вопрос «все точно так же, но не работает, почему?» дать ответ просто невозможно.

    • Скайп есть? Аська? Зашли в почту mailbox@chipspace.ru, пообщаемся плотней завтра, сейчас у нас уже ночь. Думаю так быстрей выйдет.

    • И еще раз повторю, что нужны:
      — схема;
      — настройки терминала (скриншоты);
      — какой преобразователь USB-UART используете, с какими драйверами;
      — осциллограммы, если возможно;
      — скриншоты IAR с принятыми данными.
      Только тогда буду разбираться. Еще раз повторю, что не экстрасенс.

    • «Программа терминала скачана с вашего сайта, по ссылке в одной из четырех частей статьи об USART.»
      Получил программу в письме. Я такой не выкладывал.
      Давайте сначала запустим все так же, как у меня в статье, с тем же терминалом.
      Я напомню, вы уже обращались с проблемой, и проблему вам создал «крякнутый» IAR.
      Тут лучше действовать последовательно и взять за основу проверенный проект без каких либо изменений. А потом уже творчество :).
      Шлите данные заново. Возможно, что вопросов еще будет много.

  7. неплохо было бы написать сразу про использование усарт с дма.

  8. Друг, не работает!
    у меня видимо другая ревизия платы.
    В твоём проекте: STM32L152xB
    у меня = STM32L152xС
    поэтому при попытке отладить ругается:

    Mon Sep 23, 2013 23:39:10: Loaded macro file: D:\IAR\arm\config\flashloader\ST\FlashSTM32L15x_L16x.mac
    Mon Sep 23, 2013 23:39:10: ST-Link firmware too old
    Mon Sep 23, 2013 23:39:10: Selecting SWD as current target interface.
    Mon Sep 23, 2013 23:39:10: Hardware reset with strategy 0 was performed
    Mon Sep 23, 2013 23:39:10: Initial reset was performed
    Mon Sep 23, 2013 23:39:10: 736 bytes downloaded (4.18 Kbytes/sec)
    Mon Sep 23, 2013 23:39:10: Loaded debugee: D:\IAR\arm\config\flashloader\ST\FlashSTM32L15xxxRAM16K.out
    Mon Sep 23, 2013 23:39:10: Target reset
    Mon Sep 23, 2013 23:39:11: Skipping flash loading pass because there is no data in the designated range: 0x8080000-0x8080FFF.
    Mon Sep 23, 2013 23:39:11: Downloaded D:\IAR\projects\STM32L-DISCOVERY_usart_4\STM32L_usart_4\Debug\Exe\c.out to flash memory.

    как поменять в проекте эту настройку правильно, подскажи плиз?

    • ага, поменял ревизию.
      теперь проблема такая:
      на стороне модема получаю вот что:
      <<>>
      а при отправке с модема, в ответ ничего не приходит.

      Помоги разобраться пожалуйста?
      Уже до этого в кейле твой проект пытался оживлять, там так же — отправка с платы работает, а приём — нет.
      Есть тимвьюер, могу по камере скайпа показать, как оно соединено.

  9. кто-то съел данные.
    вот что на стороне модема:

    root@OpenWrt:~# cat /dev/ttyATH0
    I’m ready

    I

    I

    I

  10. Даже не знаю на что думать, столько проблем сразу вылезло. Попробуй заново создать проект, только пользуйся нормальной IDE, не крякнутой, на эти грабли уже наступали. Попробуй простейший пример, что-то послать и принять, потом дальше двигайся. Если есть осциллограф, то глянь что реально идет по проводам, посылай простейшие символы и смотри что реально передается. Проверь настройки скорости обмена, тоже может быть причиной неверного приема.

  11. ура, решилось.

    приём платой проверял обратной отправкой того же самого.
    на модеме принимал командой «cat /dev/ttyATH0»
    А она, злодейка, текстовая, т.е. пока не пошлёшь символ новой строки, всё принятое держит в буфере, не отображает.

  12. Здравствуйте! Прошу оказать помощь. Пробую настроить USART1 на STM32L-DISCOVERY. Инициализацию портов и самого USART1 беру из вашей статьи. В отладчике не работает запись данных в регистр DR для передачи, т.е. эта строчка: USART1->DR = data; В регистре DR всегда находятся нули. Могу отправить код программы на почту.

  13. Так и должно быть, в отладчике содержимое регистра DR будет нулевым. Когда ты его смотришь в отладчике, там все уже передано и регистр пустой. Тут разница в том, что отладчик шагает по программе, а периферия работает аппаратно и отладчик видит только текущие фиксированные состояния регистров.

    • Значит ли это что флаг TC в отладчике будет всегда установлен?

      • И ещё проблема, на работе встроенный (в плату STM32L-DISCOVERY) ST-link V2 работает как и положено на USB 2.0. Дома при подключении на порт USB 2.0 работает со скоростью USB 1.0. Пробовал и разные порты и BIOS ковырял и драйвера все перепробовал — ничего не помогает. А все флешки работают на скорости USB 2.0 во всех портах. Подскажите, как настроить ST-link V2 на работу со скоростью USB 2.0 ?

      • Не факт, что какой-либо флаг будет отображаться верно в отладчике. Точнее сказать, он может быть и установится и сбросится последовательно, но ни вы, ни отладчик этого не успеете увидеть.

      • По поводу USB и всего что внутри компьютера, для меня это темный лес, как там все работает. Конечно, я отличу жесткий диск от блока питания, но не более того. :)
        По моему скорость работы непостоянна и может меняться.

  14. Возможно ли реализовать следующую программу в микроконтроллере:

    — инициализация портов и USART1;

    — разрешить прерывание по приему сообщения: USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);

    — сделать отправку сообщения по USART по нажатию пользовательской кнопки;

    — принять сообщение и выйти в программу обработчика прерывания.

    При этом контроллер НЕ БУДЕТ связан с ПК! Вывод микроконтроллера TX будет соединен с выводом RX. Такое своеобразное «Эхо» внутри контроллера. Возможно ли это?

    • А попробовать сложно? :) Даже com-порта не надо задействовать. Теоретически должно сработать, поскольку регистр данных фактически разделен на 2 — передатчика и приемника, то есть они разные. А практически что-то я не пробовал.

  15. Я попробовал. Прерывание по приему сообщения (USART_ITConfig(USART1, USART_IT_RXNE, ENABLE)) не срабатывает ни в какую. На отправку работает, на прием — нет. Готов прислать код программы, может подскажите в чем я косячу?

  16. Да я ж сам не пробовал, может и правда так не будет работать. Там же еще один UART есть как минимум, может его лучше на прием задействовать.

  17. А возможно ли организовать следующую идею:
    1) Подключить только кабель к COM-порту;
    2) Замкнуть в кабеле выводы RX и TX;
    3) С помощью программы Terminal отправить сообщение на COM-порт;
    4) Будет ли получено это сообщение ПК? Возможно ли организовать такую программу «Эхо» для проверки работоспособности COM-порта?

  18. Блин, а у меня не работает. Придется искать другой кабель.

  19. Все сделал как у вас в статье, при подключении STM32L посылает на ПК символ и больше ничего не происходит.

  20. Че за фигня! Символ 0

  21. Причем если замыкаю rx и tx на преобразователе, «Эхо» работает. Значит косяк в программе.

  22. Хочу сделать дальномер на основе ИК датчика sharp на stm32f100. Данные с ИК датчика получаю на аналоговый вход и отправляю по UART в терминал. Но в терминал приходят рандомные числа, хотя расстояние до объекта остаетя постоянным. Может кто-нибудь знает в чем может быть проблема?

    • ИК датчик выдает постоянное напряжение/ток, которое пропорционально дистанции? Или у него на выходе импульсы?
      Я бы в первую очередь посмотрел сигнал на входе АЦП STM32.

  23. Взял пример для stm32L -discovery, воткнул в кокос, скомпилировал, зашил. Затем подсоединил преобразователь usb-ttl на cp2102 к PA9 и PA10 запустил программку для работы с com портом и ничего! Нет строки I’m ready. Куда копать совершенно не знаю