作为人机交互最简单的方式,通过LED灯珠将信息显示出来无疑是仪器仪表行业最常用且成本低廉的方式。
这里给大家介绍下我常用的两颗驱动芯片ET6934和DP5125D,芯片资料网上一搜一大把,找不到的小伙伴可以私信我。
首先介绍下ET6934,这是一款恒流LED驱动控制电路,内部集成MCU数字接口、数据锁存器、LED恒流驱动模块,最多可以驱动8(段)*16(位)即128个LED灯珠。内部有专门的寄存器可以控制输出电流,可以非常方便的控制LED灯的亮度。数据传输通过I2C,控制起来非常方便。这颗芯片最牛逼的地方还是在它输出的电流你设定好了他就不会变,不受点亮的LED灯数量和输入电压变化而受影响。
典型应用电路:
硬件连接还是很简单的,I2C总线接上拉电阻就行,下面看下程序部分。
软件模拟I2C的程序相信大家都很熟悉了,单片机入门最先接触的就是他和串口。分3个信号:
起始信号:
/*****************************************************
*函数名称:void I2cStart()
*函数功能:启动i2c
*入口参数:void
*出口参数:void
*****************************************************/
void I2cStart(void)
{
I2C_SCL=1; //总线空闲时,SCL,SDA为高电平
I2C_SDA=1;
_nop_(); //SCL高电平保持 4.7US,拉低SDA,产生起始信号
_nop_();
_nop_();
_nop_();
I2C_SDA=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL=0;
_nop_();
}
应答信号:
/*****************************************************
*函数名称:bit I2cRecAck()
*函数功能:检查应答信号
*入口参数:void
*出口参数:ask
*****************************************************/
void I2cRecAck(void)
{
I2C_SDA=1; //主机主动释放SDA,为读ASK做准备
P1M3 = 0x41; //SDA改为输入
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL=0;
P1M3 = 0xC1; //应答结束后再将SDA改为输出
}
停止信号:
/*****************************************************
*函数名称:I2cStop(void)
*函数功能:停止I2C
*入口参数:void
*出口参数:void
*****************************************************/
void I2cStop(void)
{
I2C_SDA=0;
I2C_SCL=0;
_nop_();
_nop_();
I2C_SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SDA=1;
_nop_();
}
以上代码就是I2C通用的三种信号状态,小伙伴可以直接参考,亲测有效。接下来就是写入数据的时序的,这个时序需要看具体datasheet
/*****************************************************
*函数名称:I2cWriteByte(uchar dat)
*函数功能:写入一个字节
*入口参数:void
*出口参数:void
*****************************************************/
void I2cWriteByte(unsigned char dat)
{
unsigned char temp;//定义一个char类型
for(temp=0;temp<8;temp++)
{
if((dat&0X80)==0)
I2C_SDA=0;
else
I2C_SDA=1;
dat=dat<<1;
_nop_();
I2C_SCL=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL=0; //SCL低电平时,数据允许变化
_nop_();
}
}
/******************写入所有数据***********************/
void I2cWrAllData(unsigned char *p,unsigned char lengh)
{
unsigned char i;
for (i=0;i<lengh;i++) //发送最多16字节的显存数据
{
I2cWriteByte(*p); //写入数据
p++;
I2cRecAck();
}
}
/******************写完整数据***********************/
void I2cWrStruct(unsigned char *p,unsigned char length)
{
I2cStart();
I2cWriteByte(device_addr);//device_addr是宏定义好的芯片地址
I2cRecAck();
I2cWrAllData(p,length);
I2cStop();
}
然后我们就可以创建一个20字节长度的数组,管理这些灯珠的亮灭状态了,通常会列一个真值表方便写程序,因为6934是带锁存的,所以你要隔一段时间重新对他来赋值。
接下来看下DP5125D这颗芯片,首先还是先介绍硬件,硬件是软件的基础,一定要确保自己的硬件电路是没有问题的再写软件,不然找问题会把自己找绝望的,哪怕是一颗小小的采样电阻。细心的小伙伴会发现这个芯片没有SEG口,只有GRID口,所以还需要有个推的大电流的SEG口,下面我用一个我做过的老年代步车的项目电路来帮助大家理解。
MCU电路连接:
驱动芯片周边连接:
SEG口推电流电路:
双8字数码管内部电路图
细心的小伙伴会发现这不是用I2C进行数据传输了,这就要详细的看下datasheet中的时序图:
这幅图最主要的就是数据在芯片内部是SCK上升沿进行写入
代码如下:
void write_byte(unsigned int dat)//单字节数据写入
{
unsigned int i;
YB_DCK = 0;
YB_LAT = 0;
YB_PDM = 0;
for(i=0;i<16;i++)//最长16字节写入
{
if((dat &0x8000)==0)
YB_DI =0;
else
YB_DI =1;
YB_DCK = 1;//上升沿写入
dat = dat<<1;
YB_DCK = 0;//SCK再设置为低,为下一步做准备
}
}
void data_output(unsigned char num)//输出数据写入
{
write_byte(SLEDDSP[num]);
YB_LAT = 1;//串行锁存信号输入
YB_LAT = 0;
YB_PDM = 1;//输出使能信号输入
YB_PDM = 0;
}
void LedScan()//LED扫描函数,此处可以修改扫描时间
{
unsigned char i;
YC1=1;
YC2=1;
if(LedReady)//ready标志位
{
LedReady=0;
for(i=1;i<3;i++)
{
SLEDDSP[i]=LEDDSP[i];//数组
}
}
data_output(SegNumber);
if(SegNumber==1)YC1=0;
if(SegNumber==2)YC2=0;
if(++SegNumber>2)
{
SegNumber=1;
}
}
再在主函数里调用,LED扫描函数放在100ms周期内就100ms扫一次,我的项目是2个SEG口在扫,每1ms扫描一次,所以亮度会比较亮并且显示很丝滑。扫的SEG口越多,亮度越暗,但是此时要注意不能太长时间才进行一次LED扫描,否则显示看起来会非常的卡顿。