2个74HC595控制2个8×8点阵,显示3位数字,想用2个74HC595控制2个8×8点阵,显示3位数字,但这3个数字要互不干扰,如图,显示2位数字会做,但是显示3位的就不知道怎么下手了,没有思路,就像控制8位数码管的小数点亮一下灭一下,而不影响其数字的显示一样,这个问题我也不知道怎么解决,求各位大佬给点思路,怎么写这个驱动程序,小弟不胜感激,谢谢各位。
,如果每个数字字符使用5*8的点阵表达(有一个空白列作为间隔),三个数字占用15列像素。两个595可以表达两个字节计16位,绝对是够用了。但这就要求你自己重新设计所有数字、字母的点阵数据了,以适应5*8的方式。你给的图片中1、2、3,使用了5*8的点阵方式.
我个人建议你建立4*7点阵模式,因为要考虑数字中间的空白间隔。使用5*8导致太紧凑,不好看。,3位数字可自由控制,我很想知道,你两个595怎么驱动16*8点的?正反都驱动?
说说你的问题,你可以开辟一个16字节的数组,分别对应每一列。595就负责把每一列的字节显示到16*8点LED上去,这样,至于你显示什么图案,那就跟595无关了。你只需要往数组里面填充字节值就行了。
具体操作,建议你学习《人人学会单片机》视频教程,第13、14、15、16课程,就是这样操作的。,
人人学会单片机 发表于 2020-12-31 11:35
我很想知道,你两个595怎么驱动16*8点的?正反都驱动?
说说你的问题,你可以开辟一个16字节的数组,分别 …
行扫描我没有写出来,两个595是列扫描,如果2个595只显示2个数字,我会写驱动,但是2个595要显示3个数字,我没不知道怎么写了,请赐教,
suncat0504 发表于 2021-1-3 14:17
如果每个数字字符使用5*8的点阵表达(有一个空白列作为间隔),三个数字占用15列像素。两个595可以表达两个 …
2个595是16位,每次发8位,如果只显示2位数字,那好办,我不明白的是如何把16位原本显示两位数字的拆成显示3位数字,就是说我只能用一个595来控制显示1位数字,如果要让2个595来显示3位数,这个就不懂了,不知道怎么写这个驱动程序, 本帖最后由 suncat0504 于 2021-1-5 18:41 编辑
dcjdcj 发表于 2021-1-3 20:32
2个595是16位,每次发8位,如果只显示2位数字,那好办,我不明白的是如何把16位原本显示两位数字的拆成显 …
原理我已经和你说了。点阵显示数字字符,无非就是逐行逐列把像素点的数据传递给显示部件。
一个595对应一个字节,就是8个bit位。两个对应16个Bit位。当每个字符、数字占用一个字节8Bit位的时候,每个595一次只能显示一个一行8列的像素点,逐行扫描,视觉暂留现象,呈现出一个完整的字符。
当一个字符使用4×8方式显示的的时候。这个字符每一行占用4个像素点,共8行就能完整显示一个字符。那么两个595,就能同时显示4个字符了。实际使用,为了避免太紧凑,我加了一行空白行,就是全0的那行。数字之间间隔一个空白列,数字最后还有一个空白咧,就是在垂直方向上全都为0的那些列。
比如,使用我提供的点阵组合,对234这个数值的组合,我只用0和1来表达, 0表示不亮,1表示亮:
0 1234 5 6789 A BCDE F // 这行是以16进制表示Bit位的编号
——————————
0 0000 0 0000 0 0000 0 // 第0行 从这行开始,表示的是像素数据,0-不亮;1-亮;这样是空白行。
0 0110 0 0110 0 0110 0 // 第1行
0 1001 0 1001 0 1010 0 // 第2行
0 0001 0 0001 0 1010 0 // 第3行
0 0010 0 0010 0 1010 0 // 第4行
0 0100 0 0001 0 1110 0 // 第5行
0 1000 0 1001 0 0010 0 // 第6行
0 1111 0 0110 0 0010 0 // 第7行
你注意看由1组成的图形是不是2、3、4?
按照这个点阵数据,你只需要把每行的数据拆分为两个字节,分别提供给595即可。
这样。为了显示234,把以下数据逐行提供给两个595
0x00 0x00 // 第0行,,对应000000000000
0x31 0x8C // 第1行,对应0 0110 0 011 0 0 0110 0
0x4A 0x54 // 第2行 对应0 1001 0 1001 0 1010 0
0x08 0x54 // 第3行 对应0 0001 0 0001 0 1010 0
0x10 0x94 // 第4行 0 0010 0 0010 0 1010 0
0x20 0x5E // 第5行 0 0100 0 0001 0 1110 0
0x42 0x44 // 第6行 0 1000 0 1001 0 0010 0
0x79 0x84 // 第7行 0 1111 0 0110 0 0010 0
那么,在16*8的点阵LED上现实的就是234数字了。其中第0、5、A、F列是空白列。,
dcjdcj 发表于 2021-1-3 20:32
2个595是16位,每次发8位,如果只显示2位数字,那好办,我不明白的是如何把16位原本显示两位数字的拆成显 …
自己组织点阵数据对应数字,需要预先把每个数字的点阵数据以0和1的方式建立出数组,对4列8行,每个数字张勇一个二维数组,比如对于数字2的点阵数据:
pix[2]={{0,0,0,0},
{0,1,1,0},
{1,0,0,1},
{0,0,0,1},
{0,0,1,0},
{0,1,0,0},
{1,0,0,0},
{1,1,1,1}
}
把所有数字弄到一起,组成一个三维数组,方便按照下标定位数字所在元素,组成字节数据。
当需要显示234时,
先取第一行像素数据,依次把0、pix[2]的第0行像素的四列,0,pix[3]的第0行像素的前两列,0,共计8Bit位,放到第一个595
再取pix[3]的第0行像素的后两列,0,pix[4]的第0行像素的四列,0,共计8Bit位,放到第二个595中,
这样234的第一行就都被设置好了;接着是其他各行的像素数据,也按照这种方式组织并显示,最终,“234”就被显示出来了。
,实际上,pix也可以被定义为一位数组,而一位数组的每个元素是另一个二维数组(对应4 x 8的点阵数据)。这样处理,可能更容易一些。, 本帖最后由 suncat0504 于 2021-1-5 18:42 编辑
图片说明更容易理解,第五行16进制数错了,是0x20, 0x5E
, 本帖最后由 suncat0504 于 2021-1-4 23:26 编辑
如果不想用点阵模式保存,也可以用字节数据保存,比如
数字2的各行数值 pix[2] = {0, 6,9, 1, 2, 4, 8, 15}
数字3的各行数值 pix[3] = {0 6 , 9, 1, 2, 1, 9, 6 }
数字4的各行数值 pix[4] = {0, 6, 10, 10, 10, 15, 2, 2}
显示234的时候,第二行的点阵数据:
第一个595 = (pix[2][1]<<3) | (pix[3][1]>>2) ; // 6<<3 | 6>>2=49=0x31;
第一个595 = (pix[3][1]<<6) | (pix[4][1]<<1);; // 6<<6 | 6<<1=140=0x8c
这样的效果是一样的。(注意,移位操作,是不带进位的移位),
suncat0504 发表于 2021-1-4 23:20
如果不想用点阵模式保存,也可以用字节数据保存,比如
数字2的各行数值 pix[2] = {0, 6,9, 1, 2, 4, 8, 1 …
,
suncat0504 发表于 2021-1-4 23:20
如果不想用点阵模式保存,也可以用字节数据保存,比如
数字2的各行数值 pix[2] = {0, 6,9, 1, 2, 4, 8, 1 …
比如5*7的字体,16列可显示3个数字,这3个数字用变量去控制其显示的内容,
dcjdcj 发表于 2021-1-5 22:12
比如5*7的字体,16列可显示3个数字,这3个数字用变量去控制其显示的内容
是啊,你想要的这个变量,不就是数组pix的以为元素的下标吗?
变量num1=2; 那么pix[num1]不就是pix[2]吗?编程要灵活一些。,
suncat0504 发表于 2021-1-6 10:06
是啊,你想要的这个变量,不就是数组pix的以为元素的下标吗?
变量num1=2; 那么pix[num1]不就是pix[2]吗 …
看了一些教程,说是可以开一个16字节缓存,再映射到每一列上,但是我这个是发一个字节是横向排列的,不改电路的情况下可以实现一列一列的扫描吗?如果这样,就可以控制每一列显示的内容了,就可以显示任意的内容了,
suncat0504 发表于 2021-1-4 23:20
如果不想用点阵模式保存,也可以用字节数据保存,比如
数字2的各行数值 pix[2] = {0, 6,9, 1, 2, 4, 8, 1 …
非常感谢您的耐心解答,这样是可以一个595显示两个字了,但是不能把1号595的数据移到2号上面,不能实现自由显示的目的
- u8 code Table1[10][8]=
- {
- {0,6,9,9,9,9,9,6}, //0
- {0,2,6,2,2,2,2,7}, //1
- {0,6,9,1,2,4,8,15}, //2
- {0,6,9,1,6,1,9,6}, //3
- {0,2,6,10,10,15,2,2}, //4
- {0,15,8,14,1,1,9,6}, //5
- {0,6,9,8,14,9,9,6}, //6
- {0,15,9,1,2,2,4,4}, //7
- {0,6,9,9,6,9,9,6}, //8
- {0,6,9,9,7,1,2,4}, //9
- };
- void Duan_Dis() //ÏÔê¾
- {
- static u8 i=0;
- if(Dis_Flag)
- {
- Dis_Flag=0;
- LED_HX=Duan_Xuan[i];
- DATA1=Table1[5][i]<<4|Table1[2][i];
- DATA2=Table1[9][i]<<4|Table1[0][i];
- i++;
- i%=8;
- }
- }
复制代码
,
dcjdcj 发表于 2021-1-6 23:57
非常感谢您的耐心解答,这样是可以一个595显示两个字了,但是不能把1号595的数据移到2号上面,不能实现自 …
显示原理通了,下一步就是怎么用程序用合理的逻辑实现的问题了,对吗?这不就是程序员要做到的事情吗?,
suncat0504 发表于 2021-1-7 14:40
显示原理通了,下一步就是怎么用程序用合理的逻辑实现的问题了,对吗?这不就是程序员要做到的事情吗?
唉,刚入坑小白一枚,理论经验都不足,
dcjdcj 发表于 2021-1-7 18:44
唉,刚入坑小白一枚,理论经验都不足
这是我刚刚测试过的程序,已经用proteus模拟过了。你可以试试。
,
dcjdcj 发表于 2021-1-7 18:44
唉,刚入坑小白一枚,理论经验都不足
程序稍加改动,就可以变成驱动四位数字的。// 保存四位数字的数组变量
u8 v[4]={2,3,4,5};
void getValue(void) {
v[0]=val/1000;
v[1]=(val%1000)/100;
v[2]=(val%100)/10;
v[3]=val%10;
}
void main() {
// 初始化595控制管脚
DATA=0;
CLK=0;
LOCK=0;
getValue(); // 获得显示数值
while(1) {
// 按键按下,累加数据
if (Key==0) {
delayms(5); // 防抖
if (Key==0) {
while(Key==0); // 等待按键松开
val++; // 累加1
getValue(); // 获得显示数值
}
}
disp();
}
}
disp函数中,计算行显示数据的地方:
// 循环行
for (row=0; row<8; row++) {
// 根据显示数值,计算每行的点阵数据。一行两个字节,16Bit位对应16列
// col_data[row][0]对应第一个595,col_data[row][1]对应第二个595.
// 因为是级联,所以从col_data[row][1]到col_data[row][0],从Bit0到Bit7串行输出
//col_data[row][0]=(Table[v[0]][row]<<3) | (Table[v[1]][row]>>2);
//col_data[row][1]=(Table[v[1]][row]<<6) | (Table[v[2]][row]<<1);
col_data[row][0]=(Table[v[0]][row]<<4) | (Table[v[1]][row]);
col_data[row][1]=(Table[v[2]][row]<<4) | (Table[v[3]][row]);
}
编译、执行proteus模拟后,就会看到显示结果。每按动一次按钮,显示数据+1.
,把显示延时3毫秒改成1毫秒,proteus显示更稳定,不闪烁。,
suncat0504 发表于 2021-1-7 20:41
程序稍加改动,就可以变成驱动四位数字的。// 保存四位数字的数组变量
u8 v[4]={2,3,4,5};
显示4位数字的已经实现了,但是太紧凑了,显示3位的问题是:如何将1号595的数据移一点在2号595上,这样就可以显示3位了,还可以每位数字之间间隔一列空的,但只能右移4次,超过的就移出去了,预想的是移到2号595上
,
suncat0504 发表于 2021-1-7 20:41
程序稍加改动,就可以变成驱动四位数字的。// 保存四位数字的数组变量
u8 v[4]={2,3,4,5};
3位的我也懂了,非常谢谢你,还想请教一个问题:就有源蜂鸣器怎么实现检查到按键按下响,长按就一直响直到松手为止,这个问题也困扰了我好久,网上也没有找到解决的方法,有一个多月了,现在也没有想出怎么驱动,难道是我不适合这条路吗,
dcjdcj 发表于 2021-1-7 22:14
3位的我也懂了,非常谢谢你,还想请教一个问题:就有源蜂鸣器怎么实现检查到按键按下响,长按就一直响直 …
你下载的程序里,在主函数中不是有按键的监察处理吗?从按下到松开的整个过程,都有代码。你只要在防抖动检查的Key==0的判断之后,开启声音;在确认松开之后(while(Key==0);)架上停止声音的代码不就可以了吗?
if (Key==0) { // 检查按键是否按下
delayms(20); // 防抖的延时,防止因为异常干扰引起的误触发动作
if (Key==0) { // 在防抖之后,再次确认按键是否真的被按下
打开声音(); // 按键被按下,开始播放声音
while(Kewy==0); // 直到按键松开后,才执行“关闭声音();”开始处的代码
关闭声音(); // 按键已经被松开,停止i播放声音
… // 按键被按下后,执行对应的处理机能
}
},
suncat0504 发表于 2021-1-8 09:03
你下载的程序里,在主函数中不是有按键的监察处理吗?从按下到松开的整个过程,都有代码。你只要在防抖动 …
我学的按键检测是用状态机的方式实现的,网上说判断按键按下后,给一个标志位,蜂鸣器用npn管驱动,给高就响,低就不响,又不能像LED灯一样io口取反,给了1以后,多久给0,还是在按键松手后也给个标志位?