Урок 20. Интерфейс UART в STM32. Работа с ним через регистры CMSIS. Использование прерывания UART.

Последовательный порт stm32

Получим необходимый минимум информации об интерфейсах UART микроконтроллеров STM32. Научимся управлять ими через регистры библиотеки CMSIS.

Предыдущий урок     Список уроков     Следующий урок

UART – это наиболее распространенный последовательный интерфейс передачи данных. Через него к микроконтроллеру могут быть подключены самые разные устройства: от миниатюрного цифрового датчика, до компьютера. На базе UART могут создаваться даже локальные сети. Нам этот интерфейс необходим как минимум для отладки программ.

 

Протокол интерфейса UART.

Данные передаются асинхронным последовательным кодом.

Протокол UART

Интерфейс называется асинхронным. Это означает, что данные могут быть переданы в любой момент, без использования между приемником и передатчиком синхронизирующих импульсов. В одну сторону данные предаются с помощью одного сигнала. Сам сигнал содержит как данные, так и синхронизирующую информацию.

Для того, чтобы приемник понял, что начинается передача данные сопровождаются специальными битами: стартовым и стоповым.

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

Все биты передаются за одинаковые промежутки времени. Время передачи одного бита определяет скорость передачи интерфейса. Часто она указывается в бодах (бит в секунду). Как я писал выше, кроме собственно данных в поток добавляются биты синхронизации. Таким образом, для передачи байта требуется не 8, а 10 битов.

Погрешность скорости передачи не должна превышать 5% (рекомендуется не более 1,5 %.)

Я рассказываю о самом распространенном формате протокола UART. Бывают варианты с различными количествами битов данных, обычно от 5 до 9. Могут использоваться форматы с двумя стоповыми битами. Иногда добавляется бит контроля четности. Но такие варианты используются редко.

Главное, что надо знать:

  • в неактивном режиме (состоянии ожидания) выход передатчика UART находится в высоком состоянии;
  • передача байта начинается со стартового бита, который равен 0 (низкий уровень сигнала);
  • передача байта заканчивается стоповым битом, который равен 1 (высокий уровень сигнала);
  • данные передаются, начиная с младшего бита;
  • для передачи байта требуется 10 битов;
  • время передачи одного байта вычисляется исходя из скорости обмена и количества битов  в пакете (10 бит при передаче байта).

Существуют стандартные скорости передачи интерфейса UART. Наиболее распространены следующие.

 

Скорость передачи,
бод
Время передачи одного бита, мкс Время передачи байта,
мкс
4800 208 2083
9600 104 1042
19200 52 521
38400 26 260
57600 17 174
115200 8,7 87

Обмен данными через UART происходит в дуплексном режиме. Т.е. передача и прием данных могут происходить одновременно.

У интерфейса UART существуют 2 сигнала RX и TX. Иногда их маркируют RXD и TXD, подчеркивая, что это сигналы передачи данных.

При подключении двух UART устройств сигналы RX соединяются с сигналами TX. Используется перекрестная схема соединения.

 

UART в микроконтроллерах STM32.

У микроконтроллеров STM32F103C8T6 целых 3 интерфейса UART. Они имеют одинаковые структуры и функциональные возможности.

Не повторяя информацию об общепринятых функциях UART, я бы выделил следующие возможности этого интерфейса в микроконтроллерах STM32.

  • При частоте тактирования 72 МГц скорость передачи данных до 4,5 Мбит/сек.
  • Размерность передаваемых данных 8 или 9 бит.
  • Могут быть заданы форматы с 1 или 2 стоповыми битами.
  • Интерфейс поддерживает физический уровень протокола инфракрасного порта (IRDA).
  • Также поддерживается интерфейс контактных смарт-карт ISO 7816.
  • Передача и прием данных могут происходить с использованием контроллера прямого доступа к памяти (DMA).
  • Интерфейс может работать в синхронном режиме.

Я коротко, упрощенно расскажу, как работает UART STM32.

Вот часть функциональной схемы интерфейса, через которую происходит передача и прием данных. Все остальное – это управляющая часть. Я ее не привел.

Структурная схема

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

Собственно передатчик состоит из 2 регистров: регистра сдвига (Transmit Shift Register) и буферного регистра (TDR).

Данное загружается в буферный регистр передатчика. Программно доступен только он. Если передача предыдущего данного закончена и регистр сдвига пуст, то данное перегружается в него, сдвигается и побитно поступает на выход TX. Как только данное перегружено в регистр сдвига, буферный регистр освобождается и в него может быть загружено новое слово.  Оно будет ждать окончания передачи и автоматически перегрузится в сдвиговый регистр.

