【51单片机】普中A2开发板 模块化编程 单片机入门 实例教学目录

写在前面😋(跟着b站up江科大自化协学习的)

一、 流水灯代码

1. 点亮第一个小灯

#include <REGX52.H>
void main()
{
    
    P2=0xfe;
    
}

2. LED闪烁

#include <REGX52.H>
void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}
void main()
{
    while(1)
    {
        P2=0x55;   //亮
        Delay(1000);
        P2=0xff;  // 灭
        Delay(1000);
    }
    
}
#include <REGX52.H>
#include<intrins.h>
void Delay1000ms()		//@11.0592MHz
{
    unsigned char i, j, k;
    
    _nop_();
    i = 8;
    j = 1;
    k = 243;
    do
    {
        do
        {
            while (--k);
        } while (--j);
    } while (--i);
}

void main()
{
    while(1)
    {
        P2=0x55;   //亮
        Delay1000ms();
        P2=0xff;  // 灭
        Delay1000ms();
    }
    
}

3. LCD流水灯

#include <REGX52.H>

void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}
void main (void) 
{
    while (1) 
    {
        P2=0xfe;
        Delay(1000);
        P2=0xfd;
        Delay(1000);
        P2=0xfb; 
        Delay(1000);
        P2=0xf7;
        Delay(1000); 
        P2=0xef; 
        Delay(1000);
        P2=0xdf;
        Delay(1000);
        P2=0xbf;
        Delay(1000); 
        P2=0x7f;
        Delay(1000); 
    }
 }

4. 内部原理图

二、 独立按键代码

1. 独立按键控制LED灯亮灭

#include <REGX52.H>
void main (void) 
{
    while (1) 
    {
        if(P3_1==0)
        { 
            P2_0=0;
        }
        if(P3_1==1)
        { 
            P2_0=1;
        }
    }
 }

2. 独立按键控制LED灯状态

#include <REGX52.H>

void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}

void main (void) 
{
    while (1) 
    {
        if(P3_1==0)
        {
            Delay(10);
            while(P3_1!=1);
            Delay(10);
            P2=~P2;
            
        } 
    }
 }

3. 独立按键控制LED显示二进制

#include <REGX52.H>
unsigned char temp=0;
void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}

void main (void) 
{
    while (1) 
    {
        if(P3_1==0)
        {
            Delay(10);
            while(P3_1!=1);
            Delay(10);
            temp++;
            P2=~temp;
        } 
    }
 }

4. 独立按键控制LED移位

#include <REGX52.H>
unsigned char temp=0;
void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}

void main (void) 
{ 
    while (1) 
    {
        if(P3_1==0)
        {
            Delay(10);
            while(P3_1!=1);
            Delay(10);
            P2=~(0x01<<temp);
            temp++;
            if(temp==8)
            {
                temp=0;
                
            } 
        }
        if(P3_0==0)
        {
            Delay(10);
            while(P3_0!=1);
            Delay(10);
            
            if(temp==0)
                temp=7;
            else
                temp--;
            P2=~(0x01<<temp);
        }
    }
}
--------------------------------------------------------------
#include <REGX52.H>
//利用左移右移函数版本
#include <intrins.h>
void Delay(unsigned int time)                 //定义延时函数
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  //用两个循环是为了保证延时函数的正确性
}
void main()
{    
    P2=0x7f;
    
    while (1) 
    { 
        if(P3_1==0)
        {
            Delay(10);
            while(P3_1!=1);
            Delay(10);
            P2=_crol_(P2,1); //P2的值整体左移一位
            
        } 
        
        if(P3_0==0)
        {
            Delay(10);
            while(P3_0!=1);
            Delay(10);
            P2=_cror_(P2,1); //P2的值整体右移一位
            
        } 
    }  
}  

5. 内部原理图

三、动态数码管代码

1. 静态数码管显示

#include <REGX52.H>
unsigned char Num_table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Nixie (unsigned char Location,Number)
{
    switch(Location)
    {
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        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=Num_table[Number];
    
}

void main()
{    
    
    Nixie(1,0);   //第1个数码管显示0
    
    
    while (1) 
    { 
        
       
    }  
}  

2. 动态数码管显示

#include <REGX52.H>
unsigned char Num_table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
void Delay(unsigned int time)     //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  
}
void Nixie (unsigned char Location,Number)  //位选,段选
{
    switch(Location)
    {
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        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=Num_table[Number];
    
}
void xiaoying()  //消影
{
    Delay(1);
    P0=0x00;
}
void main()
{ 
    while (1) 
    { 
        Nixie(1,0);//第1个数码管显示0
        xiaoying();
        Nixie(2,8);//第2个数码管显示8
        xiaoying();
        Nixie(3,2);//第3个数码管显示2
        xiaoying();
        Nixie(4,0);//第4个数码管显示0
        xiaoying();
        Nixie(5,0);//第5个数码管显示0
        xiaoying();
        Nixie(6,5);//第6个数码管显示5
        xiaoying();
        Nixie(7,2);//第7个数码管显示2
        xiaoying();
        Nixie(8,2);//第8个数码管显示2
        xiaoying();
    }  
}  

3. main.c(模块化)

 

4. 内部原理图

四、模块化编程

1. 延时函数

void Delay(unsigned int time)                
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--);  
}
#ifndef   __DELAY_H__
#define  __DELAY_H__

void Delay(unsigned int time);

#endif     

2. 数码管显示

#include <REGX52.H>
#include "Delay.h"
void Nixie (unsigned char Location,Number)
{   
    unsigned char Num_table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
    switch(Location)
    {
        case 1:P2_4=1;P2_3=1;P2_2=1;break;
        case 2:P2_4=1;P2_3=1;P2_2=0;break;
        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=Num_table[Number];
    Delay(1);
    P0=0x00;
}
#ifndef __NIXIE_H__
#define __NIXIE_H__

void Nixie (unsigned char Location,Number);


#endif

3. LCD1602

#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');
	}
}
#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

4. 矩阵按键

#include <REGX52.H>
#include "Delay.h"
/**
  * @brief  矩阵键盘读取按键键码
  * @param  无
  * @retval KeyNumber 按下按键的键码值
			如果按键按下不放,程序会停留在此函数,松手的一瞬间,返回按键键码,没有按键按下时,返回0
  */
