这里timeBase不变,选择默认systick。
时钟配置如下:
RCC外部高低速时钟disable。
GPIO参照官方nucleo板子,指定一个led脚和一个key脚。配置分别为output和input。
RTT无论是打印日志还是输入cmd,都需要uart支持。uart设置如下(波特率等参数默认就可以,115200N81,无流控):
要获取 RT-Thread Nano 软件包,需要在 CubeMX 中添加 https://www.rt-thread.org/download/cube/RealThread.RT-Thread.pdsc 。
具体步骤:进入打开 CubeMX,从菜单栏 help 进入 Manage embedded software packages 界面,点击 From Url 按钮,进入 User Defined Packs Manager 界面,其次点击 new,填入上述网址,然后点击 check,如下图所示:
check 通过后,点击 OK 回到 User Defined Packs Manager 界面,再次点击 OK,CubeMX 自动连接服务器,获取包描述文件。回到 Manage embedded software packages 界面,就会发现 RT-Thread Nano 3.1.3 软件包,选择该软件包,点击 Install Now,如下图所示:
安装过程中会有同意授权选项,选accept即可。正确安装后结果如下图:
点击 Additional Softwares,进入 Additional Software Components selection 界面,在 Pack Vendor 中选择 RealThread, 然后根据需求选择 RT-Thread 组件(此处只移植 Nano选择 kernel 和shell),然后点击 OK 按钮,如下图所示:
返回软件界面 Pinout & Configuration 中,进入所选组件参数配置区,按照下图进行配置
作为学习使用的话,建议打开大部分功能,这样避免后期再做修改。
选择,GENERATE CODE ,生成代码。在keil mdk中打开工程。
增加头文件
#include "usart.h"
/**
* This function will initial your board.
*/
extern void SystemClock_Config(void);
extern HAL_StatusTypeDef HAL_Init(void);
void rt_hw_board_init()
{
/* System Clock Update */
//为了和main起初生成的代码一致,这里需要使用main.c中调用的两个函数
HAL_Init();
SystemClock_Config();
//SystemCoreClockUpdate();
MX_USART2_UART_Init();
/* System Tick Configuration */
_SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
/* Call components board initial (use INIT_BOARD_EXPORT()) */
#ifdef RT_USING_COMPONENTS_INIT
rt_components_board_init();
#endif
#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
rt_system_heap_init(rt_heap_begin_get(), rt_heap_end_get());
#endif
}
增加头文件的引用
#include "rtthread.h"
#include
增加两个函数的声明
char rt_hw_console_getchar(void);
void rt_hw_console_output(const char *str);
增加uart.h中新增两个函数的实现
/* USER CODE BEGIN 1 */
char rt_hw_console_getchar(void)
{
int ch = -1;
if (__HAL_UART_GET_FLAG(&huart2, UART_FLAG_RXNE) != RESET)
{
ch = huart2.Instance->RDR & 0xff;
}
else
{
if(__HAL_UART_GET_FLAG(&huart2, UART_FLAG_ORE) != RESET)
{
__HAL_UART_CLEAR_OREFLAG(&huart2);
}
rt_thread_mdelay(10);
}
return ch;
}
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\r';
__HAL_UNLOCK(&huart2);
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\n')
{
HAL_UART_Transmit(&huart2, (uint8_t *)&a, 1, 1);
}
HAL_UART_Transmit(&huart2, (uint8_t *)(str + i), 1, 1);
}
}
/* USER CODE END 1 */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "rtthread.h" //添加头文件的引用
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
//HAL_Init(); //去掉
/* Configure the system clock */
// SystemClock_Config();//去掉
/* Initialize all configured peripherals */
MX_GPIO_Init();
/* USER CODE BEGIN 2 */
rt_kprintf("hello rt-thread.\r\n");
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
rt_thread_mdelay(1000);
HAL_GPIO_TogglePin(LED_GPIO_Port,LED_Pin);
//rt_kprintf("hello rt-thread.\n");
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
至此,真个移植过程结束。
在步骤二 查询方式上,修改uart.c文件为如下内容:
中断方式下,需要做的工作相对较多,需要实现一个环形缓冲区,uart中断配置、uart中断服务函数实现以及中断回调实现。
/* Includes ------------------------------------------------------------------*/
#include "usart.h"
/* USER CODE BEGIN 0 */
#define rt_ringbuffer_space_len(rb) ((rb)->buffer_size - rt_ringbuffer_data_len(rb))
struct rt_ringbuffer
{
rt_uint8_t *buffer_ptr;
rt_uint16_t read_mirror : 1;
rt_uint16_t read_index : 15;
rt_uint16_t write_mirror : 1;
rt_uint16_t write_index : 15;
rt_int16_t buffer_size;
};
enum rt_ringbuffer_state
{
RT_RINGBUFFER_EMPTY,
RT_RINGBUFFER_FULL,
/* half full is neither full nor empty */
RT_RINGBUFFER_HALFFULL,
};
rt_inline enum rt_ringbuffer_state rt_ringbuffer_status(struct rt_ringbuffer *rb)
{
if (rb->read_index == rb->write_index)
{
if (rb->read_mirror == rb->write_mirror)
return RT_RINGBUFFER_EMPTY;
else
return RT_RINGBUFFER_FULL;
}
return RT_RINGBUFFER_HALFFULL;
}
/**
* get the size of data in rb
*/
rt_size_t rt_ringbuffer_data_len(struct rt_ringbuffer *rb)
{
switch (rt_ringbuffer_status(rb))
{
case RT_RINGBUFFER_EMPTY:
return 0;
case RT_RINGBUFFER_FULL:
return rb->buffer_size;
case RT_RINGBUFFER_HALFFULL:
default:
if (rb->write_index > rb->read_index)
return rb->write_index - rb->read_index;
else
return rb->buffer_size - (rb->read_index - rb->write_index);
};
}
void rt_ringbuffer_init(struct rt_ringbuffer *rb,
rt_uint8_t *pool,
rt_int16_t size)
{
RT_ASSERT(rb != RT_NULL);
RT_ASSERT(size > 0);
/* initialize read and write index */
rb->read_mirror = rb->read_index = 0;
rb->write_mirror = rb->write_index = 0;
/* set buffer pool and size */
rb->buffer_ptr = pool;
rb->buffer_size = RT_ALIGN_DOWN(size, RT_ALIGN_SIZE);
}
/**
* put a character into ring buffer
*/
rt_size_t rt_ringbuffer_putchar(struct rt_ringbuffer *rb, const rt_uint8_t ch)
{
RT_ASSERT(rb != RT_NULL);
/* whether has enough space */
if (!rt_ringbuffer_space_len(rb))
return 0;
rb->buffer_ptr[rb->write_index] = ch;
/* flip mirror */
if (rb->write_index == rb->buffer_size-1)
{
rb->write_mirror = ~rb->write_mirror;
rb->write_index = 0;
}
else
{
rb->write_index++;
}
return 1;
}
/**
* get a character from a ringbuffer
*/
rt_size_t rt_ringbuffer_getchar(struct rt_ringbuffer *rb, rt_uint8_t *ch)
{
RT_ASSERT(rb != RT_NULL);
/* ringbuffer is empty */
if (!rt_ringbuffer_data_len(rb))
return 0;
/* put character */
*ch = rb->buffer_ptr[rb->read_index];
if (rb->read_index == rb->buffer_size-1)
{
rb->read_mirror = ~rb->read_mirror;
rb->read_index = 0;
}
else
{
rb->read_index++;
}
return 1;
}
/* USER CODE END 0 */
/* 第二部分:finsh 移植对接部分 */
#define UART_RX_BUF_LEN 16
rt_uint8_t uart_rx_buf[UART_RX_BUF_LEN] = {0};
struct rt_ringbuffer uart_rxcb; /* 定义一个 ringbuffer cb */
static UART_HandleTypeDef huart2;
static struct rt_semaphore shell_rx_sem; /* 定义一个静态信号量 */
/* USART2 init function */
void MX_USART2_UART_Init(void)
{
/* 初始化串口接收 ringbuffer */
rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN);
/* 初始化串口接收数据的信号量 */
rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0);
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
huart2.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
huart2.Init.ClockPrescaler = UART_PRESCALER_DIV1;
huart2.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetTxFifoThreshold(&huart2, UART_TXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_SetRxFifoThreshold(&huart2, UART_RXFIFO_THRESHOLD_1_8) != HAL_OK)
{
Error_Handler();
}
if (HAL_UARTEx_DisableFifoMode(&huart2) != HAL_OK)
{
Error_Handler();
}
/* 中断配置 */
__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
HAL_NVIC_EnableIRQ(USART2_IRQn);
HAL_NVIC_SetPriority(USART2_IRQn, 3, 3);
}
/*** 使用下边的命令可以直接把函数添加到板级初始化中 ***/
//INIT_BOARD_EXPORT(MX_USART2_UART_Init);
void HAL_UART_MspInit(UART_HandleTypeDef* huart2)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if(huart2->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspInit 0 */
/* USER CODE END USART2_MspInit 0 */
/* USART2 clock enable */
__HAL_RCC_USART2_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
GPIO_InitStruct.Pin = GPIO_PIN_2|GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
GPIO_InitStruct.Alternate = GPIO_AF1_USART2;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* USER CODE BEGIN USART2_MspInit 1 */
/* USER CODE END USART2_MspInit 1 */
}
}
void HAL_UART_MspDeInit(UART_HandleTypeDef* huart2)
{
if(huart2->Instance==USART2)
{
/* USER CODE BEGIN USART2_MspDeInit 0 */
/* USER CODE END USART2_MspDeInit 0 */
/* Peripheral clock disable */
__HAL_RCC_USART2_CLK_DISABLE();
/**USART2 GPIO Configuration
PA2 ------> USART2_TX
PA3 ------> USART2_RX
*/
HAL_GPIO_DeInit(GPIOA, GPIO_PIN_2|GPIO_PIN_3);
/* USER CODE BEGIN USART2_MspDeInit 1 */
/* USER CODE END USART2_MspDeInit 1 */
}
}
/* USER CODE BEGIN 1 */
void rt_hw_console_output(const char *str)
{
rt_size_t i = 0, size = 0;
char a = '\r';
__HAL_UNLOCK(&huart2);
size = rt_strlen(str);
for (i = 0; i < size; i++)
{
if (*(str + i) == '\n')
{
HAL_UART_Transmit(&huart2, (uint8_t *)&a, 1, 1);
}
HAL_UART_Transmit(&huart2, (uint8_t *)(str + i), 1, 1);
}
}
char rt_hw_console_getchar(void)
{
char ch = 0;
/* 从 ringbuffer 中拿出数据 */
while (rt_ringbuffer_getchar(&uart_rxcb, (rt_uint8_t *)&ch) != 1)
{
rt_sem_take(&shell_rx_sem, RT_WAITING_FOREVER);
}
return ch;
}
void USART2_IRQHandler(void)
{
int ch = -1;
rt_base_t level;
/* enter interrupt */
rt_interrupt_enter(); //在中断中一定要调用这对函数,进入中断
if ((__HAL_UART_GET_FLAG(&(huart2), UART_FLAG_RXNE) != RESET) &&
(__HAL_UART_GET_IT_SOURCE(&(huart2), UART_IT_RXNE) != RESET))
{
while (1)
{
ch = -1;
if (__HAL_UART_GET_FLAG(&(huart2), UART_FLAG_RXNE) != RESET)
{
ch = huart2.Instance->RDR & 0xff;
}
if (ch == -1)
{
break;
}
/* 读取到数据,将数据存入 ringbuffer */
rt_ringbuffer_putchar(&uart_rxcb, ch);
}
rt_sem_release(&shell_rx_sem);
}
/* leave interrupt */
rt_interrupt_leave(); //在中断中一定要调用这对函数,离开中断
}
/* USER CODE END 1 */
/************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
两种方式下,最后运行结果是一样的
参考链接:
基于 CubeMX 移植 RT-Thread Nano
在 RT-Thread Nano 上添加控制台与 FinSH