51单片机详解

前言

这是我对这几个月学习51单片机的一些汇总,谈谈对51的一些看法,51大致就是对定时器,计算器,中断,串口的一些操作,前面我浅谈一下51的基本操作,后面我会对Sg-90舵机,超声波,LCD1602,DHT11温湿度传感器,IIC-OLED,HC-05蓝牙模块,esp8266-01sWI-FI模块,4G模块,4驱小车进行一个详细的汇总,希望能对大家有所帮助。

文章目录

  • 前言
  • 一、单片机入门
  • 1.什么是单片机
  • 2.单片机工作的基本时序
  • 3.数字电路基础
  • 4.二进制逻辑运算
  • 6.89C52的引脚图
  • 二、单片机的一些项目
    • 1.点亮一个LED&按键点亮
    • 2.LED循环点亮
    • 3.震动传感器介绍
    • 4.震动传感器点亮Led&震动传感器触发继电器点亮Led
    • 5.433接发模块&Relay做一个简易的报警器
    • 6.定时器详解
    • 7.中断详解
    • 8.利用舵机&超声波通过中断&定时器做一个自动垃圾桶
    • 9.UART串口详解
    • 10.利用串口发一个字符到上位机
    • 11.通过发送发送字符串到上位机
    • 12.通过串口用HC-05蓝牙模块,手机连接蓝牙点亮一个LED
    • 13.通过esp8266WI-FI模块通过上位机点亮一个LED
    • 14.通过4GI模块通 过上位机点亮一个LED
    • 15.Lcd1602详解
    • 16.DTH11温湿度详解
    • 17.IIC_OLED详解
    • 18.四驱小车
  • 总结

一、单片机入门

1.什么是单片机

单片机是一种集成电路芯片,采用超大规模集成技术把具有处理数据能力的中央处理器CPU、随机存储器ROM、只读存储器RAM、定时器/计算器、中断系统和IO口等功能集成到一块硅片上构成的一个小型计算机,从当时的4为、8位发展到现在的300M的高速单片机。

2.单片机工作的基本时序

我们都知道在学校是通过铃声来控制所有班级的上下课时间,我们都知道单片机执行指令的过程就是从ROM取出一条指令执行来完成它在各个地方的作用,那它什么时候取指令这个是顺序呢?这里引入一个时序的周期,每访问一次ROM的时间,就是一个机器周期的时间

1个机器周期 = 6个状态周期 = 12个时钟(振荡)周期  

时钟周期:即单片机的基本时间单位,若晶体的频率=12MHZ,那时钟周期 = 1/12MHZ,一个时钟周期 = 1/12MHZ = 1/12000 000每秒

机器周期:即12x1/12 000 000 =0.000001s = 1us,访问一次ROM取指令的时间就是1us

3.数字电路基础 

电平特性

数字电路中只有两种电平:高电平和低电平

高电平:5v或者3.3v,取决与单片机电源

低电平:0V

RS232电平:计算机串口的电平

高电平:-12v

低电平:+12v

我们跟电脑通信的时候,要通过元器件将单片机的电平转换成电脑能识别的电平,才能跟电脑进行通信。

4.二进制逻辑运算

"与"运算

有0得0,全1才1

1&1 = 1,1&0 = 0; 0&0 = 0;

"或"运算

有1得1,全0才0;

1|1 = 1;1|0 = 1;0|0 = 0;

"非"运算

~1 = 0;~0 = 1;

6.89C52的引脚

 二、单片机的一些项目

1.点亮一个LED&按键点亮

通过sbit访问单片机P2^0口,给它一个低电平,使它点亮

#include <REGX52.h>

sbit led = P2^0;//sbit作用是定义特殊功能寄存器的位变量 此时变量led就保存了p2^0的地址

void main()
{

		led = 0;//通过看原理图,这个io口的led是低电平触发


}

通过单片机自带的按键使它点亮

#include <REGX52.h>

sbit led = P2^0;

sbit key_open  = P3^1;
sbit key_close = P3^2;

void main()
{
	
	led = 1;//先默认让led关

		while(1)
		{
				if(key_open == 0)//当按下key_open它会的到一个低电平
				{
					led = 0;//按下按键我打开led
				}
				
				if(key_close == 0)//按下key_close,就关闭led
				{
					led = 1;
				}
		}




}

 这里是通过按键开关来控制点亮了led的

2.LED循环点亮

#include <REGX52.h>
#include <intrins.h>

void main()
{
	
	P2 = 0xfe;//因为led是低电平点亮 0xfe = 1111 1110,我们先让第0位点亮
	
	while(1)
	{
			
			
			Delay1000ms();
	  	P2 = P2 << 1;//然后依次左移一位就= 1111 1101,让第1位点亮,后面依次操作
									//循环到第7位 = 是0111 1111 但是之前每循环左移都给了低电平
		if(P2 == 0x00)//所以当 = 0111 1111 的时候重新给它赋值位0xfe
		{
				
	    P2 = 0xfe;
		}

	}


}

