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&震动传感器触发继电器点亮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(); } } }
总结
感谢各位的观看,需要其中代码的兄弟可以私聊我。