【51单片机】Proteus C51 例题

醍醐灌顶的东西(搬运自我的笔记,所以有些格式不是太完美)

大家注意:只有P0口需要外界上拉电阻(内部结构决定的),其他口不加也能仿真出结果

语雀源文件链接

一、 流水灯代码

1. 最初版本

#include <reg51.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) 
    {
        P1=0xfe;
        delay(1000);            
        P1=0xfd;
        delay(1000);
        P1=0xfb; 
        delay(1000);
        P1=0xf7;
        delay(1000); 
        P1=0xef; 
        delay(1000);
        P1=0xdf;
        delay(1000);
        P1=0xbf;
        delay(1000); 
        P1=0x7f;
        delay(1000); 
    }
 }

2. 简化版本

#include <reg51.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()
{    
     P1=0x7f;             
    while (1) 
    { 
      P1=_crol_(P1,1);  //P1的值整体左移一位
      delay(1000);  
    }  
}  

3. Proteus仿真图

大家注意:只有P0口需要外界上拉电阻(内部结构决定的),其他口不加也能仿真出结果

二、 外部中断代码

1. 最初版本

#include <reg51.h>
sbit KEY = P3^3; //外部中断1是P3.3
unsigned int i,j,k,m,n; //说一下这个unsigned吧,无符号型,也就是从0开始,没有负数
void IntInit()  //定义中断
{
    
    IT1 = 1;	//设置外部中断1的触发方式   1是下降沿 0是低电平
    EX1= 1;     //打开外部中断1
    EA = 1;		//打开总中断开关	
}
void delay()                 //定义1s延时函数
{  
    for(m=200;m>0;m--)
        for(n=500;n>0;n--);
}
void Delay10s()		//定义10s延时函数
{
    unsigned char i=58, j=3, k=227;
    
    do
    {
        do
        {
            while (--k);
        } 
        while (--j);
    } 
    while (--i);
}

void main() 
{  
    
    IntInit(); //对中断进行声明
    while (1) //流水灯程序
    {   
        P1=0xfe;
        delay();
        P1=0xfd;
        delay();
        P1=0xfb; 
        delay();
        P1=0xf7;
        delay(); 
        P1=0xef; 
        delay();
        P1=0xdf;
        delay();
        P1=0xbf;
        delay(); 
        P1=0x7f;
        delay(); 
    }    
}  
void Int () interrupt 2 //外部中断1 中断号是2
{    
    
    if(KEY==0) //判断P3.3口是否被按下
        P1=~P1;  //取反
    Delay10s();  //延时10s钟
    
}

2. 修改建议

这里咱们用的是外部中断1 也就是传说中的 INT1,如果用外部中断0(INT0)的话,需要修改的地方有:

代码部分:

  sbit KEY = P3^3; //外部中断1是P3.3                  第2行
    IT1 = 1;	//设置外部中断1的触发方式       	      第7行
    EX1= 1;     //打开外部中断1                         第8行
   void Int() interrupt 2 //外部中断1 中断号是2         第55行
sbit KEY = P3^2; //外部中断0是P3.2                  第2行
IT0= 1;  	//设置外部中断0的触发方式       	       第7行
EX0= 1;     //打开外部中断0                         第8行
void Int() interrupt 0 //外部中断0 中断号是0         第55行

原理图部分:

把proteus中按钮的引脚从P3.3改到P3.2

3. 简化版本

这个版本有个小问题,就是按键按下去之后,不会自己恢复,需要重新按键才会回到正常程序运行,再研究一下有没有好的解决方案(感觉是延时和中断出冲突了,但是没有找到问题所在😢)

键抖也考虑一下

已经解决掉😍

#include <reg51.h>
#include <intrins.h>
sbit KEY = P3^3;  //外部中断1是P3.3
unsigned int i,j,k;
void delay( unsigned int i)		//定义延时函数
{
    unsigned char j=3, k=227;
     do
    { do
        { while (--k);
        } 
        while (--j);
    } 
    while (--i);
}
void main()
{    
     IT1 = 1;  	
     EX1= 1;
     EA = 1;		
     P1=0x7f;
    while (1) 
    { 
      P1=_crol_(P1,1);  //P1的值整体左移一位
      delay(10);  
    }  
}  
void Int() interrupt 2
{    
       if(KEY==0)
        P1=~P1; 
       delay(60);//延时10s
       if(KEY==1)
         P1=~P1;     
}

4. Proteus仿真图


三、 定时器代码

1. 最初版本

#include <reg51.h> //51头文件
unsigned char count=0,num=0; //定义两个无符号字符型变量
unsigned char code led[]=
{0xfa,0xf5,0xaf,0x5f,0xaa,0x55,0x00,0xff};
//对每种情况进行声明,前两个分别是1 3亮,2 4亮,后面以此类推,和题目保持一致
void main()
{
    TMOD=0X10;//这里用的是高四位,如果是低四位是0x01
    TH1=0X3C;  //2^16-50ms/1us 65536-50000=15536 十六进制是3CB0H 这是高位
    TL1=0XB0;   //这是低位(上面用50ms参与运算是因为题目中说每隔0.05s T1溢出一次)
    EA=1;   //打开总中断开关
    ET1=1;  //打开定时器1的中断,0是定时器1不中断
    TR1=1;  //定时器1工作,0是不工作
    while(1)  //超循环
    {
        P1=led[num]; //用总线运算点亮P1端口的led
    }
}
void Timer() interrupt 3 using 0  //using 0可以省略,这个是中断函数. 
    //interrupt后面是中断号3,是因为中断源符号是T1,如果是T0,后面中断号3换成1
{
    TH1=0X3C;  //2^16-50ms/1us 65536-50000=15536 十六进制是3CB0H 这是高位
    TL1=0XB0;   //这是低位(上面用50ms参与运算是因为题目中说每隔0.05s T1溢出一次)
    count++;  //每中断一次 count+1 
    if(count==20)// 20*50ms正好是一秒种  
    {
        count=0; //让count归零,方便下次中断计数
        num++; //中断完成,返回主函数,继续执行main函数,即是 让led按照预定程序改变亮灯方式
        if(num==8)
        num=0;
    }
}

2. 修改建议

这里咱们用的是定时器1 也就是传说中的 T1,如果用定时器0(T0)的话,需要修改的地方有:

代码部分:

TMOD=0X10; //设置定时器1工作方式为01(传说中的方式1) TMOD是工作方式寄存器
TH1=0X3C;  //写入T1的高位初值
TL1=0XB0;   //写入T1的低位初值
EA=1;  //开总中断
ET1=1;//开定时器1中断
TR1=1;//启动定时器1
void Timer() interrupt 3 using 0 //T1的中断号是3
TMOD=0X01; //设置定时器1工作方式为01 TMOD是工作方式寄存器  第8行
TH0=0X3C;  //写入T0的高位初值                            第9行
TL0=0XB0;   //写入T0的低位初值                           第10行
EA=1;  //开总中断                            😎这行不用改
ET0=1;//开定时器0中断                                    第12行
TR0=1;//启动定时器0                                      第13行
void Timer() interrupt 1 using 0 //T0的中断号是1         第19行

2.无注释代码 (其实也有一点儿😊)

#include <reg51.h> 
unsigned char count=0,num=0; 
unsigned char code led[]=
{0xfa,0xf5,0xaf,0x5f,0xaa,0x55,0x00,0xff};
void main()
{
    TMOD=0X10;
    TH1=0X3C;   //也可写为(65536-50000/256
    TL1=0XB0;   //也可写为(65536-50000)%256
    EA=1;  
    ET1=1;
    TR1=1;
    while(1)  
    {
        P1=led[num]; 
    }
}
void Timer() interrupt 3 using 0 
{
    count++;  
    if(count==20)
    { 
        count=0;
        num++; 
        if(num==8)
         num=0;
    }
}

3. Proteus仿真图

四、 数码管代码

这里给出共阴极数码管0~9,和部分字母的显示十六进制数😉

0x3F, //"0"

0x06, //"1"

0x5B, //"2"

0x4F, //"3"

0x66, //"4"

0x6D, //"5"

0x7D, //"6"

0x07, //"7"

0x7F, //"8"

0x6F, //"9"

0x77, //"A"

0x7C, //"B"

0x39, //"C"

0x5E, //"D"

0x79, //"E"

0x71, //"F"

0x76, //"H"

0x38, //"L"

0x37, //"n"

0x3E, //"u"

0x73, //"P"

0x5C, //"o"

0x40, //"-"

0x00 //熄灭

按照题目要求

只需修改下列代码第四行 { } 内的十六进制数就行😋

cc是共阴极数码管,ca是共阳极数码管

1. 最初版本

#include <reg51.h>
unsigned char cnt=0;
unsigned char code table[]=
{0x5b,0x5b,0x6f,0x5b,0x06,0x6d};   //229215 共阴极数码管
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void main(void)
{
    P2=table[cnt];
    while (1)
    { 
        P2=table[cnt];
        delay(50);
        P2=0x00;     //数组中的数全部显示一遍后,将数码管熄灭
        delay(50);
        cnt++;
        if(cnt==6)   //判断数组中的数据是否溢出,溢出则清零显示
        {	cnt=0;delay(200);}
        
    }
}

2. Proteus仿真图

五、 独立按键代码

1. 最初版本


#include <reg51.h>

sbit P1_4=P1^4;
sbit P1_5=P1^5;
sbit P1_6=P1^6;
sbit P1_7=P1^7;

void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}

void main(void)
{
    P0=0x00; //  熄灯
    P2=0x00;   //熄灯   
    P3=0x00; //熄灯
    
    while (1)
    {
        if(P1_4==0)    
        { delay(10);  //按下去键抖
          P0=0x3E; //  U
          P2=0x73;   //   P
          P3=0x06;  //1
         while(P1_4==0) ;//松手去键抖
          delay(10);
        }
        if(P1_5==0)
        { delay(10); //去键抖
         P0=0x5E; //D
         P2=0x5C;//O 
         P3=0x5B; //2
         while(P1_5==0);
          delay(10);
        }
        if(P1_6==0)
        { delay(10); //去键抖
         P0=0x38;  //  L
         P2=0x79;  // E
         P3=0x4F;//3
         while(P1_6==0); 
         delay(10);
        }
        if(P1_7==0)
        { delay(10); //去键抖
         
         
         P0=0x77; // R
         P2=0x06;   //  I
         P3=0x66;//4
         while(P1_7==0);
         delay(10);
        }  
    }
}

2. 简化版本

这个版本有个小问题,初始状态会默认按键1按下,但是不影响后续结果,符合题目要求。

#include <reg51.h>
unsigned char cnt=0;
unsigned char code LED1[]={0x3E,0x5E,0x38,0x77};
unsigned char code LED2[]={0x73,0x5C,0x79,0x06};
unsigned char code LED3[]={0x06,0x5B,0x4F,0x66};
sbit P1_4=P1^4;
sbit P1_5=P1^5;
sbit P1_6=P1^6;
sbit P1_7=P1^7;
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void main()   
{   
    while (1) 
    {    
        switch(P1)
        {case(0xef):cnt=0;break;  //按键1按下
         case(0xdf):cnt=1;break;  //按键2按下
         case(0xbf):cnt=2;break;  //按键3按下
         case(0x7f):cnt=3;break;  //按键4按下
       }
        delay(20);  //去按下键抖
        P0=LED1[cnt];
        P2=LED2[cnt];
        P3=LED3[cnt];
        while(0); //去松手键抖
        delay(20);
    }
}

3. Proteus仿真图

4. 调试版本(有错误,仅供展览)

#include <reg51.h>
unsigned char cnt=0;
unsigned char code LED1[0x3E,0x5E,0x38,0x77];
unsigned char code LED2[0x73,0x5C,0x79,0x06];
unsigned char code LED3[0x06,0x5B,0x4F,0x66];
sbit P1_4=P1^4;
sbit P1_5=P1^5;
sbit P1_6=P1^6;
sbit P1_7=P1^7;
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void main(void)
    
