51单片机入门 - 点阵显示程序设计实验

博主福利:100G+电子设计学习资源包!

http://mp.weixin.qq.com/mp/homepage?__biz=MzU3OTczMzk5Mg==&hid=7&sn=ad5d5d0f15df84f4a92ebf72f88d4ee8&scene=18#wechat_redirect
--------------------------------------------------------------------------------------------------------------------------

 

一、LED点阵发光原理

8*8单色单片机结构图如下:

https://blog.csdn.net/weixin_42625444/article/details/90897605

从电路图中很简单的就可以看出来,想要点亮点阵中的某一个LED灯。只要使得那个灯所在的行输出高电平,所在列输出低电平就好。

 

二、点阵扫描实验

 

/***********************************************
实验名称:      点阵扫描
实验说明:      扫描每个LED灯,检查点阵是否完好
实验时间:    
***********************************************/
#include 
#include 

#define uchar unsigned char
#define uint  unsigned int

sbit MOSIO = P3^4;//输入口
sbit R_CLK = P3^5;//锁存器时钟
sbit S_CLK = P3^6;//移位寄存器时钟

//data3:右边半块列数据;data2:左边半块列数据
//data1:下边半块行数据;data0:上边半块行数据
void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0);

void main()
{
    uint i,j;
    uchar d;

    while(1)
    {
        //全亮
        HC595Pro(0x00,0x00,0xFF,0xFF);
        for(i=0;i<40000;i++);          //延时40ms  
            
        /*行扫描*/
        //上半块行扫描
        d = 0x01;
        for(i=0;i<8;i++)
        {
            HC595Pro(0x00,0x00,0x00,d);
            d <<= 1;
            for(j=0;j<20000;j++);               //延时20ms    
        }      
        //下半块行扫描
        d = 0x01;
        for(i=0;i<8;i++)
        {
            HC595Pro(0x00,0x00,d,0x00);
            d <<= 1;
            for(j=0;j<20000;j++);                 //延时20ms        
        }

        /*列扫描*/
        //左半快列扫描
        d = 0xFE;
        for(i=0;i<8;i++)
        {
            HC595Pro(0xFF,d,0xFF,0xFF);
            //如果还想用跟行扫描一样的形式,看main()最下面注释行
            d = _crol_(d,1);                   //循环左移
            for(j=0;j<20000;j++);              //延时20ms        
        }
        //右半块列扫描
        d = 0xFE;
        for(i=0;i<8;i++)
        {
            HC595Pro(d,0xFF,0xFF,0xFF);
            d = _crol_(d,1);
            for(j=0;j<20000;j++);               //延时20ms    
        }
        /******************************************************
        b1 = 0x01;
        for(i = 0; i<8; i++)
        {
            HC595Pro(0xFF, ~b1, 0xFF, 0xFF);
            b1 <<= 1;
            for(j=0; j<20000; j++);
        }

        b1 = 0x01;
        for(i = 0; i<8; i++)
        {
            HC595Pro(~b1, 0xFF, 0xFF, 0xFF);
            b1 <<= 1;
            for(j=0; j<20000; j++);
        }    
        ******************************************************/
    }
}

void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0)
{
    uchar i;
    //先移入的会被后面移入的数据推移到后面的595中,所以需要先移入data3
    for(i=0;i<8;i++)
    {
        //先移入高位再移入低位,移位寄存器移入的第一位就是输出的最高位
        MOSIO = data3 >> 7;
        data3 <<= 1;
        S_CLK = 0;//给一个上升沿,移位
        S_CLK = 1;
    }    
    for(i=0;i<8;i++)
    {
        MOSIO = data2 >> 7;
        data2 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }
    for(i=0;i<8;i++)
    {
        MOSIO = data1 >> 7;
        data1 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }
    for(i=0;i<8;i++)
    {
        MOSIO = data0 >> 7;
        data0 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }

    //上升沿时将移位寄存器数据移到锁存器中用于显示,平时保持低电平,数据不变
    R_CLK = 0;
    R_CLK = 1;
    R_CLK = 0;

}

 