unsigned char MatrixKey()
{
	unsigned char KeyNumber=0;
	
	P1=0xFF;
	P1_3=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=1;}
	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=0xFF;
	P1_2=0;
	if(P1_7==0){Delay(20);while(P1_7==0);Delay(20);KeyNumber=2;}
	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;}
	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;}
	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;
}

#ifndef   ___MatrixKeyH__
#define  __MatrixKey_H__

unsigned char MatrixKey();

#endif     

5. 独立按键


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

/**
  * @brief  获取独立按键键码
  * @param  无
  * @retval 按下按键的键码,范围: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;
}
#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key();

#endif

6. 定时器0

#include <REGX52.H>

/**
  * @brief  定时器0初始化,1毫秒@12.000MHz
  * @param  无
  * @retval 无
  */
void Timer0Init(void)
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0=1;
	EA=1;
	PT0=0;
}

/*定时器中断函数模板
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=1000)
	{
		T0Count=0;
		
	}
}
*/
#ifndef __TIMER0_H__
#define __TIMER0_H__

void Timer0Init(void);

#endif

7. 串口通信

#include <REGX52.H>

/**
* @brief   初始化串口 
* @param    无
* @retval   无
*/
void UART_Init()		//9600bps@11.0592MHz
{
    PCON &= 0x7F;		//波特率不倍速
    SCON = 0x50;		//8位数据,可变波特率
    TMOD &= 0x0F;		//设置定时器模式
    TMOD |= 0x20;		//设置定时器模式
    TL1 = 0xFD;		//设置定时初始值
    TH1 = 0xFD;		//设置定时重载值
    ET1 = 0;		//禁止定时器%d中断
    TR1 = 1;		//定时器1开始计时
    EA=1;        //打开总中断
    ES=1;        //打开串口中断
}
/**
* @brief    串口发送数据 Byte是要发送的数据
* @param     Byte
* @retval    无
*/
void UART_SendByte(unsigned char Byte)
{
    
    SBUF=Byte;
    while(TI==0);
    TI=0;
    
}

/**
* @brief    串口通信中断  P2口接收显示数据,并把数据发送给电脑
* @param    无
* @retval   无
*/
void UART_Routine() interrupt 4
{
    
    if(RI==1)
    {  
        P2=~SBUF;
        RI=0;
        UART_SendByte(SBUF);
    }
    
}
#ifndef   __UART_H__
#define  __UART_H__

    void UART_Init();
    void UART_SendByte(unsigned char Byte);

#endif     

8. 点阵

#include <REGX52.H>
sbit RCK=P3^5;		//RCLK
sbit SCK=P3^6;		//SRCLK
sbit SER=P3^4;		//SER
void _74HC595_WriteByte(unsigned char Byte) 
{
    unsigned char i;
    SCK=0;
    RCK=0;
    for(i=0;i<8;i++)
    {
        SER=Byte&(0x80>>i);
        SCK=1;
        SCK=0;
    }
    RCK=1;
    RCK=0;
    
}
void MatrixLED_ShowColumn(unsigned char Column,Data)//列,数据
{
    _74HC595_WriteByte(Data);
    
    P0=~(0x80>>Column);
    
    
    
}
#ifndef   __MATRIXLED_H__
#define  __MATRIXLED_H__

void MatrixLED_ShowColumn(unsigned char Column,Data); //列,数据
void _74HC595_WriteByte(unsigned char Byte) ;  //行配置 

#endif     

9. DS1302

#include <REGX52.H>

//引脚定义
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
unsigned char DS1302_Time[]={19,5,20,12,55,44,3};
//寄存器写入地址/指令定义
#define DS1302_SECOND		0x80
#define DS1302_MINUTE		0x82
#define DS1302_HOUR			0x84
#define DS1302_DAY			0x86
#define DS1302_MONTH		0x88
#define DS1302_WEEK			0x8A
#define DS1302_YEAR			0x8C
#define DS1302_WP			0x8E


void DS1302_Init(void)
{
    DS1302_CE=0;
    DS1302_SCLK=0;
    
}
void DS1302_WriteByte(unsigned char Command,Data)
{  
    unsigned char i;
    DS1302_CE=1;
    for(i=0;i<=7;i++)
        
    { 
        DS1302_IO=Command&(0x01<<i);
        DS1302_SCLK=1;
        DS1302_SCLK=0;
    }
    for(i=0;i<=7;i++)
        
    { 
        DS1302_IO=Data&(0x01<<i);
        DS1302_SCLK=1;
        DS1302_SCLK=0;
    }
    DS1302_CE=0;
}
unsigned char DS1302_ReadByte(unsigned char Command)
{
    unsigned char i,Data=0x00;
    Command|=0x01;	//将指令转换为读指令
    DS1302_CE=1;
    for(i=0;i<=7;i++)
        
    { 
        DS1302_IO=Command&(0x01<<i);
        DS1302_SCLK=0;
        DS1302_SCLK=1;
    }
    for(i=0;i<=7;i++)
    { 
        DS1302_SCLK=1;
        DS1302_SCLK=0;
        if(DS1302_IO)
        {
            Data=Data|(0x01<<i);
        }
    }
    DS1302_CE=0;
    DS1302_IO=0;	//读取后将IO设置为0,否则读出的数据会出错
    return Data;
}
void DS1302_SetTime(void)
{
    DS1302_WriteByte(DS1302_WP,0x00);
    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_DAY,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_WEEK,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_DAY);
    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_WEEK);
    DS1302_Time[6]=Temp/16*10+Temp%16;
    
}
#ifndef   __DS1302_H__
#define  __DS1302_H__

//外部可调用时间数组,索引0~6分别为年、月、日、时、分、秒、星期
extern unsigned char DS1302_Time[];

void DS1302_Init(void);
void DS1302_WriteByte(unsigned char Command,Data);
unsigned char DS1302_ReadByte(unsigned char Command);
void DS1302_SetTime(void);
void DS1302_ReadTime(void);

#endif     

10.蜂鸣器

#include <REGX52.H>
#include <INTRINS.H>

//蜂鸣器端口:
sbit Buzzer=P2^5;

/**
  * @brief  蜂鸣器私有延时函数,延时500us
  * @param  无
  * @retval 无
  */
void Buzzer_Delay500us()		//@12.000MHz
{
	unsigned char i;

	_nop_();
	i = 247;
	while (--i);
}

/**
  * @brief  蜂鸣器发声
  * @param  ms 发声的时长,范围:0~32767
  * @retval 无
  */
