RT-Thread: 移植RT-Thread,基于 STM32CubeMX 生成的 KEIL 工程

24 篇文章 2 订阅
8 篇文章 0 订阅

目录

关键词:RT-Thread 移植,基于 STM32CubeMX 生成的 KEIL 工程,JLINK-RTT 移植

1).使用 STM32CubeMX 生成芯片对应的裸机工程

2).KEIL 打开工程,配置工程,打开 Use MicroLIB库

3).添加 RT-Thread

4).修改 RTOS 的配置文件 rtconfig.h 

5).修改 RTOS 的 board.c 文件

6).添加JLINK 的RTT 打印功能

7).board.c 完整参考文件

8).编译、排错错误、测试

9).JLINK RTT 软件设置及应用


1).使用 STM32CubeMX 生成芯片对应的裸机工程

使用 STM32CubeMX  根据所需芯片创建工程

 注意:选择 Debug 为 Serial Wire 不然可能下载一次程序后就不能再下载了。

 时钟设置

 工程输出设置

 生成工程 打开工程对应文件夹

 

打开工程对应文件夹

2).KEIL 打开工程,配置工程,打开 Use MicroLIB库

打开  Use MicroLIB 库,使用 printf 等库函数需要如下勾选上。

配置调试接口

 

 配置完成,编译一下检查是否有错,为下一步添加系统提前排除错误。 

3).添加 RT-Thread

 添加 RTOS

添加好后,RTOS出现在项目目录里面

4).修改 RTOS 的配置文件 rtconfig.h 

 rtconfig.h 文件参考

/* RT-Thread config file */


#ifndef __RTTHREAD_CFG_H__
#define __RTTHREAD_CFG_H__


// <<< Use Configuration Wizard in Context Menu >>>


// <h>Basic Configuration
// <o>Maximal level of thread priority <8-256>
//  <i>Default: 32
#define RT_THREAD_PRIORITY_MAX  32
// <o>OS tick per second
//  <i>Default: 1000   (1ms)
#define RT_TICK_PER_SECOND  1000
// <o>Alignment size for CPU architecture data access
//  <i>Default: 4
#define RT_ALIGN_SIZE   4
// <o>the max length of object name<2-16>
//  <i>Default: 8
#define RT_NAME_MAX    16                                                    /* YL 从8改16 */
// <c1>Using RT-Thread components initialization
//  <i>Using RT-Thread components initialization
#define RT_USING_COMPONENTS_INIT
// </c>


#define RT_USING_USER_MAIN


// <o>the stack size of main thread<1-4086>
//  <i>Default: 512
#define RT_MAIN_THREAD_STACK_SIZE     256                                    /* YL 从 256 改 2048 */


// </h>


// <h>Debug Configuration
// <c1>enable kernel debug configuration
//  <i>Default: enable kernel debug configuration
//#define RT_DEBUG
// </c>
// <o>enable components initialization debug configuration<0-1>
//  <i>Default: 0
#define RT_DEBUG_INIT 0
// <c1>thread stack over flow detect
//  <i> Diable Thread stack over flow detect
//#define RT_USING_OVERFLOW_CHECK
// </c>
// </h>


// <h>Hook Configuration
// <c1>using hook
//  <i>using hook
//#define RT_USING_HOOK
// </c>
// <c1>using idle hook
//  <i>using idle hook
//#define RT_USING_IDLE_HOOK
// </c>
// </h>


// <e>Software timers Configuration
// <i> Enables user timers
#define RT_USING_TIMER_SOFT         0
#if RT_USING_TIMER_SOFT == 0
    #undef RT_USING_TIMER_SOFT
#endif
// <o>The priority level of timer thread <0-31>
//  <i>Default: 4
#define RT_TIMER_THREAD_PRIO        4
// <o>The stack size of timer thread <0-8192>
//  <i>Default: 512
#define RT_TIMER_THREAD_STACK_SIZE  512
// </e>