{ 
    P0=P1=P2=0x00;
    
    
    
    switch(k)
    {
        case 0:cnt=0;
        case 1:cnt=1;
        case 2:cnt=2;
        case 3:cnt=3;
            
    }
    
    while (1)
    {   
        P0=LED1[cnt];
        P2=LED2[cnt];
        P3=LED3[cnt];
    }
}
unsigned char code LED1[]={0x3E,0x5E,0x38,0x77,0x00};
unsigned char code LED2[]={0x73,0x5C,0x79,0x06,0x00};
unsigned char code LED3[]={0x06,0x5B,0x4F,0x66,0x00};
#include <reg51.h>
#define uchar unsigned char;
#define uint unsigned int;
uchar num=0;
uchar code table[]={0x3F,0x06, 0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
void delay(unsigned int time)     
{
    unsigned int i=120;
    for(time;time>0;time--)
        for(i=120;i>0;i--);
}
void key_scan()
{ 
    unsigned char temp1=0,temp2=0,temp=0;
    P1=0xf0;
    if(P1!=0xf0)
    {
        delay(20);
        temp1=P1;
        P1=0x0f;  
        if(P1!=0x0f)
        { 
            delay(20);
            temp2=P1;
        }
    }
    temp=temp1+temp2;
    if(temp==0xee)
    { 
        num=0;
    }
}
void main(void)
{
    
    while(1)
    {
        key_scan();
        P2=table[num]; 
    }
}

六、 矩阵按键代码

1. 最初版本

#include <reg51.h>
unsigned char num=99; //让LED初始为熄灭状态
unsigned char code table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void key_scan()    //按键扫描
{ 
    unsigned char temp0=0,temp1=0,temp;
    P1=0xf0;    
    if(P1!=0xf0)  //检测按键是否被按下
    {
        delay(20);
        temp0=P1;
        P1=0x0f;  
        if(P1!=0x0f)
        { 
             temp1=P1;
        }
    }
    temp=temp0+temp1;
    if(temp==0xee)
    { num=0;}
    if(temp==0xed)
    { num=1;}
    if(temp==0xeb)
    { num=2;}
    if(temp==0xe7)
    { num=3;}
    if(temp==0xde)
    { num=4;}
    if(temp==0xdd)
    { num=5;}
    if(temp==0xdb)
    { num=6;}
    if(temp==0xd7)
    { num=7;}
    if(temp==0xbe)
    { num=8;}
    if(temp==0xbd)
    { num=9;}
    if(temp==0xbb)
    { num=10;}
    if(temp==0xb7)
    { num=11;}
    if(temp==0x7e)
    { num=12;}
    if(temp==0x7d)
    { num=13;}
    if(temp==0x7b)
    { num=14;}
    if(temp==0x77)
    { num=15;}
}
void display()
{
    P2=table[num]; 
}
void main()
{
    
    while(1)
    {
        key_scan();
        display(); 
    }
}

2. 简化版本

#include <reg51.h>
unsigned char num=99;
unsigned char code table[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,0x77,0x7C,0x39,0x5E,0x79,0x71};
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void key_scan()
{ 
    unsigned char temp0=0,temp1=0,temp;
    P1=0xf0;
    if(P1!=0xf0)
    {
        delay(20);
        temp0=P1;
        P1=0x0f;  
        if(P1!=0x0f)
        { temp1=P1; }
    }
    temp=temp0+temp1;  
    switch(temp)
    {
        case(0xee):num=0;break;
        case(0xed):num=1;break;
        case(0xeb):num=2;break;
        case(0xe7):num=3;break;
        case(0xde):num=4;break;
        case(0xdd):num=5;break;
        case(0xdb):num=6;break;
        case(0xd7):num=7;break;
        case(0xbe):num=8;break;
        case(0xbd):num=9;break;
        case(0xbb):num=10;break;
        case(0xb7):num=11;break;
        case(0x7e):num=12;break;
        case(0x7d):num=13;break;
        case(0x7b):num=14;break;
        case(0x77):num=15;break;
    }}
void main()
{ 
    while(1)
    {
        key_scan();
        P2=table[num]; 
    }
}

3. Proteus仿真图

七、 串行口代码

1. 最初版本

#include <reg51.h>
unsigned char flag=0;
unsigned char recdata=0;
void init_scon()
{
    SCON=0x50;   //0101 0000  工作方式1,没有多机通信,允许接受
    TMOD=0x20;  //0010 0000 8位定时器 定时器1(高四位) 定时模式 
    TH1=256-3;   //波特率为9600
    TL1=256-3;
    EA=1;    //打开总中断
    ES=1;   // 打开串口中断
    TR1=1;   //打开定时器1
    
}
void send_data()   //发送数据
{
    SBUF=recdata;
    while(TI==0);
    
    TI=0; 
}

void main()
    
{
    init_scon();  //初始化串口
    while(1)
    {
        if(flag==1)
        {
            send_data();
            flag=0;  
        }
    }  
}

void scon_interrupt() interrupt 4  //串口中断中断号是4,中断服务函数
{
    
    recdata=SBUF;   //接收的数据就是缓存寄存器中的数据
    
    RI=0;      //接收中断手动清0,等待下次中断
    flag=1;   //标志位
} 

2. 无注释版本

#include <reg51.h>
unsigned char flag=0;
unsigned char recdata=0;
void init_scon()
{
    SCON=0x50;
    TMOD=0x20;  
    TH1=256-3;
    TL1=256-3;
    EA=1;
    ES=1;
    TR1=1;
    
}
void send_data()
{
    SBUF=recdata;
    while(TI==0);
    TI=0; 
}

void main()
    
{
    init_scon();
    while(1)
    {
        if(flag==1)
        {
            send_data();
            flag=0;  
        }
    }  
}
void scon_interrupt() interrupt 4
{
    
    recdata=SBUF;
    RI=0;
    flag=1; 
} 

3. Proteus仿真图

4. Proteus仿真现象

八、计数器代码

1. 最初版本

#include <reg51.h>
sbit key=P1^7;
unsigned char cnt 0;
unsigned char code table[]=
{0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
void main(void)
{
    P0=P2=table[0];
    while (1)
    {
        if(key==0)
        {
            cnt++;
            if(cnt>=99)
                cnt=0;
            P0=table[cnt/10];  //取整
            P2=table[cnt%10];   //取余
            while(key==0);  
        }     
    }   
}

2. Proteus仿真图

九、 流水灯拓展

1. 最初版本

#include <reg51.h>
unsigned char led[]={0xfe,0xfd,0xfb,0xf7};  // 默认从下往上点亮跑马灯
void delay(unsigned int time)     //延时
{
    unsigned int i=120;
    for(time;time>0;time--)
        for(i=120;i>0;i--);
}
void main()
{
    bit dir=0,run=0;
    char n;
    while(1)
    {
        switch(P0&0x0f)
        {
            case 0x0e:run=1;break;                   //开始运行                   
            case 0x0d:run=0,dir=0;break;            //停止运行
            case 0x0b:dir=1;break;                //从上到下点亮
            case 0x07:dir=0;break;              //从下到上点亮
              
        }
        if(run==1)
          if(dir==1)
                for(n=0;n<=3;n++)
                {     P2=led[n];
                      delay(200);
                }
        else
            
            for(n=3;n>=0;n--)
            {      P2=led[n];
             delay(200);
            }
        
        else
            P2=0xff; //熄灭所有灯
    }
}

2. Proteus仿真图

十、 动态数码管拓展

1. 最初版本

#include <reg51.h>
unsigned char wei[]={ 0x01,0x02,0x04,0x08,0x10,0x20 };//位选码 1 2 3 4 5 6
unsigned char duan[]={ 0x5b,0x5b,0x6f,0x5b,0x06,0x6d };//段选码 2 2 9 2 1 5

void delay(unsigned int time)    //延时
{
    unsigned int i=120;
    for(time;time>0;time--)
        for(i=120;i>0;i--);
}
void pro()  //子函数
{  
     int k=0;
     for(k;k<6;k++)
 {
     P3=~wei[k];  //位选低电平有效
     P2=duan[k];
     delay(10);
 }
}
void main()  
{  
    while (1)
    {
        pro(); 
    }
    
}

2. Proteus仿真图

3. 改进版本(减少IO口占用)

#include <reg51.h>
unsigned char wei[]={ 0x00,0x01,0x02,0x03,0x04,0x05 };
unsigned char duan[]={0x5b,0x5b,0x6f,0x5b,0x06,0x6d};

void delay(unsigned int time)    
{
    unsigned int i=120;
    for(time;time>0;time--)
        for(i=120;i>0;i--);
}
void pro()
{ int k=0;
 for(k;k<6;k++)
 {
     P3=wei[k];
     P2=duan[k];
     delay(10);
 }
}
void main()
{  
    while (1)
    {
         pro(); 
    }
    
}

4. Proteus仿真图

十一、 LCD1602的初试及应用

1. 最初版本

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
unsigned char str[]={"what's u problem"};
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}
void display()
{ 
    unsigned char i=0;
    writecom(0x80+0x40);
    while(str[i]!='\0')
    {
        writedat(str[i]);
        delay(5);
        i++;
    }
    writecom(0x80);
    delay(5);
    writedat('J');
    delay(5);
    writedat('L');
    delay(5);
    writedat('A');
    delay(5);
    writedat('U');
    delay(5);
    writedat(':');
    delay(5);   
}
void initlcd()
{
    writecom(0x38);//设置16*2显示,5*7点阵,8位数据接口
    writecom(0x0c);  //设置开显示,不显示光标
    writecom(0x06); //写一个字符后地址指针加1
    writecom(0x01);//显示清零,数据指针清零
    
}
void main()
{
    initlcd();
    while(1)
    {
        display();  
    }
}

2. Proteus仿真图

3. Proteus仿真现象

十二、 简易示波器的制作

方波 锯齿波 正弦波 三角波 咱都能生成 还能调幅值和频率😢

1. 最初版本

#include <reg51.h>
unsigned int code sin[256]={0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5,0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,0xda,0xdd,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda,0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,0x66,0x63,0x60,0x5d,0x5a,0x57,0x55,0x51,0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,0x33,0x30,0x2e,0x2b,0x29,0x27,0x25,0x22,0x20,0x1e,0x1c,0x1a,0x18,0x16,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,0x27,0x29,0x2b,0x2e,0x30,0x33,0x35,0x38,0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e,0x51,0x55,0x57,0x5a,0x5d,0x60,0x63,0x66,0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80};  //正弦表
sbit key0=P1^0;
sbit key1=P1^1;
sbit key2=P1^2;
sbit key3=P1^3;
sbit key4=P1^4;
sbit key5=P1^5;
unsigned int flag1=0,flag2=0,cnt=50,count=0;
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}

void square()  //方波
{
    unsigned int m;
    for(m=0;m<=400;m++)
    {   
        P2=0x00;
        delay(40);
        P2=0xff;
        delay(cnt);
    }
}
void sinwave()  //正弦波
    
{    unsigned int i,m;
 for(m=0;m<=100;m++)
 {   
     for(i=0;i<255;i++)
         P2=sin[i];
     
 }
}
void sawtooth ()  //锯齿波
{
    
    unsigned int i,m;
    for(m=0;m<=50;m++)
    {   for(i=0;i<=255;i++)
    {
        P2=i;
        if(i==255)
            P2=0; 
    }
    }
}
void tri_wave() //三角波 
{
    unsigned int i,j,m;
    for(m=0;m<=15;m++)
    {   
        for(i=0;i<255;i++)
            P2=i;
        for(j=255;j>0;j--)
            P2=j; 
    }
}
void key()  //调整方波的频率
{
    if(key4==0&&flag1==0)
        flag1=1;
    if(key4==1&&flag1==1)
    {  cnt=cnt+10;
     flag1=0;
    }
    if(key5==0&&flag2==0)
        flag2=1;
    if(key5==1&&flag2==1)
    {  cnt=cnt-10;
     flag2=0;
    }
}

void main()  
{   
    while(1)
    {     
        
        key();   //默认刚仿真的时候可以调方波频率
        P2=0x00;
        delay(50);
        P2=0xff;
        delay(cnt);
        switch(P1)
        {
            case(0xfe):square();break;
            case(0xfd):sinwave();break;
            case(0xfb):sawtooth();break;
            case(0xf7):tri_wave();break;
                
        }
        
    }
}

2. 待调试版本

