在一块LED显示模块上发现了这个MC2302D控制芯片,查了一下,功能比较强大,控制使用也是比较简单,鉴于一开始没有找到太多的相关资料,故决定分享下来。
可以看到这个模块有很多的LED,都可以单独控制的哦,,控制芯片有两个MC2302D,控制线有4根,分别对应公共数据(DIN),公共时钟(CLK),片选1(STB1),片选2(STB2),VCC,GND不用说,电源引脚,供电范围2.7 - 5.5V。用来制作多功能仪表盘是再合适不过了,当然了,做个时钟也不错,不过只能用12小时制(为啥?因为最大18:88),配合功能窗指示上午,下午。
这里我用的STM32主控,以下是具体引脚
介绍MC2302D
首先去官网把相应的数据手册下载下来,看一下相关功能,引脚等
前面介绍就这么多,大家可以看看,也没什么解释的,很容易理解
驱动时序
说白了和SPI一样,片选拉低,DIN数据在时钟线拉低时候赋值就写入,DOUT平时拉高,DIN写入一个字节后芯片输出DOUT数据,具体细节可看SPI协议。DIN是写命令和数据的,DOUT只是用来读按键状态的,如果未接按键,可不用管DOUT引脚。
协议说明
一共4条命令,分别对应显示设置命令,数据设置命令,地址设置命令,显示控制命令。
显示设置命令,这部分和硬件设计有关,具体选择几位几段根据实际情况来,我这里使用了7位11段 (#0000_0011B)。
数据设置命令,设置数据写入方式设置,地址增量方式设置和方式设置。和功能需求有关,我这里只用到了写(#0100_0000B)。
地址设置命令,显示存储器有地址设置命令寻址,就是寻址偏移量,和硬件设计,以及功能显示有关,我这里从默认的00 开始寻址(#1100_0000B)。接着就是跟14 个8位数据,(根据官方给的程序,最多14段)。
显示控制命令,就是用来开启或关闭显示器,同时可以设8级脉冲宽度(其实是7级,000时候关闭显示),对应不同的亮度,2/16最暗,14/16最亮。
官方示例代码
void Make_Signal()
{
STB=1;
CLK=1;
for(i=0; i<8; i++) //command 1 (#0000_0011B)
{
STB=0;
CLK=0;
if(i==1 || i==0)
DIN=1;
else
DIN=0;
CLK=1;
}
STB=1;
for(i=0; i<8; i++) //command 2 (#0100_0000B)
{
STB=0;
CLK=0;
if(i==6)
DIN=1;
else
DIN=0;
CLK=1;
}
STB=1;
for(i=0; i<8; i++) //command 3 (#1100_0000B)
{
STB=0;
CLK=0;
if(i==6 || i==7)
DIN=1;
else
DIN=0;
CLK=1;
}
/*
for(i=0; i<112; i++) //data 14*8个,初始化赋0值
{
STB=0;
CLK=0;
DIN=0;
CLK=1;
}
STB=1;
*/
for(i=0; i<14; i++) //显示数据,操作seg_data[14]这个数组,即可进行相应的显示。
{
for(j=0; j<8; j++)
{
STB=0;
CLK=0;
DIN=seg_data[i] & comp_seg;
CLK=1;
seg_data[i]=seg_data[i]/2;
}
}
STB=1;
for(i=0; i<8; i++) //command 4 (#1000_0100B)
{
STB=0;
CLK=0;
switch(f_dimming) //PWM亮度调节 f_dimming 0-7 0默认最亮
{
case(0):
if(i==3 || i==7|| i==2 || i==1|| i==0)
DIN=1;
else
DIN=0;
break;
case(1):
if(i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(2):
if(i==1 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(3):
if(i==1 || i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(4):
if(i==2 ||i==3 || i==7)
DIN=1;
else
DIN=0;
break;
case(5):
if(i==2 || i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(6):
if(i==2 || i==1 ||i==3 || i==7)
DIN=1;
else
DIN=0;
break;
case(7):
if(i==2 || i==1 || i==0 ||i==7)
DIN=1;
else
DIN=0;
break;
}
CLK=1;
}
STB=1;
}
修改驱动代码
其实挺简单的,就是发送 cmd_1 ,cmd_2, cmd_3 14*8数据,cmd_4。稍加修改如下:
void Make_Signal_1(void)
{
uchar i, j;
uchar dis_data = 0;
STB_1=1;
CLK=1;
for(i=0; i<8; i++) //command 1 (#0000_0011B)
{
STB_1=0;
CLK=0;
if(i==1 || i==0)
DIN=1;
else
DIN=0;
CLK=1;
}
STB_1=1;
for(i=0; i<8; i++) //command 2 (#0100_0000B)
{
STB_1=0;
CLK=0;
if(i==6)
DIN=1;
else
DIN=0;
CLK=1;
}
STB_1=1;
for(i=0; i<8; i++) //command 3 (#1100_0000B)
{
STB_1=0;
CLK=0;
if(i==6 || i==7)
DIN=1;
else
DIN=0;
CLK=1;
}
/*
for(i=0; i<112; i++) //data
{
STB_1=0;
CLK=0;
DIN=0;
CLK=1;
}
STB_1=1;
*/
for(i=0; i<14; i++)
{
dis_data = seg_data_1[i];
for(j=0; j<8; j++)
{
STB_1=0;
CLK=0;
DIN=dis_data & 0x01;
CLK=1;
dis_data = dis_data>>1;//右移一位
}
}
STB_1=1;
for(i=0; i<8; i++) //command 4 (#1000_0100B)
{
STB_1=0;
CLK=0;
switch(f_dimming_1) //显示亮度模式
{
case(0):
if(i==3 || i==7|| i==2 || i==1|| i==0)
DIN=1;
else
DIN=0;
break;
case(1):
if(i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(2):
if(i==1 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(3):
if(i==1 || i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(4):
if(i==2 ||i==3 || i==7)
DIN=1;
else
DIN=0;
break;
case(5):
if(i==2 || i==0 || i==3 ||i==7)
DIN=1;
else
DIN=0;
break;
case(6):
if(i==2 || i==1 ||i==3 || i==7)
DIN=1;
else
DIN=0;
break;
case(7):
if(i==2 || i==1 || i==0 ||i==7)
DIN=1;
else
DIN=0;
break;
}
CLK=1;
}
STB_1=1;
}
结合模块进行显示
具体断码显示不再赘述,整理如下
uchar f_dimming_1 = 0; //亮度可调 1-7级 0默认 最亮
uchar f_dimming_2 = 0; //亮度可调 1-7级 0默认 最亮
uchar Font_Data[10]={0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F}; //数码管
uchar Font_point[4]={0x00, 0x03, 0x01, 0x02}; //数码管 点
uchar RGY_DIS[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //红1绿1黄1 红2绿2黄2
uchar seg_data_1[14]={0};//缓存数组
uchar seg_data_2[14]={0};//缓存数组
数码管部分使用Font_Data,和Font_point,进行显示,对于杂点,则进行了重新分布设置,这样使用宏定义即可实现对其控制亮灭。
//置位 点亮
//中间杂点
#define DIS1_SET_1 seg_data_1[10]=(seg_data_1[10]|0X01)
#define DIS1_SET_2 seg_data_1[10]=(seg_data_1[10]|0X02)
#define DIS1_SET_3 seg_data_1[7] =(seg_data_1[7] |0X04)
#define DIS1_SET_4 seg_data_1[10]=(seg_data_1[10]|0X04)
#define DIS1_SET_5 seg_data_1[10]=(seg_data_1[10]|0X08)
#define DIS1_SET_6 seg_data_1[9] =(seg_data_1[9] |0X04)
#define DIS1_SET_7 seg_data_1[0] =(seg_data_1[0] |0X80)
#define DIS1_SET_8 seg_data_1[2] =(seg_data_1[2] |0X80)
#define DIS1_SET_9 seg_data_1[4] =(seg_data_1[4] |0X80)
#define DIS1_SET_10 seg_data_1[5] =(seg_data_1[5] |0X01)
#define DIS1_SET_11 seg_data_1[11]=(seg_data_1[11]|0X04)
#define DIS1_SET_12 seg_data_1[5] =(seg_data_1[5] |0X02)
#define DIS1_SET_13 seg_data_1[10]=(seg_data_1[10]|0X10)
#define DIS1_SET_14 seg_data_1[10]=(seg_data_1[10]|0X20)
#define DIS1_SET_15 seg_data_1[10]=(seg_data_1[10]|0X40)
#define DIS1_SET_16 seg_data_1[10]=(seg_data_1[10]|0X80)
#define DIS1_SET_17 seg_data_1[11]=(seg_data_1[11]|0X01)
#define DIS1_SET_18 seg_data_1[11]=(seg_data_1[11]|0X02)
//左右点
#define DIS2_SET_1 seg_data_1[6]=(seg_data_1[6] |0X01)
#define DIS2_SET_2 seg_data_1[6]=(seg_data_1[6] |0X02)
#define DIS2_SET_3 seg_data_1[6]=(seg_data_1[6] |0X04)
#define DIS2_SET_4 seg_data_1[6]=(seg_data_1[6] |0X08)
#define DIS2_SET_5 seg_data_1[6]=(seg_data_1[6] |0X10)
#define DIS2_SET_6 seg_data_1[6]=(seg_data_1[6] |0X20)
#define DIS2_SET_7 seg_data_1[6]=(seg_data_1[6] |0X40)
#define DIS2_SET_8 seg_data_1[6]=(seg_data_1[6] |0X80)
#define DIS2_SET_9 seg_data_1[7]=(seg_data_1[7] |0X01)
#define DIS2_SET_10 seg_data_1[7]=(seg_data_1[7] |0X02)
#define DIS2_SET_11 seg_data_1[8]=(seg_data_1[8] |0X01)
#define DIS2_SET_12 seg_data_1[8]=(seg_data_1[8] |0X02)
#define DIS2_SET_13 seg_data_1[8]=(seg_data_1[8] |0X04)
#define DIS2_SET_14 seg_data_1[8]=(seg_data_1[8] |0X08)
#define DIS2_SET_15 seg_data_1[8]=(seg_data_1[8] |0X10)
#define DIS2_SET_16 seg_data_1[8]=(seg_data_1[8] |0X20)
#define DIS2_SET_17 seg_data_1[8]=(seg_data_1[8] |0X40)
#define DIS2_SET_18 seg_data_1[8]=(seg_data_1[8] |0X80)
#define DIS2_SET_19 seg_data_1[9]=(seg_data_1[9] |0X01)
#define DIS2_SET_20 seg_data_1[9]=(seg_data_1[9] |0X02)
//置0 熄灭
//中间杂点
#define DIS1_CLR_1 seg_data_1[10]=(seg_data_1[10]&(~0X01))
#define DIS1_CLR_2 seg_data_1[10]=(seg_data_1[10]&(~0X02))
#define DIS1_CLR_3 seg_data_1[7] =(seg_data_1[7] &(~0X04))
#define DIS1_CLR_4 seg_data_1[10]=(seg_data_1[10]&(~0X04))
#define DIS1_CLR_5 seg_data_1[10]=(seg_data_1[10]&(~0X08))
#define DIS1_CLR_6 seg_data_1[9] =(seg_data_1[9] &(~0X04))
#define DIS1_CLR_7 seg_data_1[0] =(seg_data_1[0] &(~0X80))
#define DIS1_CLR_8 seg_data_1[2] =(seg_data_1[2] &(~0X80))
#define DIS1_CLR_9 seg_data_1[4] =(seg_data_1[4] &(~0X80))
#define DIS1_CLR_10 seg_data_1[5] =(seg_data_1[5] &(~0X01))
#define DIS1_CLR_11 seg_data_1[11]=(seg_data_1[11]&(~0X04))
#define DIS1_CLR_12 seg_data_1[5] =(seg_data_1[5] &(~0X02))
#define DIS1_CLR_13 seg_data_1[10]=(seg_data_1[10]&(~0X10))
#define DIS1_CLR_14 seg_data_1[10]=(seg_data_1[10]&(~0X20))
#define DIS1_CLR_15 seg_data_1[10]=(seg_data_1[10]&(~0X40))
#define DIS1_CLR_16 seg_data_1[10]=(seg_data_1[10]&(~0X80))
#define DIS1_CLR_17 seg_data_1[11]=(seg_data_1[11]&(~0X01))
#define DIS1_CLR_18 seg_data_1[11]=(seg_data_1[11]&(~0X02))
//左右点
#define DIS2_CLR_1 seg_data_1[6]=(seg_data_1[6] &(~0X01))
#define DIS2_CLR_2 seg_data_1[6]=(seg_data_1[6] &(~0X02))
#define DIS2_CLR_3 seg_data_1[6]=(seg_data_1[6] &(~0X04))
#define DIS2_CLR_4 seg_data_1[6]=(seg_data_1[6] &(~0X08))
#define DIS2_CLR_5 seg_data_1[6]=(seg_data_1[6] &(~0X10))
#define DIS2_CLR_6 seg_data_1[6]=(seg_data_1[6] &(~0X20))
#define DIS2_CLR_7 seg_data_1[6]=(seg_data_1[6] &(~0X40))
#define DIS2_CLR_8 seg_data_1[6]=(seg_data_1[6] &(~0X80))
#define DIS2_CLR_9 seg_data_1[7]=(seg_data_1[7] &(~0X01))
#define DIS2_CLR_10 seg_data_1[7]=(seg_data_1[7] &(~0X02))
#define DIS2_CLR_11 seg_data_1[8]=(seg_data_1[8] &(~0X01))
#define DIS2_CLR_12 seg_data_1[8]=(seg_data_1[8] &(~0X02))
#define DIS2_CLR_13 seg_data_1[8]=(seg_data_1[8] &(~0X04))
#define DIS2_CLR_14 seg_data_1[8]=(seg_data_1[8] &(~0X08))
#define DIS2_CLR_15 seg_data_1[8]=(seg_data_1[8] &(~0X10))
#define DIS2_CLR_16 seg_data_1[8]=(seg_data_1[8] &(~0X20))
#define DIS2_CLR_17 seg_data_1[8]=(seg_data_1[8] &(~0X40))
#define DIS2_CLR_18 seg_data_1[8]=(seg_data_1[8] &(~0X80))
#define DIS2_CLR_19 seg_data_1[9]=(seg_data_1[9] &(~0X01))
#define DIS2_CLR_20 seg_data_1[9]=(seg_data_1[9] &(~0X02))
如代码,除去数码管,全部点亮
具体驱动应用
到了这一步,驱动显示部分已经完了,接下来驱动显示时间即可,值得注意的是,第一个芯片使用seg_data_1[]数组的每个数据控制不同的显示,0-5为数码管使用和中间杂点7 8 9号这3个使用,具体 ,0 2 4 为3个完整数码管和杂点7 8 9号(,数码管使用7段,杂点一段,如果不使用这3个点,忽略即可),1为第一位“1”使用,3为中间“:”使用,6-11则为中间杂点和两侧使用,12,13未使用。
四周RGY彩灯使用第二个芯片,seg_data_2[]数组,
0 Red1 ,2 Green1 ,4 Yellow1 ,6 Red2 ,8 Green1 ,10 Yellow2 ,其他未使用 。
seg_data_1[1]=Font_point[time_data.hour/10]; //时的十位
seg_data_1[0]=Font_Data[time_data.hour%10]; //时的个位
seg_data_1[2]=Font_Data[time_data.min/10]; //分的十位
seg_data_1[4]=Font_Data[time_data.min%10]; //分的个位
if(time_data.AM_PM) //上午
{
DIS1_CLR_1 ;
DIS1_CLR_2 ;
DIS1_CLR_3 ;
DIS1_SET_4 ;
DIS1_SET_5 ;
DIS1_SET_6 ;
}
else //下午
{
DIS1_SET_1 ;
DIS1_SET_2 ;
DIS1_SET_3 ;
DIS1_CLR_4 ;
DIS1_CLR_5 ;
DIS1_CLR_6 ;
}
if(sec1 != time_data.sec) //时分之间的点,每隔一秒闪烁
{
sec_point = 1 - sec_point;
seg_data_1[3]=Font_point[sec_point];
sec1 = time_data.sec;
}
Make_Signal_1(); //显示数据
加上彩灯
至于控制彩色流水灯,相关代码例程很多,不再赘述,如下随便截取一点
uchar RGY_DIS[6]={0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; //红1绿1黄1 红2绿2黄2
uchar table0[] = {0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f}; //LED从低位往高位移
uchar table1[] = {0x7f, 0xbf, 0xdf, 0xef, 0xf7, 0xfb, 0xfd, 0xfe}; //LED从高位往低位移
uchar table2[] = {0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80, 0x00}; //LED从1个亮到8个都点亮(从低位往高位)
uchar table3[] = {0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01, 0x00}; //LED从1个亮到8个都点亮(从高位往低位)
uchar table4[] = {0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff}; //LED从8个全亮到一个都不亮(从低位往高位)
uchar table5[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff}; //LED从8个全亮到一个都不亮(从高位往低位)
uchar table6[] = {0xfe, 0xfc, 0xfa, 0xf6, 0xee, 0xde, 0xbe, 0x7e}; //LED从低位往高位移(最低位始终为0)
uchar table7[] = {0x7f, 0x3f, 0x5f, 0x6f, 0x77, 0x7b, 0x7d, 0x7e}; //LED从高位往低位移(最高位始终为0)
uchar i, j; //定义循环变量
int tt = 70; //定义时间指数
void delay_tim(int time)
{
Make_Signal_2();
delay_ms(time);
seg_data_2[2] = seg_data_2[0];
seg_data_2[8] = seg_data_2[6];
Make_Signal_2();
delay_ms(time);
seg_data_2[4] = seg_data_2[0];
seg_data_2[10] = seg_data_2[6];
Make_Signal_2();
delay_ms(time);
}
void disp0() //状态0 所有LED闪烁3次
{
for(i=0;i<3;i++)
{
seg_data_2[0]=0x00; seg_data_2[6]=0x00;
delay_tim(300);
seg_data_2[0]=0xff; seg_data_2[6]=0xff;
delay_tim(300);
}
}
void disp1() //状态1 LED顺时针转一圈
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table1[i];
delay_tim(100);
}
seg_data_2[0]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[6]=table1[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
}
void disp2() //状态2 LED逆时针转一圈
{
for(i=0;i<8;i++)
{
seg_data_2[6]=table0[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[0]=table0[i];
delay_tim(100);
}
seg_data_2[0]=0xff;
}
void disp3() //状态3 4个LED同时顺时、逆时针移动1/4圈
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table1[i];
seg_data_2[6]=table0[i];
delay_tim(100);
}
for(i=0;i<8;i++)
{
seg_data_2[0]=table0[i];
seg_data_2[6]=table1[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
}
void disp4() //状态4 2个LED同时顺时针移动半圈
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table1[i];
delay_tim(100);
}
seg_data_2[0]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[6]=table1[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
}
void disp5() //状态5 2个LED同时逆时针移动半圈
{
for(i=0;i<8;i++)
{
seg_data_2[6]=table0[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[0]=table0[i];
delay_tim(100);
}
seg_data_2[0]=0xff;
}
void disp6() //状态6 LED自上而下逐渐点亮(一半点亮一半不亮)
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table3[i];
delay_tim(100);
}
seg_data_2[0]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[6]=table3[i];
delay_tim(100);
}
seg_data_2[6]=0xff;
}
void disp7() //状态7 LED自下而上逐渐点亮(直到全部点亮)
{
for(i=0;i<8;i++)
{
seg_data_2[6]=table2[i];
delay_tim(100);
}
for(i=0;i<8;i++)
{
seg_data_2[0]=table2[i];
delay_tim(100);
}
}
void disp8() //状态8 间断8格的4个LED亮并逆时针旋转
{
for(j=0;j<2;j++)
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table0[i];
seg_data_2[6]=table0[i];
delay_tim(100);
}
seg_data_2[0]=0xff; seg_data_2[6]=0xff;
for(i=0;i<8;i++)
{
seg_data_2[0]=table0[i];
seg_data_2[6]=table0[i];
delay_tim(100);
}
seg_data_2[0]=0xff; seg_data_2[6]=0xff;
}
}
void disp9() //状态9 间断8格的4个LED亮,然后逆时针逐渐点亮(直到全部点亮)
{
for(i=0;i<8;i++)
{
seg_data_2[0]=table2[i];
seg_data_2[6]=table2[i];
delay_tim(100);
}
delay_tim(500);
}
相关资料下载