前言
这是我对这几个月学习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详解

#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();
}
}
}
总结
感谢各位的观看,需要其中代码的兄弟可以私聊我。