/*#include <reg51.h>
unsigned int code sin[256]={0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5,0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,0xda,0xdd,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,0xe9,0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda,0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99,0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,0x66,0x63,0x60,0x5d,0x5a,0x57,0x55,0x51,0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,0x38,0x35,0x33,0x30,0x2e,0x2b,0x29,0x27,0x25,0x22,0x20,0x1e,0x1c,0x1a,0x18,0x16,0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15,0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,0x27,0x29,0x2b,0x2e,0x30,0x33,0x35,0x38,0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e,0x51,0x55,0x57,0x5a,0x5d,0x60,0x63,0x66,0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80};  //正弦表
sbit key0=P1^0;
sbit key1=P1^1;
sbit key2=P1^2;
sbit key3=P1^3;
sbit key4=P1^4;
sbit key5=P1^5;
sbit RS=P3^0;  
sbit RW=P3^1;
sbit E=P3^2;
unsigned char data str1[]={"The time:    "};
unsigned int flag1=0,flag2=0,cnt=50,count=0;
signed int hour=0,min=0,sec=0,week=1,k=0,i=0;
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}

void inittimer0()   //定时器0初始化
{   
    TMOD=0x01;
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    ET0=1;
    EA=1;
    TR0=1;
    
}
void writecom(unsigned char com) //写命令
{
    RS=0;
    RW=0;
    E=0;
    P0=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat) //写数据
{
    RS=1;
    RW=0;
    E=0;
    P0=dat;
    delay(5);
    E=1;
    E=0;  
}
void square()  //方波
{
  unsigned int m;
for(m=0;m<=400;m++)
 {   
    P2=0x00;
    delay(50);
    P2=0xff;
    delay(cnt);
}
}
void sinwave()  //正弦波
    
{    unsigned int i,m;
for(m=0;m<=100;m++)
 {   
 for(i=0;i<255;i++)
     P2=sin[i];
 
}
}
void sawtooth()  //锯齿波
{
    
    unsigned int i,m;
for(m=0;m<=50;m++)
 {   for(i=0;i<=255;i++)
    {
        P2=i;
        if(i==255)
           P2=0; 
    }
}
}
void tri_wave()//三角波
{
  unsigned int i,j,m;
for(m=0;m<=15;m++)
 {   
    for(i=0;i<255;i++)
        P2=i;
    for(j=255;j>0;j--)
        P2=j; 
}
}
void key()
{
  if(key4==0&&flag1==0)
   flag1=1;
if(key4==1&&flag1==1)
{  cnt=cnt+10;
   flag1=0;
}
if(key5==0&&flag2==0)
   flag2=1;
if(key5==1&&flag2==1)
{  cnt=cnt-10;
   flag2=0;
}
}
void initlcd()  //初始化LCD1602
{
    writecom(0x38);  //设置16*2显示,5*7点阵,8位数据接口
    writecom(0x0c);  //设置开显示,不显示光标
    writecom(0x06);  //写一个字符后地址指针加1
    writecom(0x01);  //显示清零,数据指针清零
    
}

void display ()
{ 
    
    unsigned char temp0=0,temp1=0,temp2=0,temp3=0,temp4=0,temp5=0;//如果不是int 是 char 还用不用加0x30
    temp0=hour/10;
    temp1=hour%10;
    temp2=min/10;
    temp3=min%10;
    temp4=sec/10;
    temp5=sec%10;
    writecom(0x80+0x44);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(':');
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(temp3+0x30); 
    writedat(':');
    delay(5);
    writedat(temp4+0x30);
    delay(5);
    writedat(temp5+0x30);
    delay(5);//等会儿全放到中断里弄试试
}
void initlcd()  //初始化1602
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}
void main()
{   inittimer0(); 
    initlcd();
    while(1)
    {     
        display ();
        key();

       // P2=0x00;
       // delay(50);
      //  P2=0xff;
      //  delay(cnt);
         //  switch(P1)
    //{
     //   case(0xfe):square();break;
      //  case(0xfd):sinwave();break;
      //  case(0xfb):sawtooth();break;
			//	case(0xf7):tri_wave();break;
        
    //}

}
}
void timer0_isr() interrupt 1  //定时器0的中断函数
{   
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    count++;
    if(count==20)
    { sec++; count=0; }  
    if(sec==60)
    {  min++;sec=0; }
    if(min==60)
    {  hour++;min=0; }
    if(hour==24)
    { week++; hour=0;  }
    if(week==8)
    {week=1;}
}
*/
#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit k1=P1^0; 
sbit k2=P1^1;
sbit k3=P1^2;  
sbit k4=P1^3;  
sbit k5=P1^4; 
sbit k6=P1^5; 
unsigned char str[]={"Set up the time:"};
unsigned char str1[]={"The time:"};
unsigned char cnt=0,flag=0;
unsigned int hour=0,min=0,sec=0;
void delay(unsigned int time)         
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P0=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P0=dat;
    delay(5);
    E=1;
    E=0;  
}
void inittimer0()
{   TMOD=0x01;
 TH0=(65536-50000)/256;
 TL0=(65536-50000)%256;
 ET0=1;
 EA=1;
 TR0=1;
 
}

void display ()
{ 
    
    unsigned char temp0=0,temp1=0,temp2=0,temp3=0,temp4=0,temp5=0;//如果不是int 是 char 还用不用加0x30
    temp0=hour/10;
    temp1=hour%10;
    temp2=min/10;
    temp3=min%10;
    temp4=sec/10;
    temp5=sec%10;
    writecom(0x80);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(':');
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(temp3+0x30); 
    writedat(':');
    delay(5);
    writedat(temp4+0x30);
    delay(5);
    writedat(temp5+0x30);
    delay(5);//等会儿全放到中断里弄试试
}
void initlcd()  //初始化1602
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}
void main()
{   inittimer0();
 initlcd();
 while(1)
 {    
     display();  
   
 }
}
void timer0_isr() interrupt 1
{   
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    cnt++;
    if(cnt==20)
    {   sec++;
     cnt=0;
    }  
    if(sec==60)
    {
        min++;
        sec=0;
    }
    if(min==60)
    { 
        hour++;
        min=0;
    }
    if(hour==24)
    {
        
        hour=0;
        
    }
}

3. Proteus仿真图

十三、密码锁的制作(画饼中😢)

1. 最初版本

2. Proteus仿真图

十四、简易电子钟的制作(后期代码暂时不公开😎)

初期版本可以实现24小时制的日期显示,有需要的可以联系我加入星期 天 月 年和文字修饰和居中对齐。这样代码行数就多啦,看起来很高级😁

1. 最初版本(这个可以考虑用一下)

用这个的俺提供技术支持(PPT Visio word咱都可以参考)

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
unsigned char str[]={""};
unsigned char cnt=0;
unsigned int hour=0,min=0,sec=0; //设置初始时间
void delay(unsigned int time)         
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}
void inittimer0()
{   TMOD=0x01;
 TH0=(65536-50000)/256;
 TL0=(65536-50000)%256;
 ET0=1;
 EA=1;
 TR0=1;
 
}
void display()
{ 
    
    unsigned char temp0=0,temp1=0,temp2=0,temp3=0,temp4=0,temp5=0;//如果不是int 是 char 还用不用加0x30
    temp0=hour/10;
    temp1=hour%10;
    temp2=min/10;
    temp3=min%10;
    temp4=sec/10;
    temp5=sec%10;
    writecom(0x80);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(':');
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(temp3+0x30); 
    writedat(':');
    delay(5);
    delay(5);
    writedat(temp4+0x30);
    delay(5);
    writedat(temp5+0x30);
    delay(5);//等会儿全放到中断里弄试试
}
void initlcd()
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}
void main()
{   inittimer0();
 initlcd();
 while(1)
 {
     display();  
 }
}
void timer0_isr() interrupt 1
{   
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    cnt++;
    if(cnt==20)
    {   sec++;
     cnt=0;
    }  
    if(sec==60)
    {
        min++;
        sec=0;
    }
    if(min==60)
    { 
        hour++;
        min=0;
    }
    if(hour==24)
    {
        
        hour=0;
        
    }
}

2. Proteus仿真图

3. 工程中后器期代码(这个俺用了)

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit k1=P1^0; 
sbit k2=P1^1;
sbit k3=P1^2;  
sbit k4=P1^3;  
sbit k5=P1^4; 
sbit k6=P1^5; 
unsigned char str[]={"Set up the time:"};
unsigned char str1[]={"The time:"};
unsigned char cnt=0,flag=0;
unsigned int hour=0,min=0,sec=0;
void delay(unsigned int time)         
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}
void inittimer0()
{   TMOD=0x01;
 TH0=(65536-50000)/256;
 TL0=(65536-50000)%256;
 ET0=1;
 EA=1;
 TR0=1;
 
}
void keys()
{
    
    if(k1==0)
    {  
        delay(10);
        if(k1==0)//设置
        {
            ET0=0;
            flag++;
            if(flag==4)
                flag=0;
        }}
    
    if(k2==0);//开始
    {delay(10);
     if(k2==0)
     {ET0=1;}
     while(k2==0);
    }
    
    if(k3==0);//停止
    {
        delay(10);
        if(k3==0)
        {ET0=0;}
        while(k3==0);
    }
    
    if(k4==0);//清零
    {
        delay(10);
        if(k4==0)
        {hour=0;min=0;sec=0;ET0=0;}
        while(k4==0);
    }
    
    if(k5==0) //加
    { delay(10);
     if(k5==0)
     {
         if(flag==1)
         {
             hour++;
             if(hour==60)
             {
                 hour=0;
             }
         }
         else if(flag==2)
         {min++;
          if(min==60)
          {
              min=0;
          }
         }
         else if (flag==3)
         {
             sec++;
             if(sec==60)
             {
                 sec=0;
             }
         }
     }	while(k5==0);
    }
    
    
    if(k6==0) //减
    {
        delay(10);
        if(k6==0)
        { 
            if(flag==1)
            {
                hour--;
                if(hour<0)
                {hour=23;}
            }
            else if(flag==2)
            {min--;
             if(min<0)
             {min=59;}
            }
            else if(flag==3)
            {sec--;
             if(sec<0)
             {sec=59;}
            }
        }	while(k6==0);
    }
}
void display ()
{ 
    
    unsigned char temp0=0,temp1=0,temp2=0,temp3=0,temp4=0,temp5=0;//如果不是int 是 char 还用不用加0x30
    temp0=hour/10;
    temp1=hour%10;
    temp2=min/10;
    temp3=min%10;
    temp4=sec/10;
    temp5=sec%10;
    writecom(0x80);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(':');
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(temp3+0x30); 
    writedat(':');
    delay(5);
    writedat(temp4+0x30);
    delay(5);
    writedat(temp5+0x30);
    delay(5);//等会儿全放到中断里弄试试
}
void initlcd()  //初始化1602
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}
void main()
{   inittimer0();
 initlcd();
 while(1)
 {    
     display();  
     keys();
 }
}
void timer0_isr() interrupt 1
{   
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    cnt++;
    if(cnt==20)
    {   sec++;
     cnt=0;
    }  
    if(sec==60)
    {
        min++;
        sec=0;
    }
    if(min==60)
    { 
        hour++;
        min=0;
    }
    if(hour==24)
    {
        
        hour=0;
        
    }
}

4. 后期Proteus仿真图(这个俺用了)

十五、 抢答器的制作(画饼中😋)

1. 最初版本

2. Proteus仿真图

十六、 数字电压表的制作

DAC转换 实时把变化的电压显示到LCD屏幕上

1. 最初版本

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit START=P3^3;
sbit EOC=P3^4;
sbit OE=P3^5;
unsigned int vol=0;
unsigned char str[]={"Voltage:"};
void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void ADC ()
{
		START=0;
		START=1;
		delay(5);
		START=0;
		while(EOC!=1);
		OE=1;
		vol=P1;
		OE=0;

}
void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}
void initlcd()
{
    writecom(0x38);//设置16*2显示,5*7点阵,8位数据接口
    writecom(0x0c);  //设置开显示,不显示光标
    writecom(0x06); //写一个字符后地址指针加1
    writecom(0x01);//显示清零,数据指针清零
    
}
void display()
{
   unsigned int temp1,temp2,temp3,i=0;
   vol=(vol*100)/51;     //  (vol*5)/255
   temp1=vol/100;
   temp2=(vol%100)/10;  //  不加括号对不对 试一下
   temp3=vol%10;
   writecom(0x80);
   delay(5);
  for(i=0;i<=7;i++)
{
  writedat(str[i]);
  delay(5);

}
	  writecom(0x80+0x40+0x04);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat('.');
    delay(5);
		writedat(temp2+0x30);
    delay(5);
		writedat(temp3+0x30);
    delay(5);
    writedat('V');
    delay(5);

}
void main()
{
    initlcd();
	
    while(1)
    {	   ADC();
        display();  
    }
}