// <h>IPC(Inter-process communication) Configuration
// <c1>Using Semaphore
//  <i>Using Semaphore
#define RT_USING_SEMAPHORE                                /* YL 信号量 */     
// </c>
// <c1>Using Mutex
//  <i>Using Mutex
//#define RT_USING_MUTEX                                  /* YL 互斥量 */
// </c>
// <c1>Using Event
//  <i>Using Event
//#define RT_USING_EVENT                                  /* YL 事件 */
// </c>
// <c1>Using MailBox
//  <i>Using MailBox
#define RT_USING_MAILBOX                                  /* YL 邮箱 */
// </c> 
// <c1>Using Message Queue
//  <i>Using Message Queue
//#define RT_USING_MESSAGEQUEUE                           /* YL 消息队列 */
// </c>
// </h>


// <h>Memory Management Configuration
// <c1>Memory Pool Management
//  <i>Memory Pool Management
//#define RT_USING_MEMPOOL
// </c>
// <c1>Dynamic Heap Management(Algorithm: small memory )
//  <i>Dynamic Heap Management
#define RT_USING_HEAP
#define RT_USING_SMALL_MEM
// </c>
// <c1>using tiny size of memory
//  <i>using tiny size of memory
//#define RT_USING_TINY_SIZE
// </c>
// </h>


// <h>Console Configuration
// <c1>Using console
//  <i>Using console
#define RT_USING_CONSOLE                                 /* YL 控制台 */     
// </c>
// <o>the buffer size of console <1-1024>
//  <i>the buffer size of console
//  <i>Default: 128  (128Byte)
#define RT_CONSOLEBUF_SIZE          256
// </h>


// <h>FinSH Configuration
// <c1>include finsh config
//  <i>Select this choice if you using FinSH 
#include "finsh_config.h"                                /* YL 开启宏定义,再到finsh_port.c 中关闭对应提示 */  
// </c>
// </h>


// <h>Device Configuration
// <c1>using device framework
//  <i>using device framework
//#define RT_USING_DEVICE                                /* YL 设备框架: 开启宏定义, */                
// </c>
// </h>


// <<< end of configuration section >>>


#endif

5).修改 RTOS 的 board.c 文件

//添加MCU的滴答定时器中断函数,并调用 RTOS 的滴答定时器回调函数
/* cortex-m  SysTick_Handler() */
void SysTick_Handler()
{
    rt_os_tick_callback();
}




//在 rt_hw_board_init 添加系统初始化调用的 MCU 函数


void rt_hw_board_init(void)
{
//#error "TODO 1: OS Tick Configuration."
    /* 
     * TODO 1: OS Tick Configuration
     * Enable the hardware timer and call the rt_os_tick_callback function
     * periodically with the frequency RT_TICK_PER_SECOND. 
     */


     HAL_Init(); 
     SystemClock_Config(); 
//   SystemCoreClockUpdate();
//   HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / 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
}


//添加RTOS控制台的收发代码
void rt_hw_console_output(const char *str)
{
//#error "TODO 3: Output the string 'str' through the uart."
    
#if  PRINTF_PORT_JLINK        /* j-link rtt 模式*/
    SEGGER_RTT_printf(0,str);
#else                         /* 硬件串口 模式*/
    while (*str != '\0')
    {
        // HAL_UART_Transmit(&Uart1Handle, (uint8_t *) (str++), 1, 1000);
    }
#endif
    rt_exit_critical();


}




char rt_hw_console_getchar(void)
{
    /* Note: the initial value of ch must < 0 */
    int ch = -1;
#if  PRINTF_PORT_JLINK          /* j-link rtt 模式*/
    ch = SEGGER_RTT_GetKey();
#else                           /* 硬件串口 模式*/
     //read_uart1_ch(&ch);
#endif


    return ch;
}


//添加 printf 函数重定向代码
/* printf 重定向  */
int fputc(int ch, FILE *f)
{
#if PRINTF_PORT_JLINK            /* j-link rtt 模式*/
    SEGGER_RTT_PutChar(0, ch);
#else
    HAL_UART_Transmit(&Uart1Handle, (uint8_t *)&ch, 1, 1000); /* 硬件串口 模式*/
#endif
    return (ch);
}

6).添加JLINK 的RTT 打印功能

安装JLINK 后,在如下目录中可以找到一个 RTT 文件夹,把这文件夹添加到工程中

