硬件篇:基于微信小程序的智能分类垃圾桶(详细介绍)

硬件选择

因为我们需要实现的主要功能是控制四个垃圾桶的开合,所以舵机是必不可少的,至于用什么来控制舵机,我直接就选择了51单片机(因为我只学了51),明确了主要的硬件,进一步细化目标,用微信小程序通过云平台发送请求,51这边接收返回数据进行处理后控制舵机。网络这里我直接选用了我稍微了解一点的esp8266wifi模块,云平台经过与写小程序的同学商量决定采用容易上手的乐联网,这样一来,整个作品硬件选用思路就明确了!

硬件清单及部分图片展示

黑体为主要元件,非黑体为供电元件,可自行更换选择!!
DIY专用小垃圾桶
51单片机最小系统板
SG90舵机9g180度四个
ESP8266-12F WiFi模块

面包板+面包板电源模块
聚合物锂电池+LM2596降压模块(用于给舵机单独供电)
DC头12V1.5A电源适配器
公对母、母对母、公对公杜绑线若干
在这里插入图片描述
在这里插入图片描述

硬件连接示意图

注意:根据ESP8266用户手册要求,该模块工作电压为3.3V,同时EN置高点平。
在这里插入图片描述

乐联网设置流程

乐联网注册登录问题就不在这里赘述了,CSDN也有很多优秀的博客可以参考。注册登录后你只需要知道你的Userkey和网关号即可,因为任务中我们是要通过乐联网实现对51单片机的反向控制,所以选用了乐联网的服务器发送数据串给客户端的通信方式,具体流程可以参考乐联网官网给的指南或者下面的截图,应乐联网的要求你必须每隔40s向服务器发送一次登录信息以保证与服务器的正常连接,小程序发出请求后乐联网会返回字符串给客户端,此时客户端需要解析数据选择指定的舵机控制其转动,具体解析方法见程序部分。

{
    
    "method": "update","gatewayNo": "你的网关号","userkey": "你的userkey"}&^!  //登录信息
{
    
    "method":"send","gatewayNo":"你的网关号","userkey":"你的userkey","f":"updateSensor","p1":"约定的控制参数"}&^! //服务器返回的数据

在这里插入图片描述

单片机程序编写

根据此次任务要求,我们需要通过ESP8266WiFi模块与51单片机串口通信控制四路舵机,因为使用51控制四路舵机转动并不难,程序源码中也加了相关注释,对此我不做过多解释。这里我主要介绍51与WiFi模块串口通信、51定时40秒发送登录信息和51解析收到的数据部分。
串口通信时受51串口打印的限制,我们需要自己写打印函数,否则无法使用printf()进行打印,类似的博客在CSDN也有很多可以参考,下面是我的代码:

void sendChar(u8 a) //单片机发送一个字节
{
    
    
        SBUF = a;
        while(TI==0);
        TI=0;        
}
void sendString(u8 *s)   //发送一个字符串
{
    
    
        while(*s!='\0')
        {
    
    
                sendChar(*s);
                s++;
        }        
}

这样一来sendString()就成了我新定义的打印函数用于串口打印字符串。
51定时40秒发送登录信息乐联网要求我们每隔40s发送一次登录信息,这里我用了51的T2定时器精确定时40秒,据我了解我的STC89C52RC是有三个定时器的,可能有一些只有两个,那就难受了啊。。为控制文章篇幅,这里的代码我会在文章末尾统一展示。
服务器返回的字符串的解析,我定义了一个全局变量的数组来存放,寄存器接收后放进数组,根据与小程序方面的约定,我们取!为一个字符串的结束标志,取下标为103的字符来控制舵机的选择。在中断里加了标志位,让舵机选择在主程序中完成以保证中断的正常运行,代码及部分注释:

void Usart() interrupt 4//串口通信中断函数
{
    
    
	if(RI==1) //接收完一帧数据
	{
    
    
		RI=0;//清除接收中断标记位
		dat=SBUF;      //出去接收到的数据   收到的数据放入receivedata[120]用于待解析
		receivedata[k]=dat;
		if(receivedata[k]=='!')  //收到标志位
		{
    
    
			k=0;
			X=receivedata[103];  //X为全局变量,将取得字符赋给他
			flag=1;  //接收完成标记位
		}else{
    
    
			k++;
		}
		}
	}

