嵌入式学习--江协51单片机day5

发布于:2025-05-14 ⋅ 阅读:(10) ⋅ 点赞:(0)

江协每个模块的学习都是第一集讲原理,第二集将简单应用。如果比较着急的,可以不看第一集,只要明白怎么用就行。

今天学习DS1302时钟和蜂鸣器

DS1302

内部原理图,DS1302是有内部电源,电源的引脚名要注意

这两个原理图比较重要,第一个是寄存器(BIT7-BIT4的单位是10xx,second,minute等是BCD码的存储,在使用时要进行转换),第二个是写和读的过程,模拟这个过程就能对DS1302进行读和写(要注意读的时钟只有15个周期,在模拟的时候要通过重复赋值过滤一个)

DS1302时钟

#include <REGX52.H>

//引脚定义
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;

//寄存器写入地址/指令定义
#define DS1302_SECOND		0x80
#define DS1302_MINUTE		0x82
#define DS1302_HOUR			0x84
#define DS1302_DATE			0x86
#define DS1302_MONTH		0x88
#define DS1302_DAY			0x8A
#define DS1302_YEAR			0x8C
#define DS1302_WP			0x8E

//时间数组,索引0~6分别为年、月、日、时、分、秒、星期
unsigned char DS1302_Time[]={19,11,16,12,59,55,6};

/**
  * @brief  DS1302初始化
  * @param  无
  * @retval 无
  */
void DS1302_Init(void)
{
	DS1302_CE=0;
	DS1302_SCLK=0;
}

/**
  * @brief  DS1302写一个字节
  * @param  Command 命令字/地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void DS1302_WriteByte(unsigned char Command,Data)
{
	unsigned char i;
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

/**
  * @brief  DS1302读一个字节
  * @param  Command 命令字/地址
  * @retval 读出的数据
  */
unsigned char DS1302_ReadByte(unsigned char Command)
{
	unsigned char i,Data=0x00;
	Command|=0x01;	//将指令转换为读指令
	DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);
		DS1302_SCLK=0;
		DS1302_SCLK=1;
	}
	for(i=0;i<8;i++)
	{
		DS1302_SCLK=1;
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0;	//读取后将IO设置为0,否则读出的数据会出错
	return Data;
}

/**
  * @brief  DS1302设置时间,调用之后,DS1302_Time数组的数字会被设置到DS1302中
  * @param  无
  * @retval 无
  */
void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP,0x00);
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//十进制转BCD码后写入
	DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
	DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
	DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
	DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
	DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
	DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
	DS1302_WriteByte(DS1302_WP,0x80);
}

/**
  * @brief  DS1302读取时间,调用之后,DS1302中的数据会被读取到DS1302_Time数组中
  * @param  无
  * @retval 无
  */
void DS1302_ReadTime(void)
{
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;//BCD码转十进制后读取
	Temp=DS1302_ReadByte(DS1302_MONTH);
	DS1302_Time[1]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DATE);
	DS1302_Time[2]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_HOUR);
	DS1302_Time[3]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_MINUTE);
	DS1302_Time[4]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_SECOND);
	DS1302_Time[5]=Temp/16*10+Temp%16;
	Temp=DS1302_ReadByte(DS1302_DAY);
	DS1302_Time[6]=Temp/16*10+Temp%16;
}

DS1302可调时钟

这个主要是比较复杂

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Delay.h"
#include "Timer0.h"
#include "Key.h"
unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;
void TimeShow()
{
		DS1302_ReadTime();
		LCD_ShowNum(1,1,DS1302_Time[0],2);
		LCD_ShowNum(1,4,DS1302_Time[1],2);
		LCD_ShowNum(1,7,DS1302_Time[2],2);
		LCD_ShowNum(2,1,DS1302_Time[3],2);
		LCD_ShowNum(2,4,DS1302_Time[4],2);
		LCD_ShowNum(2,7,DS1302_Time[5],2);
}

