Stm32 uart frame error

USART stm32 HAL USART (Universal Synchronous-Asynchronous Receiver/Transmitter) — универсальный синхронно-асинхронный приёмопередатчик, интерфейс для для передачи данных между цифровыми устройствами. Он на столько универсальный, что даже провода по которым к вам домой приходит интернет, это тоже USART (RS485). USART микроконтроллера stm32 может работать в различных режимах — асинхронный, синхронный, полудуплекс и т.д. Asynchronous Это самый […]

USART stm32 HAL

USART (Universal Synchronous-Asynchronous Receiver/Transmitter) — универсальный синхронно-асинхронный приёмопередатчик, интерфейс для для передачи данных между цифровыми устройствами. Он на столько универсальный, что даже провода по которым к вам домой приходит интернет, это тоже USART (RS485).

USART микроконтроллера stm32 может работать в различных режимах — асинхронный, синхронный, полудуплекс и т.д.

Asynchronous

Это самый распространённый режим, устройства соединяются так…

… а согласуются между собой с помощью заранее установленной скорости передачи данных.

Тут следует немного пояснить работу USART’а для упрощения понимания некоторых настроек.

Мы будем передавать 8-ми битные байты (в отдельных случаях байты могут 9-ти битные), на скорости 115200 бит в секунду…


Parity — использование бита проверки чётности (см. ниже).
Stop Bits — количество стоповых битов (1 или 2).
Data Direction — включается приём и передача, или что-то одно.
Over Sampling — см. ниже.

Получаемый пакет из восьми бит (один байт) выглядит так…


Отправляемые/получаемые байты отделяются друг от друга стартовыми и стоповыми битами.

Если ничего не передаётся, то линия находится в состоянии HIGH. Передатчик, начиная отправку, прижимает линию к «земле», а приёмник расценивает это как начало пакета — START (стартовый бит). Далее идёт приём (отсчитывая биты) и после последнего (D7) бита проверяется что линия установлена в HIGH — STOP (стоповый бит). Иногда для большей достоверности окончания приёма используются два стоповых бита.

Количество принятых бит подсчитывается следующим образом: как только появляется стартовый бит (переход с HIGH на LOW) сразу же начинается отсчёт — 16 тиков на каждый бит…


Over Sampling — 16 Samples.

Эти 16 семплов «прощупывают» уровень линии, и если в момент предполагаемой середины бита (MIDBIT) линия находится в состоянии HIGH, то в соответствующий разряд приёмного регистра записывается единичка, если LOW, то нолик. За это отвечают три центральных семпла…

Другие семплы сигнализирует об ошибках. Например, если первые два семпла покажут что линия находится в состоянии HIGH, а следующие два скажут что она LOW, и снова HIGH, то микроконтроллеру станет совершенно очевидно, что при передаче в линию вклинились помехи. В результате вместо байта мы получим сообщение об ошибке — HAL_UART_ERROR_NE — шум в линии. Если же нужные нам семплы «съезжают» в сторону, в право или влево, то это будет означать, что у передающего устройства «плавает» частота, а мы получим ошибку кадра — HAL_UART_ERROR_FE.

Вот таким вот нехитрым образом происходит принятие одного байта.

Я не могу говорить за все микроконтроллеры stm32, но например на F303 можно указать частоту семплирования либо 16 либо 8. За счёт уменьшения семплирования можно повышать скорость USART’а. Каким образом — да очень просто: USART_1 тактируется от шины APB2, на каждый бит нам нужно по 16 тиков, значит при частоте шины 72МГц и семплирований 16, мы можем получить максимальную скорость USART’а равную 4.5 Mбит/с (72000000 / 16 = 4500000). Если же указать семплирование 8, то теоретически мы получим скорость 9 Mбит/с.

Parity — бит чётности. С помощью этого бита можно проверять целостность полученного пакета.

Пакет с добавленным битом чётности выглядит так…


Word Length нужно указать 9 Bits. Если оставить 8 Bits, то полезных битов будет 7.

При отправке в этот бит записывается единица или ноль в зависимости от количества единичек в предыдущих восьми битах. Если единичек чётное кол-во, то записывается 0, если нечётное, то 1.

Если отправляется 10111101 (шесть единичек — чётное количество), то бит чётности будет . Пакет будет выглядеть так — 101111010.

Если отправляется 01110011 (пять единичек — нечётное количество), то бит чётности будет 1. Пакет будет выглядеть так — 011100111.

При приёме такого пакета производится проверка — соответствует ли количество единичек значению в девятом бите, и если не соответствует, то пакет считается повреждённым — ошибка контроля чётности (HAL_UART_ERROR_PE).

Вычисления производятся с помощью битовой операции XOR (исключающее «или»).

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

С помощью опций — Even и Odd , можно выбрать что будет считаться чётным.

Hardware Flow Control — это контроль передачи данных (с помощью дополнительных линий) используемый, например, для соединения через COM-порт. Оставьте Disable , нам это не понадобится.

Если устройство хочет прекратить передачу данных, оно устанавливает состояние сигнала RTS (Request To Send) в «ноль» (-12 вольт). Это означает — «не посылать запросы ко мне» (прекратить передачу). Когда устройство готово для принятия очередной партии данных оно устанавливает сигнал RTS в «единицу» (+12 вольт) и обмен данными возобновляется.

Сигналы контроля передачи данных всегда посылаются в противоположном направлении от потока данных. DCE устройства (модемы) работают по тому же принципу, только посылают сигнал на контакте CTS (Clear To Send). Поэтому тип контроля передачи данных RTS/CTS использует 2 линии.

Advanced Features — здесь можно включить автоопределение скорости (Auto Baudrate) и отключить сообщения об ошибках (Overrun, DMA on RX Error), остальные пункты, это различные специфические настройки, которые не стоит менять. Оставьте всё по умолчанию.

Почитать про USART подробно здесь и здесь.

Теперь можно попрограммировать.

Чтобы принять или отправить данные достаточно описанных выше настроек.

Отправить строку «Hello World» можно так:

Первый аргумент — указатель на структуру USART’а, второй — строка (приведённая к указателю), третий кол-во символов в отправляемой строке, четвёртый — таймаут в миллисекундах (если по каким-то причинам не удастся выполнить отправку в течении секунды, то вернётся ошибка).

