UART в STM32
На борту микроконтроллера STM32 есть несколько UARTов.
Если глянуть что поэтому поводу говорит википедия > UART, мы узнаем что это один из самых распространенных протоколов обмена информации.
Итак у STM32 есть таких несколько а именно:
Теперь напишем в Coocox IDE программу для нашего МК. Будем использовать стандартные библиотеки от ST.
Для того что бы пользоваться USART нам необходимо инициализировать и настроить его.
необходимости конфигурировать их для нашего примера.
Для того что бы отправлять или получать данные мы будем использвать DR(Data Register) используемого USART.
Если прочитать регистр то мы получим последним полученный байт. Если записать в регистр, то записанный байт будет передан.
Есть два решения для отправки/приема данных.
Первое (не очень хорошее). Для отправки используется задержка после записи в регистр, и если задержка достаточно велика, мы можем быть уверены в том, что наши данные были переданы. Далее будем опрашивать регистр до тех пор пока прочитанный байт не будет отличатья от последнего прочитанного.
Мы же будем использовать решение лучше. Для нашего примера пригодится SR(Status Register) на USART1. SR имеет бит, который сообщаетбыли ли переданы/получены данные. Как только DR будет прочитан, Флаг полученных данных автоматически сбрасывается.
Альтернативно можно включить прерывание USART1 для полученных данных. Если мы это сделаем, прерывание будет обрабатываться каждый раз как только будут поступать новые данные.
Далее я более детально опишу, как настроить, получать и принимать данные на языке С. Для этого нам нужно сделать 3 функции.
Замечание: мы используем CHR для пинов с 8 по 15 так они находят в регистре Н, а пины с 0 по 7 части регистра L.
Далее нам необходимо настроит USART. Для начала опеределим используемый бодрейт. Это делается используя регистр BRR в USART. Так как у STM32 фракционный генератор можно получить любой бодрейт из системного тактирования (systems bus clock). Значение для регистра BRR можно легко расчиать из такой простой формулы:
USART_BRR = [BUS_FREQUENCY_in_Hz] / [BAUD_RATE]
Для того что бы настроить USART на 38400 бод,запишем следующее в код:
Если глянуть что поэтому поводу говорит википедия > UART, мы узнаем что это один из самых распространенных протоколов обмена информации.
Итак у STM32 есть таких несколько а именно:
Пин | Функция |
PA8 | USART1_CK |
PA11 | USART1_CTS |
PA12 | USART1_RTS |
PA9 | USART1_TX |
PA10 | USART1_RX |
PA4 | USART2_CK |
PA0 | USART2_CTS |
PA1 | USART2_RTS |
PA2 | USART2_TX |
PA3 | USART2_RX |
PB12 | USART3_CK |
PB13 | USART3_CTS |
PB14 | USART3_RTS |
PB10 | USART3_TX |
PB11 | USART3_RX |
Как мы видим у нас есть 3 полноценных USART с распиновкой. Давайте подключим отладочную плату к FT232RL по такой схеме
- PA9 от STM32 (USART1_TX) подключим к RXD на FT232RL
- PA10 от STM32 (USART1_RX) подключим TXD на FT232RL
- GND на STM32 подключим GND на FT232RL
(сорри за качество фото с мобильника, но сути не меняет)
Для того что бы пользоваться USART нам необходимо инициализировать и настроить его.
- включить системное тактирование для USART1
- настроить пины RX/TX для USART1
- установить baudrate для USART1
- включить USART1 и его RX/TX компоненты.
необходимости конфигурировать их для нашего примера.
Для того что бы отправлять или получать данные мы будем использвать DR(Data Register) используемого USART.
Если прочитать регистр то мы получим последним полученный байт. Если записать в регистр, то записанный байт будет передан.
Есть два решения для отправки/приема данных.
Первое (не очень хорошее). Для отправки используется задержка после записи в регистр, и если задержка достаточно велика, мы можем быть уверены в том, что наши данные были переданы. Далее будем опрашивать регистр до тех пор пока прочитанный байт не будет отличатья от последнего прочитанного.
Мы же будем использовать решение лучше. Для нашего примера пригодится SR(Status Register) на USART1. SR имеет бит, который сообщаетбыли ли переданы/получены данные. Как только DR будет прочитан, Флаг полученных данных автоматически сбрасывается.
Альтернативно можно включить прерывание USART1 для полученных данных. Если мы это сделаем, прерывание будет обрабатываться каждый раз как только будут поступать новые данные.
Далее я более детально опишу, как настроить, получать и принимать данные на языке С. Для этого нам нужно сделать 3 функции.
- board_init: тут проведиться вся инициализация
- usart_rec: блок получения данных
- usart_snd: блко отправки данных.
board_init
Для начала нам необходимо включить тактирование USART1 и GPIOA ( так RX/TX находятся именно тут). Для использования втроенных светодиодов , необходимо включить CPIOC.
Сделаем это установивши регистр RCC для шины APB2 (как GPIOA так USART1 покдлючены к данной шине):RCC->APB2ENR = 0 // Включаем USART1 | RCC_APB2ENR_USART1EN // Включаем IO Port A | RCC_APB2ENR_IOPAEN;Теперь надо насторить GPIO для РA9(TX) и PA10(RX). Пин ТХ должен быть настроен пин-выход с альтернативной функцией (USART1_TX). Конфигурируем это пин на выход режиме push-pull и частоте 50 МГц. Собрав все эти биты для настройки вместе мы получим значение 0хВ для данной конфигурации. Р10 (RX) должен быть настроен на вход в режиме floating input так как подключенная FT232RL сама позаботится о pull-up/pull-down. Для настройки floating input для нужного пина нужно в регистр записать значение 0х4. В коде это буде выглядеть вот так:
// Устанавливаем PA9 (TX) на альтернавтивную функцию выхода push-pull при 50 MHz // Установим PA10 (RX) на floating input GPIOA->CRH = 0x000004B0;
Замечание: мы используем CHR для пинов с 8 по 15 так они находят в регистре Н, а пины с 0 по 7 части регистра L.
Далее нам необходимо настроит USART. Для начала опеределим используемый бодрейт. Это делается используя регистр BRR в USART. Так как у STM32 фракционный генератор можно получить любой бодрейт из системного тактирования (systems bus clock). Значение для регистра BRR можно легко расчиать из такой простой формулы:
USART_BRR = [BUS_FREQUENCY_in_Hz] / [BAUD_RATE]
Для того что бы настроить USART на 38400 бод,запишем следующее в код:
// Настроим BRR делением тактирования на необходиимый бодрейт USART1->BRR = 8000000/38400;И наконец нужно включить UART, TX, RX. Делается это установкой соответствующих флагов в конфигурирующем регистре 1 (CR1) USART1.
USART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;
Вот и все. Ваш USART теперь готов общаться со скоростью 38400 бод при 8 битах данный, без flow control и одним stop-bit.usart_rec
Для того что прочитать полученные данные, все что необходиом сделать ,то это подождать пока RXNE (RX not empty (не пустой)) бит не будет установлен в регистре статуса SR в USART1. После того как бит будет установлен, мы читаем данные из регистра данных DR в USART1. Так как регистр DR 32 битный, но используется только 9 бит, мы применим маску 0x1FF для входящих данных, что бы не получать мусор. После того как регистр DR будет проичан, USART сбрасывает RXNE флаг автоматически. В нашей программе это будет выглядеть вот так.
/* Ждем пока данные будут получены. */ while ((USART1->SR & USART_SR_RXNE) == 0); // читаем данные RX, применяя маскуDR мы получаем только 9 бит) return USART1->DR & 0x1FF;
board_snd
Для того что бы отправить данные, нам просто нужно их записать в регистр данных DR. Далее подождем пока флаг ТХЕ (TX empty (пустой) в регистре статуса SR будет установлен и можем быть уверены что данные переданы. В коде это будет выглядеть вот так:
USART1->DR = data; // ждем отправки TX while ((USART1->SR & USART_SR_TXE) == 0);Вот код для main.c
/*** USART Loopback sample for STM32 Discovery board** 26.07.2011, Stefan Wendler, devnull@kaltpost.de** читает байт RX с USART1, отображает в квадратных* скобках и шлет в TX USART1.** т.е. вводим"A", программа отвечает "[A]".** Каждый раз как только байт получен, мигает зеленый светодиод,* а как только отправляются 3 байта мигает синий.*** USART1 настроен 38400, 8, N, 1* PA9 - TX , PA10 - RX.**/#include "stm32f10x.h"#include "stm32f10x_gpio.h"#include "stm32f10x_rcc.h"#include "stm32f10x_usart.h"#include "stm32f10x_i2c.h"//i2c#include <stdio.h>
#include "stm32f10x.h"#define LED_BLUE 8 /* PC8-синий LED */#define LED_GREEN 9 /* PC9 зеленый LED */#define MODE_ON 0 /* Offset to add to pin for ON */#define MODE_OFF 16 /* Offset to add to pin for OFF */void nmi_handler(void);void hardfault_handler(void);int main(void);/*** Four vectors - the starting stack pointer value,* code entry point and NMI and Hard-Fault handlers*/unsigned int * myvectors[4]__attribute__ ((section("vectors")))= {(unsigned int *) 0x20002000,(unsigned int *) main,(unsigned int *) nmi_handler,(unsigned int *) hardfault_handler};/*** Инициализируем плату* - влючаем тактирование* - настраиваем GPIO* - настраиваем USARТ1*/void board_init(void) {// Большиство периферии подключено к APB2. Включаем тактирование// на интересуещей нас переферииRCC->APB2ENR = 0// Влючаем USART1| RCC_APB2ENR_USART1EN// ВлючаемIO Порта A| RCC_APB2ENR_IOPAEN// Включаем IO Порта C| RCC_APB2ENR_IOPCEN;// Установим PC8 и PC9 в режим outpute (встроенные LED)GPIOC->CRH = 0x11;// Установим PA9 (TX)альтернативную функцию выхода push-pull при 50 MHz//УстановимPA10 (RX) в floating inputGPIOA->CRH = 0x000004B0;// Сконфигурируем BRR делением bus clock на baud rateUSART1->BRR = 8000000/38400;// Активируем USART, TX, и RX схемуUSART1->CR1 = USART_CR1_UE | USART_CR1_TE | USART_CR1_RE;}/*** Задержка для"cnt" NOPs.** @param[in] cnt количество NOPs для задержки*/void delay(int cnt) {while (cnt-- > 0) {asm("nop");}}/*** Получим один байт отUSART1. будем ждать
* пока USART не даст сигнал о том что байт получен** @return полученый байт*/int usart_rec(void) {/* Ждем готовность принятия данных. */while ((USART1->SR & USART_SR_RXNE) == 0);// читаем данные RX , применяя маску DR (будем принимать только 9 битs)return USART1->DR & 0x1FF;}/*** Шлем один байт в \USART1. Ждем пока* USART не отошлет байт.** @param[in] байт который нужно отправить*/void usart_snd(int data) {USART1->DR = data;// ждемTXwhile ((USART1->SR & USART_SR_TXE) == 0);}/*** Шлем строку в USART1** @param[in] str которую надо отправить */void usart_snd_str(char *str) {int i = 0;while(str[i] != 0) {usart_snd(str[i++]);}}/*** Включаем LED на PORTC on/off.** @param[in] пин светодиода(0-15) для включения/вылючения* @param[in] режим светодиода (LED_ON | LED_OFF)*/void set_led(int led, int mode) {GPIOC->BSRR = 1<<(led + mode);}/*** Мигаем светодиодом.** @param[in] пин светодиода(0-15)для мигания*/void flash_led(int led) {set_led(led, MODE_ON);delay(15000);set_led(led, MODE_OFF);}int main(void) {board_init();usart_snd_str("\n\rПожалуйста введите что нибудь\n\r");for(;;) {// читаем USARTint rec = usart_rec();// мигнем зеленым светодиодом если принила данныеflash_led(LED_GREEN);if(rec == '\r') {usart_snd_str("\n\r");} else {// шлем байт в скобкахusart_snd('[');usart_snd(rec);usart_snd(']');}// мигаем синим после оправки 3 байтflash_led(LED_BLUE);}}void nmi_handler(void) {return ;}void hardfault_handler(void) {return ;}
и вот что выходит в терминале
Перехожу с avr-8bit на stm32 статья как раз в тему, с подсветкой синтаксиса кода было бы немного более читабельней, удачи в начинаниях!
ВідповістиВидалити