printf в микроконтроллере STM32 и других.
Эта короткая заметка будет небольшим мануалом по налаживанию работы таких привычных си программистам функций, как printf, scanf и их модификаций.
Не думаю, сто стоит рассказывать о функциях printf
и scanf
. Раз читаете эту заметку, то в курсе зачем они, знаете плюсы, и возможно минусы. Обсуждение и того и другого можно расписать на целую статью, я лишь хочу показать как их завести в прошивке для микроконтроллера.
Объектом испытания будет выступать микроконтроллер фирмы STMicroelectronics
STM32F205RGT6
. Почему не ванильный f103
? Всё просто, отладку с ним переделал под 205
чип, да и разрабатываемое устройство базируется на 205
чипе. Хотя это на самом деле и не важно, реализация полностью кросплатформенная.
Ну что поехали.
Первое что нужно для использования функций это подключить заголовочный файл директивой
#include <stdio.h>
Теперь необходимо реализовать две функции:
/**
* @brief Retargets the C library printf function to the USART or USBD.
*/
int fputc(int ch, FILE *f) //-V2537
{
char item = (char)ch;
#ifdef USE_FREERTOS
xQueueSendToBack(stdout_queue, &item, 0);
#else
(void)HAL_UART_Transmit(&huart1, (uint8_t *)&item, 1, 1000);
#endif
return ch;
}
/**
* @brief Retargets the C library scanf function to the USART or USBD.
*/
int fgetc(FILE *f)
{
uint8_t ch;
#ifdef USE_FREERTOS
return (xQueueReceive(stdin_queue, &ch, portMAX_DELAY) == pdPASS) ? (int)ch : (int)'\0';
#else
(void)HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, 1000);
return((int)ch);
#endif
}
Готово.
Поясню код. В проекте использую FreeRTOS
, и работы с принимаемыми и передаваемыми данными веду через очереди, которые обрабатываю в соответствующих задачах.
Задача передачи выглядит следующим образом:
void StdoutTask(void *pvParameters)
{
for(;;)
{
STDOUT_Flush();
}
__ASM volatile("BKPT #01");
vTaskDelete( NULL );
}
void STDOUT_Flush(void)
{
static uint8_t buf[ STDOUT_QUEUE_SIZE ];
uint16_t length = 0;
if (xQueueReceive(stdout_queue, &buf[length], portMAX_DELAY) == pdPASS)
{
while((++length < STDOUT_QUEUE_SIZE) && (xQueueReceive(stdout_queue, &buf[length], 0) == pdPASS)) {};
(void)HAL_UART_Transmit_IT(&huart1, buf, length);
while (HAL_UART_GetState(&huart1) != HAL_UART_STATE_READY && HAL_UART_GetState(&huart1) != HAL_UART_STATE_BUSY_RX)
{
vTaskDelay( TIME_MSEC );
}
}
}
Подробно объяснять думаю нет необходимости, в цикле задачи выполняется функция, которая блокирует задачу до момента появления данных в очереди, затем считывает и посылает через USART1
.
Задачу для получения приводить не буду, тянет на отдельную статью - реализует CLI
(интерфейс командной строки), по сути громадный парсер команд, которые может выполнять железяка.
Кстати у FreeRTOS
есть готовая библиотека для реализации командной строки. Возможно скоро о ней напишу Вот заметка о ней.
Надеюсь пригодится данная заметка. Хорошего кодинга 😉