void Delay1000ms()		//延迟函数
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 154;
	k = 122;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

3.震动传感器介绍

 通过震动点亮led

#include <REGX52.h>
#include <intrins.h>

sbit shake = P0^0;
sbit led   = P2^0;

void main()
{
	led = 1;
	
	while(1)
	{
		if(shake == 0)//当发生震动 就点亮led
		{
			led = 0;
		}
		
	}
	


}

4.震动传感器点亮Led&震动传感器触发继电器点亮Led

通过震动让继电器把接在继电器上的灯点亮

#include <REGX52.h>
#include <intrins.h>

sbit shake = P0^0;
sbit relay = P0^1;

void main()
{
	
	while(1)
	{
		if(shake == 0)//当发生震动打开继电器
		{
			relay = 0;
			
		}
		
	}
	
}

5.433接发模块&Relay做一个简易的报警器

通过433收发模块按下打开继电器让报警器响,在按一下让它停止响,当然你也可以在配一个震动传感器,如果发生震动就响,在按一下就停止响。

#include <REGX52.h>
#include <intrins.h>

sbit d0 = P0^0;
sbit d1 = P0^1;
sbit relay = P0^7;

void main()
{
	
	while(1)
	{
		if(d0 == 1)
		{
			relay = 0;
		}
		
		if(d1 == 1)
		{
			relay = 1;
		}
	}
	

}

 6.定时器详解

51单片机有两组定时器,一组是T0,一组是T1,因为几个定时/计数,所以称为定时器。定时器的本质就是每过一个机器周期加1

定时器一共有4个模式

GATE =1,要用软件使TR0/TR1置1,才能开始工作,同时外部中断INT0/1为高电平,才能启动定时器 

C/T = 0是定时模式,=1是计数模式

#include <REGX52.h>
#include <intrins.h>

sbit led = P2^0;


void Delay1000ms()		//延迟函数
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 154;
	k = 122;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Time_Init()
{
	TMOD = 0x01;
	TL0 = 0x20;		//设置定时初值1ms,定时器初值=(2的16次方(因为我选的模式1)—x)x12/你单片机晶振的频率 = 你要设的初值(us)求出的x转换成16 进制就行了
	TH0 = 0xD1;
	TR0  = 1;
	TF0  = 0; 


}


void main()
{
	int num = 0;
	Time_Init();

	
	led = 1;//默认led为关的状态
	
	while(1)
	{
	   if(TF0 == 1)//定时好了溢出
  	{
       
	  	  ++num;//每溢出一次加1
		
				TL0 = 0x20;		//设置定时初值
				TH0 = 0xD1; 		
	 }
	 
	 if(num == 1000)//加到1000 也就是1s 打开led
			{
				led = !led;
				
			}
	 

}
	
	

}

7.中断详解

比如:你正在喝奶茶,此时发生了一个紧急事情,你就会先暂停喝奶茶,转而取处理这个紧急事情,等紧急事情处理完了,你就可以继续和奶茶了。我们把这种紧急事情叫做中断。但是如果你喝奶茶期间发生了许多事情,那就要按照紧急事情的优先级来处理。

#include <REGX51.H>

sbit led = P2^0;

int cnt = 0;

void Time_Init()
{
	TMOD = 0x10;
	TL1 = 0x18;		//设置定时初值
	TH1 = 0xFC;
	TR1 = 1;
	TF1 = 0;//现在还没有溢出,先让他=0
	ET1 = 1;//用的T1就必须用T1中断通道
	EA = 1;
	


}



void main()
{
	Time_Init();
	led = 1;
	
	while(1);
	
}

void zd() interrupt 3
{
	TL1 = 0x18;		
	TH1 = 0xFC;
	
	cnt++;
	
	if(cnt == 500)
	{
		cnt = 0;
		led =!led;
	}
}

8.利用舵机&超声波通过中断&定时器做一个自动垃圾桶

超声波测距

#include <regx52.h>

sbit trig = P0^1;//发送超声波,要发送超声波,必须给trig一个10us以上的高电平
sbit echo = P0^0;//判断超声波什么时候发送和什么时候接收
sbit led  = P2^0; 

void Delay10us()		//@11.0592MHz
{
	unsigned char i;

	i = 2;
	while (--i);
}


void trig10us()
{
	trig = 0;
	trig = 1;
	Delay10us();
	trig = 0;
	
}

void Time1_Init()
{
    TMOD = 0x10;//choose 16bit 计数
    TL1 = 0;
    TH1 = 0;
}


