在动态扫描基础上实现多级亮度控制

[复制链接]
7690|38
手机看帖
扫描二维码
随时随地手机跟帖
le062|  楼主 | 2014-7-26 21:39 | 显示全部楼层 |阅读模式
本帖最后由 le062 于 2014-7-27 23:23 编辑

    相信大家再刚接触单片机时一定玩过动态扫描,我这儿说下在动态扫描电路下对单颗LED进行亮度调节的实现方法。

    首先说下一般动态扫描电路的做法,
图片1.png
    如图,红黑线的16个交点为LED灯,限流电阻串在黑线上。依次导通COM口,同时控制四路SEG口的逻辑电平即可控制对应COM口上4led的亮灭状态。通过快速扫描COM即实现动态扫描显示功能。
    记SEG口数量为SEGNUMCOM口数量为COMNUM;扫描频率为LEDFREQ;动态扫描执行频率为EXECFREQ
    在一般动态扫描中,有EXECFREQ = LEDFREQ * COMNUM,最大亮度为常亮亮度的1/COMNUM。在较多LED灯的电路中,考虑到布线和IO资源,一般选择8COM口左右。

    那么,如何做亮度控制呢?
    假设亮度级别为LIGHTLEVEL
    我们将COM口的EXECFREQ 增大到 LEDFREQ * COMNUM *LIGHTLEVEL。在一个扫描周期,即LEDFREQ * COMNUM次扫描里根据LED的亮度让该LED0至(LIGHTLEVEL - 1)次。
    当然也可以维持COM口的扫描频率为LEDFREQ * COMNUM,将一个COM口导通时间分割成LIGHTLEVEL 个时间段,对应LED的亮度通过控制SEG口导通时间决定。

    这两种方案都是可行的,后面将就后一种方案的软件实现进行说明。

相关帖子

le062|  楼主 | 2014-7-26 21:41 | 显示全部楼层
本帖最后由 le062 于 2014-7-28 00:04 编辑

假设扫描频率60COM8个,亮度级30,那么EXECFREQ=60*8*30=14.4k。在单片机里面用这么高的频率跑的程序必须是固定处理时间的,并且需要放在中断里面执行。

综合考虑的话,COM口数量过高会导致CPU负荷较重,轮询时间变长,如果将COM口减到3个,可以使EXECFREQ降低到原来的3/8,同时相同电流下的最大亮度提升为原来的8/3倍,当然也会导致占用IO口变多,对于90LED的电路,那么至少需要33IO


下面以3*30的扫描电路为例,
对每颗LED建立如下结构:
struct s_LED
{
        struct s_LED* pNextLed;
        struct s_LED* pPrevLed;
        u8 seg_num;                //标明这颗LED对应SEG
        u8 target_level;        //目标亮度
        u8 cur_level;                //当前实际亮度
};

考虑到使用方便,可以将它们放在一个大结构体内:
struct
{
        //COM1 区域
        struct s_LED LED1_01;
        struct s_LED LED1_02;
        ...
        struct s_LED LED1_30;


        //COM2 区域
        struct s_LED LED2_01;
        struct s_LED LED2_02;
        ...
        struct s_LED LED2_30;

        //COM3 区域
        struct s_LED LED3_01;
        struct s_LED LED3_02;
        ...
        struct s_LED LED3_30;
} LEDS;

struct s_LED其实是一个双向链表节点,我们会把这90个节点放在3*30条链表上。


先考虑这种数据结构在固定亮度下的扫描过程:
图片1.png
我们将每个LED根据其所在COM口和亮度放在对应链表上,
那么在最小处理周期上(图中青色方框),处里一条对应链表即可(COM口调整时需处理多条)。
中断伪代码如下:
ISR
{
    if (COM口需要调整)
        {
                关闭当前COM口,
                关闭当前COM口中最高亮度链表中的LED
                开启下一个COM口中非0亮度链表中的LED
                开启下一个COM口
        }
        Else
        {
                关闭当前亮度级所对应链表中的LED
        }
        当前亮度级和COM口状态调整
}
在这个中断程序中最坏情况是需要关闭当前COM口下所有LED,并开启下个COM口下所有LED


下一步,就可以基于以上结构实现下面两点:
1.控制任意LED灯的亮度从 A级 缓变到 B级,变化速度恒定(比如,0.5秒从全黑到最亮)
2.控制任意LED灯的亮度从 A级 瞬变到 B

笼统的说,这两个任务都是去维护这个3*30的多链表,将每个节点根据亮度变化要求在链表间调整,这就纯粹是编码的活了。

使用特权

评论回复
le062|  楼主 | 2014-7-26 21:42 | 显示全部楼层
占楼

使用特权

评论回复
dirtwillfly| | 2014-7-26 22:16 | 显示全部楼层
谢谢分享

使用特权

评论回复
dirtwillfly| | 2014-7-26 22:17 | 显示全部楼层
楼主赶紧分享,我给你加精:lol:handshake

使用特权

评论回复
排山倒海| | 2014-7-27 09:30 | 显示全部楼层
如果只是几个亮度还好实现,如果是几十个亮度等级就需要较快的驱动间隔时间要求。

使用特权

评论回复
le062|  楼主 | 2014-7-27 10:19 | 显示全部楼层
哈哈,终于不裸奔了,:victory:

是要每个LED都要做到亮度可调。
最终控制效果是:
1.控制任意LED灯的亮度从 A级 缓变到 B级,变化速度恒定(比如,0.5秒从全黑到最亮)
2.控制任意LED灯的亮度从 A级 瞬变到 B级
亮度控制由驱动层实现,应用层调用以下接口控制即可
LED_changeLightness(u8 ledid, u8 targetLightness, bool is_immd )

我在16M主频的8位单片机上驱动 3* 30的扫描电路,做到30级亮度调整
估计耗用cpu 20%,相关数据结构占用ram达到1k

变化速度可调的实现方法还没想过。

使用特权

评论回复
gyh974| | 2014-7-28 20:14 | 显示全部楼层

使用特权

评论回复
hsst| | 2014-7-29 14:40 | 显示全部楼层
谢谢分享,顶一下

使用特权

评论回复
lzyyoumuren| | 2014-7-29 15:05 | 显示全部楼层
顶一下

使用特权

评论回复
通宵敲代码| | 2014-7-31 22:09 | 显示全部楼层
有搞头!
赞一个!

使用特权

评论回复
allround| | 2014-8-2 13:37 | 显示全部楼层
在LED点阵屏驱动上做过类似算法,100级亮度控制

使用特权

评论回复
dictionary| | 2014-8-4 10:48 | 显示全部楼层
好是好 但是 一个 LED亮度调节 占用了这么多内存资源 可以么?

使用特权

评论回复
le062|  楼主 | 2014-8-4 10:59 | 显示全部楼层
dictionary 发表于 2014-8-4 10:48
好是好 但是 一个 LED亮度调节 占用了这么多内存资源 可以么?

要不要这样玩,是需求决定的
和资源、技术没太大关系

使用特权

评论回复
dictionary| | 2014-8-4 11:22 | 显示全部楼层
通过软件方法 32位数据就能表示2048*2048 LED板的单个 LED 256级的 亮度调节了。

使用特权

评论回复
le062|  楼主 | 2014-8-4 12:00 | 显示全部楼层
dictionary 发表于 2014-8-4 11:22
通过软件方法 32位数据就能表示2048*2048 LED板的单个 LED 256级的 亮度调节了。

这个控制方法的目标是让所有led实现非同步的呼吸灯效果,各种图标,数码管,按键灯等都能根据需要自由的进行闪烁,亮灭,缓变。

在单片机上,主要短板在于其扫描时的流畅性,所以弄出个多链表来。

至于一个LED 256级,8bit数据就够了

使用特权

评论回复
dictionary| | 2014-8-4 14:28 | 显示全部楼层
本帖最后由 dictionary 于 2014-8-4 14:32 编辑
le062 发表于 2014-8-4 12:00
这个控制方法的目标是让所有led实现非同步的呼吸灯效果,各种图标,数码管,按键灯等都能根据需要自由的 ...

8bit数据是不够的 至少需要16bit 但是这样内存操作较多所以使用32bit来实现
我说的 不是单个LED 是LED阵列中的 单个LED 整体功能是作为 LED显示板 要控制其中任何一个LED灯的亮度  单个LED只要32bit数据
至于你说的流畅度,我之前已经给出了限制 那就是 分辨率为2048X2048(这里说分辨率是不对的,主要是LED灯的数量)
如果MCU运行速度足够快的话 那么 分辨率可以达到更高

使用特权

评论回复
huangqi412| | 2014-8-5 13:43 | 显示全部楼层
没看楼主的帖子内容,   只看了  相信大家再刚接触单片机时一定玩过动态扫描,我这儿说下在动态扫描电路下对单颗LED进行亮度调节的实现方法。

没做过LED彩屏,猜测。。。
从最简单单个数码管显示开始,到最后最复杂应该就是广场上的全彩LED视频, 用通用的思路分析就跟显示器一样,底层=显存+扫描时序。刷的是整个屏幕,不存在什么对单个LED进行亮度调节。  再上面跟显卡一样搞一些图像加强功能(在显存里折腾数据)。   如果不要像显卡一样神马3D神马的,  接口就是读写显存,哪来单个LED概念和接口呢。   
比如8*8分辨率,RGB 24位色,刷新率60HZ,   单层显存8*8*3字节, 占用IO 8+3*8=32根  刷新次数8*8*60=3840,整个画面你爱显示什么显示什么,修改对应坐标的显存值。

使用特权

评论回复
le062|  楼主 | 2014-8-5 16:09 | 显示全部楼层
huangqi412 发表于 2014-8-5 13:43
没看楼主的帖子内容,   只看了  相信大家再刚接触单片机时一定玩过动态扫描,我这儿说下在动态扫描电路下 ...

比如8*8分辨率,RGB 24位色,刷新率60HZ,   单层显存8*8*3字节, 占用IO 8+3*8=32根  刷新次数8*8*60=3840,整个画面你爱显示什么显示什么,修改对应坐标的显存值。

3840HZ的扫描速度能做到256级颜色?求解惑

使用特权

评论回复
评论
huangqi412 2014-8-5 17:12 回复TA
没做过屏,但是分析应该是这样子的。 
huangqi412| | 2014-8-5 17:06 | 显示全部楼层
le062 发表于 2014-8-5 16:09
比如8*8分辨率,RGB 24位色,刷新率60HZ,   单层显存8*8*3字节, 占用IO 8+3*8=32根  刷新次数8*8*60=384 ...

电脑用的是2进制,不要用人的十进制来想。这样就是3840了,是次/秒,不是HZ。

非矩形显示点阵,也可以将显存按像素数量划为矩形显存,上层图片做转换后写入显存啊。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

13

主题

435

帖子

4

粉丝