C51江协源代码(加详细的注释)

目录

1.点灯

1.1点亮第一个LED(三种方法)

1.2LED闪烁

1.3LED流水灯

1.4流水灯随意控制时间的形式

2.独立按键

2.1独立按键控制led灯亮灭

2.2独立按键控制led状态

2.3独立按键控制led显示二进制

2.4独立按键控制led移位

3.数码管

3.1静态数码管显示

3.2动态数码管显示

4.模块化编程

5.LCD1602

6.键盘

6.1矩阵键盘

6.2密码锁

7.定时器

7.1按键控制led流水灯模式

7.2定时器时钟

8.串口

8.1串口向电脑发送数据

8.2电脑通过串口控制led

9.LED点阵屏

9.2.1led点阵屏显示图形 

9.2.2LED点阵屏显示动画

10.DS1302实时时钟

10.1 DS1302时钟 


1.点灯

1.1点亮第一个LED(三种方法)

#include<REGX52.H>//点击右键来的
void main()
{
    P2=0xfe;//1111 1110将其转为上面的16进制的数
   //这个上面的0x是一个前缀,代表后面的是十六进制数
    while(1){}
}
#include <REGX52.H>//点击右键来的
void main()
{
    P2_0=0;//输出一个低电平0,这时,第一个led灯被点亮
//由于我的LED是通过正极接到单片机的某个引脚上,那么当引脚输出低电平(0)时,LED就会点亮;
//如果你的不同,那么就接在1试试;
//你要点亮其他的灯也可以P2_x=0;这个x在0到7之间,这个0->1号,1->2号,2->3号
}
#include"reg52.h"//这个一个自己打的头文件
sbit led1=P2^0;//定义一个名字为led1的名字,使其等于第一个灯的
void main()
{
    while(1){
        led1=0;//输出低电压
    }
}
/*Sbit是C51单片机中位地址的定义指令。单片机的编程需要控制字节地址或位地址进行输入和输出,
以控制其它设备,而位地址定义sbit是基础。*/
//这个0->1号,1->2号,2->3号····

1.2LED闪烁