Эта функция блокирующая, то есть пока она не выполнится программа будет приостановлена.

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

Включите глобальное прерывание…

Отправлять данные так:

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

По окончании отправки сработает прерывание и вызовет колбек:

Второй аргумент — указатель на массив, третий — длина строки в массиве.

Аргументы те же, что и у предыдущей функции.

Колбек тот же что и HAL_UART_Transmit_IT(. ) , но тут есть нюанс. DMA вызывает два прерывания, первое после отправки половины буфера, а второе при завершении. Чтоб отключить половинку, нужно в файле stm32f1xx_hal_uart.c найти функцию HAL_UART_Transmit_DMA(. ) и закомментировать строчку…

Больше про отправку сказать нечего.

Для приёма нужно сделать так:

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять, последний — таймаут.

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

Если для отправки данных блокирующая функция вполне подходит, то для приёма совсем не годится (мы ведь не знаем когда придут данные, если конечно они не идут сплошным потоком). Поэтому нужно использовать функцию вызывающую прерывание…

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять.

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

Помните о том, что если посылаете данные из какого-то терминала, то этот терминал может посылать символы «новой строки» и «воврат каретки». То есть, если вы пошлёте 15 символов, а терминал добавит ещё свои, то программа получит первые 15, вызовет колбек, примет ещё (то что добавил терминал) и будет ожидать. Короче говоря, программа провернётся через колбек и будет ждать.

Включаем канал для приёма…

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять.

Колбек тот же что и при использовании HAL_UART_Receive_IT(. ) , и так же как и с отправкой, будут вызываться два прерывания — половина буфера и полный. Как отключить половинку вы уже знаете.

Поскольку при приёме/отправке могут возникать ошибки, то чтобы их отловить нужно создать специальный колбек…

Сюда приходят все ошибки USART’а.

HAL_UART_ERROR_PE — ошибка контроля чётности.

HAL_UART_ERROR_NE — шум в линии.

HAL_UART_ERROR_FE — ошибка кадра. У передающего устройства «плавает» частота.

HAL_UART_ERROR_ORE — ошибка переполнения. Возникает когда в USART приходит новый байт, а предыдущий ещё не был считан из приёмного регистра — Data Register (DR). Это происходит из-за того, что прерывание обрабатывается слишком медленно и программа не успевает очистить приёмный регистр.

HAL устроен так, что в случае ошибки приём будет перезапущен. Это можно отключить в файле stm32f1xx_hal_uart.c в функции void HAL_UART_IRQHandler(UART_HandleTypeDef *huart) …

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

Если нужно время от времени получать один-два байта, то можно просто в начале программы (перед бесконечным циклом) вызвать функцию приёма…

… а в колбеке что-то поделывать, и вызывать снова…

Можно организовать кольцевой буфер.

Идея заключается в следующем: создаётся массив (размер указывается исходя из потребностей) , полученный байт записывается в этот массив, указатель сдвигается на следующую ячейку, следующий байт сохраняется в эту ячейку, указатель опять сдвигается, и так до тех пор пока буфер не заполнится. После того как буфер заполнился можно поступить двумя способами: первый — указатель перескакивает на нулевую ячейку и буфер заполняется заново постепенно затирая ранее полученные данные. То есть запись идёт по кругу без остановки. Второй — при заполнении буфер останавливается, а новые данные записываются в него по мере вычитывания замещая прочитанные.

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

Вот тут библиотека кольцевого буфера, которой я пользуюсь постоянно.

И ещё один способ — это воспользоваться флагом IDLE. Этот флаг устанавливается аппаратно при обнаружении незанятой линии. То есть, если в приёмник поступает несколько байт подряд, а потом возникает пауза (линия находиться в состоянии HIGH некоторое время), то взводится флаг IDLE генерирующий прерывание, а мы по этому прерыванию определяем что данные перестали поступать.

Допустим мы точно не знаем сколько байт должны прийти, но знаем что их не больше 12, тогда делаем так…

Другое устройство пульнёт нам две строчки…

В результате сначала произойдёт прерывание от IDLE (в буфер запишется строка «Hello World»), а потом прерывание при заполнении буфера. В итоге в буфере будет лежать «Hello WorldHell» — 15 байт.

Если это делать через DMA…

… то вся работа, кроме обработчиков двух прерываний, будет выполняться аппаратно. Не забудьте отключить половинку DMA.

Примеры — раз и два. Эти примеры рабочие, но код я так и не привёл в порядок, ибо как писал выше, пользуюсь «кольцевиком».

Замечание: прерывание по IDLE нужно отключать вручную в колбеке, а так же сбрасывать флаг. Это есть в примере.

Single Wire (Half-Duplex)

Команды те же, что и в обычном (асинхронном) режиме, только надо предварительно настроить линию на приём или передачу…

Можно использовать прерывания и DMA.

… то есть, если одно устройство отправляет данные, то другое должно находиться в режиме приёма.

Линия RX соединена с TX внутри микроконтроллера.

MultiProcessor Communication

В этом режиме можно соединить несколько устройств. Одно устройство выступает в роли Мастера, а другие являются Слейвами. Мастер обращается к слейвам отправляя им их адреса — слейв видя что это его адрес принимает полезные данные.

Подключение обычное, как в асинхронном режиме…

Настройка в CubeMX…

World Lenght — девятибитный режим. Можно и восьмибитный (см. в конце главы).

В момент старта слейв находится в так называемом «тихом» режиме, то есть он не будет принимать полезные данные (принимаются только адреса) пока не поймёт, что они адресованы именно ему. Как только слейв видит что данные адресованы ему, он выходит (Wake-Up) из «тихого» режима и начинает приём полезных данных.

Wake-Up Method ⇨ Address Mark — слейвы будут выходить из «тихого» режима при получении своего адреса.

Wake-Up Address — адрес устройства. Для мастера укажите — , а для слейвов1, 2 и т.д.

Если у вас только два устройства, один мастер и один слейв, тогда подтяните к «плюсу» резистором 10кОм TX мастера. Без этого у меня не работало. Если слейвов несколько, то всё окей.

