51单片机七段数码管显示时钟无按键控制—①—74HC595版

参考链接:
51单片机七段数码管显示时钟加按键控制—③—74HC595版
51单片机七段数码管显示时钟加按键控制—②—74HC595版

一、实验内容:

1.使用七段数码管显示一个时钟
2.编写程序让接在P0口的数码管显示时分秒,秒数每秒加一
3.要求1秒时间间隔使用定时器中断实现
4.七段数码管的位选和段选通过74HC595控制

二、实验分析:

①七段数码管显示屏需要显示数字的话需要知道段码(具体显示的数值)和位码(第 1——8 位)

②单片机传输信息告诉显示屏位码和段码是多少是通过74HC595芯片实现,使用此芯片的好处是能使用更少的引脚控制更多的位(原本需要单片机上8个引脚控制位码,8个引脚控制段值,现在只需要3根引脚即可“无限”扩展)

③单片机是怎么告诉显示器位码和段码是多少的呢,如果是使用8位+8位的话,那么直接就可以通过将配置引脚输出不同的值即可选中段码和位码 。示例
而使用74HC595的话则通过51芯片先发送八位位码,再送八位段码。一个比特一个比特传输,共两个字节,调用两次SendTo595(char byteData)函数。
因为51单片机是8位的不能一次送16位进去,所以分两次执行
在这里插入图片描述

8+8位控制举例:例如我拿出P0_0—P0_7 八引脚控制段值P2_0—P2_7八引脚控制位码。如果我要做第1位显示数字5,那么我只需要在P0八口输出0x6D——0110 1101, P2八口输出0x7F——0111 1111

位码选择:
位码选择:
*注:此处使用的是CC共阴数码管

选择段值 :
在这里插入图片描述

七段数码管引脚定义:
在这里插入图片描述
(这里的编码显示的是共阳的,共阴没找到相应的图,知道怎么对应就行。)

在这里插入图片描述

三、仿真图:

在这里插入图片描述

四、源代码:

(注释我感觉写的挺详细的,要看懂的话要先了解74HC595的工作方式)

#include "reg52.h"
#include "intrins.h"

typedef unsigned int u16;	  //对数据类型进行声明定义
typedef unsigned char u8;

//定义P0口的三个引脚,赋予不同的涵义
sbit SER = P0^1;    //p0.1脚控制串行数据输入
sbit SCK = P0^0;    //串行输入时钟
sbit RCK = P0^2;    //存储寄存器时钟

u8 code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};//显示0~F的值
char duanMa[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};//选择1-8哪个数码管段
char duanZhi[8]={0,0,0x40,0,0,0x40,0,0};	 	//保存8个数码管的中每个数码管段的数值 0x40:显示横杠

//num1:秒初始值 num2:分初始值 num3:时初始值
u16 num1=55,num2=59,num3=23;

static int i = 0;	//给中断计数使用

//函数声明
void SendTo595(char byteData);

/***********************************************************
*函数名		:display
*功能		:对传如的时分秒进行处理计算,转化为七段数码管要显示的值
*参数		:num1 秒	num2 分	  num3 时
************************************************************/
void display(u16 num1,u16 num2,u16 num3)
{

	//先发送8位位码,后发送8位段码
	//8位数码管需要发送8次
	char i=0;	//给单片机for循环使用,由于Keil4 把 变量定义放for里会报错,只能放函数体前面

	//分离每个数字的个位和十位/
	static char shi1,ge1,shi2,ge2,shi3,ge3;
	shi1=(char)num1/10;
	ge1=(char)num1%10;

	shi2=(char)num2/10;
	ge2=(char)num2%10;

	shi3=(char)num3/10;
	ge3=(char)num3%10;
	///=======

	//保存段值/
	duanZhi[0]=smgduan[shi1];
	duanZhi[1]=smgduan[ge1];
	duanZhi[3]=smgduan[shi2];
	duanZhi[4]=smgduan[ge2];
	duanZhi[6]=smgduan[shi3];
	duanZhi[7]=smgduan[ge3];	
	///=======

	i=0;
	for(;i<8;i++)	
	{
		SendTo595(~duanMa[i]); 		//送段码
		SendTo595(duanZhi[i]);		//送位码
		
		/*位移寄存器数据准备完毕,转移到存储寄存器*/
	   RCK = 0;         
	   _nop_();
	   _nop_();
	   RCK = 1; 	   //检测到上升沿,让存储寄存器时钟变为高电平
	}
		
}