void Buzzer_Time(unsigned int ms)
{
	unsigned int i;
	for(i=0;i<ms*2;i++)
	{
		Buzzer=!Buzzer;
		Buzzer_Delay500us();
	}
}

#ifndef __BUZZER_H__
#define __BUZZER_H__

void Buzzer_Time(unsigned int ms);

#endif

11. AT24C02 读写数据

#include <REGX52.H>
#include "I2C.h"

#define AT24C02_ADDRESS		0xA0

/**
  * @brief  AT24C02写入一个字节
  * @param  WordAddress 要写入字节的地址
  * @param  Data 要写入的数据
  * @retval 无
  */
void AT24C02_WriteByte(unsigned char WordAddress,Data)
{
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_SendByte(Data);
	I2C_ReceiveAck();
	I2C_Stop();
}

/**
  * @brief  AT24C02读取一个字节
  * @param  WordAddress 要读出字节的地址
  * @retval 读出的数据
  */
unsigned char AT24C02_ReadByte(unsigned char WordAddress)
{
	unsigned char Data;
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS);
	I2C_ReceiveAck();
	I2C_SendByte(WordAddress);
	I2C_ReceiveAck();
	I2C_Start();
	I2C_SendByte(AT24C02_ADDRESS|0x01);
	I2C_ReceiveAck();
	Data=I2C_ReceiveByte();
	I2C_SendAck(1);
	I2C_Stop();
	return Data;
}

#ifndef __AT24C02_H__
#define __AT24C02_H__

void AT24C02_WriteByte(unsigned char WordAddress,Data);
unsigned char AT24C02_ReadByte(unsigned char WordAddress);


#endif

12. AT24C02 I2C通信

#include <REGX52.H>

sbit I2C_SCL=P2^1;
sbit I2C_SDA=P2^0;

/**
  * @brief  I2C开始
  * @param  无
  * @retval 无
  */
void I2C_Start(void)
{
	I2C_SDA=1;
	I2C_SCL=1;
	I2C_SDA=0;
	I2C_SCL=0;
}

/**
  * @brief  I2C停止
  * @param  无
  * @retval 无
  */
void I2C_Stop(void)
{
	I2C_SDA=0;
	I2C_SCL=1;
	I2C_SDA=1;
}

/**
  * @brief  I2C发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void I2C_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		I2C_SDA=Byte&(0x80>>i);
		I2C_SCL=1;
		I2C_SCL=0;
	}
}

/**
  * @brief  I2C接收一个字节
  * @param  无
  * @retval 接收到的一个字节数据
  */
unsigned char I2C_ReceiveByte(void)
{
	unsigned char i,Byte=0x00;
	I2C_SDA=1;
	for(i=0;i<8;i++)
	{
		I2C_SCL=1;
		if(I2C_SDA){Byte|=(0x80>>i);}
		I2C_SCL=0;
	}
	return Byte;
}

/**
  * @brief  I2C发送应答
  * @param  AckBit 应答位,0为应答,1为非应答
  * @retval 无
  */
void I2C_SendAck(unsigned char AckBit)
{
	I2C_SDA=AckBit;
	I2C_SCL=1;
	I2C_SCL=0;
}

/**
  * @brief  I2C接收应答位
  * @param  无
  * @retval 接收到的应答位,0为应答,1为非应答
  */
unsigned char I2C_ReceiveAck(void)
{
	unsigned char AckBit;
	I2C_SDA=1;
	I2C_SCL=1;
	AckBit=I2C_SDA;
	I2C_SCL=0;
	return AckBit;
}

#ifndef __I2C_H__
#define __I2C_H__

void I2C_Start(void);
void I2C_Stop(void);
void I2C_SendByte(unsigned char Byte);
unsigned char I2C_ReceiveByte(void);
void I2C_SendAck(unsigned char AckBit);
unsigned char I2C_ReceiveAck(void);


#endif

13. DS18B20 单总线

#include <REGX52.H>

//引脚定义
sbit OneWire_DQ=P3^7;

/**
  * @brief  单总线初始化
  * @param  无
  * @retval 从机响应位,0为响应,1为未响应
  */
unsigned char OneWire_Init(void)
{
	unsigned char i;
	unsigned char AckBit;
	EA=0;
	OneWire_DQ=1;
	OneWire_DQ=0;
	i = 247;while (--i);		//Delay 500us
	OneWire_DQ=1;
	i = 32;while (--i);			//Delay 70us
	AckBit=OneWire_DQ;
	i = 247;while (--i);		//Delay 500us
	EA=1;
	return AckBit;
}

/**
  * @brief  单总线发送一位
  * @param  Bit 要发送的位
  * @retval 无
  */
void OneWire_SendBit(unsigned char Bit)
{
	unsigned char i;
	EA=0;
	OneWire_DQ=0;
	i = 4;while (--i);			//Delay 10us
	OneWire_DQ=Bit;
	i = 24;while (--i);			//Delay 50us
	OneWire_DQ=1;
	EA=1;
}

/**
  * @brief  单总线接收一位
  * @param  无
  * @retval 读取的位
  */
unsigned char OneWire_ReceiveBit(void)
{
	unsigned char i;
	unsigned char Bit;
	EA=0;
	OneWire_DQ=0;
	i = 2;while (--i);			//Delay 5us
	OneWire_DQ=1;
	i = 2;while (--i);			//Delay 5us
	Bit=OneWire_DQ;
	i = 24;while (--i);			//Delay 50us
	EA=1;
	return Bit;
}

/**
  * @brief  单总线发送一个字节
  * @param  Byte 要发送的字节
  * @retval 无
  */
void OneWire_SendByte(unsigned char Byte)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		OneWire_SendBit(Byte&(0x01<<i));
	}
}

/**
  * @brief  单总线接收一个字节
  * @param  无
  * @retval 接收的一个字节
  */
unsigned char OneWire_ReceiveByte(void)
{
	unsigned char i;
	unsigned char Byte=0x00;
	for(i=0;i<8;i++)
	{
		if(OneWire_ReceiveBit()){Byte|=(0x01<<i);}
	}
	return Byte;
}

#ifndef __ONEWIRE_H__
#define __ONEWIRE_H__

unsigned char OneWire_Init(void);
void OneWire_SendBit(unsigned char Bit);
unsigned char OneWire_ReceiveBit(void);
void OneWire_SendByte(unsigned char Byte);
unsigned char OneWire_ReceiveByte(void);

#endif

