MDK 在 RT-Thread Nano 上添加控制台与 FinSH 问题总结

MDK 在 RT-Thread Nano 上添加控制台与 FinSH 问题总结

近日学习RT-Thread,发现在添加控制台与FinSH时遇到了问题,并没有像示例教程那样打印出信息,通过keil的simulation发现一直死在串口HAL驱动中的。在这里插入图片描述
为什么会出现该现象呢?我经过仔细排查,后发现并解决了该问题。首先,将该问题复现如下:
1.准备一个MDK可以正常运行的LED程序。可以自己用keil搭建,也可以用cubeMx生成。为了快速生成工程,我采用cubeMx生成的。
2.将生成的LED工程用keil打开,然后按照 《基于 Keil MDK 移植 RT-Thread Nano》
添加RT-Thread OS在这里插入图片描述
增加相关代码后,LED闪烁。
我的主函数代码为:

	while (1)
  {
    /* USER CODE END WHILE */
		Mytime++;
		
		if(Mytime==20)
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED1_Pin);
		else if(Mytime==40)		
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED2_Pin);
		else if(Mytime==60)		
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED3_Pin);
		else if(Mytime==80)		
			HAL_GPIO_TogglePin(LED1_GPIO_Port,LED4_Pin);
		
		if(Mytime>90)
		{			
			Mytime=0;		
			rt_kprintf("RT_VERSION\n");
		}
		rt_thread_mdelay(50);
		
		//delay_ms(10);
    /* USER CODE BEGIN 3 */
  }

在protues8.9 中搭建硬件,直接导入程序后验证程序OK
在这里插入图片描述
3.参考《在 RT-Thread Nano 上添加控制台与 FinSH》添加链接描述
在main.c中添加相关代码:

/* USER CODE BEGIN 4 */
void  rt_hw_console_output(const char *str)
{
	rt_size_t i=0,size=0;
	char  a='\r';
	__HAL_UNLOCK(&huart1);
	
	size=rt_strlen(str);
	for(i=0;i<size;i++)
	{
		if(*(str+i)== '\n')
		{
			HAL_UART_Transmit(&huart1,(uint8_t *)&a,1,1);
		}
		HAL_UART_Transmit(&huart1,(uint8_t *)(str+i),1,1);
	}
}

char  rt_hw_console_getchar(void)
{
	int ch=-1;

//	if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_RXNE) !=RESET)
//	{
//		ch=huart1.Instance->DR &0xff;
//	}
//	else
//	{
//		if(__HAL_UART_GET_FLAG(&huart1,UART_FLAG_ORE) !=RESET)
//		{
//			__HAL_UART_CLEAR_OREFLAG(&huart1);
//		}
//		rt_thread_mdelay (10);
//	}

	return  ch;
}
/* USER CODE END 4 */

编译没有问题,然后采用自带simulation 进行仿真,发现程序一直死循环,没有运行到main函数。
在这里插入图片描述
4.首先,为了能编译过去,我自己定义了一个 timeout变量,让其跳出死循环。代码如下:

static HAL_StatusTypeDef UART_WaitOnFlagUntilTimeout(UART_HandleTypeDef *huart, uint32_t Flag, FlagStatus Status, uint32_t Tickstart, uint32_t Timeout)
{
	static uint32_t timeout=0;
  /* Wait until flag is set */
  while (((__HAL_UART_GET_FLAG(huart, Flag) ? SET : RESET) == Status) )
  {
    /* Check for the Timeout */
    if (Timeout != HAL_MAX_DELAY)
    {
      if ((Timeout == 0U) || ((HAL_GetTick() - Tickstart) > Timeout))
      {
        /* Disable TXE, RXNE, PE and ERR (Frame error, noise error, overrun error) interrupts for the interrupt process */
        CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE | USART_CR1_TXEIE));
        CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);

        huart->gState  = HAL_UART_STATE_READY;
        huart->RxState = HAL_UART_STATE_READY;

        /* Process Unlocked */
        __HAL_UNLOCK(huart);

        return HAL_TIMEOUT;
      }
    }
		if((timeout++>20000))
			return HAL_TIMEOUT;
  }
  return HAL_OK;
}在这里插入代码片

编译后通过,运行也OK。
在这里插入图片描述
但是运行久了就不打印了。其实这是有问题,通过单步运行,找到问题点。
原来mdk增加RTT系统后,从stratup.s中启动,先运行的是RTT中的初始化,而非Main 中初始化程序。这样其实会造成一个问题,STM32F4xx的系统时钟和外设都没初始化好,就给RTT使用,必定会造成初始中的函数运行有问题。即使按照官方给的文档,增加INIT_BOARD_EXPORT(MX_USART1_UART_Init); 这样的初始化在rt_hw_board_init()中,也是不可以的。虽然用INIT_BOARD_EXPORT 可以在 下图的第98行调用实现。
在这里插入图片描述
文档中说要在rt_hw_board_init 中调用对应的函数,我在V5.29中 发现不能使用。
在这里插入图片描述
按照上述调用,编译会出错,该函数其实在rt_components_board_init 中会自动执行。
这样,归根到底还是初始化没有按照正确的顺序执行导致的问题。
正确的执行顺序应该是在rt_hw_board_init 中将main函数中的初始函数先调用。
在这里插入图片描述
这个在后面看到的Keil 模拟器 STM32F103 上手指南
这个模板工程中得到验证。

/**
 * This function will initial STM32 board.
 */
void rt_hw_board_init(void)
{
    HAL_Init();
    SystemClock_Config();
#ifdef RT_USING_HEAP
    rt_system_heap_init((void *)HEAP_BEGIN, (void *)HEAP_END);
#endif
#ifdef RT_USING_COMPONENTS_INIT
    rt_components_board_init();
#endif
#ifdef RT_USING_CONSOLE
    rt_console_set_device(RT_CONSOLE_DEVICE_NAME);
#endif
}

还有,SysTick_Handler 函数调用中,必须增加HAL_IncTick()函数调用。

/**
 * This is the timer interrupt service routine.
 *
 */
void SysTick_Handler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();
    HAL_IncTick();
    rt_tick_increase();
    /* leave interrupt */
    rt_interrupt_leave();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章