#include <REGX52.H>
//下面是延时函数
//------------------------------------------
void Delay(unsigned int xms)	
{
	unsigned char i, j;
	while(xms--){
	   i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
//-------------------------------------------
void main(){
	P2=0xfe;//亮
	Delay(500);
	P2=0xff;//灭
	Delay(500);
}

1.3LED流水灯

#include <REGX52.H>
#include<intrins.h>
void Delay500ms()		//@12.000MHz
{
	unsigned char i, j, k;
    _nop_();//只要你不是特别精确,这个可以删除
	i = 4;	  // _nop_();需要加一个头文件#include<INTRINS.H>
	j = 205;
	k = 187;
	do
	{
		do
		{  
		while (--k);
		} while (--j);
	} while (--i);
}
void main()
{      while(1)
	  {
	  	  P2=0xfe;//1111 1110 第一个亮
		  Delay500ms();
		  P2=0xfd;	 //1111 1101 第二个亮
		  Delay500ms();
		  P2=0xfb;	 //1111 1011 第3个亮
		  Delay500ms();
		  P2=0xf7;	  //1111 0111 第4个亮
		  Delay500ms();
		  P2=0xef;	   //1110 1111 第5个亮
		  Delay500ms();
		  P2=0xdf;	   //1101 1111 第6个亮
		  Delay500ms();
		  P2=0xbf;	   //1011 1111 第7个亮
		  Delay500ms();
		  P2=0x7f;	   //0111 1111 第8个亮
		  Delay500ms();
      }
}

1.4流水灯随意控制时间的形式

#include <REGX52.H>
void Delay1ms(unsigned int xms)		//起一个函数x毫秒,这里有软件生产加一点改动
{
	unsigned char i, j;
	while(xms)
	{
		i = 2;
		j = 239;
	do
	{
		while (--j);
	} while (--i);
	   xms=xms-1;
	}

}

void main()
{
     while(1)
	  {
	  	  P2=0xfe;//1111 1110  第1灯亮
		  Delay1ms(500);//括号里面的500可以改为其他数字
		  P2=0xfd;	 //1111 1101   第2灯亮
		  Delay1ms(500);
		  P2=0xfb;	 //1111 1011    第3灯亮
		  Delay1ms(500);
		  P2=0xf7;	  //1111 0111	 第4灯亮
		  Delay1ms(500);
		  P2=0xef;	   //1110 1111 	  第5灯亮
		  Delay1ms(500);
		  P2=0xdf;	   //1101 1111 	  第6灯亮
		  Delay1ms(500);
		  P2=0xbf;	   //1011 1111 	 第7灯亮
		  Delay1ms(500);
		  P2=0x7f;	   //0111 1111  第8灯亮
		  Delay1ms(500);
      }
}

2.独立按键

2.1独立按键控制led灯亮灭

#include <REGX52.H>
void main()
{
    //P2=0xfe; 操作一个寄存器8位的时给8位的数据
    //P2_0=0;//操作寄存器1位时给1位的数据0/1(给2也相当是1)
	//P2_0=1;//加一个这个是不是led就会熄灭
	//第一个按键控制,按下时点亮执行P2_0=0;,松开时熄灭执行P2_0=1;
	while(1)
	{
	  if(P3_1==0)//第一个键时P3_1,第二个P3_0,第三个P3_2,第四个P3_3
	  {
	    P2_0=0;  
	  }
	  else
	  {
	     P2_0=1;
	  }
	}
}

 

2.2独立按键控制led状态

#include <REGX52.H>
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--){
	  i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
void main(){
	while(1){
		if(P3_1==0){
		  Delay(20);//消除按下抖动
		  while(P3_1==0);//检测松手
		  Delay(20);//消除松手抖动
		  P2_0=~P2_0;
		}
	}
}

2.3独立按键控制led显示二进制

#include <REGX52.H>
void Delay(unsigned int xms)		//@12.000MHz
{
	unsigned char i, j;
	while(xms--){
	  i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
void main(){
	unsigned int led=0;//定义一个变量
	while(1){
		if(P3_1==0){  //P3_1是第一个按键
			Delay(20);
			while(P3_1==0);
			Delay(20);
			//这里不能直接写成P2++,P2再加就会溢出,加到最大就变成最小的0000 0000
			//P2=~P2,这里取反而变成1111 1111 ,从此循环,造成不能达到想要的结果
			led++;
			P2=~led;

		}
	}
}

2.4独立按键控制led移位

#include <REGX52.H>
void Delay(unsigned int xms)		
{
	unsigned char i, j;
	while(xms--){
	  i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
void main(){
	unsigned int led=0;//定义一个变量
	while(1){
		if(P3_1==0){
			Delay(20);
			while(P3_1==0);
			Delay(20);
//下面三行是与上一个代码变化的部分
			led++;
			if(led>=8)led=0;
			P2=~(0x01<<led);//<<代表向左移位,<<1代表左移一位 例如0000 0001变成0000 0010
		}

	}
}

增加一个方向的方法 

#include <REGX52.H>
void Delay(unsigned int xms)		
{
	unsigned char i, j;
	while(xms--){
	  i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
void main(){
	unsigned int led=0;//定义一个变量
	while(1){
		if(P3_1==0){
			Delay(20);
			while(P3_1==0);
			Delay(20);
			led++;
			if(led>=8)led=0;
			P2=~(0x01<<led);//<<代表向左移位,<<1代表左移一位 例如0000 0001变成0000 0010
		   }
		//增加一个使得按该键向另一个方向移动---------
		//--------------------增加的部分---------------
		if(P3_0==0){
		 	Delay(20);
			while(P3_0==0);
			Delay(20);
			if(led==0)led=7;
			else led--;
			P2=~(0x01<<led);			
		}	
		//---------------------------------------------

	}
}

3.数码管

3.1静态数码管显示

//要求:需要第三个数码管显示6
//第三个数码管是LED6,由图可知对于的是Y5,Y5转为二进制是101
//给到的信号要高位对高位,所以P2_4=1;(第一个1)P2_3=0;P2_2=1;
//其次因为要显示6,段码为1011 1110,
//高位对高位=0 1 1 1 1 1 0 1;转换成十六进制位输出=0x7D;
#include <REGX52.H>
void main(){
	P2_4=1;
	P2_3=0;
	P2_2=1;
	P0=0x7D;
	while(1){}
}
#include <REGX52.H>
//下面这个函数用来实现输出在哪一个数码管上
void sumag(unsigned char Location,Number){
		switch(Location)
   {
   	  case 1:	P2_4=1;P2_3=1;P2_2=1;break;//led8
	  case 2:	P2_4=1;P2_3=1;P2_2=0;break;//led7
	  case 3:	P2_4=1;P2_3=0;P2_2=1;break;
	  case 4:	P2_4=1;P2_3=0;P2_2=0;break;
	  case 5:	P2_4=0;P2_3=1;P2_2=1;break;
	  case 6:	P2_4=0;P2_3=1;P2_2=0;break;
	  case 7:	P2_4=0;P2_3=0;P2_2=1;break;
	  case 8:	P2_4=0;P2_3=0;P2_2=0;break;
   }
   P0=0x7d;
}
void main(){
	sumag(7,2);//2会赋值给number,但现在上面并未处理
	while(1){}
}
#include <REGX52.H>
unsigned char sumagtable[]={0x3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
void sumag(unsigned char Location,Number){
		switch(Location)
   {
   	  case 1:	P2_4=1;P2_3=1;P2_2=1;break;//led8
	  case 2:	P2_4=1;P2_3=1;P2_2=0;break;//led7
	  case 3:	P2_4=1;P2_3=0;P2_2=1;break;
	  case 4:	P2_4=1;P2_3=0;P2_2=0;break;
	  case 5:	P2_4=0;P2_3=1;P2_2=1;break;
	  case 6:	P2_4=0;P2_3=1;P2_2=0;break;
	  case 7:	P2_4=0;P2_3=0;P2_2=1;break;
	  case 8:	P2_4=0;P2_3=0;P2_2=0;break;
   }
   P0=sumagtable[Number];//引用number的值
}
void main(){
	sumag(6,2);//前面6代表是第6个数码管,2代表的是输出数字2
	while(1){}
}

3.2动态数码管显示

#include <REGX52.H>
//下面是延时函数
//------------------------------------------
void Delay(unsigned int xms)	
{
	unsigned char i, j;
	while(xms--){
	   i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
	}
}
//-------------------------------------------
//下面一行定义一个数组方便调用
unsigned char sumagtable[]={0x3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};
void sumag(unsigned char Location,Number){
		switch(Location)
   {
   	  case 1:	P2_4=1;P2_3=1;P2_2=1;break;//led8
	  case 2:	P2_4=1;P2_3=1;P2_2=0;break;//led7
	  case 3:	P2_4=1;P2_3=0;P2_2=1;break;
	  case 4:	P2_4=1;P2_3=0;P2_2=0;break;
	  case 5:	P2_4=0;P2_3=1;P2_2=1;break;
	  case 6:	P2_4=0;P2_3=1;P2_2=0;break;
	  case 7:	P2_4=0;P2_3=0;P2_2=1;break;
	  case 8:	P2_4=0;P2_3=0;P2_2=0;break;
   }
   P0=sumagtable[Number];//引用number的值
   Delay(1);//稳定一秒,让其稳定显示,如果立马清零就会变得很暗
   P0=0x00;//清零
}
void main(){
	while(1){
		sumag(1,1);//前面6代表是第6个数码管,2代表的是输出数字2
		sumag(2,2);
		sumag(3,3);
		//这里最多弄8个
	}
}

4.模块化编程

借用3.2的代码将其模块化

首先建立5个新的文档,分别命名为main.c      Delay.c   Delay.h      sumag.c      sumag.h

再main.c中存放的代码是

#include <REGX52.H>
#include "Delay.h"//调用
#include "sumag.h"//调用
void main()
{
	while(1){
	sumag(1,1);
    sumag(2,2); 
    sumag(3,3);
	}
}

Delay.c中放的是

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

 Delay.h中存放的是

#ifndef __DELAY_H__
#define __DELAY_H__


void Delay(unsigned int xms);//这里要写;结束

#endif

sumag.c存放的是

#include <REGX52.H>
#include "Delay.h"
unsigned char sumagtable[]={0x3F,0X06,0X5B,0X4F,0X66,0X6D,0X7D,0X07,0X7F,0X6F};//这是0~10
void sumag(unsigned char Location,Number)
{
   switch(Location)
   {
   	  case 1:	P2_4=1;P2_3=1;P2_2=1;break;//led8
	  case 2:	P2_4=1;P2_3=1;P2_2=0;break;//led7
	  case 3:	P2_4=1;P2_3=0;P2_2=1;break;
	  case 4:	P2_4=1;P2_3=0;P2_2=0;break;
	  case 5:	P2_4=0;P2_3=1;P2_2=1;break;
	  case 6:	P2_4=0;P2_3=1;P2_2=0;break;
	  case 7:	P2_4=0;P2_3=0;P2_2=1;break;
	  case 8:	P2_4=0;P2_3=0;P2_2=0;break;
   }
   P0=sumagtable[Number];//引用number的值
   Delay(1);//稳定一秒,让其稳定的显示,如果立马清零会导致变得很暗
   P0=0x00;//清零
} 

sumag.h存放的是

#ifndef __SUMAG_H__
#define __SUMAG_H__

void sumag(unsigned char Location,Number);

#endif

这样将每一部分都进行分开了,方便以后的调用

5.LCD1602

还是创建5个文档,mian.c     lcd1602.c   lcd1602.h    Delay.c    Delay.h

LCD_Init();//初始化
LCD_ShowChar(1,1,'a');//第一行第一列显示a
//显示字符
LCD_ShowString(1,3,"hello");//第一行第三列开始显示hello
//显示字符串
LCD_ShowNum(1,9,123,3);//第一行,第9列,开始显示123,长度为3
//显示十进制数字
LCD_ShowSignedNum(1,13,-66,2);
//显示带有符号的十进制数字
LCD_ShowHexNum(2,1,0xA8,2);
//显示16进制数字
LCD_ShowBinNum(2,4,0xAA,8);
//显示二进制数字

mian.c中含

#include <REGX52.H>
#include "lcd1602.h"
#include"Delay.h"
int result=0;
void main()
{
	LCD_Init();//初始化
	while(1){
		result++;
		Delay(1000);	
	   LCD_ShowNum(1,1,result,3);
	}
}

led1602.c中含(这个可以直接复制)

#include <REGX52.H>

//引脚配置:
sbit LCD_RS=P2^6;
sbit LCD_RW=P2^5;
sbit LCD_EN=P2^7;
#define LCD_DataPort P0

//函数定义:
/**
  * @brief  LCD1602延时函数,12MHz调用可延时1ms
  * @param  无
  * @retval 无
  */
void LCD_Delay()
{
	unsigned char i, j;

	i = 2;
	j = 239;
	do
	{
		while (--j);
	} while (--i);
}

/**
  * @brief  LCD1602写命令
  * @param  Command 要写入的命令
  * @retval 无
  */
void LCD_WriteCommand(unsigned char Command)
{
	LCD_RS=0;
	LCD_RW=0;
	LCD_DataPort=Command;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602写数据
  * @param  Data 要写入的数据
  * @retval 无
  */
void LCD_WriteData(unsigned char Data)
{
	LCD_RS=1;
	LCD_RW=0;
	LCD_DataPort=Data;
	LCD_EN=1;
	LCD_Delay();
	LCD_EN=0;
	LCD_Delay();
}

/**
  * @brief  LCD1602设置光标位置
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @retval 无
  */
void LCD_SetCursor(unsigned char Line,unsigned char Column)
{
	if(Line==1)
	{
		LCD_WriteCommand(0x80|(Column-1));
	}
	else if(Line==2)
	{
		LCD_WriteCommand(0x80|(Column-1+0x40));
	}
}

/**
  * @brief  LCD1602初始化函数
  * @param  无
  * @retval 无
  */
void LCD_Init()
{
	LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
	LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
	LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
	LCD_WriteCommand(0x01);//光标复位,清屏
}

/**
  * @brief  在LCD1602指定位置上显示一个字符
  * @param  Line 行位置,范围:1~2
  * @param  Column 列位置,范围:1~16
  * @param  Char 要显示的字符
  * @retval 无
  */
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
{
	LCD_SetCursor(Line,Column);
	LCD_WriteData(Char);
}

/**
  * @brief  在LCD1602指定位置开始显示所给字符串
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  String 要显示的字符串
  * @retval 无
  */
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=0;String[i]!='\0';i++)
	{
		LCD_WriteData(String[i]);
	}
}

/**
  * @brief  返回值=X的Y次方
  */
int LCD_Pow(int X,int Y)
{
	unsigned char i;
	int Result=1;
	for(i=0;i<Y;i++)
	{
		Result*=X;
	}
	return Result;
}

/**
  * @brief  在LCD1602指定位置开始显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~65535
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以有符号十进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:-32768~32767
  * @param  Length 要显示数字的长度,范围:1~5
  * @retval 无
  */
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
{
	unsigned char i;
	unsigned int Number1;
	LCD_SetCursor(Line,Column);
	if(Number>=0)
	{
		LCD_WriteData('+');
		Number1=Number;
	}
	else
	{
		LCD_WriteData('-');
		Number1=-Number;
	}
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
	}
}

/**
  * @brief  在LCD1602指定位置开始以十六进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~0xFFFF
  * @param  Length 要显示数字的长度,范围:1~4
  * @retval 无
  */
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i,SingleNumber;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		SingleNumber=Number/LCD_Pow(16,i-1)%16;
		if(SingleNumber<10)
		{
			LCD_WriteData(SingleNumber+'0');
		}
		else
		{
			LCD_WriteData(SingleNumber-10+'A');
		}
	}
}

/**
  * @brief  在LCD1602指定位置开始以二进制显示所给数字
  * @param  Line 起始行位置,范围:1~2
  * @param  Column 起始列位置,范围:1~16
  * @param  Number 要显示的数字,范围:0~1111 1111 1111 1111
  * @param  Length 要显示数字的长度,范围:1~16
  * @retval 无
  */
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
{
	unsigned char i;
	LCD_SetCursor(Line,Column);
	for(i=Length;i>0;i--)
	{
		LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
	}
}

lcd1602.h中含

#ifndef __LCD1602_H__
#define __LCD1602_H__

//用户调用函数:
void LCD_Init();
void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);

#endif

Delay.c和Delay.h可以将4.模块化编程的复制粘贴过来

6.键盘

6.1矩阵键盘

首先把前面Delay和lcd1602两个各自的两个文件复制在一个文件夹中,在创建一个main.c和

MatrixKey.c和MatrixKey.h几个文件

main.c

#include <REGX52.H>
#include"Delay.h"
#include"lcd1602.h"
#include"matrixkey.h"
unsigned char keynum;//什么函数
void main()
{
	LCD_Init();//初始化
	LCD_ShowString(1,1,"matrixkey:");//在1行第1列输出字符串matrixkey:
	while(1){
		keynum=matrixkey();//将获得的值给keynum	   
//如果没按键就是0,如果有按键就会卡在matrixkey,一旦松手就回返回给keynum
		if(keynum){	  //判断如果有按键按下,这里判断的是keynum!=0,在这里直接写keynum也行
		 	LCD_ShowNum(2,1,keynum,2);//第2行第1列开始输出长度为2,值为keynum
		}
	}
}

MatrixKey

#include <REGX52.H>
#include"Delay.h"
/*矩阵键盘读取按键代码,
如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键代码
没有按键按下时,返回0
*/
unsigned char matrixkey(){
	unsigned char keynumber=0;
	P1=0xff;//全部位于高电伏
	P1_3=0;//把第一列置零
	//Delay(20);while(P1_7==0);Delay(20);keynumber=1;这个是用来消隐的
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);keynumber=1;}//while(P1_7==0);
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);keynumber=5;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);keynumber=9;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);keynumber=13;}
//因为只有第一位置 置零了,所以其他列的都不亮
//这时P1_7对s1,P1_6对s5,····
	
	P1=0xff;//全部位于高电伏
	P1_2=0;//把第二列置零
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);keynumber=2;}//while(P1_7==0);
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);keynumber=6;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);keynumber=10;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);keynumber=14;}
	
	P1=0xff;//全部位于高电伏
	P1_1=0;//把第三列置零
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);keynumber=3;}//while(P1_7==0);
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);keynumber=7;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);keynumber=11;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);keynumber=15;}
	
	P1=0xff;//全部位于高电伏
	P1_0=0;//把第四列置零
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);keynumber=4;}//while(P1_7==0);
	if(P1_6==0){Delay(20);while(P1_6==0);Delay(20);keynumber=8;}
	if(P1_5==0){Delay(20);while(P1_5==0);Delay(20);keynumber=12;}
	if(P1_4==0){Delay(20);while(P1_4==0);Delay(20);keynumber=16;}
	return keynumber;
}


