Реклама ⓘ
Главная » Микроконтроллеры
Призовой фонд
на апрель 2024 г.
1. 100 руб.
От пользователей

Похожие статьи:


Реклама ⓘ

STM32. Урок 3. UART

Рано или поздно у каждого разработчика появляется необходимость подключить свое устройство к компьютеру. Для этого можно использовать LPT, COM или USB порты. Если первый морально устарел и зачастую отсутствует на материнских платах, а последний слишком сложен для начинающего, то COM порт является наиболее подходящим. Он все еще есть на материнских платах, и он относительно прост в использовании. Как и раньше, я не буду очень сильно углубляться в теоретические дебри, которых уйма на просторах интернета, а постараюсь максимально доступно объяснить основы работы на практике.

Постановка задачи:
1) Подключить STM32F4Discovery к компьютеру через COM порт;
2) Реализовать режим echo;
3) Набираемые символы должны сохраняться в текстовую переменную, по нажатию Enter в консоль должна вернуться полная строка;
4) При отправки строки “led” должны загореться 4 светодиода на плате.
Подключение к компьютеру является наиболее сложной частью задачи. У UART есть 2 основных вывода: Rx (Received Data) и Tx (Transmitted Data). Главная проблема – согласование уровней напряжения, так как в порте компьютера оно составляет 12В, а в порте микроконтроллера - 3,3В. Для решения этой проблемы используется микросхема MAX3232. Схема переходника показана на рисунке.

Схема переходника

Диод VD1 – индикатор питания, светодиод в корпусе 0805, VD2 – защита от переполюсовки, можно взять любой маломощный. Микросхема – MAX3232 в корпусе SO16.

К статье прилагается проект платы в Sprint Layout.

2.png

Плата выполнена на одностороннем стеклотекстолите толщиной 2мм. Ответная часть для COM порта берется для монтажа на провод и одевается на текстолит, получается компактно и аккуратно.
Заранее отмечу, что я не изготавливал этот переходник для урока, так как у меня уже есть платка с аналогичной микросхемой, но такие переходники мною делались ранее.
У переходника 4 вывода:
1) Vcc – подключается к 3В питанию на отладочной плате;
2) Rx – подключается к Rx UART2 (PA3) микроконтроллера;
3) Tx – подключается к Tx UART2 (PA2);
4) GND – подключается к «земле» на плате.
Для связи с компьютером используется программа-терминал Putty.

1.jpg

Настройка:
Во вкладке Session выбираем Serial.
В строке Serial line пишем номер порта, к которому вы подключили плату.
В строке Speed пишем 9600 – это скорость работы.
Переходим во вкладку Serial.

2.jpg

Data bits ставим 8.
Stop bits – 1.
Parity и Flow control надо выставить None.
Нажимаем Open и получаем консоль.

3.jpg

Если подключить переходник к COM порту, выводы Vcc и GND подключить к плате, а Tx и Rx соединить, тогда то, что вы будете писать в консоли, будет возвращаться в нее же. Если при нажатии клавиш ничего не происходит и консоль остается чистой – ищите и исправляйте ошибку.

Итак, с подключением вроде справились. Теперь начинаем писать программу.
Первым делом нужно инициализировать UART, для этого создается функция:

//Инициализируем USART2
void usart_init(void)
{
  GPIO_InitTypeDef GPIO_InitStructure; //Структура содержащая настройки порта
  USART_InitTypeDef USART_InitStructure; //Структура содержащая настройки USART

  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //Включаем тактирование порта A
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE); //Включаем тактирование порта USART2

  GPIO_PinAFConfig(GPIOA, GPIO_PinSource3, GPIO_AF_USART2); //Подключаем PA3 к TX USART2
  GPIO_PinAFConfig(GPIOA, GPIO_PinSource2, GPIO_AF_USART2); //Подключаем PA2 к RX USART2

  //Конфигурируем PA2 как альтернативную функцию -> TX UART. Подробнее об конфигурации можно почитать во втором уроке.
  GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  //Конфигурируем PA3 как альтернативную функцию -> RX UART. Подробнее об конфигурации можно почитать во втором уроке.
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_Init(GPIOA, &GPIO_InitStructure);

  USART_StructInit(&USART_InitStructure); //Инициализируем UART с дефолтными настройками: скорость 9600, 8 бит данных, 1 стоп бит

  USART_Init(USART2, &USART_InitStructure);
  USART_Cmd(USART2, ENABLE); //Включаем UART
}