• Мастер может отравлять данные любому слейву (предварительно отправляя адрес), и получать данные от любого слейва.
• Слейвы слушают линию, и если прилетает правильный адрес, то принимают данные следующие за этим адресом.
• Слейвы могут отправлять данные только мастеру.
• Мастер запускается в обычном режиме, то есть ни каких специальных команд не требуется.
• Слейв запускается в «тихом» режиме.

Для запуска в «тихом» режиме нужно перед бесконечным циклом сделать так…

Пока ничего делать не нужно — команды приведены в ознакомительных целях.

Слейвы в «тихом» режиме ожидают адрес. Мастер, чтобы отправить кому-то данные, сначала отправляет в линию адрес, а затем данные.

Адреса и полезные данные передаются в девятибитном формате (9-ти битный байт). Если отправляется байт с адресом, то в первых восьми битах хранится сам адрес, а в девятый бит записывается единица. Если отправляется байт данных, то в девятый бит записывается ноль. То есть, приёмное устройство отличает байт с данными от байта с адресом по тому, что записано в девятом бите.

Адресный байт мастер отправляет так:

Поскольку байт девятибитный, то переменная 16-ти битная. Адрес первого слейва — 1, записываем его в переменную, а девятый бит превращаем в единицу.

Для слейва с адресом 2 команда будет такая:

После того как адрес отправлен, слейвы проверяют его (это происходит аппаратно, без нашего участия). Тот слейв, чей адрес совпал, переходит из «тихого» режима в обычный и начинает приём данных, которые мы шлём вслед за адресом…

Не обязательно слать один байт, можно отправлять массив, и сколько угодно раз. То есть дальше идёт передача как в обычном режиме, только в 9-ый бит каждого байта будет автоматически (без нашего участия) записываться ноль, чтоб принимающая сторона понимала, что это данные, а не адрес.

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

Теперь, если мастер пошлёт адрес другого слейва…

… то принимать данные будет слейв с адресом 2, а слейв с адресом 1 перейдёт в «тихий» режим.

Вот наглядная схема…

Здесь показано как ведёт себя слейв с адресом 1. Входит в «тихий» режим (RWU written), получает адрес (Addr=0) и игнорирует его вместе с последующими байтами данных, затем получает адрес 1 (Addr=1) и переходит в режим приёма (получает два байта данных — Data 3 и Data 4), а когда получает адрес 2 (Addr=2), то автоматически уходит в «тихий» режим.

Помимо автоматических переходов в «тихий» режим и обратно, это можно делать программно.

Слейвы могут посылать данные мастеру в любой момент без каких-либо адресов. Мастеру конечно можно назначить адрес, но в этом нет смысла так как он один.

В колбеке ловим данные от мастера и выводим их в USART_2 (основной USART_1).

В бесконечном цикле раз в секунду отправляем мастеру букву U.

В колбеке ловим букву U и моргаем лампочкой.

В цикле отправляем данные на разные адреса.

Слейв 1 полчает это…

Восьмибитный режим тоже можно использовать. Всё происходит так же как и в девятибитном, а передаваемые данные будут семибитными — символы с 0x00 по 0x7F. Восьмой бит используется для определения адрес это или данные.

Если не передаёте какие-то специфичные символы, то можно использовать восьмибитный режим.

Адрес подготавливается так:

Это USART через инфракрасный передатчик. Такие штуки были в старинных сотовых телефонах, можно было что-то передавать с телефона на телефон или на компьютер. К компьютеру подключался инфракрасный приёмопередатчик и определялся как COM-порт. В общем можно связать два МК через USART «по воздуху».Функции для работы находятся в файле — stm32f1xx_hal_irda.c .

С остальными режимами я подробно не разбирался, поэтому просто коротенькая справка.

Synchronous — синхронный режим USART’а отличается от асинхронного тем, что частота синхронизации подается от одного устройства к другому по линии CLOCK. На сколько я понимаю, можно работать с SPI…

SmartCard — подключение к смарт-картам.

На этом всё.

Всем спасибо

Источник

USART (Universal Synchronous-Asynchronous Receiver/Transmitter) — универсальный синхронно-асинхронный приёмопередатчик, интерфейс для для передачи данных между цифровыми устройствами. Он на столько универсальный, что даже провода по которым к вам домой приходит интернет, это тоже USART (RS485).

USART микроконтроллера stm32 может работать в различных режимах — асинхронный, синхронный, полудуплекс и т.д.

Asynchronous

Это самый распространённый режим, устройства соединяются так…

RX

<>

TX
TX

<>

RX

… а согласуются между собой с помощью заранее установленной скорости передачи данных.

Тут следует немного пояснить работу USART’а для упрощения понимания некоторых настроек.

Мы будем передавать 8-ми битные байты (в отдельных случаях байты могут 9-ти битные), на скорости 115200 бит в секунду…

Parity

— использование бита проверки чётности (см. ниже).

Stop Bits

— количество стоповых битов (1 или 2).

Data Direction

— включается приём и передача, или что-то одно.

Over Sampling

— см. ниже.

Получаемый пакет из восьми бит (один байт) выглядит так…


Отправляемые/получаемые байты отделяются друг от друга стартовыми и стоповыми битами.

Если ничего не передаётся, то линия находится в состоянии HIGH. Передатчик, начиная отправку, прижимает линию к «земле», а приёмник расценивает это как начало пакета — START (стартовый бит). Далее идёт приём (отсчитывая биты) и после последнего (D7) бита проверяется что линия установлена в HIGH — STOP (стоповый бит). Иногда для большей достоверности окончания приёма используются два стоповых бита.

Количество принятых бит подсчитывается следующим образом: как только появляется стартовый бит (переход с HIGH на LOW) сразу же начинается отсчёт — 16 тиков на каждый бит…


Over Sampling — 16 Samples.

Эти 16 семплов «прощупывают» уровень линии, и если в момент предполагаемой середины бита (MIDBIT) линия находится в состоянии HIGH, то в соответствующий разряд приёмного регистра записывается единичка, если LOW, то нолик. За это отвечают три центральных семпла…