MatrixKey.h

#ifndef  __MATRIXKEY_H__
#define  __MATRIXJEY_H__
   unsigned char matrixkey();

#endif

6.2密码锁

只修改main.c的代码

#include <REGX52.H>
#include"Delay.h"
#include"lcd1602.h"
#include"MatrixKey.h"

unsigned char KeyNum;
unsigned int  Password,count;//密码,后者用来计次

void main(){
	LCD_Init();//初始化
	LCD_ShowString(1,1,"Password"); 
	while(1)
	{
		   KeyNum=matrixKey();
		   if(KeyNum!=0)
		   {
		       if(KeyNum<=10)//如果s1~s10按键按下,输入密码
			   {
			   	  if(count<4){	 //如果次数小于4
				  	Password*=10;		  //密码左移一位
				    Password+=KeyNum%10;//获取一位密码
				  	count++;//计次加一
				  }
				  LCD_ShowNum(2,1,Password,4);//更新显示
			   }
			   if(KeyNum==11)//如果s11键按下,为确认
			   {
			   		if(Password==2345)
					{	//如果密码等于正确密码
						LCD_ShowString(1,14,"ok "); //显示ok
						Password=0;	//密码清0
						count=0;  //计次清零
						LCD_ShowNum(2,1,Password,4); //更新显示
					}
					else 					   //否则
					{
					    LCD_ShowString(1,14,"not");//显示错误
					    Password=0;	//密码清0
						count=0;  //计次清零
						LCD_ShowNum(2,1,Password,4);//更新显示
					}
			   }
			   if(KeyNum==12)//如何s12按键按下,为取消键
			   {
				    Password=0;	//密码清0
					count=0;  //计次清零
					LCD_ShowNum(2,1,Password,4); //更新显示
			   }
			   
		   }
	}
}

