zoukankan      html  css  js  c++  java
  • 4个74HC595级联控制16x16点阵横向滚动带仿真(二)

    废话

      续上篇

      《4个74HC595级联控制16x16点阵横向滚动带仿真(一)

      将横向滚动的程序分享给QQ群里后,群内的晚秋兄弟提出了另一种思路——采用行扫描、移位方式做滚动,于是熬夜将其实现了一下。仿真程序还是跟前篇一样,不再赘述。


    效果预览

      


    代码

    /**
     **********************************************************
     ******       Copyright(C), 2010-2016,吐泡泡的虾           ******
     **********************************************************
    
     *@Tittle                :    16x16点阵滚动显示汉字——横向滚动 移位方式
     *@Version        :    v1.0
     *@Author        :    吐泡泡的虾
     *@Dat            :    2016-08-05 01:11:28
     *@Desctription    :    16x16点阵采用4个74HC595移位寄存器控制,
     *                    4个移位寄存器采用串联方式。
     *                    本例采用行刷新模式。
     *                    取模方式:横向取模,字节不倒序。
     *                    适用于普中开发板。
     *                    为尽量减少RAM占用,未用buff[32]缓存满屏
     *                    显存的方式来存储要显示的文字码值,而采用
     *                    3个基准指针和3个缓存字节循环赋值的方式
     *                注意:
     *                    由于采用4个595级联方式,输入数据速度太慢,
     *                    导致闪烁感较强。可改用6T模式,改善很多。
     *
     *                     更改k值可以更改滚动速度。
     *                     更改延时也可以更改滚动速度,但注意可能引
     *                     起闪烁。
     *@History        :
         #v1.0    [Press F5 to insert time]
             1. some comment
    
     **********************************************************
     **********************************************************
     */
    
    
    #include <reg52.h>
    #include <intrins.h>
    
    
    #define uchar unsigned char
    #define uint unsigned int
    
    sbit DS_595 = P3 ^ 4;        //P3^4: 595的数据输入管脚
    sbit SHCP_595 = P3 ^ 6;        //P3^6: 595的移位寄存器时钟管脚 SCK
    sbit STCP_595 = P3 ^ 5;        //P3^5: 595的输出寄存器时钟管脚 RCK
    // sbit MR_595 = P2 ^ 3;    //P0^3: 595的输出输出寄存器重置管脚 MR
    
    void InputTo595(uchar *displayBuff, uchar len);
    void OutputFrom595();
    void DelayX10us(uchar multi);
    
    //行扫描模式下的行序号,两两一组。如0x80, 0x00为点亮第一行,0x40, 0x00为第二行
    uchar code ROW_NUM[] = {
        0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01, 0x00,
        0x00, 0x80, 0x00, 0x40, 0x00, 0x20, 0x00, 0x10, 0x00, 0x08, 0x00, 0x04, 0x00, 0x02, 0x00, 0x01,
    };
    
    //要显示的字符。开头和末尾均留1个空白字符,以显示滚入、滚出效果。任意替换中间的汉字即可
    uchar code words[] =
    {
        /*--  起始空白,滚入效果  --*/
        /*--  宽度x高度=16x16  --*/
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    
    //=======================================文字内容替换区============================================
        /*--  文字:  ☆  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x01, 0x00, 0x01, 0x00, 0x02, 0x80, 0x02, 0x80, 0x02, 0x80, 0x04, 0x40, 0xFC, 0x7E, 0x40, 0x04,
        0x30, 0x18, 0x08, 0x20, 0x08, 0x20, 0x11, 0x90, 0x16, 0x50, 0x18, 0x30, 0x20, 0x08, 0x00, 0x00,
    
        /*--  文字:  左  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFE, 0x04, 0x00, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00,
        0x0F, 0xF8, 0x10, 0x80, 0x10, 0x80, 0x20, 0x80, 0x40, 0x80, 0x80, 0x80, 0x3F, 0xFE, 0x00, 0x00,
    
        /*--  文字:  右  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x02, 0x00, 0x02, 0x00, 0x02, 0x00, 0xFF, 0xFE, 0x04, 0x00, 0x04, 0x00, 0x08, 0x00, 0x08, 0x00,
        0x1F, 0xF8, 0x28, 0x08, 0x48, 0x08, 0x88, 0x08, 0x08, 0x08, 0x08, 0x08, 0x0F, 0xF8, 0x08, 0x08,
    
        /*--  文字:  滚  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x00, 0x80, 0x20, 0x40, 0x17, 0xFC, 0x11, 0x10, 0x82, 0x48, 0x44, 0x84, 0x41, 0x20, 0x13, 0xF0,
        0x10, 0x10, 0x20, 0x88, 0xE1, 0x50, 0x23, 0x20, 0x25, 0x10, 0x29, 0x48, 0x21, 0x86, 0x01, 0x00,
    
        /*--  文字:  动  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x00, 0x40, 0x00, 0x40, 0x7C, 0x40, 0x00, 0x40, 0x01, 0xFC, 0x00, 0x44, 0xFE, 0x44, 0x20, 0x44,
        0x20, 0x44, 0x20, 0x84, 0x48, 0x84, 0x44, 0x84, 0xFD, 0x04, 0x45, 0x04, 0x02, 0x28, 0x04, 0x10,
    
        /*--  文字:  ★  --*/
        /*--  宋体12;  此字体下对应的点阵为:宽x高=16x16   --*/
        0x01, 0x00, 0x01, 0x00, 0x03, 0x80, 0x03, 0x80, 0x03, 0x80, 0x07, 0xC0, 0xFF, 0xFE, 0x7F, 0xFC,
        0x3F, 0xF8, 0x0F, 0xE0, 0x0F, 0xE0, 0x1F, 0xF0, 0x1E, 0xF0, 0x18, 0x30, 0x20, 0x08, 0x00, 0x00,
    //==================================================================================================
    
    
        /*--  空白,滚出效果  --*/
        /*--  宽度x高度=16x16  --*/
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    };
    
    
    
    void main()
    {
        uint i, j, rollSpeed;
        bit mode = 0;
        uchar num = 0;
        //显示缓存,用来存储输入到4个595中的数据。
        //displayBuff[0]:0# 595,控制上8行,上为高位
        //displayBuff[1]:1# 595,控制下8行,上为高位
        //displayBuff[2]:2# 595,控制左8列,左为高位
        //displayBuff[3]:3# 595,控制右8列,左为高位
        uchar displayBuff[4];
    
        bit moveLeft = 1;    //移动方向,1——左移,0——右移
    
        uchar* basePtr[3];    //每8次移位之前的第一行的3个半边字符(即正在显示的左半、正在显示的右半、即将显示的另一半)的基准指针,其他行码值在此基础上偏移
        uchar temp[3];        //用来存储三个半边字符的某一行的码值
        uchar cache[2];        //中间变量,可不要
        uchar wordsCount = sizeof(words) / sizeof(words[0]) / 32;    //汉字总数
    
        while (1)
        {
            //获取每8次移位前的第一行的基准指针地址
            if (mode == 0)    //模式0,左右半屏显示同一个字,basePtr[2]指向下一个即将显示的字的左半(左滚时)或右半(右滚时)的首行
            {
                basePtr[0] = words + (num)  * 32 + (moveLeft ? 0 : 1);
                basePtr[1] = words + (num)  * 32 +  (moveLeft ? 1 : 0);
                basePtr[2] = words + (num + 1) % wordsCount * 32 + (moveLeft ? 0 : 1);    //取余是为了显示到最后一个字时,temp[2]等于首字的左半
            }
            else//模式1,(左滚时)左半屏显示上一个字的右半,右半屏显示下一个字的左半
                //(右滚时)右半屏显示上一个字的左半,左半屏显示下一个字的右半
                //basePtr[1][2]指向下一个即将显示的两个半边字符码地址的首行
            {
                basePtr[0] = words + (num)  * 32 +  (moveLeft ? 1 : 0);
                basePtr[1] = words + (num + 1) % wordsCount * 32 + (moveLeft ? 0 : 1);    //取余是显示最后一个字右半时,temp[1]等于首字的左半
                basePtr[2] = words + (num + 1) % wordsCount * 32 +  (moveLeft ? 1 : 0); //取余是显示最后一个字右半时,temp[1]等于首字的右半
            }
    
            for (j = 0; j < 8; j++)
            {
                rollSpeed = 1;    //滚动速度调节
                while (rollSpeed--)
                {
                    //依次显示16列,即显示完一屏
                    for (i = 0; i < 16; i++)
                    {
                        //移位操作涉及的3个半边字符,往移动方向最先移除屏幕的定义为序号[0]
                        //根据ptr计算,可得左移时,temp[0][1][2]分别对应前左<-前右<-后左或前右<-后左-<后右
                        //右移时,temp[2][1][0]分别对应后右->前左->前右或后左->后右->前左
                        temp[0] = *(basePtr[0] + 2 * i);
                        temp[1] = *(basePtr[1] + 2 * i);
                        temp[2] = *(basePtr[2] + 2 * i);
    
                        if (moveLeft)//左移
                        {
                            cache[0] = temp[0] << j | temp[1] >> (8 - j);
                            cache[1] = temp[1] << j | temp[2] >> (8 - j);
                        }
                        else
                        {
                            cache[0] = temp[1] >> j | temp[2] << (8 - j);
                            cache[1] = temp[0] >> j | temp[1] << (8 - j);
                        }
    
                        displayBuff[0] =  ROW_NUM[2 * i];        //上8行码值,上为高位
                        displayBuff[1] =  ROW_NUM[2 * i + 1];    //下8行码值,上为高位
                        displayBuff[2] = ~cache[0];                //每一行对应的左8列码值,左为高位
                        displayBuff[3] = ~cache[1];                //每一行对应的右8列码值,左为高位
    
                        InputTo595(displayBuff, 4);
                        _nop_();
                        OutputFrom595();
                        DelayX10us(5);//显示时间延时,太长会引起闪烁感
                    }
                }
            }
    
            mode = ~mode;    //移位8次后模式反转,下一半汉字第一行码值的地址即将存到基准指针
    
            if (mode == 0) num++; //mode再次为0时,即屏幕已显示到下一个字
            if (num == wordsCount)
            {
                num = 0;
                moveLeft = ~moveLeft;    //反向滚动
            }
        }
    
    }
    
    /**
     * 将displayBuff数组输入级联的595芯片,最后一个元素先输入,从低位到高位顺序输入
     * @param displayBuff 输入数组地址
     * @param len      要输入的数组元素个数,从数组第一个元素开始计
     */
    void InputTo595(uchar *displayBuff, uchar len)
    {
        uchar i, j;
    
        for (j = len; j > 0; j--)
        {
            for (i = 0; i < 8; i++)
            {
                DS_595 = displayBuff[j - 1] & 0x01 ;    //先输入最低位
                displayBuff[j - 1] >>= 1;
    
                SHCP_595 = 0;
                _nop_();
                SHCP_595 = 1;    //上升沿,输入到移位寄存器
            }
    
        }
    }
    
    void OutputFrom595()    //595输出
    {
        STCP_595 = 0;
        _nop_();
        STCP_595 = 1;
        STCP_595 = 0;
    }
    
    //延时10us的倍数,误差5us
    void DelayX10us(uchar multi)
    {
        do
        {
            _nop_(); _nop_(); _nop_(); _nop_();
            _nop_(); _nop_(); _nop_(); _nop_();
        } while (--multi);
    }
            
    View Code

     欢迎关注本人的个人博客YoungCoding.top

  • 相关阅读:
    又到了什么都不想做的时候了/梦
    【笔记】【汇编语言】第11章 标志寄存器
    【经验】【ORACLE】CMD命令行下使用SQLPLUS执行SQL脚本后返回CMD命令行的方法
    【笔记】【汇编语言】第6章 包含多个段的程序
    【笔记】【汇编语言】第8章 数据处理的两个基本问题
    【笔记】【汇编语言】第5章 [BX]和loop指令
    【经验】【ORACLE】从字符串中截取其中的数字
    【读书】【沉思录】卷一
    【笔记】【汇编语言】第9章 转移指令的原理
    【笔记】【汇编语言】第10章 CALL和RET指令
  • 原文地址:https://www.cnblogs.com/ToddleLobster/p/5739770.html
Copyright © 2011-2022 走看看