2. Proteus仿真图

十七、 简单乐曲的演奏(画饼中😋)

透露下思路 利用矩阵按键,把每个音调对应的频率和公式加到相应按键中,当按键按下,加入蜂鸣器产生声音的代码。若想提前播放已有的歌曲,把对应的数据提前放入数组中,利用循环进行播放。

1. 最初版本

2. Proteus仿真图

十八、 温度传感器的应用(已有人用)

用温度传感器获取当前温度 并显示到LCD1602屏幕上

1. 最初版本

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit DQ=P3^3;
unsigned int readtemp=0;
unsigned char code str[]={"Temperature:   "};

void delay_18B20(unsigned int i)
{
    for(;i>0;i--);
}

void Init_DS18B20(void) 	
{
    unsigned char x=0;
    DQ = 1;          //DQ拉高
    delay_18B20(8);  //稍作延时
    DQ = 0;          //DQ拉低
    delay_18B20(80); //延时大于480us
    DQ = 1;          //拉高总线
    delay_18B20(14);
    x=DQ;            //若x=0初始化成功,若x=1初始化失败
    delay_18B20(20);
}

unsigned char ReadOneChar(void)
{
    unsigned char i=0;
    unsigned char dat = 0;
    for (i=8;i>0;i--)
    {
        DQ = 0; // 拉低总线
        dat>>=1;//每读取移位向右移移位
        DQ = 1; //拉高总线
        if(DQ)
            dat|=0x80;
        delay_18B20(4);
    }
    return(dat);
}

void WriteOneChar(unsigned char dat)   
{
    unsigned char i=0;
    for (i=8; i>0; i--)
    {
        DQ = 0;
        DQ = dat&0x01;
        if(DQ){delay_18B20(1);DQ=1;}
        else{delay_18B20(5);DQ = 1;}
        dat>>=1;
    }
}

unsigned char ReadTemperature(void)
{							 
    unsigned int a=0,b=0,temp=0;
    Init_DS18B20();
    WriteOneChar(0xCC);  // 跳过读序列号操作
    WriteOneChar(0x44);  // 启动温度转换
    delay_18B20(100);    // 
    Init_DS18B20();
    WriteOneChar(0xCC);  //跳过读序列号操作
    WriteOneChar(0xBE);  //读取温度寄存器
    delay_18B20(100);
    a=ReadOneChar();     //读温度低位
    b=ReadOneChar();     //读温度高位
    temp=((b*256+a)>>4); //当前采集温度除16得到实际温度
    return(temp);
}

void delay(unsigned int time)         
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}

void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}

void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}

void display()
{ 
    
    unsigned char temp0=0,temp1=0,temp2=0,z=0;
    temp0=readtemp/100;
    temp1=(readtemp%100)/10;
    temp2=readtemp%10;
    writecom(0x80);
    delay(5);
    while(str[z]!='\0')   
    {writedat(str[z]); delay(5);z++;}
    z=0;
    delay(5);
    writecom(0x80+0x46);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(0xdf);
    delay(5);
    writedat('C');
    delay(5);
    
}

void initlcd()
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}

void main()
{   
    initlcd();
    while(1)
    {  
        readtemp=ReadTemperature();
        display();  
    }
}

2. Proteus仿真图

十九、 蜂鸣器代码

滴~ 学生卡~~~

按键按下 蜂鸣器会响一段时间

1. 最初版本

#include <reg51.h>
sbit sounder=P3^0;
unsigned int  k=0;
void delay(unsigned int time)      //延时    
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void main()
{
	sounder=0;
	while(1)
{
		sounder=~sounder;
        delay(1);
		k++;
		if(k==2000)
	{
		sounder=1;
		k=0;
		while(1);
	}
}
}

2. Proteus仿真图

二十、 直流电机代码

爱的魔力转圈圈😍

1. 最初版本

#include <reg51.h>
sbit IN1=P2^0;
sbit IN2=P2^1;
sbit EN1=P2^2;
void delay(unsigned int time)      
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void motor()
    
    
{
    EN1=1;
    IN2=0;
    IN1=1;
    delay(50);
    IN1=0;
    delay(50);
    
}
void main()
{
    
    while(1)
    {
        motor();
        
    }
    
}

2. Proteus仿真图

二十一、 步进电机代码

每秒旋转45度😁

1. 最初版本

#include <reg51.h>
unsigned char step[]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//1001 1000 1100 0100 0110 0010 0011 0001
void delay(unsigned int time)      
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void display()
{
    unsigned char i=0;
    for(i=0;i<=7;i++)
    {
        P2=step[i];
        delay(1000);
        
    }
}
void main()
    
{
    
    while(1)
    {
        
        display();
        
    }
    
}
#include <reg51.h>
unsigned char step[]={0x09,0x08,0x0c,0x04,0x06,0x02,0x03,0x01};//1001 1000 1100 0100 0110 0010 0011 0001
unsigned char cnt=0,i=0;
void initimer0()
{
    TMOD=0x01;
    TH0=(65536-50000)/256;
    TL0=(65536-50000)%256;
    ET0=1;
    EA=1;
    TR0=1;
    
}


void main()
    
{
    
    initimer0();
    while(1)
    {
        
        
    }
    
}
void timer0_isr () interrupt 1
{
    TH0=0x3c;
    TL0=0xb0;
    cnt++;
    if(cnt==20)
    {
        P2=step[i];
        i++;
        if(i==8)
         {  i=0;}
         cnt=0;
    }
   
} 

2. Proteus仿真图

二十二、DS1302制作的万年历(已有人用)

这是一个万年历 可以显示年月日星期时分秒 并对闰年和月份有自动计算补偿功能 修改时间的时候也很方便,在主函数里面用BCD码格式修改就行了,非常直观😊

~~唉~~我去年买了个表~~~~

1. 最初版本

#include <reg51.h>
#include <intrins.h>//因为要调用nop函数,所以添加这个库函数
#define uchar unsigned char
#define uint unsigned int
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit T_RST=P3^3;
sbit T_CLK=P3^4;
sbit T_IO=P3^5;
uchar datechar[]={"DATE:"};
uchar timechar[]={"TIME:"};
uchar datebuffer[10]={0x32,0x30,0,0,0x2d,0,0,0x2d,0,0};  //0x32表示2,0x30表示0,0x2d表示 -
uchar  timebuffer[8]={0,0,0x3a,0,0,0x3a,0,0}; //0x3a表示冒号
uchar  weekbuffer={0x30};
void  WriteB(uchar  dat)  //单字节写
{ 
    uchar  i;
    for(i=8; i>0; i--)
    {
        T_IO=dat&0x01;
        T_CLK = 1;
        T_CLK = 0;
        dat = dat >> 1; 
    } 
}

void  W1302(uchar address,uchar dat) //单字节写
{
    T_RST = 0;
    T_CLK = 0;
    _nop_();
    _nop_();
    T_RST = 1;
    _nop_();
    _nop_();
    WriteB(address);         
    WriteB(dat);           
    T_CLK = 1;
    T_RST =0;
} 
uchar  ReadB(void) //单字节读
{ 
    uchar i,readdat=0;
    for(i=8; i>0; i--)
    {
        readdat=readdat>>1;
        if(T_IO)
        {
            readdat|=0x80;
        }
        T_CLK = 1;
        T_CLK = 0;            
    } 
    return(readdat); 
}
uchar  R1302(uchar  address)//单字节读(读和写都是从低位开始)
{
    uchar dat=0;
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    WriteB(address);           
    dat = ReadB();           
    T_CLK = 1;
    T_RST =0;
    return(dat);
}


void delay(unsigned int time)  //延时            
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}
void writecom(unsigned char com)  //LCD1602的写命令
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}
void writedat(unsigned char dat)  //LCD1602的写数据
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}void initlcd()   //LCD1602的初始化
{
    writecom(0x38);//设置16*2显示,5*7点阵,8位数据接口
    writecom(0x0c);  //设置开显示,不显示光标
    writecom(0x06); //写一个字符后地址指针加1
    writecom(0x01);//显示清零,数据指针清零
    
}
void display()
{
    int i=0,temp=0;
    temp=R1302(0x8d);  // read year
    datebuffer[2]=0x30+temp/16;
    datebuffer[3]=0x30+temp%16;
    
    temp=R1302(0x8b);  // read week
    weekbuffer=0x30+temp;
    
    temp=R1302(0x89);  // read month
    datebuffer[5]=0x30+temp/16;
    datebuffer[6]=0x30+temp%16;
    
    temp=R1302(0x87);  // read day
    datebuffer[8]=0x30+temp/16;
    datebuffer[9]=0x30+temp%16;
    
    temp=R1302(0x85);  // read hour
    temp=temp&0x7f;
    timebuffer[0]=0x30+temp/16;
    timebuffer[1]=0x30+temp%16;
    
    temp=R1302(0x83);  // read minute
    timebuffer[3]=0x30+temp/16;
    timebuffer[4]=0x30+temp%16;
    
    temp=R1302(0x81);  // read second
    timebuffer[6]=0x30+temp/16;
    timebuffer[7]=0x30+temp%16;
    
    writecom(0x80);  //第一行开始写"DATE:"
    for(i=0;i<5;i++)
    {
        writedat(datechar[i]);
        
    }
    writecom(0xc0); //0x80+0x40 第一行开始写"TIME:"
    for(i=0;i<5;i++)
    {
        writedat(timechar[i]);
        
    }
    
    writecom(0x86); //display calender
    for(i=0;i<10;i++)
    {
        writedat(datebuffer[i]);
        
    }
    
    writecom(0xc6);  //display time
    for(i=0;i<8;i++)
    {
        writedat(timebuffer[i]);
        
    }
    writedat(' ');
    writedat(weekbuffer); //display week
}
void main()
{
    initlcd();
    W1302(0x8e,0); //打开写保护
    W1302(0x8c,0x22); //写入年,BCD码
    W1302(0x8a,0x01); //写入星期
    W1302(0x88,0x05);  //写入月
    W1302(0x86,0x09); //写入日
    W1302(0x84,0x20); //写入小时
    W1302(0x82,0x02); //写入分
    W1302(0x80,0x50); //写入秒
    W1302(0x8e,0x80);//关闭写保护
    while(1)
    {
        display();
        
    }
    
}

2. Proteus仿真图

3. Proteus仿真现象

二十三、年轻人的第一台洗衣机(已有人用)

这台洗衣机可以让你摆脱在农大用手洗衣服的困扰,它小巧精悍:

有两个模式 正转还有反转(分别对应模式1和模式2)

可以设置倒计时洗衣服(最大300s)

当你发现洗衣服的时候忘洗了一件,我们贴心的为你准备了一个暂停功能

可以随时控制洗衣机的开和关😎

本实验是实验 5 11 20的整合

1. 最初版本

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit IN0=P1^5;
sbit IN1=P1^4;
sbit key0=P1^0;
sbit key1=P1^1;
sbit inctime=P1^2;
sbit dectime=P1^3;
sbit ST=P1^6;
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^4;


uint max_time=300;//定时最大值,可以修改
uchar s[]={"0123456789"};
uchar str[]={"MODE:"};
uchar str1[]={"TIME:"};
int dtime=0;//设定的时间
uint count=0,num=0;
char flag=0,flag0=0,flag1=0,flag2=0,flag3=0;
char mode=0;

void motor_forward()
{
	IN0=0;
	IN1=1;
}

void motor_flip()
{
	IN0=1;
	IN1=0;
}

void inittimer()
{
	TMOD=0x10;
	TH1=0x3c;//设置定时器1为50ms延时
	TL1=0xb0;
	ET1=1;
	EA=1;
}

void machine_mode()
{
	if(mode==1)
	{
		motor_forward();
	}
	if(mode==2)
	{
		motor_flip();
	}
}