/*******************************************************************************
* 函 数 名         : TimerInit
* 函数功能		   : 定时器0初始化
* 参数			   :无
*******************************************************************************/
void TimerInit()
{
	TMOD|=0X01;	//选择为定时器0模式,工作方式1,仅用TR0打开启动。
	TH0=0X4C;	//给定时器赋初值,定时50ms 		3CB0
	TL0=0X00;	//0X3CB0的十进制是15536 从15536计数到65536计数50000次 即50000us=50ms	
	ET0=1;		//打开定时器0中断允许
	EA=1;		//打开总中断
	TR0=1;		//打开定时器	

}

/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 参数			 :无
*******************************************************************************/	
void main()
{	
	TimerInit();
	
	while(1)
	{	
	 	if(i==20)//20个50毫秒即一秒
		{
			i=0;
			num1++;
			if(num1==60)
			{
				num1=0;
				num2++;
				if(num2==60)//定时一小时自动清零
				{
					num2=0;
					num3++;
					if(num3==24)
					{
						num3=0;
					}
				}	
			}
		}
		display(num3,num2,num1); 	
	}
}


/***********************************************************
*函数名		:SendTo595
*功能		:串行发送8个比特(一个字节)的数据给595,再并行输出
*参数		:byteData 
************************************************************/
void SendTo595(char byteData)
{
   char i=0;
    for(;i<8;i++)
   {
        SER = byteData>>7; 		//取出最高位(第8位)       
        byteData= byteData<<1;  //将第7位移动到最高位    

        SCK = 0;        //变为低电平,为下次准备  ,并延时2个时钟周期 
        _nop_();
        _nop_();

        SCK = 1;         //上升沿,让串行输入时钟变为高电平,
   }  
}


/*******************************************************************************
* 函 数 名         : Timer0()
* 函数功能		   : 定时器0中断函数
* 参数			   :无
*******************************************************************************/		
void Timer0() interrupt 1
{
	 TH0=0x4C;
	 TL0=0x00;
	 i++;		
}

最后也来个动图演示吧
在这里插入图片描述

  • 7
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 8
    评论
51单片机控制74HC595驱动数码管显示,一般需要以下步骤: 1. 定义数码管的连接引脚,如数码管的A-G引脚和DP引脚的连接引脚,以及74HC595的串行数据引脚(DS)、时钟引脚(SHCP)和输出使能引脚(STCP)。 2. 定义数码管显示的字符集,可以将数字0~9、字母A~F和DP转换为相应的二进制码,存储在一个数组中。 3. 编写移位函数,将待显示的数字依次存入74HC595中。 4. 在主函数中,通过调用移位函数,将要显示的数字存入74HC595中,然后通过STCP引脚的高电平脉冲,将数据输出到数码管上。 以下是一个简单的51单片机控制74HC595驱动数码管显示的代码示例: ```c #include <reg51.h> sbit DS = P2^0; //74HC595的串行数据引脚 sbit SHCP = P2^1; //74HC595时钟引脚 sbit STCP = P2^2; //74HC595的输出使能引脚 unsigned char code num[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f}; //数码管字符集 void delay(unsigned int t) //延时函数 { unsigned int i, j; for (i = 0; i < t; i++) for (j = 0; j < 125; j++); } void shift(unsigned char dat) //移位函数 { unsigned char i; SHCP = 0; for (i = 0; i < 8; i++) { DS = dat & 0x80; dat <<= 1; SHCP = 1; SHCP = 0; } STCP = 1; STCP = 0; } void main() { unsigned char i; while (1) { for (i = 0; i < 10; i++) { shift(num[i]); delay(100); } } } ``` 在上述代码中,我们定义了一个数码管字符集数组num[],通过移位函数shift()将待显示的数字存入74HC595中,最后通过STCP引脚的高电平脉冲,将数据输出到数码管上。在主函数中,我们通过循环调用移位函数,将数字0~9显示数码管上。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值