Готово, теперь для инициализации достаточно написать usart_init() в main.
В этой функции UART настраивается по дефолтным значениям. Для более тонкой настройки вместо:

USART_StructInit(&USART_InitStructure);

Пишем:

USART_InitStructure.USART_BaudRate = 9600; //Скорость обмена 9600 бод
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //Длина слова 8 бит
USART_InitStructure.USART_StopBits = USART_StopBits_1; //1 стоп-бит
USART_InitStructure.USART_Parity = USART_Parity_No ; //Без проверки четности
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Включен передатчик и приемник USART2

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

//Функция отправляет байт в UART
void send_to_uart(uint8_t data)
{
 while(!(USART2->SR & USART_SR_TC));
 USART2->DR=data;
}

//Функция отправляет строку в UART, по сути пересылая по байту в send_to_uart
void send_str(char * string)
{
 uint8_t i=0;
 while(string[i]) 
{
  send_to_uart(string[i]);
  i++;
 }
}

Принцип работы прост: send_to_uart отправляет в COM порт байт, а send_str пересылает строку по байту в send_to_uart.

Теперь нужно включить прерывание по приему сообщений от COM порта:

usart_init(); //Инициализируем UART
//Настраиваем прерывания по приему
__enable_irq(); //Глобальное включение прерывания
NVIC_EnableIRQ(USART2_IRQn); //Включаем прерывания от UART
NVIC_SetPriority(USART2_IRQn, 0); //Прерывание от UART, приоритет 0, самый высокий
USART2->CR1 |= USART_CR1_RXNEIE; //Прерывание по приему

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

GPIO_InitTypeDef GPIO_InitStructure; //Структура содержащая настройки порта
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOD, ENABLE); //Включаем тактирование порта D
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12| GPIO_Pin_13| GPIO_Pin_14| GPIO_Pin_15; //Выбераем нужные вывод
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT; //Включаем режим выхода
GPIO_Init(GPIOD, &GPIO_InitStructure); //вызов функции инициализации


И самое главное – функция обработки прерываний UART:

void USART2_IRQHandler (void)
{
   char uart_data;
   if (USART2->SR & USART_SR_RXNE) //Проверяем, прило ли чтонибудь в UART
   {
   USART2->DR = USART2->DR; //Echo по приему, символ отправленный в консоль вернется
   uart_data=USART2->DR; //Считываем то что пришло в переменную...
   uart2_rx_buf[uart2_rx_bit]=USART2->DR; //Помещаем принятый байт в буфер.
   uart2_rx_bit++; //Наращиваем счётчик байтов буфера.

   if(uart_data=='\r') //Если пришло сообщение о нажатии Enter...
   {
   GPIO_ResetBits(GPIOD, GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15); //Сбрасываем все пины в «0»
   if(strcmp(uart2_rx_buf,"led0\r")==0) //Если пришла команда "led0"
   {
   GPIO_SetBits(GPIOD, GPIO_Pin_12); //Подаем «1» на PD12
   }
   else if(strcmp(uart2_rx_buf,"led1\r")==0) //Если пришла команда "led1"
   {
   GPIO_SetBits(GPIOD, GPIO_Pin_13); //Подаем «1» на PD13
   }
   else if(strcmp(uart2_rx_buf,"led2\r")==0) //Если пришла команда "led2"
   {
   GPIO_SetBits(GPIOD, GPIO_Pin_14); //Подаем «1» на PD14
   }
   else if(strcmp(uart2_rx_buf,"led3\r")==0) //Если пришла команда "led3"
   {
   GPIO_SetBits(GPIOD, GPIO_Pin_15); //Подаем «1» на PD15
   }
   else
   {
   send_str("\n"); //Переходим на новую строку
   send_str("String: ");
   send_str(uart2_rx_buf); //Отправляем ее обратно в консоль
   }

   memset(uart2_rx_buf, 0, sizeof(uart2_rx_buf)); //Очищаем буфер
   uart2_rx_bit=0; //Сбрасываем счетчик
   send_str("\n");
   }
   }
}

