为了做到能拍照及录像不频闪,所以选择定时器设置每250us做一次灯扫描,然后每扫完所有灯后做一次按键扫描。
一、变量设计
1、按键
共6行21列,创建一个数组,数组共6个元素,每个元素4个字节:
#define KEY_ROW 6u
#define KEY_COL 21u
u32 KeyMap[KEY_ROW];
每个元素里包含21列的IO状态,设计为从最低位开始,依次表示第1列到第21列IO状态;
2、灯光
共12COM、9SEG,创建一个结构体数组,数组共12*9=108个元素,每个元素的结构体由r、g、b三个变量组成:
#define RGB_SEG 9
#define RGB_COM 12
#define RGB_NUM (RGB_SEG*RGB_COM)
typedef struct
{
u8 r;
u8 g;
u8 b;
}RGB_STRUCT;
RGB_STRUCT RGBMgr[RGB_NUM];
这里r、g、b的排列根据实际硬件排布决定,有些走线可能是gbr之类的顺序;
3、当前灯光扫描的COM索引
u8 CathodeCom@(0x00);
这里使用了强制指定地址,为了方便后面的汇编使用。
二、代码设计
1、初始化
将所有变量初始化,按键初始化0XFFFFFFFF,其余初始化为0;pwm初始化为频率20KHz以上、周期寄存器设置为255,定时器设置250us;此处就不贴代码了,硬件初始化每个芯片不一样;
2、灯光扫描
步骤:
1、关闭所有的PMOS,也就是COM的IO输出高电平;
2、COM索引指向的RGB结构体里的值赋值到PWM占空比寄存器;此时最好是能重新启动PWM。
3、打开索引指向的PMOS,索引+1,结束;
static uc8 CathodeTab[RGB_COM*3]=
{
B(11011111),B(11111111),B(11111111),
B(10111111),B(11111111),B(11111111),
B(01111111),B(11111111),B(11111111),
B(11111111),B(11111110),B(11111111),
B(11111111),B(11111101),B(11111111),
B(11111111),B(11111011),B(11111111),
B(11111111),B(11110111),B(11111111),
B(11111111),B(11101111),B(11111111),
B(11111111),B(11011111),B(11111111),
B(11111111),B(10111111),B(11111111),
B(11111111),B(01111111),B(11111111),
B(11111111),B(11111111),B(11111101),
};
void RGBMgr_Cathode(void)
{
//PWM1、PWM2输出低电平
PWM2RLDEN = 0X55;
PWM2EN = 0; //关闭PWM2使能
TC1EN = 0; //关闭定时器1使能,PWM1所有已使能的模块将强制输出无效电平
//关闭COM(COM切为输入上拉,PNP此处可能需要改为输出高电平,以加快PNP关闭速度)
OEA1 = 0;
OEE = 0;
OED = 0;
//更新PWM2占空比
u8 *pDuty = &RGBMgr[M(CathodeCom,0)].r;
PWM2_0PL = *pDuty++;
PWM2_0NL = *pDuty++;
PWM2_1PL = *pDuty++;
PWM2_1NL = *pDuty++;
PWM2_2PL = *pDuty++;
PWM2_2NL = *pDuty++;
//更新PWM1占空比
u8 *ptr = PWM1DL_BaseAddr;
for(u8 i=0;i<PWM1_NUM;i++)
{
*ptr = *pDuty++;
ptr -= 2;
}
//COM端输出状态
IOD &= CathodeTab[CathodeCom*3];
IOE &= CathodeTab[CathodeCom*3 + 1];
IOA &= CathodeTab[CathodeCom*3 + 2];
//打开定时器1、PWM2使能
PWM2EN = 1;
PWM2RLDEN = 0XAA;
TC1EN = 1;
//COM设为输出端口
OEA1 = 1;
OEE = 0XFF;
OED = 0XFF;
if(++CathodeCom>=RGB_COM)
{
CathodeCom=0;
}
}
这段主要是利用一个const数组来改变PMOS的状态,其余大部分为硬件操作。
3、按键扫描
在灯光扫描完一轮后,做一次按键扫描,依次将每个行输出低电平,列IO做上拉输入,按键按下会读到低电平,否则为高电平;
按键矩阵扫描基本操作了,这里就不贴代码了。
4、汇编
上述的所有代码是用C写的,但由于运行时间过长,实际灯光帧数较低,在拍照或者录像都会有严重频闪,所以最终将所有的C转成了汇编,并优化了代码时间,由原来的运行时间200us缩减至25us,基本能保证在拍照以及正常录像下不频闪,由于汇编的助记符和PIC18的完全不同,所以这里就不贴出来了。