void main()
{
    double time;
    double dis;
    Time1_Init();

    while(1)
    {

        trig10us();
        while(echo == 0);//判断超声波说明时候发送
        TR1 = 1;//开始定时
        while(echo == 1);//判断超声波什么时候返回
        TR1 = 0;//停止计时
        time = (TH1 *256 + TL1)*1;//TL1和TH1是所计的数,1是机器周期1us,time就是超声波去的时间和返回的时间
        dis = (time/2)*0.034;//因为time存放的是去和返回的时间,所以要除以2,超声波测距是340m/s换算成 34000cm/s = 34cm/ms = 0.034cm/us
        if(dis < 10)
        {
            led = 0;//open led
        }        
        else
        {
            led = 1;
        }

        TH1 = 0;
        TL1 = 0;
    }    

}

舵机 

/*
    控制舵机是通过占空比来控制的,也就是在单位时间内,你控制让它得到多少高电平
    sg90舵机最高频率是50Mhz 周期就是0.02s = 20ms,我们字舵机20ms这个周期内给它高电平控制舵机角度

     0° = 0.5ms
    45° = 1ms
    90° = 1.5ms
    135°= 2ms
    180°= 2.5ms 	

*/
#include <regx52.h>
#include <intrins.h>

sbit sg90 = P0^7;

int jd;//用于控制舵机角度
int cnt;//用于计数来判断定时器中断溢出

void Time0_Init()
{
    TMOD = 0x01;
  	TL0 = 0x33;	//定时器第八位初始化
	  TH0 = 0xFE;//定时器高八位初始化 设置定时0,5ms
    TR0 = 1;
    TF0 = 0;
    ET0 = 1;
    EA  = 1;
    
}

void Delay1000ms()		//延迟函数
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void main()
{
    Time0_Init();
    jd = 1;
		cnt = 0;
    
    while(1)
    {
        jd = 5;
				cnt = 0;
        Delay1000ms();
        jd = 1;
				cnt = 0;
        Delay1000ms();

    }

}

void zd() interrupt 1
{
	  TL0 = 0x33;	
	  TH0 = 0xFE;
    cnt++;

    if(cnt <= jd)
    {
        sg90 = 1;
    }
    
    else
    {
        sg90 = 0;
    }

    if(cnt == 40)
    {
        cnt = 0;
    }
}

垃圾桶

#include <regx52.h>
#include <intrins.h>

sbit led = P2^0;
sbit trig = P0^1; //超声波发送 给trig至少10us高电平
sbit echo = P0^0;//怎么知道他开始发和接受的返回波
sbit dj = P0^7;
sbit key = P3^1;
int cnt = 0;
int jd;

void Time0_Init()
{
	TMOD &= 0xF0;                                    
  TMOD |= 0x01;                                            
	TL0 = 0x33;	//定时器第八位初始化
	TH0 = 0xFE;//定时器高八位初始化 设置定时0,5ms
	TR0 = 1;//开始定时
	TF0 = 0;//定时器溢出标志位
	EA = 1;//中断允许总开关
	ET0 = 1;//T0中断允许开关



}

void Delay2500ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 18;
	j = 131;
	k = 103;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Delay10us()		//给trig一个10us延时
{
	unsigned char i;

	i = 2;
	while (--i);
}

void Time1_Init()//初始化定时器
{
	TMOD = 0x10;
	TH1 = 0;//从0开始定时
	TL1 = 0;

}

void trig10()//给trig一个10us高电平
{
	trig = 0;
	trig = 1;//向外发送
	Delay10us();
	trig = 0;//恢复
	
}

double Read_Csb()
{
	double dis;
	double time;
	
		TH1 = 0;//从0开始定时
	  TL1 = 0;
		
		trig10();//发送一个信号
		while(echo == 0);//通过echo从高电平跳转到低电平知道已经开始发送信号了
		TR1 = 1;//信号发送开始定时
		while(echo == 1);//通过从低电平跳转到高电平知道波回来了
		TR1 = 0;//波回来了结束定时
		time=(TH1 * 256 + TL1)*1;//us为单位  计算中间进过的时间 记得数TH0和TL0相加 就是TH0左移8位 移1位 = 2;8位 = 256 ;*1.085一个机器周期
		dis = time / 2* 0.034;//距离 = 340m/s = 34000cm/s = 34cm/ms = 0.034cm/us 时间来回两次 / 2
		
	
	return dis;

}

void main()
{
	double dis;
	Time1_Init();//初始化定时器
  Time0_Init();
	jd  = 1;
	cnt = 0;
	led = 1;
	
	while(1)
	{
		dis = Read_Csb();
		
		if(dis < 10 || key == 0)
		{
			led = 0;
			jd = 5;
			Delay2500ms();
			
			
			
		}
		else
		{
			led = 1;
			jd = 1;
		}

	
	
	}
	
}	