添加 RTT 功能使用到的2个 .C 文件

添加 RTT 的头文件

 添加 RTT 的收发代码、printf的重定向函数 到 board.c

void rt_hw_console_output(const char *str)
{
//#error "TODO 3: Output the string 'str' through the uart."
    
#if  PRINTF_PORT_JLINK        /* j-link rtt 模式*/
    SEGGER_RTT_printf(0,str);
#else                         /* 硬件串口 模式*/
    while (*str != '\0')
    {
        // HAL_UART_Transmit(&Uart1Handle, (uint8_t *) (str++), 1, 1000);
    }
#endif
    rt_exit_critical();
}


char rt_hw_console_getchar(void)
{
    /* Note: the initial value of ch must < 0 */
    int ch = -1;
#if  PRINTF_PORT_JLINK          /* j-link rtt 模式*/
    ch = SEGGER_RTT_GetKey();
#else                           /* 硬件串口 模式*/
     //read_uart1_ch(&ch);
#endif

    return ch;
}

/* printf 重定向  */
int fputc(int ch, FILE *f)
{
#if PRINTF_PORT_JLINK            /* j-link rtt 模式*/
    SEGGER_RTT_PutChar(0, ch);
#else
    HAL_UART_Transmit(&Uart1Handle, (uint8_t *)&ch, 1, 1000); /* 硬件串口 模式*/
#endif
    return (ch);
}

7).board.c 完整参考文件

/*
 * Copyright (c) 2006-2019, RT-Thread Development Team
 *
 * SPDX-License-Identifier: Apache-2.0
 *
 * Change Logs:
 * Date           Author       Notes
 * 2021-05-24                  the first version
 */
#include <rthw.h>
#include <rtthread.h>
#include "main.h"
#include "gpio.h"
#include "SEGGER_RTT.h"
#include "stdio.h"

#define PRINTF_PORT_JLINK   1        //打印数据端口选择  1:Jlink RTT 打印,0:MCU 串口打印
#define Printf_UartHandle   huart1   //MCU控制台串口


extern UART_HandleTypeDef huart1;    //MCU控制台串口


#if defined(RT_USING_USER_MAIN) && defined(RT_USING_HEAP)
/*
 * Please modify RT_HEAP_SIZE if you enable RT_USING_HEAP
 * the RT_HEAP_SIZE max value = (sram size - ZI size), 1024 means 1024 bytes
 */
#define RT_HEAP_SIZE (20*1024)                //定义系统堆大小  
static rt_uint8_t rt_heap[RT_HEAP_SIZE];

RT_WEAK void *rt_heap_begin_get(void)
{
    return rt_heap;
}

RT_WEAK void *rt_heap_end_get(void)
{
    return rt_heap + RT_HEAP_SIZE;
}
#endif

void rt_os_tick_callback(void)
{
    rt_interrupt_enter();
    
    rt_tick_increase();

    rt_interrupt_leave();
}


/* cortex-m  SysTick_Handler() */

//添加MCU的滴答定时器中断函数,并调用 RTOS 的滴答定时器回调函数
void SysTick_Handler()
{
    rt_os_tick_callback();
}


/**
 * This function will initial your board.
 */

//在 rt_hw_board_init 添加系统初始化调用的 MCU 函数
void rt_hw_board_init(void)
{
		 /*"TODO 1: OS Tick Configuration."*/
    /* 
     * TODO 1: OS Tick Configuration
     * Enable the hardware timer and call the rt_os_tick_callback function
     * periodically with the frequency RT_TICK_PER_SECOND. 
     */
		HAL_Init(); 
	  
        SystemClock_Config(); 
        SystemCoreClockUpdate();
        HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );	
        MX_GPIO_Init();
 

    /* 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
}



#ifdef RT_USING_CONSOLE

static int uart_init(void)
{
//#error "TODO 2: Enable the hardware uart and config baudrate."
    return 0;
}
INIT_BOARD_EXPORT(uart_init);



//添加RTOS控制台的发送代码
void rt_hw_console_output(const char *str)
{
//#error "TODO 3: Output the string 'str' through the uart."
    /* empty console output */
    rt_enter_critical();
    