void datdeal()
{
	if(key0==0&&flag==0)//模式加
	{
		flag=1;
	}
	if(flag==1&&key0==1)
	{
		mode++;
		flag=0;
	}
	if(key1==0&&flag0==0)//模式减
	{
		flag0=1;
	}
	if(flag0==1&&key1==1)
	{
		mode--;
		flag0=0;
	}
	
	if(ST==0&&flag1==0)//开始运行
	{
		flag1=1;
	}
	if(flag1==1&&ST==1)
	{
		machine_mode();
		if(dtime>0)
		{
			TR1=1;
		}
		else TR1=0;
		flag1=0;
	}
	
	if(inctime==0&&flag2==0)//增加设定时间
	{
		flag2=1;
	}
	if(flag2==1&&inctime==1)
	{
		dtime++;
		flag2=0;
	}
	
	if(dectime==0&&flag3==0)//减少设定时间
	{
		flag3=1;
	}
	if(flag3==1&&dectime==1)
	{
		dtime--;
		flag3=0;
	}
	if(mode>2)
	{
		mode=0;
	}
	else if(mode<0)
	{
		mode=0;
	}
	if(dtime<0)//当时间为0时,电机停止运行
	{
		dtime=0;
		TR1=0;
		IN1=0;
		IN0=0;
	}
	if(dtime>max_time)
	{
		dtime=max_time;
	}
}
void delay(unsigned int t)
{
	unsigned int i=0,j=0;
	for(i=0;i<t;i++)
	{
		for(j=0;j<120;j++);
	}
}

void writedat(unsigned char dat)
{
	RS=1;
	RW=0;
	E=0;
	E=1;
	P2=dat;
	delay(5);
	E=0;
}

void writecom(unsigned char com)
{
	RS=0;
	RW=0;
	E=0;
	E=1;
	P2=com;
	delay(5);
	E=0;
}

void display()
{
	uchar temp0=0;
	uchar ttemp0=0,ttemp1=0,ttemp2=0;
	uchar i=0,j=0;
	
	temp0=mode%10;
	ttemp0=dtime/100;
	ttemp1=dtime%100/10;
	ttemp2=dtime%10;
	
	writecom(0x80);//第一行显示mode
	while(str[i]!='\0')
	{
		writedat(str[i]);
		i++;
	}
	writedat(':');
	writedat(s[temp0]);
	
	writecom(0x80+0x40);//第二行显示time
	while(str1[j]!='\0')
	{
		writedat(str1[j]);
		j++;
	}
	writedat(s[ttemp0]);
	writedat(s[ttemp1]);
	writedat(s[ttemp2]);
	writedat('s');
}

void initex()//初始化外部中断0
{
	IE0=1;
	EX0=1;
}


	
void initlcd()
{
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}

void main()
{
	initex();//初始化外部中断
	inittimer();//初始化定时器
	initlcd();//初始化lcd
	while(1)
	{
		datdeal();
		display();
	}
}

void ex_isr() interrupt 0//停止运行电机
{
	TR1=0;
	IN1=0;
	IN0=0;
}

void timer1_isr() interrupt 3//每一秒钟设定时间减1
{
	TH1=0x3c;
	TL1=0xb0;
	num++;
	if(num==20)
	{
		dtime--;
		num=0;
	}
}

2. Proteus仿真图

二十四、年轻人的第一个风扇(已有人用)

这个小风扇可以实现在LCD1602上实时显示 当前温度

并且在温度大于30度的时候,开始启动风扇,且温度越高,风扇的转速越快

风扇开启关闭还有提示哦😋

让你在农大拥有一个美好的夏天!!!!😉

1. 最初版本

#include <reg51.h>
sbit RS=P3^0;
sbit RW=P3^1;
sbit E=P3^2;
sbit DQ=P3^4;
sbit IN0=P1^0;
sbit IN1=P1^1;
sbit EN=P1^2;
unsigned int readtemp=0;
unsigned char code str[]={"Temperature:   "};

void delay_18B20(unsigned int i)
{
    for(;i>0;i--);
}

void Init_DS18B20(void) 	
{
    unsigned char x=0;
    DQ = 1;          //DQ拉高
    delay_18B20(8);  //稍作延时
    DQ = 0;          //DQ拉低
    delay_18B20(80); //延时大于480us
    DQ = 1;          //拉高总线
    delay_18B20(14);
    x=DQ;            //若x=0初始化成功,若x=1初始化失败
    delay_18B20(20);
}

unsigned char ReadOneChar(void)
{
    unsigned char i=0;
    unsigned char dat = 0;
    for (i=8;i>0;i--)
    {
        DQ = 0; // 拉低总线
        dat>>=1;//每读取移位向右移移位
        DQ = 1; //拉高总线
        if(DQ)
            dat|=0x80;
        delay_18B20(4);
    }
    return(dat);
}

void WriteOneChar(unsigned char dat)   
{
    unsigned char i=0;
    for (i=8; i>0; i--)
    {
        DQ = 0;
        DQ = dat&0x01;
        if(DQ){delay_18B20(1);DQ=1;}
        else{delay_18B20(5);DQ = 1;}
        dat>>=1;
    }
}

unsigned char ReadTemperature(void)
{							 
    unsigned int a=0,b=0,temp=0;
    Init_DS18B20();
    WriteOneChar(0xCC);  // 跳过读序列号操作
    WriteOneChar(0x44);  // 启动温度转换
    delay_18B20(100);    // 
    Init_DS18B20();
    WriteOneChar(0xCC);  //跳过读序列号操作
    WriteOneChar(0xBE);  //读取温度寄存器
    delay_18B20(100);
    a=ReadOneChar();     //读温度低位
    b=ReadOneChar();     //读温度高位
    temp=((b*256+a)>>4); //当前采集温度除16得到实际温度
    return(temp);
}

void delay(unsigned int time)         
{
    unsigned int i;
    for(time;time>0;time--)
        for(i=120;i>0;i--); 
}

void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    P2=com;
    delay(5);
    E=1;
    E=0; 
    
}

void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    P2=dat;
    delay(5);
    E=1;
    E=0;  
}

void display()
{ 
    int temp=0;
    unsigned char temp0=0,temp1=0,temp2=0,z=0;
    
    temp0=readtemp/100;
    temp1=(readtemp%100)/10;
    temp2=readtemp%10;
    temp=100*temp0+10*temp1+temp2;
    
    if(temp>30)   //温度大于30℃时
    {
        
        IN1=0;
        IN0=1;
        delay(10*temp);
        IN0=0;
        delay(5);
        EN=1;
        writecom(0x80+0x40);
        delay(5);
        writedat('O');
        delay(5);
        writedat('N');
        delay(5);
        writedat(' ');
        delay(5);
    }
    else if(temp<=30)//温度小于等于30℃时
    { 
        IN0=0;
        IN1=0;
        writecom(0x80+0x40);
        delay(5);
        writedat('O');
        delay(5);
        writedat('F');
        delay(5);
        writedat('F');
        delay(5);
    }
    
    writecom(0x80);
    delay(5);
    while(str[z]!='\0')   
    {writedat(str[z]); delay(5);z++;}
    z=0;
    delay(5);
    writecom(0x80+0x46);
    delay(5);
    writedat(temp0+0x30);
    delay(5);
    writedat(temp1+0x30);
    delay(5);
    writedat(temp2+0x30);
    delay(5);
    writedat(0xdf);
    delay(5);
    writedat('C');
    delay(5);
    
}

void initlcd()
{
    writecom(0x38);
    writecom(0x0c);  
    writecom(0x06); 
    writecom(0x01);
    
}

void main()
{   
 initlcd();
 while(1)
 {  
     readtemp=ReadTemperature();
     display(); 
     
 }
}

2. Proteus仿真图

3. Proteus仿真现象

二十五、正弦波频率发生器(已有人用)

用按键控制生成可变频率的正弦波并在LCD1602上显示相关频率信息

1. 最初版本

#include <reg51.h>
#define uint unsigned int
#define uchar unsigned char
sbit key0=P1^0;
sbit key1=P1^1;
sbit start=P1^2;
sbit RS=P3^3;
sbit RW=P3^4;
sbit E=P3^5;
code unsigned char sin[256]=
{
    0x80,0x83,0x86,0x89,0x8d,0x90,0x93,0x96,
    0x99,0x9c,0x9f,0xa2,0xa5,0xa8,0xab,0xae,
    0xb1,0xb4,0xb7,0xba,0xbc,0xbf,0xc2,0xc5,
    0xc7,0xca,0xcc,0xcf,0xd1,0xd4,0xd6,0xd8,
    0xda,0xdd,0xdf,0xe1,0xe3,0xe5,0xe7,0xe9,
    0xea,0xec,0xee,0xef,0xf1,0xf2,0xf4,0xf5,
    0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,
    0xfd,0xfe,0xff,0xff,0xff,0xff,0xff,0xff,
    0xff,0xff,0xff,0xff,0xff,0xff,0xfe,0xfd,
    0xfd,0xfc,0xfb,0xfa,0xf9,0xf8,0xf7,0xf6,
    0xf5,0xf4,0xf2,0xf1,0xef,0xee,0xec,0xea,
    0xe9,0xe7,0xe5,0xe3,0xe1,0xde,0xdd,0xda,
    0xd8,0xd6,0xd4,0xd1,0xcf,0xcc,0xca,0xc7,
    0xc5,0xc2,0xbf,0xbc,0xba,0xb7,0xb4,0xb1,
    0xae,0xab,0xa8,0xa5,0xa2,0x9f,0x9c,0x99,
    0x96,0x93,0x90,0x8d,0x89,0x86,0x83,0x80,
    0x80,0x7c,0x79,0x76,0x72,0x6f,0x6c,0x69,
    0x66,0x63,0x60,0x5d,0x5a,0x57,0x55,0x51,
    0x4e,0x4c,0x48,0x45,0x43,0x40,0x3d,0x3a,
    0x38,0x35,0x33,0x30,0x2e,0x2b,0x29,0x27,
    0x25,0x22,0x20,0x1e,0x1c,0x1a,0x18,0x16,
    0x15,0x13,0x11,0x10,0x0e,0x0d,0x0b,0x0a,
    0x09,0x08,0x07,0x06,0x05,0x04,0x03,0x02,
    0x02,0x01,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x02,
    0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,
    0x0a,0x0b,0x0d,0x0e,0x10,0x11,0x13,0x15,
    0x16,0x18,0x1a,0x1c,0x1e,0x20,0x22,0x25,
    0x27,0x29,0x2b,0x2e,0x30,0x33,0x35,0x38,
    0x3a,0x3d,0x40,0x43,0x45,0x48,0x4c,0x4e,
    0x51,0x55,0x57,0x5a,0x5d,0x60,0x63,0x66,
    0x69,0x6c,0x6f,0x72,0x76,0x79,0x7c,0x80
    };  //正弦表
uint count=0,fre=0;
uchar flag=0,flag0=0,flag1=0;
uchar timeh=0,timel=0;
uchar str[]={"Frequence:"};

void delay(unsigned int t)
{
    unsigned int i=0,j=0;
    for(i=0;i<t;i++)
    {
        for(j=0;j<120;j++);
    }
}

void writedat(unsigned char dat)
{
    RS=1;
    RW=0;
    E=0;
    E=1;
    P0=dat;
    delay(5);
    E=0;
}

void writecom(unsigned char com)
{
    RS=0;
    RW=0;
    E=0;
    E=1;
    P0=com;
    delay(5);
    E=0;
}

void initlcd()
{
    writecom(0x38);
    writecom(0x0c);
    writecom(0x06);
    writecom(0x01);
}

void key()
{
    if(key0==0&&flag==0)
    {
        flag=1;
    }
    if(flag==1&&key0==1)
    {
        fre=fre+1;
        flag=0;
    }
    
    if(key1==0&&flag0==0)
    {
        flag0=1;
    }
    if(flag0==1&&key1==1)
    {
        fre=fre-1;
        flag0=0;
    }
    
    if(start==0&&flag1==0)
    {
        flag1=1;
    }
    if(flag1==1&&start==1)
    {
        TR0=1;
        flag1=0;
    }
}

void datdeal()
{
    uint temp=0;//temp里面是初值
    temp=62500/(fre*16);   // 计算公式:1000000/(fre*256)=1/fre/256*1000000
    timeh=(65536-temp)/256;
    timel=(65536-temp)%256;
}

void inittimer()
{
    TMOD=0x01;
    TH0=timeh;
    TL0=timel;
    ET0=1;
    EA=1;
}

void init_exit1()
{
    IE0=1;
    EX0=1;
}

void display()
{
    uchar temp0=0,temp1=0,temp2=0;
    uchar i=0;
    temp0=fre/100;
    temp1=fre%100/10;
    temp2=fre%10;
    
    writecom(0x80);
    while(str[i]!='\0')
    {
        writedat(str[i]);
        i++;
    }
    writecom(0x80+0x46);
    writedat(	temp0+0x30);
    writedat(	temp1+0x30);
    writedat(	temp2+0x30);
    writedat('H');
    writedat('Z');
}