主程序利用标志位减少在中断里的程序执行代码

void main(void)
{
    
    
	ConfigTimer0();//配置定时器0
	next=0;
	isSend=0;
	time2_init();
	UsartInit();	  //串口初始化
	while(1)
	{
    
    
		if(isSend==0){
    
       //标志位
			led=0;
		}else{
    
    
			led=1;
			isSend=0;
			sendString("{\"method\":\"update\",\"gatewayNo\":\"02\",\"userkey\":\"30e217750d7e48008d8595105a14df2d\"}&^!");    //登录信息
		}
		
		if(flag==0) //标志位
		{
    
    
			led1=0;
		}else{
    
    
			led1=1;
			flag=0;
			sendString("{\"method\":\"response\",\"result\":{\"successful\":true,\"message\":\"Write serial successful 0\"}}&^!");
			dj_control();
			DJ_turn();
			X='4';
			receivedata[103]=0;
		}
		if( dj_select != 0)
			{
    
    
			dj_select = 0;	
			}
   }
}

硬件安装及部分细节

因为材料原因,所有的硬件的连接我都只用了热熔胶固定,需要注意的一点是舵机的固定,我尝试了很多方法后采用的也是热熔胶固定,具体看图。两个LED是为了我能更直观确定数据的收发情况,可以以省略。
在这里插入图片描述

成品展示

更多成品展示参见我的上一篇博文:博文地址!!
在这里插入图片描述

总结反思

回想这次的制作过程可真是太难了,因为51是自学的,所以为了解决定时发送登录信息的问题吃饭都不香了!!数据解析实现控制也颇费了些力气,过程中请教了物联网学长很多问题,也得到了他的很多帮助,在这里还是想再说一句谢谢!最终经过近10天的时间成功实现了预期的效果,虽然没能在比赛中获奖,但这也是我的一次经历,一次提升我的过程。老师和同学的肯定是我继续学习硬件的动力之一。在这里我将我的经历一一记录下来,供小伙伴们参考,希望和你们一起进步。
工程文件自取地址:
链接:https://pan.baidu.com/s/1Hus4Ltfjs3GjgBsKvumlEA
提取码:7m0f
在这里插入图片描述

程序源码展示

#include <reg52.h>
#include <intrins.h>
#include <stdio.h>
#include <string.h>
 
typedef unsigned int u16;	      //数据类型声明
typedef unsigned char u8;
 
 sbit pwm1 = P0^0;
 sbit pwm2 = P0^1;
 sbit pwm3 = P0^2;
 sbit pwm4 = P0^3;
 sbit led=P2^0;
 sbit led1=P2^1;

 unsigned char count=0,dat;
unsigned char receivedata[120];     //变量数组存放数据
unsigned char  jd=20;
unsigned int i=0,k=0;  			
int dj_select=0;	//舵机选择(全局变量)
int next=0,isSend=0,flag=0;
char X='4';

void delay_ms(unsigned int z)//毫秒级延时
{
    
    
	unsigned int i,j;
	for(j=z;j>0;j--)
	for(i=112;i>0;i--);
}
void sendChar(u8 a) //单片机发送一个字节
{
    
    
        SBUF = a;
        while(TI==0);
        TI=0;        
}
void sendString(u8 *s)   //发送一个字符串
{
    
    
        while(*s!='\0')
        {
    
    
                sendChar(*s);
                s++;
        }        
}

void UsartInit(void)		//	串口初始化,定时器1
{
    
    
	SCON=0X50;			//设置为模式1
	PCON|=0X80;
	TMOD|=0X20;
	TH1=0XFA;				//计数器初始值设置
	TL1=0XFA;
	ES=1;						//打开接收中断,修改为0测试
	ET1 = 0;    //禁止定时器1中断
	EA=1;						//总中断
	TR1=1;					//打开计数器1
}

void ConfigTimer0()//配置并启动T0,0.1ms-T0定时时间 
{
    
    
  TMOD=0X01;//定时器
	TH0=(65536-100)/256;	  
	TL0=(65536-100)%256;
	ET0= 1;					
	TR0= 1;//打开计数器
	EA=1;
}