7.定时器

#include <REGX52.H>
void Timer0_Init()//初始化函数
{
	//TMOD=0x01;//0000 0001	改为下面的,可以操作某些位,而不影响其他位
	TMOD=TMOD&0xf0;//把TMOD低四位清零,高四位不变
	//比如:1010 0011   1010 0011&1111 0000=1010 0000
	TMOD=TMOD|0x01;//把TMOD的低四位放置1,高四位保持不变
	//比如:1010 0000  1010 0000|0000 0001=1010 0001
	TF0=0;//先清零
	TR0=1; //开启,使其工作
	//0~65535,每隔1us计数加1,总计65535us
	//64535离计数器溢出差值1000,刚好1ms
	TH0=64535/256;//取高位
	TL0=64535/256; //取低位
	//例如:123 -》123/100=1  123%100=23
	ET0=1;
	EA=1;
	PT0=0;
}
void main()
{
	Timer0_Init();
	while(1)
	{
		
	}
}
//闹钟响之后,要跳转到下面这个子函数来,来执行中断任务
unsigned int T0Count;
void Timer0_Routine() interrupt 1
{
	//定时器中断之后会溢出就变成0了,下次开机计数就不是从初始值开始了
	//第一次是1ms,第二次就是从0开始就是65ms了
	//所以,每次重新开始之后,都要重新给它赋一个初值
	TH0=64535/256;//取高位
	TL0=64535/256; //取低位
	T0Count++;
	if(T0Count>=1000){
		T0Count=0;
		P2_0=~P2_0;//造成每隔一秒闪一下
	}
}

