UART. Передача данных
Обновлено 12.04.2025Исправим код в файле main.c из предыдущей статьи так, чтобы при переключении светодида по UART ещё отправлялось слово Hello.
Для этого в среде Mik32 IDE на панели Project Explorer скопируем наш проект blinky_timer_irq из предыдущей статьи, и сохраним его под названием uart_tx_timer_irq:

Копирование проекта
Затем откроем файл main.c, и изменим код следующим образом:
1) Включаем файл uart.h, в котором содержатся определения констант для UART:

Добавление заголовочного файла uart.h
2) Добавляем процедуры по инициализации UART и отправке данных:

Добавление процедур по инициализации UART и отправке данных
3) Включаем тактирование UART_1 и GPIO_1:

Включение тактирования UART_1 и GPIO_1
4) Настраиваем вывод P1.9 как UART_TX:

Настройка вывода UART_TX
5) Добавляем инициализацию UART_1 в main():

Вызов инициализации UART_1 из main():
6) Добавляем отправку слова Hello в обработчик прерывания по таймеру. Тогда оно будет отправляться каждую секунду:

Отправка данных в обработчике прерывания
Таким образом, у нас получился такой файл main.c:
#include <mik32_memory_map.h> #include <pad_config.h> #include <gpio.h> #include <power_manager.h> #include <wakeup.h> #include <timer32.h> //определения констант для таймера #include <epic.h> //определения констант для контроллера прерываний #include <scr1_csr_encoding.h> //определения констант регистров ядра #include <csr.h> //определения для операций взаимодействия с регистрами ядра #include <uart.h> //определения констант для UART /* * Данный пример демонстрирует работу с GPIO и PAD_CONFIG. * В примере настраивается вывод, который подключенный к светодиоду, в режим GPIO. * Светодиод переключается в прерывании от таймера. * */ #define PIN_LED 9 // Светодиод управляется выводом PORT_0_9 #define PIN_BUTTON 10 // Кнопка управляет сигналом на выводе PORT_0_10 void initUART(UART_TypeDef *uart, uint32_t uart_divider) { uart->DIVIDER = uart_divider; // divider = 32 000 000 / baud uart->CONTROL1 = UART_CONTROL1_TE_M | UART_CONTROL1_RE_M| UART_CONTROL1_UE_M; //TX, RX, Enable while (!(uart->FLAGS & UART_FLAGS_TEACK_M) && !(uart->FLAGS & UART_FLAGS_REACK_M)); } void writeByte(UART_TypeDef *uart, char byte) { uart->TXDATA = byte; while (!(uart->FLAGS & UART_FLAGS_TC_M)); } void writeLine(UART_TypeDef *uart, char *line) { for (int i = 0; line[i] != '\0'; i++) { writeByte(uart, line[i]); } } void trap_handler() { if (EPIC->STATUS & (1 << EPIC_TIMER32_0_INDEX)) //если прерывание от таймера { GPIO_0->OUTPUT ^= 1 << PIN_LED; // Установка сигнала вывода 9 порта 0 в противоположный уровень writeLine(UART_1, "Hello\n"); TIMER32_0->INT_CLEAR = TIMER32_INT_OVERFLOW_M; //Сброс флага прерывания таймера EPIC->CLEAR = 1 << EPIC_TIMER32_0_INDEX; //Сброс флага прерывания линии таймера } } void EnableInterrupts() { // Разрешение прерываний (установка соответствующих регистров состояния в ядре) set_csr(mstatus, MSTATUS_MIE); set_csr(mie, MIE_MEIE); } void InitClock() { PM->CLK_APB_P_SET |= PM_CLOCK_APB_P_GPIO_0_M // Включение тактирования GPIO_0 | PM_CLOCK_APB_P_GPIO_1_M // Включение тактирования GPIO_1 | PM_CLOCK_APB_P_UART_1_M;// Включение тактирования UART_1 PM->CLK_APB_M_SET |= PM_CLOCK_APB_M_PAD_CONFIG_M // Включение тактирования контроллера выводов | PM_CLOCK_APB_M_PM_M // Включение тактирования блока управления питанием | PM_CLOCK_APB_M_TIMER32_0_M // Включение тактирования таймера32_0 | PM_CLOCK_APB_M_EPIC_M; // Включение тактирования контроллера прерываний } int main() { InitClock(); // Включение тактирования GPIO PAD_CONFIG->PORT_0_CFG &= ~(0b11 << (2 * PIN_LED)); // Установка вывода 9 порта 0 в режим GPIO PAD_CONFIG->PORT_0_CFG &= ~(0b11 << (2 * PIN_BUTTON)); // Установка вывода 10 порта 0 в режим GPIO PAD_CONFIG->PORT_1_CFG &= ~(0b11 << (2 * 9)); PAD_CONFIG->PORT_1_CFG |= 0b01 << (2 * 9); // Установка вывода 9 порта 1 в режим UART1_TX GPIO_0->DIRECTION_OUT = 1 << PIN_LED; // Установка направления вывода 9 порта 0 на выход GPIO_0->DIRECTION_IN = 1 << PIN_BUTTON; // Установка направления вывода 10 порта 0 на вход //Настраиваем максимальное значение счётчика 32*10^6, //что при такрировании 32 МГц будет соответствовать 1 секунде TIMER32_0->TOP = 32000000u; //Включаем прерывание при переполнении счётчика TIMER32_0->INT_MASK = TIMER32_INT_OVERFLOW_M; EPIC->MASK_EDGE_CLEAR = 0xFFFF; //сброс маски прерываний по фронту EPIC->CLEAR = 0xFFFF; //сброс флагов прерываний EPIC->MASK_EDGE_SET = 1 << EPIC_TIMER32_0_INDEX;//установка маски прерываний по фронту от таймера32_0 EnableInterrupts(); TIMER32_0->ENABLE = TIMER32_ENABLE_TIM_EN_M; //включаем таймер initUART(UART_1, 278); // 115200 baud while (1) { } }
Теперь собираем проект, и загружаем прошивку в отладочную плату. Светодиод, как и раньше, должен начать мигать раз в секунду. Но теперь, чтобы увидеть, как данные передаются по UART, нужно установить на компьютере драйвер для установленного на отладочной плате преобразователя UART<->USB CH340 с сайта производителя микросхемы. Теперь в диспетчере устройств при подключении отладочной платы будет появляться COM-порт. У меня это COM10, у вас может быть другой номер.
В Mik32 IDE откроем терминал:

Открытие терминала
В открывшемся окне terminal подключаем COM-порт:

Подключение COM-порта
Вводим данные COM-порта и нажимаем ОК:

Ввод данных COM-порта
И видим принимаемые с отладочной платы данные:

Данные с отладочной платы