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

Реклама ⓘ

Управление текстовыми командами (USART на STM32)

В процессе изучения микроконтроллеров STM32 многие могут заметить (а многие по этой причине и выбрать эти микроконтроллеры), что в отличие от привычных для нас AVR, PIC они имеют по несколько модулей USART, I2C, SPI. Так микроконтроллер STM32F103C8T6 имеет два модуля SPI, два модуля I2C и три модуля USART. И если, например, к интерфейсу I2C можно подключить без проблем несколько устройств одновременно, то иметь больше одного модуля USART иногда очень полезно, а в нашем примере их даже три (Medium-density device), а вообще может быть и пять, если взять другой более крупный микроконтроллер STM32 (High-density device).

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

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

Если же Вы собираете схему на собственной плате, обязательно должны присутствовать конденсаторы по питанию. Резистор R5 подтягивает вывод BOOT0 к земле, что обеспечивает выполнение программы из flash памяти, при этом уровень на выводе PB2 (BOOT1) не учитывается и может быть как нулем, так и единицей (при комбинации нулей и единиц на BOOT0 и BOOT1 обеспечивается выполнение программы из разных областей памяти при включении питания – flash, SRAM, ISP). Кнопка S1 необходима лишь для удобства – после прошивки микроконтроллера его необходимо перезапустить, что и делается при нажатии на эту кнопку. Для обеспечения заданного режима по питанию используется стабилизатор напряжения AMS1117-3,3. LCD дисплей используется на базе микроконтроллера HD44780, в моем варианте это 2004а – четыре строки по двадцать символов. В данной ситуации микроконтроллер STM32 питается от напряжения 3,3 вольта, а LCD дисплей от напряжения 5 вольт и при этом взаимодействуют друг с другом. Дело в том, что большинство выводов микроконтроллера толерантные к уровням напряжения 5 вольт. Подключение LCD  дисплея к микроконтроллеру осуществляется по стандартной 4-х битной схеме. Резистор R1 ограничивает ток подсветки дисплея, подстроечный резистор R2 задает контраст символов на экране. Светодиод в данном случае является исполнительным элементом, резистор R6 ограничивает ток, протекающий через светодиод, чтобы он не вышел из строя. Вариант подключения светодиода взят в соответствии с подключением на отладочной плате, которую я буду использовать. Логическая единица будет выключать светодиод, а логический ноль будет включать светодиод.

Дополнительно к схеме нам понадобится программатор (ST-link v2) и преобразователь USB-UART.

Собранная схема на минимальной отладочной плате:

Начнем с использования одного модуля USART (USART1). Модуль USART1 подключается к выводам PA9 (TxD) и PA10 (RxD) (CK, CTS, RTS не трогаем, нет необходимости). Кроме этого модуль USART1 можно переназначить на другие выводы – PB6 (TxD) и PB7 (RxD) с помощью ремапа – для этого необходимо обозначит альтернативные функции для этих выводов. Могут случаться ситуации, когда это может облегчить трассировку печатной платы.

Итак, чтобы запустить модуль USART1 (или любой другой аналогично), необходимо провести инициализацию с заданными настройками, для этого нам необходимо настроить выводы микроконтроллера для модуля USART1 и сам модуль USART1.

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

На рисунке выше изображена схема тактирования для микроконтроллеров STM32F103. Как видно, все переффирийные устройства тактируются от нескольких шин, поэтому при выборе модуля USART нужно всегда помнить, что разные модули находятся на разных шинах, в противном случае устройство не будет работать. Далее просто задаем настройки модуля USART с учетом источника тактирвоания.