可以使用stc直接生成

调节地方

void Timer0_Init()		//1毫秒@12.000MHz
{
	//AUXR &= 0x7F;		//定时器时钟12T模式,这个在新系列的里面有
	//在89C52里面没有,所以删除
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	//stc生成的少了三个,把下面补充在下面
	ET0=1;
	EA=1;
	PT0=0;
}

 新的

#include <REGX52.H>
void Timer0_Init()		//1毫秒@12.000MHz
{
	//AUXR &= 0x7F;		//定时器时钟12T模式,这个在新系列的里面有
	//在89C52里面没有,所以删除
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	//stc生成的少了三个,把下面补充在下面
	ET0=1;
	EA=1;
	PT0=0;
}
void main()
{
	Timer0_Init();
	while(1)
	{
		
	}
}
//闹钟响之后,要跳转到下面这个子函数来,来执行中断任务
unsigned int T0Count;
void Timer0_Routine() interrupt 1
{
	//定时器中断之后会溢出就变成0了,下次开机计数就不是从初始值开始了
	//第一次是1ms,第二次就是从0开始就是65ms了
	//所以,每次重新开始之后,都要重新给它赋一个初值


//------------------修改地方-----------------------------------------
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
//-------------------------------------------------------------------
	

    T0Count++;
	if(T0Count>=1000){
		T0Count=0;
		P2_0=~P2_0;//造成每隔一秒闪一下
	}
}

7.1按键控制led流水灯模式

mian.c 

#include <REGX52.H>
#include"Timer0.h"
#include"Key.h"
#include"intrins.h"//提供左右循环移动函数的
unsigned char KeyNum,LEDMode;
void main()
{
    P2=0xfe;//给一个初值,方便移动
	Timer0_Init();
	while(1)
	{
	  KeyNum=key();
		if(KeyNum!=0){
			 if(KeyNum==1){
			 	LEDMode++;
				if(LEDMode>=2)LEDMode=0;
				//每次按下就是0 1 0 1的变化
			 }
		}
	}
}
//下面这个子函数代码闹钟响之后,它要跳转到这个子函数这来,执行中断
void Timer0_Routine() interrupt  1
{
   	static unsigned int T0Count;//static保留T0Count的值
    TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=500)//每隔500ms
	{
		T0Count=0;
//例如a=0x01  a=_crol_(a,1);	//a的值左移一位之后赋给a,一直到0x08之后
//又回到0x01
		if(LEDMode==0){
			P2=_crol_(P2,1); //左移
		}
		if(LEDMode==1){
			P2=_cror_(P2,1);//右移
		}	
	}
}   

Timer0.c 

#include <REGX52.H>
/*
定时器0初始化,//1毫秒@12.000MHz
*/
void Timer0_Init()		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
//-----下面的是需要自己加的-----------------------------
	ET0=1;
	EA=1;
	PT0=0;
//------------------------------------------------------
}
/*
定时器中断函数模板


void Timer0_Init()//初始化函数
{
	//TMOD=0x01;//0000 0001	改为下面的,可以操作某些位,而不影响其他位
	TMOD=TMOD&0xf0;//把TMOD低四位清零,高四位不变
	//比如:1010 0011   1010 0011&1111 0000=1010 0000
	TMOD=TMOD|0x01;//把TMOD的低四位放置1,高四位保持不变
	//比如:1010 0000  1010 0000|0000 0001=1010 0001
	TF0=0;//先清零
	TR0=1; //开启,使其工作
	//0~65535,每隔1us计数加1,总计65535us
	//64535离计数器溢出差值1000,刚好1ms
	TH0=64535/256;//取高位
	TL0=64535/256; //取低位
	//例如:123 -》123/100=1  123%100=23
	ET0=1;
	EA=1;
	PT0=0;
}	 */