这里我用到的是16*16的点阵。其实也就是4个8*8的小点阵组成起来的。其结构图如下:

1 2
3 4

这里只是简单示意一下。。。其中4个小块都是与一个相对应的74HC595相连。每个74HC595又是级联的,入口只有一个,我们需要输入相对应的行,列电平情况来控制LED灯的亮灭。

根据74HC595的结构可以知道,输入的数据是8位8位的输入的。最开始输入的8位数据会被后面的输入数据推移到第四个74HC595中。

所以实际输入时,是先输入2和4的列数据,再输入1和3的列数据,然后再是3和4的行数据,最后才是1和2的行数据。

 

三、16*16点阵倒计时

 

/***********************************************************************
实验名称:   16*16点阵数字倒计时
实验时间:   
***********************************************************************/
#include 
#include 

#define uchar unsigned char
#define uint  unsigned int

sbit MOSIO = P3^4;
sbit R_CLK = P3^5;
sbit S_CLK = P3^6;

void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0);

void main()
{
    uint i,c;
    uchar j;
    i = 100;

    while(1)
    {
        //显示数字10
        for(c=i;c>0;c--)//延时
            for(j=0;j<16;j++)
            {
                //字模取出来的数据是跟实际实际所需数据相反的,所以要取反。
                //函数对应的参数分别表示列2,列1,行2,行1
                HC595Pro(~tab1[2*j+1],~tab1[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字09
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab2[2*j+1],~tab2[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字08
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab3[2*j+1],~tab3[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字07
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab4[2*j+1],~tab4[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字06
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab5[2*j+1],~tab5[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字05
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab6[2*j+1],~tab6[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字04
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab7[2*j+1],~tab7[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字03
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {                          
                HC595Pro(~tab8[2*j+1],~tab8[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字02
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab9[2*j+1],~tab9[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字01
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab10[2*j+1],~tab10[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示数字00
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab11[2*j+1],~tab11[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏

        //显示字母GO
        for(c=i;c>0;c--)
            for(j=0;j<16;j++)
            {
                HC595Pro(~tab12[2*j+1],~tab12[2*j],tab0[2*j],tab0[2*j+1]);
            }
        HC595Pro(0xFF,0xFF,0x00,0x00);//清屏
    }    
}

void HC595Pro(uchar data3,uchar data2,uchar data1,uchar data0)
{
    uchar i;
    //先移入的会被后面移入的数据推移到后面的595中,所以需要先移入data3
    for(i=0;i<8;i++)
    {
        //先移入高位再移入低位,移位寄存器移入的第一位就是输出的最高位
        MOSIO = data3 >> 7;
        data3 <<= 1;
        S_CLK = 0;//给一个上升沿,移位
        S_CLK = 1;
    }    
    for(i=0;i<8;i++)
    {
        MOSIO = data2 >> 7;
        data2 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }
    for(i=0;i<8;i++)
    {
        MOSIO = data1 >> 7;
        data1 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }
    for(i=0;i<8;i++)
    {
        MOSIO = data0 >> 7;
        data0 <<= 1;
        S_CLK = 0;
        S_CLK = 1;
    }

    //上升沿时将移位寄存器数据移到锁存器中用于显示,平时保持低电平,数据不变
    R_CLK = 0;
    R_CLK = 1;
    R_CLK = 0;
}

 

array.h头文件如下:

//点阵显示数组
//用于行扫描
unsigned char code tab0[] = {0x00, 0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80,
                             0x01, 0x00, 0x02, 0x00, 0x04, 0x00, 0x08, 0x00, 0x10, 0x00, 0x20, 0x00, 0x40, 0x00, 0x80, 0x00}; 
//1数字10的字模
unsigned char code tab1[] = {0, 0, 0, 0, 0, 0, 8, 24, 14, 36, 8, 66, 8, 66, 8, 66, 
                              8, 66, 8, 66, 8, 66, 8, 36, 62, 24, 0, 0, 0, 0, 0, 0};
//数字09的字模
unsigned char code tab2[] = {0, 0, 0, 0, 0, 0, 24, 24, 36, 36, 66, 66, 66, 66, 66,
                             66, 66, 100, 66, 88, 66, 64, 66, 64, 36, 36, 24, 28, 0, 0, 0, 0} ;
//数字08的字模
unsigned char code tab3[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 66, 66, 36,
                             66, 24, 66, 36, 66, 66, 66, 66, 36, 66, 24, 60, 0, 0, 0, 0};
//数字07的字模
unsigned char code tab4[] = {0, 0, 0, 0, 0, 0, 24, 126, 36, 34, 66, 34, 66, 16, 66, 16,
                             66, 8, 66, 8, 66, 8, 66, 8, 36, 8, 24, 8, 0, 0, 0, 0};
//数字06的字模
unsigned char code tab5[] = {0, 0, 0, 0, 0, 0, 24, 56, 36, 36, 66, 2, 66, 2, 66, 26, 66,
                             38, 66, 66, 66, 66, 66, 66, 36, 36, 24, 24, 0, 0, 0, 0};
//数字05的字模
unsigned char code tab6[] = {0, 0, 0, 0, 0, 0, 24, 126, 36, 2, 66, 2, 66, 2, 66, 26, 66,
                             38, 66, 64, 66, 64, 66, 66, 36, 34, 24, 28, 0, 0, 0, 0};
//数字04的字模
unsigned char code tab7[] = {0, 0, 0, 0, 0, 0, 24, 32, 36, 48, 66, 40, 66, 36, 66, 36, 66,
                             34, 66, 34, 66, 126, 66, 32, 36, 32, 24, 120, 0, 0, 0, 0};
//数字03的字模
unsigned char code tab8[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 32, 66, 24, 66,
                             32, 66, 64, 66, 64, 66, 66, 36, 34, 24, 28, 0, 0, 0, 0};
//数字02的字模
unsigned char code tab9[] = {0, 0, 0, 0, 0, 0, 24, 60, 36, 66, 66, 66, 66, 66, 66, 32, 66,
                             32, 66, 16, 66, 8, 66, 4, 36, 66, 24, 126, 0, 0, 0, 0};
//数字01的字模
unsigned char code tab10[] = {0, 0, 0, 0, 0, 0, 24, 8, 36, 14, 66, 8, 66, 8, 66, 8, 66, 8, 66,
                              8, 66, 8, 66, 8, 36, 8, 24, 62, 0, 0, 0, 0};
//数字00的字模
unsigned char code tab11[] = {0, 0, 0, 0, 0, 0, 24, 24, 36, 36, 66, 66, 66, 66, 66, 66, 66, 66,
                              66, 66, 66, 66, 66, 66, 36, 36, 24, 24, 0, 0, 0, 0};
//数字GO的字模
unsigned char code tab12[] = {0, 0, 0, 0, 0, 0, 60, 28, 34, 34, 34, 65, 1, 65, 1, 65, 1, 65, 113,
                              65, 33, 65, 34, 65, 34, 34, 28, 28, 0, 0, 0, 0};

 

头文件的数据是通过字模软件得出的。字模软件的工作原理就是对于一个点阵,你想要什么样的图像,然后就在相应位置数据为1。然后再通过从左到右,从上到下的顺序,组成一个个8位数据。

这些8位数据就是头文件的内容。

由此我们就可以知道,通过字模取出来的数据,而我们实际运用过程中对于列来说是相反的。

因为我们想要点亮对应的LED灯是将它所在行输出高电平,所在列输出低电平。所以取出来的字模数据作为列的值的话是相反的。所以这里用了取反。

 

你可能感兴趣的:(MCU51开发技术)