void zd() interrupt 1 //控制脉冲
{
	cnt++;
	
	TL0 = 0x33;		
	TH0 = 0xFE;
	
	if(cnt <= jd)
	{
		dj = 1;
	}
	else
	{
		dj = 0;
	}
	if(cnt == 40)
	{
		cnt = 0;
		
	}
	


}

9.UART串口详解

串口通信

1.单工   只有一根线,只能单向传输
2.半双工 有两根线Tx、Rx,交叉连接,但是任何时候只有一个方向传输和接收
3.全双工 有两根线可以在两个方向上传输

同步和异步通信

1.同步通信 发送数据和,等待接收方回应了,才能继续发送下个数据
同步通信 必须保持双方在同一个时钟
2.异步通信 发送数据后,不等待接收方的回应,继续发送下个数据
异步通信 因为发送效率低,所以每发送一个字符,要加开始位和停止位,还要配置波特率

10.发送一个字符到上位机

#include <REGX51.H>
#include <intrins.h>

void UART_Init()
{
    PCON = 0x00;//波特率不翻倍
	SCON = 0x50;//sm0 sm1 sm2 ren rb8 tb8 ti ri 每发送一个数据ti必须复位 每接收一个数据ri必须复位 ren = 1允许接收
	TMOD = 0x20;//波特率配置 方式1 9600 =(2smod/32)*t1的溢出率
	TH1  = 0XFD;//t1溢出率 = (频率/32)*(256 -TH1)
	TL1  = 0xFD;
	TR1 = 1;//打开定时器1
	
}