Timer0.h 

#ifndef __Timer0_H__
#define __Timer0_H__
Timer0_Init();
#endif

Key.c 

#include <REGX52.H>
#include"Delay.h"
/*
*  目的:获取独立按键键码
*  参数:无
*返回值:按下按键的键码,范围:0~4,无按键按下时返回值为0
*/

unsigned char Key()
{
	unsigned char KeyNumber=0;

	if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
	if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
	if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
	if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}

	return KeyNumber;

}

Key.h 

#ifndef __KEY_H__
#define __KEY_H__


unsigned char Key();

#endif

7.2定时器时钟

只修改了main.c中的代码,其他的复制过来

#include <REGX52.H>
#include"Delay.h"
#include"lcd1602.h"
#include"Timer0.h"

unsigned char Sec,Min,Hour;//秒,分钟,小时
void main(){
	LCD_Init();
	Timer0_Init();
	LCD_ShowString(1,1,"Clock:");
	LCD_ShowString(2,1,"  :  :");//显示小时和分钟的: 分钟和秒的:
	while(1){
		  LCD_ShowNum(2,1,Hour,2);
		  LCD_ShowNum(2,4,Min,2);
		  LCD_ShowNum(2,7,Sec,2);
	}
}
void Timer0_Routine()  interrupt 1
{
	static unsigned int T0Count;
	TL0=0x18;
	TH0=0xFC;
	T0Count++;
	if(T0Count>=1000){
		T0Count=0;
		Sec++;
		if(Sec>=60){
			Sec=0;
			Min++;
			if(Min>=60){
				Min=0;
				Hour++;
				if(Hour>=24){
					Hour=0;
				}
			}
		}
	}
}

8.串口

8.1串口向电脑发送数据

main.c中

#include <REGX52.H>
#include"Delay.h"
#include"UART.h"
unsigned char Sec;	//每隔一秒发送一个递增的数
void main(){
	
	UART_Init();//初始化
	while(1){
		 UART_SendByte(Sec);
		 Sec++;
		 Delay(1000);
	}
}

UART.c

#include <REGX52.H>
/*
串口初始化,4800bps@12.000MHz
输入参数:无
返回值:无
*/
//波特率函数
//--------------------------------------
void UART_Init() 
{
	SCON=0x40;
	PCON |= 0x80;
	TMOD &= 0x0f;		//设置定时器模式
	TMOD |= 0x20; //模式变了,设定定时器1为8位自动重装方式
	TL1 = 0xF3;		//设定定时初值
	TH1 = 0xF3;		//设定定时器重装值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
}
//---------------------------------------

//发送的函数
//---------------------------------------
void UART_SendByte(unsigned char Byte)
{	 //只要把数据写到SBUF里面,就会发出去
	SBUF=Byte;
	//还需要检测是否完成,你刚写完不会立即发完,
	//如果你连续发,就会出错
	while(TI==0);
	TI=0;
	 
}
//---------------------------------------

UART.h

#ifndef __UART_H__
#define	__UART_H__
void UART_Init();
void UART_SendByte(unsigned char Byte);

#endif

8.2电脑通过串口控制led

由8.1的修改而来

mian.c

UART.c

9.LED点阵屏

9.2.1led点阵屏显示图形 

#include <REGX52.H>
#include"Delay.h"
#define  MATRIX_LED_PORT  P0//给P0口定义一下,方便修改
//74HC595
//-----------------------------------------------------------
sbit RCK=P3^5;//RCK是RCLK
sbit SCK=P3^6;//SCK是SRCLK
sbit SER=P3^4;//SER
/**
  *@brief 	74HC595写入一个字节(我的单片机上没有这个,但需要这个代码)
  *@param	要写入一个字节
  *@retval	无
*/
void _74HC595_WriteByte(unsigned char Byte){
//函数目的:运行一下这个函数,然后就会把里面参数这个数据给写入8个引脚
	unsigned char i;
	for(i=0;i<8;i++){
		SER=Byte&(0x80>>i);//右边这个代表右移i位
		SCK=1;
		SCK=0;//移进去之后我们就直接清零,为下一次移位做准备
	}
	RCK=1;
	RCK=0;	//送到右边
}
//-------------------------------------------------------------
/**
  *@brief 	led点阵屏显示一列数据
  *@param	Column 要选择的列,范围:0~7,0在最左边
  *@param   Data 选择列显示的数据,高位在上,1为亮,0为灭
  *@retval	
*/
void MatrixLED_ShowColumn(unsigned char Column,Data)//矩阵点阵屏
{	//图上左边的D0~D7称为Data,Column为列
	_74HC595_WriteByte(Data);
	/*
	if(Column==0){P0=~0x80;}//~0x80是0111 1111
	if(Column==1){P0=~0x40;}//~0x40是1011 1111
	//就这么写下去就可以了,但我们可以换一种方法	
	*/
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);//延时
	MATRIX_LED_PORT=0xff;//位清零,这两行相当与数码管当时的消影
			
}
void main()
{
	SCK=0;
	//因为要给SCK一个高电平让他移位,又因为单片机初始化后所有的l口都是高电平
	//所以一上电之后要先把他复为0
	RCK=0;//初始为低电平
	
	while(1)
	{
		MatrixLED_ShowColumn(0,0x3c);//第0列显示1010 1010
		MatrixLED_ShowColumn(1,0x42);//第1列
		MatrixLED_ShowColumn(2,0xa9);//第2列
		MatrixLED_ShowColumn(3,0x85);//第3列
		MatrixLED_ShowColumn(4,0x85);//第4列
		MatrixLED_ShowColumn(5,0xa9);//第5列
		MatrixLED_ShowColumn(6,0x42);//第6列
		MatrixLED_ShowColumn(7,0x3c);//第7列
	}
}

