基于HAL库使用RT-Thread nano官方的移植

参考2. 移植RT-Thread到STM32 — [野火]RT-Thread内核实现与应用开发实战——基于STM32 文档 (embedfire.com)https://doc.embedfire.com/rtos/rtthread/zh/latest/application/porting_to_stm32.html#

         使用STM32F103VET6,野火STM32指南者,基于HAL库

 1.下载nano(3.1.5),RT-Thread

Nano 简介与下载 (rt-thread.org)https://www.rt-thread.org/document/site/#/rt-thread-version/rt-thread-nano/an0038-nano-introduction

  RT-dhread 文件夹内容组成:

文件夹

文件夹

描述

rtthread/3.0.3

bsp

板级支持包

components/finsh

RT-Thread组件

include

头文件

include/libc

头文件

libcpu/arm/cortex-m0

与处理器相关的接口文件

libcpu/arm/cortex-m3

与处理器相关的接口文件

libcpu/arm/cortex-m4

与处理器相关的接口文件

libcpu/arm/cortex-m7

与处理器相关的接口文件

src

RT-Thread内核源码

1.1 bsp文件夹:

        只需要修改board.c和rtconfig.h这两个文件的内容即可,

 1.2 components文件夹:

         保留finsh文件夹,finsh是RT- Thread组件里面最具特色的,它通过串口打印的方式来输出各种信息,方便我们调试程序。 

  1.3 include/src文件夹:

        include目录下存放的是RT-Thread内核的头文件,是内核不可分割的一部分。 src目录下面存放的是RT-Thread内核的源文件,是内核的核心。

 

1.4 libcpu文件夹:

         根据单片机选择对应文件,此处选择arm /cortex-m3下的contex_rvds.s文件以及cpuport.c文件,

 2. 添加RT-Thread源码到工程组文件夹

         使用STM32CubeMx生成工程文件

 添加对应文件到工程目录(暂时没有使用components/finsh文件)

  添加对应头文件路径

 2.1 rtconfig.h文件 

修改其为默认大小, RT_MAIN_THREAD_STACK_SIZE表示main线程栈大小,取值范围为1~~~4086,单位为字节,默认为512。

  2.2 board.c文件

        RT-Thread启动的时候会调用一个名为rt_hw_board_init()的函数,从函数名称 我们可以知道它是用来初始化开发板硬件的,比如时钟,比如串口等,具体初始化什么由用户选择。当这些硬件 初始化好之后,RT-Thread才继续往下启动。

添加头文件main.h

修改两处,可以注释掉,也可以删除

 

 把main.c里 SystemClock_Config(void)复制到board.c,改成静态函数并声明其原型

  SystemClock_Config(void)需要 去掉Error_Handler();修改如下

static void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
  HAL_StatusTypeDef ret = HAL_OK;

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;

  ret = HAL_RCC_OscConfig(&RCC_OscInitStruct);
  if(ret != HAL_OK)
  {
    while(1);
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  ret = HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2);
  if(ret != HAL_OK)
  {
    while(1) { ; }
  }
}

 rt_hw_board_init()代码如下:

void rt_hw_board_init()
{                                                   
    SystemClock_Config();
    /* 初始化SysTick */
    HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );
    
#if 0    
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif


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

在stm32f1xx_i.cstm32f1xx_i.h文件里删点或注释下面三个函数

SysTick_Handler() 、PendSV_Handler()、HardFault_Handler(void)

程序编译无误

 到此已经创建好了基于野火STM32开发板的RT-Thread工程模板

3. 创建线程 

3.1. 硬件初始化

        将main.c里初始化函数放在 rt_hw_board_init()里,其他硬件BSP初始化统统放在这里,比如LED,串口,LCD等。

void rt_hw_board_init()
{    
                                                   
    SystemClock_Config();
    /* 初始化SysTick */
    HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );
    
    HAL_Init();
    MX_GPIO_Init();
#if 0    
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif


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

此处用HAL库点灯,所以用到GPIO初始化,需要我们在main.h里添加gpio.h

首先测试测试硬件是否正常工作

void rt_hw_board_init()
{    
                                                   
    SystemClock_Config();
    /* 初始化SysTick */
    HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );

    HAL_Init();
    MX_GPIO_Init();

    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    while (1);
#if 0    
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif


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

编译无误,下载到开发板上,结果如下,

 3.2. 创建单线程—SRAM静态内存

首先将rt_hw_board_init()里测试亮灯去掉。

void rt_hw_board_init()
{    
                                                   
    SystemClock_Config();
    /* 初始化SysTick */
    HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );

    HAL_Init();
    MX_GPIO_Init();

    //HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    //while (1);
#if 0    
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif


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

 3.2.1. 定义线程函数

 让开发板上面的RGB蓝色灯以1s的频率闪烁,

static void RGB_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    rt_thread_delay(1000);
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_SET);
    rt_thread_delay(1000);
  }
}

3.2.2. 定义线程栈

ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_rgb_link_thread_stack[512];

3.2.3. 定义线程控制块

static struct rt_thread rgb_thread;

3.2.4. 初始化线程/启动线程

int main(void)
{
  rt_thread_init(&rgb_thread, "RGB_Link", RGB_link_thread_entry,\
                  RT_NULL, &rt_rgb_link_thread_stack[0], \
                  sizeof(rt_rgb_link_thread_stack), 3, 20);
  rt_thread_startup(&rgb_thread);
}

 编译无误,下载到开发板上,测试无误。