14. DS18B20 温度传感器

#include <REGX52.H>
#include "OneWire.h"

//DS18B20指令
#define DS18B20_SKIP_ROM			0xCC
#define DS18B20_CONVERT_T			0x44
#define DS18B20_READ_SCRATCHPAD 	0xBE

/**
  * @brief  DS18B20开始温度变换
  * @param  无
  * @retval 无
  */
void DS18B20_ConvertT(void)
{
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_CONVERT_T);
}

/**
  * @brief  DS18B20读取温度
  * @param  无
  * @retval 温度数值
  */
float DS18B20_ReadT(void)
{
	unsigned char TLSB,TMSB;
	int Temp;
	float T;
	OneWire_Init();
	OneWire_SendByte(DS18B20_SKIP_ROM);
	OneWire_SendByte(DS18B20_READ_SCRATCHPAD);
	TLSB=OneWire_ReceiveByte();
	TMSB=OneWire_ReceiveByte();
	Temp=(TMSB<<8)|TLSB;
	T=Temp/16.0;
	return T;
}

#ifndef __DS18B20_H__
#define __DS18B20_H__

void DS18B20_ConvertT(void);
float DS18B20_ReadT(void);

#endif

15. 定时器按键(十 十二用到)

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

unsigned char Key_KeyNumber;