void Delay10000ms()		//@11.0592MHz
{
	unsigned char i, j, k;

	_nop_();
	i = 71;
	j = 10;
	k = 171;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void main()
{

	UART_Init();
	
	while(1)
	{
		Delay10000ms();
		SBUF = 'a';//每个一秒发送一个字符
	}
}

11.发送一个字符串到上位机

#include <REGX51.H>
#include <intrins.h>

void UART_Init()
{
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0XFD;
	TL1  = 0xFD;
	TR1= 1;

	
}


void Send_Bit(char Data)
{
	SBUF = Data;
	while(!TI);
	TI = 0;

}

void Send_String(char * p)
{
	
	while(*p != '\0')
	{
		
		Send_Bit(*p);
		p++;
	}

}

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()
{
	UART_Init();

	while(1)
	{
		Delay1000ms();
		Send_String("iverson");
	}

	
}

12.通过串口用HC-05蓝牙模块,手机连接蓝牙点亮一个LED 

#include <REGX51.H>
#include <intrins.h>

sbit led =P2^0;

void UART_Init()
{
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0XFD;
	TL1  = 0xFD;
	TR1  = 1;
	ES   = 1;
  EA	 = 1;
	
}

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()
{


	UART_Init();
	
	while(1)
	{
		Delay1000ms();
		SBUF = 'a';
	}
}


void zd() interrupt 4//串口中断
{

	
	if(RI == 1)
	{
		RI = 0;
		
		if(SBUF == 'o')
		{
			led = 0;
		}
		if(SBUF == 'c')
		{
			led = 1;
		}
	}
		

}

 13.通过esp8266WI-FI模块通过上位机点亮一个LED

/*
				就是在同一个局域网 服务器先连接WiFi 获得WiFiIP esp826601s在通过WIFIIP连接服务器  
				单片机通过串口发送数据给esp826601s esp826601s接受该AT数据连接 WIFI 和 服务器等
				就开始实现数据传输 

				AT+CWMODE=3 //1. 是station(设备)模式 2.是AP(路由)模式 3.是双模
				OK

				AT+CWJAP="TP-LINK_3E30","18650711783" //指令
				WIFI CONNECTED //结果
				WIFI GOT IP //结果
				
				AT+CIFSR //指令
				+CIFSR:APIP,"192.168.4.1"         当esp826601s做路由的IP
				+CIFSR:APMAC,"4e:75:25:0d:ae:2f"
				+CIFSR:STAIP,"192.168.0.148"
				+CIFSR:STAMAC,"4c:75:25:0d:ae:2f"
				OK
				
				AT+CIPSTART="TCP","192.168.0.113",8888 //指令,注意双引号逗号都要半角(英文)输入
				CONNECT //结果:成功
				OK //结果:成功

				AT+CIPSEND=4 // 设置即将发送数据的长度 (这里是4个字节)
				>CLCA // 看到大于号后,输入消息,CLCA,不要带回车
				Response :SEND OK //结果:成功
				//注意,这种情况下,每次发送前都要先发送AT+CIPSEND=长度 的指令,再发数据!

				AT+CIPMODE=1 //开启透传模式
				Response :OK
				+++退出透传模式

				AT+CIPSEND //带回车
				Response: > //这个时候随意发送接收数据咯


*/

#include <regx52.h>
#include <intrins.h>
#include <string.h>
#define SIZE 12

sbit Led = P2^0;
sbit Led1= P2^7; 

code char LJWL []="AT+CWJAP=\"iPhone\",\"00000000\"\r\n";
code char LJFWQ[]="AT+CIPSTART=\"TCP\",\"169.254.165.190\",8880\r\n";
char TC  []="AT+CIPMODE=1\r\n";
char SJFS[]="AT+CIPSEND\r\n";

char buffer[SIZE];

void Delay7000ms()		
{
	unsigned char i, j, k;

	_nop_();
	i = 50;
	j = 7;
	k = 195;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}

void Delay1000ms()		
{
	unsigned char i, j, k;

	_nop_();
	i = 8;
	j = 1;
	k = 243;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void Uart()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
	TL1  = 0xFD;
	TR1  = 1;
	ES   = 1;
	EA   = 1;
}

void SendByt(char Js)
{
	SBUF = Js;
	while(! TI );
	TI = 0;
}

void SendString(char * p)
{
	while(*p != '\0')
	{
		SendByt(*p);
		p++;
	}
}

void main()
{
	Led = 1;
	
	Uart();
	Delay1000ms();
	
	SendString(LJWL);
	Delay7000ms();
	
	SendString(LJFWQ);
	Delay7000ms();
	
	SendString(TC);
	Delay1000ms();

	SendString(SJFS);
	Delay1000ms();	
	
	Led = 0;
	
	while(1)
	{
		SendString("666\r\n");
	}
	
}

void Zd() interrupt 4
{
	unsigned char cmd; 
	static int i = 0;
	if(RI == 1)
	{
		RI = 0;
		cmd = SBUF;
		
		if(cmd == 'o' ||cmd == 'c')
		{
			i = 0;
		}
		buffer[i++] = cmd;
		if(buffer[0] == 'o'&&buffer[3]=='n')
		{
			Led1 = 0;
			memset(buffer, '\0', SIZE);

		}
		
		if(buffer[0] == 'c'&& buffer[4]=='e')
		{
			Led1 = 1;
			memset(buffer, '\0', SIZE);

		}
		
		if(i == 12)i = 0;
	}
}

14.通过4GI模块通 过上位机点亮一个LED

/*
	
	4G是公网通信不认识:‘局域网’;
	我们可以将内网IP穿透 就是利用花生壳 把内网ip弄成外网可以访问的一个地址端口
	
	我建立个服务器 通过花生壳把IP打造成外网可以访问的IP  通过AT指令先配置好(4G模块是先配置 重启才能使用)
	单片机接受4G发来的数据 如果检索到跟我设置一样的数据就可以进行点灯操作等。。。
	跟蓝牙一样 优点是突破了地域限制
	
	
	1. 打开串口连接4G模块,串口出产默认波特率是115200,可以自行根据用户手册修改
  	2. 进入AT指令模式,在串口助手内发送+++(不要勾选发送新行),必须在发送+++指令 3s 内发送其
     	他任意 AT 指令,比如AT+CPIN 1 检测到sim卡 0 没有检测到
  	3. 观察SIM卡灯是否亮起,AT+ICCID获得SIM卡信息,确认SIM卡安装完好 返回数据:
   	  +OK=89860116838013413419
     	检查信号是否正常,通过AT+CSQ指令检查信号值,建议插入信号天线,返回数据:+OK=31
	4. AT+SOCK=TCPC,103.46.128.21,52541 连接socket服务器,
     	103.46.128.21是公网IP地址,通过花生壳获得,26532是端口号,参数之间逗号隔开
	5.AT+REBT 重启模块。
	6.AT+UART=9600,NONE  none表示没有奇偶校验位 4g默认uart=115200;
	7.AT+LINKSTA 查询 TCP 链接是否已建立链接 返回Connect(TCP 连接)/ Disconnect(TCP 断开)

	
*/

#include <regx52.h>
#include <string.h>


sbit Led = P2^7;



void Uart()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
	TL1  = 0xFD;
	TR1  = 1;
	ES   = 1;
  EA   = 1;	
}

void main()
{
	Led = 1;
	
	Uart();
	while(1);
	
}

void Zd() interrupt 4
{
	 char cmd;

	
	if(RI == 1)
	{
		RI = 0;
		cmd = SBUF;
		
		if(cmd == 'o')
		{
			Led = 0;
		}
		if(cmd == 'c')
		{
			Led = 1;
		}
	}
}

 15.Lcd1602详解