3.3 创建单线程—SRAM动态内存

RT_USING_USER_MAIN 和RT_USING_HEAP这两个宏,在rtconfig.h定义, RT_USING_USER_MAIN默认开启,RT_USING_HEAP在使用动态内存时需要开启。

#include "main.h"
#include "rtthread.h"

#if 0
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_rgb_link_thread_stack[512];

static struct rt_thread rgb_thread;

static void RGB_link_thread_entry(void* parameter);

int main(void)
{
  rt_thread_init(&rgb_thread, "RGB_Link", RGB_link_thread_entry,\
                  RT_NULL, &rt_rgb_link_thread_stack[0], \
                  sizeof(rt_rgb_link_thread_stack), 3, 20);
  rt_thread_startup(&rgb_thread);
}

static void RGB_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    rt_thread_delay(1000);
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_SET);
    rt_thread_delay(1000);
  }
}
#else

static  rt_thread_t rgb_thread = RT_NULL;
static void RGB_link_thread_entry(void* parameter);

int main(void)
{
  rgb_thread = rt_thread_create("RGB_Link", RGB_link_thread_entry,\
                                  RT_NULL, 512, 3, 20);
  if (rgb_thread != RT_NULL)
    rt_thread_startup(rgb_thread);        
  else
    return -1;
}


static void RGB_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_R_GPIO_Port, RGB_R_Pin, GPIO_PIN_RESET);
    rt_thread_delay(1000);
    HAL_GPIO_WritePin(RGB_R_GPIO_Port, RGB_R_Pin, GPIO_PIN_SET);
    rt_thread_delay(1000);
  }
}
#endif

 编译无误,下载到开发板上,测试无误。此处换成RGB红灯闪烁。读者根据实际自行修改。

 4. 重映射串口到rt_kprintf函数

 将串口控制台重映射到rt_kprintf函数,rt_hw_console_output函数 在board.c实现,

void rt_hw_console_output(const char *str)
{
    /* 进入临界段 */
    rt_enter_critical();

    /* 直到字符串结束 */
    while (*str!='\0')
    {
        /* 换行 */
        if (*str=='\n')
        {
                HAL_UART_Transmit(&huart1 ,(uint8_t *)'\r', 1, 1000);
        }
        HAL_UART_Transmit(&huart1, (uint8_t *)(str++), 1, 1000);
    }

    /* 退出临界段 */
    rt_exit_critical();
}

 在board.c的rt_hw_board_init()函数中 对串口初始化

void rt_hw_board_init()
{    
                                                   
    SystemClock_Config();
    /* 初始化SysTick */
    HAL_SYSTICK_Config( HAL_RCC_GetSysClockFreq() / RT_TICK_PER_SECOND );

    HAL_Init();
    MX_GPIO_Init();
     MX_USART1_UART_Init();
#if 0    
    /* System Clock Update */
    SystemCoreClockUpdate();
    
    /* System Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif


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

 当rt_kprintf函数对应的输出控制台初始化好之后(在rt_hw_board_init()完成), 系统接下来会调用函数rt_show_version()来打印RT-Thread的版本号,该函数在 kservice.c中实现,

#include "main.h"
#include "rtthread.h"

#if 0
ALIGN(RT_ALIGN_SIZE)
static rt_uint8_t rt_rgb_link_thread_stack[512];

static struct rt_thread rgb_thread;

static void RGB_link_thread_entry(void* parameter);

int main(void)
{
  rt_thread_init(&rgb_thread, "RGB_Link", RGB_link_thread_entry,\
                  RT_NULL, &rt_rgb_link_thread_stack[0], \
                  sizeof(rt_rgb_link_thread_stack), 3, 20);
  rt_thread_startup(&rgb_thread);
}

static void RGB_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    rt_thread_delay(1000);
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_B_Pin, GPIO_PIN_SET);
    rt_thread_delay(1000);
  }
}
#else

static  rt_thread_t rgb1_thread= RT_NULL;
static  rt_thread_t rgb2_thread = RT_NULL;

static void RGB1_link_thread_entry(void* parameter);
static void RGB2_link_thread_entry(void* parameter);

int main(void)
{
    
  rgb1_thread = rt_thread_create("RGB_Link", RGB1_link_thread_entry,\
                                  RT_NULL, 512, 3, 1000);
  if (rgb1_thread != RT_NULL)
    rt_thread_startup(rgb1_thread);        
  else
    return -1;
  
  rt_kprintf("led1_thread running,LED1_ON\r\n");
  
    rgb2_thread = rt_thread_create("RGB_Link", RGB2_link_thread_entry,\
                                  RT_NULL, 512, 3, 1000);
  if (rgb2_thread != RT_NULL)
    rt_thread_startup(rgb2_thread);        
  else
    return -1;
}


static void RGB1_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_R_GPIO_Port, RGB_B_Pin, GPIO_PIN_RESET);
    rt_thread_delay(500);
    HAL_GPIO_WritePin(RGB_R_GPIO_Port, RGB_B_Pin, GPIO_PIN_SET);
    rt_thread_delay(500);
  }
}

static void RGB2_link_thread_entry(void* parameter)
{
  while(1)
  {
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_R_Pin, GPIO_PIN_RESET);
    rt_thread_delay(1000);
    HAL_GPIO_WritePin(RGB_B_GPIO_Port, RGB_R_Pin, GPIO_PIN_SET);
    rt_thread_delay(1000);
  }
}
#endif

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值