广东企业网站建设,百度官网网址,苏宁易购的网站建设,哪里有做区块链网站的硬件#xff1a;STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、RT-Thread相关接口函数1. 挂起线程2. 恢复线程 二、程序设计1. car_led.c2.car_led.h3. main.c 三、程序测试总结 前言
在上一个任务中STM32F103ZET6、ST-LINK、usb转串口工具、4个LED灯、1个蜂鸣器、4个1k电阻、2个按键、面包板、杜邦线 文章目录 前言一、RT-Thread相关接口函数1. 挂起线程2. 恢复线程 二、程序设计1. car_led.c2.car_led.h3. main.c 三、程序测试总结 前言
在上一个任务中通过停止命令把线程删除后线程在系统中就不存在了也无法再使线程重新运行。例如输入stop_led_thread命令后led停止闪烁但也无法重新开启LED灯闪烁功能。本任务通过修改停止命令的实现代码同时增加恢复命令使led灯闪烁功能可以暂停和恢复。 一、RT-Thread相关接口函数
1. 挂起线程
线程挂起是指把线程脱离就绪队列使线程不参与调度器的调度。线程挂起使用下面的接口函数
rt_err_t rt_thread_suspend (rt_thread_t thread);线程挂起接口 rt_thread_suspend() 的参数和返回值见下表
参数描述thread线程句柄返回RT_EOK 线程挂起成功-RT_ERROR 线程挂起失败因为该线程的状态并不是就绪状态 注一个线程尝试挂起另一个线程是一个非常危险的行为因此RT-Thread对此函数有严格的使用限制该函数只能使用来挂起当前线程即自己挂起自己不可以在线程A中尝试挂起线程B。而且在挂起线程自己后需要立刻调用 rt_schedule() 函数进行手动的线程上下文切换。用户只需要了解该接口的作用即可不建议在程序中使用该接口。该接口可以视为是内部接口。这是因为A线程在尝试挂起B线程时A线程并不清楚B线程正在运行什么程序一旦B线程正在使用影响、阻塞其他线程如C线程的内核对象例如互斥量、信号量等时如果此时其他线程也在等待这个内核对象那么A线程尝试挂起B线程的操作将会引发其他线程如C线程的饥饿严重危及系统的实时性。有些地方会将其描述为死锁实际上这种现象不是死锁但是也没有比死锁好到哪去。 当线程调用 rt_thread_delay() 时线程将主动挂起当调用 rt_sem_take()rt_mb_recv() 等函数时资源不可使用也将导致线程挂起。处于挂起状态的线程如果其等待的资源超时超过其设定的等待时间那么该线程将不再等待这些资源并返回到就绪状态或者当其他线程释放掉该线程所等待的资源时该线程也会返回到就绪状态。
2. 恢复线程
恢复线程就是让挂起的线程重新进入就绪状态并将线程放入系统的就绪队列中如果被恢复线程在所有就绪态线程中位于最高优先级链表的第一位那么系统将进行线程上下文的切换。线程恢复使用下面的函数接口
rt_err_t rt_thread_resume (rt_thread_t thread);线程恢复接口 rt_thread_resume() 的参数和返回值见下表
参数描述thread线程句柄返回RT_EOK 线程恢复成功-RT_ERROR 线程恢复失败因为该个线程的状态并不是 RT_THREAD_SUSPEND 状态
二、程序设计
在前一章节的基础上修改car_led.c、car_led.h和main.c三个文件即可具体如下
1. car_led.c
增加暂停标志、暂停设置接口以及在线程中增加暂停执行代码
#include rtthread.h
#include rtdevice.h
#include drv_common.h#define DBG_TAG LED
#define DBG_LVL DBG_LOG
#include rtdbg.h
#include stdlib.h
#include car_led.h
/* 定义左右转向灯的控制引脚 */
#define LedLeft GET_PIN(D, 8)
#define LedRight GET_PIN(D, 9)
#define LedOn(pin) rt_pin_write(pin, PIN_LOW)
#define LedOff(pin) rt_pin_write(pin, PIN_HIGH)enum led_mode LedModLED_MODE_STOP;
void led_set_mode(enum led_mode m)
{LedMod m;
}
/* 暂停运行标志变量0表示运行1表示暂停 */
static int stopFlag0;
void led_thread_entry()
{rt_pin_mode(LedLeft, PIN_MODE_OUTPUT);rt_pin_mode(LedRight, PIN_MODE_OUTPUT);
while(1){/*判断是否暂停运行*/if(stopFlag){rt_thread_suspend(rt_thread_self());//挂起线程只能自已挂起自已rt_schedule();//使用suspend挂起线程后需手动进行线程上下文切换}switch(LedMod){case LED_MODE_STOP:LedOff(LedLeft);LedOff(LedRight);break;case LED_MODE_Double:LedOn(LedLeft);LedOn(LedRight);rt_thread_mdelay(500);LedOff(LedLeft);LedOff(LedRight);break;case LED_MODE_LEFT:LedOff(LedRight);LedOn(LedLeft);rt_thread_mdelay(250);LedOff(LedLeft);break;case LED_MODE_RIGHT:LedOff(LedLeft);LedOn(LedRight);rt_thread_mdelay(250);LedOff(LedRight);break;default:LOG_D(mode error\n);}rt_thread_mdelay(250);}
}
void ledmode(int argn, char *argv[])
{if(argn2){LOG_W(ledmode #mode);return ;}led_set_mode(atoi(argv[1]));}
void led_stop_flag(int i)//设置暂停标志的接口
{stopFlagi;
}/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(ledmode, set led flash mode);
2.car_led.h
代码如下
#ifndef APPLICATIONS_CAR_LED_H_
#define APPLICATIONS_CAR_LED_H_/* 车灯闪烁模式定义 */
enum led_mode {LED_MODE_STOP0, //停止闪烁LED_MODE_Double, //双闪LED_MODE_LEFT, //左灯闪烁LED_MODE_RIGHT //右灯闪烁
};
void led_thread_entry(); //线程入口函数声明
void led_set_mode(enum led_mode m); //车灯闪烁模式设置声明
void led_stop_flag(int i); //接口声明同时导出模块接口供其它模块使用#endif /* APPLICATIONS_CAR_LED_H_ */3. main.c
主要修改stop_led_thread()函数的实现同时增加线程恢复函数并把线程恢复函数导出到msh命令中使我们可以通过终端来恢复线程。
#include rtthread.h
#define DBG_TAG main
#define DBG_LVL DBG_LOG
#include rtdbg.h
#include car_led.h //包含LED控制模块头文件
#include car_beep.h //包含蜂鸣器控制模块头文件#define THREAD_STACK_SIZE 1024 //定义线程栈大小
#define THREAD_PRIORITY 20 //定义线程优先级
#define THREAD_TIMESLICE 10 //定义线程时间片/* 栈首地址必须系统对齐 */
ALIGN(RT_ALIGN_SIZE)
static char beep_stack[THREAD_STACK_SIZE]; //定义栈空间
static struct rt_thread beepThread; //静态方式定义beep线程控制块
rt_thread_t TidLed RT_NULL; //动态方式定义LED线程句柄int main(void)
{int ret;/* 动态方式创建线程 */TidLed rt_thread_create(LED, led_thread_entry, RT_NULL,THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE);if (TidLed ! RT_NULL)//判断线程是否成功创建rt_thread_startup(TidLed);//成功则启动线程else {//否则打印日志并即出LOG_D(can not create LED thread!);return -1;}/* 采用静态方式初始化线程 */ret rt_thread_init(beepThread,BEEP,beep_thread_entry,RT_NULL,beep_stack[0],sizeof(beep_stack),THREAD_PRIORITY,THREAD_TIMESLICE);if (ret RT_EOK) //判断线程是否成功创建rt_thread_startup(beepThread); //成功则启动线程else { //否则打印日志并即出LOG_D(can not init beep thread!);return -1;}return RT_EOK;
}
void stop_led_thread()//暂停运行
{led_stop_flag(1);
}
void resume_led_thread()//恢复运行
{led_stop_flag(0);//先设置为运行rt_thread_resume(TidLed);//再恢复线程return;
}
/* 导出到 msh 命令列表中 */
MSH_CMD_EXPORT(resume_led_thread, resume led thread);//唤醒命令
MSH_CMD_EXPORT(stop_led_thread, stop led thread);
三、程序测试
1系统启动后使用命令“ledmode 1”使能车灯双闪观察到车灯闪烁。 2输入命令“stop_led_thread”命令观察到车灯停止闪烁说明线程已经被挂起。 3输入命令“resume_led_thread”命令观察到车灯重新闪烁说明线程被重新唤醒。 4输入命令“ps”命令如图所示观察到BEEP和LED两个线程都处理挂起状态这主要是因为ps命令输出时CPU正在运行tshell程序命令是在tshell线程上下文件中运行的而此时BEEP和LED两个线程因为执行rt_thread_mdelay()函数而被挂起。 总结
本章节学习线程的挂起与恢复的应用