Таким образом, происходит буферизация данных передатчика. Это позволяет реализовывать передачу данных без пауз между словами. После загрузки буферного регистра есть время на запись нового данного, равное времени передачи. Если успевать заполнять буферный регистр, то данные будут передаваться сплошным потоком.

Об окончании передачи данных регистром сдвига и освобождении буферного регистра сообщают специальные флаги. По ним могут быть сформированы прерывания.

Приемная часть устройства также состоит из двух регистров:  регистра сдвига (Receive Shift Register) и буферного регистра (RDR). С входа RX данные поступают на сдвиговый регистр, сдвигаются и, после формирования полного слова, перегружаются в буферный регистр. Буферный регистр доступен программно. Из него считывается полученное данное. Если данные поступают сплошным потоком, без пауз, то после приема данного есть время, равное времени передачи слова, на то, чтобы считать его из буферного регистра. Иначе придет новое данное, а старое будет потеряно.

 

Регистры UART.

Регистров много, битов еще больше. Я не претендую на подробное описание регистров UART. Приведу только информацию, необходимую нам в ближайших уроках.

USART_SR  - регистр состояния.

Формат SR

Прежде всего, нам интересны флаги, сообщающие о состоянии приема и передачи.

  • Бит 7 TXE. Буферный регистр передатчика пуст. Флаг становится равным 1 после того, как данное перегружается в регистр сдвига. Т.е. флаг сообщает о том, что буферный регистр пуст, может быть загружено новое данное. Флаг устанавливается аппаратно и сбрасывается после записи байта в буферный регистр USART_DR.
  • Бит 6 TC. Флаг устанавливается аппаратно и сообщает о том, что передача данного закончена, сдвиговый регистр пуст. Если предыдущий флаг (TXE) говорит о том, что можно в буферный регистр загружать новое данное. Физическая передача может продолжаться, на выходе TX возможно идет поток битов. То флаг TC сообщает, что все биты переданы. Часто этот момент необходимо определять для отключения передатчика шинного интерфейса сети, например, в интерфейсе RS-485. Сбрасывается флаг последовательным чтением регистров USART_SR и USART_DR.
  • Бит 5 RXNE. Буферный регистр приема не пуст. Флаг сообщает, что в буферном регистре приемника есть данное. Данное должно быть считано до прихода следующего, иначе оно будет потеряно. Сбрасывается флаг при чтении регистра USART_DR.

UART способен определить некоторые ошибки приема данных, возникающие из-за искажения сигнала при передаче или за счет неправильных программных операций с ним. Об ошибках сигнализируют следующие 4 бита.

  • Бит 3 ORE. Ошибка переполнения. Флаг устанавливается в случае, если в приемный буферный регистр поступило новое данное, а предыдущее считано не было. Т.е. при потере данного.
  • Бит 2 NE. Флаг устанавливается при выделении шума во входном сигнале. Наличие шума определяется как слишком частое переключение входного сигнала.
  • Бит 1 FE. Ошибка приема фрейма (кадра). Возникает, когда не был выделен стоп-бит. Т.е. после приема стартового бита и  8 битов данных на месте стопового бита UART считал сигнал низкого уровня.
  • Бит 0 PE.  Ошибка паритета. Сигнализирует об ошибке при включенном контроле четности.

Все биты сбрасываются программно последовательным чтением сначала регистра USART_SR, затем USART_DR.

 

USART_DR  - регистр данных.

Формат DR

Используется для записи данных в буферный регистр передатчика и чтения данных из буферного регистра приемника. На самом деле это 2 регистра, для обращения к которым используется один адрес.

 

USART_BRR - регистр, задающий скорость обмена.

Формат BRR

Регистр содержит значение делителя частоты (USARTDIV), который определяет скорость передачи и приема данных.

Скорость вычисляется по формуле:

BAUD = Fck / (16 * USARTDIV), где

  • BAUD – скорость, бод.
  • Fck – входная частота тактирования UART:
    • сигнал PCLK2 для UART1 (шина APB2);
    • сигнал PCLK1 для UART2 и 3 (шина APB1).
  •  USARTDIV – значение регистра USART_BRR.

USARTDIV задано в формате с фиксированной запятой с дробной частью.

15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Целая часть (12 разрядов) Дробная часть (4 разр)
11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4

В верхней строке – разряды регистра USART_BRR.

