项目端(1)-H74595控制四位数码管和呼吸灯以及放歌

文章目录


前言

作为对H74595的学习,使用内核为STC15204S,进行一次十分有意义的探索。

至于为什么不做流水灯(无聊),参考江科大的代码进行修改为595驱动,使用的是595并发

一、原理图

3b636b4f3b59498798249ea6811f1218.png

二、代码部分

#include <INTRINS.H>
#include <STC15F2K60S2.H>
#include <Delay.h>
#include <Timer0.h>
#include <stdlib.h>
sbit LED =P1^0;
sbit SER2 = P1^1;
sbit SCK2 = P3^6;
sbit RCK2 = P3^7;
sbit SER = P1^4;//SER
sbit SCK = P1^3;//这个就是sclk,移位寄存器,,,名字会混,sclr就先不管了SRCLK移位SH_CP口,数据输入时钟线
sbit RCK = P1^2;//缓存寄存器RCLK,,,,,,,SRCLR是什么鬼东西,//RCLK缓存 ST_CP口,输出存储器锁存时钟线
sbit SW1 = P3^0;
sbit SW2 = P3^1;
sbit SW3 = P3^2;
/
sbit S0 = P3^3;
sbit S1 = P5^5;
sbit S2 = P1^5;
sbit S3 = P5^4;
typedef unsigned char u8; 		// 重命名类型u8简化代码编写
typedef unsigned int u16;

unsigned char FreqSelect,MusicSelect;
u16 zhuangtai=0;

1.595驱动代码

代码如下:

typedef unsigned char u8;         // 重命名类型u8简化代码编写
void Hc595SendByte(u8 dat)
{
    u8 i = 0, j = 0;
 
    SCK = 0;                // 将SCK置为初始状态
    RCK = 0;                // 将RCK置为初始状态
 
    for (i=0; i<8; i++)
    {
        SER = dat & (0x01);
        dat >>= 1;
 
        SCK = 1;
        j++;                  // 延时代码,等同于nop指令
        j++;                // 延时代码,等同于nop指令
        SCK = 0;    
    }
 
    RCK = 1;
    j++;                    // 延时代码,等同于nop指令
    j++;                    // 延时代码,等同于nop指令
}

void Hc595SendByte2(u8 datf)
{
    u8 i = 0, j = 0;
 
    SCK2 = 0;                // 将SCK置为初始状态
    RCK2 = 0;                // 将RCK置为初始状态
 
    for (i=0; i<8; i++)
    {
        SER2 = datf & (0x01);
        datf >>= 1;
 
        SCK2 = 1;
        j++;                  // 延时代码,等同于nop指令
        j++;                // 延时代码,等同于nop指令
        SCK2 = 0;    
    }
 
    RCK2 = 1;
    j++;                    // 延时代码,等同于nop指令
    j++;                    // 延时代码,等同于nop指令
}

2.定时器

代码如下

#include <STC15F2K60S2.H>
 void Timer0Init(void)
{
    TMOD &= 0xF0;        //设置定时器模式
    TMOD |= 0x01;        //设置定时器模式
    TL0 = 0x18;        //设置定时初值
    TH0 = 0xFC;        //设置定时初值
    TF0 = 0;        //清除TF0标志
    TR0 = 1;        //定时器0开始计时
    ET0=1;
    EA=1;
    PT0=0;
}
#ifndef __TIMER0_H__
#define __TIMER0_H__

 void Timer0Init(void);

#endif

3、流水灯代码(还是写了。。)

//Hc595SendByte(0x7F);//0111 1111
//Hc595SendByte(0x7E);//0111 1110
//Hc595SendByte(0xFD);//1111 1101
//Hc595SendByte(0x7B);//0111 1011
//Hc595SendByte(0xF7);//1111 0111
//Hc595SendByte(0x6F);//0110 1111
//Hc595SendByte(0xDF);//1101 1111
//Hc595SendByte(0x3F);//0011 1111//中断函数,可能要再开一个定时器,不然没有办法示,奇

4、数码管动画