void time2_init() //配置定时器2
	{
    
    
	TH2=0x4C;   //50ms
  TL2=0x00;
	T2CON=0;
	T2MOD=0;
	EA=1;
	ET2=1;
	TR2=1;
} 


void pwm_Servomoto(void)//PWM信号产生控制舵机 
{
    
      
		if(dj_select==1)//选择哪个舵机转动
		{
    
    
			if(count<=jd)
				pwm1=1;
			else 
					pwm1=0;
			if(count>=200)
			{
    
    
				count=0;
			}
		}
		else if(dj_select==2)
		{
    
    
			if(count<=jd)
				pwm2=1;
			else 
					pwm2=0;
			if(count>=200)
			{
    
    
				count=0;
			}
		}
		else if(dj_select==3)
		{
    
    
			if(count<=jd)
				pwm3=1;
			else 
					 pwm3=0;
			if(count>=200)
			{
    
    
				count=0;
			}
		}
		else if(dj_select==4)
		{
    
    
			if(count<=jd)
				pwm4=1;
			else 
					 pwm4=0;
			if(count>=200)
			{
    
    
				count=0;
			}
		}

}

void DJ_turn()     //舵机转动控制
{
    
    
	if(dj_select==1) 
	{
    
    
			jd=10;
			delay_ms(2500);
			jd=20;	
			delay_ms(1000);
	}
		if(dj_select==2) 
		{
    
    
			jd=10;
			delay_ms(2500);
			jd=20;	
			delay_ms(1000);
		}
   if(dj_select==3) 
			{
    
    
			jd=10;
			delay_ms(2500);
			jd=20;	
			delay_ms(1000);
		}
		if(dj_select==4) 
		{
    
    
			jd=10;
			delay_ms(2500);
			jd=20;	
			delay_ms(1000);
		}

}

void dj_control()   //根据解析函数的值判断
{
    
    
	if(X=='0')
	  {
    
    
		  dj_select = 1;
	  }
	if(X=='1')
		{
    
    
			dj_select = 2;
		}
	if(X=='2')
			{
    
    
			dj_select = 3;
			}
	if(X=='3')
		{
    
    
			dj_select = 4;
	}
}



void time1() interrupt 1   using 2//TIMER1中断服务子函数产生PWM信号
{
    
    	
   TH0=(65536-100)/256;	  //0.1ms
	 TL0=(65536-100)%256;		
	 count++;
	 pwm_Servomoto();
 }

 void time2() interrupt 5  //控制发送登录信息
	{
    
    
		TH2=0X4C;	  //初值为50ms
	  TL2=0X00;	
		next+=1;
		if(next>800){
    
    
			isSend=1;
			next=0;
		}
		TF2=0;
}

 

void Usart() interrupt 4//串口通信中断函数
{
    
    
	if(RI==1) //接收完一帧数据
	{
    
    
		RI=0;//清除接收中断标记位
		dat=SBUF;      //出去接收到的数据   收到的数据放入receivedata[120]用于待解析
		receivedata[k]=dat;
		if(receivedata[k]=='!')  //收到标志位
		{
    
    
			k=0;
			X=receivedata[103];
			flag=1;  //接收完成标记位
		}else{
    
    
			k++;
		}
		}
	}

void main(void)
{
    
    
	ConfigTimer0();//配置定时器0
	next=0;
	isSend=0;
	time2_init();
	UsartInit();	  //串口初始化
	while(1)
	{
    
    
		if(isSend==0){
    
    
			led=0;
		}else{
    
    
			led=1;
			isSend=0;
			sendString("{\"method\":\"update\",\"gatewayNo\":\"02\",\"userkey\":\"30e217750d7e48008d8595105a14df2d\"}&^!");    //登录信息
		}
		
		if(flag==0)
		{
    
    
			led1=0;
		}else{
    
    
			led1=1;
			flag=0;
			sendString("{\"method\":\"response\",\"result\":{\"successful\":true,\"message\":\"Write serial successful 0\"}}&^!");
			dj_control();
			DJ_turn();
			X='4';
			receivedata[103]=0;
		}
		if( dj_select != 0)
			{
    
    
			dj_select = 0;	
			}
   }
}

猜你喜欢

转载自blog.csdn.net/k1507157/article/details/110069578