/**
  * @brief  获取按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key(void)
{
	unsigned char Temp=0;
	Temp=Key_KeyNumber;
	Key_KeyNumber=0;
	return Temp;
}

/**
  * @brief  获取当前按键的状态,无消抖及松手检测
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key_GetState()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){KeyNumber=1;}
	if(P3_0==0){KeyNumber=2;}
	if(P3_2==0){KeyNumber=3;}
	if(P3_3==0){KeyNumber=4;}
	
	return KeyNumber;
}

/**
  * @brief  按键驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Key_Loop(void)
{
	static unsigned char NowState,LastState;
	LastState=NowState;				//按键状态更新
	NowState=Key_GetState();		//获取当前按键状态
	//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
	if(LastState==1 && NowState==0)
	{
		Key_KeyNumber=1;
	}
	if(LastState==2 && NowState==0)
	{
		Key_KeyNumber=2;
	}
	if(LastState==3 && NowState==0)
	{
		Key_KeyNumber=3;
	}
	if(LastState==4 && NowState==0)
	{
		Key_KeyNumber=4;
	}
}

#ifndef __KEY_H__
#define __KEY_H__

unsigned char Key(void);
void Key_Loop(void);

#endif

具体参考 十 AT24C02掉电存储(2)

四、LCD1602

1. 小试牛刀

#include <REGX52.H>
#include "LCD1602.h"
#include "Delay.h"
void main()
{ 
    int Number=0;
    LCD_Init();
    LCD_ShowChar(1,1,'Q');
    LCD_ShowString(1,3,"Qiandao");
    LCD_ShowNum(2,1,234,3);
    LCD_ShowSignedNum(2,5,-2,1);
    
    while(1)
    {
        Number++;
        LCD_ShowNum(2,9,Number,3);
        Delay(500);
    }
    
}

2. 俺让你瞅瞅

3. 内部原理图

30

五、矩阵键盘

1. 用矩阵按键控制LCD数字显示

#include <REGX52.H>
#include "Delay.h"		//包含Delay头文件
#include "LCD1602.h"	//包含LCD1602头文件
#include "MatrixKey.h"	//包含矩阵键盘头文件

unsigned char KeyNum;

void main()
{
	LCD_Init();							//LCD初始化
	LCD_ShowString(1,1,"MatrixKey:");	//LCD显示字符串
	while(1)
	{
		KeyNum=MatrixKey();				//获取矩阵键盘键码
		if(KeyNum)						//如果有按键按下
		{
			LCD_ShowNum(2,1,KeyNum,2);	//LCD显示键码
		}
	}
}

2. 用矩阵按键制作密码锁

#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)
        {
            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;		//密码清零
                    Count=0;		//计次清零
                    LCD_ShowNum(2,1,Password,4);	//更新显示
                }
                else				//否则
                {
                    LCD_ShowString(1,14,"ERR");	//显示ERR
                    Password=0;		//密码清零
                    Count=0;		//计次清零
                    LCD_ShowNum(2,1,Password,4);	//更新显示
                }
            }
            if(KeyNum==12)	//如果S12按键按下,取消
            {
                Password=0;		//密码清零
                Count=0;		//计次清零
                LCD_ShowNum(2,1,Password,4);	//更新显示
            }
            if(KeyNum==13)  //如果s13按键按下,退位
            {
                Password/=10;  //密码退位
                if(Count>0)
                {
                    Count--;  //计次减一
                    LCD_ShowNum(2,1,Password,4);
                    LCD_ShowString(1,14,"   ");
                }
                else
                {
                    LCD_ShowNum(2,1,Password,4);
                    LCD_ShowString(1,14,"   ");
                }
            }
        }
        

五、定时器

1. 有定时器参与的按键流水灯

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include <INTRINS.H>

unsigned char KeyNum,LEDMode;

void main()
{
	P2=0xFE;
	Timer0Init();
	while(1)
	{
		KeyNum=Key();		//获取独立按键键码
		if(KeyNum)			//如果按键按下
		{
			if(KeyNum==1)	//如果K1按键按下
			{
				LEDMode++;	//模式切换
				if(LEDMode>=2)LEDMode=0;
			}
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;		//T0Count计次,对中断频率进行分频
	if(T0Count>=500)//分频500次,500ms
	{
		T0Count=0;
		if(LEDMode==0)			//模式判断
			P2=_crol_(P2,1);	//LED输出
		if(LEDMode==1)
			P2=_cror_(P2,1);
	}
}

2. 定时器时钟

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

unsigned char Sec=55,Min=59,Hour=23;

void main()
{
	LCD_Init();
	Timer0Init();
	
	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)	//定时器分频,1s
	{
		T0Count=0;
		Sec++;			//1秒到,Sec自增
		if(Sec>=60)
		{
			Sec=0;		//60秒到,Sec清0,Min自增
			Min++;
			if(Min>=60)
			{
				Min=0;	//60分钟到,Min清0,Hour自增
				Hour++;
				if(Hour>=24)
				{
					Hour=0;	//24小时到,Hour清0
				}
			}
		}
	}
}

六、串口通信

1. 串口发送数据

#include <REGX52.H>
#include "Delay.h"
#include "UART.h"
unsigned char Count=0; 

void main ()
{
    UART_Init();
    while(1)   
  {
    UART_SendByte(Count);
    Delay(1000);
    Count++;
    
   
  }

}

2. 串口接收和发送数据

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

void main ()
{
    UART_Init();
    while(1)   
    {
        
        
    }
    
}
void UART_Routine() interrupt 4
{
    
    if(RI==1)
    {  
        P2=~SBUF;
        RI=0;
        UART_SendByte(SBUF);
    }
    
}

七、LED点阵屏

1.点阵屏显示图形

#include <REGX52.H>
sbit RCK=P3^5;		//RCLK
sbit SCK=P3^6;		//SRCLK
sbit SER=P3^4;		//SER

void _74HC595_WriteByte(unsigned char Byte) 
{
    unsigned char i;
    for(i=0;i<8;i++)
    {
        SER=Byte&(0x80>>i);
        SCK=1;
        SCK=0;
    }
    RCK=1;
    RCK=0;
    
}
void MatrixLED_ShowColumn(unsigned char Column,Data)//列,数据
{
    _74HC595_WriteByte(Data);
    
    P0=~(0x80>>Column);
    
    
    
}
void main()
{
    SCK=0;
    RCK=0;
    MatrixLED_ShowColumn(7,0xff);   //第七列全亮
    while(1)
    {
        
    }
    
    
    
}

2.点阵屏显示动画

#include <REGX52.H>
#include "MatrixLED.h"
    unsigned int code MengXin[]={
    0x00,0x81,0x81,0xFF,0x81,0x81,0x00,0x00,
    0xFF,0x01,0x01,0x01,0x00,0xFF,0x81,0x81,
    0x81,0xFF,0x00,0xC0,0x30,0x0C,0x03,0x0C,
    0x30,0xC0,0x00,0xFF,0x89,0x89,0x89,0x89,
    0x00,0x00,0xC0,0x30,0x0F,0x30,0xC0,0x00,
    0xFF,0x81,0x81,0x81,0xFF,0x00,0xFF,0x01,
    0x01,0x01,0xFF,0x00,0x00,0x38,0x44,0x82,
    0x41,0x31,0x41,0x82,0x44,0x38,0x00,0x00};

void main()
{   
    unsigned char i=0,count=0,flag=0;
    
    while(1)
    {
        for(i=0;i<8;i++)
            
        {
            MatrixLED_ShowColumn(i,MengXin[i+flag]); 
        }
        count++;
        if(count==10)
        { 
            count=0;
            flag++;
            if(flag==56)
            {  flag=0;}
            
            
        }
    }
    
}
#include <REGX52.H>
#include "MatrixLED.h"
unsigned int code MengXin[]={
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x81,0x81,0xFF,0x81,0x81,0x00,0x00,
    0xFF,0x01,0x01,0x01,0x00,0xFF,0x81,0x81,
    0x81,0xFF,0x00,0xC0,0x30,0x0C,0x03,0x0C,
    0x30,0xC0,0x00,0xFF,0x89,0x89,0x89,0x89,
    0x00,0x00,0xC0,0x30,0x0F,0x30,0xC0,0x00,
    0xFF,0x81,0x81,0x81,0xFF,0x00,0xFF,0x01,
    0x01,0x01,0xFF,0x00,0x00,0x38,0x44,0x82,
    0x41,0x31,0x41,0x82,0x44,0x38,0x81,0x83,
    0x85,0x89,0x91,0xA1,0xC1,0x81,0x00,0x03,
    0x0C,0x30,0xC0,0x30,0x0C,0x03,0x0C,0x30,
    0xC0,0x30,0x0C,0x03,0x00,0x00,0x00,0x81,
    0x42,0x24,0x18,0x18,0x24,0x42,0x81,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };

void main()
{   
    unsigned char i=0,count=0,flag=0;
    
    while(1)
    {
        for(i=0;i<8;i++)
            
        {
            MatrixLED_ShowColumn(i,MengXin[i+flag]); 
        }
        count++;
        if(count==20)
        { 
            count=0;
            flag++;
            if(flag==104)
            {  flag=0;}
            
            
        }
    }
    
}
#include <REGX52.H>
#include "MatrixLED.h"
unsigned int code MengXin[]={
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x81,0x81,0xFF,0x81,0x81,0x00,0x00,
    0xFF,0x01,0x01,0x01,0x00,0xFF,0x81,0x81,
    0x81,0xFF,0x00,0xC0,0x30,0x0C,0x03,0x0C,
    0x30,0xC0,0x00,0xFF,0x89,0x89,0x89,0x89,
    0x00,0x00,0xC0,0x30,0x0F,0x30,0xC0,0x00,
    0xFF,0x81,0x81,0x81,0xFF,0x00,0xFF,0x01,
    0x01,0x01,0xFF,0x00,0x00,0x38,0x44,0x82,
    0x41,0x31,0x41,0x82,0x44,0x38,0x81,0x83,
    0x85,0x89,0x91,0xA1,0xC1,0x81,0x00,0x03,
    0x0C,0x30,0xC0,0x30,0x0C,0x03,0x0C,0x30,
    0xC0,0x30,0x0C,0x03,0x00,0x00,0x00,0x81,
    0x42,0x24,0x18,0x18,0x24,0x42,0x81,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
    };

void main()
{   
    unsigned char i=0,count=0,flag=0;
    
    while(1)
    {
        for(i=0;i<8;i++)
            
        {   MatrixLED_ShowColumn(i,0x00); 
         MatrixLED_ShowColumn(i,MengXin[i+flag]); 
         MatrixLED_ShowColumn(i,0x00); 
         
        }
        count++;
        if(count=10)
        { 
            count=0;
            
            flag++;
            if(flag==104)
            {  flag=0;}
            
            
        }
    }
    
}

3.原理图

八、DS1302时钟

1.时钟

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"

void main ()
{
   
	LCD_Init();
	DS1302_Init();
	LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示
	LCD_ShowString(2,1,"  :  :  ");
	
	DS1302_SetTime();//设置时间
	


   while(1)
   { 
   
        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);//显示秒


	
   }


}

2.按键可调时钟

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Timer0.h"
#include "Key.h"

unsigned 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++;//设置选择位加1
        TimeSetSelect%=6;//越界清零
        
        LCD_ShowNum(2,10,TimeSetSelect,2);
        
    }
    if(KeyNum==3)
    {
        
        DS1302_Time[TimeSetSelect]++;//时间设置位数值加1
        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[0]%4==0)
            {
                if(DS1302_Time[2]>29){DS1302_Time[2]=1;}//闰年2月
            }
            else
            {
                if(DS1302_Time[2]>28){DS1302_Time[2]=1;}//平年2月
            }
        }
        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]--;//时间设置位数值减1
        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[0]%4==0)
            {
                if(DS1302_Time[2]<1){DS1302_Time[2]=29;}//闰年2月
                if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
            }
            else
            {
                if(DS1302_Time[2]<1){DS1302_Time[2]=28;}//平年2月
                if(DS1302_Time[2]>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;}//秒越界判断
        
        
    }
    //更新显示,根据TimeSetSelect和TimeSetFlashFlag判断可完成闪烁功能
    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 ()
{
    Timer0Init();
    LCD_Init();
    DS1302_Init();
    LCD_ShowString(1,1,"  -  -  ");//静态字符初始化显示
    LCD_ShowString(2,1,"  :  :  ");
    
    DS1302_SetTime();//设置时间
    
    
    
    while(1)
    {
        KeyNum=Key();//读取键码
        if(KeyNum==1)//按键1按下
        {
            if(Mode==0){Mode=1;TimeSetSelect=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)//每500ms进入一次
    {
        T0Count=0;
        TimeSetFlashFlag=!TimeSetFlashFlag;//闪烁标志位取反
    }
}

九、蜂鸣器(无源)

1. 蜂鸣器的按键控制

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
sbit Buzzer=P2^5;
unsigned int i,KeyNum;
void main ()//独立按键按下,数码管显示按键数字,并发出响声500ms
{   
    Nixie(1,0);
    while(1)
    {  
        KeyNum=Key();
        if(KeyNum)
        {
            Nixie(1,KeyNum);
            for(i=0;i<500;i++)
            {
                Buzzer=~Buzzer;
                Delay(1);
            }
            
        }
    }
    
}

2. 蜂鸣器演奏《天空之城》

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

//蜂鸣器端口定义
sbit Buzzer=P2^5;

//播放速度,值为四分音符的时长(ms)
#define SPEED	500

//音符与索引对应表,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,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,65198,65217,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]!=0xFF)	//如果不是停止标志位
		{
			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;	//翻转蜂鸣器IO口
	}
}

十、AT24C02 掉电存储

1. 存储0~65535数字

#include <REGX52.H>
#include "LCD1602.h"
#include "Key.h"
#include "AT24C02.h"
#include "Delay.h"

unsigned char KeyNum;
unsigned int Num;

void main()
{
	LCD_Init();
	LCD_ShowNum(1,1,Num,5);
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)	//K1按键,Num自增
		{
			Num++;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==2)	//K2按键,Num自减
		{
			Num--;
			LCD_ShowNum(1,1,Num,5);
		}
		if(KeyNum==3)	//K3按键,向AT24C02写入数据
		{
			AT24C02_WriteByte(0,Num%256);
			Delay(5);
			AT24C02_WriteByte(1,Num/256);
			Delay(5);
			LCD_ShowString(2,1,"Write OK");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
		if(KeyNum==4)	//K4按键,从AT24C02读取数据
		{
			Num=AT24C02_ReadByte(0);
			Num|=AT24C02_ReadByte(1)<<8;
			LCD_ShowNum(1,1,Num,5);
			LCD_ShowString(2,1,"Read OK ");
			Delay(1000);
			LCD_ShowString(2,1,"        ");
		}
	}
}

2. 数码管秒表+

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include "Nixie.h"
#include "Delay.h"
#include "AT24C02.h"

unsigned char KeyNum;
unsigned char Min,Sec,MiniSec;
unsigned char RunFlag;

void main()
{
	Timer0_Init();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)			//K1按键按下
		{
			RunFlag=!RunFlag;	//启动标志位翻转
		}
		if(KeyNum==2)			//K2按键按下
		{
			Min=0;				//分秒清0
			Sec=0;
			MiniSec=0;
		}
		if(KeyNum==3)			//K3按键按下
		{
			AT24C02_WriteByte(0,Min);	//将分秒写入AT24C02
			Delay(5);
			AT24C02_WriteByte(1,Sec);
			Delay(5);
			AT24C02_WriteByte(2,MiniSec);
			Delay(5);
		}
		if(KeyNum==4)			//K4按键按下
		{
			Min=AT24C02_ReadByte(0);	//读出AT24C02数据
			Sec=AT24C02_ReadByte(1);
			MiniSec=AT24C02_ReadByte(2);
		}
		Nixie_SetBuf(1,Min/10);	//设置显示缓存,显示数据
		Nixie_SetBuf(2,Min%10);
		Nixie_SetBuf(3,11);
		Nixie_SetBuf(4,Sec/10);
		Nixie_SetBuf(5,Sec%10);
		Nixie_SetBuf(6,11);
		Nixie_SetBuf(7,MiniSec/10);
		Nixie_SetBuf(8,MiniSec%10);
	}
}

/**
  * @brief  秒表驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Sec_Loop(void)
{
	if(RunFlag)
	{
		MiniSec++;
		if(MiniSec>=100)
		{
			MiniSec=0;
			Sec++;
			if(Sec>=60)
			{
				Sec=0;
				Min++;
				if(Min>=60)
				{
					Min=0;
				}
			}
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count1,T0Count2,T0Count3;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count1++;
	if(T0Count1>=20)
	{
		T0Count1=0;
		Key_Loop();	//20ms调用一次按键驱动函数
	}
	T0Count2++;
	if(T0Count2>=2)
	{
		T0Count2=0;
		Nixie_Loop();//2ms调用一次数码管驱动函数
	}
	T0Count3++;
	if(T0Count3>=10)
	{
		T0Count3=0;
		Sec_Loop();	//10ms调用一次数秒表驱动函数
	}
}

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

//数码管显示缓存区
unsigned char Nixie_Buf[9]={0,10,10,10,10,10,10,10,10};

//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x00,0x40};

/**
  * @brief  设置显示缓存区
  * @param  Location 要设置的位置,范围:1~8
  * @param  Number 要设置的数字,范围:段码表索引范围
  * @retval 无
  */
