Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
Devices
贡献一个小巧轻便的LED闪烁控制软件包
发布于 2020-03-29 16:24:01 浏览:1675
订阅该版
* 本帖最后由 sunwan 于 2020-3-29 16:36 编辑 * 有人问我:RT-Thread官网上已经有好几个有关LED控制的软件包了,你又弄一个干嘛? 嗯,怎么说呢,一个觉得是开源的软件包是多多益善,给大家更多选择的余地;第二,这些年对LED的控制,一直像大部分的作品一样,每个LED弄个线程,控制这个LED的亮和暗。后来,不知怎么,就像开窍了样,巧妙地利用信号量及信号量本身的等待时间,只在一个守护线程里,实现所有LED的闪烁控制,于是就有了这个软件包(不知道网上其它OS里是不是有类似的软件)。前一段时间把它修改了下,可以不需要移植,直接应用在 RT-Thread 标准版和 Nano 版。 项目主页: [https://github.com/Sunwancn/rtt-pkgs-easyblink.git](https://github.com/Sunwancn/rtt-pkgs-easyblink.git) [https://gitee.com/sunwancn/rtt-pkgs-easyblink.git](https://gitee.com/sunwancn/rtt-pkgs-easyblink.git) 简介 小巧轻便的LED控制软件包,可以容易地控制LED开、关、反转和各种间隔闪烁,占用RAM少,可以设置成线程安全型的;不需要移植就可以同时适用 RT-Thread 标准版和 Nano 版。 特点 和其它LED同类软件相比,easyblink 有一个显著的特点,占用 RAM 特别少,其它 LED 软件一般每一个LED都需要创建一个线程,LED一多,线程数就多了,所占用的栈空间就相应的增大。而 easyblink 始终只使用一个守护线程(线程栈可以是预先分配的静态栈空间),无论多少个 LED,就一个线程。另外,不需要移植就可以同时适用 RT-Thread 标准版和 Nano 版,特别适合 RAM 紧张的产品。同时,也可以设置成线程安全型的。 获取软件包 使用 easyblink 软件包需要在 ENV 环境的包管理中选中它,若没有找到,先使用 `pkgs --upgrade` ,升级本地的包列表,运行 menuconfig 后具体路径如下: ```RT-Thread online packages peripheral libraries and drivers ---> (*) easyblink: Blink the LED easily and use a little RAM --->``` ``` --- easyblink: Blink the LED easily and use a little RAM (3) Setting the max LED nums [ ] Blink led on console to test [ ] Use mutex to make thread safe [ ] Use heap with the easyblink thread stack created Version (latest) --->``` 设置选项: Setting the max LED nums: 最多可使用的LED数目。 Blink led on console to test: 可以在控制台控制LED闪烁,进行测试。 Use mutex to make thread safe: 使用互锁,成为线程安全型的应用。 Use heap with the easyblink daemon thread stack created: LED守护线程栈使用系统动态堆内存。 API 简介 ```ebled_t easyblink_init(GPIO_TypeDef *port, rt_uint16_t pin, GPIO_PinState active_level)``` easyblink 的初始化函数,必须的。 参数: port: 为LED驱动引脚端口,GPIOx,x 为 A、B、C、D 等等。 pin: 引脚端口号,GPIO_PIN_0 - GPIO_PIN_15。 active_level: 点亮LED时的端口电平,为 GPIO_PIN_RESET 或 GPIO_PIN_SET。 函数返回 ebled_t 类型指针,init 次数超过最大LED数目,返回空指针。 ```/*************************************************************************************************** * @fn easyblink * * @brief 以给定的次数、脉宽和周期闪烁LED。 * 若要在中断中使用 easyblink,并开了互锁,请把宏 PKG_EASYBLINK_WAIT_MUTEX_TICK 设为 0 吧, * 漏掉一次不闪就一次不闪吧,只是LED指示,无所谓的,还是中断的实时性重要。 * * @param led - LED句柄 * nums - LED闪烁次数,-1为无限次 * pulse - LED闪亮的脉冲宽度,以毫秒为单位 * period - LED闪烁的周期,以毫秒为单位 * * @return None ***************************************************************************************************/ void easyblink(ebled_t led, rt_int16_t nums, rt_uint16_t pulse, rt_uint16_t period)``` 参数: led: easyblink_init 后得到的 LED 句柄。 nums: 闪烁次数,-1 为一直闪烁。 pulse: LED 闪烁时点亮LED的脉冲宽度,以毫秒为单位。 period: LED 闪烁周期,亮和暗即一个完整的周期。 当前LED正在闪烁时,如果这时LED再调用一次 easyblink(),若当前LED的nums为-1(即一直闪烁),则会打断当前LED的闪烁,先关闭LED 500ms,然后使用新的参数进行闪烁,闪烁好了后,会再关闭LED 5000ms,再恢复原来的LED参数继续闪烁,关断LED的前后时间可以在 easyblink.h 里调整设置。否则,会保存参数在后备区,等当前的闪烁完了后,接着以新的参数闪烁。 因为只有一个后备区,因此当后备区有待闪烁的参数时,再次调用 easyblink(),原来后备区的参数将丢失,代之于新的参数。 若要在中断中使用 easyblink() ,并开了互锁,请把宏 PKG_EASYBLINK_WAIT_MUTEX_TICK 设为 0 ,漏掉一次不闪就一次不闪吧,只是LED指示,无所谓的,还是中断的实时性重要。 ```void easyblink_stop(ebled_t led)``` 主动停止 LED 闪烁。 ```void eb_led_on(ebled_t led)``` 点亮 LED 。 ```void eb_led_off(ebled_t led)``` 关闭 LED 。 ```void eb_led_toggle(ebled_t led)``` 翻转 LED 。 Nano 版: 直接拷贝 easyblink.h 和 easyblink.c 到用户文件夹,然后要确保开启宏 RT_USING_SEMAPHORE,再自己配置几个宏定义: PKG_EASYBLINK_MAX_LED_NUMS: 定义 LED 数目。 PKG_EASYBLINK_USING_MSH_CMD: 定义可以在控制台使用 eblink 进行LED的闪烁测试。 PKG_EASYBLINK_USING_MUTEX: 使用互锁,成为线程安全型应用,确保开启 RT_USING_MUTEX 。对只有少量的LED,闪烁频次不是很高,或者都是同一个线程控制的话,觉得不是非常必要。 PKG_EASYBLINK_USING_HEAP: LED的守护线程栈使用系统的动态堆内存,同时,要开启 RT_USING_HEAP,否则,在编译时就自动分配好内存。在小内存产品上,建议还是不要开启动态堆。 使用示例 ```#include "easyblink.h" ... ebled_t led1 = RT_NULL; ebled_t led2 = RT_NULL; int main(void) { ... /* 初始化LED1,引脚B口5脚,低电平有效 */ led1 = easyblink_init(GPIOB, GPIO_PIN_5, GPIO_PIN_RESET); /* 初始化LED2,引脚B口3脚,低电平有效 */ led2 = easyblink_init(GPIOB, GPIO_PIN_3, GPIO_PIN_RESET); /* led1 闪3次,周期1000ms,亮500ms */ easyblink(led1, 3, 500, 1000); /* led1 上次的闪完后,再接着闪2次,周期2000ms,亮1500ms */ easyblink(led1, 2, 1500, 2000); /* led2 一直闪,周期1000ms,亮5ms */ easyblink(led2, -1, 5, 1000); rt_thread_mdelay(8000); /* 打断led2闪烁,开始闪5次,周期500ms,亮300ms,闪完后恢复led2前次的序列 */ easyblink(led2, 5, 300, 500); easyblink(led1, -1, 10, 5000); rt_thread_mdelay(8000); /* 中途打断,停止闪烁 */ easyblink_stop(led2); rt_thread_mdelay(5000); while(1) { eb_led_toggle(led2); rt_thread_mdelay(3000); } }``` 在 Msh 控制台,可以使用 easyblink 命令测试LED: ```eblink
[period] [pulse]``` 前2个参数必选,后2个可以省略,可以输入 2、3、或 4 个参数。 init_num: 从 1 开始的正整数,是按 LED 的 init 初始化顺序排序的。 nums: 闪烁次数,-1 为一直闪。 period: 周期,默认 1000 毫秒。 pulse: 点亮 LED 的脉冲宽度,默认为 period 的一半。 最后 希望大家多多参与软件包的编写!
查看更多
14
个回答
默认排序
按发布时间排序
aozima
2020-03-29
调网络不抓包,调I2C等时序不上逻辑分析仪,就像电工不用万用表!多用整理的好的文字,比截图更省流量,还能在整理过程中思考。
点个赞
小小李sunny
2020-05-27
这家伙很懒,什么也没写!
led闪烁次数,我设置为-1,但是灯不会闪烁是什么情况? 设置其他值的时候都正常。
小小李sunny
2020-05-27
这家伙很懒,什么也没写!
>led闪烁次数,我设置为-1,但是灯不会闪烁是什么情况? >设置其他值的时候都正常。 ... --- 调试发现,当闪烁次数设置为-1 时,会一直阻塞在下边这个地方,是什么问题呢? /* 若wait_tick非零,在此阻塞线程wait_tick,或通过信号量同步后,开始准备闪烁 */ while (wait_tick) { tick = rt_tick_get(); /* 线程等待 wait_tick 个 os tick */ if (rt_sem_take(eb_sem, wait_tick) != RT_EOK) break; /* 接收到信号量,校正其它LED的tick数,并取最小ticks */ wait_tick = correct_or_get_min_ticks(tick, RT_TRUE); }
sunwan
2020-05-27
这家伙很懒,什么也没写!
>led闪烁次数,我设置为-1,但是灯不会闪烁是什么情况? >设置其他值的时候都正常。 ... --- 在我这里一切正常。RTT版本以及esayblink版本?是在程序中还是运行控制台命令? esayblink2.0.0以后,初始化LED时建议使用新的API: ``` ebled_t easyblink_init_led(rt_base_t rt_pin, rt_base_t active_level) ```
小小李sunny
2020-05-27
这家伙很懒,什么也没写!
[i=s] 本帖最后由 小小李sunny 于 2020-5-27 21:10 编辑 [/i] >在我这里一切正常。RTT版本以及esayblink版本?是在程序中还是运行控制台命令? >esayblink2.0.0以后,初 ... --- RTT是4.0.2,esayblink2.0.0 在程序中执行的。另外通过控制台命令输入好像不行,控制台输入-1的话,提示错误范围应该是1-any 。我看程序里也确实是这样的。
sunwan
2020-05-28
这家伙很懒,什么也没写!
>RTT是4.0.2,esayblink2.0.0 在程序中执行的。另外通过控制台命令输入好像不行,控制台输入-1的话,提示 ... --- 嗯,控制台确实是不能输入-1的,因为担心会一直闪,关不掉。但程序里应该是可以的,既然其它数值可以,这个好像不应该啊,我这里都正常的。具体例程是怎样的,可以发一些代码吗?
小小李sunny
2020-05-28
这家伙很懒,什么也没写!
[i=s] 本帖最后由 小小李sunny 于 2020-5-28 14:11 编辑 [/i] >嗯,控制台确实是不能输入-1的,因为担心会一直闪,关不掉。但程序里应该是可以的,既然其它数值可以,这 ... --- 代码就涉及一个初始化和一个led线程,因为我需要根据程序中某些状态量来实时改变led闪烁的情况,所以就写了一个线程。线程里想用-1实现无限次的闪烁,这样当状态需要改变时可以直接改变。但是写了-1 灯只会很快的闪一下就没了,现在只能先用5次或者10次来实现,但是实际应用这样不行,闪烁不能及时改变。代码如下: ``` void my_led_init(void) { /* 初始化LED,高电平有效 */ gps_led = easyblink_init(GPIOE, GPIO_PIN_10, GPIO_PIN_SET); can1_led = easyblink_init(GPIOE, GPIO_PIN_9, GPIO_PIN_SET); can2_led = easyblink_init(GPIOE, GPIO_PIN_8, GPIO_PIN_SET); net_led = easyblink_init(GPIOE, GPIO_PIN_7, GPIO_PIN_SET); } void my_led_display_entry(void *param) { while(1) { /*这里正常应该用-1,无限次闪烁,但是不成功,原因未知,先按10次,由于该线程一直会执行,因此也可以满足*/ if(gps_fixed_is_ok == 1) easyblink(gps_led, 2, 1000, 1000); //如果GPS定位成功,GPS灯常亮 else easyblink(gps_led, 5, 1000, 2000); //GPS定位不成功则逐秒闪烁 if(can1_is_ok == 1) { easyblink(can1_led, 5, 1000, 1000); //如果CAN1有数据,指示灯常亮 can1_is_ok = 0; } else easyblink(can1_led, 5, 1000, 2000); //否则逐秒闪烁 if(can2_is_ok == 1) { easyblink(can2_led, 5, 1000, 1000); //如果CAN2有数据,指示灯常亮 can2_is_ok = 0; } else easyblink(can2_led, 5, 1000, 2000);//否则逐秒闪烁 if((socket1_connect_is_ok == 1) || (socket2_connect_is_ok == 1)) easyblink(net_led, 5, 1000, 1000); //如果socket1连接成功,指示灯常亮 else //否则逐秒闪烁 easyblink(net_led, 5, 1000, 2000); rt_thread_delay(100); } } ```
sunwan
2020-05-28
这家伙很懒,什么也没写!
[i=s] 本帖最后由 sunwan 于 2020-5-28 19:29 编辑 [/i] >代码就涉及一个初始化和一个led线程,因为我需要根据程序中某些状态量来实时改变led闪烁的情况,所以就写 ... --- 额,我当时没有考虑到你有这种使用方法。你这个是连续快速(rt_thread_delay(100);很大可能也就100ms)使用easyblink()写入参数。原则上只要使用easyblink()一次就够了,比如要实现一直闪烁,只需要调用一次 easyblink() 并且nums为 -1 就够了,不需要在一个线程里循环写入,当然,连续写入也可以,只是针对有限次的闪烁,如果第一次的没闪完,第二次的参数会保存在后备区,等第一次的闪完了,接着会以第二次的参数闪烁。如果第一次的没闪完,接着又写入第二次的,第三次的,只保留最后一次的参数在后备区。 像你的这种用法,随便闪几次,表现出来的就是一直闪烁的。 你这个不需要另外使用线程来检测,在状态改变时,直接调用相应的API接口进行闪烁控制,注意以下几点: 1、LED常亮建议使用下面的API,代替使用占空比100%的脉冲,这样可以减少CPU占用。 ``` void eb_led_on(ebled_t led) ``` 2、当由无限次闪烁更改成有限次的时,一般先 easyblink_stop() 掉这个LED, 再重新 easyblink(), 否则闪完了,过个几秒,会恢复无限次的闪烁。 ``` void easyblink_stop(ebled_t led) ``` 3、初始化时可以使用新的API,这样可以简化代码: ``` ebled_t easyblink_init_led(rt_base_t rt_pin, rt_base_t active_level) ``` 4、建议使用 v2.0.1版本。 还有其它的API,链接里有介绍的,这个帖子是最早的版本,并且帖子还不能修改的。 还有,谢谢你提供的样本,下次我也得改改我的代码,连续调用easyblink()并且nums为 -1 时,还可以一直闪烁,不会停掉。
小小李sunny
2020-05-29
这家伙很懒,什么也没写!
>额,我当时没有考虑到你有这种使用方法。你这个是连续快速(rt_thread_delay(100);很大可能也就100ms)使 ... --- 非常感谢,新的代码闪烁设置为-1,可以使用了。 我这里由于4个指示灯所指示的状态需要根据4个状态量进行实时变化,这4个状态量的扫描频率更高,而且这4个状态分别在不同的函数和文件里执行,因此用了一个专门的led的线程来进行,这样要方便一些。我这里把线程的延时改成了2000ms(至少要执行完一个闪烁周期,否则闪烁会出现异常)。 现在用的过程中发现有两个地方: 1.当eb_led_on()状态时,如果要调用easyblink(),那么就必须要先调用easyblink_stop(),否则easyblink不会起作用; 2.当无限次闪烁时,如果要继续调用easyblink()改变占空比进行无限次闪烁时,或者直接调用eb_led_on()进行常亮时,也必须要先调用easylink_stop(),否则灯状态不会改变; 你看这里是不是可以优化一下,在改变灯的闪烁状态时不需要再先调用easylink_stop(),直接执行状态的改变?
yushigengyu
认证专家
2020-05-29
这家伙很懒,什么也没写!
如何将软件包加入env软件包列表?
撰写答案
登录
注册新账号
关注者
0
被浏览
1.7k
关于作者
sunwan
这家伙很懒,什么也没写!
提问
10
回答
91
被采纳
0
关注TA
发私信
相关问题
1
问个问题,ili9320驱动里面rt_hw_lcd_draw_blit_line 这个函数是干什么用的
2
LCD双缓冲有什么好的办法实现
3
LCD NT35510 驱动代码
4
io设备驱动的疑惑与建议
5
液晶屏驱动 U8g2 移植
6
求助:在模板上添加LCD模块出现L6406E错误
7
hwtimer硬件定时器驱动和使用经验
8
硬件定时器超时时间计算问题
9
请教spi驱动lcd显示屏问题
10
rtt-master(3.1.1)bsp—armfly中drv_lcd.c中是不是错了啊?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
最新文章
1
RT-thred的stm32h723对应bsp包CubeMX添加其他外设报错
2
RT-Thread中的time溢出问题,时间戳溢出,解决方法
3
ART-PI使用env驱动ETH网卡,pc和板子可以ping通
4
SystemView线程名字不显示
5
只用网页也能跑RT-Smart 无门槛腾讯Cloud studio + smart-build快速构建
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
9
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
winfeng
2
个答案
1
次被采纳
YZRD
2
个答案
1
次被采纳
本月文章贡献
catcatbing
2
篇文章
5
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
阳光的掌控者
1
篇文章
1
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部