Другие семплы сигнализирует об ошибках. Например, если первые два семпла покажут что линия находится в состоянии HIGH, а следующие два скажут что она LOW, и снова HIGH, то микроконтроллеру станет совершенно очевидно, что при передаче в линию вклинились помехи. В результате вместо байта мы получим сообщение об ошибке — HAL_UART_ERROR_NE — шум в линии. Если же нужные нам семплы «съезжают» в сторону, в право или влево, то это будет означать, что у передающего устройства «плавает» частота, а мы получим ошибку кадра — HAL_UART_ERROR_FE.

анимашка

Вот таким вот нехитрым образом происходит принятие одного байта.

Я не могу говорить за все микроконтроллеры stm32, но например на F303 можно указать частоту семплирования либо 16 либо 8. За счёт уменьшения семплирования можно повышать скорость USART’а. Каким образом — да очень просто: USART_1 тактируется от шины APB2, на каждый бит нам нужно по 16 тиков, значит при частоте шины 72МГц и семплирований 16, мы можем получить максимальную скорость USART’а равную 4.5 Mбит/с (72000000 / 16 = 4500000). Если же указать семплирование 8, то теоретически мы получим скорость 9 Mбит/с.

Parity

— бит чётности. С помощью этого бита можно проверять целостность полученного пакета.

Пакет с добавленным битом чётности выглядит так…


Word Length нужно указать 9 Bits. Если оставить 8 Bits, то полезных битов будет 7.

При отправке в этот бит записывается единица или ноль в зависимости от количества единичек в предыдущих восьми битах. Если единичек чётное кол-во, то записывается 0, если нечётное, то 1.

То есть:

Если отправляется 10111101 (шесть единичек — чётное количество), то бит чётности будет 0. Пакет будет выглядеть так — 101111010.

Если отправляется 01110011 (пять единичек — нечётное количество), то бит чётности будет 1. Пакет будет выглядеть так — 011100111.

При приёме такого пакета производится проверка — соответствует ли количество единичек значению в девятом бите, и если не соответствует, то пакет считается повреждённым — ошибка контроля чётности (HAL_UART_ERROR_PE).

Вычисления производятся с помощью битовой операции XOR (исключающее «или»).

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

С помощью опций —

Even

и

Odd

, можно выбрать что будет считаться чётным.

Hardware Flow Control

— это контроль передачи данных (с помощью дополнительных линий) используемый, например, для соединения через COM-порт. Оставьте Disable, нам это не понадобится.

RTS/CTS

Если устройство хочет прекратить передачу данных, оно устанавливает состояние сигнала RTS (Request To Send) в «ноль» (-12 вольт). Это означает — «не посылать запросы ко мне» (прекратить передачу). Когда устройство готово для принятия очередной партии данных оно устанавливает сигнал RTS в «единицу» (+12 вольт) и обмен данными возобновляется.

Сигналы контроля передачи данных всегда посылаются в противоположном направлении от потока данных. DCE устройства (модемы) работают по тому же принципу, только посылают сигнал на контакте CTS (Clear To Send). Поэтому тип контроля передачи данных RTS/CTS использует 2 линии.

Advanced Features

— здесь можно включить автоопределение скорости (Auto Baudrate) и отключить сообщения об ошибках (Overrun, DMA on RX Error), остальные пункты, это различные специфические настройки, которые не стоит менять. Оставьте всё по умолчанию.

Почитать про USART подробно здесь и здесь.


Теперь можно попрограммировать.ОТПРАВКА

Чтобы принять или отправить данные достаточно описанных выше настроек.

Отправить строку «Hello World» можно так:

HAL_UART_Transmit(&huart1, (uint8_t*)"Hello Worldn", 12, 1000);

Первый аргумент — указатель на структуру USART’а, второй — строка (приведённая к указателю), третий кол-во символов в отправляемой строке, четвёртый — таймаут в миллисекундах (если по каким-то причинам не удастся выполнить отправку в течении секунды, то вернётся ошибка).

Эта функция блокирующая, то есть пока она не выполнится программа будет приостановлена.

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

Включите глобальное прерывание…

Отправлять данные так:

HAL_UART_Transmit_IT(&huart1, (uint8_t*)"Hello Worldn", 12);

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

По окончании отправки сработает прерывание и вызовет колбек:

void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  // можно установить какой-то флаг, сообщающий об окончании отправки
	  }	
}

Отправить массив:

/* USER CODE BEGIN Includes */
#include "string.h"
/* USER CODE END Includes */
...

char buff[16] = {0,};

snprintf(buff, 15, "Hello Worldn");
HAL_UART_Transmit_IT(&huart1, (uint8_t*)buff, strlen(buff));

Второй аргумент — указатель на массив, третий — длина строки в массиве.

Через DMA

Включаем…

Отправляем:

HAL_UART_Transmit_DMA(&huart1, (uint8_t*)buff, strlen(buff));

Аргументы те же, что и у предыдущей функции.

Колбек тот же что и

HAL_UART_Transmit_IT(…)

, но тут есть нюанс. DMA вызывает два прерывания, первое после отправки половины буфера, а второе при завершении. Чтоб отключить половинку, нужно в файле

stm32f1xx_hal_uart.c

найти функцию

HAL_UART_Transmit_DMA(…)

и закомментировать строчку…

/* Set the UART DMA Half transfer complete callback */
//huart->hdmatx->XferHalfCpltCallback = UART_DMATxHalfCplt;

Больше про отправку сказать нечего.

ПРИЁМ

Для приёма нужно сделать так:

uint8_t buff[16] = {0,};
HAL_UART_Receive(&huart1, (uint8_t*)buff, 15, 1000);

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять, последний — таймаут.

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

Если для отправки данных блокирующая функция вполне подходит, то для приёма совсем не годится (мы ведь не знаем когда придут данные, если конечно они не идут сплошным потоком). Поэтому нужно использовать функцию вызывающую прерывание…

uint8_t buff[16] = {0,};
HAL_UART_Receive_IT(&huart1, (uint8_t*)buff, 15);

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять.

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

Колбек:

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  // что-то делаем
	  }
}