void perform2(void)
{
	Nixie_Scan(1,13);Delay(700);
	Nixie_Scan(1,14);Delay(700);
	Nixie_Scan(1,15);Delay(700);
	Nixie_Scan(1,16);Delay(700);
	Nixie_Scan(1,17);Delay(700);
	Nixie_Scan(2,13);Delay(700);
	Nixie_Scan(2,14);Delay(700);
	Nixie_Scan(2,15);Delay(700);
	Nixie_Scan(2,16);Delay(700);
	Nixie_Scan(2,17);Delay(700);
	Nixie_Scan(3,13);Delay(700);
	Nixie_Scan(3,14);Delay(700);
	Nixie_Scan(3,15);Delay(700);
	Nixie_Scan(3,16);Delay(700);
	Nixie_Scan(3,17);Delay(700);
	Nixie_Scan(4,13);Delay(700);
	Nixie_Scan(4,14);Delay(700);
	Nixie_Scan(4,15);Delay(700);
    Nixie_Scan(4,16);Delay(700);
	Nixie_Scan(4,17);Delay(700);
}

 显示的十六进制数码管要自己去根据实际调整,这里不一样

unsigned char FreqSelect,MusicSelect;
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x6F,0x40,0X7F,0XDF,0XEF,0XFE,0XFD,0XFD,0XF7,0XEF,0XBF,0X7F};
void Nixie_Scan(unsigned char Location,Number)
{
	Hc595SendByte2(0xff);//段码清0,消影
	switch(Location)		//位码输出
	{
		case 1:S3 = 0;break;
		case 2:S2 = 0;break;
		case 3:S1 = 0;break;
		case 4:S0 = 0;break;
	}
	Hc595SendByte2(NixieTable[Number]);	//段码输出
	Delay(1);				//显示一段时间
	
}
//0X7F,0XBF,0XFD,0XF7,0XEF //0XEF,0XDF,0XFD,0XFB,0X7F
///显示6的动画afedcg 0X7F,0XFB,0XF7,0XEF,0XDF,0XFD,编码备用
因为学长的电路图而重写的版本,ke wu
//0X7F 0XDF 0XEF 0XFE 0XFD//0XFD 0XF7 0XEF 0XBF 0X7F//GAI BAN//0X7F,0XBF,0XFE,0XFD,0XF7,0XEF

5、放歌

unsigned char FreqSelect,MusicSelect;
//索引与频率对照表
unsigned int FreqTable[]={0,
	63628,63731,63835,63928,64021,64103,64185,64260,64331,64400,64463,64528,
	64580,64633,64684,64732,64777,64820,64860,64898,64934,64968,65000,65030,
	65058,65085,65110,65134,65157,65178,
};
//播放速度,值为四分音符的时长(ms)
#define SPEED	500
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P	0 
#define M2	15
#define M3	17
#define M4	18
#define M4_	19
#define M5	20
#define M5_	21
#define M6	22
#define M6_	23
#define M7	24
#define H1	25
#define H2	27
#define H3	29
#define H4	30
#define H5	32
#define H6	35
unsigned char code Music[]={
	//音符,时值,
	//1
	P,4,P,4,P,4,M6,	2,M7,2,
	H1,	4+2,M7,2,H1,4,H3,4,
	M7,	4+4+4,M3,2,M3,2,
	//2
	M6,	4+2,M5,	2,M6,4,H1,4,
	M5,	4+4+4,M3,4,
	M4,	4+2,M3,	2,M4,4,H1,4,
	//3
	M3,	4+4,P,2,H1,2,H1,2,H1,2,
	M7,	4+2,M4_,2,M4_,4,M7,	4,
	M7,	8,P,4,M6,2,M7,2,
	//4
	H1,	4+2,M7,	2,H1,4,H3,4,
	M7,	4+4+4,M3,2,M3,2,
	M6,	4+2,M5,2,M6,4,H1,4,
	//5
	M5,	4+4+4,M2,2,M3,2,
	M4,	4,H1,2,M7,2+2,H1,2+4,
	H2,	2,H2,2,H3,2,H1,2+4+4,
	//6
	H1,	2,M7,2,M6,2,M6,2,M7,4,M5_,4,
	M6,	4+4+4,
	0xFF	//终止标志
};

 这里放完歌后会自动返回主函数(乐谱只有一部分,曲名天空之城)

