一、大致结构
手机(通过 TCP连接 这个APP)连接esp8266,esp8266通过串口与单片机(stm32f103c8t6)进行通信,单片机通过数据解析,从而进行控制电机与舵机。
洒水小车由两个个电机分别控制行进与洒水,两个舵机分别控制行进方向与洒水方向。
二、配置代码
1 .sep8266配置
ESP8266是一款超低功耗的UART-WiFi 透传模块,拥有业内极富竞争力的封装尺寸和超低能耗技术,专为移动设备和物联网应用设计,可将用户的物理设备连接到Wi-Fi 无线网络上,进行互联网或局域网通信,实现联网功能。
硬件连接
将esp8266模块的GND、VCC、TXD、RXD、CH-PD与单片机对应引脚连接,其中TXD与RXD要反接,模块在工作时CH-PD要处于高电平状态。
软件配置
第一步:设置WiFi模块的工作模式
ESP8266模块支持STA/AP/STA+AP 三种工作模式。
由于我是用手机连接WiFi,所以应该是WiFi作为热点,设置工作模式为AP模式 指令为 “AT+CWMODE=<mode>”
<mode> 1 STA 模式:ESP8266模块通过路由器连接互联网,手机或电脑通过互联网实现对设 备的远程控制。
2 AP 模式:ESP8266模块作为热点,实现手机或电脑直接与模块通信,实现局域网无 线控制。
3 STA+AP 模式:两种模式的共存模式,即可以通过互联网控制可实现无缝切换,方 便操作。
第二步:设置 AP 模式下的参数
设置热点的参数 指令为“ AT+ CWSAP=<ssid>,<pwd>,<chl>,<ecn>”
其中<ssid>字符串参数,热点名称,
<pwd>字符串参数,密码最长 64 字节 ASCII,
<chl>通道号,
<ecn> 加密类型 0 OPEN
2 WPA_PSK
3 WPA2_PSK
4 WPA_WPA2_PSK
第三步:启动多连接
设置热点的连接类型(单连接或者多连接)
指令为“AT+ CIPMUX=<mode>”
<mode> 0 单路连接模式
1 多路连接模式
第四步:配置为服务器
开启 server 后自动建立 server 监听,当有 client 接入会自动按顺序占用一个连接 , AT+ CIPMUX=1 时才能开启服务器
指令为“AT+ CIPSERVER= <mode>,<port>”
<mode> 0 关闭 server 模式
1 开启 server 模式
<port> 端口号,缺省值为 333
WiFi模块配置代码
void esp8266_start_trans(void)
{
//设置工作模式 1:station模式 2:AP模式 3:兼容 AP+station模式
esp8266_send_cmd("AT+CWMODE=2","OK",100);
esp8266_send_cmd("AT+CWSAP=\"yeyeye\",\"12345678\",1,3","OK",100);
esp8266_send_cmd("AT+CIPMUX=1","OK",100);
esp8266_send_cmd("AT+CIPSERVER=1,8080","OK",100);
}
2.串口协议接收与解析
通过手机发送一个长度为8个十六进制数的数据(包括指令头、地址、控制指令、校验码)到单片机,单片机通过串口接收,经过解析,完成对单片机控制。
//协议接收
void ESP8266_IntGenData(u16 rec_tem)
{
static unsigned char rec_count = 0;//--接收计数
static unsigned char start_rec = 0;//--贞开始
if(rec_tem == open_cpu||rec_tem == cpu_openstatse) //判断帧头
{
rec_count = 0;
start_rec = 1;
}
if(start_rec == 1)
{
receive_dat[rec_count++] = rec_tem; //接收数据
if(rec_count == command_length) //判断数据是否接收到八位
{
start_rec = 0;
rec_flag = 1;
}
}
}
串口接收到的数据传输到协议接收函数,先判断指令头是否正确,正确则接收标志位为1,把数据保存到数组中,当接收到数据为8个时,协议解析标志位为1,进行协议解析。
3. 电机与舵机配置
电机配置
分别使用定时器3的通道3与通道4控制前进与洒水的电机
void TIM3_PWM_Init(u16 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); //使能GPIO外设时钟使能
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1; //
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOB, &GPIO_InitStructure);
TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
TIM_TimeBaseStructure.TIM_ClockDivision = 0; //设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_Pulse = 0; //设置待装入捕获比较寄存器的脉冲值
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
TIM_OC3Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC4Init(TIM3, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OC3PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH1预装载使能
TIM_OC4PreloadConfig(TIM3, TIM_OCPreload_Enable); //CH2预装载使能
TIM_ARRPreloadConfig(TIM3, ENABLE); //使能TIMx在ARR上的预装载寄存器
TIM_Cmd(TIM3, ENABLE); //使能TIM3
}
舵机配置
定时器2的通道1与通道2分别控制行进的舵机与洒水的舵机
void MG996_SG90_pwm_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //声明一个结构体变量,用来初始化GPIO
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;//声明一个结构体变量,用来初始化定时器
TIM_OCInitTypeDef TIM_OCInitStructure;//根据TIM_OCInitStruct中指定的参数初始化外设TIMx
/* 开启时钟 */
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
/* 配置GPIO的模式和IO口 */
GPIO_InitStructure.GPIO_Pin= GPIO_Pin_0|GPIO_Pin_1;// PA0|PA1
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_PP;//复用推挽输出
GPIO_Init(GPIOA,&GPIO_InitStructure);
//TIM3定时器初始化
TIM_TimeBaseInitStructure.TIM_Period = 199; //PWM 频率=72000/(199+1)=36Khz//设置自动重装载寄存器周期的值
TIM_TimeBaseInitStructure.TIM_Prescaler = 7199;//设置用来作为TIMx时钟频率预分频值
TIM_TimeBaseInitStructure.TIM_ClockDivision = 0;//设置时钟分割:TDTS = Tck_tim
TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
TIM_TimeBaseInit(TIM2, & TIM_TimeBaseInitStructure);
//PWM初始化 //根据TIM_OCInitStruct中指定的参数初始化外设TIMx
TIM_OCInitStructure.TIM_OCMode=TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState=TIM_OutputState_Enable;//PWM输出使能
TIM_OCInitStructure.TIM_OCPolarity=TIM_OCPolarity_Low;
TIM_OC1Init(TIM2, &TIM_OCInitStructure);
TIM_OC2Init(TIM2,&TIM_OCInitStructure);
//注意此处初始化时TIM_OC1Init而不是TIM_OCInit,否则会出错。因为固件库的版本不一样。
TIM_OC1PreloadConfig(TIM2, TIM_OCPreload_Enable);
TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable);//使能或者失能TIMx在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM2,ENABLE);
TIM_Cmd(TIM2,ENABLE);//使能或者失能TIMx外设
}
4.红外避障
在车头前方安装了3个红外避障模块,车子有自动行进洒水功能
//获取红外避障模块状态
char GetVoidStatus(void)
{
char left=0,right=0,zhong=0;
char count;
if(bizhang_left == BARRIER_N) //左边检测到有障碍物
{
left = 1;
}
else left=0;
if(bizhang_right == BARRIER_N) //右边检测到有障碍物
{
right = 2;
}
else right = 0;
if(bizhang_zhong == BARRIER_N) //前方检测到有障碍物
{
zhong = 4;
}
else zhong = 0;
return left + right+zhong;
}
//红外避障处理
//处理方式:左边检测到 右转
// 右边检测到 左转
// 前方检测到 停止 后退 右转
// 两边检测到 停止 后退 右转
// 没检测到 直行
void VoidRun(void)
{
char status=7;
if(model==12)
{
status = GetVoidStatus();
}
switch(status)
{
case VOID_1: ;
CarLeft(); delay_ms(1000);Cargo();
break;
case VOID_2:
CarRight(); delay_ms(1000); Cargo();
break;
case VOID_3:
CarStop();
break;
case VOID_4:
CarStop();delay_ms(500);CarBack(); delay_ms(1500);CarRight(); delay_ms(1000);Cargo();
break;
case VOID_5:
CarStop();delay_ms(500);CarBack(); delay_ms(1500);CarRight(); delay_ms(1000);Cargo();
break;
case VOID_6:
CarStop();delay_ms(500);CarBack(); delay_ms(1500);CarRight(); delay_ms(1000);Cargo();
break;
case VOID_NONE:
Cargo();
break;
default: break;
}
}
三、成品展示
ESP8266遥控洒水小车.zip-嵌入式文档类资源-CSDN下载
内附完整代码