Помните о том, что если посылаете данные из какого-то терминала, то этот терминал может посылать символы «новой строки» и «воврат каретки». То есть, если вы пошлёте 15 символов, а терминал добавит ещё свои, то программа получит первые 15, вызовет колбек, примет ещё (то что добавил терминал) и будет ожидать. Короче говоря, программа провернётся через колбек и будет ждать.

Через DMA

Включаем канал для приёма…

Запускаем…

HAL_UART_Receive_DMA(&huart1, (uint8_t*)buff, 15);

Второй аргумент — указатель на массив в который будут записываться полученные данные, третий — кол-во байт, которые нужно принять.

Колбек тот же что и при использовании

HAL_UART_Receive_IT(…)

, и так же как и с отправкой, будут вызываться два прерывания — половина буфера и полный. Как отключить половинку вы уже знаете.

Поскольку при приёме/отправке могут возникать ошибки, то чтобы их отловить нужно создать специальный колбек…

error

Сюда приходят все ошибки USART’а.

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart)
{
	if (huart == &huart1)
	{
		uint32_t er = HAL_UART_GetError(&huart1);
 
		if (er & HAL_UART_ERROR_PE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Parity errorn", 27, 1000);
			__HAL_UART_CLEAR_PEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_NE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Noise errorn", 26, 1000);
			__HAL_UART_CLEAR_NEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_FE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Frame errorn", 26, 1000);
			__HAL_UART_CLEAR_FEFLAG(&huart1);
		}
		if (er & HAL_UART_ERROR_ORE)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - Overrun errorn", 28, 1000);
			__HAL_UART_CLEAR_OREFLAG(huart);
		}
		if (er & HAL_UART_ERROR_DMA)
		{
			HAL_UART_Transmit(&huart1, (uint8_t*) "ERR_Callbck - DMA transfer errorn", 33, 1000);
			__HAL_UART_CLEAR_NEFLAG(&huart1);
		}
		huart->ErrorCode = HAL_UART_ERROR_NONE;
	}
}

Файл stm32f1xx_hal_uart.h

HAL_UART_ERROR_PE

— ошибка контроля чётности.

HAL_UART_ERROR_NE

— шум в линии.

HAL_UART_ERROR_FE

— ошибка кадра. У передающего устройства «плавает» частота.

HAL_UART_ERROR_ORE

— ошибка переполнения. Возникает когда в USART приходит новый байт, а предыдущий ещё не был считан из приёмного регистра — Data Register (DR). Это происходит из-за того, что прерывание обрабатывается слишком медленно и программа не успевает очистить приёмный регистр.

HAL устроен так, что в случае ошибки приём будет перезапущен. Это можно отключить в файле

stm32f1xx_hal_uart.c

в функции

void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)

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

Если нужно время от времени получать один-два байта, то можно просто в начале программы (перед бесконечным циклом) вызвать функцию приёма…

/* USER CODE BEGIN PV */
volatile char sim;
/* USER CODE END PV */

...

HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);

… а в колбеке что-то поделывать, и вызывать снова…

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  HAL_UART_Transmit(&huart1, (uint8_t*)&sim, 1, 1000);
		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}

Можно организовать кольцевой буфер.

Идея заключается в следующем: создаётся массив

(размер указывается исходя из потребностей)

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

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

Вот тут библиотека кольцевого буфера, которой я пользуюсь постоянно.

И ещё один способ — это воспользоваться флагом IDLE. Этот флаг устанавливается аппаратно при обнаружении незанятой линии. То есть, если в приёмник поступает несколько байт подряд, а потом возникает пауза (линия находиться в состоянии HIGH некоторое время), то взводится флаг IDLE генерирующий прерывание, а мы по этому прерыванию определяем что данные перестали поступать.

Допустим мы точно не знаем сколько байт должны прийти, но знаем что их не больше 12, тогда делаем так…

HAL_UART_Receive_IT(&huart1, (uint8_t*)buff, 15);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

Другое устройство пульнёт нам две строчки…

HAL_UART_Transmit(&huart2, (uint8_t*)"Hello World", 11, 1000);  
HAL_UART_Transmit(&huart2, (uint8_t*)"Hello World", 11, 1000);

В результате сначала произойдёт прерывание от IDLE (в буфер запишется строка «Hello World»), а потом прерывание при заполнении буфера. В итоге в буфере будет лежать «Hello WorldHell» — 15 байт.

Если это делать через DMA…

HAL_UART_Receive_DMA(&huart1, (uint8_t*)buff, 15);
__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);

… то вся работа, кроме обработчиков двух прерываний, будет выполняться аппаратно. Не забудьте отключить половинку DMA.

Примеры — раз и два. Эти примеры рабочие, но код я так и не привёл в порядок, ибо как писал выше, пользуюсь «кольцевиком».

Замечание: прерывание по IDLE нужно отключать вручную в колбеке, а так же сбрасывать флаг. Это есть в примере.


Single Wire (Half-Duplex)

Полудуплексный режим — данные передаются и принимаются по одной линии (TX). В этом режиме устройства обмениваются данными по очереди — один слушает, другой отправляет. Линию нужно обязательно подтянуть к «плюсу» резистором ~10кОм…

Команды те же, что и в обычном (асинхронном) режиме, только надо предварительно настроить линию на приём или передачу…

HAL_HalfDuplex_EnableReceiver(&huart1); // устройство в режиме приёма
HAL_UART_Receive(&huart1, (uint8_t*)buff, 12, 1000);
HAL_HalfDuplex_EnableTransmitter(&huart1); // устройство в режиме отправки
HAL_UART_Transmit(&huart1, (uint8_t*)buff, 12, 1000);

Можно использовать прерывания и DMA.

… то есть, если одно устройство отправляет данные, то другое должно находиться в режиме приёма.

Линия RX соединена с TX внутри микроконтроллера.


MultiProcessor Communication

В этом режиме можно соединить несколько устройств. Одно устройство выступает в роли Мастера, а другие являются Слейвами. Мастер обращается к слейвам отправляя им их адреса — слейв видя что это его адрес принимает полезные данные.

Подключение обычное, как в асинхронном режиме…

Настройка в CubeMX…

F303

World Lenght

— девятибитный режим. Можно и восьмибитный (см. в конце главы).

