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();
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章