RS 为寄存器选择,高电平时选择数据寄存器、低电平时选择指令寄存器
R/W 为读写信号线,高电平时进行读操作,低电平时进行写操作,当 RS 为低电平 R/W 为高电平时可以读忙信号。

#include <regx52.h>
#include <intrins.h>
#define buffer P0

sbit RS = P2^6;
sbit RW = P2^5;
sbit EN = P2^7;



void Read_Busy()
{
	char flag = 0x80;
	buffer = 0x80;
	
	while(flag & 0x80)
	{
		RS = 0;
		RW = 1;
		EN = 0;
		_nop_();
		
		EN = 1;
		_nop_();
		_nop_();
		
		flag = buffer;
		
		EN = 0;
		_nop_();
		
	}


}

void Write_Cmd(char cmd)
{
	Read_Busy();
	
	RS = 0;
	RW = 0;
	
	EN = 0;
	_nop_();
	
	buffer = cmd;
	_nop_();
	
	EN = 1;
	_nop_();
	_nop_();
	
	EN = 0;
	_nop_();
	


}

void Write_Data(char Data)
{
	Read_Busy();

	
	RW = 0;
	RS = 1;
	EN = 0;
	_nop_();
	
	buffer = Data;
	_nop_();
	
	EN = 1;
	_nop_();
	_nop_();
	
	EN = 0;
	_nop_();
	

}

void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 10;
	j = 183;
	do
	{
		while (--j);
	} while (--i);
}

void Delay15ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 30;
	j = 43;
	do
	{
		while (--j);
	} while (--i);
}



void LCD1602_Init()
{
		//(1)延时 15ms
	Delay15ms();
	//(2)写指令 38H(不检测忙信号)
	Write_Cmd(0x38);
	//(3)延时 5ms
	Delay5ms();
	//(4)以后每次写指令,读/写数据操作均需要检测忙信号
	//(5)写指令 38H:显示模式设置
	Write_Cmd(0x38);
	//(6)写指令 08H:显示关闭
	Write_Cmd(0x08);
	//(7)写指令 01H:显示清屏
	Write_Cmd(0x01);
	//(8)写指令 06H:显示光标移动设置
  Write_Cmd(0x06);
	//(9)写指令 0CH:显示开及光标设置}
	Write_Cmd(0x0c);


}


void Data_Show(char hang,char lie,char *p)
{
	switch(hang)
	{
		case 1:
			
		  Write_Cmd(0x80 + lie);
			
		  while(*p != '\0')
			{
					Write_Data(*p);
				  p++;
			}
		case 2:
			
		 Write_Cmd(0x80 + 0x40 + lie);
			
			while(*p != '\0')
			{
			     Write_Data(*p);
						p++;
			}
	}

}

void main()
{
	LCD1602_Init();
	
	while(1)
	{
		
		Data_Show(1,6,"NO.1");
		Data_Show(2,4,"iverson!");
		
	}
	//Write_Cmd(0x80);
	//Write_Data('a');
	

}

 16.DTH11温湿度详解

 

#include <regx52.h>
#include <intrins.h>

sbit Led = P2^0;
sbit Dht = P0^0;
char Data[5];

void Uart()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
	TL1  = 0xFD;
	TR1  = 1;
}

void SendByte(char Js)
{
	SBUF = Js;
	while(!TI);
	TI  =  0;
}

void SendString(char *p)
{
	while(*p != '\0')
	{
		SendByte(*p);
		p++;
	}
}

void Delay30us()		
{
	unsigned char i;

	i = 11;
	while (--i);
}