void init_usart() {
	
	GPIO_InitTypeDef PORT;  //Структура содержащая настройки порта
  USART_InitTypeDef USART;  //Структура содержащая настройки USART
	
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //Включаем тактирование порта USART1
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //Включаем тактирование порта A
	
	//Пины PA9 и PA10 в режиме альтернативных функций – Rx и Tx USART’а
	GPIO_StructInit(&PORT); 
	// задаем параметры выводов 
	PORT.GPIO_Pin = GPIO_Pin_9;
	PORT.GPIO_Mode = GPIO_Mode_AF_PP;
	PORT.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA , &PORT);
	
	PORT.GPIO_Pin = GPIO_Pin_10;
	PORT.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	PORT.GPIO_Speed = GPIO_Speed_2MHz;
	GPIO_Init(GPIOA , &PORT);
	
	//Настройка USART
	USART_StructInit(&USART);  
	USART.USART_BaudRate = 9600;   //Скорость обмена 9600 бод
	USART.USART_WordLength = USART_WordLength_8b; //Длина слова 8 бит
	USART.USART_StopBits = USART_StopBits_1; //1 стоп-бит
	USART.USART_Parity = USART_Parity_No ; //Без проверки четности
	USART.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //Без аппаратного контроля
	USART.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //Включен передатчик и приемник USART2
	USART_Init(USART1, &USART);
	
	USART_Cmd(USART1, ENABLE);  //Включаем UART
	
}

Функции отправки данных достаточно простые

void send(char chr) {
    while(!(USART1->SR & USART_SR_TC));
    USART1->DR = chr;
}

void send_str(char* str) {
    int i=0;
    while(str[i])
        send(str[i++]);
}

Теперь вся суть заключается в приеме и обработке полученной информации. Мы принимаем некоторое количество символов, которые образуют понятное для нас слово (компьютеру все равно что понимать, если это прописано в коде), далее строка обрабатывается и сравнивается со строкой привязанной к той или иной команде, заложенной в микроконтроллере. Строки могут быть разной длины, поэтому так же необходимо определять, что это конец. Один из способов в конце строки ставить какой-то заключительный символ, например, как в этом материале символ слэш, имеющий код 47 по таблице ASCII. Таким образом, можно формировать строки-команды различной длины, понятные любому человеку - написал "зажги, пожалуйста, светодиод" и светодиод горит. Либо формировать пароль при включении устройства, либо еще много различных способов применения. Данные принимаются в прерывании.

// обработчик прерывания юарт1
void USART1_IRQHandler()
{
    //Проверяем, действительно ли прерывание вызвано приемом нового байта
    if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET)
    {	
			//USART1->DR = USART1->DR; //эхо
			usartData = USART_ReceiveData(USART1);	
			
			// послений символ строки должен быть заведомо известный, чтобы корректо обрабатывать данные (энтер или другой символ)
			if (usartData == 47) // если принимаем последний символ строки или команды, то совершаем действие
			{
				// при этом последний принятый байт не заносится в строку
				usart_buf[usart_bit++] = 0;  // делаем нуль-терминированную строку
				usart_bit=0;                 // обнуляем счетчик символов строки
				//-----------------------------------
				send_str("String: "); send_str(usart_buf); send(13); // отзыв обратно в терминал и символ энтера
				
				// здесь задумка такая, чтобы выводить в 4 строчки экрана команды или сообщения
				// последнее сообщение всегда на 4й строке, при появлении нового все принятые строки поднимаются вверх
				// таким образом, наблюдаем текущую строчку и 3 предыдущих
				for(t=0;t<32;t++) {buf1[t]=buf2[t];} // при приеме новой строки передвинуть вверх предыдущие и вывести все далее на экран lcd
				for(t=0;t<32;t++) {buf2[t]=buf3[t];}
				for(t=0;t<32;t++) {buf3[t]=buf4[t];}
				for(t=0;t<32;t++) {buf4[t]=usart_buf[t];}
				lcd_clear(); 
				lcd_set_xy(0,0);
				lcd_out("> ");
				lcd_out(buf1);				
				lcd_set_xy(0,1);
				lcd_out("> ");
				lcd_out(buf2);
				lcd_set_xy(0,2);
				lcd_out("> ");
				lcd_out(buf3);
				lcd_set_xy(0,3);// выводим на экран принятую строку
				lcd_out("> ");
				lcd_out(buf4);
				
				com_exe(usart_buf); // проверка на наличие команды и ее выполнение
				//-----------------------------------
				usartData=0;  // очищаем последний принятый байт
				memset(usart_buf, 0, sizeof(usart_buf)); /*Очищаем буфер*/
			}
			else 
			{
				// если строка или команда все еще не принята
				// Складываем символ в приёмный буфер
				usart_buf[usart_bit++] = usartData; //Помещаем принятый байт в буфер.
				//usart_bit++; //Наращиваем счётчик байтов буфера.
			}	
	 
	 
    }
}

