RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植

RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植

前言

stm32CubeMx在stm32开发上提供了很大的便利性,我们可以用它来配置一些外设,系统时钟。RTT是一款很棒的RTOS,但是Device框架对我这些初学者来说还是有一定的难度,有时我们只需使用RTOS的核心功能就行,而RTT可以很方便地包含进自己的工程中来。下面是移植过程的一些笔记。本文大部分内容都能在RTT官网文档中找到,但是有些细节的部分可能文档中没提到,下面结合CubeMx的LL库移植RTT和Finsh。
感觉CubeMx的LL库和stm32的标准库比较相似,LL库比HAL库底层,代码简洁,但是也会有些问题,比如在串口发送数据的时候不能直接使用库提供发送函数,而需要我们额外写,比如添加发送完成标志检测等,要不然由于发送数据操作太快导致串口发送会出错。
本文假设已经安装了CubeMx和MDK,并且相关pack也已经安装好了。

CubeMx配置

CubeMx我用的是旧版,讲真CubeMx界面是越更新越丑,也有一些难以忍受的bug,用起来也不方便。所以还是旧版的好使。
我用的板子是STM32F411CEU6的最小系统板。系统主频最大100Mhz。
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第1张图片
配置系统时钟外部时钟25Mhz:
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第2张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第3张图片
配置串口,打开接收中断(记得勾选全局中断)。
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第4张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第5张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第6张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第7张图片
直接生成MDK5工程即可。
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第8张图片

将RTTHREAD NANO加进工程中

RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第9张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第10张图片
中断与异常处理
RT-Thread 会接管异常处理函数 HardFault_Handler() 和 PendSV_Handler(),这两个函数由 RT-Thread 实现,所以需要删除工程里中断服务例程文件 stm32f4xx_it.c中的这两个函数还有就是删除要用到的串口中断函数,避免在编译时产生重复定义错误。如果此时对工程进行编译,没有出现函数重复定义的错误,则不用做修改。
接下来就是系统时钟,rtt用stm32的嘀嗒时钟为其提供时基。所以我们还要改嘀嗒时钟配置和中端函数,在中断文件中我们也删除void SysTick_Handler(void)函数,然后在RTT的board文件中改,另外我们将main中时钟配置函数也复制过去:
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第11张图片
然后在usart.c中实现Finsh输出,输入函数。这里重写串口数据发送函数否则数据发送会出错。主要是添加标志位检测,防止发送数据过快。

void uart_send(uint8_t c)
{
	  uint32_t t=0;
      LL_USART_TransmitData8(USART1,c);
	 while(LL_USART_IsActiveFlag_TC(USART1) == (uint16_t)RESET)
	 {
	   t++;
	   if(t>0xffff)return;
	 }
	
}
void rt_hw_console_output(const char *str)
{
    rt_size_t i = 0, size = 0;
    char a = '\r';
	  size = rt_strlen(str);
	  for (i = 0; i < size; i++)
    {
        if (*(str + i) == '\n')
        {
					 uart_send((uint8_t)a);
        }
				uart_send((uint8_t )(*(str + i)));
    }
}

//数据接收采用中断+ ringbuffer 缓冲的方式,具体代码和官网文档一样
//使用的时候要先初始化:
 
 rt_ringbuffer_init(&uart_rxcb, uart_rx_buf, UART_RX_BUF_LEN);
   
  rt_sem_init(&(shell_rx_sem), "shell_rx", 0, 0);

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; 
	
	
}

/* uart 中断 */
void USART1_IRQHandler(void)
{
    int ch = -1;
//    rt_base_t level;
    /* enter interrupt */
    rt_interrupt_enter();          //在中断中一定要调用这对函数,进入中断
    if(LL_USART_IsActiveFlag_RXNE(USART1) && LL_USART_IsEnabledIT_RXNE(USART1))
  {
       while (1)
        {
            ch = -1;
            if (LL_USART_IsActiveFlag_RXNE(USART1)  != RESET)
            {
                ch =  LL_USART_ReceiveData8(USART1);
            }
            if (ch == -1)
            {
                break;
            }  
            /* 读取到数据,将数据存入 ringbuffer */
            rt_ringbuffer_putchar(&uart_rxcb, ch);
        }        
        rt_sem_release(&shell_rx_sem);
  }
  /* USER CODE END USART1_IRQn 1 */  

    /* leave interrupt */
    rt_interrupt_leave();    //在中断中一定要调用这对函数,离开中断
}

然后我们使用RTT的初始化机制:
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第12张图片
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第13张图片
main函数中延时函数改rtt的延时函数rt_thread_mdelay();这个函数会让当前线程让出CPU控制权。
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第14张图片
这里基本就完成RTT+Finsh移植了
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第15张图片
然后编译下载:发现能出RTT的LOGO
,但不能输入:
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第16张图片
后来发现串口中断那里还要加语句打开串口中断(主要是CubeMx那里配置时忘记打开串口接收中断):
LL_USART_EnableIT_RXNE(USART1); //接收中断
//LL_USART_EnableIT_PE(USART1);//串口总中断
重新编译下载:
RT-Thread nano+Finsh+STM32CubeMx+LL库在MDK527中移植_第17张图片
可以看到能输出也能接收命令输入了。

总结

LL库比较接近寄存器操作的了。
最后工程代码我已经上传到这里了。可以到我的资源那找。

你可能感兴趣的:(STM32学习)