void Delay40us()		
{
	unsigned char i;

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


void Dht_Start()
{
	Dht = 1;
	Dht = 0;
	Delay30us();
	Dht = 1;
	
	while(Dht);
	while(!Dht);
	while(Dht);
	
	
}

void Read_Dht()
{
	int i;
	int j;
	char tmp;
	char flag;
	
	Dht_Start();
	
	for(i = 0;i < 5;++i)
	{
		for(j = 0;j < 8;++j)
		{
			
			
			while(!Dht);
			Delay40us();
			
			if(Dht == 1)
			{
				flag = 1;
				while(Dht);
			}
			else
			{
				flag = 0;
			}
			tmp = tmp << 1;
			tmp = flag | tmp;
			
		}
		Data[i] = tmp;
	}
}


void Delay500ms()		
{
	unsigned char i, j, k;

	_nop_();
	i = 4;
	j = 129;
	k = 119;
	do
	{
		do
		{
			while (--k);
		} while (--j);
	} while (--i);
}


void main()
{
	
	Uart();
	
	while( 1 )
	{
		Delay500ms();
		Read_Dht();
		
		SendString("H:");
		
	  SendByte(Data[0] / 10 +0x30); //0x30 - 0x39 是0 - 9的ascll码 
		SendByte(Data[0] % 10 + 0x30);//这样就可以把对应的字符变成ascll输出
		SendByte('.');
		SendByte(Data[1] / 10 +0x30);
		SendByte(Data[1] % 10 + 0x30);
		SendString("\r\n");
		
		SendString("T:");
		
		SendByte(Data[2] / 10 +0x30);
		SendByte(Data[2] % 10 + 0x30);
		SendByte('.');
		SendByte(Data[3] / 10 +0x30);
		SendByte(Data[3] % 10 + 0x30);
		SendString("\r\n");
	
		
		
	}

	
	

	
}

让dht温湿度数据显示在Lcd1602上面

#include <regx52.h>
#include <intrins.h>
#define buffer P0


/*---------定义LCD1602 & DHT 引脚-----------*/

sbit dht = P0^0;
sbit RS = P2^6;
sbit RW = P2^5;
sbit EN = P2^7;

/*----------wd&sd用于存放温湿度数据---------*/
char Data[5];
char sd[9];
char wd[9];

/*----------读第7位是不是高电平-------------*/
void Read_Busy()
{
	char flag = 0x80;
	buffer = 0x80;
	
	while(flag & 0x80)
	{
		RS = 0;
		RW = 1;
		EN = 0;
		_nop_();
		
		EN = 1;
		_nop_();
		_nop_();
		
		flag = buffer;
		
		EN = 0;
		_nop_();
		
	}


}

void Write_Cmd(char cmd)
{
	Read_Busy();
	
	RS = 0;
	RW = 0;
	
	EN = 0;
	_nop_();
	
	buffer = cmd;
	_nop_();
	
	EN = 1;
	_nop_();
	_nop_();
	
	EN = 0;
	_nop_();
	


}

void Write_Data(char Data)
{
	Read_Busy();

	
	RW = 0;
	RS = 1;
	EN = 0;
	_nop_();
	
	buffer = Data;
	_nop_();
	
	EN = 1;
	_nop_();
	_nop_();
	
	EN = 0;
	_nop_();
	

}

void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 10;
	j = 183;
	do
	{
		while (--j);
	} while (--i);
}

void Delay15ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 30;
	j = 43;
	do
	{
		while (--j);
	} while (--i);
}



void LCD1602_Init()
{
		//(1)延时 15ms
	Delay15ms();
	//(2)写指令 38H(不检测忙信号)
	Write_Cmd(0x38);
	//(3)延时 5ms
	Delay5ms();
	//(4)以后每次写指令,读/写数据操作均需要检测忙信号
	//(5)写指令 38H:显示模式设置
	Write_Cmd(0x38);
	//(6)写指令 08H:显示关闭
	Write_Cmd(0x08);
	//(7)写指令 01H:显示清屏
	Write_Cmd(0x01);
	//(8)写指令 06H:显示光标移动设置
  Write_Cmd(0x06);
	//(9)写指令 0CH:显示开及光标设置}
	Write_Cmd(0x0c);


}


void Data_Show(char hang,char lie,char *p)
{
	switch(hang)
	{
		case 1:
			
		  Write_Cmd(0x80 + lie);
			
		  while(*p != '\0')
			{
					Write_Data(*p);
				  p++;
			}
		case 2:
			
		 Write_Cmd(0x80 + 0x40 + lie);
			
			while(*p != '\0')
			{
			     Write_Data(*p);
						p++;
			}
	}

}

void Uart()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
	TL1  = 0xFD;
	TR1  = 1;
}

void SendByte(char Js)
{
	SBUF = Js;
	while(!TI);
	TI  =  0;
}

void SendString(char *p)
{
	while(*p != '\0')
	{
		SendByte(*p);
		p++;
	}
}


void Delay30us()		
{
	unsigned char i;

	i = 11;
	while (--i);
}