void Nixie_SetBuf(unsigned char Location,Number)
{
	Nixie_Buf[Location]=Number;
}

/**
  * @brief  数码管扫描显示
  * @param  Location 要显示的位置,范围:1~8
  * @param  Number 要显示的数字,范围:段码表索引范围
  * @retval 无
  */
void Nixie_Scan(unsigned char Location,Number)
{
	P0=0x00;				//段码清0,消影
	switch(Location)		//位码输出
	{
		case 1:P2_4=1;P2_3=1;P2_2=1;break;
		case 2:P2_4=1;P2_3=1;P2_2=0;break;
		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=NixieTable[Number];	//段码输出
}

/**
  * @brief  数码管驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Nixie_Loop(void)
{
	static unsigned char i=1;
	Nixie_Scan(i,Nixie_Buf[i]);
	i++;
	if(i>=9){i=1;}
}

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

unsigned char Key_KeyNumber;

/**
  * @brief  获取按键键码
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key(void)
{
	unsigned char Temp=0;
	Temp=Key_KeyNumber;
	Key_KeyNumber=0;
	return Temp;
}

/**
  * @brief  获取当前按键的状态,无消抖及松手检测
  * @param  无
  * @retval 按下按键的键码,范围:0,1~4,0表示无按键按下
  */
unsigned char Key_GetState()
{
	unsigned char KeyNumber=0;
	
	if(P3_1==0){KeyNumber=1;}
	if(P3_0==0){KeyNumber=2;}
	if(P3_2==0){KeyNumber=3;}
	if(P3_3==0){KeyNumber=4;}
	
	return KeyNumber;
}

/**
  * @brief  按键驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Key_Loop(void)
{
	static unsigned char NowState,LastState;
	LastState=NowState;				//按键状态更新
	NowState=Key_GetState();		//获取当前按键状态
	//如果上个时间点按键按下,这个时间点未按下,则是松手瞬间,以此避免消抖和松手检测
	if(LastState==1 && NowState==0)
	{
		Key_KeyNumber=1;
	}
	if(LastState==2 && NowState==0)
	{
		Key_KeyNumber=2;
	}
	if(LastState==3 && NowState==0)
	{
		Key_KeyNumber=3;
	}
	if(LastState==4 && NowState==0)
	{
		Key_KeyNumber=4;
	}
}

3. 数码管秒表 -

#include <REGX52.H>
#include "Timer0.h"
#include "Key.h"
#include "Nixie.h"
#include "Delay.h"
#include "AT24C02.h"
sbit Buffer=P2^5;
unsigned char KeyNum;
signed char i,Min,Sec=2,MiniSec=00;
unsigned char RunFlag;

void main()
{
	Timer0_Init();
    Buffer=0 ;
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)			//K1按键按下
		{
			RunFlag=!RunFlag;	//启动标志位翻转
		}
		if(KeyNum==2)			//K2按键按下
		{
			Min=10;				//计数十分钟
			Sec=00;
			MiniSec=00;
		}

       if(KeyNum==3)			//K3按键按下
		{
			Sec++;             //秒加加
       if(Sec==60){Sec=0;}
           
		}
		if(KeyNum==4)			//K4按键按下
		{
			Min++;	  //分加加
        if(Min==60){Min=0;}			
			
		}
		Nixie_SetBuf(1,Min/10);	//设置显示缓存,显示数据
		Nixie_SetBuf(2,Min%10);
		Nixie_SetBuf(3,11);
		Nixie_SetBuf(4,Sec/10);
		Nixie_SetBuf(5,Sec%10);
		Nixie_SetBuf(6,11);
		Nixie_SetBuf(7,MiniSec/10);
		Nixie_SetBuf(8,MiniSec%10);
	}
}

/**
  * @brief  秒表驱动函数,在中断中调用
  * @param  无
  * @retval 无
  */
void Sec_Loop(void)
{
	if(RunFlag)
	{   
		MiniSec--;

		if(MiniSec<=00)
		{
			MiniSec=99;
			Sec--;

			if(Sec<=0)
			{
			    Sec=59;
				Min--;
				if(Min<=0)
				{
					Min=0;
                    Sec=0;
                    MiniSec=0;
                    Buffer=~Buffer;
                   // P2=0x00;
                
                 
				}
//    else
//                   { P2=0xff;  //灯和蜂鸣器只能二选一,很烦哦
//                    Buffer=0;}
			}
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count1,T0Count2,T0Count3;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count1++;
	if(T0Count1>=20)
	{
		T0Count1=0;
		Key_Loop();	//20ms调用一次按键驱动函数
	}
	T0Count2++;
	if(T0Count2>=2)
	{
		T0Count2=0;
		Nixie_Loop();//2ms调用一次数码管驱动函数
	}
	T0Count3++;
	if(T0Count3>=10)
	{
		T0Count3=0;
		Sec_Loop();	//10ms调用一次数秒表驱动函数
	}
}

十一、直流电机驱动

1. 呼吸灯制作

#include <REGX52.H>
void Delay(unsigned int time)                
{
    while(time--);
}
void main ()
{
    unsigned char Time,i;
    while(1)
    {  
        for(Time=0;Time<100;Time++)
        {
            
            for(i=0;i<20;i++)
            {
                P2_3=0;
                Delay(Time);
                P2_3=1;
                Delay(100-Time);
            }
        }
        
        for(Time=100;Time>0;Time--)
        {
            
            for(i=0;i<20;i++)
            {
                P2_3=0;
                Delay(Time);
                P2_3=1;
                Delay(100-Time);
            }
        }
        
    }
    
    
}

2. 直流电机的按键调速

#include <REGX52.H>
#include "Delay.h"
#include "Key.h"
#include "Nixie.h"
#include "Timer0.h"

sbit Motor=P1^0;

unsigned char Counter,Compare;	//计数值和比较值,用于输出PWM
unsigned char KeyNum,Speed;

void main()
{
	Timer0_Init();
	while(1)
	{
		KeyNum=Key();
		if(KeyNum==1)
		{
			Speed++;
			Speed%=4;
			if(Speed==0){Compare=0;}	//设置比较值,改变PWM占空比
			if(Speed==1){Compare=50;}
			if(Speed==2){Compare=75;}
			if(Speed==3){Compare=100;}
		}
		Nixie(1,Speed);
	}
}

void Timer0_Routine() interrupt 1
{
	TL0 = 0xA4;		//设置定时初始值 100us  
	TH0 = 0xFF;		//设置定时初始值
	Counter++;
	Counter%=100;	//计数值变化范围限制在0~99
	if(Counter<Compare)	//计数值小于比较值
	{
		Motor=1;		//输出1
	}
	else				//计数值大于比较值
	{
		Motor=0;		//输出0
	}
}

十二、DS18B20温度实时显示

1. 温度读取

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"

float T;

void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	LCD_Init();
	LCD_ShowString(1,1,"Temperature:");
	while(1)
	{
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(2,1,'-');	//显示负号
			T=-T;			//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(2,1,'+');	//显示正号
		}
		LCD_ShowNum(2,2,T,3);		//显示温度整数部分
		LCD_ShowChar(2,5,'.');		//显示小数点
		LCD_ShowNum(2,6,(unsigned long)(T*10000)%10000,4);//显示温度小数部分
	}
}

2. 温度报警器

#include <REGX52.H>
#include "LCD1602.h"
#include "DS18B20.h"
#include "Delay.h"
#include "AT24C02.h"
#include "Key.h"
#include "Timer0.h"

float T,TShow;
char TLow,THigh;
unsigned char KeyNum;

void main()
{
	DS18B20_ConvertT();		//上电先转换一次温度,防止第一次读数据错误
	Delay(1000);			//等待转换完成
	THigh=AT24C02_ReadByte(0);	//读取温度阈值数据
	TLow=AT24C02_ReadByte(1);
	if(THigh>125 || TLow<-55 || THigh<=TLow)
	{
		THigh=20;			//如果阈值非法,则设为默认值
		TLow=15;
	}
	LCD_Init();
	LCD_ShowString(1,1,"T:");
	LCD_ShowString(2,1,"TH:");
	LCD_ShowString(2,9,"TL:");
	LCD_ShowSignedNum(2,4,THigh,3);
	LCD_ShowSignedNum(2,12,TLow,3);
	Timer0_Init();
	
	while(1)
	{
		KeyNum=Key();
		
		/*温度读取及显示*/
		DS18B20_ConvertT();	//转换温度
		T=DS18B20_ReadT();	//读取温度
		if(T<0)				//如果温度小于0
		{
			LCD_ShowChar(1,3,'-');	//显示负号
			TShow=-T;		//将温度变为正数
		}
		else				//如果温度大于等于0
		{
			LCD_ShowChar(1,3,'+');	//显示正号
			TShow=T;
		}
		LCD_ShowNum(1,4,TShow,3);		//显示温度整数部分
		LCD_ShowChar(1,7,'.');		//显示小数点
		LCD_ShowNum(1,8,(unsigned long)(TShow*100)%100,2);//显示温度小数部分
		
		/*阈值判断及显示*/
		if(KeyNum)
		{
			if(KeyNum==1)	//K1按键,THigh自增
			{
				THigh++;
				if(THigh>125){THigh=125;}
			}
			if(KeyNum==2)	//K2按键,THigh自减
			{
				THigh--;
				if(THigh<=TLow){THigh++;}
			}
			if(KeyNum==3)	//K3按键,TLow自增
			{
				TLow++;
				if(TLow>=THigh){TLow--;}
			}
			if(KeyNum==4)	//K4按键,TLow自减
			{
				TLow--;
				if(TLow<-55){TLow=-55;}
			}
			LCD_ShowSignedNum(2,4,THigh,3);	//显示阈值数据
			LCD_ShowSignedNum(2,12,TLow,3);
			AT24C02_WriteByte(0,THigh);		//写入到At24C02中保存
			Delay(5);
			AT24C02_WriteByte(1,TLow);
			Delay(5);
		}
		if(T>THigh)			//越界判断
		{
			LCD_ShowString(1,13,"OV:H");
		}
		else if(T<TLow)
		{
			LCD_ShowString(1,13,"OV:L");
		}
		else
		{
			LCD_ShowString(1,13,"    ");
		}
	}
}

void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;		//设置定时初值
	TH0 = 0xFC;		//设置定时初值
	T0Count++;
	if(T0Count>=20)
	{
		T0Count=0;
		Key_Loop();	//每20ms调用一次按键驱动函数
	}
}