int perform()
{
    perform2();
	while(Music[MusicSelect]!=0xFF)
			{
			    Timer0Init();
				if(Music[MusicSelect]!=0xFF)	//如果不是停止标志位
				{
				FreqSelect=Music[MusicSelect];	//选择音符对应的频率
				MusicSelect++;
				Delay(SPEED/4*Music[MusicSelect]);	//选择音符对应的时值
				MusicSelect++;
				TR0=0;
				Delay(700);	//音符间短暂停顿
				TR0=1;
				}
			}
	mode=0;
	TR0=0;
	Music[1];
	MusicSelect=0;
    return 0;				
}

6、延时函数


void Delay(unsigned int xms)
{
	unsigned char i, j;
	while(xms--)
	{
		i = 2;
		j = 239;
		do
		{
			while (--j);
		} while (--i);
	}
}

#ifndef __DELAY_H__
#define __DELAY_H__

void Delay(unsigned int xms);

#endif

中断函数 

void Timer0_Routine() interrupt 1
{  

	if(mode==1)
	{
		if(FreqTable[FreqSelect])	//如果不是休止符
		{
			/*取对应频率值的重装载值到定时器*/
			TL0 = FreqTable[FreqSelect]%256;		//设置定时初值
			TH0 = FreqTable[FreqSelect]/256;		//设置定时初值
			Hc595SendByte(0xff);
			Hc595SendByte(0x00);
			
		}
	}
}

 7、主函数

void main()
{
	unsigned char Time,i;
	while(1)
{
	if(mode==0)
{
		for(Time=0;Time<100;Time++)		//改变亮灭时间,由暗到亮
		{
			for(i=0;i<20;i++)			//计次延时
			{
				Hc595SendByte(0X01);					//LED亮
				S0=0;S1=0;S2=0;S3=0;
				Hc595SendByte2(0X00);
				LED =0;
				elay(Time);			//延时Time
				Hc595SendByte(0XFF);					//LED灭
				S0=1;S1=1;S2=1;S3=1;
				Hc595SendByte2(0XFF);
				LED =1;
				elay(100-Time);		//延时100-Time
			}
		}
		for(Time=100;Time>0;Time--)		//改变亮灭时间,由亮到暗
		{
			for(i=0;i<20;i++)			//计次延时
			{
				Hc595SendByte(0X01);					//LED亮
				S0=0;S1=0;S2=0;S3=0;
				Hc595SendByte2(0X00);
				LED =0;
				elay(Time);			//延时Time
				Hc595SendByte(0XFF);					//LED灭
				S0=1;S1=1;S2=1;S3=1;
				Hc595SendByte2(0XFF);
				LED =1;
				elay(100-Time);		//延时100-Time
			}
		}
	}
		if(SW2==0)
		{
			mode=1;
			if (mode==1)
			{
				{
					perform();
				}
			}
		}
			
		if(SW3==0)
		{
			mode=2;
			if (mode==2)
			{
				
			}
		}
}

放在主函数里的延时(这里延时大概是0.45us,当时弄错了QWQ)

void elay(unsigned int t)
{
	while(t--);
}

9.功能切换 (未完善)

void zhuangtai2()
{
	switch(mode)
	{
		case(0):zhuangtai=0;break;
		case(1):perform();break;
		case(2):zhuangtai=2;break;
	}
}

总结

f75fa0223cce422b8d5cc8e8f6081096.jpeg

NE555芯片原理与使用

  

 

表示低电平会触发这个引脚,加个横杠表示低电平触发这个引脚

运放,差分电路是什么,非门是什么

比较器是将一个模拟电压信号与一个基准电压相比较的电路。比较器的两路输入为模拟信号,输出则为二进制信号 0 或 1,当输入电压的差值增大或减小且正负符号不变时,其输出保持恒定。

 

C1和C2就是两个差分电路

电子琴的关键在于555定时发生器产生不同频率的脉冲

电源与地之间接电容的原因有两个作用,储能和旁路储能:电路的耗电有时候大,有时候小,当耗电突然增大的时候如果没有电容,电源电压会被拉低,产生噪声,振铃,严重会导致CPU重启,这时候大容量的电容可以暂时把储存的电能释放出来,稳定电源电压,就像河流和水库的关系旁路:电路电流很多时候有脉动,例如数字电路的同步频率,会造成电源电压的脉动,这是一种交流噪声,小容量的无极电容可以把这种噪声旁路到地(电容可以通交流,阻直流,小容量电容通频带比大电容高得多),也是为了提高稳定性

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值