В данном случае LCD дисплей используется для визуализации принятой информации, некоторое подобие терминала.

В прерывании присутствует функция com_exe, в которой и прописана обработка и выполнение команд, которые закладываются в микроконтроллере. В данном случае это простые команды управления светодиодом.

// функция обработчик команд, поступаемых по уарт, сравнивает строки буфера и выполняет действие
void com_exe (char *cmd)
{
	if(strcmp(usart_buf,"led_on")==0) //Если пришла команда 
   {GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_RESET);}
	if(strcmp(usart_buf,"led_off")==0) //Если пришла команда 
   {GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET);}
	if(strcmp(usart_buf,"blink")==0) //Если пришла команда 
   {for(t=0;t<10;t++) {GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_RESET); delay(250); GPIO_WriteBit(GPIOA,GPIO_Pin_1,Bit_SET); delay(250);}}	
	if(strcmp(usart_buf,"clear")==0) //Если пришла команда 
   {lcd_clear();
	  memset(buf1, 0, sizeof(buf1));
	  memset(buf2, 0, sizeof(buf2));
	  memset(buf3, 0, sizeof(buf3));
	  memset(buf4, 0, sizeof(buf4));
	  lcd_set_xy(0,0);
		lcd_out("> ");
		lcd_set_xy(0,1);
		lcd_out("> ");
		lcd_set_xy(0,2);
		lcd_out("> ");
		lcd_set_xy(0,3);
		lcd_out("> ");}
				
	 
}

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

К статье прилагается исходный код и небольшое видео работы представленного алгоритма.

Список радиоэлементов

Обозначение Тип Номинал Количество ПримечаниеМагазинМой блокнот
IC1 МК STM32
STM32F103C8
1 Поиск в магазине ОтронВ блокнот
VR1 Линейный регулятор
AMS1117-3.3
1 Поиск в магазине ОтронВ блокнот
HG1 LCD-дисплей2004a1 Поиск в магазине ОтронВ блокнот
R1 Резистор
22 Ом
1 Поиск в магазине ОтронВ блокнот
R2 Переменный резистор10 кОм1 Поиск в магазине ОтронВ блокнот
R3, R5, R6 Резистор
10 кОм
3 Поиск в магазине ОтронВ блокнот
R4 Резистор
100 Ом
1 Поиск в магазине ОтронВ блокнот
R7 Резистор
390 Ом
1 Поиск в магазине ОтронВ блокнот
C1, C3, C7-C10 Конденсатор100 нФ6 Поиск в магазине ОтронВ блокнот
C2 Электролитический конденсатор220 мкФ1 Поиск в магазине ОтронВ блокнот
C4 Электролитический конденсатор10 мкФ1 Поиск в магазине ОтронВ блокнот
C5, C6 Конденсатор22 пФ2 Поиск в магазине ОтронВ блокнот
Z1 Кварцевый резонатор8 МГц1 Поиск в магазине ОтронВ блокнот
S1 Тактовая кнопка1 Поиск в магазине ОтронВ блокнот
HL1 СветодиодЗеленый1 Поиск в магазине ОтронВ блокнот
Добавить все

Скачать список элементов (PDF)

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

Теги:

Опубликована: 0 1
Я собрал 0 0
x

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

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

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

Интернет-магазин Мир Электрики. Купить кабель в Минске с доставкой.

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

0
Публикатор #
На форуме автоматически создана тема для обсуждения статьи.
Ответить
0
mr_smit #
Внутри прерывания функция отправки в USART (с циклом while внутри) - это плохо. Так делать нельзя. По прерыванию надо всё складывать в буфер, а обработку производить уже в основной программе.
Ответить
Добавить комментарий
Имя:
E-mail:
не публикуется
Текст:
Защита от спама:
В чем измеряется напряжение?
Файлы:
 
Для выбора нескольких файлов использйте CTRL

Программатор Pickit3
Программатор Pickit3
Конструктор регулируемого преобразователя напряжения LM317 Бокс для хранения компонентов
вверх