/*
---------------------------------------------------------------------------
void _74HC595_WriteByte(unsigned char BYte){
//函数目的:运行一下这个函数,然后就会把里面参数这个数据给写入8个引脚
	SER=Byte&0x80;
	//先取第八位(最下面那一位),如果第八位是1,上面就是0x80,为0的化就是0,1就是高电平,0就是低电平
	//如果我们对一位进行处理,那么后面这个操作数给1还是0,这是正常的
	//非0即1:如果不是0随便任何一个数,都会置1
	SCK=1;
	SCK=0;//移进去之后我们就直接清零,为下一次移位做准备
	//下面是最后从上到下第7位
	SER=Byte&0x40; //0x40就是0100 0000
	SCK=1;
	SCK=0;
	//下面是最后从上到下第6位
	SER=Byte&0x20; //0x40就是0010 0000
	SCK=1;
	SCK=0;
	//进行8次就可以把8位引进去了
} 
---------------------------------------------------------------------------
*/
/*
---------------------------------------------------------------------------
void MatrixLED_ShowColumn(unsigned char Column,Data)//矩阵点阵屏
{	//图上左边的D0~D7称为Data,Column为列
	_74HC595_WriteByte(Data);
	if(Column==0){P0=~0x80;}//~0x80是0111 1111
	if(Column==1){P0=~0x40;}//~0x40是1011 1111
			
}
----------------------------------------------------------------------------
*/

9.2.2LED点阵屏显示动画

打开取字模软件,点击新建图像,高度设为8,长度根据动画的长度来设计,进来后点击模拟动画的放大格点,放到自己觉得合适的大小,点击参数设置,点击其他选项

然后在画面上点出需要的,然后点击取模方式,点击C51格式,然后复制下面生成的数据,复制到我们代码动画那里

建造3个文档,分别是main.c   MatrixLED.c   MatrixLED.h

main.c中

#include <REGX52.H>
#include"Delay.h"
#include"MatrixLED.h"

unsigned char Animation[]={
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//这里是自己加的
	0xFF,0x08,0x08,0x08,0xFF,0x00,0x0E,0x15,
	0x15,0x15,0x08,0x00,0x7E,0x01,0x02,0x00,
	0x7E,0x01,0x02,0x00,0x0E,0x11,0x11,0x0E,
	0x00,0x3D,0x00,0x00,0x00,0x00,0x00,0x00,
	0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//这里是自己加的
};

void main()
{
	unsigned char i,offset=0,Count=0;//offset表示偏移量,因为要使其右移动
	//这里的两行东西重新定义了一个函数,放到MatrixLED.c里面去了
	MatrixLED_Init();
	while(1)						//Count用来计次
	{  	for(i=0;i<8;i++){
	    	MatrixLED_ShowColumn(i,Animation[i+offset]);//第i列显示,Animation[i]
		}
		Count++;
		if(Count>10){
			Count=0;
			offset++;//扫描10遍之后,就右移动一位
			//-----------------------------------
			//如果想要显示逐帧的offset就一次要加8
			//-----------------------------------
		}
		if(offset>40)//防止offset溢出,总共32个,取到最后一针的时候,应该是32-8
		{			 //因为自己加了16个,所以为40-8	,原本是>32,因为要把感叹号全部不再后
					 //再显示下一轮,所以是40
			offset=0;
		}
	}
}


/*-------------------------------------------------------
void main()
{
	//这里的两行东西重新定义了一个函数,放到MatrixLED.c里面去了
	MatrixLED_Init();
	while(1)
	{  	
		MatrixLED_ShowColumn(0,Animation[0]);//第0列显示1010 1010
		MatrixLED_ShowColumn(1,Animation[1]);//第1列
		MatrixLED_ShowColumn(2,Animation[2]);//第2列
		MatrixLED_ShowColumn(3,Animation[3]);//第3列
		MatrixLED_ShowColumn(4,Animation[4]);//第4列
		MatrixLED_ShowColumn(5,Animation[5]);//第5列
		MatrixLED_ShowColumn(6,Animation[6]);//第6列
		MatrixLED_ShowColumn(7,Animation[7]);//第7列
	}
}
从上面的代码改为了下面的代码

//----------------------------------------------------------------
void MatrixLED_ShowColumn(unsigned char Column,Data)//矩阵点阵屏
{	//图上左边的D0~D7称为Data,Column为列
	_74HC595_WriteByte(Data);
	if(Column==0){P0=~0x80;}//~0x80是0111 1111
	if(Column==1){P0=~0x40;}//~0x40是1011 1111
			
}
-------------------------------------------------------*/

MatrixLED.h

#ifndef _MATRIX_LED_H__
#define _MATRIX_LED_H__
void MatrixLED_ShowColumn(unsigned char Column,Data);
void MatrixLED_Init();

#endif

MatrixLED.c