Вот и все, теперь запускаем консоль, прошиваем плату, подключаем и набираем строку, а затем жмем Enter и наслаждаемся результатом. Команды led0, led1, led2, led3 управляют светодиодами на плате. Как это все работает видно на видео. Исходники и плата прикреплены к статье.

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

Прикрепленные файлы:

Теги:

Опубликована: Изменена: 10.10.2014 0 1
Я собрал 0 3
x

Оценить статью

  • Техническая грамотность
  • Актуальность материала
  • Изложение материала
  • Полезность устройства
  • Повторяемость устройства
  • Орфография
0

Средний балл статьи: 5 Проголосовало: 3 чел.

Комментарии (13) | Я собрал (0) | Подписаться

0
Алексей #
Автор продолжает радовать интересными статьями. Сегодня вечером займусь этим.
Вопрос: имею собственноручный переходник USB-uart на микросхемке ft232rl. Скажите, если я совмещу два переходника, то получу ли я полноценный USB-COM(5вольт на 12вольт)?
И еще кое что, придется ли мне перекрещивать выводы( Rx(ftdi) с tx(max) и наоборот, tx(ftdi)с rx(max)?
Ответить
0

[Автор]
Rough #
Спасибо за хороший отзыв
По Вашему вопросу: особенность FT232 - наличие полного ком порта, то есть есть выводы RI, RTS, CTS и тд. Так вот, если вы хотите получить полноразмерный ком порт, если можно так выразиться, то MAX вам не подойдет, слишком мало выводов. Советую почитать документацию на эту микруху, там схема есть. Ну и вообще рекомендую читать документацию на компоненты, иногда оооочень полезно:) RX и TX перекрещивать не придется.
Ответить
0
Петр #
Я давно хотел научиться микроконтроллерам. AVR не хочу учить, говорят потом фиг с них слезешь. А тут все доходчиво для полного чайника.
Автор, статьи супер, только пожалуйста не упускай мелочей и дальше. Пока вроде получается.
А через встроенный USB подключать нельзя? Я имею ввиду можно ли вшить в память контроллера преобразователь uart-USB? Или это сложно/бесполезно?
Ответить
0
Евгений #
Не получится - надо согласовать электрические параметры посылок к приемлемым для COM-порта. Обязательно должен быть какой-то драйвер
Ответить
0
Петр #
Не затруднит выложить пару фото переходника и всей конструкции? Было бы вообще шикарно
Ответить
0

[Автор]
Rough #
Конкретно такого переходника у меня, к сожалению нету, я его делал для работы в свое время в нескольких экземплярах.
По поводу USB-лично я смысла не вижу, да и геморно это. Лучше возьмите FT232.
Ответить
0
Вадим #
Программатор STM32L-discovery. Не пойму почему не происходит Echo. Передача вроде бы работает нормально

//Шаблон для программ FD
//
//************************INCLUDES*********************************//
#include "stm32l1xx.h"
#include "stm32l_discovery_lcd.h"

//************************DEFINES**********************************//
#define enableInterrupts __enable_irq();
#define disableInterrupts __disable_irq();
//************************FUNCTIONS********************************//
void STM_USART_INIT(void);
void STM_INTERPUT_INIT(void);
void USART3_IRQHandler(void);
void Usart3_Transmit(uint8_t);
void Usart3_Transmit_str(char* str);
//************************END_FUNCTIONS****************************//
char* tmp;
uint32_t i = 0;
//************************MAIN*************************************//

int main()
{
disableInterrupts;
STM_USART_INIT();
enableInterrupts;
//for(i=0; i < 1000000; i++);
Usart3_Transmit_str("START");
while(1)
{
}
}

//************************END_MAIN********************************//

