51单片机P0口作为IO口输出时,输出低电平为0 输出高电平为高组态(并非5V,相当于悬空状态,也就是说P0
口不能真正的输出高电平)。给所接的负载提供电流,因此必须接上拉电阻(一电阻连接到VCC),
这句话是对的,但是当P0口作为总线输出的时候,他是不需要加上拉电阻的,例如图中P0口接的是LCD的数据口,赋值时 P0=DATA;
另一种情况是如果是用STM32来驱动的话,请注意。
还要根据LCD1602是5V还是3.3V来加上拉电阻。此处不细说。
图中的继电器电路我采用的是低电平触发,为什么是低电平触发而不是高电平触发呢?这也是有讲究的。
目前我这个系统想法是上电的时候,指示灯是暗的,当收到开启命令后,继电器“嗒”的一声,灯亮。
重点来了,51单片机上电瞬间IO口是高电平,所以
如果采用高电平触发的话,继电器一上电就吸合了。
三极管的作用是放大电流,因为51单片机的输出电流较小。
单片机程序不难:
DHT11、LCD1602这些驱动程序网上都有
这里我把最主要的ESP8266通信程序
以及串口中断判断程序放出来。
//这里是某些宏定义
#define uchar unsigned char
#define uint unsigned int
volatile uchar Rec_stop = 0; //接收停止位
volatile uchar flag = 0; //连接标志位
volatile uchar RsPoint = 0; //接收字节位
volatile uchar rec_buf[2]; //OK判断位
volatile uchar TX_Flag = 0; //开启发送标志位
volatile uchar RX_Flag = 0; //开启接收标志位
volatile uchar TH_Flag = 0; //温湿度发送标志位
sbit keep_te = P1^6; //定义保温开关接口
sbit keep_hu = P1^5; // 定义保湿开关接口
void wifi_init()
{
//esp8266复位
memset(rec_buf,' ',sizeof(rec_buf));
RsPoint=0;
SendString("AT+RST\r\n");
write_1602com(0x01);
write_string(0x80,"AT+RST",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
delayms_1000ms(14);
//设置sta兼ap模式
memset(rec_buf,' ',sizeof(rec_buf));
RsPoint=0;
SendString("AT+CWMODE=1\r\n");
write_1602com(0x01);
write_string(0x80,"AT+CWMODE=1",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
SendString("\r\n");
delayms_1000ms(4);
//清除回显
memset(rec_buf,' ',sizeof(rec_buf));
RsPoint=0;
SendString("ATE0\r\n");
write_1602com(0x01); //清屏
write_string(0x80,"ATE0",0);
while(Rec_stop==0);
Rec_stop=0;
delayms_1000ms(4);
//连接热点
memset(rec_buf,' ',sizeof(rec_buf));
RsPoint=0;
SendString("AT+CWJAP=\"hhhh\",\"a123456789\"\r\n");
write_1602com(0x01);
write_string(0x80,"Linking AP...",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
delayms_1000ms(18);
//设置单连接
memset(rec_buf,' ',sizeof(rec_buf));
RsPoint=0;
SendString("AT+CIPMUX=0\r\n");
write_1602com(0x01);
write_string(0x80,"AT+CIPMUX=0",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
delayms_1000ms(4);
//开始监听
memset(rec_buf,' ',sizeof(rec_buf));
SendString("AT+CIPSTART=\"TCP\",\"8.129.224.216\",3000\r\n");
//这个就是公网的IP地址以及端口号。
write_1602com(0x01);
write_string(0x80,"AT+CIPSTART",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
delayms_1000ms(4);
//开启透传模式
memset(rec_buf,' ',sizeof(rec_buf));
SendString("AT+CIPMODE=1\r\n");
write_1602com(0x01);
write_string(0x80,"AT+CIPMODE=1",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x45,rec_buf,0);
delayms_1000ms(4);
//开始发送数据
memset(rec_buf,' ',sizeof(rec_buf));
SendString("AT+CIPSEND\r\n");
write_1602com(0x01);
write_string(0x80,"AT+CIPSEND",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0x40,rec_buf,0);
delayms_1000ms(4);
//发送初始化的继电器开关值
memset(rec_buf,' ',sizeof(rec_buf));
SendString("{\"type\":\"kg\",\"wdkg\":\"0\",\"sdkg\":\"0\"}");
write_1602com(0x01);
write_string(0x80,"send_relay",0);
while(Rec_stop==0);
Rec_stop=0;
write_string(0x80+0X40,"OK",0);
delayms_1000ms(4);
write_1602com(0x01);
//发送一段温湿度的数值
memset(rec_buf,' ',sizeof(rec_buf));
SendString("{\"type\":\"wsd\",\"wd\":\"0\",\"sd\":\"0\"}");
write_1602com(0x01);
write_string(0x80,"send_data",0);
}
void Usart() interrupt 4//在中断里面进行两个判断,首先是WiFi响应"OK"的判断,接着是":A" ":B" ":C" ":D"的判断
{
uchar receiveData;
if(RI == 1)
{
receiveData = SBUF;//出去接收到的数据
flag = 1;
RI = 0;//清除接收中断标志位
if(TX_Flag == 1) //进入通信部分 收发信息 做出反应
{
if(receiveData == ':')
{
RX_Flag = 1;
}
else if(RX_Flag == 1)
{
if(receiveData == 'A')
{
SendString("{\"type\":\"kgchanged\"}"); //因为是低电平触发,所以改为0是触发
keep_te=0;
keep_hu=0;
}
if(receiveData == 'B')
{
SendString("{\"type\":\"kgchanged\"}");
keep_te=0;
keep_hu=1;
}
if(receiveData == 'C')
{
SendString("{\"type\":\"kgchanged\"}");
keep_te=1;
keep_hu=0;
}
if(receiveData == 'D')
{
SendString("{\"type\":\"kgchanged\"}");
keep_te=1;
keep_hu=1;
}
RX_Flag = 0; //自锁
}
}
//上面的判断是来控制保温保湿开关的,下面的判断是用来判断ESP8266指令的OK返回
if((RsPoint==0)&&(receiveData=='O'))
{
rec_buf[RsPoint]=receiveData;
RsPoint++;
}
else if((RsPoint==1)&&(receiveData=='K'))
{
rec_buf[RsPoint]=receiveData;
RsPoint++;
Rec_stop=1;
}
else
{
RsPoint=0;
}
}
}
RsPoint 代码解释。
因为我要判断对方有没有发送OK给我,OK是两个字符,占两个字节,而单片机是一个字节进入一次中断这样。所以接收到O进入中断,保存。接着处理剩下的K,进入下次中断、保存、接着Rec_stop置1,那么ESP8266就可以发送下一个指令了。
假设我收到的是OAK的话,那么Rec_stop也不会置1, 因为当时A的时候,RsPoint就会是0。
所以RsPoint的作用是保证O和K是连在一起的。
这里的重难点是连续字符的判断。
https://www.bilibili.com/video/BV1py4y1Y7tq
发邮件虽然说不是很麻烦,但是多起来就不想发了,所以大家关注我公众号:高精度小数 回复:代码 就可以得到代码了