#include <REGX52.H>
#include"Delay.h"
#define  MATRIX_LED_PORT  P0//给P0口定义一下,方便修改
//74HC595
//-----------------------------------------------------------
sbit RCK=P3^5;//RCK是RCLK
sbit SCK=P3^6;//SCK是SRCLK
sbit SER=P3^4;//SER
/**
  *@brief 	74HC595写入一个字节(我的单片机上没有这个,但需要这个代码)
  *@param	要写入一个字节
  *@retval	无
*/
void _74HC595_WriteByte(unsigned char Byte){
//函数目的:运行一下这个函数,然后就会把里面参数这个数据给写入8个引脚
	unsigned char i;
	for(i=0;i<8;i++){
		SER=Byte&(0x80>>i);//右边这个代表右移i位
		SCK=1;
		SCK=0;//移进去之后我们就直接清零,为下一次移位做准备
	}
	RCK=1;
	RCK=0;	//送到右边
}
/**
  *@brief   点阵屏初始化
  *@param	无
  *@retval	无
  */
void MatrixLED_Init(){ //初始化工作
	SCK=0;
	//因为要给SCK一个高电平让他移位,又因为单片机初始化后所有的l口都是高电平
	//所以一上电之后要先把他复为0
	RCK=0;//初始为低电平
}
//-------------------------------------------------------------
/**
  *@brief 	led点阵屏显示一列数据
  *@param	Column 要选择的列,范围:0~7,0在最左边
  *@param   Data 选择列显示的数据,高位在上,1为亮,0为灭
  *@retval	
*/
void MatrixLED_ShowColumn(unsigned char Column,Data)//矩阵点阵屏
{	//图上左边的D0~D7称为Data,Column为列
	_74HC595_WriteByte(Data);
	/*
	if(Column==0){P0=~0x80;}//~0x80是0111 1111
	if(Column==1){P0=~0x40;}//~0x40是1011 1111
	//就这么写下去就可以了,但我们可以换一种方法	
	*/
	MATRIX_LED_PORT=~(0x80>>Column);
	Delay(1);//延时
	MATRIX_LED_PORT=0xff;//位清零,这两行相当与数码管当时的消影
			
}

10.DS1302实时时钟

10.1 DS1302时钟 

5个文档,分别是DS1302.c   DS1302.h   main.c    lcd1602.c    lcd1602.h   

main.c中

#include <REGX52.H>
#include"lcd1602.h"
#include"DS1302.h"
void main(){

	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  -  -  ");
	LCD_ShowString(2,1,"  :  :  ");
	//————————————————————————————————————————
	DS1302_WriteByte(0x8e,0x00);
	//    如果读出时间为一个大于59的并且不动的数,则芯片可能是处在写保护
	//状态,在这里加上上面一句的就可以解除芯片保护
	//————————————————————————————————————————
	DS1302_SetTime();
	while(1){
		DS1302_ReadTime();
		//BCD码是用四位二进制数来表示1位10进制数
		//BCD码转为十进制:DEC=BCD/16*10+BCD%16
		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);//秒
		}
}

DS1302.c

#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//写保护

unsigned char DS1302_Time[]={19,11,16,12,59,55,6};

//默认情况下CE是0,SCLK也是0,但我们单片机所有的L口默认都是1
void DS1302_Init(void)//初始化
{
	DS1302_CE=0;
	DS1302_SCLK=0;				
}
//单字节写入(SINGLE-BYTE WRITE)
void DS1302_WriteByte(unsigned char Command,Data)//命令字Command,数据Data
{
	unsigned char i;
	DS1302_CE=1;//操作要CLK置1
	/*————————————————————————————————————————————————————————————
	DS1302_IO=Command&0x01;//取出Command的第0位
	DS1302_SCLK=1;//因为51的速率是比较慢的,与下面一行之间所以不需要加延时
	DS1302_SCLK=0;

	DS1302_IO=Command&0x02;//0x02是0000 0010 取出Command中的第1位给左边
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	DS1302_IO=Command&0x04;//取出Command中的第2位给左边
	DS1302_SCLK=1;
	DS1302_SCLK=0;
	.....
	————————————————————————————————————————————————————————————————*/
	//上面的可以用for循环代替
	for(i=0;i<8;i++){
		DS1302_IO=Command&(0x01<<i);//左移i位
		DS1302_SCLK=1;//操作图中前八个,上升沿部分
		DS1302_SCLK=0;//操作图中前八个,下升沿部分
	} 
	for(i=0;i<8;i++){//操作图中后八个D0~D7
		DS1302_IO=Data&(0x01<<i);//左移i位
		DS1302_SCLK=1;
		DS1302_SCLK=0;
	} 
	DS1302_CE=0;//结束清零
}
//单字节读取(SINGLE-BYTE READ)
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);//左移i位
		DS1302_SCLK=0;//因为上面只有15个脉冲,把图向间断向左移一点,这样左边都是与写入有关的
		DS1302_SCLK=1;	
	} 	
	/*
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	if(DS1302_IO){Data=Data|0x01;}//把Data的最低为置1
	//if()相当于判断了一下是否为1,或0
	DS1302_SCLK=0;
	DS1302_SCLK=1;
	if(DS1302_IO){Data=Data|0x02;}
	......
	*/
	//可以换为for循环
	for(i=0;i<8;i++){
		DS1302_SCLK=1;//这里于上面重复置1,就可以把这个周期过滤掉
		DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;//清零
	DS1302_IO=0;
	return Data;
}

void DS1302_SetTime(void)
{
	DS1302_WriteByte(DS1302_WP,0x00);
	//下面用了10进制转BCD码
	DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);//年
	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);//写保护
}
void DS1302_ReadTime(void)
{
	//读取时间
	unsigned char Temp;
	Temp=DS1302_ReadByte(DS1302_YEAR);
	DS1302_Time[0]=Temp/16*10+Temp%16;
	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.h

#ifndef __DS1302_H__
#define __DS1302_H__
extern unsigned char DS1302_Time[];//如果变量声明变量要加extern
void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_ReadTime(void);
void DS1302_SetTime(void);
#endif

 

  • 4
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值