void TimeSet()
{
		if(KeyNum==2)
		{
			TimeSetSelect++;
			TimeSetSelect%=6;
		
		}
		if(KeyNum==3)
		{
			DS1302_Time[TimeSetSelect]++;
			if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
			if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
			if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7
				||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12)
			{
				if(DS1302_Time[2]>31)DS1302_Time[2]=1;
			}
			else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11)
			{
				if(DS1302_Time[2]>30)DS1302_Time[2]=1;
			}
			else if(DS1302_Time[1]==2)
			{
				if(DS1302_Time[1]%4==0)
				{
					if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
					
				}
				else
				{
					if(DS1302_Time[1]>28){DS1302_Time[2]=1;}
				}
			}
			if(DS1302_Time[3]>23){DS1302_Time[3]=0;}
			if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
			if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
		}
		if(KeyNum==4)
		{
			DS1302_Time[TimeSetSelect]--;
			if(DS1302_Time[0]<0){DS1302_Time[0]=99;}
			if(DS1302_Time[1]<1){DS1302_Time[1]=12;}
			if(DS1302_Time[1]==1||DS1302_Time[1]==3||DS1302_Time[1]==5||DS1302_Time[1]==7
				||DS1302_Time[1]==8||DS1302_Time[1]==10||DS1302_Time[1]==12)
			{
				if(DS1302_Time[2]<1)DS1302_Time[2]=31;//更改月后更改前的日和更改后的月不匹配
				if(DS1302_Time[2]>31)DS1302_Time[2]=1;

			}
			else if(DS1302_Time[1]==4||DS1302_Time[1]==6||DS1302_Time[1]==9||DS1302_Time[1]==11)
			{
				if(DS1302_Time[2]<1)DS1302_Time[2]=30;
				if(DS1302_Time[2]>30)DS1302_Time[2]=1;

			}
			else if(DS1302_Time[1]==2)
			{
				if(DS1302_Time[1]%4==0)
				{
					if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
					if(DS1302_Time[2]>29){DS1302_Time[2]=1;}

					
				}
				else
				{
					if(DS1302_Time[1]<1){DS1302_Time[2]=28;}
					if(DS1302_Time[1]>28){DS1302_Time[2]=1;}

				}
			}
			if(DS1302_Time[3]<0){DS1302_Time[3]=23;}
			if(DS1302_Time[4]<0){DS1302_Time[4]=59;}
			if(DS1302_Time[5]<0){DS1302_Time[5]=59;}
		}
		//设置时闪烁
		if(TimeSetSelect==0&&TimeSetFlashFlag==1){LCD_ShowString(1,1,"  ");}
		else{	LCD_ShowNum(1,1,DS1302_Time[0],2);}
		if(TimeSetSelect==1&&TimeSetFlashFlag==1){LCD_ShowString(1,4,"  ");}
		else{	LCD_ShowNum(1,4,DS1302_Time[1],2);}
		if(TimeSetSelect==2&&TimeSetFlashFlag==1){LCD_ShowString(1,7,"  ");}
		else{	LCD_ShowNum(1,7,DS1302_Time[2],2);}
		if(TimeSetSelect==3&&TimeSetFlashFlag==1){LCD_ShowString(2,1,"  ");}
		else{	LCD_ShowNum(2,1,DS1302_Time[3],2);}
		if(TimeSetSelect==4&&TimeSetFlashFlag==1){LCD_ShowString(2,4,"  ");}
		else{	LCD_ShowNum(2,4,DS1302_Time[4],2);}
		if(TimeSetSelect==5&&TimeSetFlashFlag==1){LCD_ShowString(2,7,"  ");}
		else{	LCD_ShowNum(2,7,DS1302_Time[5],2);}
}

void main()
{
	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");//初始化并设置格式
	Timer0Init();
	DS1302_SetTime();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)//按键一按下切换模式
		{
				if(MODE==0){MODE=1;}//1是设置0是展示
				else if(MODE==1){MODE=0;DS1302_SetTime();}
		}
		switch(MODE)
		{
			case 0:TimeShow();break;
			case 1:TimeSet();break;
		}

	}



}
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=500)
	{
		T0Count=0;
		TimeSetFlashFlag=!TimeSetFlashFlag;
	}
}

