单片机课程设计 课程题目: 基于单片CPU的8LED显示频率计设计
目录 第一章 前言 1 1.1频率计概述 1 1.2频率计设计内容 1 第二章 系统总体方案设计 2 2.1测频的原理 2 2.2总体思路 2 2.3具体模块 2 第三章 硬件电路具体设计 3 3.1 AT89S52主控制器模块 3 3.1.1 AT89S52的介绍3 3.1.2 复位电路及时钟电路4 3.1.2 引脚功能4 74HC595芯片介绍6 3.2 显示模块 7 3.2.1 数码管介绍7 3.2.2 频率值显示电路:八位数码管显示四位频率和四位周期。7 第四章 系统的软件设计 7 4.1 软件模块设计 7 4.2 中断服务子程序 8 4.3 显示子程序 9 4.4 应用软件简介 10 4.4.1 Keil简介10 4.4.2 protues简介11 第五章 频率计的系统调试 11 5.1 软件调试 11 5.1.1 Pouteus软件调试11 5.1.2 功能调试11 5.2系统调试 12 5.2.1 系统软件调试12 5.3 误差分析 12 第六章 总结 13 参考文献 13
第一章 前言频率测量是电子学测量中最为基本的测量之一。由于频率信号抗干扰性强,易于传输,因此可以获得较高的测量精度。随着数字电子技术的发展,频率测量成为一项越来越普遍的工作,测频原理和测频方法的研究正受到越来越多的关注。 1.1频率计概述数字频率计是计算机、通讯设备、音频视频等科研生产领域不可缺少的测量仪器。它是一种用十进制数字显示被测信号频率的数字测量仪器。它的基本功能是测量正弦信号、方波信号及其他各种单位时间内变化的物理量。在进行模拟、数字电路的设计、安装、调试过程中,由于其使用十进制数显示,测量迅速,精确度高,显示直观,经常要用到频率计。传统的频率计采用测频法测量频率,通常由组合电路和时序电路等大量的硬件电路组成,产品不但体积大,运行速度慢而且测量低频信号不准确。本次采用单片机技术设计一种数字显示的频率计,测量准确度高,响应速度快,体积小等优点[1]。 1.2频率计设计内容利用电源、单片机、分频电路及数码管显示等模块,设计一个简易的频率计能够粗略的测量出被测信号的频率。 参数要求如下: 基本要求: 1 用P1或P3口,产生一方波信号,频率为1000Hz,用LED显示频率和周期 2 将输出信号输入到另一端口作频率计的信号输入端,测量此方波信号的频率、周期和脉宽,在另一LED上将参数值显示出来。 3 设置一功能键,能将当前LED上的信号值锁定 发挥部分: 1 通过键盘,可修改方波的频率。每按一次键,频率值进给或后退100Hz,频率范围100Hz~1500Hz 2 按键时,蜂鸣器发出提示音,表示按键有效 3 用图形方式显示输入波形
第二章 系统总体方案设计2.1测频的原理测频的原理归结成一句话,就是“在单位时间内对被测信号进行计数”。被测信号,通过单片机内部定时、计数产生方波,从P3.2口输入端输入,从P1.0口输出。通过网络信号将其接入按键,控制输出的信号扫描。由晶体振荡器产生的基频,按十进制分频得出的分频脉冲,经过基选通门去触发主控电路,再通过主控电路以适当的编码逻辑便得到相应的控制指令,用以控制主门电路选通被测信号所产生的方波波,至十进制计数电路进行直接计数和显示。 2.2总体思路频率的测量实际上就是在单位时间内对信号进行计数,计数值就是信号频率。该频率计实现1000HZ~1500HZ的频率测量,而且可以实现通过KEY1可修改方波的频率,每按一次键,频率值进给+100Hz,用八位LED显示频率和周期测量结果。用KEY0实现能将当前LCD上的信号值锁定。 2.3具体模块根据上述系统分析,频率计系统设计共包括五大模块:单片机控制模块、74HC595串入并出模块及显示模块、蜂鸣器模块。各模块作用如下: 1、单片机控制模块:以AT89S52单片机为控制核心,来完成它待测信号的计数,译码,和显示以及对分频比的控制。利用其内部的定时/计数器完成待测信号周期/频率的测量。单片机AT89S52内部具有2个16位定时/计数器,定时/计数器的工作可以由编程来实现定时、计数和产生计数溢出时中断要求的功能。 2、74HC595串入并出: 数据在SCHcp的上升沿输入,在STcp的上升沿进入的存储寄存器中去。如果两个时钟连在一起,则移位寄存器总是比存储寄存器早一个脉冲。 移位寄存器有一个串行移位输入(Ds),和一个串行输出(Q7’),和一个异步的低电平复位,存储寄存器有一个并行8位的,具备三态的总线输出,当使能OE时(为低电平),存储寄存器的数据输出到总线。 3、显示模块:显示电路采用八位共阳极数码管动态显示。 4、蜂鸣器模块:按键每按一下,蜂鸣器响一下。 频率计的总体设计 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB2DE.tmp.jpg 图1 频率计总体设计框图
第三章 硬件电路具体设计根据系统设计的要求,频率计实际需要设计的硬件系统主要包括以下几个部分:AT89S52单片机最小系统模块、74HC595串入并出及显示模块,下面将分别给予介绍。 3.1 AT89S52主控制器模块3.1.1 AT89S52的介绍 AT89S52片内集成256字节程序运行空间、8K字节Flash存储空间,支持最大64K外部存储扩展。根据不同的运行速度和功耗的要求,时钟频率可以设置在0-33M之间。片内资源有4组I/O控制端口、3个定时器、8个中断、软件设置低能耗模式、看门狗和断电保护。可以在4V到5.5V宽电压范围内正常工作。 3.1.2 复位电路及时钟电路复位电路和时钟电路是维持单片机最小系统运行的基本模块。复位电路通常分为两种:上电复位(图2)和手动复位(图3)。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB2EF.tmp.png file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB2F0.tmp.png 图2 上电复位 图3 手动复位 合适频率的晶振对于选频信号强度准确度都有好处,本次设计选取12.000M无源晶振接入XTAL1和XTAL2引脚。并联2个30pF陶瓷电容帮助起振。AT89S52单片机最小系统如图6所示。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB2F1.tmp.png 图4 单片机最小系统原理图 3.1.2 引脚功能P0口:P0口是一个8位漏极开路的双向I/O口。作为输出口,每位能驱动8个TTL逻辑电平。对P0端口写“1”时,引脚用作高阻抗输入。当访问外部程序和数据存储器时,P0口也被作为低8位地址/数据复用。在这种模式下,P0具有内部上拉电阻。在 flash编程时,P0口用来接收指令字节;在程序校验时,输出指令字节。程序校验时,需要外部上拉电阻[7]。 P1口:P1口是一个具有内部上拉电阻的8位双向I/O口,P1 输出缓冲器能驱动4个TTL 逻辑电平。对 P1 端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流。此外,P1.0和P1.2分别作定时器/计数器2的外部计数输入和定时器/计数器2的触发输入,P1口功能具体如表1所示。在flash编程和校验时,P1口接收低8位地址字节。 表1 P1口的第二种功能说明表 引脚号 | | | T2(定时器/计数器T2的外部计数输入),时钟输出 | | T2EX(定时器/计数器T2的捕捉/重载触发信号和方向控制) | | | | | | |
P2口:P2口是一个具有内部上拉电阻的8位双向I/O口,P2输出缓冲器能驱动4 个TTL逻辑电平。对P2端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流。在访问外部程序存储器或用16位地址读取外部数据存储器时,P2口送出高八位地址。在这种应用中,P2口使用很强的内部上拉发送1。在使用8位地址访问外部数据存储器时,P2口输出P2锁存器的内容。在flash编程和校验时,P2口也接收高8位地址字节和一些控制信号。 P3口:P3口是一个具有内部上拉电阻的8位双向I/O口,P2输出缓冲器能驱动4个TTL逻辑电平。对P3端口写“1”时,内部上拉电阻把端口拉高,此时可以作为输入口使用。作为输入使用时,被外部拉低的引脚由于内部电阻的原因,将输出电流。P3口亦作为AT89C51特殊功能(第二功能)使用。 表2 P3口的第二种功能说明表 引脚号 | | | | | | | file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB301.tmp.png(外部中断0) | | file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB302.tmp.jpg(外部中断1) | | | | | | file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB303.tmp.png(外部数据存储器写选通) | | file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB304.tmp.png(外部数据存储器写选通) |
RST:复位输入。晶振工作时,RST脚持续2个机器周期高电平将使单片机复位。看门狗计时完成后,RST 脚输出96个晶振周期的高电平。特殊寄存器 AUXR(地址8EH)上的DISRTO位可以使此功能无效。DISRTO默认状态下,复位高电平有效。 XTAL1:振荡器反相放大器和内部时钟发生电路的输入端。 XTAL2:振荡器反相放大器的输出端。 单片机引脚分配 根据系统设计及各模块的分析得出,单片机的引脚分配如表3所示。 表 3 单片机端口分配表 74HC595芯片介绍引脚说明 符号 | | | | 15[size=10.5000pt], 1[size=10.5000pt], 7 | | | | | | | | | | | | | | | | | | | | | | | | | |
3.2 显示模块 显示模块由频率值显示电路和周期值显示电路组成。用P3口设计程序,产生一方波信号,频率为1000Hz,用LED显示频率和周期。 将输出信号输入到另一端口P1口作频率计的信号输入端,测量此方波信号的频率、周期,在另一LED上将参数值显示出来。 3.2.1 数码管介绍根据其结构的不同,可分为共阳极数码管和共阴极数码管两种。根据管脚资料,可以判断使用的是何种接口类型[14].两种数码管内部原理如图5所示。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB315.tmp.jpg 图5 两种数码管内部原理图 LED数码管中各段发光二极管的伏安特性和普通二极管类似,只是正向压降较大,正向电阻也较大。在一定范围内,其正向电流与发光亮度成正比。由于常规的数码管起辉电流只有1~2 mA,最大极限电流也只有10~30 mA,所以它的输入端在5 V电源或高于TTL高电平(3.5 V)的电路信号相接时,一定要串加限流电阻,以免损坏器件。 3.2.2 频率值显示电路:八位数码管显示四位频率和四位周期。第四章 系统的软件设计4.1 软件模块设计频率计开始工作或者完成一次频率测量,系统软件都进行测量初始化。测量初始化模块设置堆栈指针(SP)、工作寄存器、中断控制和定时/计数器的工作方式。定时/计数器的工作首先被设置为计数器方式,即用来测量信号频率[15]。 首先定时/计数器的计数寄存器清0,运行控制位TR置1,启动对待测信号的计数。计数闸门由软件延时程序实现,从计数闸门的最小值(即测量频率的高量程)开始测量,计数闸门结束时TR清0,停止计数。计数寄存器中的数值经过数制转换程序从十六进制数转换为十进制数。判断该数的最高位,若该位不为0,满足测量数据有效位数的要求,测量值和量程信息一起送到显示模块;若该位为0,将计数闸门的宽度扩大10倍,重新对待测信号的计数,直到满足测量数据有效位数的要求。定时/计数器的工作被设置为定时器方式,定时/计数器的计数寄存器清0,在判断待测信号的上跳沿到来后,运行控制位TR置为1,以单片机工作周期为单位进行计数,直至信号的下跳沿到来,运行控制位TR清0,停止计数。16位定时/计数器的最高计数值为65535,当待测信号的频率较低时,定时/计数器可以对被测信号直接计数,当被测信号的频率较高时,先由硬件十分频后再有定时/计数器对被测信号计数,加大测量的精度和范围。 4.2 中断服务子程序T0中断服务子程序流程如图20所示。测频时,定时器T0 工作在定时方式,每次定时50mS ,则T0 中断20 次正好为1秒,即T0用来产生标准秒信号,定时器T0 用作计数器,对待测信号计数,每秒钟的开始启动T0 ,每秒钟的结束关闭T0 ,则定时器T0 之值乘以分频系数就为待测信号的频率。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB316.tmp.png 图6 T0中断服务子程序 定时/计数器T1工作在计数方式, 对信号进行计数,计数器1中断流程图。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB317.tmp.png 图7 计数器1中断服务子程序 4.3 显示子程序显示子程序将存放在显示缓冲区的频率或周期值送往数码管上显示出来,由于所有4 位数码管的8 根段选线并联在一起由单片机的P2口 控制,因此,在每一瞬间4位数码管会显示相同的字符,要想每位显示不同的字符就必须采用扫描方法轮流点亮各位数码管,即在每一瞬间只点亮某一位显示字符,在此瞬间,段选控制口P2输出相应字符。由P0.0-P0.3逐位轮流点亮各个数码管, 每位保持1mS ,在10mS~20mS 之内再点亮一次,重复不止,利用人的视角暂留,好像4 位数码管同时点亮。数码管显示子程序流程如图8所示。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB318.tmp.png 图8 显示子程序流程图 4.4 应用软件简介4.4.1 Keil简介Keil软件是目前最流行开发系列单片机的软件,Keil提供了包括C编译器、宏汇编、连接器、库管理和一个功能强大的仿真调试器等在内的完整开发方案,通过一个集成开发环境(uVision)将这些部份组合在一起。而Proteus与其它单片机仿真软件不同的是,它不仅能仿真单片机CPU的工作情况,也能仿真单片机外围电路或没有单片机参与的其它电路的工作情况。 (1)建立工程文件 点击“Project->New project”菜单,出现一个对话框,要求给将要建立的工程起一个名字,你可以在编缉框中输入一个名字,点击“保存”按钮,出现第二个对话框,按要求选择目标器件片。建立新文件并增加到组。分别设置“target1”中的“Target,output,debug”各项,使程序汇编后产生HEX文件。 (2)汇编,调试系统程序 Keil 单片机模拟调试软件内集成了一个文本编辑器,用该文本编辑器可以编辑源程序。在集成开发环境中选择菜单“File → New...”、单击对应的工具按钮或者快捷键Ctrl +N 将打开一个新的文本编辑窗口,完成汇编语言源文件的输入,并且完成源程序向当前工程的添加。 然后在集成开发环境中选择菜单“File→Save As...”可以完成文件的第一次存储。注意,汇编语言源文件的扩展名应该是“ASM”,它应该与工程文件存储在同一文件夹之内。在完成文件的第一次存储以后,当对汇编语言源文件又进行了修改,再次存储文件则应该选择菜单“File→Save”、单击对应的工具按钮或者快捷键Ctrl +S 实现文件的保存。 接着的工作需要把汇编语言源文件加入工程之中。选择工程管理器窗口的子目“Source Group 1”,再单击鼠标右键打开快捷菜单。在快捷菜单中选择“Add File to Group ‘Source Group 1’”,加入文件对话框被打开。双击要加入的文件名或者选择要加入的文件名再单击“Add”按钮即可完成把汇编语言源文件加入工程。文件加入以后,加入文件对话框并不消失,更多的文件也可以利用它加入工程。如果不需要加入其它文件,单击“Close”按钮可以关闭加入文件对话框。这时工程管理窗口的文件选项卡中子目录“Source Group 1”下出现一个汇编语言源文件。 (3)编译源程序,出现错误时,返回上一级对错误更改后重新编译,直到没有错误为止。 4.4.2 protues简介(1)首先将keil和 Protues两个软件安装好。 (2)打开protues软件,新建一文件将硬件原理图绘入图中。 (4)将KEIL生成的HEX文件下载入单片机中,点击“开始”进行仿真。 (5)在keil中进行debug,同时在proteus中查看直观的结果(如LED显示⋯⋯)。
第五章 频率计的系统调试5.1 软件调试5.1.1 Pouteus软件调试根据系统设计要求,进行Keil和Proteus系统仿真,不断调试程序,直到符合功能要求。Proteus总体仿真图9所示。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB319.tmp.jpg 5.1.2 功能调试当测量频率值加200时,数码管显示频率值,作为Hz档单位指示。仿真显示如图10所示。 file:///C:\Users\shaoanqi\AppData\Local\Temp\ksohtml\wpsB32A.tmp.jpg 图10 HZ档频率仿真 5.2系统调试5.2.1 系统软件调试经软件的调试—修改—再调试,如此反复,排除各种故障最终基本完成了设计所要求的任务。由系统软件设计可以测出1000HZ-1500HZ的量程范围,可以实现量程档的自动转换,使用的动态显示测量时会出现闪烁现象,但显示数值准确,稳定时显示不闪烁。 表6:频率的数据记录表 表7:周期的数据记录表 5.3 误差分析从记录的数据可以看出,系统软件仿真误差很小,在1000Hz-1500MHz范围内测量出来的频率基本上就是输入信号的频率。但是在硬件调试中,可能是由于标准元器件本身误差,如随着时间的延长,造成测量结果没有软件仿真精确。同时手工焊接单片机最小系统、分频整形电路等也会带来一定的干扰,造成信号的失真,从而导致测量精度下降,测量范围有所缩小,但是可以看出,误差在允许范围内,所设计的电路基本符合要求
第六章 总结通过本次试验我学到了很多书本以外的知识。了解了单片机的基本知识和在控制领域的作用和地位。在实验的过程中我进一步了掌握了C语言的编写程序,学会了使用PROTUTES和KEIL的仿真来实现,同时掌握了如何收集、查阅、应用文献资料,如何根据实际需要有选择的阅读书籍和正确确定系统所要使用的元器件的类型。我明白了理论和实践之间存在的距离只有靠不断的思考不断的动手才能将所学的知识真正运用到实践上来。在设计中我的很多方面的能力都得到了提高,尤其在单片机软件编程方面让我感触颇深。我个人认为软件设计是个即灵活又细腻的工作,不仅仅要运用理科知识还要运用艺术中的很多元素。它要求耐心和细心去不断完善,同时还需要有良好的逻辑思维能力。这长达两周的课程设计让我绞尽脑汁完成了自己认为完成不了的任务让我很有成就感。也是我对单片机产生了更深的兴趣。我很享受课程设计的过程。
参考文献 [1]邹大挺.频率计的设计[J]. 《电子产品世界》出版社. 2006. 第193期. 4-7. [2]雷玉堂.光电检测技术[M]. 中国计量出版社. 1995. [3]季建华. 智能仪表原理[M]. 山东教育出版社. 2004. [4]王永生. 电子测量学[M]. 西北工业大学出版社. 2003. [5]李华.单片机实用接口技术[M]. 航空航天大学出版社. 2006. [6]张鹏.王雪梅. 单片机原理与应用实例教程[M]. 海军出版社. 2007. [7]赫建国等. 单片机在电子电路设计中的应用[M]. 清华大学出版社. 2005. [8]康华光.电子技术基础(模拟部分)[M]. 高等教育出版社. 1998.
频率计源程序 #include "stdio.h" #include "absacc.h" #include <intrins.h> #include <math.h> #include "LEDshow.h" sbit signal_out=P1^0; sbit key0=P2^6; sbit key1=P3^4; sbit beep=P2^7; bit state_old=0,state_new=0; bit int_flag; unsigned int frequency=1000,frequency_temp;//测量信号频率Hz unsigned int signal=1000;//产生信号频率Hz,初始值1000Hz unsigned char counter0,counter1;//用于记录中断次数 unsigned char hight=1; //高电平所需次数 unsigned char total=2;//一个周期所需中断总次数,占空比 hight/total,题目要求为方波。 unsigned char th1,tl1;////产生信号频率,定时时间为500us,初始值为1000Hz unsigned int f_count,t_count;// unsigned char temp_flag=0; void Display(void); void Mcu_init(void);
void main() { Mcu_init(); while(1) { Display(); } } void Display(void) { if(IE0==0 || IE1==0) beep=0; LED0_show(signal,(1000000/signal));//显示信号发生器的频率Hz,周期us LED1_show(frequency,(1000000/frequency)); }
void Mcu_init(void) { th1=((65536-1000000/(2*signal))/256),tl1=((65536-1000000/(2*signal))%256);//产生信号频率 beep=0; TMOD=0x11; //定时器1 方式1 16位手动重装初值 ; 定时器0 方式1 16位手动重装初值 TH0 = 0x03c; TL0 = 0x0b0;//50ms TH1=th1; TL1=tl1; // ET0=1;//允许T/C0申请中断 TR0=1;//启动T/C0 ET1=1;//允许T/C1申请中断 TR1=1;//启动T/C1 IT0=1;//下降沿触发 EX0=1;//启动外部触发器0 IT1=1;//下降沿触发 EX1=1;//启动外部触发器1 TR2=1;//启动T/C2 RCAP2H=0x00; RCAP2L=0x00; EA=1; } void EXint0(void) interrupt 0 //锁存,停止刷新显示 { if(frequency<2000)//Measure_T(); { TR2=1;//启动T/C2 temp_flag++;//上升沿的个数 if(temp_flag==2)//第二个上升沿 { temp_flag=0;//上升沿的个数 t_count=TH2*256+TL2; TR2=0;//停止T/C2 TH2=0x00; TL2=0x00; frequency_temp=1000000/t_count; return; }
} else if(frequency>=2000)//Measure_F(); { f_count++;//单位时间内计到的沿个数 if(int_flag)///单位时间50ms { f_count=0;//单位时间内计到的沿个数 int_flag=0;//单位时间50ms frequency_temp=f_count*20;//frequency=f_count/50ms(Hz) } } } void time0(void) interrupt 1 //50ms测量一次频率,并刷新显示 { TH0 = 0x3c; TL0 = 0xb0;//50ms counter0 ++;//T/C0中断次数加一 int_flag=1; //单位时间50ms if(counter0 ==2)//定时时间 50ms*counter0 { counter0 =0;//T/C0中断次数清零 frequency=frequency_temp; } }
void EXint1(void) interrupt 2 { if(key0 ==0) TR0 =~TR0; if(key1 ==0)//频率递增100Hz { signal +=100; if(signal>1500) signal =100; th1=((65536-1000000/(2*signal))/256),tl1=((65536-1000000/(2*signal))%256);//产生信号频率 return; } beep=1; } void time1(void) interrupt 3 //方波发生 { counter1++; //中断次数加1 if(counter1 == hight) signal_out=0;//高电平时间到,转为低电平 else if(counter1 == total) //低电平时间到,转为高电平,并清零counter { signal_out =1; counter1 =0; } TH1=th1; TL1=tl1; }
LED显示程序 #include "LEDshow.h" //const unsigned char Led_Disbuf[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x80}; //共阴极 const unsigned char Led_Disbuf[]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xff,0x7f,0xbf}; //共阳极 const unsigned char ComBuf[8] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; void LED0_show(unsigned int high_4,unsigned int low_4) { unsigned char i,temp[8]; temp[0]= high_4 /1000; temp[1]= high_4 %1000/100; temp[2]= high_4 %100/10; temp[3]= high_4 %10; temp[4]= low_4 /1000; temp[5]= low_4 %1000/100; temp[6]= low_4 %100/10; temp[7]= low_4 %10; for(i=0;i<8;i++) { DATA0_HC595_Send_Data(Led_Disbuf[temp]); //送端口数据 CONTROL0_HC595_Send_Data(ComBuf); //选通位选端口 delay_ms(1); //延时 CONTROL0_HC595_Send_Data(0x00); //位选通关闭 } } void LED1_show(unsigned int high_4,unsigned int low_4) { unsigned char i,temp[8]; temp[0]= high_4 /1000; temp[1]= high_4 %1000/100; temp[2]= high_4 %100/10; temp[3]= high_4 %10; temp[4]= low_4 /1000; temp[5]= low_4 %1000/100; temp[6]= low_4 %100/10; temp[7]= low_4 %10; for(i=0;i<8;i++) { DATA1_HC595_Send_Data(Led_Disbuf[temp]); //送端口数据 CONTROL1_HC595_Send_Data(ComBuf); //选通位选端口 delay_ms(1); //延时 CONTROL1_HC595_Send_Data(0x00); //位选通关闭 } } void delay_ms(unsigned char time) { unsigned char i,j; for(i=time;i>0;i--) for(j=20;j>0;j--); } //发送一个字节 void CONTROL0_HC595_Send_Data(unsigned char byte) { unsigned char i; for(i = 0;i < 8;i++) { if(byte & 0x80) { CONTROL0_HC595_data=1; } else { CONTROL0_HC595_data=0; } byte <<=1; CONTROL0_HC595_sclk=1; //上升沿数据移位 CONTROL0_HC595_sclk=0; }
CONTROL0_HC595_latch=1; CONTROL0_HC595_latch=0; } /************* //发送字符串 void CONTROL0_HC595_Output_Data(unsigned char Data) { CONTROL0_HC595_latch=0; //下降沿锁存器数据不变 CONTROL0_HC595_Send_Data(Data); CONTROL0_HC595_latch=1; //上升沿数据打入8位锁存器 } *************/ //发送一个字节 void DATA0_HC595_Send_Data(unsigned char byte) { unsigned char i; for(i = 0;i < 8;i++) { if(byte & 0x80) { DATA0_HC595_data=1; } else { DATA0_HC595_data=0; } byte <<=1; DATA0_HC595_sclk=1; //上升沿数据移位 DATA0_HC595_sclk=0; }
DATA0_HC595_latch=1; DATA0_HC595_latch=0; } /**************** //发送字符串 void DATA0_HC595_Output_Data(unsigned char Data) { DATA0_HC595_latch=0; //下降沿锁存器数据不变 DATA0_HC595_Send_Data(Data); DATA0_HC595_latch=1; //上升沿数据打入8位锁存器 } *****************/ //发送一个字节 void CONTROL1_HC595_Send_Data(unsigned char byte) { unsigned char i; for(i = 0;i < 8;i++) { if(byte & 0x80) { CONTROL1_HC595_data=1; } else { CONTROL1_HC595_data=0; } byte <<=1; CONTROL1_HC595_sclk=1; //上升沿数据移位 CONTROL1_HC595_sclk=0; }
CONTROL1_HC595_latch=1; CONTROL1_HC595_latch=0; } /******************** //发送字符串 void CONTROL1_HC595_Output_Data(unsigned char Data) { CONTROL1_HC595_latch=0; //下降沿锁存器数据不变 CONTROL1_HC595_Send_Data(Data); CONTROL1_HC595_latch=1; //上升沿数据打入8位锁存器 } ***********************/ //发送一个字节 void DATA1_HC595_Send_Data(unsigned char byte) { unsigned char i; for(i = 0;i < 8;i++) { if(byte & 0x80) { DATA1_HC595_data=1; } else { DATA1_HC595_data=0; } byte <<=1; DATA1_HC595_sclk=1; //上升沿数据移位 DATA1_HC595_sclk=0;
}
DATA1_HC595_latch=1; DATA1_HC595_latch=0; } /*************** //发送字符串 void DATA1_HC595_Output_Data(unsigned char Data) { DATA1_HC595_latch=0; //下降沿锁存器数据不变 DATA1_HC595_Send_Data(Data); DATA1_HC595_latch=1; //上升沿数据打入8位锁存器 } |