51单片机详解

2年前博客15362
51单片机详解 置顶 No Iverson 已于2022-08-12 20:29:33修改 6163 收藏 158 分类专栏: 51单片机 文章标签: 51单片机 于2022-06-26 21:19:53首次发布 51单片机 专栏收录该内容 1 篇文章 3 订阅 订阅专栏 前言

这是我对这几个月学习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&震动传感器触发继电器点亮Led5.433接发模块&Relay做一个简易的报警器6.定时器详解7.中断详解8.利用舵机&超声波通过中断&定时器做一个自动垃圾桶9.UART串口详解10.利用串口发一个字符到上位机11.通过发送发送字符串到上位机12.通过串口用HC-05蓝牙模块,手机连接蓝牙点亮一个LED13.通过esp8266WI-FI模块通过上位机点亮一个LED14.通过4GI模块通 过上位机点亮一个LED15.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(); } } }

 

 总结

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

相关文章

随机森林算法(Random Forest)Python实现

随机森林算法(Random Forest)Python实现...

[2022-10 持续更新] 谷歌google镜像/Sci-Hub可用网址/Github镜像可用网址总结

[2022-10 持续更新] 谷歌google镜像/Sci-Hub可用网址/Github镜像可用网址总结...

【毕业季】这四年一路走来都很值得——老学长の忠告

【毕业季】这四年一路走来都很值得——老学长の忠告...

Python中的层次聚类,详细讲解

Python中的层次聚类,详细讲解...

七大排序算法(插排,希尔,选择排序,堆排,冒泡,快排,归并)--图文详解

七大排序算法(插排,希尔,选择排序,堆排,冒泡,快排,归并)--图文详解...

【C++】vector类模拟实现

【C++】vector类模拟实现...