2个74HC595控制2个8×8点阵,显示3位数字

2个74HC595控制2个8×8点阵,显示3位数字,想用2个74HC595控制2个8×8点阵,显示3位数字,但这3个数字要互不干扰,如图,显示2位数字会做,但是…

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 …

#include<reg52.h>
#include<intrins.h>
#define LED_HX P2
typedef unsigned int u16;        
typedef unsigned char u8;
bit Dis_Flag=0;                                    //扫描时间标志位
u8 DATA1,DATA2;                                //   595数据
u8 Duan_Xuan[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};//行扫描
u8 code Num_Table[3][8]=
{
        {0x00,0x0E,0x11,0x11,0x11,0x11,0x11,0x0E},        //     0
        {0x00,0x04,0x0C,0x04,0x04,0x04,0x04,0x0E},        //        1
//        {},        //  2
//        {},        //        3
//        {},        //        4
//        {},        //        5
//        {},        //        6
        {0x00,0x1F,0x01,0x02,0x04,0x04,0x04,0x04},        //        7
//        {},        //        8
//        {},        //        9
};

sbit SRCLK=P1^0;
sbit R_CLK=P1^1;
sbit SER=P1^2;

void Hc595SendByte()
{
        u8 i;
        SER=1;
        SRCLK=0;
        R_CLK=0;
                for(i=0;i<8;i++)
                {
                        SER=DATA1&0x80;
                        DATA1<<=1;
                        SRCLK=1;
                        _nop_();
                        _nop_();
                        SRCLK=0;        
                }

                for(i=0;i<8;i++)
                {
                        SER=DATA2&0x80;
                        DATA2<<=1;
                        SRCLK=1;
                        _nop_();
                        _nop_();
                        SRCLK=0;        
                }

                R_CLK=1;
                _nop_();
                _nop_();
                R_CLK=0;
}

void Duan_Dis()                //显示
{
        static u8 i=0;
        if(Dis_Flag)
        {
                Dis_Flag=0;
                LED_HX=Duan_Xuan[ i];     
                DATA1=Num_Table[0][ i];
                DATA2=Num_Table[2][ i];
                i++;
                i%=8;
        }
}

void Timer0Init(void)                //100us 22.1184.000MHz
{        
        TMOD &= 0xF0;               
        TMOD |= 0x02;               
        TL0 = 0x48;               
        TH0 = 0x48;               
        TF0 = 0;               
        TR0 = 1;               
        ET0=1;
        EA=1;
}

void main(void)
{
        Timer0Init();
        while(1)                        
        {
                Hc595SendByte();
                Duan_Dis();
        }
}

void Timer_Ser(void) interrupt 1
{
        static u8 i;
        i++;
        if(i>=5)
        {
                i=0;
                Dis_Flag=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号上面,不能实现自由显示的目的

  1. u8 code Table1[10][8]=
  2. {
  3.         {0,6,9,9,9,9,9,6},                //0
  4.         {0,2,6,2,2,2,2,7},                //1        
  5.         {0,6,9,1,2,4,8,15},                //2
  6.         {0,6,9,1,6,1,9,6},                //3
  7.         {0,2,6,10,10,15,2,2},        //4
  8.         {0,15,8,14,1,1,9,6},        //5
  9.         {0,6,9,8,14,9,9,6},                //6
  10.         {0,15,9,1,2,2,4,4},                //7
  11.         {0,6,9,9,6,9,9,6},                //8
  12.         {0,6,9,9,7,1,2,4},                //9
  13. };
  14. void Duan_Dis()                //ÏÔê¾
  15. {
  16.         static u8 i=0;
  17.         if(Dis_Flag)
  18.         {
  19.                 Dis_Flag=0;
  20.                 LED_HX=Duan_Xuan[i];     
  21.                 DATA1=Table1[5][i]<<4|Table1[2][i];
  22.                 DATA2=Table1[9][i]<<4|Table1[0][i];
  23.                 i++;
  24.                 i%=8;
  25.         }
  26. }

复制代码

,

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,还是在按键松手后也给个标志位?

作者: soufei

为您推荐


Fatal error: Can't use function return value in write context in /www/wwwroot/www.qianrushi.com.cn/wp-content/themes/news/footer.php on line 115