void main()
{
    init_exit1();
    inittimer();
    initlcd();
    while(1)
    {
        key();
        datdeal();
        display();
    }
}

void ex_isr() interrupt 0
{
    TR0=0;
}

void timer_isr() interrupt 1
{
    TH0=timeh;
    TL0=timel;
    count++;
    P2=sin[count];
    if(count==256)
    {
        count=0;
    }	
}

2. Proteus仿真图

3. Proteus仿真现象

二十六、16*16点阵的应用😁

1. 最初版本

#include <reg51.h>
unsigned int row[]={1,2,4,8,16,32,64,128,256,512,1024,2048,4096,8192,16384,32768};
code unsigned int column[]=
{
	
	0x0000,0x2088,0x1108,0x13C8,0x0248,0x03DC,0x7248,0x13C8,0x1268,0x17D8,0x10C8,0x1148,0x1A48,0x1448,0x00D8,0x0000,//谢
	0x0000,0x2088,0x1108,0x13C8,0x0248,0x03DC,0x7248,0x13C8,0x1268,0x17D8,0x10C8,0x1148,0x1A48,0x1448,0x00D8,0x0000,//谢
	0x0000,0x0100,0x0100,0x7FFC,0x0100,0x0100,0x3FF0,0x0810,0x0820,0x0440,0x0280,0x0100,0x0280,0x0C60,0x701C,0x0000,//支
	0x0000,0x1040,0x1040,0x11F8,0x7C40,0x1040,0x13FC,0x1410,0x1810,0x73FC,0x1010,0x1110,0x1090,0x1010,0x7070,0x0000,//持
};
unsigned char num=0,count=0;
unsigned char row_num=16,column_num=16;
unsigned int temp=0;

void delay(unsigned int t)
{
	unsigned int i=0,j=0;
	for(i=0;i<t;i++)
	{
		for(j=0;j<120;j++);
	}
}

void matrix()
{
	unsigned char i=0;
	
	for(i=0;i<row_num;i++)
	{
		P1=row[i]/256;
		P0=row[i]%256;
		temp=(column[i+column_num*count])>>num;
		P3=~(temp/256);
		P2=~(temp%256);
		delay(1);
	}
 	num++;
	delay(40);
 	if(num==16)//num移动次数
 	{
 		num=0;
		count++;
 	}
	if(count==4)//count汉字的个数
	{
		count=0;
	}
}

void main()
{
	while(1)
	{
		matrix();
	}
}

2. Proteus仿真图

3. Proteus仿真现象

二十七、基于51单片机频率检测计的实现

1. 最初版本

#include <reg51.h>
#define uchar unsigned char
#define uint unsigned int
uchar count=0,valueH=0,valueL=0;
uchar str1[]={"Frequence:"};
uint fre=0;
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;

void initex0()  //初始化外部中断0
{
	IT0=1;
	EX0=1;
	EA=1;
}

void inittimer0()  //初始化定时器0
{
	TMOD=0x01;
	TH0=0x00;
	TL0=0x00;
}

void datadeal()  //数据处理
{
	uint value=0;
	value=valueH*256+valueL;
	fre=10000000/value;
}
void delay(unsigned int t)//延时函数
{
	unsigned int i=0,j=0;
	for(i=0;i<t;i++)
	{
		for(j=0;j<120;j++);
	}
}

void writecom(unsigned char com)//写命令
{
	RS=0;
	RW=0;
	E=0;
	E=1;
	P2=com;
	delay(5);
	E=0;
}

void writedat(unsigned char dat) //写数据
{
	RS=1;
	RW=0;
	E=0;
	E=1;
	P2=dat;
	delay(5);
	E=0;
}


	
void initlcd()  //初始化LCD1602
{
	writecom(0x38);
	writecom(0x0c);
	writecom(0x06);
	writecom(0x01);
}

void display()  //演示函数
{
	uchar temp0=0,temp1=0,temp2=0,temp3=0,temp4=0;
	uchar i=0;
	temp0=(fre%100000)/10000;  //万
	temp1=(fre%10000)/1000;  // 千
	temp2=(fre%1000)/100;   //百
	temp3=(fre%100)/10;  // 十
	temp4=fre%10;    //个
	writecom(0x80);
	delay(1);
	while(str1[i]!='\0')
	{
		writedat(str1[i]);  //写Frequence
		delay(1);
		i++;
	}
	writecom(0x80+0x40+4);
	delay(1);
	writedat(temp0+0x30);
	delay(1);
	writedat(temp1+0x30);
	delay(1);
	writedat(temp2+0x30);
	delay(1);
	writedat(temp3+0x30);
	delay(1);
	writedat('.');  //小数点
	delay(1);
	writedat(temp4+0x30);
	delay(1);
	writedat('H');
	delay(1);
	writedat('Z');
	delay(1);
}

void main()
{
	initex0();
	inittimer0();
	initlcd();
	while(1)
	{
 		datadeal();
		display();
	}
}

void ex0_isr() interrupt 0
{
	if(count==0)
	{
		TH0=0x00;
		TL0=0x00;
		TR0=1;
	}
	else if(count==1)
	{
		TR0=0;
		valueH=TH0;
		valueL=TL0;
		count=0;
	}
 	count++;
}

2. Proteus仿真图

二十八、贪吃蛇游戏的实现

1. 最初版本

#include "reg52.h"
#include "stdlib.h"

typedef unsigned char u8;  //0~255
typedef unsigned int u16;  //0~65535
typedef unsigned long u32; //0~4294967295

sbit D0=P2^0;
sbit D1=P2^1;
sbit D2=P2^2;
sbit D3=P2^3;
sbit KEY1=P3^5;
sbit KEY2=P3^4;
sbit KEY3=P3^3;
sbit KEY4=P3^2;

#define X1 P0
#define X2 P1

u8 Date[32]=
{
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
};//点阵屏显示数据
u8 snake_turn_point[20]={0};//存储蛇尾的转折点
u32 snake_turn=0;//相应转点为左转还是右转 0为左转1为右转
u8 snake_cd=2;//蛇的长度 初始值为2
u8 smake_head_x=10;//蛇头的x轴坐标
u8 smake_head_y=10;//蛇头的y轴坐标
u8 smake_tail_x=10;//蛇尾的x轴坐标
u8 smake_tail_y=11;//蛇尾的y轴坐标
u8 snake_fx=3;//蛇的运动方向  1:上 2:下 3:左 4:右
u8 snake_sd=10;//运动速度
u8 snake_turn_time=0;//蛇的尾巴剩余转点
u8 snake_tail_fx=3;//蛇尾运动方向
u8 food_x=5;//食物的x轴坐标
u8 food_y=5;//食物的y轴坐标
u8 food_x_next=10;//下一个食物的x轴坐标
u8 food_y_next=10;//下一个食物的y轴坐标

void Display(void);//显示函数
void InitTimer0(void);//定时器中断初始化 10ms
void Key_Scan(void);//按键扫描函数
void Write_Date(u8 x,u8 y,u8 a);//对点的写操作
void snake_move(void);//蛇的移动
void game_over(void);//游戏结束 显示完
void creat_food();//生产食物

void main(void)
{
    InitTimer0();//初始化定时器
    Write_Date(food_x,food_y,1);
    while(1)
    {
        Display();
        Key_Scan();
    }
}

void InitTimer0(void)
{
    TMOD = 0x01;
    TH0 = 0x0D8;
    TL0 = 0x0F0;
    EA = 1;
    ET0 = 1;
    TR0 = 1;
}

void Display(void)
{
    X1=0x00;	X2=0x00;	D3=0;	D2=0;	D1=0;	D0=0;	X1=Date[0];		X2=Date[1];
    X1=0x00;	X2=0x00;	D3=0;	D2=0;	D1=0;	D0=1;	X1=Date[2];		X2=Date[3];
    X1=0x00;	X2=0x00;	D3=0;	D2=0;	D1=1;	D0=0;	X1=Date[4];		X2=Date[5];
    X1=0x00;	X2=0x00;	D3=0;	D2=0;	D1=1;	D0=1;	X1=Date[6];		X2=Date[7];
    X1=0x00;	X2=0x00;	D3=0;	D2=1;	D1=0;	D0=0;	X1=Date[8];		X2=Date[9];
    X1=0x00;	X2=0x00;	D3=0;	D2=1;	D1=0;	D0=1;	X1=Date[10];	X2=Date[11];
    X1=0x00;	X2=0x00;	D3=0;	D2=1;	D1=1;	D0=0;	X1=Date[12];	X2=Date[13];
    X1=0x00;	X2=0x00;	D3=0;	D2=1;	D1=1;	D0=1;	X1=Date[14];	X2=Date[15];
    X1=0x00;	X2=0x00;	D3=1;	D2=0;	D1=0;	D0=0;	X1=Date[16];	X2=Date[17];
    X1=0x00;	X2=0x00;	D3=1;	D2=0;	D1=0;	D0=1;	X1=Date[18];	X2=Date[19];
    X1=0x00;	X2=0x00;	D3=1;	D2=0;	D1=1;	D0=0;	X1=Date[20];	X2=Date[21];
    X1=0x00;	X2=0x00;	D3=1;	D2=0;	D1=1;	D0=1;	X1=Date[22];	X2=Date[23];
    X1=0x00;	X2=0x00;	D3=1;	D2=1;	D1=0;	D0=0;	X1=Date[24];	X2=Date[25];
    X1=0x00;	X2=0x00;	D3=1;	D2=1;	D1=0;	D0=1;	X1=Date[26];	X2=Date[27];
    X1=0x00;	X2=0x00;	D3=1;	D2=1;	D1=1;	D0=0;	X1=Date[28];	X2=Date[29];
    X1=0x00;	X2=0x00;	D3=1;	D2=1;	D1=1;	D0=1;	X1=Date[30];	X2=Date[31];
}

void Key_Scan(void)
{
    static fx=3;
    if(KEY1==0)
        snake_fx=1;
    if(KEY2==0)
        snake_fx=2;
    if(KEY3==0)
        snake_fx=3;
    if(KEY4==0)
        snake_fx=4;
    
    if(fx!=snake_fx)
    {
        snake_turn_point[snake_turn_time]|=snake_fx*16;//保存蛇尾拐点方向
        if(snake_fx==1||snake_fx==2)
            snake_turn_point[snake_turn_time]+=smake_head_y;
        else if(snake_fx==3||snake_fx==4)
            snake_turn_point[snake_turn_time]+=smake_head_x; 		//保存蛇尾拐点的坐标
        snake_turn_time++;
        fx=snake_fx;
    }
}

