完善资料让更多小伙伴认识你,还能领取20积分哦, 立即完善>
`在前面一节中,介绍了RT-Thread的特点与基本功能,并基于其特点实现了LED功能的基础移植,本章主要实现基于RT-Thread 的按键控制,基本思路为: (一)建立两个任务:thread1用于检测按键,thread2用来控制LED。 (二)在任务中因为需要使用到共享资源,因此需要实现线程的同步,在RT-Thread 中实现任务同步有三种方式,分别为信号量、互斥锁、事件集。 信号量 信号量是在多线程环境下使用的一种设施,是可以用来保证两个或多个关键代码段不被并发调用。在进入一个关键代码段之前,线程必须获取一个信号量;一旦该关键代码段完成了,那么该线程必须释放信号量。其它想进入该关键代码段的线程必须等待直到第一个线程释放信号量。 互斥锁 互斥可以看做一个特殊二值信号量。 事件集 事件集主要用于线程间的同步,与信号量不同,它的特点是可以实现一对多,多对多的同步。即一个线程与多个事件的关系可设置为:其中任意一个事件唤醒线程,或几个事件都到达后才唤醒线程进行后续的处理;同样,事件也可以是多个线程同步多个事件。这种多个事件的集合可以用一个 32 位无符号整型变量来表示,变量的每一位代表一个事件,线程通过 “逻辑与” 或“逻辑或”将一个或多个事件关联起来,形成事件组合。事件的 “逻辑或” 也称为是独立型同步,指的是线程与任何事件之一发生同步;事件 “逻辑与” 也称为是关联型同步,指的是线程与若干事件都发生同步。 考虑到例程中任务量较少,不会有优先级翻转的影响,同时为了更少的占用资源,因此选用信号量来实现线程的同步。 01 创建工程 基于上一章移植完成的RT-Thread程序,我们来添加需要使用到的.C文件到工程中,如下图。 图2 添加RT-Thread后的工程 新建event_simple.c文本,同时将led.c/led.h/key.h/key.c一起置于HARDWARE文件夹中。右键工程左侧的USER文件夹选择Add Existing Files to GROUP,将Led.c/key.c/ event_simple.c添加到工程中,添加后如图。 图3 添加RTOS内核 02 创建线程 初步的工程搭建已经完成,我们现在来制作按键控制例程。 (1)在event_simple.c中创建两个空的线程: /* 指向线程控制块的指针 */ static rt_thread_t tid1 = RT_NULL; static rt_thread_t tid2 = RT_NULL; /* 线程1入口函数 */ static void thread1_entry(void *param) { while (1) { } } unsigned char flash_buff[40]; /* 线程2入口函数 */ static void thread2_entry(void *param) { while (1) { } } int event_simple_init() { /* 创建线程1 */ tid1 = rt_thread_create("t1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid1 != RT_NULL) rt_thread_startup(tid1); else tc_stat(TC_STAT_END | TC_STAT_FAILED); /* 创建线程2 */ tid2 = rt_thread_create("t2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid2 != RT_NULL) rt_thread_startup(tid2); else tc_stat(TC_STAT_END | TC_STAT_FAILED); return 0; } int rt_application_init() { event_simple_init(); return 0; } (2)添加功能到线程中: /* 线程1入口函数 */ static void thread1_entry(void *param) { while (1) { key_flag = KEY_Scan(0); rt_thread_delay(10); } } unsigned char flash_buff[40]; /* 线程2入口函数 */ static void thread2_entry(void *param) { while (1) { if(KEY1_PRES == key_flag) { LED4_TOGGLE(); } else if(KEY2_PRES == key_flag) { LED3_TOGGLE(); } else if(KEY3_PRES == key_flag) { LED2_TOGGLE(); } else if(KEY4_PRES == key_flag) { LED1_TOGGLE(); } else { rt_thread_delay(10); } } } int rt_application_init() { LED_Init(); KEY_Init(); event_simple_init(); return 0; } 此时我们将程序下载到板子中会发现,当按下按键时,LED亮灭比较混乱。这主要是因为,在程序中key_flag为共享资源,在多线程并发的环境下,多个线程在竞争着对同一资源对象进行操作,那么这两个线程将处于竞态条件(Race Condition),竞态条件下执行的代码结果依赖于并发执行或者事件的顺序,这种结果往往具有不确定性和不可重现性。因此我们需要使用信号量来实现线程的同步。 (3)添加信号量: /* 线程1入口函数 */ static void thread1_entry(void *param) { while (1) { key_flag = KEY_Scan(0); rt_sem_release(&sem); rt_thread_delay(10); } } unsigned char flash_buff[40]; /* 线程2入口函数 */ static void thread2_entry(void *param) { while (1) { rt_sem_take(&sem, RT_WAITING_FOREVER); if(KEY1_PRES == key_flag) { LED4_TOGGLE(); } else if(KEY2_PRES == key_flag) { LED3_TOGGLE(); } else if(KEY3_PRES == key_flag) { LED2_TOGGLE(); } else if(KEY4_PRES == key_flag) { LED1_TOGGLE(); } else { rt_thread_delay(10); } } } int event_simple_init() { rt_err_t result; result = rt_sem_init(&sem, "sem", 0, RT_IPC_FLAG_FIFO); if (result != RT_EOK) { return 0; } /* 创建线程1 */ tid1 = rt_thread_create("t1", thread1_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid1 != RT_NULL) rt_thread_startup(tid1); else tc_stat(TC_STAT_END | TC_STAT_FAILED); /* 创建线程2 */ tid2 = rt_thread_create("t2", thread2_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); if (tid2 != RT_NULL) rt_thread_startup(tid2); else tc_stat(TC_STAT_END | TC_STAT_FAILED); return 0; } 03 实验 当我们按下KEY1时,LED1亮起,再按一次灭。 当我们按下KEY2时,LED2亮起,再按一次灭。 当我们按下KEY3时,LED3亮起,再按一次灭。 当我们按下KEY4时,LED4亮起,再按一次灭。 实验视频: 可从灵动MM32MCU公众号中观看 2020灵动MM32协作大会 2020年9月10日 9:00 深圳星河丽思卡尔顿酒店 “2020灵动MM32协作大会”重磅开启!大会内容: 新品发布 技术分享 市场分析行业专家热点剖析 合作伙伴现场秀、互动小游戏 热销“MM32 INSIDE”应用案例展演等 更多精彩等着您,欢迎扫码报名参会! ` |
|
相关推荐
|
|
只有小组成员才能发言,加入小组>>
2206个成员聚集在这个小组
加入小组灵动微电子MM32全系列MCU产品应用手册,库函数和例程和选型表
10774 浏览 3 评论
【MM32 eMiniBoard试用连载】+基于OLED12864的GUI---U8G2
5676 浏览 1 评论
【MM32 eMiniBoard试用连载】移植RT-Thread至MM32L373PS
10524 浏览 0 评论
【MM32 eMiniBoard测评报告】+ 开箱 + 初探
4384 浏览 1 评论
灵动微课堂(第106讲) | MM32 USB功能学习笔记 —— WinUSB设备
4078 浏览 1 评论
[MM32软件] MM32F002使用内部flash存储数据怎么操作?
616浏览 1评论
532浏览 0评论
小黑屋| 手机版| Archiver| 电子发烧友 ( 湘ICP备2023018690号 )
GMT+8, 2024-4-20 04:35 , Processed in 0.519433 second(s), Total 59, Slave 49 queries .
Powered by 电子发烧友网
© 2015 bbs.elecfans.com
关注我们的微信
下载发烧友APP
电子发烧友观察
版权所有 © 湖南华秋数字科技有限公司
电子发烧友 (电路图) 湘公网安备 43011202000918 号 电信与信息服务业务经营许可证:合字B2-20210191 工商网监 湘ICP备2023018690号