В нижней строке – разряды дробного числа USARTDIV. Отрицательные – это дробные разряды. Разряд – 1 это ½ или в десятичном виде 0,5. -2 это ¼ или 0,25. И т.д. Это стандартная форма представления дробного числа с фиксированной запятой. Для перевода в привычную десятичную форму можно воспользоваться формулой:

Десятичное значение USARTDIV = целая часть + (дробная часть / 16).

Например, если целая часть равна 78, а дробная 5, то

USARTDIV = 78 + (5 / 16) = 78,3125.

Можно перевести в десятичный код содержимое всего регистра (разряды 0…15) и разделить его на 16.

Скорость при частоте тактирования 72 Мгц

BAUD = 72000000 / (16 * 78,3125) = 57462 бод.

Для обратного вычисления USARTDIV по скорости BAUD можно использовать формулу:

USARTDIV = Fck / (16 * BAUD)

 

USART_CR1 – управляющий регистр 1.

Формат CR1

  • Бит 13 UE. Разрешение работы UART. Отключение UART (UE=0) уменьшает ток потребления микроконтроллера.
  • Бит 12 M. Задает длину слова 8 бит (M=0) или 9 бит (M=1).
  • Бит 10 PCE. Разрешение контроля четности (PCE=1).
  • Бит 7 TXEIE. Разрешение прерывания по флагу TXE, т.е. когда буферный регистр передатчика пуст.
  • Бит 6 TCIE. Разрешение прерывания по флагу TC, т.е. когда пуст сдвиговый регистр передатчика.
  • Бит 5 RXNEIE. Разрешение прерывания по флагу RXNE, т.е. когда в буферном регистре приемника есть непрочитанное данное.
  • Бит 3 TE. Разрешение работы передатчика.
  • Бит2 RE. Разрешение работы приемника.

У всех разрядов активный уровень единица.

 

USART_CR2 – управляющий регистр 2.

Формат CR2

Нам интересно только одно поле.

  • Биты 13:12 STOP. Биты задают формат стопового признака слова:
    • 00 – 1 стоп-бит;
    • 01 – 0,5 стоп-бита;
    • 10 – 2 стоп-бита;
    • 11 – 1,5 стоп бита.

 

USART_CR3 – управляющий регистр 3.

Формат CR3

Пока при инициализации UART запишем в этот регистр 0.

 

Работа с UART через регистры CMSIS.

Большей частью мы будем управлять UART с помощью HAL- функций. Но бывают задачи, когда без прямого обращения к регистрам UART не обойтись.

Например, сейчас я разрабатываю центральный контроллер для системы управления шаговыми двигателями. Передача данных происходит со скоростью 1 Мбит/сек, и операции обмена крайне критичны ко времени выполнения. Тратить время на вызовы функций библиотеки HAL при такой задаче очень расточительно. Все удачно реализовывается при прямом обращении к регистрам UART.

Поэтому, я решил, коротко рассказать о таком способе управления передачей данных.

Поставим задачу – реализовать эхо-терминал. Т.е. устройство, которому мы посылаем данные и получаем их в ответ. Будем использовать UART1. В нашей системе он уже подключен к компьютеру.

Создадим проект Lesson20_1. В нем настроим только систему тактирования на частоту 72 мГц.

В файле main.c создаем блок инициализации UART.

  /* USER CODE BEGIN SysInit */

  // инициализация UART1

Включаем тактирование UART1. Он подключен к шине APB2.

RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // включаем тактирование UART1

UART1 использует выводы: PA9 (для сигнала TX) и PA10 (сигнал RX). Надо задать конфигурацию для них.

RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // разрешаем тактирование порта GPIOA

// настройка вывода PA9 (TX1) на режим альтернативной функции с активным выходом
// Биты CNF = 10, ,биты MODE = X1
GPIOA->CRH &= (~GPIO_CRH_CNF9_0);
GPIOA->CRH |= (GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9);

// настройка вывода PA10 (RX1) на режим входа с подтягивающим резистором
// Биты CNF = 10, ,биты MODE = 00, ODR = 1
GPIOA->CRH &= (~GPIO_CRH_CNF10_0);
GPIOA->CRH |= GPIO_CRH_CNF10_1;
GPIOA->CRH &= (~(GPIO_CRH_MODE10));
GPIOA->BSRR |= GPIO_ODR_ODR10;

Теперь конфигурация самого UART.

// конфигурация UART1
USART1->CR1 = USART_CR1_UE; // разрешаем USART1, сбрасываем остальные биты