void tail_turn()
{
    u8 i;
    for(i=0;i<snake_turn_time;i++)
    {
        snake_turn_point[i]=snake_turn_point[i+1];
    }
    snake_turn_time-=1;
}
void res_food()
{
    food_x=food_x_next;
    food_y=food_y_next;
    Write_Date(food_x,food_y,1);
}
void snake_move(void)
{
    u8 dat=0x01;
    u8 bj_get_food=0;
    if(smake_head_y==0&&snake_fx==3)
        game_over();
    if(smake_head_x==0&&snake_fx==1)
        game_over();									//判断蛇头是否碰到上、左墙壁
    
    if(snake_fx==1)
    {
        if(!((smake_head_x-1==food_x)&&(smake_head_y==food_y)))
        {
            Write_Date(smake_tail_x,smake_tail_y,0);		//熄灭蛇尾
            bj_get_food=1;
        }		
    }
    else if(snake_fx==2)
    {
        if(!((smake_head_x+1==food_x)&&(smake_head_y==food_y)))
        {
            Write_Date(smake_tail_x,smake_tail_y,0);		//熄灭蛇尾
            bj_get_food=1;
        }
    }
    else if(snake_fx==3)
    {
        if(!((smake_head_y-1==food_y)&&(smake_head_x==food_x)))
        {
            Write_Date(smake_tail_x,smake_tail_y,0);		//熄灭蛇尾
            bj_get_food=1;
        }
    }
    else if(snake_fx==4)
    {
        if(!((smake_head_y+1==food_y)&&(smake_head_x==food_x)))
        {
            Write_Date(smake_tail_x,smake_tail_y,0);		//熄灭蛇尾
            bj_get_food=1;
        }
    }
    if(!bj_get_food)
    {
        res_food();
    }																	//如果吃食物了 点亮下一个食物
    
    if((snake_tail_fx==1)&&(smake_tail_x==(snake_turn_point[0]&0x0f)))
    {
        snake_tail_fx=snake_turn_point[0]/16;
        tail_turn();
    }
    else if((snake_tail_fx==2)&&(smake_tail_x==(snake_turn_point[0]&0x0f)))
    {
        snake_tail_fx=snake_turn_point[0]/16;
        tail_turn();
    }
    else if((snake_tail_fx==3)&&(smake_tail_y==(snake_turn_point[0]&0x0f)))
    {
        snake_tail_fx=snake_turn_point[0]/16;
        tail_turn();
    }
    else if((snake_tail_fx==4)&&(smake_tail_y==(snake_turn_point[0]&0x0f)))
    {
        snake_tail_fx=snake_turn_point[0]/16;
        tail_turn();
    }		
    //判断蛇尾是否需要转向
    
    if(bj_get_food)
    {
        if(snake_tail_fx==1)
            smake_tail_x-=1;
        else if(snake_tail_fx==2)
            smake_tail_x+=1;
        else if(snake_tail_fx==3)
            smake_tail_y-=1;
        else if(snake_tail_fx==4)
            smake_tail_y+=1; 						//蛇尾巴移动
    }
    
    if(snake_fx==1)
        smake_head_x-=1;
    else if(snake_fx==2)
        smake_head_x+=1;
    else if(snake_fx==3)
        smake_head_y-=1;
    else if(snake_fx==4)
        smake_head_y+=1; 						//蛇头移动
    
    if(smake_head_y==16||smake_head_x==16)
        game_over();								//判断蛇头是否碰到下、右墙壁
    
    if(smake_head_y<8)
    {
        dat=dat<<smake_head_y;
        if((Date[2*smake_head_x]&dat)&&bj_get_food)
            game_over();
    }
    else
    {
        dat=dat<<(smake_head_y-8);
        if((Date[2*smake_head_x+1]&dat)&&bj_get_food)
            game_over();
    }															//判断蛇头是否碰到了身子
    
}

void Write_Date(u8 x,u8 y,u8 a)
{
    u8 i;
    u8 dat;
    if(a==0)
    {
        dat=0xfe;
        if(y<8)
        {
            for(i=0;i<y;i++)
            {
                dat=dat<<1;
                dat|=0x01;
            }
            Date[2*x]&=dat;
        }
        else if(y<16)
        {
            y-=8;
            for(i=0;i<y;i++)
            {
                dat=dat<<1;
                dat|=0x01;
            }
            Date[2*x+1]&=dat;
        }
    }
    else
    {
        dat=0x01;
        if(y<8)
        {
            dat=dat<<y;
            Date[2*x]|=dat;
        }
        else if(y<16)
        {
            y-=8;
            dat=dat<<y;
            Date[2*x+1]|=dat;
        }
    }
}

void game_over()
{
    u8 wan[32]=
    {
        0x40,0x00,0x80,0x00,0xFE,0x7F,0x02,0x40,0x01,0x20,0xF8,0x0F,0x00,0x00,0x00,0x00,
        0xFE,0x3F,0x20,0x02,0x20,0x02,0x20,0x02,0x10,0x22,0x10,0x22,0x08,0x22,0x06,0x3C,
    };
    u8 i;
    for(i=0;i<32;i++)
        Date[i]=wan[i];
    EA=0;
}

void creat_food()
{
    u8 dat=0x01;
    u8 x,y,next_x,next_y;
    u8 bj=0;
    y=food_y_next;
    x=food_x_next;
    do
    {
        bj=0;
        next_x=(rand()%16);
        next_y=(rand()%16);
        if(next_y>=8)
        {
            bj=1;
            next_y-=8;
        }
        dat=0x01;
        dat=dat<<next_y;
    }while(dat==Date[2*next_x+bj]);
    food_x_next=next_x;
    food_y_next=next_y+8*bj;
}

void Timer0Interrupt(void) interrupt 1
{
    static u8 js=0;
    
    if(js<snake_sd) js++;
    else if(js==snake_sd)
    {
        js=0;
        creat_food();
        snake_move();
        Write_Date(smake_head_x,smake_head_y,1);
    }
    TH0 = 0x0D8;
    TL0 = 0x0F0;
}

二十九、智能计算器的实现

1. 最初版本

/*  S16 S12 S8 S4分别是123+
	S15 S11 S7 S3分别是456-
	S14 S10 S6 S2分别是789*
	S13 S9 S5 S1分别是0 CLR = /
*/

/* 实现两个数的运算,每个数的位数至少可以八位  */
#include<reg52.h>			
typedef unsigned char uint8;
typedef unsigned int uint16;

sbit rw=P2^5;
sbit rs=P2^6;
sbit e=P2^7;
sbit led=P3^7;

sbit beep=P2^0;
uint8 key,num;
uint8 fuhao;//定义具体的那个符号,是加减还是乘除。
uint8 flag;	//定义有没有按下符号键,这个是统称
long a,b,c,d;	//定义运算数据的第一个和第二个及等于的数变量
uint8 k; //定义小数点后面显示的位数
uint8 biao;

uint8 dat1[]={1,2,3,0x2b-0x30, 4,5,6,0x2d-0x30, 7,8,9,0x2a-0x30, 0,0x01-0x30,0x3d-0x30,0x2b-0x30 };//保存显示的数据

void delay(uint16 i)
{
	while(i--);
}
void lcdwrc(uint8 c)
{
	delay(1000);
	rs=0;
	rw=0;
	e=0;
	P0=c;
	e=1;
	delay(1000);
	e=0;
}
void lcdwrd(uint8 dat)
{
	delay(1000);
	rs=1;
	rw=0;
	e=0;
	P0=dat;
	e=1;
	delay(1000);
	e=0;
	rs=0;
}

