draapho 发表于 2011-12-2 16:33:51

火牛板学习RT-Thread Step by Step——第二篇:跑马灯,动态线程及静态线程

2011年12月2日。开始学习RT-Thread的第三天。
前两天花了点时间重构了RT-Thread的目录结构。
目录结构见:
http://www.ourdev.cn/bbs/bbs_content.jsp?bbs_sn=5247738&bbs_page_no=1&bbs_id=3066

下面就开始学习创建线程。
RT-Thread的线程分为静态线程和动态线程。
要使用动态线程。必须在 rtconfig.h 中宏定义 RT_USING_HEAP,使能堆。

顾名思义,
静态线程的内存地址分配都必须事先定下来,不能进行回收分配。使用 rt_thread_init 对线程进行初始化操作。
动态线程使用 rt_thread_cteate 创建而来,需要由RT-Thread向堆中申请一片内存。当线程删除时 rt thread delete, 系统会回收该片内存。

静态线程不会有创建失败的可能性,在系统上电对其进行初始化后,其内存范围就确定且不可更改了。
动态线程在创建时,较为费时,而且可能由于堆用完等原因创建失败。其优点是RAM资源可回收再利用。

因此,结合我自己的理解,对线程使用的观点是:
重要的线程,以及一直使用的线程,可使用静态线程。
次要的线程,偶尔被使用的线程,可使用动态线程。

线程的几个状态时实时操作系统的基础,不做过多解释
1. 运行状态:当前线程正在使用CPU
2. 就绪状态:线程可以被运行,只是由于有优先级更高的线程正在占用CPU。当此线程成为最高优先级时,就进入运行态
3. 挂起状态:线程被挂起/阻塞,不会被运行。
4. 初始状态:线程初始化,或被删除的一个状态。
状态间的转换图:
http://cache.amobbs.com/bbs_upload782111/files_48/ourdev_700946ECC2YP.png
线程状态的转换图 (原文件名:无标题.png)

第一个范例:跑马灯。
此范例将用到函数:
rt_thread_init// 初始化一个静态线程
rt_thread_create// 创建一个动态线程
rt_thread_delay // 任务延时

一、在stm32f10x_conf.h文件中,配置LED灯的硬件IO口,如果是火牛板,如下:
/// LED硬件配置
#define LED_LEVEL                     1                                       ///< 0, 低电平点亮LED. 1, 高电平点亮LED

#define LED_NUM                         4                                       ///< 设置LED的数量, 该驱动最多允许16个LED灯.
#if(LED_NUM > 16)
#error "LED_NUM define error!"
#endif

#define LED0_PIN                        GPIO_Pin_8                              ///< 设置该LED的PIN口
#define LED0_PORT                     GPIOD                                 ///< 设置该LED的PORT口
#define LED0_CLK                        RCC_APB2Periph_GPIOD                  ///< 设置该LED的时钟模块

#define LED1_PIN                        GPIO_Pin_9
#define LED1_PORT                     GPIOD
#define LED1_CLK                        RCC_APB2Periph_GPIOD

#define LED2_PIN                        GPIO_Pin_10
#define LED2_PORT                     GPIOD
#define LED2_CLK                        RCC_APB2Periph_GPIOD

#define LED3_PIN                        GPIO_Pin_11
#define LED3_PORT                     GPIOD
#define LED3_CLK                        RCC_APB2Periph_GPIOD

typedef enum
{
LED1 = 0,// 4个LED灯的名字
LED2 = 1,
LED3 = 2,
LED4 = 3,
} ledName_t;

二、在application.c文件中写一个线程
static void LedApp(void* parameter)
{
while(1)
{
    LedOn(LED1);
// 其本质是rt_thread_delay();
// 为了代码兼容性(我的底层驱动延时都是用的DelayMs函数),
// 用DelayMs函数调用了rt_thread_delay()
    DelayMs(500);
    LedOn(LED2);
    DelayMs(500);
    LedOn(LED3);
    DelayMs(500);
    LedOn(LED4);
    DelayMs(500);
    LedOff(LED1);
    DelayMs(500);
    LedOff(LED2);
    DelayMs(500);
    LedOff(LED3);
    DelayMs(500);
    LedOff(LED4);
    DelayMs(500);
}
}

三、创建或初始化跑马灯线程
//使用静态线程, 需要预留好栈
static uint8_t ledThreadStack; // 跑马灯线程用到的栈
static struct rt_thread ledThread;// 跑马灯线程TCB控制块