Устанавливаем скорость обмена.

Частота тактирования UART1 72 мГц, нам нужна скорость 9600 бод. Вычисляем значение USARTDIV.

USARTDIV = Fck / (16 * BAUD) = 72000000 / (16 * 9600) = 468,75

Значение регистра USART_BRR = 468,75 * 16 = 7500.

USART1->BRR = 7500; // скорость 9600 бод

Разрешаем работу приемника  и передатчика. Прерывания по событиям UART не разрешаем.

USART1->CR1 |= USART_CR1_TE | USART_CR1_RE ; // разрешаем приемник и передатчик
USART1->CR2 = 0;
USART1->CR3 = 0;

Инициализация закончена.

Теперь для передачи необходимо дождаться, когда бит TXE станет равным 1 и загрузить в регистр данных передаваемое число.

while ((USART1->SR & USART_SR_TXE) == 0) {}
USART1->DR = d;

Для приема надо дождаться, когда бит RXNE станет равным 1 и считать из регистра данных принятое число.

while ((USART1->SR & USART_SR_RXNE) == 0) {}
d = USART1->DR;

Для реализации эхо-терминала поместим такой блок в цикл while:

/* Infinite loop */
  /* USER CODE BEGIN WHILE */

  while (1)
  {

    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */

      // получить данное
      while ((USART1->SR & USART_SR_RXNE) == 0) {}
      uint8_t d = USART1->DR;

      // отослать данное назад
      while ((USART1->SR & USART_SR_TXE) == 0) {}
      USART1->DR = d;
  }

  /* USER CODE END 3 */

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

 

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!
 

Проверяем.

Загружаем программу в микроконтроллер.

Запускаем программу CoolTerm.

Окно CoolTerm

Нажимаем Options, выбираем COM-порт, скорость обмена.

Окно CoolTerm

Нажимаем кнопку Connect.

В верхнем меню, в закладке Connection выбираем Send String (Послать строку).

Набираем текстовую информацию, нажимаем Send и посланная строка появляется в окне принятых данных.

Окно терминала CoolTerm

Эхо-терминал работает.

Программу CoolTerm можно не закрывать. Если необходимо загрузить программу в STM32, то можно нажать кнопку Disconnect. CoolTerm  освободит COM-порт и даст возможность запрограммировать микроконтроллер. Для возобновления работы CoolTerm достаточно нажать Connect.

 

Использование прерываний UART.

В предыдущей программе в основном цикле while постоянно происходила проверка состояния флага RXNE. На остальные задачи времени не оставалось. И это притом, что флаг становился активным не чаще чем с периодом 1 мс. Заставить микроконтроллер тратить минимум вычислительных ресурсов на работу с UART можно за счет применения прерываний.

Реализуем ту же задачу с использованием прерываний.

Я создал новый проект Lesson20_2, в котором настроена только система тактирования на 72 мГц.

Открываем урок 18 и кто забыл, повторяем необходимые действия для работы с прерываниями.

Копируем блок инициализации UART из предыдущей программы. В нем делаем изменения только в одной строке. В регистре CR1 разрешаем прерывание по флагу RXNE.

USART1->CR1 |= USART_CR1_TE | USART_CR1_RE | USART_CR1_RXNEIE; // разрешаем приемник, передатчик и прерывание по приему

Разрешаем прерывание в контроллере прерываний.

// разрешения прерывания UART1 в контроллере прерываний
NVIC_EnableIRQ (USART1_IRQn);

В конце файла stm32f1xx_it.c размещаем функцию обработки прерывания UART1.

/* USER CODE BEGIN 1 */

void USART1_IRQHandler(void) {

}

Не забываем добавить в файл stm32f1xx_it.h прототип функции обработки прерывания.

/* Exported functions prototypes ---------------------------------------------*/
void USART1_IRQHandler(void);

Остается заполнить функцию обработки прерывания.

/* USER CODE BEGIN 1 */

void USART1_IRQHandler(void) {

uint8_t d = USART1->DR; // получить данное
USART1->DR = d; // отослать данное назад
}

/* USER CODE END 1 */

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

 

Зарегистрируйтесь и оплатитеВсего 60 руб. в месяц за доступ ко всем ресурсам сайта!
 

Теперь цикл while пустой. В нем можно выполнять любые задачи. Микроконтроллер будет прерывать его только на короткое время при приеме данного.

 

В следующем уроке будем работать с UART через HAL-функции. Поговорим об отладке программ с помощью UART.

