精华内容
下载资源
问答
  • 51单片机课程设计

    2013-07-16 10:46:02
    单片机 51单片机课程设计--人机界面的多功能电脑时钟
  • 51单片机课程设计报告
  • 51单片机课程设计万年历源码以及报告,在51上编写代码,实现万年历功能。有课程设计报告,有详细的技术文档和完整的汇编源码。
  • 51单片机课程设计万年历源码以及报告,在51上编写代码,实现万年历功能。有课程设计报告,有详细的技术文档和完整的汇编源码。
  • 51单片机课程设计 电子琴,zlg7289
  • C语言51单片机课程设计 这是一个8个数码管显示的芯片:89C51 74HS595
  • 51单片机课程设计毕业设计资料包,包含60多个例子,供大家下载。
  • 大学51单片机课程设计,电子钟数码管显示(按键定时+闹钟)
  • 51单片机课程设计,3层电梯控制,附带程序代码、仿真电路图。
  • 基于51单片机课程设计,电子时钟设计,希望对同学们有帮助.
  • 51单片机课程设计实例,包括时钟和温度检测两个设计!
  • 51单片机课程设计_电子时钟 课程设计 实现电子时钟 使用汇编实现程序
  • 51单片机课程设计:基于51单片机的超声波测距(测距原理介绍)本程序利用超声波模块来进行距离的测量,并显示在数码管上,其他朋友可以在本程序的基础上,修改部分代码,应用到智能小车上或者其他测距设备上。...

    51单片机课程设计:基于51单片机的超声波测距(测距原理介绍)

        本程序利用超声波模块来进行距离的测量,并显示在数码管上,其他朋友可以在本程序的基础上,修改部分代码,应用到智能小车上或者其他测距设备上。

        超声波测距的原理是:首先给模块Trig端一个高电平,然后单片机开始计时,同时模块会发射超声波信号,当单片机检测到Echo端为高电平时(也就是说模块收到反射的信号),计时停止。通过以上操作,我们就可以得到一个时间变量,然后调用对应的公式就可以将时间变量转换为距离。

        相关工程文件以及资料在文章下方,感兴趣的朋友可以下载。

        关于粘贴复制乱码的问题:如果程序复制到Keil编译器上出现注释乱码,可以先建一个.c文件,也就是说不在keil里面编辑,然后用记事本打开.c文件,将源码复制进去,再在keil中添加文件即可。

    /****************************************************************
                        基于51单片机的超声波测距例程
    如果需要在其他开发板上运行并显示,只需要修改数码管显示模块即可
    DisplayData[8]用于存放转换后的距离数据,也就是说你只需要将其中
    的数据在其他显示模块显示出来。
        引脚3.1 接模块Trig
        引脚3.2 接模块Echo
        晶振频率一般都是12MHZ
                                2016-12-30---------------------SWorld
    ****************************************************************/
    #include<reg52.h>
    #define uchar unsigned char   //宏定义无符号字符型
    #define uint  unsigned  int   //宏定义无符号整型
    #define GPIO_DIG P0//位选以及段选数据输出端口定义
    unsigned char code DIG_CODE[10]={ 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //显示段码 数码管字跟
    unsigned char DisplayData[8];//用来存放要显示的8位数的值
    sbit DUC=P2^2;//   DUC段选信号
    sbit WEC=P2^3;//WEC    位选信号
    sbit Trig=P3^1; 
    sbit Echo=P3^2;
    uchar succeed_flag=0;
    uint timeH,timeL,distance=0,time=0,ss;
    //float ;
    //延时子程序   延时1ms
    void delay_ms(uint c)
    {
        uchar a, b;
        for(;c>0;c--)
        {
            for (b=38;b>0;b--)
            {
                for (a=13;a>0;a--);
            }      
        }   
    }
    //延时子程序  延时1us
    void delay_us(uint c)
    {
        uchar a ;
        for(;c>0;c--)
            for(a=0;a<5;a++);
    }
    
    //数码管显示
    void DigDisplay()
    {
        unsigned char i;
        unsigned int j;
        for(i=0;i<8;i++)
        {
            WEC=1;DUC=0;
            switch(i) //位选,选择点亮的数码管,
            {
                case(0):
                    GPIO_DIG=0x7F; break;//显示第0位
                case(1):
                    GPIO_DIG=0xBF; break;//显示第1位
                case(2):
                    GPIO_DIG=0xDF; break;//显示第2位
                case(3):
                    GPIO_DIG=0xEF; break;//显示第3位
                case(4):
                    GPIO_DIG=0xF7; break;//显示第4位
                case(5):
                    GPIO_DIG=0xFB; break;//显示第5位
                case(6):
                    GPIO_DIG=0xFD; break;//显示第6位
                case(7):
                    GPIO_DIG=0xFE; break;//显示第7位
            }
            WEC=0;DUC=1;
            GPIO_DIG=DisplayData[i];//发送段码
            j=15; //扫描间隔时间设定
            while(j--);
            GPIO_DIG=0x00;//消隐
        }
    }
    //主函数模块
    void main(void)
    {
        Trig=0;
        EA=1;
        TMOD=0x11;//定时器1,16位工作方式  定时器0 16位工作方式
        while(1)
        {
            EA=0;           //关总中断
            Trig=1;         
            delay_us(20);   //延时20us
            Trig=0;         //20us脉冲
            while(Echo==0);    //等待Echo回波引脚变高电平
                succeed_flag=0; 
            EA=1; //开外部中断
            EX0=1;         //打开外部中断0
            TH1=0;          //定时器1缺清零
            TL1=0;   //计数溢出标志
            TF1=0;          
            TR1=1;          //启动定时器1
            delay_ms(20);      
            TR1=0;          //关闭定时器1
            EX0=0;          //关外部中断
            if(succeed_flag==1)
            {   
                time=timeH*256+timeL;
                distance=time*0.172;  
             }                         
             if(succeed_flag==0)
            {
                distance=0;                    
            } 
            DisplayData[5]=DIG_CODE[distance/100];
            DisplayData[4]=DIG_CODE[(distance%100)/10];  
            DisplayData[3]=DIG_CODE[distance%10];  
            for(ss=0;ss<200;ss++)
            DigDisplay();
        }
    }
    //外部中断0  用于判断回波电路
    void exter()  interrupt 0   
    {   
         timeH =TH1;    //取出定时器值H
         timeL =TL1;    //取出定时器值L
         succeed_flag=1;//成功测量标志
         EX0=0;         //关外部中断
    }
    //定时器1中断  用作超声波测距计时
    void timer1() interrupt 3  
    {
        TH1=0;
        TL1=0;
    }


    转载于:https://blog.51cto.com/970076933/1887628

    展开全文
  • 51单片机资料\经典单片机课程设计题目大全(大学教授珍藏资料)
  • 数字电位器 MCP42100 通过实物验证 51单片机 课程设计
  • 根据要求,将总体功能分解成若干个子功能模块,每个功能模块完成一个特定的功能。 2.根据总体要求及分解的功能模块,确定各功能模块之间的关系,设计出完整的程序流程图。
  • 51单片机课程设计(内含50多个课程设计,包括汇编代码和c代码,还有电路图)
  • 51单片机课程设计数显简易频率计设计

    千次阅读 多人点赞 2020-11-29 15:54:32
    51数显简易频率计设计 ... 1、总体方案设计 (1)系统总体结构 (2)芯片选择 (3)定时与计数方式 2、硬件电路设计 (1)AT89C51 单片机最小系统 (2)AT89C51 单片机波形产生及测量电路设计 (3)显示电路与 AT89C5

    51单片机课程设计
    数显简易频率计设计

    设计实验条件

    电路及程序设计:Proteus8.7、Keil4 仿真及编程环境

    设计任务及基本要求

    自行设计输入电路,测量信号类型方波、正弦波、三角波等常规周期信号; 输入信号频率范围:10HZ—1MHZ,频率量程自行设定;频率信号的实时显示。其他附加功能自行创新设计。
    1、总体方案设计
    (1)系统总体结构
    (2)芯片选择
    (3)定时与计数方式
    2、硬件电路设计
    (1)AT89C51 单片机最小系统
    (2)AT89C51 单片机波形产生及测量电路设计
    (3)显示电路与 AT89C51 单片机接口电路设计
    (4)键盘电路与 AT89C51 单片机接口电路设计
    3、软件设计
    (1)程序框图
    (2)波形产生程序框图
    (3)波形频率测量程序框图
    (4)键盘输入
    (5)显示程序框图
    4、调试与测试结果分析
    (1)实验系统连线图
    (2)程序调试
    (3)实验结果分析
    5、程序清单和系统原理图

    设计报告

    前言

    课题背景

    频率计是一种基础测量仪器,到目前为止已有 30 多年的发展历史。由于电子器件之间的互相干扰,从而影响频率计的精度,同时由 于其体积较大,已经不适应电子设计的发展要求。随着科学技术的发展,频率计也日益发展。目前已经有操作方便、量程(足够)宽、可靠性高的频率计;也有适应高分辨率、高精度、高稳定度、高测量速度的频率计。
    频率计的基本原理是用一个频率稳定度高的频率源作为基准时钟,对比测量其他信号的频率。通常情况下计算每秒内待测信号的脉冲个数,此时我们称闸门时间为 1 秒。频率计是用数字显示被测信号 频率的仪器,被测信号可以是正弦波,方波或其它周期性变化的信号。

    设计意义

    单片机是一门发展极快,应用方式极其灵活的使用技术。单片机频率计以其可靠性高、体积小、价格低、功能全等优点,广泛地应用于各种智能仪器中。另外,在电子技术中,频率是最基本的参数之一, 并且与许多电参量的测量方案、测量结果都有十分密切的关系,因此频率计在教学、科研、测量仪器、工业控制等方面都有较广泛的应用。

    设计主体

    总体方案设计

    本课程设计的总体思路是以 AT89S51 微控制器为主控,结合外设及硬件电路实现对输入信号频率的测量。由外部中断 1 引脚接入被测信号,定时 1 秒计信号的下降沿个数作为被测信号的频率,并由 LED 数码管进行输出显示。系统总体设计框图

    硬件电路设计

    最小系统设计

    (1)时钟电路:选取 12MHz 的石英晶振,机器周期为 1us,电容选取 33pf 的瓷片电容,时钟电路两输出分别接到单片机的 19 号引脚 XTAL1 和 18 号引脚 XTAL2;
    (2)复位电路:AT89S51 复位信号为高电平有效,对应引脚为 9 号引脚 RST;
    (3)电源电路:40 引脚 VCC 接 5V 电源正极,20 引脚 GND 接电源负极。
    最小系统电路

    波形处理及测量电路设计

    由于输入信号类型及幅值不同,在此设计运算放大电路对幅值进行放大并对波形进行整形,根据三极管的特性可将各种波形的信号转换为矩形波。 信号经整形后通过开关接到单片机的 13 引脚 INT1’,开关可控制信号是否输入单片机。
    信号处理电路

    显示电路设计

    测得频率由 7 段共阴极数码管,共 8 个,共阴数码管由低电平选通,选通信号由 74LS138 经过译码产生。
    显示电路

    检测电路设计

    通过三个不同颜色的 LED 灯对单片机运行状态及频率是否超限进行显示。
    检测电路

    软件程序设计

    根据自己的已有思路写出来基本的程序,但由于各种原因程序无法实现,如写的程序过于复杂,51 单片机系统资源不足带不动,不可控的外部中断频繁触发使得程序无法按正常的逻辑执行,另外,LED 数码管需要不断刷新占用大量的 CPU 执行时间。 经不断完善程序,采取了分时执行的方法,测频时不显示,显示时关闭外部中断不测频。
    主程序流程图
    中断服务程序流程图
    显示程序流程图

    调试与测试结果分析

    (1)断开信号输入开关,侧的频率值为 0;
    (2)设定频率上限为 1000,下限为 100,闭合信号输入开关,
    1)接 500Hz 的正弦波,示波器观察到输入波形为矩形波,绿灯每隔 1 秒亮 1 秒,绿灯亮时数码管不显示,绿灯不亮时数码管显示 86610500;
    2)接 1.5kHz 正弦波,示波器观察到输入波形为矩形波,绿灯每隔 1 秒亮 1 秒,绿灯亮时数码管不显示,绿灯不亮时数码管显示 86611500,且数码管显示同时红灯亮起; 3)接 5Hz 正弦波,示波器观察到输入波形近似为矩形波, 绿灯每隔 1 秒亮 1 秒,绿灯亮时数码管不显示,绿灯不亮时数码管显 示 86610050,且数码管显示同时黄灯亮起;
    (3)输入其他类型的信号时,如三角波、矩形波、锯齿波,观 察到的结果与(2)类似;
    (4)经多次测量,测量误差在 5% 以内;

    硬件电路实现

    实现了频率计的实物制作,由于硬件电路不够稳定以及实物模型的执行延迟,在测量上存在一定的偏差,不过实现了大体的功能。
    实物实现展示图片

    结束语

    通过这次数显简易频率计的设计,我对 51 单片机有了更深的理解,在编程中对执行程序的时序分配及任务周期对程序执行效果的影响有了更深的印象,之后编程会更多的注意这一点,争取让自己的程 序更有效更出彩。
    这次仿真设计也让我对我本不熟悉的 Proteus 软件有了一些初步的了解,之后的科创之路上或许我会通过这款软件或类似的软件增加对硬件电路的了解。 通过对硬件电路的搭建我了解了硬件的不易,以后编程也会更多地考虑硬件执行的时间,另外,尽量不要用低效的硬件,避免程序的执行困难重重。

    参考文献

    【1】马淑华、高军、蔡凌.单片机原理及接口技术第三版.北京邮电大学出版社[M],2018.06

    附录一(程序)

    #include "reg51.h"
    
    #define	uint8 unsigned short int
    
    uint8 i,k;
    
    /******  非准确延时函数  *******/
    void delay_us(int t)
    {
        i = t;
        while(i--)
    	{}
    }
    /*******************************/
    
    /*************************************  数码管显示  **************************************/
    uint8 code smg_data[11] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x00};//共阴数码管段显编码(0-9、不显示)
    uint8 smg7,smg6,smg5,smg4,smg3,smg2,smg1,smg0;//显示数据的各位:个、十、百、千...位数值
    //数码管显示信号频率
    void smg(int a)
    {
        smg0 = 8;
    	smg1 = 6;
    	smg2 = 6;
    	smg3 = 1;
        smg4 = (a%10000)/1000;//频率值的千位
    	smg5 = (a%1000)/100;//频率值的百位
    	smg6 = (a%100)/10;//频率值的十位
    	smg7 = a%10;//频率值的个位
    
    	P2 = 0xf7;//1111 0000选中第8个数码管
    	P0 = smg_data[smg7];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf6;//1111 0000选中第7个数码管
    	P0 = smg_data[smg6];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf5;//1111 0000选中第6个数码管
    	P0 = smg_data[smg5];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf4;//1111 0000选中第5个数码管
    	P0 = smg_data[smg4];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf3;//1111 0000选中第4个数码管
    	P0 = smg_data[smg3];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf2;//1111 0001选中第3个数码管
    	P0 = smg_data[smg2];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf1;//1111 0010选中第2个数码管
    	P0 = smg_data[smg1];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    
    	P2 = 0xf0;//1111 0011选中第1个数码管
    	P0 = smg_data[smg0];
    	delay_us(200);
    	P0 = smg_data[10];//数码管消隐
    	delay_us(10);
    }
    /****************************************************************************************/
    
    /**********  下降沿计数  ***********/
    int count = 0;//采到下降沿的数量
    //信号下降沿计数,由外部中断1采集
    void single_in() interrupt 2
    {
        count++;//采集到下降沿,数值加1
    }
    /***********************************/
    
    /*******************  频率计算及显示  ********************/
    uint8 flag = 1;//计脉冲及显示操作标志
    uint8 time0_num = 0;//定时器0中断次数
    int fr_cest = 0;//测得频率
    void timer0() interrupt 1
    {
        TH0 = 0x3c;//定时器0重新赋值,定时时间为50毫秒,65536-50000=3cb0
    	TL0 = 0xb0;
    	time0_num++;//定时器0中断计数
    	if(time0_num>=20&&flag==0)//定时器0中断达到20次,即定时1秒,执行频率计算
    	{
    	    EX1 = 0;//关闭外部中断,准备开始显示
    		fr_cest = count;//频率计算
    		time0_num = 0;//定时器0中断计次清0
    		flag = 1;//显示操作标志
    	}
    	else if(time0_num>=20&&flag==1)
    	{
    	    EX1 = 1;//开启外部中断,开始计脉冲
    		count = 0;//下降沿计数清0
    		time0_num = 0;//定时器0中断计次清0
    		flag = 0;//记脉冲操作标志
    	}
    }
    /*********************************************************/
    
    /****************************  中断初始化  ******************************/
    void interrupt_init()
    {
        TMOD = 0x11;    //0001 0001  T1门控位清0  T1为定时器模式  01,T1选择模式1        T0门控位清0  T0为定时器模式  01,T0选择模式1
        TCON = 0x14;    //0001 0100  T1标志位清0  T1计时关闭  T0标志位清0  T0开启计时        外部1标志位清0  外部1下降沿触发  外部0标志位清0  外部0电平触发
    	IP = 0x09;      //0000 1001	 --  --	 --  串口中断优先级为低        T1中断优先级为高  外部中断1优先级为低  T0中断优先级为低  外部中断0优先级为低
    	IE = 0x86;      //1000 0110	 开启总中断  --  --  关闭串行中断        关闭T1中断  开启外部中断1  开启T0中断  关闭外部中断0  
    }
    /***********************************************************************/
    
    void main()
    {
        interrupt_init();//中断初始化
    	while(1)
    	{
    	    if(flag==1)
    		{
    		    if(fr_cest>1000)
    			{
    			    P1 = 0x01;
    			}
    			else if(fr_cest<100)
    			{
    			    P1 = 0x04;
    			}
    			else
    			{
    			    P1 = 0x00;
    			}
    		    smg(fr_cest);
    		}
    		else
    		{
    		    P1 = 0x02;
    		}
    	}
    }
    

    附录二(系统设计电路原理图)

    仿真电路

    展开全文
  • 随着现代工农业技术的发展及人们对生活环境要求的提高人们也迫切需要检测与控制温度本文通过采用蜂鸣器作为电声元件的温度报警器的设计阐明了该装置进行设计与制作的具体过程及方法这种温度报警器结构简单可操作性强...
  • 51单片机课程设计(水箱水门控制) 水箱水门控制
  • 80c51单片机课程设计

    2010-07-19 21:36:14
    已知两个数4字节的有符号数,(以补码表示)。最高字节的最高位为符号位。编写程序完成两数的乘除运算。结果可以不显示出来,直接在单片机的内存中查看结果。
  • 单片音乐播放器,希望对课设同学有帮助!!!!!!!!!.........................................................................................
  • 51单片机课程设计:基于GSM的简易手机设计 上次课程设计,由于个人兴趣原因,想挑战有点难度的东西,于是利用单片机和GMS模块来开发一款可以打电话和发短信的手机,功夫不负有心人,进过几天的努力,做出了一个可以...

    51单片机课程设计:基于GSM的简易手机设计


       上次课程设计,由于个人兴趣原因,想挑战有点难度的东西,于是利用单片机和GMS模块来开发一款可以打电话和发短信的手机,功夫不负有心人,进过几天的努力,做出了一个可以用单片机来进行拨号和发短信的手机,这对于我这个初学者来说应该算是一项不错的成果了,废话不说,咱直接进入正题。

    一、硬件选择

        应为我购买的是普中科技的单片机开发板,所以使用的资源基本都是开发板自带的,只不过自己添加了一个GSM模块,使用过普中开发板的同学都知道其自带一个3.5寸的LCD电阻触摸屏。所有你只要将电阻屏连接到单片机上就行,然后再讲GSM模块连接到单片机的串口通信端就行。

    二、界面截图

    wKioL1gUrtiiv5z2ABaKXZV5mns252.jpg-wh_50wKioL1gVioyBHxNcAB2QKMOHkM8700.jpg-wh_50

    wKiom1gUrwuxXHJ3ABwH10g-EmE374.jpg-wh_50

    wKioL1gUryGilpzBABKg1X7q1os628.jpg-wh_50

    wKioL1gUrzqiP7xiABPCMQXbqdQ911.jpg-wh_50

    wKioL1gUr1Wzp4v7AB16ZE5DdYY534.jpg-wh_50


    三、软件源码

        软件源码在下方附件里面,源码都有注释,我就不介绍了。

    转载于:https://blog.51cto.com/970076933/1867328

    展开全文
  • 51单片机课程设计——led点阵广告牌程序设计

    万次阅读 多人点赞 2020-02-06 18:15:56
    上学期期末的课设题目是led点阵广告牌,当时的要求如下: (1)能够显示不同字符的LED点阵广告牌;...当时用的是我用是的普中科技的STC89C51RD+的单片机,不过只要是51单片机,换哪个51内核的芯片都可...

    上学期期末的课设题目是led点阵广告牌,当时的要求如下:
    (1)能够显示不同字符的LED点阵广告牌;
    (2)按键切换不同的显示效果(如闪烁,静止,平移等);
    (3)按键切换不同的显示内容;
    (4)能够显示图形或自定义字符;
    (5)其他功能(创新部分);
    (6)系统调试、分析、总结与功能实现。
    当时用的是我用是的普中科技的STC90C51RD+的单片机,不过只要是51单片机,换哪个51内核的芯片都可以,只要电路和程序匹配就可以。
    我用的那款普中科技的51单片机可以直接连线决定线路的布置,不需要自己去重新焊一个电路板。
    然后我根据任务要求连接了电路,写了对应的程序,还有proteus仿真。
    另外,觉得有趣可以点个赞;有什么有趣的想法可以评论一下,我感兴趣的话会做一下。

    一、设计思路

    首先是P1连接8个独立按键,P3.4,P3.5,P3.5三个I/O口通过模拟SPI(51单片机没有硬件的SPI总线控制器)控制led点阵。
    下面是包含头文件,定义独立键盘,选用模拟SPI的三个I/O口的程序内容,其中也包括重定义函数变量的内容,可以有效地减少编写程序时的负担。

    #include <reg51.h>
    #include <intrins.h>
    
    #define  GPIO_KEY P1  //独立键盘用P1口
    
    //--重定义函数变量--//
    #define uchar unsigned char
    #define uint  unsigned int
    #define ulong unsigned long
    
    //--定义SPI要使用的 IO--//
    sbit MOSIO = P3^4;
    sbit R_CLK = P3^5;
    sbit S_CLK = P3^6;
    

    之后设计显示在led点阵上的文字,符号。(当时设计的是我和组员的名字还有一些自定义的符号)。
    要实现的效果是:打开电源后按下K1可以一堆汉字会从上而下移动,按下K2汉字会闪烁显示(闪烁显示就是显示一个字零点几秒钟,然后先后显示其他字),按下K3是我自定义的那些字符闪烁显示,然后进入每个功能后都可以按下K8退出这个功能,之后可以按下K1,K2或K3进入这三个功能。

    二、通过I/O口模拟SPI发送数据

    (1)传输数据函数与对应模块的仿真

    以下是普中科技单片机自带的通过I/O口模拟SPI发送数据的函数,因为有配套的字模生成软件,所以对这个部分我就不写太多东西了,有想要字模软件的可以在文末的百度网盘链接自己下载。

    //通过74HC595发送四个字节的数据
    void HC595SendData(uchar BT3, uchar BT2,uchar BT1,uchar BT0)
    {  
    	uchar i;
    	
    	//--发送第一个字节--//
    	for(i=0;i<8;i++)
    	{
    		MOSIO = BT3 >> 7 ;	//从高位到低位
    		BT3 <<= 1;
    
    		S_CLK = 0;
    		S_CLK = 1;		
    	}
    
    	//--发送第二个字节--//
    	for(i=0;i<8;i++)
    	{
    		MOSIO = BT2 >>7;		//从高位到低位
    		BT2 <<= 1;
    
    		S_CLK = 0;
    		S_CLK = 1;	
    	}
    
    	//--发送第三个字节--//
    	for(i=0;i<8;i++)
    	{
    		MOSIO = BT1 >> 7;		//从高位到低位
    		BT1 <<= 1;
    		S_CLK = 0;
    		S_CLK = 1;	
    	}
    
    	//--发送第四个字节--//
    	for(i=0;i<8;i++)
    	{
    		MOSIO = BT0 >> 7;		//从高位到低位
    		BT0 <<= 1;
    		S_CLK = 0;
    		S_CLK = 1;
    	}
       
    	//--输出--//
    	R_CLK = 0; //set dataline low
    	R_CLK = 1; //片选
    	R_CLK = 0; //set dataline low
    }
    

    这个部分使用了4个74HC595,下面是对应的仿真图片,里面RX8是排阻,可以不要,我这个图片里有是因为普中科技给的原理图里有这个排阻,我做仿真的时候直接照猫画虎画上去了,其实完全不需要,普中的板子上有这个是因为要把各个模块分开,连接的时候用排线连接就可以,POS和NEG可以理解为16 * 16LED点阵的行和列。
    在这里插入图片描述
    LED点阵要求是16 * 16的,需要使用4个8 * 8的LED点阵组合起来,在proteus中的制作方法在 这里,我拼接16 * 16LED点阵是按照这个做的,之后按照普中给的原理图写引脚的网络标号,在proteus对应着标了一遍(注意:这个图的网络标号是错的),然后仿真出来的结果有问题,我重画了很多次都有问题,可能是原理图有问题,也可能是别的原因,使用普中科技的板子的朋友可以注意一下,我按照这个原理图画仿真怎么画也不对,最后干脆16个行分别标上POS1到POS16,16个列标上NEG1到NEG16结果对了。
    下面是最终可以使用的点阵仿真图:
    正确的点阵仿真
    下面是原理图(照着画网络标号有问题,其他的没有问题):
    普中科技51单片机板子的原理图
    下面是照着原理图画的仿真(画了两次都不能用,出现的图案与预期不符):
    在这里插入图片描述
    (2)要传输的数据

    传输的数据需要选择一些汉字,字符或者自定义符号。
    以下为一些姓氏和自定义的字符对应的数组,tab0是用来确定显示位置的,下面会提到。

    //点阵显示数组
    uchar 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}; 
    //--张--//
    uchar code tab1[] = {
    128,1,191,49,176,49,176,25,176,13,190,7,134,
    1,230,255,134,7,190,13,176,13,176,25,176,49,176,103,158,195,140,1};				 
    //--王--//
    uchar code tab1[] = {
    0,0,252,31,128,0,128,0,128,0,128,0,128,0,248,
    15,128,0,128,0,128,0,128,0,128,0,254,63,0,0,0,0};
    //--李--//
    uchar code tab2[] = {
    128,0,128,0,254,63,160,2,144,4,136,8,6,48,240,
    3,0,1,128,0,254,63,128,0,128,0,224,0,0,0,0,0};
    //--任--//
    uchar code tab3[] = {
    16,0,16,28,208,3,8,2,8,2,12,2,10,2,232,63,8,2,
    8,2,8,2,8,2,8,2,200,31,0,0,0,0};
    //--徐-//
    uchar code tab4[] = {
    16,2,16,2,8,5,132,8,82,16,176,47,8,2,12,2,202,
    31,8,2,72,18,72,34,40,34,136,3,0,0,0,0};
    //--杨--//
    uchar code tab5[] = {
    24,0,152,63,24,24,24,12,127,6,24,3,156,255,60,
    219,126,219,126,219,155,217,152,205,216,204,120,198,24,123,152,49};	
    //--桃心--//
    uchar code xin[] = {
    0,0,28,56,252,63,254,127,255,255,207,243,135,
    225,7,224,15,240,30,120,60,60,120,30,240,15,224,7,192,3,128,1};
    //--五角星--//
    uchar code char1[] = {
    128,1,128,1,192,3,192,3,192,3,96,6,127,254,6,
    96,28,56,48,12,48,12,152,27,248,30,56,28,12,48,0,0};
    //--圆--//
    uchar code char2[] = {
    0,0,224,7,120,30,28,56,28,56,14,112,14,112,14,
    112,14,112,14,112,28,56,28,56,120,30,224,7,0,0,0,0};
    //--三角--//
    uchar code char3[] = {
    0,0,128,1,128,1,192,3,192,3,96,6,96,6,48,12,48,
    12,24,24,24,24,12,48,12,48,254,127,0,0,0,0};
    //--菱形--//
    uchar code char4[] = {
    128,0,64,1,32,2,16,4,8,8,4,16,2,32,1,64,2,32,
    4,16,8,8,16,4,32,2,64,1,128,0,0,0};
    //--箭头--//
    uchar code char5[] = {
    0,0,0,0,0,0,0,2,0,4,0,8,0,16,0,32,126,64,0,
    32,0,16,0,8,0,4,0,2,0,0,0,0};
    

    之后会将要显示的数组在混合起来成为一个新的指针数组,这个数组是用来直接在点阵显示的函数中使用的,*p的指针数组中多余很多是被我删掉的名字,只留下了姓。

    uchar *p[] = {tab1, tab2, tab3, tab4, tab5, tab6, tab7, tab8,
    							tab9, tab10, tab11, tab12, tab13,	tab14};	
    uchar *c[] = {char1, char2, char3, char4,char5};	
    

    三、检测独立按键

    主函数中首先是while(1),无限循环,只要没有检测到键值(即独立按键中有任意键被按下),就一直循环,并且执行清屏的程序(即调用标题二中的传输数据功能,分别传输0xff,0xff,0,0四个数据)如果检测到键值就进入对应的功能中,进入每个功能对应的函数。
    以下是主函数内容:

    void main(void)
    {
       while(1)
       {
    		 HC595SendData(0xff,0xff,0,0);	//清屏	
    		 keyNum=Key_Scan();		//读取键值
    		 switch (keyNum)
    		{
    			case(0xFE) :	  //返回按键K1的数据
    				translation();//文字从上到下平移
    				break;
    			case(0xFD) :	  //返回按键K2的数据
    				twinkle1();		//文字闪烁
    				break;
    			case(0xFB) :	  //返回按键K3的数据
    				twinkle2();		//符号闪烁
    				break;
    //			case(0xF7) :	  //返回按键K4的数据
    //				;
    //				break;
    //			case(0xEF) :	  //返回按键K5的数据
    //				;
    //				break;
    //			case(0xDF) :	  //返回按键K6的数据
    //				;
    //				break;
    //			case(0xBF) :	  //返回按键K7的数据
    //				;
    //				break;
    			case(0x7F) :	  //返回按键K8的数据
    				HC595SendData(0xff,0xff,0,0);				//清屏
    				break;
    			default:
    				break;
    		}		 	
       }
    }
    

    读取键值

    前面有提到定义P1为独立按键,即程序中的GPIO_KEY,当独立按键按下时GPIO_KEY != 0xFF,这时消除抖动(即延时十毫秒)再检测一次,如果检测为按下按键则将键值保存到keyValue中,之后松开按键或500ms后仍未松开按键,都会将读取到的键值返回。

    unsigned char Key_Scan()
    {
    	unsigned char keyValue = 0 , i; //保存键值
    
    	//--检测按键1--//
    	if (GPIO_KEY != 0xFF)		//检测按键K1是否按下
    	{
    		Delay10ms(1);	//消除抖动
    
    		if (GPIO_KEY != 0xFF)	//再次检测按键是否按下
    		{
    			keyValue = GPIO_KEY;
    			i = 0;
    			while ((i<50) && (GPIO_KEY != 0xFF))	 //检测按键是否松开
    			{
    				Delay10ms(1);
    				i++;
    			}
    		}
    	}
    
    	return keyValue;   //将读取到键值的值返回
    }
    

    四、具体功能

    (1)文字自上而下移动

    K1按键对应的是文字自上而下移动的功能,以下为对应的程序,其中内嵌的第三个循环for(k = 0; k < 16; k++)中k从0到15遍历,对应LED点阵的1到16行,内嵌的第二个循环for(ms = 10; ms > 0; ms–)决定显示同一个内容的时间,内嵌的第一个循环为while(keyNum!=0x7F),只要keyNum!=0x7F一直成立,就无限循环。

    i.如何实现随时按下K8退出该功能,重新回到主函数

    在最小的循环中完成内嵌一个检测键值的程序keyNum=Key_Scan();然后判断是否为0x7F(即按下K8时的键值),若是则退出该循环,回到第二个循环,第二个循环中也有判断键值是否为K8的程序,同理,若是,回到第一个循环,while(keyNum!=0x7F)同样会判断键值是否为0x7F,若不是则退出循环,回到主函数。

    ii.如何实现文字从上而下移动

    刚进入这个功能还未进入循环时,赋值j=0(如果这里不赋值j=0也可以,只是下次进入这个功能会接着这次结束时显示的图像继续向下平移),在内嵌的第三个循环,也就是最小的的那个循环中给LED点阵发送数据,且是一次发送一行数据,循环16次,每次k+1即可显示全整个LED点阵,k加到16时退出最小的循环,第二个循环for(ms = 10; ms > 0; ms–)决定进入最小循环的次数即显示的时间,显示完规定的时间后,退出第二个循环,回到第三个循环,j+1,之后再进入最小循环时发送的前两位数据对应的指针数组中的位置会各自加2j,即显示的文字或字符向上移动一位,最下方空缺出来的一行会由下一个文字或字符的第一行代替,之后同理,则形成了文字向上移动的效果,一个字需要16行,从0开始,当j=15要显示的文字或字符数量时,再令j=0,重新从第一个字开始显示。

    以下是文字移动的程序:

    //文字由上而下平移
    void translation()
    {
    	j=0;
    	while(keyNum!=0x7F)
    	{
    		for(ms = 10; ms > 0; ms--)	//移动定格时间设置
    		{
    			for(k = 0; k < 16; k++)	//显示一个字
    			{	 						
    				HC595SendData(~(*(p[0] + 2*(k+j) + 1)),~(*(p[0] + 2*(k+j) )),
    				tab0[2*k],tab0[2*k + 1]); 
    				//因为字模软件取的数组是高电平有效,所以列要取反	  
    				keyNum=Key_Scan();
    					if(keyNum==0x7F)
    						break;
    			}			
    			HC595SendData(0xff,0xff,0,0);										   //清屏	
    			if(keyNum==0x7F)
    				break;			
    		} 	
    		j++;
    		if(j == (14*15) )
    		{
    			j = 0; 
    		}
    	}
    	
    }
    

    以下是文字移动的效果(这时第一个字已经消失了近一半,下一个字也显示出一小半,分别是“王”字和“李”字):
    在这里插入图片描述

    (2)文字闪烁显示

    i.如何实现随时按下K8退出该功能,重新回到主函数

    与文字从上而下移动的功能同理,只不过文字闪烁功能有四个循环,比文字移动多一个,同样是最小循环中检测键值,若检测到keyNum==0x7F,则逐级退出,最后返回主函数。

    ii.如何实现文字闪烁显示

    与文字移动有些类似的地方,在最小的循环中发送数据从LED点阵第一行显示到最后一行,上一级循环决定最小循环一共运行几次,即显示一个字的时间,再上一级循环中每次i+1决定显示下一个文字,当i=14时回到最外层循环,之后回到刚才的循环重新从第一个文字开始显示。

    第二个循环中有多少要显示的文字,就循环多少次,例如我原先共设计了14个文字,则 for(i = 0; i < 14; i++) 中i<14。
    以下是文字闪烁的程序:

    //文字闪烁
    void twinkle1()
    {
    	while(keyNum!=0x7F)
    	{
    		for(i = 0; i < 14; i++)		//总共14个字
    		{
    			for(ms = 50; ms > 0; ms--)	//显示50次,即肉眼可识别的停留时间
    			{
    				for(k = 0; k < 16; k++)			//显示一个字
    				{	 						
    					//--因为字模软件取的数组是高电平有效,所以列要取反--//
    					HC595SendData(~(*(p[i] + 2*k + 1)),~(*(p[i] + 2*k )),
    												 tab0[2*k],tab0[2*k + 1]); 
    					keyNum=Key_Scan();
    					if(keyNum==0x7F)
    						break;
    				}
    				HC595SendData(0xff,0xff,0,0);				//清屏	
    				if(keyNum==0x7F)
    					break;				
    			}
    			if(keyNum==0x7F)
    						break;
    		}
    	}
    }
    

    以下是文字闪烁的效果,一瞬间只显示一个文字:
    在这里插入图片描述

    (3)符号闪烁显示

    其原理与文字闪烁显示完全相同,只不过这个程序里包含的指针数组里的全是自定义的符号。

    以下是符号闪烁的程序:

    //符号闪烁
    void twinkle2()
    {
    	while(keyNum!=0x7F)
    	{
    		for(i = 0; i <5; i++)		//总共5个字
    		{
    			for(ms = 50; ms > 0; ms--)	//显示50次,即肉眼可识别的停留时间
    			{
    				for(k = 0; k < 16; k++)			//显示一个字
    				{	 						
    					//--因为字模软件取的数组是高电平有效,所以列要取反--//
    					HC595SendData(~(*(c[i] + 2*k + 1)),~(*(c[i] + 2*k )),
    												 tab0[2*k],tab0[2*k + 1]); 
    					keyNum=Key_Scan();
    					if(keyNum==0x7F)
    						break;
    				}
    				HC595SendData(0xff,0xff,0,0);				//清屏
    				if(keyNum==0x7F)
    						break;
    			}
    			if(keyNum==0x7F)
    						break;
    		}
    	}
    }
    

    以下是符号闪烁的效果,一瞬间只显示一个自定义符号:
    在这里插入图片描述

    (4)创新部分

    做这个程序的时候快要期末考试了,就没有费心思去做创新部分,但其实很简单,例如,可以把符号也弄成从上而下移动的,可以一会儿闪烁一会移动,比如把要显示的东西横置过来,然后闪烁显示一个人的名字,之后移动显示I LOVE YOU.甚至如果有无源蜂鸣器的话,还可以在显示的同时放首歌。

    五、proteus仿真

    下面是我用proteus做的仿真,仿真效果就不放了,就是那个LED点阵上显示之前在单片机上的LED点阵相同的东西罢了。
    在这里插入图片描述

    PS:字模软件网盘链接:
    链接:https://pan.baidu.com/s/1xrshrLyE3dNWbLnDDi8TxQ
    提取码:j9u8

    展开全文
  • 一份详细教学单片机秒表程序设计的好课件,单片机设计的参考实用资料
  • 包括keil 4的project,以及proteus仿真
  • 51单片机课程设计,使用的是汇编语言,包括电子钟,四键电子琴,1602液晶的出租车计价器,喜欢的可以看看,不过电子钟的年份判断上没有判断闰年的情况,可以上网搜一下。出租车计价器有时钟,显示,键盘...
  • 采用STC89C51单片机作为主控制器,外部加上三极管驱动放音设备,超再生无线模块实现无线的链接。 发射器采用电池供电,静态电流小; 采用无线电进行遥控,具有一定的遥控距离; 在同一区域范围内能有多套系统同时...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 5,353
精华内容 2,141
关键字:

51单片机课程设计