创建单线程—SRAM 静态内存(学习笔记)

本文参考自[野火EmbedFire]《RT-Thread内核实现与应用开发实战——基于STM32》,仅作为个人学习笔记。更详细的内容和步骤请查看原文(可到野火资料下载中心下载)

硬件初始化

本文将创建一个LED闪烁的线程,所以必须先进行LED的硬件配置,我所使用的开发板为正点原子STM32F103ZET6核心板,有两个LED,分别对应PB5和PE5,led的bsp文件如下:
bsp_led.h

#ifndef __BSP_LED_H
#define __BSP_LED_H

#include "stm32f10x.h"

#define LED0_GPIO_PIN              GPIO_Pin_5
#define LED0_GPIO_PORT             GPIOB
#define LED0_GPIO_CLK              RCC_APB2Periph_GPIOB


#define LED1_GPIO_PIN              GPIO_Pin_5
#define LED1_GPIO_PORT             GPIOE
#define LED1_GPIO_CLK              RCC_APB2Periph_GPIOE

#define    ON        1
#define    OFF       0

// \  C语言里面叫续行符,后面不能有任何的东西

#define   LED0(a)   if(a) \
	                       GPIO_ResetBits(LED0_GPIO_PORT, LED0_GPIO_PIN); \
                     else  GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN);


#define   LED1(a)   if(a) \
	                       GPIO_ResetBits(LED1_GPIO_PORT, LED1_GPIO_PIN); \
                     else  GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);

// ^ 异或,C语言的一个二进制的运算符
// 与1异或改变,与0异或不变

#define LED0_TOGGLE        {LED0_GPIO_PORT->ODR ^= LED0_GPIO_PIN;}
#define LED1_TOGGLE        {LED1_GPIO_PORT->ODR ^= LED1_GPIO_PIN;}

void LED_GPIO_Config(void);

#endif /* __BSP_LED_H */


bsp_led.c

// bsp :board support package 板级支持包
#include "bsp_led.h"

void LED_GPIO_Config(void)
{
    
    
	GPIO_InitTypeDef  GPIO_InitStruct;
	
	RCC_APB2PeriphClockCmd(LED0_GPIO_CLK, ENABLE);
	RCC_APB2PeriphClockCmd(LED1_GPIO_CLK, ENABLE);
	
	// LED0
	GPIO_InitStruct.GPIO_Pin = LED0_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(LED0_GPIO_PORT, &GPIO_InitStruct);

	// 默认拉高
	GPIO_SetBits(LED0_GPIO_PORT, LED0_GPIO_PIN);
	
	// LED1
	GPIO_InitStruct.GPIO_Pin = LED1_GPIO_PIN;
	GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
	
	GPIO_Init(LED1_GPIO_PORT, &GPIO_InitStruct);
	
	// 默认拉高
	GPIO_SetBits(LED1_GPIO_PORT, LED1_GPIO_PIN);
}

编写完led的底层驱动后,将LED_GPIO_Config()添加到board.crt_hw_board_init()函数里:

void rt_hw_board_init(void)
{
    
    
#if 0
    /* TODO: OS Tick Configuration */
    _SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);
#endif
	
	/* 初始化 SysTick */
	SysTick_Config(SystemCoreClock / RT_TICK_PER_SECOND);

	/* 硬件 BSP 初始化统统放在这里,比如 LED,串口,LCD 等 */
	
	// LED初始化
	LED_GPIO_Config();
	
	// 测试
	//LED0(1);
	//LED1(1);

    /* 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_ALIGN_SIZE 个字节对齐
ALIGN(RT_ALIGN_SIZE)

// 定义线程栈
static rt_uint8_t rt_led0_thread_stack[1024];

在大多数系统中需要做栈空间地址对齐,ARM体系结构中需要向4字节地址对齐。RT_ALIGN_SIZE是rtconfig.h中的一个宏。

定义线程控制块

线程控制块是一个结构体,里面存放了线程的全部信息,通常称这个控制块为线程的身份证。

// 定义线程控制块
static struct rt_thread led0_thread;

定义线程函数

线程函数即线程入口函数,是线程的功能代码,由于线程需要不停运行,所以需要加上一个while(1),下面这个线程函数实现的功能是LED0以500ms的间隔进行闪烁。

/******************************************************************************
* @ 函数名  : led0_thread_entry
* @ 功  能  : LED0线程入口函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
    
    
	while(1)
	{
    
    
		LED0(1);
		rt_thread_delay(500); // 500个tick(500ms)
		LED0(0);
		rt_thread_delay(500);
	}
}

初始化线程

一个静态线程的三要素是线程入口函数线程栈线程控制块,我们需要用rt_thread_init()函数将这三者联系起来,使其变成一个可以工作的线程。

	// 初始化一个静态线程
	rt_thread_init(&led0_thread,                  // 线程控制块
					"led0",                       // 线程名字
	                led0_thread_entry,            // 线程入口函数
	                RT_NULL,                      // 入口函数参数
	                &rt_led0_thread_stack[0],     // 线程栈起始地址
					sizeof(rt_led0_thread_stack), // 线程栈大小
				    5,                            // 线程优先级
					10);                          // 线程时间片
							

关于线程的优先级,一定要填rtconfig.h中规定的范围内的数字(在昨天移植系统时,我把线程优先级的最大值设置成了8),如果线程初始化时将优先级设置过大,线程将不会工作。

在这里插入图片描述

启动线程

线程初始化后,线程只是处于初始态(RT_THREAD_INIT),要想让线程进入就绪态(RT_THREAD_READY),还需使用rt_thread_startup()函数。

	// 开启线程调度
	rt_thread_startup(&led0_thread);
							

实验效果

请添加图片描述

完整代码

所有静态线程相关函数我都放在main.c,下面代码不包括底层驱动代码。

#include "board.h"
#include "rtthread.h"

// 线程栈需要 RT_ALIGN_SIZE 个字节对齐
ALIGN(RT_ALIGN_SIZE)

// 定义线程栈
static rt_uint8_t rt_led0_thread_stack[1024];

// 定义线程控制块
static struct rt_thread led0_thread;

/******************************************************************************
* @ 函数名  : led0_thread_entry
* @ 功  能  : LED0线程入口函数
* @ 参  数  : parameter 外部传入的参数
* @ 返回值  : 无
******************************************************************************/
static void led0_thread_entry(void *parameter)
{
    
    
	while(1)
	{
    
    
		LED0(1);
		rt_thread_delay(500); // 500个tick(500ms)
		LED0(0);
		rt_thread_delay(500);
	}
}

int main(void)
{
    
    
	// 硬件初始化和RTT的初始化已经在component.c中的rtthread_startup()完成
	
	// 初始化一个静态线程
	rt_thread_init(&led0_thread,                  // 线程控制块
					"led0",                       // 线程名字
	                led0_thread_entry,            // 线程入口函数
	                RT_NULL,                      // 入口函数参数
	                &rt_led0_thread_stack[0],     // 线程栈起始地址
					sizeof(rt_led0_thread_stack), // 线程栈大小
				    5,                            // 线程优先级
					10);                          // 线程时间片
	
	// 开启线程调度
	rt_thread_startup(&led0_thread);
							
}


猜你喜欢

转载自blog.csdn.net/weixin_43772810/article/details/123567499