01
介绍
本项目要实现的是一个通过手机APP控制寝室灯开关的辅助工具。
项目框图如下图所示。
实现原理
-
手机和本模块都接入同一个wifi网络,手机端发送命令,本模块执行相应的命令。
-
开关灯,通过舵机来进行实现。
02
硬件设计
2.1 主控
ESP8266串口WIFI
ESP-12F
ESP8266-12F是ESP8266-12的增强版。
2.2 原理图设计
2.2.1 控制板
本项目实际上只需要一个GPIO口来控制舵机即可。
将其他的引脚引入是为了后续可能扩展其他功能使用。
2.2.2 电源板
ESP12F模组3.3v供电,舵机5v供电。
使用了一片AMS1117-3.3v和一片AMS1117-5v芯片,实现12v至3.3v和5v的转换。
( 由于寝室开关座子附近有一个插座,所以就直接找了一个输入220v输出12v点的电源线,作为电源板的输入电源 )
2.3 PCB设计
2.3.1 控制板PCB
需要注意ESP12F模组天线部分的布局,与周围的PCB要有大于5mm的间距。
2.3.2 电源板PCB
03
软件设计
3.1 控制程序
开发环境使用的是Arduino IDE。
要实现的功能有两大块
-
舵机的控制
-
UDP网络通信
WiFI-UDP通信参考: ESP8266 – WiFiUDP库 – 太极创客 (taichi-maker.com)
通信协议较为简单,命令长度为2个字节,第1个字节为固定值0xff,第2个字节为相应的控制码( 0x00: 关灯,0x01开灯 )
通信的安全性,在通信过程中并没有做握手、认证等处理。通信用户的有效性是通过wifi密码来鉴别的( 只有成功连接wifi,才可以控制灯的开关 )。
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
/*********************** 舵机相关 ************************/
// 连接舵机的引脚
typedef enum SWITCH_STATE{
SWITCH_ON,
SWITCH_OFF
}SWITCH_STATE;
typedef struct SWITCH_CONTROL{
u16 switch_on;
u16 switch_off;
SWITCH_STATE switch_state;
}SWITCH_CONTROL;
void Steer_Init_PWM(){
pinMode(STEER_PIN,OUTPUT);
}
/**
* 根据pwm高电平时间(us)控制舵机
*/
void Steer_SetAngle_PWM(u16 pwm) {
u8 index = 0;
// 控制舵机转动
for(index = 0;index<10;index++){
digitalWrite(STEER_PIN,HIGH);
delayMicroseconds(pwm);
digitalWrite(STEER_PIN,LOW);
delayMicroseconds(20000 - pwm);
}
}
SWITCH_CONTROL switch_contrl = {
.switch_on = 2300,
.switch_off = 1400,
.switch_state = SWITCH_OFF
};
void Change_Switch_State( u8 switch_state ) {
if( switch_state == SWITCH_ON){
Steer_SetAngle_PWM(switch_contrl.switch_on);
switch_contrl.switch_state = SWITCH_ON;
}else if(switch_state == SWITCH_OFF){
Steer_SetAngle_PWM(switch_contrl.switch_off);
switch_contrl.switch_state = SWITCH_OFF;
}else{
}
}
/*******************************************************/
/*********************** WIFI相关 ***********************/
typedef enum WIFI_STATE{
WIFI_OK,
WIFI_ERROR,
UDP_OK,
UDP_ERROR
}WIFI_STATE;
typedef enum USER_CMD {
CMD_ERROR,
CMD_SWITCH_ON,
CMD_SWITCH_OFF
}USER_CMD;
const char* ssid = "xxxxx"; //wifi name
const char* passwd = "xxxxx";//wifi passwd
// buf
unsigned char udp_buf[BUF_LEN] = {0};
WiFiUDP Udp;
u8 WIFI_Init(const char* wifi_ssid, const char* wifi_passwd){
u8 counter = 0;
WiFi.begin(wifi_ssid, wifi_passwd);
while (WiFi.status() != WL_CONNECTED) {
counter++;
delay(500);
//10秒后如果还是连接不上,就判定为连接超时
if (counter > 20) return WIFI_ERROR;
}
return WIFI_OK;
}
u8 UDP_Init(u16 port) {
if(Udp.begin(port)){ //启动Udp监听服务
return UDP_OK;
}else {
return UDP_ERROR;
}
}
u8 Get_UDP_Packet(unsigned char * buf,u8 buf_len){
int packetSize = Udp.parsePacket();//获得解析包
if(Udp.available()){
return Udp.read(buf, buf_len);
}else{
return 0;
}
}
/**
* 定义报文格式
* 1B 1B
* 0xff cmd
* 开关灯的cmd: 0x00:关灯 0x01:开灯
*/
u8 Parse_UDP_Packet(unsigned char * data,u8 data_len){
if( data[0] != 0xff ) return CMD_ERROR;
if( data[1] == 0x00 ) return CMD_SWITCH_OFF;
else if( data[1] == 0x01 ) return CMD_SWITCH_ON;
else return CMD_ERROR;
}
void Execute_Cmd(u8 cmd){
switch( cmd ) {
case CMD_SWITCH_ON:
Change_Switch_State(SWITCH_ON);
break;
case CMD_SWITCH_OFF:
Change_Switch_State(SWITCH_OFF);
break;
default:
break;
}
}
/*******************************************************/
void setup() {
Serial.begin(9600); // 波特率9600
Steer_Init_PWM();
if(WIFI_Init(ssid,passwd) == WIFI_OK) {
Serial.println(WiFi.localIP()); // 打印ip地址
if( UDP_Init(UDP_PORT) ) {
Serial.printf("UDP监听端口:%d\r\n",UDP_PORT);
}else{
Serial.println("UDP Init Failed");
}
}else{
Serial.println("WIFI Init Failed");
}
}
void loop() {
u8 datalen = Get_UDP_Packet(udp_buf,BUF_LEN);
if( datalen == 0 ) return ;
u8 user_cmd = Parse_UDP_Packet(udp_buf,datalen);
if( user_cmd == CMD_ERROR ) return;
Execute_Cmd(user_cmd);
}
3.2 手机APP程序
使用Flutter开发手机APP,实现遥控灯的开关。
界面设计较为简单,只有两个功能按键,分别对应灯的开与关。
04
外壳设计
05
结果展示