void Delay40us()		
{
	unsigned char i;

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


void Dht_Start()
{
	dht = 1;
	dht = 0;
	Delay30us();
	dht = 1;
	
	while(dht);
	while(!dht);
	while(dht);
	
	
}

void Read_Dht()
{
	int i;
	int j;
	char tmp;
	char flag;
	
	Dht_Start();
	
	for(i = 0;i < 5;++i)
	{
		for(j = 0;j < 8;++j)
		{
			
			
			while(!dht);
			Delay40us();
			
			if(dht == 1)
			{
				flag = 1;
				while(dht);
			}
			else
			{
				flag = 0;
			}
			tmp = tmp << 1;
			tmp = flag | tmp;
			
		}
		Data[i] = tmp;
	}
}


void Put_Data()
{
	sd[0] = 's';
	sd[1] = 'd';
	sd[2] = ':';
	sd[3] = Data[0] /10 + 0x30;
	sd[4] = Data[0] %10 + 0x30;
	sd[5] = '.';
	sd[6] = Data[1] /10 + 0x30;
	sd[7] = Data[1] %10 + 0x30;
	sd[8] = '\0';

  wd[0] = 'w';
	wd[1] = 'd';
	wd[2] = ':';
	wd[3] = Data[2] /10 + 0x30;
	wd[4] = Data[2] %10 + 0x30;
	wd[5] = '.';
	wd[6] = Data[3] /10 + 0x30;
	wd[7] = Data[3] %10 + 0x30;
	wd[8] = '\0';
}


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()
{
	Uart();
	Delay1000ms();
	
	LCD1602_Init();
	
	

	while(1)
	{
		Delay1000ms();
		Read_Dht();
		Put_Data();
		
		Delay1000ms();
		Delay1000ms();

		SendString(wd);
		SendString("\r\n");
		SendString(sd);
		SendString("\r\n");
		
		Data_Show(1,0,wd);
		Data_Show(2,0,sd);

		
		
	}
}

 17.IIC_OLED详解

/*
    代码太多,需要的可以加我qq:2652408527
*/
#include <regx52.h>
#include <intrins.h>
#include "oled.h"
#include "oled_ziku.h"
#include "dht.h"

sbit SDA = P0^0;
sbit SCL = P0^1;
sbit dht = P0^2;

extern char Data[5];
extern char sd[9];
extern char wd[9];



void main()
{
	
	
	Oled_INIT();
	
	Oled_Write_Cmd(0x20);
	Oled_Write_Cmd(0x02);//选择页寻址
	
	Oled_Clear();//清屏
	
	while(1)
	{
	
		Oled_Show_Str(1,0,"Li zhen");
		Oled_Show_Str(2,0,"I LOVE YOU");
		Oled_Show_Str(2,80,"!");
		
		
	}
	
	
}
	

/*
	部分代码,需要的可以加我QQ:2652408527
*/

#include <regx52.h>
#include <intrins.h>
#include "oled.h"
#include "oled_ziku.h"
#include "dht.h"

sbit SDA = P0^0;
sbit SCL = P0^1;
sbit dht = P0^2;

extern char Data[5];
extern char sd[9];
extern char wd[9];
	char command[5];


void UART_Init()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
	TL1  = 0xFD;
	TR1  = 1;
	ES   = 1;
  EA   = 1;	
}


void main()
{
	UART_Init();
	 Delay1000ms();
	Oled_INIT();
	
	Oled_Write_Cmd(0x20);
	Oled_Write_Cmd(0x02);//选择页寻址
	
	Oled_Clear();//清屏
	

	while(1)
	{
		
		
		Read_Dht();
	
	  Put_Data();
		

		
		Oled_Show_Str(4,40,"Li jian hua");
		
		Delay1000ms();
		
	}
	
	
}
	

void zd() interrupt 4
{
	static i = 0;
	

	
	if(RI == 1)
	{
		RI = 0;
		command[i] = SBUF;
		i++;
		
		if(command[0]=='o'&&command[1]=='p'&&command[2]=='e'&&command[3]=='n')
		{
					Oled_Show_Str(1,0,wd);
		      Oled_Show_Str(2,0,sd); 
		}
		
	if(command[0]=='c'&&command[1]=='l'&&command[2]=='o'&&command[3]=='s')
	{
					Oled_Show_Str(1,0,"                                                                 ");
		      Oled_Show_Str(2,0,"                                                                  "); 
		}
		
	}

}

 18.四驱小车

由于没有循迹模块,我直接写了一个可以上下左右的小车代码

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

void UART_Init()
{
	PCON = 0x00;
	SCON = 0x50;
	TMOD = 0x20;
	TH1  = 0xFD;
  TL1  = 0xFD;
  TR1  = 1;
  ES   = 1;
  EA   = 1; 	
}

void zd() interrupt 4
{
	if(RI == 1)
	{
			RI = 0;
			
		 if(SBUF == 'a')
		 {
			 		 Dianji_Left1Ward_Init();
					 Dianji_Left2Ward_Init();
					 Dianji_Right1Ward_Init();
					 Dianji_Right2Ward_Init();
			 
			}
			
			if(SBUF == 'b')
			{
					   Dianji_Left1Back_Init();
						 Dianji_Left2Back_Init();
						 Dianji_Right1Back_Init();
						 Dianji_Right2Back_Init();
			}
			
			if(SBUF == 'e')
			{
				7 Stop();
			}
	}


}

 

 总结

感谢各位的观看,需要其中代码的兄弟可以私聊我。

  • 146
    点赞
  • 1173
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

No Iverson

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值