void LedAppInit(void)
{
//////静态线程初始化使用 _init函数
////rt_thread_init(&ledThread,
////    "LedApp",            // 线程名称
////    LedApp, RT_NULL,       // 线程函数及入口参数
////    ledThreadStack,      // 线程栈地址
////    sizeof(ledThreadStack),// 线程栈大小
////    25,                  // 线程优先级
////    8);                                           // 同优先级时的轮询时间片
////
////rt_thread_startup(&ledThread); // 进入就绪态

//动态线程创建使用 _create函数
rt_thread_t thread;
thread = rt_thread_create(
      "led1",                           // 线程名称
      LedApp, RT_NULL,                   // 线程函数及入口参数
      512,                     // 要动态分配的线程栈大小
      20,                                           // 线程优先级
      5);                                     // 同优先级时的轮询时间片
if (thread != RT_NULL) rt_thread_startup(thread);       // 进入就绪态
else assert_param(0);// 创建失败则报错
}

四、在main.c文件中
在HardwareInit()函数中
调用 LedInitAll(); 初始化所有的LED灯
在ApplicationInit()函数中
调用 LedAppInit(); 完成线程的初始化或创建

五、编译和下载,就能看到跑马灯了。

STM32_RTThread 跑马灯ourdev_700974RCJJT7.rar(文件大小:3.26M) (原文件名:STM32_RTThread_V100.rar)

haphard 发表于 2011-12-2 16:42:18

不错,支持

dmxfeng 发表于 2011-12-2 17:28:47

占位学习

edaworld 发表于 2011-12-2 18:57:01

马甲

pangfen 发表于 2011-12-2 20:48:14

这个必须学习,必须顶!

ljt80158015 发表于 2011-12-2 21:06:33

不错!

ndt2000 发表于 2011-12-2 21:41:38

好,mark

fgcx 发表于 2011-12-2 23:18:20

这个ok.f教程太好了, 支持一下。。

xoolhaha 发表于 2011-12-3 10:41:54

支持!

dpjkflyq 发表于 2011-12-8 09:02:51

楼主 设置为100表示10ms, 设置为1000表示1ms. 这个不明白。请说下。

dpjkflyq 发表于 2011-12-8 09:06:12

******************************************************************************
* @brief系统嘀嗒时钟初始化为RT-Thread配置的周期. 其中断处理函数见"rt_hw_timer_handler.c".
*         参考RT_TICK_PER_SECOND. 设置为100表示10ms, 设置为1000表示1ms.//        1s=1000=1000ms   100
* @paramNone
* @retval None
******************************************************************************
*/
void SysTickInit(void)
{
RCC_ClocksTypeDef rcc_clocks;
uint32_t       cnts;

RCC_GetClocksFreq(&rcc_clocks);                //获取外接晶振
cnts = (rt_uint32_t)rcc_clocks.HCLK_Frequency / RT_TICK_PER_SECOND; // msRT_TICK_PER_SECOND= 1000, 1ms sytick 中断一次72000 &0xFFFFFF

SysTick_Config(cnts);
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);
}

/**
******************************************************************************
* @brief毫秒延时函数
* @paramtime, 要延时的毫秒时间. 误差为最小系统嘀嗒时钟. 该函数不允许在中断中使用!
*         例如, 系统嘀嗒时钟为10ms, 则使用DelayMs(1), 也将延时10ms.
* @retval None
******************************************************************************
*/
void Delay_ms(uint32_t time)
{
uint32_t base, tdly;

base = 1000 / RT_TICK_PER_SECOND;                                             // 获取基值
tdly = time / base;                                                         // 获取系统延时时间
if (time % base) tdly++;                                                      // 有余数, 延时取大值
rt_thread_delay(tdly);
}

dpjkflyq 发表于 2011-12-8 09:07:01

100 应该是 1s

draapho 发表于 2011-12-8 12:09:31

RT_TICK_PER_SECOND   
设置的是每秒有多少个系统节拍。设为100就是:每秒有100个系统节拍。
那系统节拍时间就是 1000ms/100 = 10ms

quweisy 发表于 2011-12-29 13:59:55

系列教程,支持!

jesonsyj 发表于 2012-2-16 20:25:12

回复【楼主位】draapho
-----------------------------------------------------------------------

跟着楼主学习,很好的东西~

allen6kid 发表于 2012-4-17 08:03:00

mark,支持一下

reynoldxmh 发表于 2012-6-5 11:54:49

谢谢分享引导入门,但是附件下不了

shotstar 发表于 2012-6-5 12:34:56

写得不错,

chnzh 发表于 2013-9-3 10:34:07

继续学习,支持
页: [1]
查看完整版本: 火牛板学习RT-Thread Step by Step——第二篇:跑马灯,动态线程及静态线程