一、判断现在手里头买的是共阴还是共阳数码管
我们可使用万用表进行最简单判断,将万用表调到二极管档,
(1)万用表笔随便一脚,假设红笔, 搭在数码管上任一脚 。黑笔在其它脚上扫过,如果不亮,有可能此管为共阴,可用2法再试。如有一段点亮。黑笔不动, 移动红笔,在其它脚测。如果其它脚 分别都 能点亮,则可以说明黑笔接的是公共脚 ,此管共阳。(指针 表的黑表笔是正电源)
(2)表笔更换一下,黑笔先搭一脚,扫红笔。如有一段点亮,红笔不动,扫黑笔。如各段分别点亮,则红笔所接为公共 ,此管共阴
二、段选与位选
多位一体数码管,内部的公告端是独立的,我们把公共端叫做位选线
负责显示什么数字的线全部都是连接在一起,我们把这个叫做段选线
三、现在使用大部分都直接使用驱动芯片了,所以我们重点来讲驱动芯片的使用
网上搜一搜 ,比如tm1650就是一个8*4驱动,可以驱动4位数码管,采用的IIC通讯
当时开发用的中微的芯片,所以在此我就拿中微的CMS1650来写,其实他跟TM1650都是一样的,数码管驱动芯片大同小异,掌握一款其他就都会了。
三、CMS1650
1、概述
方便使用,电路设计便捷,工作电压又低,堪称完美
2、管脚
管脚分布图DIG就是位选,其他就是段选
3、通讯协议
通讯协议采用的是IIC通讯协议。我们可以看看规格书,规格书我上传了。
(1)先来看看规格书写的协议的开始的信号与停止信号
启始信号,在SCL为高电平期间,SDA出现下降沿现象;
考虑代码整洁性,我们可以先进行宏定义
#define CLS_CMS_SCL P0_4 = 0 //时钟拉低 #define SET_CMS_SCL P0_4 = 1 //时钟拉高 #define SET_CMS_SDA P0_5 = 1 //数据拉低 #define CLS_CMS_SDA P0_5 = 0 //数据拉高
#define CLK P0_4 #define SDA P0_5
#define SDA_OUT() {P0TRIS |= 0x20;P0 |= 0x20; } #define SDA_INT() {P0TRIS &= 0xDF;P0UP |=0x20;}
void LED_Init(void) { P0TRIS |= 0x10; //设置P04输出 SCL P0 |= 0x10; //输出高 P0TRIS |= 0x20; //设置P05输出 SDA P0 |= 0x20; //输出高 }
void CMS1650_Start(void) //SCL 为“1”,SDA 从“1”跳“0”,认为是开始信号 { SDA_OUT();//设置/SCL、SDA 为输出脚 SET_CMS_SCL; SET_CMS_SDA; delay_us(5); CLS_CMS_SDA; delay_us(5); CLS_CMS_SCL;//钳住I2C总线,准备发送或接收数据,(IIC规定只有在SCL为低电平期间,数据线上才允许高低变化,所以开始信号启动后,拉低SCL) }
void CMS1650_Stop(void) // SCL 为“1”电平,SDA 从“0”跳“1”,认为是结束信号 { SDA_OUT(); SET_CMS_SCL; CLS_CMS_SDA; delay_us(5); SET_CMS_SDA; delay_us(5);//停止信号,就不用把SCL拉低 }
(2)应答信号
应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉低说明数据传输正确,产生应答。
所以我们代码应该这样写,传输完数据后,得先释放数据线;再将SCL拉高,判断低电平是否到来。
//等待从机应答信号到来 //返回值:1,接收应答失败 // 0,接收应答成功 u8 CMS1650_Wait_Ack(void) { u16 time = 0; SDA_INT();//将SDA设置为上拉输入 ,主机释放数据总线(总线在空闲状态为高电平)等待从机产生应答信号 SET_CMS_SCL;delay_us(1); // SCL拉高 while(SDA == 1)//在while循环延时这段时间内,看丛机是否有产生应答信号,有的话SDA就=0,跳出循环 { time++; if(time>255)//从机没应答,传输失败 { CMS1650_Stop(); return 1; //有必要的话显示或者产生个中断说明传输失败,跳出循环。注:return可以可以跳出while循环
continue:不跳出当前循环,结束本次循环(结束当前循环),执行下一轮循环 break:跳出当前循环,结束该循环执行 } } CLS_CMS_SCL; return 0; }
(3)写入数据
void CMS1650_SendByte(u8 txd) { u8 t = 0; // SDA_OUT(); // CLS_CMS_SCL;//拉低时钟开始数据传输 ,开始信号已经拉低SCL了,这里可以不用写了 for(t=0;t<8;t++) { if((txd&0x80)>>7) SET_CMS_SDA; else CLS_CMS_SDA; txd<<=1; delay_us(5); SET_CMS_SCL;//数据发送完,拉高时钟 delay_us(5); CLS_CMS_SCL;//拉低时钟开始数据传输 delay_us(5); } }
对于数据的写入为啥要SCL 从“0”跳到“1”,再从“1”跳到“0”这么写,我们来看看接收方是怎么接收就一目了然了;
从设备收数据:主设备发送了开始位后,把clk拉低,只有clk拉低,sda才可以做高低变化; 当clk被拉高时,(0->1)从设备就会去读取sda的高低电平值;clk再次被拉低时,(1->0)从设备认为此位已读取完毕,认为是有效位,等待clk再次拉高,读取下一位。
(4)一个完整的写显示时序
首先得先写入数据命令,然后开显示确定显示的亮度
8段显示的话就是小数点也显示出来
再来确定显存地址(确定位选地址)
最后
void main() {
u8 t = 0;
LED_Init(); //SCL SDA 设置为输出
delay_ms(300); //延时一段时间,否则开显示无响应
CMS1650_SendByte(0x48);
CMS1650_Wait_Ack();//等待应答
//这里应答处理,看大家要做什么处理,这里应答处理我就先不作处理
CMS1650_SendByte(0x30);//开显示:3级亮度
CMS1650_Wait_Ack();//等待应答 CMS1650_Stop();
CMS1650_WriteByte(0x6E,0x7f); CMS1650_WriteByte(0x6C,0x7f); CMS1650_WriteByte(0x6A,0x7f); CMS1650_WriteByte(0x68,0x7f);//开机8888
//单片机上电数码管显示8.8.8.8.
}
void LED_Init(void) { P0TRIS |= 0x10; //设置P04输出 SCL P0 |= 0x10; //输出高 P0TRIS |= 0x20; //设置P05输出 SDA P0 |= 0x20; //输出高 } void CMS1650_Start(void) //SCL 为“1”,SDA 从“1”跳“0”,认为是开始信号 { SDA_OUT(); SET_CMS_SCL; SET_CMS_SDA; delay_us(5); CLS_CMS_SDA; delay_us(5); CLS_CMS_SCL;//钳住I2C总线,准备发送或接收数据 } void CMS1650_Stop(void) // SCL 为“1”电平,SDA 从“0”跳“1”,认为是结束信号 { SDA_OUT(); SET_CMS_SCL; CLS_CMS_SDA; delay_us(5); SET_CMS_SDA; delay_us(5); }
//等待从机应答信号到来 //返回值:1,接收应答失败 // 0,接收应答成功 u8 CMS1650_Wait_Ack(void) { u16 time = 0; SDA_OUT(); SET_CMS_SDA;delay_us(1);//主机释放数据总线,(总线在空闲状态为高电平)等待从机产生应答信号 SET_CMS_SCL;delay_us(1); SDA_INT();//将SDA设置为上拉输入 while(SDA == 1)//在while循环延时这段时间内,看丛机是否有产生应答信号,有的话SDA就=0,跳出循环 { time++; if(time>255)//从机没应答,传输失败 { CMS1650_Stop(); return 1; //有必要的话显示或者产生个中断说明传输失败 } } CLS_CMS_SCL; return 0; }
void CMS1650_SendByte(u8 txd) { u8 t = 0; // SDA_OUT(); // CLS_CMS_SCL;//拉低时钟开始数据传输 ,开始信号已经拉低SCL了,这里可以不用写了 for(t=0;t<8;t++) { if((txd&0x80)>>7) SET_CMS_SDA; else CLS_CMS_SDA; txd<<=1; delay_us(5); SET_CMS_SCL;//数据发送完,拉高时钟 delay_us(5); CLS_CMS_SCL;//拉低时钟开始数据传输 delay_us(5); } }
void CMS1650_WriteByte(u8 Addr,u8 Data) { CMS1650_Start(); CMS1650_SendByte(Addr); CMS1650_Wait_Ack();//等待应答 CMS1650_SendByte(Data); CMS1650_Wait_Ack();//等待应答 CMS1650_Stop(); }