本帖最后由 le062 于 2014-7-28 00:04 编辑
假设扫描频率60,COM口8个,亮度级30,那么EXECFREQ=60*8*30=14.4k。在单片机里面用这么高的频率跑的程序必须是固定处理时间的,并且需要放在中断里面执行。
综合考虑的话,COM口数量过高会导致CPU负荷较重,轮询时间变长,如果将COM口减到3个,可以使EXECFREQ降低到原来的3/8,同时相同电流下的最大亮度提升为原来的8/3倍,当然也会导致占用IO口变多,对于90个LED的电路,那么至少需要33个IO。
下面以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条链表上。
先考虑这种数据结构在固定亮度下的扫描过程: 我们将每个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的多链表,将每个节点根据亮度变化要求在链表间调整,这就纯粹是编码的活了。 |