В момент старта слейв находится в так называемом «тихом» режиме, то есть он не будет принимать полезные данные (принимаются только адреса) пока не поймёт, что они адресованы именно ему. Как только слейв видит что данные адресованы ему, он выходит (Wake-Up) из «тихого» режима и начинает приём полезных данных.

Wake-Up Method ⇨ Address Mark

— слейвы будут выходить из «тихого» режима при получении своего адреса.

Wake-Up Address

— адрес устройства. Для мастера укажите — 0, а для слейвов1, 2 и т.д.

Если у вас только два устройства, один мастер и один слейв, тогда подтяните к «плюсу» резистором 10кОм TX мастера. Без этого у меня не работало. Если слейвов несколько, то всё окей.

Как работает:

• Мастер может отравлять данные любому слейву (предварительно отправляя адрес), и получать данные от любого слейва.
• Слейвы слушают линию, и если прилетает правильный адрес, то принимают данные следующие за этим адресом.
• Слейвы могут отправлять данные только мастеру.
• Мастер запускается в обычном режиме, то есть ни каких специальных команд не требуется.
• Слейв запускается в «тихом» режиме.

Для запуска в «тихом» режиме нужно перед бесконечным циклом сделать так…

Для F103:

HAL_MultiProcessor_EnterMuteMode(&huart1);

Для F303:

HAL_MultiProcessor_EnableMuteMode(&huart1);
HAL_MultiProcessor_EnterMuteMode(&huart1);

Пока ничего делать не нужно — команды приведены в ознакомительных целях.

Слейвы в «тихом» режиме ожидают адрес. Мастер, чтобы отправить кому-то данные, сначала отправляет в линию адрес, а затем данные.

Адреса и полезные данные передаются в девятибитном формате (9-ти битный байт). Если отправляется байт с адресом, то в первых восьми битах хранится сам адрес, а в девятый бит записывается единица. Если отправляется байт данных, то в девятый бит записывается ноль. То есть, приёмное устройство отличает байт с данными от байта с адресом по тому, что записано в девятом бите.

Адресный байт мастер отправляет так:

uint16_t adr_data = 0;
adr_data = 1 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);

Поскольку байт девятибитный, то переменная 16-ти битная. Адрес первого слейва — 1, записываем его в переменную, а девятый бит превращаем в единицу.

Для слейва с адресом 2 команда будет такая:

uint16_t adr_data = 0;
adr_data = 2 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);

После того как адрес отправлен, слейвы проверяют его (это происходит аппаратно, без нашего участия). Тот слейв, чей адрес совпал, переходит из «тихого» режима в обычный и начинает приём данных, которые мы шлём вслед за адресом…

uint16_t adr_data = 0;
adr_data = 1 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
HAL_UART_Transmit(&huart1, (uint8_t*)"A", 1, 1000);

Не обязательно слать один байт, можно отправлять массив, и сколько угодно раз. То есть дальше идёт передача как в обычном режиме, только в 9-ый бит каждого байта будет автоматически (без нашего участия) записываться ноль, чтоб принимающая сторона понимала, что это данные, а не адрес.

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

Теперь, если мастер пошлёт адрес другого слейва…

uint16_t adr_data = 0;
adr_data = 2 | 0x0100;
HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);

… то принимать данные будет слейв с адресом 2, а слейв с адресом 1 перейдёт в «тихий» режим.

Вот наглядная схема…

Здесь показано как ведёт себя слейв с адресом 1. Входит в «тихий» режим (RWU written), получает адрес 0 (Addr=0) и игнорирует его вместе с последующими байтами данных, затем получает адрес 1 (Addr=1) и переходит в режим приёма (получает два байта данных — Data 3 и Data 4), а когда получает адрес 2 (Addr=2), то автоматически уходит в «тихий» режим.

Помимо автоматических переходов в «тихий» режим и обратно, это можно делать программно.

Для F103:

HAL_MultiProcessor_EnterMuteMode(&huart1); // затихариться

HAL_MultiProcessor_ExitMuteMode(&huart1); // очнутся

Для F303:

HAL_MultiProcessor_EnableMuteMode(&huart1);
HAL_MultiProcessor_EnterMuteMode(&huart1);  // затихариться

HAL_MultiProcessor_DisableMuteMode(&huart1); // очнутся

Слейвы могут посылать данные мастеру в любой момент без каких-либо адресов. Мастеру конечно можно назначить адрес, но в этом нет смысла так как он один.

программа для тестов

СЛЕЙВ

/* USER CODE BEGIN PV */
volatile uint16_t sim;
char trans_str[16] = {0,};
/* USER CODE END PV */

В колбеке ловим данные от мастера и выводим их в USART_2 (основной USART_1).

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  HAL_UART_Transmit(&huart2, (uint8_t*)&sim, 1, 1000);
		  HAL_UART_Transmit(&huart2, (uint8_t*)"rn", 2, 1000);

		  //HAL_MultiProcessor_EnterMuteMode(&huart1);

		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}

В бесконечном цикле раз в секунду отправляем мастеру букву U.

/* USER CODE BEGIN 2 */
  HAL_MultiProcessor_EnterMuteMode(&huart1);
  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  HAL_Delay(990);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"U", 1, 1000);
          ...

МАСТЕР

/* USER CODE BEGIN PV */
volatile uint8_t sim;
/* USER CODE END PV */

В колбеке ловим букву U и моргаем лампочкой.

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	  if(huart == &huart1)
	  {
		  if(sim == 'U')
		  {
			  HAL_GPIO_TogglePin(LD10_GPIO_Port, LD10_Pin);
		  }

		  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);
	  }
}

В цикле отправляем данные на разные адреса.

/* USER CODE BEGIN 2 */
  HAL_UART_Receive_IT(&huart1, (uint8_t*)&sim, 1);

  uint16_t adr_data = 0;
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
	  adr_data = 1 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"A", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"B", 1, 1000);
	  HAL_Delay(1000);

	  adr_data = 2 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"C", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"z", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"x", 1, 1000);
	  HAL_Delay(1000);

	  HAL_UART_Transmit(&huart1, (uint8_t*)"n", 1, 1000);
	  HAL_Delay(1000);

	  adr_data = 1 | 0x0100;
	  HAL_UART_Transmit(&huart1, (uint8_t*)&adr_data, 1, 1000);
	  HAL_UART_Transmit(&huart1, (uint8_t*)"D", 1, 1000);
	  HAL_Delay(1000);
          ...