void STM_USART_INIT(void)
{
STM_INTERPUT_INIT(); //инициализация прерываний


RCC->CR |= RCC_CR_HSION; //Включаем тактовый генератор HSI
while(!(RCC_CR_HSIRDY)); //Ждем его стабилизации

RCC->CFGR |= RCC_CFGR_SW_HSI; //Выбираем источником тактовой частоты SYSCLK генератор HSI
RCC->CR &= ~RCC_CR_MSION; //Отключаем генератор MSI.
RCC->AHBENR |= RCC_AHBENR_GPIOCEN; //Включаем тактирование порта C
RCC->APB1ENR |= RCC_APB1ENR_USART3EN; //Включаем тактирование модуля USART1



USART3->CR1 &= ~USART_CR1_M; //Длина слова - 8 бит
USART3->CR2 &= ~USART_CR2_STOP; //1 стоп-бит
USART3->BRR = 0x683; //baud rate 9600 при частоте HSI = 16 МГц
USART3->CR1 |= (USART_CR1_TE | USART_CR1_RE); //Разрешаем передачу данных
USART3->CR1 |= USART_CR1_RXNEIE; //прерывание по приему данных на МК, флаг RXNE
USART3->CR1 |= USART_CR1_UE; //Включаем USART3



//GPIO_INIT
GPIOC->MODER |= GPIO_MODER_MODER10_1; //PC10 - выход AF
GPIOC->OTYPER &= ~GPIO_OTYPER_OT_10; //PC10 - выход push-pull
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR10); //PC10 - без подтяжки
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR10; //PC10 - скорость 40 МГц
GPIOC->AFR[1] |= (0x00000070); //AF7, для USART3_TX

GPIOC->MODER |= GPIO_MODER_MODER11_1;
GPIOC->OTYPER &= ~(GPIO_OTYPER_OT_11);
GPIOC->PUPDR &= ~(GPIO_PUPDR_PUPDR11);
GPIOC->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR11;
GPIOC->AFR[1] |= (0x00000700); //AF7, для USART3_RX

RCC->AHBENR |= RCC_AHBENR_GPIOBEN; //Включаем тактирование порта B
GPIOB->MODER |= GPIO_MODER_MODER6_0;
GPIOB->OTYPER &= GPIO_OTYPER_OT_6;
GPIOB->PUPDR &= ~GPIO_PUPDR_PUPDR6;
GPIOB->OSPEEDR |= GPIO_OSPEEDER_OSPEEDR6;
GPIOB->BSRRL |= GPIO_Pin_6;

GPIOC->MODER |= GPIO_MODER_MODER9_0; // port B pin 6
// light on the blue light

}
//----------------------------------------------------
void STM_INTERPUT_INIT(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);
NVIC_EnableIRQ(USART3_IRQn);
}
//----------------------------------------------------
void USART3_IRQHandler(void)
{

//если причина прерывания прием данных на МК
if(!(USART3->SR & USART_SR_RXNE))
{
USART3->DR = USART3->DR;
//USART3->SR &= ~USART_SR_RXNE; //очистить флаг
}

}
//---------------------------------------------------
//Функци передачи символа через USART
void Usart3_Transmit(uint8_t data)
{
while(!(USART3->SR & USART_SR_TC)); //Ждем установки флага TC - завершения передачи
USART3->DR = data;
}
//---------------------------------------------------
void Usart3_Transmit_str(char* str)
{
uint8_t i=0;
while(str[i])
{
Usart3_Transmit(str[i]);
i++;
}
Usart3_Transmit('\n');
Usart3_Transmit('\r');
}

Ответить
+1
Николай #
Пишу отработку ат-команд для wifi модуля. Модуль подключен к STM32VL Discovery параллельно с пк. Проблема в том, что stm видит только то, что приходит с пк. ПК в свою очередь видит все, включая ответы модуля wifi. Направьте, в какую сторону копать?
Ответить
+1
Иван #
Отличные статьи. Все легко и понятно. А когда выйдут продолжения?
Ответить
0

[Автор]
Rough #
К сожалению, в связи со сменой места работы, свободного времени не осталось. Написать очень хочется, но некогда...
Ответить
0
Сергей #
Можете подсказать как бороться с такой ошибкой. Мастер и слейв с одним бод рейтом работают отлично, а если я кину посылку слейву на другой скорости, он зависает, и надо перегружать устройство. Есть может какой-то метод борьбы с этим?
Ответить
0
Александр #
Вопрос: а как преобразовать введенный символ в числовой тип? Т.е. ввожу "0" как "строку" (30 в hex коде), а в результате хочу вывести "0" как число (0 в hex коде). И как это отследить? В различных терминалах уже сразу конвертируется результат ввода в ASCII/Hex. Про функцию atoi я в курсе.
Ответить
0
panigo #
У меня ругается на русские буквы в названии. Версия 1.7.8. Помогите исправить плиз.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется сила тока?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

AVR-программатор USB ASP
AVR-программатор USB ASP
Ветрогенератор Бокс для хранения компонентов
вверх