#if  PRINTF_PORT_JLINK
    SEGGER_RTT_printf(0,str);
#else
    while (*str != '\0')
    {
         HAL_UART_Transmit(&Printf_UartHandle, (uint8_t *) (str++), 1, 1000);
    }
#endif
    rt_exit_critical();
}

#endif

//添加RTOS控制台的接收代码
char rt_hw_console_getchar(void)
{
    /* Note: the initial value of ch must < 0 */
    int ch = -1;
#if  PRINTF_PORT_JLINK          /* j-link rtt 模式*/
    ch = SEGGER_RTT_GetKey();
#else                           /* 串口 模式*/
    //read_uart1_ch(&ch);
     HAL_UART_Receive(&Printf_UartHandle, (uint8_t *)&ch, 1, 10);
#endif
    return ch;
}


//添加 printf 函数重定向代码
/* printf 重定向 */
int fputc(int ch, FILE *f)
{
#if PRINTF_PORT_JLINK            /* j-link rtt 模式*/
    SEGGER_RTT_PutChar(0, ch);
#else
    HAL_UART_Transmit(&Printf_UartHandle, (uint8_t *)&ch, 1, 10); /* 硬件串口 模式*/
#endif
    return (ch);
}

/* scanf 重定向 */
int fgetc(FILE *f)
{
  int ch;
  HAL_UART_Receive(&Printf_UartHandle, (uint8_t *)&ch, 1, 1000);
  return (ch);
}

8).编译、排错错误、测试

编译过程中可能会出现如下错误,错误原因因为重复定义。在 Core\Src\stm32g4xx_it.c 文件中找到对应函数,屏蔽掉即可。

SysTick_Handler()  //屏蔽掉
PendSV_Handler()   //屏蔽掉
HardFault_Handler()//屏蔽掉

 测试:在main.c 函数中增加系统测试代码

  uint32_t count = 0;
  while (1)
  {
    /* USER CODE END WHILE */
      count++;
      rt_thread_mdelay(1000);
      printf("count = %d ,tick_time = %d \r\n",count,rt_tick_get());
    /* USER CODE BEGIN 3 */
  }

下载程序,打开 JLINK 的 RTT

系统成功运行后打印如下信息

9).JLINK RTT 软件设置及应用

 

打开软件后按 F2 可以弹出如下窗口;

设置后 OK可以打开 RTT 功能按F3可以断开链接;

窗口数据停止刷新ALT + R 清除窗口显示;

按如下设置后,输入信息按 回车键才会发出,这样配置后才能使用 RT thread 的控制台

在输入窗口输入 help 回车可以看到系统控制台的打印信息 

  • 5
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Keil License是指Keil软件的许可证。Keil是一家德国公司,开发出了一系列嵌入式系统软件开发工具,包括编译器和调试器等。对于使用Keil软件进行开发的用户来说,需要购买相应的Keil License来合法使用软件。 Keil License是一种许可证,它规定了用户可以使用Keil软件的权限和限制。购买Keil License后,用户可以在一定的时间期限内使用Keil软件来开发嵌入式系统。不同的Keil License可能拥有不同的功能和服务。一般来说,Keil License分为个人/教育版和商业版两种。 个人/教育版的Keil License适用于个人、教育或非商业组织使用,价格较为便宜或者是免费的。它提供了基本的软件开发功能,可以满足个人或教育场景下的需求。 商业版的Keil License适用于商业组织或需要更高级功能的用户。商业版一般具有更强大的软件开发功能和更广泛的技术支持,价格较高。 在购买Keil License后,用户将获得一个许可证文件。用户需要将该文件导入到Keil软件中,以激活软件并解锁相应的功能。根据许可证中规定的期限,用户可以在使用期限内享受Keil软件的各项功能和服务。 需要注意的是,Keil License是一种付费许可证,用户需要购买合法的许可证来使用Keil软件。未经许可的使用属于侵权行为,可能会受到法律制裁。 总而言之,Keil License是一种许可证,用于合法使用Keil软件进行嵌入式系统开发。凭借Keil License,用户可以获得软件开发功能和技术支持,提高开发效率和质量。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值