Слейв 1 полчает это…

Восьмибитный режим тоже можно использовать. Всё происходит так же как и в девятибитном, а передаваемые данные будут семибитными — символы с 0x00 по 0x7F. Восьмой бит используется для определения адрес это или данные.

Если не передаёте какие-то специфичные символы, то можно использовать восьмибитный режим.

Адрес подготавливается так:

uint8_t adr_data = 0;

adr_data = 1 | 0x80;

IrDA

Это USART через инфракрасный передатчик. Такие штуки были в старинных сотовых телефонах, можно было что-то передавать с телефона на телефон или на компьютер. К компьютеру подключался инфракрасный приёмопередатчик и определялся как COM-порт. В общем можно связать два МК через USART «по воздуху».Функции для работы находятся в файле —

stm32f1xx_hal_irda.c

.


С остальными режимами я подробно не разбирался, поэтому просто коротенькая справка. Synchronous

— синхронный режим USART’а отличается от асинхронного тем, что частота синхронизации подается от одного устройства к другому по линии CLOCK. На сколько я понимаю, можно работать с SPI…

LIN

— посмотрите здесь.

SmartCard

— подключение к смарт-картам.

На этом всё.

Всем спасибо

Телеграм-чат istarik

Телеграм-чат STM32

Он ещё и у F7 и у F3 особенный…

Появившийся флаг overflow или frame error тоже надо снимать. Даже если прерывания по нему не разрешены.

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

Где-то тут я уже жаловался на найденную аномалию поведения.

...
#elif CPUSTYLE_STM32F30X || CPUSTYLE_STM32F0XX || CPUSTYLE_STM32L0XX || CPUSTYLE_STM32F7XX

    void USART1_IRQHandler(void)
    {
        const uint_fast32_t isr = USART1->ISR;

        if (isr & USART_ISR_RXNE)
            cat_parsechar(USART1->RDR);
        if (isr & USART_ISR_ORE)
        {
            USART1->ICR = USART_ICR_ORECF;
            cat_rxoverflow();
        }
        if (isr & USART_ISR_FE)
            USART1->ICR = USART_ICR_FECF;
        if (isr & USART_ISR_TXE)
            cat_sendchar();
    }
#endif

И для случия поллинга:

...
#elif CPUSTYLE_STM32F30X || CPUSTYLE_STM32F0XX || CPUSTYLE_STM32L0XX || CPUSTYLE_STM32F7XX
    const uint_fast32_t isr = USART1->ISR;
    if (isr & USART_ISR_ORE)
        USART1->ICR = USART_ICR_ORECF;
    if (isr & USART_ISR_FE)
        USART1->ICR = USART_ICR_FECF;
    if ((isr & USART_ISR_RXNE) == 0)
        return 0;
    * cp = USART1->RDR;

#endif

Оффтопик:

Вот люди с аномалией в F4 возились…

https://my.st.com/public/STe2ecommunities/m…rrentviews=1896

А вот моё:

Продолжаю разбираться.

Получи все-таки ситуацию (Не на единичных байтах).

В статусном регистре (после входа в обработчик) нет установленного бита готовности данных приёмника, но есть бит ошибки ORE. Но это после нескольких килобайт… Перед этим пара правильных срабатываний (и данные и флаг ORE) проходит.

Вот так выглядит выдача:

$$$$ rxc=61847, ovf=1008, sr=00000008, SR=000000D8, CR1=000020AC, CR2=00000000

$$$$ rxc=351, ovf=1004, sr=00000008, SR=000000D8, CR1=000020AC, CR2=00000000

А вот код:

            void USART1_IRQHandler(void)
            {
                        static unsigned long ovf = 0;
                        static unsigned long rxc = 0;
                        const unsigned long sr = USART1->SR;
                        uint_fast8_t f = 0;

                        if (sr & USART_SR_RXNE)
                        {
                                   (void) USART1->DR;
                                   f=1;
                                   ++ rxc;
                        }
                        if (sr & USART_SR_ORE)
                                   ++ ovf;
                        if (sr & USART_SR_TXE)
                        {
                                   USART1->DR = 0x01;
                                   f=1;
                        }

                        if (f == 0)
                        {
                                   static int cnt = 1000;
                                   if (-- cnt == 0)
                                   {
                                               char buff [128];

                                               local_delay_ms(100);    // чтобы успело ещё множество байт прилететь - скорость 115200
                                               local_snprintf_P(
                                                           buff, sizeof buff / sizeof buff [0], 
                                                           PSTR("n$$$$ rxc=%lu, ovf=%lu, sr=%08lX, SR=%08lX, CR1=%08lX, CR2=%08lXn"), 
                                                           rxc,
                                                           ovf, 
                                                           sr, 
                                                           USART1->SR, 
                                                           USART1->CR1,
                                                           USART1->CR2
                                                           );

                                               hdbg_puts_impl(buff);
                                               for (;;)
                                                          ;
                                   }
                        }
            }

Функция hdbg_puts_impl просто выводит в тот же порт строчку «посмертного дампа», пользуясь программным опросом готовности.


Изменено 18 марта, 2016 пользователем Genadi Zawidowski

Сообщения без ответов | Активные темы

ПРЯМО СЕЙЧАС:

Автор Сообщение

Не в сети

Заголовок сообщения: USART Framing error[STM32F103]

СообщениеДобавлено: Вс окт 05, 2014 14:17:45 

Первый раз сказал Мяу!

Карма: 2

Рейтинг сообщений: 0

Зарегистрирован: Сб дек 28, 2013 20:31:22
Сообщений: 35

Рейтинг сообщения: 0

Добрый день. Писал программу для пересылки через USART в терминал. Во прекрасно работает. В терминал шлется и символ и строка, но когда я проверяю тот же код логическим анализатором, он выдает ошибку Framing error, причем отмечает крестиком именно последний стоповый бит… Помогите разобраться в чем причина.
Собственно код:

Код:

void GPIO_Configuration(void)
{
   RCC->APB2ENR|= (RCC_APB2ENR_IOPAEN|RCC_APB2ENR_AFIOEN);

   //USART1_TX(PA9)
   GPIOA->CRH |= (GPIO_CRH_CNF9_1|GPIO_CRH_MODE9_0);

   //USART1_RX(PA10)
   GPIOA->CRH |=GPIO_CRH_CNF10_0;
   GPIOA->CRH &= ~GPIO_CRH_CNF10_1;
   GPIOA->CRH &= ~GPIO_CRH_MODE10;
}

void USART_Configuration(void)
{
   RCC->APB2ENR|= RCC_APB2ENR_USART1EN;

   USART1->CR1 = 0x0000;
   USART1->CR1 |= (USART_CR1_UE|USART_CR1_RE|USART_CR1_TE);
   USART1->BRR = 0xB65;
}

/*char data[128];
uint32_t count=0,j=0;

void USART_Send_Symbol(uint8_t data)
{
   while(!(USART1->SR & USART_SR_TC));
   USART1->DR=data;
}

void USART_Send_String(char *data, uint8_t terminate)
{

   uint8_t i = 0;
   while(data[i])
   {
      USART_Send_Symbol(data[i++]);
   }
   if(terminate)
   {
      USART_Send_Symbol(‘r’);
      USART_Send_Symbol(‘n’);
   }
}*/

int main(void)
{
   SYSCLK_Configuration();
   GPIO_Configuration();
   USART_Configuration();   
   while(!(USART1->SR & USART_SR_TC));
   USART1->DR=’H’;   
while(1)
   {

      }

}

Фото с логического анализатора прикреплено ниже!

Вложения:


csKfrSZ5WC4.jpg [47.14 KiB]

Скачиваний: 554

Вернуться наверх
 

ПрофильПрофиль

 

Реклама

dosikus

Не в сети

Заголовок сообщения: Re: USART Framing error[STM32F103]

СообщениеДобавлено: Вс окт 05, 2014 16:38:17 

Друг Кота
Аватар пользователя

Карма: 30

Рейтинг сообщений: 154

Зарегистрирован: Пн июл 28, 2008 22:12:01
Сообщений: 3604

Рейтинг сообщения: 0

Научиться делать скриншоты и пользоваться лог. анализатором …

Вернуться наверх
Реклама

Foxek

Не в сети

Заголовок сообщения: Re: USART Framing error[STM32F103]

СообщениеДобавлено: Вс окт 05, 2014 17:12:25 

Карма: 2

Рейтинг сообщений: 0

Зарегистрирован: Сб дек 28, 2013 20:31:22
Сообщений: 35

Рейтинг сообщения: 0

ой тыж гений какой. А по умнее что либо сказать?

Вернуться наверх

dosikus

Не в сети

Заголовок сообщения: Re: USART Framing error[STM32F103]

СообщениеДобавлено: Вт окт 07, 2014 09:44:11 

Друг Кота
Аватар пользователя

Карма: 30

Рейтинг сообщений: 154

Зарегистрирован: Пн июл 28, 2008 22:12:01
Сообщений: 3604

Рейтинг сообщения: 0

Foxek писал(а):

А по умнее что либо сказать?

По умней что? Ляпнуть по умней высера — «ой тыж гений какой» ???? :)))
Легко

Код:

#define USARTCLK 72000000UL
#define BAUDRATE 115200UL

Код:

 

 void USART1_IRQHandler (void)
 {

    if(USART1->SR & USART_SR_RXNE)
   {
     UsartBuf =USART1->DR;

       }

    }

 void UsartInit(void)
 {
   RCC->APB2ENR |=RCC_APB2ENR_USART1EN | RCC_APB2ENR_IOPAEN;

        GPIOA->CRH &=~ (GPIO_CRH_CNF10 |GPIO_CRH_CNF9|GPIO_CRH_MODE10);
    GPIOA->CRH |= GPIO_CRH_CNF10_0 |GPIO_CRH_CNF9_1 | GPIO_CRH_MODE9;

        USART1->CR1 |= USART_CR1_TE |USART_CR1_RE |USART_CR1_RXNEIE;
    USART1->BRR =(USARTCLK+BAUDRATE/2)/BAUDRATE;
    USART1->CR1 |=USART_CR1_UE;

        NVIC_SetPriority(USART1_IRQn,15);
    NVIC_EnableIRQ(USART1_IRQn);

       }

void USART_write (char data)
  {
    while(!(USART1->SR & USART_SR_TXE));
    USART1->DR=data;
  }
void  USART_WR_String(const char *s)
{
        char c;
        while ((c = *s++)) {
                USART_write(c);
        }
}

Код:

 int main (void)
   {
        UsartBuf=0;
 SysTick_Config(SystemCoreClock /1000); 
 UsartInit();

     Delay_mS(100);
  while(1)
  {
  if(UsartBuf==’h’)
  {
   UsartBuf =0;

      USART_WR_String(«Hello worldrn»);
  }
  Delay_mS(100);
  }   
      return 0;
   }

Изображение
Изображение
Изображение

И вопрос к страждущему — модуль HC переведен из режима «команд» в режим «данные» ?

Вернуться наверх
Реклама

Выгодные LED-драйверы для решения любых задач

КОМПЭЛ представляет со склада и под заказ широкий выбор LED-драйверов производства MEAN WELL, MOSO, Snappy, Inventronics, EagleRise. Линейки LED-драйверов этих компаний, выполненные по технологии Tunable White и имеющие возможность непосредственного встраивания в систему умного дома (димминг по шине KNX), перекрывают практически полный спектр применений: от простых световых указателей и декоративной подсветки до диммируемых по различным протоколам светильников внутреннего и наружного освещения.

Подобрать LED-драйвер>>

Кто сейчас на форуме

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 7

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете добавлять вложения

Понравилась статья? Поделить с друзьями:
  • Stm32 error failed to erase memory
  • Stm ide error launching installer
  • Stlink usb communication error
  • Stk500 error entering programming mode
  • Still fm x20 ошибки