Предыдущий урок     Список уроков     Следующий урок

3

Автор публикации

не в сети 9 часов

Эдуард

285
Комментарии: 1946Публикации: 199Регистрация: 13-12-2015

Один комментарий на «Урок 20. Интерфейс UART в STM32. Работа с ним через регистры CMSIS. Использование прерывания UART.»

  1. Привет. Прочитал только про UART, 20 урок. Так держать. Молодец. CMSIS рулит. Обращаюсь ко всем читателям вот таких уроков. Все кто читает такие уроки не скупитесь, заплатите. Хороший труд необходимо поддерживать. Кто в поисках интересной и познавательной информации о микроконтроллерах STM32 на русском языке, тот должен меня понять. Обратите внимание на уроки nordic energy в you tube. На мой взгляд похвально. Автору платежеспособных читателей и прекрасных творческих идей в области просвещения о насыщенных внутренних процессах, протекающих в микроконтроллерах. Описание механики работы микросхемы в картинках плюс примеры кода на CMSIS хорошая база знаний для нормального освоения железа. Краткие записи заполнения регистров периферии с комментариями гораздо лучше усваиваются, чем километры говнокода без комментариев. Хотел бы обратить внимание на знаки «=» и «|=» при записи в регистры при инициализации периферии. Очень хорошо иногда писать просто «=», а иногда только «|=». В примерах Автора хорошо показан этот момент. Видимо понимает о чём пишет;). Тем кто замечает какие либо ошибки или не понимает, что написано автором, сообщайте. Совершенству в обучении микроконтроллеров нет предела.

    3
    • Димон, думаю тут не лучшее место для впаривания левых уроков от левых чудаков. Уважайте автора.

      0
  2. Эдуард, здоровья Вам и всех благ за Ваш труд.
    Как скоро можно ждать урока по LCD с отображением данных от источников с управлением от кнопок?

    0
    • Здравствуйте! Спасибо за пожелания.
      В планах, конечно, есть LCD дисплеи. Но по срокам ничего не могу обещать. Времени катастрофически не хватает.

      0
  3. Здравствуйте, Эдуард! Спасибо за отличный цикл статей. С другой стороны есть пожелание, не изобретайте пожалуйста велосипед. Отладка проводится через ST Link. Зачем отлаживать проекты через низкоскоростной UART? Это же не ардуино…

    0
  4. Михаил, изобретение велосипеда является лучшим учебным пособием для изучения ребёнком основ механики 🙂

    0
  5. Добрый день. А как можно задать для А10 режим альтернативной функции с помощью библиотеки LL? Я так понял важно для 10ой ножки поставить биты MODE10 регистра CRH в 00, то есть в режим входа.
    Но функция SetPinMode трогает только биты CONF как я понял
    Функция SetPinSpeed меняет MODE10 биты на 10, 01 или 11.
    Как тогда задать на вход 10ую ножку с помощью этих функций?

    0
    • Здравствуйте!
      Почему. Биты MODE функция SetPinMode тоже устанавливает.

      __STATIC_INLINE void LL_GPIO_SetPinMode(GPIO_TypeDef *GPIOx, uint32_t Pin, uint32_t Mode)
      {
      register uint32_t *pReg = (uint32_t *)((uint32_t)(&GPIOx->CRL) + (Pin >> 24));
      MODIFY_REG(*pReg, ((GPIO_CRL_CNF0 | GPIO_CRL_MODE0) < < (POSITION_VAL(Pin) * 4U)), (Mode << (POSITION_VAL(Pin) * 4U))); }

      0
      • MODIFY_REG(*pReg, ((GPIO_CRL_CNF0 | GPIO_CRL_MODE0) < < (POSITION_VAL(Pin) * 4U)), (Mode << (POSITION_VAL(Pin) * 4U)));

        Эта функция, как я понял: 1. очищает регистр в соответствии с маской (CNF0 | MODE0). 2. затем устанавливает "Mode". Если мод будет равен LL_GPIO_MODE_ALTERNATE, то значит в соответствующие биты будет записано (GPIO_CRL_CNF0_1 | GPIO_CRL_MODE0_0)
        то есть в CONF будет 10 (альтернативная функция) а в MODE будет записано 01 (Выход, синхронизация 10 мГц)
        То есть как ни крути, на вход он отсюда не настроится
        И если я нигде не ошибся, то как скинуть эти биты (_MODE) в 00 (настроить на вход)

        0
    • Здравствуйте!
      Самому стыдно. Начал. Сейчас справочник для HAL UART пишу. Далее следующий урок по работе с UART через HAL.

      0
  6. Доброго!
    Эдуард спасибо за ваш материал, поддерживаю.
    Если можно кратко скажите отличие настройки uart под 232 и 485 интереса. У меня под руками только преобразователь на MAX3485 и USB->485 преобразователь. Ваш пример с эхом работает, но на приёме идут не те символы что ввёл. Отправляю 1 получаю g, 2->3.

    0
    • Здравствуйте!
      Настройки UART одинаковые для обоих интерфейсов. Отличие в том, что RS485 — шинный интерфейс. По одной линии происходит передача и прием информации. Поэтому, после передачи данных устройство должно освобождать шину и переходить на прием. Появляется необходимость управлять третьим состоянием передатчика. Для этого необходимо по окончанию передачи отключать передатчик специальным сигналом.
      Посмотрите подробнее в уроке 60 Ардуино.

      0
    • USART – Universal Synchronous/Asynchronous Receiver/Transmitter — по сравнению с UART имеет третью линию для синхронизации. В данном уроке разбирается работв с UART, но синтаксис команд имеет букву S. Предполагаю, что команды для обоих вариантов протокола унифицированы и просто нет вариантов команд с …UART…

      0
    • Здравствуйте!
      UART это асинхронный интерфейс, а в USART добавлен синхронный режим. Т.е. UART это часть режимов UART.

      0
  7. У Вас просто дар разжевывать без лишней информации. На более менее обремененные знаниями мозги информация копируется замечательно. Скорее подтверждает, что и так ты вроде знаешь, а вроде и куча шелухи в голове.

    Из замечаний — что бросилось в глаза.
    1.
    Передающая и приемная часть работают совершенно независимо друг от друга. Из общего у них только тактовый генератор. Т.е. могут быть задействован только приемник, или только передатчик.

    Я переформулировал бы последнее предложение. Например — вы можете задействовать их абсолютно в разное время, они не влияют на работу друг друга. А можете вообще один из каналов не задейстовать, второй будет работать на 100%.
    2. В режиме ожидания сигнал на входе приемника находится в высоком уровне. Первым передается стоповый бит.

    Стартовый.

    Надеюсь полезные замечания. Может еще что выловлю, облегчающее восприятие читающего.

    0
  8. Добрый день! Коды в уроках 20 — 21 запустить не удалось. Данных в терминале на прием нет. Пробовал непосредственно загружать hex урока через флешер — та же ситуация. Терминал установлен рекомендованный в уроках, с ардуино проверил и уарт и терминал — работает. Прошивка шьется через уарт, значит с подключением rx tx все ок, перемычку ставлю на место, где еще я мог ошибиться!?

    0
    • Здравствуйте!
      Проверьте, поступают ли данные на вход RxD платы STM32. Если нет осциллографа, припаяйте к выводу светодиод к 3 В через резистор.

      0
      • Светодиоды стоят на уарте, они моргали на передачу, не моргали на прием.
        Решение нашел. В Кубе конфигурацию сделал, и закинул кусок кода из урока на прием в терминал строки — работает. Спасибо за ценные уроки!

        0
  9. Почему в CoolTerm настраиваем Com4, откуда это берётся? У меня в CoolTerm доступны только Com1 и Com3, и не по одному не получается принять, только отправить.

    0
    • Здравствуйте!
      У меня драйвер моста USB/UART установил виртуальный COM4. У вас COM3. COM1 есть в компьютере всегда. Он зарезервирован под ИК-порт. Его использовать нельзя.

      0
  10. Приветы.
    там…в IRQHandler,
    return; не нужен ?
    или прерывание запрещать после входа ?
    а потом разрешать.

    0
  11. А флаг прерывания для TXEIE, TCIE. RXNEIE когда очищается? В прерывании мы для RXNEIE с фдагом ничего не делаем. Там, как я понимаю, само чтение входящих данных сбросит? Что с остальными?

    0
    • Здравствуйте!
      Это флаги разрешения прерываний. Мы их устанавливаем только если нужны прерывания по соответствующим событиям.
      Флаги устанавливаются или сбрасываются только программно.

      0
  12. День добры уважаемий Эдуард. Огромное спасибо за твою информацию и мне совсем не жалько что плотиль. хочу утачнить чо то в роди не так здесь.

    Устанавливаем скорость обмена.

    Частота тактирования UART1 72 мГц, нам нужна скорость 9600 бод. Вычисляем значение USARTDIV.

    USARTDIV = Fck / (16 * BAUD) = 72000000 / (16 * 9600) = 468,75

    Значение регистра USART_BRR = 468,75 * 16 = 7500.

    USART1->BRR = 7500; // скорость 9600 бод

    возможно не 72000000 на делить а его половина.
    у менйа получилсо когда я USART1->BRR = 3750

    ещо раз спасибо.

    0
    • Здравствуйте!
      Все программы я проверяю. Формула вычисления скорости правильная.
      А как вы определили, что скорость не та? Может вы при конфигурации татирования частоту не 72 мГц задали. Можете запустить мой проект и проверить, какая скорость в нем.

      0
  13. Здравстуйте. Можете привести пример согласования интерфейсов на примере двух интерфейсов UART?

    0
  14. Господа, может кто сможет помочь?
    Не заводится USART через CMSIS (Lesson20_1). Проверял, параметрируя USART через CubeMX, оставив тот-же код в главном цикле (while(1)) — всё работает. Сделал вывод, что я не верно инициализирую USART… Вот код из раздела SysInit (работаю с платой STM32F411CEU6 (Black Pill), поэтому регистры параметрирования GPIO отличаются, не удивляйтесь):

    /* USER CODE BEGIN SysInit */

    /* Инициализация UART1 */
    RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // включаем тактирование UART1
    RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // разрешаем тактирование порта GPIOA

    /* Настройка вывода PA9 (TX1) на режим альтернативной функции с активным выходом */
    GPIOA->MODER &= (~GPIO_MODER_MODE9_0); // сброс младшего бита MODER9 (Alternate function mode)
    GPIOA->MODER |= GPIO_MODER_MODE9_1; // установка старшего бита MODER9 (Alternate function mode)
    GPIOA->OTYPER &= (~GPIO_OTYPER_OT_9); // сброс регистра OTYPER9 (режим «Output push-pull)
    GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED9; // установка регистра OSPEEDR9 в режим «High speed»
    GPIOA->PUPDR &= (~GPIO_PUPDR_PUPD9); // установка регистра PUPDR9 в режим «No pull-up, pull-down»

    /* Настройка вывода PA10 (RX1) на режим входа с подтягивающим резистором */
    GPIOA->MODER &= (~GPIO_MODER_MODE10); // сброс битов MODER10 (Input)
    GPIOA->PUPDR &= (~GPIO_PUPDR_PUPD10_1); // сброс старшего бита PUPDR10 (Pull-up)
    GPIOA->PUPDR |= GPIO_PUPDR_PUPD10_0; // установка младшего бита PUPDR10 (Pull-up)

    /* Конфигурация UART1 */
    USART1->CR1 = USART_CR1_UE; // разрешаем USART1, сбрасываем остальные биты
    USART1->BRR = 7500; // скорость 9600 бод
    USART1->CR1 |= (USART_CR1_TE | USART_CR1_RE); // разрешаем приёмник и передатчик
    USART1->CR2 = 0;
    USART1->CR3 = 0;

    /* USER CODE END SysInit */

    Может кто-нибудь увидит, где я оплошал?

    1
    • Сам спросил, сам отвечу, вдруг есть еще такие чудаки вроде меня, идущие по курсу с BlackPill вместо BluePill (кстати, рекомендую, наткнулся на такое количество отличий, столько информации пришлось искать, так много пришлось переделывать, что гораздо лучше начинаешь
      понимать как работает то или иное в STM32).

      Итого, чего мне не хватало: В STM32F411CEU6(BlackPill), в отличие от STM32F103C8T6(BluePill), для того, чтобы запараметрировать ноги на USART нужно настроить оба вывода на режим альтернативной функции, и установить AF07(0b0111) в соответствующий AFR. Итого получилось:

      /* USER CODE BEGIN SysInit */

      /* Инициализация UART1 */
      RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // включаем тактирование UART1
      RCC->AHB1ENR |= RCC_AHB1ENR_GPIOAEN; // разрешаем тактирование порта GPIOA

      /* Настройка вывода PA9 (TX1) на режим альтернативной функции */
      GPIOA->MODER &= (~GPIO_MODER_MODE9_0); // сброс младшего бита MODER9 (Alternate function mode)
      GPIOA->MODER |= GPIO_MODER_MODE9_1; // установка старшего бита MODER9 (Alternate function mode)
      GPIOA->OTYPER &= (~GPIO_OTYPER_OT_9); // сброс регистра OTYPER9 (режим «Output push-pull)
      GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED9; // установка регистра OSPEEDR9 в режим «High speed»
      GPIOA->PUPDR &= (~GPIO_PUPDR_PUPD9); // установка регистра PUPDR9 в режим «No pull-up, pull-down»
      GPIOA->AFR[1] |= (GPIO_AFRH_AFRH1_0 | GPIO_AFRH_AFRH1_1 | GPIO_AFRH_AFRH1_2); // Установка битов AFRH9 в 0x0111 (AF07 — USART)
      GPIOA->AFR[1] &= (~GPIO_AFRH_AFRH1_3); // Установка битов AFRH9 в 0x0111 (AF07 — USART)

      /* Настройка вывода PA10 (TX1) на режим альтернативной функции */
      GPIOA->MODER &= (~GPIO_MODER_MODE10_0); // сброс младшего бита MODER10 (Alternate function mode)
      GPIOA->MODER |= GPIO_MODER_MODE10_1; // установка старшего бита MODER10 (Alternate function mode)
      GPIOA->OTYPER &= (~GPIO_OTYPER_OT_10); // сброс регистра OTYPER10 (режим «Output push-pull)
      GPIOA->OSPEEDR |= GPIO_OSPEEDR_OSPEED10; // установка регистра OSPEEDR10 в режим «High speed»
      GPIOA->PUPDR &= (~GPIO_PUPDR_PUPD10); // установка регистра PUPDR10 в режим «No pull-up, pull-down»
      GPIOA->AFR[1] |= (GPIO_AFRH_AFRH2_0 | GPIO_AFRH_AFRH2_1 | GPIO_AFRH_AFRH2_2); // Установка битов AFRH10 в 0x0111 (AF07 — USART)
      GPIOA->AFR[1] &= (~GPIO_AFRH_AFRH2_3); // Установка битов AFRH10 в 0x0111 (AF07 — USART)

      /* Конфигурация UART1 */
      USART1->CR1 = USART_CR1_UE; // разрешаем USART1, сбрасываем остальные биты
      USART1->BRR = 7500; // скорость 9600 бод
      USART1->CR1 |= (USART_CR1_TE | USART_CR1_RE); // разрешаем приёмник и передатчик
      USART1->CR2 = 0;
      USART1->CR3 = 0;

      /* USER CODE END SysInit */

      USART завёлся, пашет. С прерыванием USART1_IRQn проблем не возникло, всё идентично.

      1
  15. Здравствуйте. Можете, пожалуйста, поподробнее объяснить что означает строчка «Погрешность скорости передачи не должна превышать 5% (рекомендуется не более 1,5 %.)»?

    0
    • Здравствуйте!
      Посмотрите в уроке Ардуино диаграмму сигнала UART. Синхронизация приема битов происходит по первому старт-биту. От него отсчитываются времена приема битов. Внутренний импульс синхронизации приема должен попадать в середину интервала передачи бита. Если частота синхронизации будет значительно отличаться от идеальной, то импульс синхронизации может сдвинуться за интервал бита. Это приведет к тому, что последние биты будут приняты с ошибкой.

      0
  16. И снова здравствуйте.
    Во время инициализции usart мы делаем след шаги:

    1. разрешить usart
    2. настроить скорость передачи
    3. разрешить прием/передачу
    обязательно ли делать это именно в таком порядке?
    можно ли поменять поменять 1 с другими шагами местами?

    Да и в самом в начале мы включаем тактирование по шине, отсюда еще вопрос(извините за такое количество вопросов)) : регистры usart отображенные в памяти на самом деле находятся в самом модуле usart? Значит чтобы можно было что-то туда записать и включают тактирование по шине?
    И последний вопрос обязательно ли записывать в cr2 и cr3 нули? Что там находится по умолчанию?

    0
    • Здравствуйте!
      Лучше придерживаться такого порядка. Насколько я помню, скорость можно настроить при запрещенном UART, но зачем.
      Все регистры лучше переустанавливать при инициализации независимо ото того, что в них устанавливается по сбросу микроконтроллера.
      Да, конечно, регистры это составляющая аппаратного модуля. Тактирование соответствующей шины надо включать.

      0
  17. GPIOA->BSRR |= GPIO_ODR_ODR10;
    Не ошибочная запись? Хотя наверное работает, потому что сдвиг битов такой же.

    0

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Нажимая кнопку "Отправить" Вы даёте свое согласие на обработку введенной персональной информации в соответствии с Федеральным Законом №152-ФЗ от 27.07.2006 "О персональных данных".