先看到这里(2022.05.22 21:52)

2022 05 23 13:19 数 位数提取规律

十三、AD、DA转换(已做,有时间上传)

十三、AD、DA转换(有时间再看)


写在后面:

终于完成了51单片机的阶段性学习,咱们的学习之路还很长,继续加油!!

临近考试周,目前还是居家隔离的状态(第八天)。

透漏一下自己的学习计划:

现在开始转向 STM32 F103的学习,准备近两天先学习下立创的PCB的绘制(AD放后面),暑假会系统的学习下Python(学到爬虫)和STM32(这个可能学得深一些)。准备自己做个循迹小车或者智能家居系统,或者相关的内容。有时间的话再学习下Esp8266和XXX。加油!!!

2022 05/23 17:33

  • 27
    点赞
  • 168
    收藏
    觉得还不错? 一键收藏
  • 10
    评论
普中51单片机A2开发板是一款智能控制开发板,采用51单片机作为控制核心。该开发板具有丰富的接口资源和强大的功能,适用于物联网、智能家居、机器人等多种应用场景。 该开发板的资料包括以下主要内容: 1. 主板设计资料:包括电路原理图、PCB设计文件、材料清单等。主板设计资料详细描述了开发板的硬件电路设计,包括各个接口的连接方式、电源部分设计等。这些资料对于理解开发板的硬件工作原理非常重要。 2. 软件开发资料:包括51单片机的开发环境、编程工具和普中提供的代码库等。开发环境通常包括集成开发环境(IDE)和编译器等,用于编写、调试、烧录代码。普中还提供了丰富的代码库,包含各种功能的例程,如LED控制、串口通信、温度传感器读取等。 3. 使用手册:详细介绍了开发板的功能、使用方法和注意事项等。手册中包括硬件连接示意图、软件调试步骤以及常见问题解答等内容,帮助用户快速上手和解决问题。 4. 实验教程:提供一系列实验教程,引导用户逐步学习开发板的各种功能和应用。实验教程通常包括实验目的、实验原理、实验步骤和实验结果等内容,用户可以跟随实验教程一步一步掌握开发板的使用。 通过阅读这些资料例程,用户可以了解开发板的硬件设计和软件开发过程,掌握开发板的各种功能和应用,进而进行自己的项目开发。同时,普中还提供了技术支持平台,用户可以在平台上提问和交流,获得更详细的技术指导和帮助。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值