void lcdinit()
{
	delay(1500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	delay(500);
	lcdwrc(0x38);
	lcdwrc(0x08);
	lcdwrc(0x01);
	lcdwrc(0x06);
	lcdwrc(0x0c);
	key=0;
	num=0;
	flag=0;
	fuhao=0;
	a=0;
	b=0;
	c=0;
	d=0;
	biao=0;
	led=0;

}

void keyscan()
{
	P1=0xfe;   //令第一行为0,然后判断是哪一列按下
	if(P1!=0xfe)
	{
		delay(1000);
		if(P1!=0xfe)
		{
			key=P1&0xf0;
			switch(key)
			{
				case 0xe0: num=0;break;	  //1
				case 0xd0: num=1;break;	  //2
				case 0xb0: num=2;break;	  //3
				case 0x70: num=3;break;	  //加
			}
		}
		while(P1!=0xfe);
		if(num==0||num==1||num==2)	 //确认第一行的数1,2,3
		{
			if(flag==0)	 //没有按下符号键
			{
				//led=1;
				a=a*10+dat1[num];	
			}
			else
			{
				//led=1;
				b=b*10+dat1[num];
			}
		
		}
		if(num==3)
		{
			//led=0;
			flag=1;
			fuhao=1;//加号+	
		}
		lcdwrd(0x30+dat1[num]);
	}


	P1=0xfd;				//令第二行为0,判断是哪一列按下
	if(P1!=0xfd)
	{
		delay(1000);
		if(P1!=0xfd)
		{
			key=P1&0xf0;
			switch(key)
			{
				case 0xe0: num=4;break;	  //4
				case 0xd0: num=5;break;	  //5
				case 0xb0: num=6;break;	  //6
				case 0x70: num=7;break;	  //减—
			}	
		}
		while(P1!=0xfd);
		if(num==4||num==5||num==6)
		{
			if(flag==0)	 //没有按下符号键
			{
				//led=1;
				a=a*10+dat1[num];	
			}
			else
			{
				//led=1;
				b=b*10+dat1[num];
			}			
		}
		else
		{
			flag=1;
			fuhao=2;//带表减号
		}
		lcdwrd(0x30+dat1[num]);
	}


	P1=0xfb;		 //令第三行为0,判断哪一列按下
	if(P1!=0xfb)
	{
		delay(1000);
		if(P1!=0xfb)
		{
			key=P1&0xf0;
			switch(key)
			{
				case 0xe0: num=8;break;	  //7
				case 0xd0: num=9;break;	  //8
				case 0xb0: num=10;break;  //9
				case 0x70: num=11;break;  //乘*
			}	
		}
		while(P1!=0xfb);
		if(num==8||num==9||num==10)
		{
			if(flag==0)	 //没有按下符号键
			{
				//led=1;
				a=a*10+dat1[num];	
			}
			else
			{
				//led=1;
				b=b*10+dat1[num];
			}			
		}
		else
		{
			flag=1;
			fuhao=3;//带表乘号*
		}
		lcdwrd(0x30+dat1[num]);
	}


	P1=0xf7;		 //令第四行为0,判断哪一列按下
	if(P1!=0xf7)
	{
		delay(1000);
		if(P1!=0xf7)
		{
			key=P1&0xf0;
			switch(key)
			{
				case 0xe0: num=12;break;  //0
				case 0xd0: num=13;break;  //清除rst
				case 0xb0: num=14;break;  //等号=
				case 0x70: num=15;break;  //除/
			}	
		}
		while(P1!=0xf7);
		switch(num)
		{
			case 12: 
					if(flag==0)	 //没有按下符号键
					{
						//led=1;
						a=a*10+dat1[num];
						lcdwrd(0x30);	
					}
					else
					{
						//led=1;
						b=b*10+dat1[num];
						lcdwrd(0x30);
					}
					break;
			
			case 13: 
					lcdwrc(0x01);	//清屏指令			
					a=0;
					b=0;
					flag=0;
					fuhao=0;
					break;

			case 15:
			
					flag=1;
					fuhao=4;
					lcdwrd(0x2f);//除号/
					break;
					
			case 14: 
					if(fuhao==1)//加
					{
						lcdwrc(0x4f+0x80);
						lcdwrc(0x04);//设置光标左移,屏幕不移动
						c=a+b;
						while(c!=0)	 //一位一位显示
						{
							lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
							c=c/10;//取前面的结果数据	
						}
						lcdwrd(0x3d); //显示等于号=
						a=0;
						b=0;
						flag=0;
						fuhao=0;//全部清除为0
					}
					if(fuhao==2)   //减
					{
						lcdwrc(0x4f+0x80);
						lcdwrc(0x04);//设置光标左移,屏幕不移动
						if(a>b)
							c=a-b;
						else
							c=b-a;
						
						while(c!=0)	 //一位一位显示
						{
							lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
							c=c/10;//取前面的结果数据	
						}
						if(a<b)	lcdwrd(0x2d); //显示-号
						lcdwrd(0x3d); //显示等于号=
						a=0;
						b=0;
						flag=0;
						fuhao=0;//全部清除为0
					}
					if(fuhao==3)//乘法		
					{
						lcdwrc(0x4f+0x80);
						lcdwrc(0x04);//设置光标左移,屏幕不移动
						c=a*b;
						while(c!=0)	 //一位一位显示
						{
							lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
							c=c/10;//取前面的结果数据	
						}
						lcdwrd(0x3d); //显示等于号=
						a=0;
						b=0;
						flag=0;
						fuhao=0;//全部清除为0	
					}
					if(fuhao==3)//乘法		
					{
						lcdwrc(0x4f+0x80);
						lcdwrc(0x04);//设置光标左移,屏幕不移动
						c=a*b;
						while(c!=0)	 //一位一位显示
						{
							lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
							c=c/10;//取前面的结果数据	
						}
						lcdwrd(0x3d); //显示等于号=
						a=0;
						b=0;
						flag=0;
						fuhao=0;//全部清除为0	
					}
					if(fuhao==4)
					{
						k=0;
						lcdwrc(0x4f+0x80);
						lcdwrc(0x04);//设置光标左移,屏幕不移动
						c=(long)(((float)a/b)*1000);//强制转换为long。
						while(c!=0)	 //一位一位显示
						{
							k++;
							lcdwrd(0x30+c%10);//显示结果的最后一位在0x4f的位置
							c=c/10;//取前面的结果数据
							if(k==3)
							{
								lcdwrd(0x2e);
								k=0;
							}		
						}
						if(a/b<0)	  //如果a比b小的话那么除的结果最高位是0
						{
							lcdwrd(0x30);	
						}
						lcdwrd(0x3d); //显示等号
						a=0;
						b=0;
						flag=0;
						fuhao=0;//全部清除为0
					}
					break;

		}
	}

}



void main()
{
	lcdinit();
	while(1)
	{
		keyscan();	
	}
}

三十、孵化环境温湿度监控系统设计

1. 最初版本

#include<reg52.h>
#include "intrins.h"
typedef unsigned char uint8;
typedef unsigned int uint16;
sbit rs=P2^6;	 // 数据命令选择
sbit rw=P2^5;	 //读写选择
sbit e=P2^7;	  //使能

sbit k1=P3^3; //模式
sbit k2=P2^1; //加
sbit k3=P2^2; //减

sbit DHT11_DQ_OUT=P3^2;
sbit led1=P3^6;
sbit led2=P3^7;

sbit dq=P2^0;

uint8 mode=0,xian;
char temph=50,templ=20;
char humih=80,humil=20;
uint8 temp,humi;
uint8 flag;	  //设定报警标志
uint8 a,c,tempvalue;
uint8 code num[10]="0123456789";

uint8 code str1[]="Temp:";  //温度
uint8 code str2[]="Humi:";  //湿度
uint8 code str3[]="Error";  
uint8 code str4[]="Success    "; 
uint8 code str5[]="%RH";
uint8 code str6[]="TempH:";	  //设定温度上限显示
uint8 code str7[]="TempL:";	  //设定温度下限显示
uint8 code str8[]="HumiH:";	   //设定湿度上限显示
uint8 code str9[]="HumiL:";	   //设定湿度下限显示


void delay(uint16 i)
{
	while(i--);
}

void delay_ms(uint16 i)
{
	while(i--)
		delay(90);
}

void wrc(uint8 c)	 //写命令
{
	delay(1000);
	rs=0;
	rw=0;
	e=0;
	P0=c;
	e=1;
	delay(10);
	e=0;
}
void wrd(uint8 dat)	  //写数据
{
	delay(1000);
	rs=1;
	rw=0;
	e=0;
	P0=dat;
	e=1;
	delay(10);
	e=0;
	rs=0;
}
void lcd_init()	   // LCD1602初始化
{
	delay(1000);
	wrc(0x38);
	wrc(0x38);	 //功能设置命令,选择8位总线,双行显示  5*7点阵字符
	wrc(0x38);
	wrc(0x06);	//光标和显示模式设置  光标右移  整屏不移动
	wrc(0x0c);	//显示开关控制  开显示  无光标 光标不闪烁
	wrc(0x01);	//清零指令  固定的
}
//复位DHT11
void DHT11_Rst()	   
{                 
    DHT11_DQ_OUT=0; 	//拉低DQ
    delay_ms(20);    	//拉低至少18ms
    DHT11_DQ_OUT=1; 	//DQ=1 
	delay(3);     	//主机拉高20~40us
}

//等待DHT11的回应
//返回1:未检测到DHT11的存在
//返回0:存在
uint8 DHT11_Check() 	   
{   
	uint8 retry=0;	 
    while (DHT11_DQ_OUT&&retry<100)//DHT11会拉低40~50us
	{
		retry++;
		_nop_();
	};	 
	if(retry>=100)return 1;
	else retry=0;
    while (!DHT11_DQ_OUT&&retry<100)//DHT11拉低后会再次拉高40~50us
	{
		retry++;
		_nop_();
	};
	if(retry>=100)return 1;	    
	return 0;
}


//DHT11初始化 
//返回0:初始化成功,1:失败
uint8 DHT11_Init()
{
	DHT11_Rst();	  
	return DHT11_Check();	
}


//从DHT11读取一个位
//返回值:1/0
uint8 DHT11_Read_Bit(void) 			 
{
 	uint8 retry=0;
	while(DHT11_DQ_OUT&&retry<100)//等待变为低电平 12-14us 开始
	{
		retry++;
		_nop_();
	}
	retry=0;
	while((!DHT11_DQ_OUT)&&retry<100)//等待变高电平	 26-28us表示0,116-118us表示1
	{
		retry++;
		_nop_();
	}
	delay(1);//等待40us
	if(DHT11_DQ_OUT)return 1;
	else return 0;		   
}

//从DHT11读取一个字节
//返回值:读到的数据
uint8 DHT11_Read_Byte(void)    
{        
    uint8 i,dat=0;
	for (i=0;i<8;i++) 
	{
   		dat<<=1; 
	    dat|=DHT11_Read_Bit();
    }						    
    return dat;
}

//从DHT11读取一次数据
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
uint8 DHT11_Read_Data(uint8 *temp,uint8 *humi)    
{        
 	uint8 buf[5];
	uint8 i;
	DHT11_Rst();
	if(DHT11_Check()==0)
	{
		for(i=0;i<5;i++)//读取40位数据
		{
			buf[i]=DHT11_Read_Byte();
		}
		if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
		{
			*humi=buf[0];
			*temp=buf[2];
		}
		
	}else return 1;
	return 0;	    
}




void ds18b20init()		//18b20的初始化
{
	dq=1;
	delay(1);
	dq=0;
	delay(80);
	dq=1;
	delay(5);
	dq=0;
	delay(20);
	dq=1;
	delay(35);
}
void ds18b20wr(uint8 dat)	  //18b20写数据
{
	uint8 i;
	for(i=0;i<8;i++)
	{
		dq=0;
		dq=dat&0x01;
		dat>>=1;
		delay(8);//在时序上只有这一块对时序要求最准确,他的时间必须大于15us
		dq=1;
		delay(1);
	}	
}
uint8 ds18b20rd()		  //18b20读数据
{
	uint8 value,i;
	for(i=0;i<8;i++)	
	{
		dq=0;
		value>>=1;
		dq=1;
		if(dq==1)value|=0x80;
		delay(8);//在这一块也对时间要求特别准确,整段程序必须大于60us		
	}
	return value;
}
uint8 readtemp()			  //读取温度内需要复位的
{
	uint8 b;
	ds18b20init();		//初始化
	ds18b20wr(0xcc);   //发送忽略ROM指令
	ds18b20wr(0x44);   //发送温度转换指令
	delay(100);
	ds18b20init();	   //初始化
	ds18b20wr(0xcc);   //发送忽略ROM指令
	ds18b20wr(0xbe);   //发读暂存器指令
	a=ds18b20rd();	 //温度的低八位
	b=ds18b20rd();	 //温度的高八位
	b<<=4;			 //ssss s***;s为标志位s=0表示温度值为正数,s=1温度值为负数
	c=b&0x80;		//温度正负标志位确认
	b+=(a&0xf0)>>4;
	a=a&0x0f;	  //温度的小数部分
	return b;
}


void key_pros()  //按键处理函数
{
	if(k1==0)
	{
		delay(1000);
		if(k1==0)
		{
			mode++;
			if(mode==5)mode=0;
			wrc(0x01);
		}
		while(!k1);
	}
	if(mode==1)		  //对温度上限设定
	{
		if(k2==0)		  //加
		{
			delay(1000);
			if(k2==0)
			{
				temph++;
				if(temph>=80)temph=80;
			}
			while(!k2);
		}
		if(k3==0)	   //减
		{
			delay(1000);
			if(k3==0)
			{
				temph--;
				if(temph<=0)temph=0;
			}
			while(!k3);
		}
	}
	if(mode==2)		  //对温度下限设定
	{
		if(k2==0)		  //加
		{
			delay(1000);
			if(k2==0)
			{
				templ++;
				if(templ>=80)templ=80;
			}
			while(!k2);
		}
		if(k3==0)	   //减
		{
			delay(1000);
			if(k3==0)
			{
				templ--;
				if(templ<=0)templ=0;
			}
			while(!k3);
		}
	}
	if(mode==3)		  //对湿度上限设定
	{
		if(k2==0)		  //加
		{
			delay(1000);
			if(k2==0)
			{
				humih++;
				if(humih>=80)humih=80;
			}
			while(!k2);
		}
		if(k3==0)	   //减
		{
			delay(1000);
			if(k3==0)
			{
				humih--;
				if(humih<=0)humih=0;
			}
			while(!k3);
		}
	}
	if(mode==4)		  //对湿度下限设定
	{
		if(k2==0)		  //加
		{
			delay(1000);
			if(k2==0)
			{
				humil++;
				if(humil>=80)humil=80;
			}
			while(!k2);
		}
		if(k3==0)	   //减
		{
			delay(1000);
			if(k3==0)
			{
				humil--;
				if(humil<=0)humil=0;
			}
			while(!k3);
		}
	}
}

void lcd_init_display()	   //LCD初始化显示
{
	uint8 i;
	for(i=0;i<5;i++)
	{
		wrc(0x80+i);
		wrd(str1[i]);	
	}

	for(i=0;i<5;i++)
	{
		wrc(0xc0+i);
		wrd(str2[i]);	
	}
}

void data_pros()	//数据处理函数
{
	uint8 i;  	    
	uint8 temp_buf[2],humi_buf[2];
	uint8 temphbuf[2],templbuf[2],humihbuf[2],humilbuf[2];
	float dio;
	uint16 k;

	tempvalue=readtemp();
	DHT11_Read_Data(&temp,&humi);
	temp_buf[0]=temp/10+0x30;	
	temp_buf[1]=temp%10+0x30;

	humi_buf[0]=humi/10+0x30;	
	humi_buf[1]=humi%10+0x30;
	
	dio=a*0.0625;
	k=dio*10000;//取小数点后两位有效数字

	temphbuf[0]=temph/10+0x30;
	temphbuf[1]=temph%10+0x30;
	templbuf[0]=templ/10+0x30;
	templbuf[1]=templ%10+0x30;

	humihbuf[0]=humih/10+0x30;
	humihbuf[1]=humih%10+0x30;
	humilbuf[0]=humil/10+0x30;
	humilbuf[1]=humil%10+0x30;

	if(mode==0)
	{
		lcd_init_display();
		wrc(0x85);
		wrd(num[tempvalue%100/10]);
		wrd(num[tempvalue%100%10]);
		wrd('.');
		wrd(num[k/1000]);
		wrd(0xdf);
		wrd('C');
	
		for(i=0;i<2;i++)
		{
			wrc(0Xc5+i);
			wrd(humi_buf[i]);		  
		}	
		for(i=0;i<3;i++)
		{
			wrc(0Xc7+i);
			wrd(str5[i]);		  
		}	
	}
	if(mode==1)			  //温度上限显示
	{
		wrc(0x80);
		for(i=0;i<6;i++)
		{
			wrd(str6[i]);		  
		}
		wrd(temphbuf[0]);
		wrd(temphbuf[1]);			
	}
	if(mode==2)			  //温度下限显示
	{
		wrc(0x80);
		for(i=0;i<6;i++)
		{
			wrd(str7[i]);		  
		}
		wrd(templbuf[0]);
		wrd(templbuf[1]);			
	}
	if(mode==3)			  //湿度上限显示
	{
		wrc(0x80);
		for(i=0;i<6;i++)
		{
			wrd(str8[i]);		  
		}
		wrd(humihbuf[0]);
		wrd(humihbuf[1]);			
	}
	if(mode==4)			  //湿度下限显示
	{
		wrc(0x80);
		for(i=0;i<6;i++)
		{
			wrd(str9[i]);		  
		}
		wrd(humilbuf[0]);
		wrd(humilbuf[1]);			
	}
}

void baojinpros()	//报警处理
{
	if(tempvalue>=temph||humi>=humih)	 //检测温度或者湿度高于设定上限值 降温湿
	{
		led1=1;		//降温湿指示灯
		led2=0;
	}
	if(tempvalue<=templ||humi<=humil)	//检测温度或者湿度低于设定下限值  升温湿
	{
		led1=0;
		led2=1;	   //升高温湿指示灯
	}
	if((tempvalue>templ&&tempvalue<temph)&&(humi>humil&&humi<humih))
	{
		led1=0;
		led2=0;	
	}
}

void main()
{
	uint8 i=0;
	led1=0;
	led2=0;
	lcd_init();
	while(DHT11_Init())	//检测DHT11是否存在
	{
		for(i=0;i<5;i++)
		{
			wrc(0x80+i);
			wrd(str3[i]);	
		}			
	}
	wrc(0x01);
	lcd_init_display();	   //LCD初始化显示
	i=0;
	while(1)
	{	
		i++;
		key_pros();
		baojinpros();	//报警处理
		if(i==15)
		{
			i=0;
			data_pros();  	 //读取一次DHT11数据最少要大于100ms
		}
		delay(1000); 
		
	}	
}

  • 10
    点赞
  • 98
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值