蜂鸣器

这个不用了解地很清楚

蜂鸣器播放提示音

#include <REGX52.H>
#include  "Delay.h"
#include <INTRINS.H>
//蜂鸣器端口
sbit Buzzer=P2^5;
/**
  * @brief  蜂鸣器私有延时函数
  * @param  
  * @retval 
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}
/**
  * @brief  蜂鸣器发生
  * @param  ms 发生时长
  * @retval 
  */
void Buzzer_Time(unsigned int ms)
{
			unsigned int i;

			for(i=0;i<ms*2;i++)
			{
						Buzzer=!Buzzer;
						Buzzer_Delay500us();
			}
}

蜂鸣器播放音乐

#include <REGX52.H>
#include "Delay.h"
#include "Timer0.h"
sbit Buzzer=P2^5;
#define SPEED 250
//音符与索引对应表,P:休止符,L:低音,M:中音,H:高音,下划线:升半音符号#
#define P	0
#define L1	1
#define L1_	2
#define L2	3
#define L2_	4
#define L3	5
#define L4	6
#define L4_	7
#define L5	8
#define L5_	9
#define L6	10
#define L6_	11
#define L7	12
#define M1	13
#define M1_	14
#define M2	15
#define M2_	16
#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 H1_	26
#define H2	27
#define H2_	28
#define H3	29
#define H4	30
#define H4_	31
#define H5	32
#define H5_	33
#define H6	34
#define H6_	35
#define H7	36

unsigned int FreqTable[]={
	0,63628,
63731,63836,63929,64021,64104,64185,64261,64332,64400,64464,64524,
64580,64634,64685,64733,64778,64820,64861,64899,64935,
64968,65000,65030,65058,65086,65111,65135,65157,65179,65199,65218,65235,65252,65268,65283
};
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,
	H1,	2,
	H2,	2,
	
	H3,	4+2,
	H2,	2,
	H3,	4,
	H5,	4,
	
	//7
	H2,	4+4+4,
	M5,	2,
	M5,	2,
	
	H1,	4+2,
	M7,	2,
	H1,	4,
	H3,	4,
	
	H3,	4+4+4+4,
	
	//8
	M6,	2,
	M7,	2,
	H1,	4,
	M7,	4,
	H2,	2,
	H2,	2,
	
	H1,	4+2,
	M5,	2+4+4,
	
	H4,	4,
	H3,	4,
	H3,	4,
	H1,	4,
	
	//9
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4,
	H5,	4,
	
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	//10
	H2,	4,
	H1,	2,
	H2,	2,
	H2,	4,
	H5,	4,
	
	H3,	4+4+4,
	H3,	4,
	
	H6,	4+4,
	H5,	4+4,
	
	//11
	H3,	2,
	H2,	2,
	H1,	4+4,
	P,	2,
	H1,	2,
	
	H2,	4,
	H1,	2,
	H2,	2+4,
	M7,	4,
	
	M6,	4+4+4,
	P,	4,
	
	0xFF	//终止标志
};

unsigned char FreqSelect,MusicSelect;


void main()
{
	Timer0Init();
	while(1)
	{
		if(Music[MusicSelect])
		{
		FreqSelect=Music[MusicSelect];
		MusicSelect++;
		Delay(SPEED/4*Music[MusicSelect]);
		MusicSelect++;
		TR0=0;
		Delay(5);
		TR0=1;
		}
		else
		{
			TR0=0;
			while(1);
		}
	}



}
void Timer0_Routine() interrupt 1
{
	if(FreqTable[FreqSelect])
	{
	TL0 = FreqTable[FreqSelect]%256;		//设置定时初值
	TH0 = FreqTable[FreqSelect]/256;		//设置定时初值
	}
	
	Buzzer=!Buzzer;
}


网站公告

今日签到

点亮在社区的每一天
去签到