您的位置:首页 > 移动开发

基于STM32设计的遥控小车(手机APP+GPS+温湿度+ESP8266)

2021-06-12 22:39 1461 查看

一、环境介绍

小车主控MCU: STM32F103ZET6 

STM32程序开发IDE: keil5

STM32程序风格:  采用寄存器方式开发,注释齐全,执行效率高,方便移植

手机APP:  采用QT设计,程序支持跨平台编译运行(Android、IOS、Windows、Linux都可以编译运行,对应平台上QT的环境搭建,之前博客已经发了文章讲解)

硬件包含:  淘宝购买的完整一套4轮遥控小车(采用STM32F103ZET6作为主控板)、DHT11温湿度传感器、中科微GPS模块、ESP8266

小车完整源码下载地址: https://download.csdn.net/download/xiaolong1126626497/19557040

APP完整源码下载地址: https://download.csdn.net/download/xiaolong1126626497/19557009

二、功能介绍

这是基于STM32设计的4轮遥控小车,支持通过Android手机APP、Windows上位机完成对小车遥控;支持前进、后退、左转、右转、停止等操作。

小车上会实时采集温度、湿度、GPS经纬度、通过ESP8266 WIFI上传至手机APP,手机APP收到数据之后,会将温湿度实时显示出来,经纬度收到后会调用百度地图,显示小车的位置,并且数据也会存放到数据库里,方便查看历史数据;支持范围内温湿度查询、最高温湿度、最低温湿度查询。

小车电机驱动模块采用L298N、WIFI模块采用ESP8266、MCU采用STM32F103C8T6、温湿度模块采用DTH11、GPS模块采用北斗GPS+BDS。

 

 

三、相关硬件介绍

 

四、程序源码

硬件连接说明:  
GPS接的串口1:   PA3(RX)   --5V~3.3V
WIFI接的串口3:  PB10(TX)--->接ESP8266的RX    PB11(RX)--->接ESP8266的TX    --3.3V
DHT11温湿度接:  PA7  

4.1  STM32小车端:  main.c源码

#include "stm32f10x.h"
#include "led.h"
#include "delay.h"
#include "key.h"
#include "usart.h"
#include <string.h>
#include "timer.h"
#include "bluetooth.h"
#include "esp8266.h"
#include "dht11.h"
#include "gps.h"
#include "motor.h"

/*
硬件连接说明:
GPS接的串口1:   PA3(RX)   --5V~3.3V
WIFI接的串口3:  PB10(TX)--->接ESP8266的RX    PB11(RX)--->接ESP8266的TX    --3.3V
DHT11温湿度接:  PA7
*/
u8 ESP8266_SendBuff[50];
char Buffer[1024];

int main()
{
u32 time_cnt=0;
double Longitude=120.086199;
double latitude=30.139219;
u8 temp=20;
u8 humi=70;

//延时2秒保证系统稳定
delay_ms(1000);
delay_ms(1000);

LED_Init();
BEEP_Init();

USART1_Init(115200);  //串口调试

USART2_Init(9600); //接GPS模块
TIMER2_Init(72,20000);

USART3_Init(115200);   //串口-WIFI ESP8166_01默认波特率9600  ESP8266_12F默认波特率115200
TIMER3_Init(72,20000); //超时时间20ms

printf("正在初始化请稍等.\r\n");

printf("DHT11_Init:%d\r\n",DHT11_Init());//温湿度传感器初始化

printf("准备检测WIFI硬件,请稍等...\r\n");
//初始化WIFI硬件
if(ESP8266_Init())printf("WIFI硬件错误.\r\n");
else
{
printf("WIFI设备正常....\r\n");
//配置WIFI的模式   192.168.4.1
printf("WIFI配置状态:%d\r\n",ESP8266_AP_TCP_Server_Mode("esp8266_666","12345678",8089));
}

MotorInit();  //电机初始化

//电机脉冲控制
TIMER4_Init(72,1000);

while(1)
{
//接收到GPS的数据
if(USART2_RX_FLAG)
{
USART2_RX_BUFFER[USART2_RX_CNT]='\0';
//解析经纬度
GPS_GNRMC_Decoding((char*)USART2_RX_BUFFER,&Longitude,&latitude);
USART2_RX_CNT=0;
USART2_RX_FLAG=0;
//打印到串口调试助手
printf("GPS:%f,%f\r\n",Longitude,latitude);
}

//接收到WIFI的数据
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
printf("WIFI:%s\r\n",USART3_RX_BUFFER);

strcpy(Buffer,(char*)USART3_RX_BUFFER);
USART3_RX_CNT=0;
USART3_RX_FLAG=0;

BEEP=1;
delay_ms(50);
BEEP=0;

if(strstr((char*)Buffer,":a"))
{
printf("向前...\r\n");
CarGo();
}
else if(strstr((char*)Buffer,":b"))
{
printf("后退...\r\n");
CarBack();
}
else if(strstr((char*)Buffer,":c"))
{
printf("向左...\r\n");
CarLeft();
}
else if(strstr((char*)Buffer,":d"))
{
printf("向右...\r\n");
CarRight();
}
else if(strstr((char*)Buffer,":e"))
{
printf("停止...\r\n");
CarStop();
}
}

time_cnt++;
delay_ms(10);

//判断轮询时间
if(time_cnt>=100*2)
{
time_cnt=0;
//读取温湿度数据
DHT11_Read_Data(&temp,&humi);

sprintf((char*)ESP8266_SendBuff,"#%d,%d,%f,%f",temp,humi,Longitude,latitude);
//向服务器上传数据
ESP8266_ServerSendData(0,ESP8266_SendBuff,strlen((char*)ESP8266_SendBuff));

//打印到串口调试助手
printf("ESP8266_SendBuff:%s\r\n",(char *)ESP8266_SendBuff);

//运行状态
Motor_LED=!Motor_LED;
}
}
}

4.2 STM32小车端: 电机控制源码

#include "motor.h"

//全局变量定义
unsigned int speed_count=0;//占空比计数器 50次一周期
int front_left_speed_duty=SPEED_DUTY;
int front_right_speed_duty=SPEED_DUTY;
int behind_left_speed_duty=SPEED_DUTY;
int behind_right_speed_duty=SPEED_DUTY;

unsigned char continue_time=0;

//根据占空比驱动电机转动
void CarMove(void)
{
BEHIND_RIGHT_EN;
//右前轮
if(front_right_speed_duty > 0)//向前
{
if(speed_count < front_right_speed_duty)
{
FRONT_RIGHT_GO;
}else                //停止
{
FRONT_RIGHT_STOP;
}
}
else if(front_right_speed_duty < 0)//向后
{
if(speed_count < (-1)*front_right_speed_duty)
{
FRONT_RIGHT_BACK;
}else                //停止
{
FRONT_RIGHT_STOP;
}
}
else                //停止
{
FRONT_RIGHT_STOP;
}

//左后轮
if(behind_left_speed_duty > 0)//向前
{
if(speed_count < behind_left_speed_duty)
{
BEHIND_LEFT_GO;
}	else                //停止
{
BEHIND_LEFT_STOP;
}
}
else if(behind_left_speed_duty < 0)//向后
{
if(speed_count < (-1)*behind_left_speed_duty)
{
BEHIND_LEFT_BACK;
}	else                //停止
{
BEHIND_LEFT_STOP;
}
}
else                //停止
{
BEHIND_LEFT_STOP;
}
}

//向前
void CarGo(void)
{
front_left_speed_duty=SPEED_DUTY;
front_right_speed_duty=SPEED_DUTY;
behind_left_speed_duty=SPEED_DUTY;
behind_right_speed_duty=SPEED_DUTY;
}

//后退
void CarBack(void)
{
front_left_speed_duty=-SPEED_DUTY;
front_right_speed_duty=-SPEED_DUTY;
behind_left_speed_duty=-SPEED_DUTY;
behind_right_speed_duty=-SPEED_DUTY;
}

//向左
void CarLeft(void)
{
front_left_speed_duty=-20;
front_right_speed_duty=SPEED_DUTY;
behind_left_speed_duty=-20;
behind_right_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
}

//向右
void CarRight(void)
{
front_left_speed_duty=SPEED_DUTY;
front_right_speed_duty=-20;
behind_left_speed_duty=SPEED_DUTY+10;//增加后轮驱动力
behind_right_speed_duty=-20;
}

//停止
void CarStop(void)
{
front_left_speed_duty=0;
front_right_speed_duty=0;
behind_left_speed_duty=0;
behind_right_speed_duty=0;
}

/*
FRONT_LEFT_F_PIN	PG13	左前前进IO
FRONT_LEFT_B_PIN	PG11	左前后退IO

FRONT_RIGHT_F_PIN	PC11	右前前进IO
FRONT_RIGHT_B_PIN	PD0	  右前后退IO

BEHIND_LEFT_F_PIN	PD6	    左后前进IO
BEHIND_LEFT_B_PIN	PG9	    左后后退IO

右后电机的两个控制IO这里改为两路使能EN1、EN2,高电平有效
BEHIND_RIGHT_F_PIN	PD4	    右电机使能IO
BEHIND_RIGHT_B_PIN	PD2	    左电机使能IO
*/
void MotorInit(void)
{
RCC->APB2ENR|=1<<8; //PG
RCC->APB2ENR|=1<<5; //PD
RCC->APB2ENR|=1<<4; //PC

GPIOG->CRH&=0xFF0F0F0F;
GPIOG->CRH|=0x00303030;

GPIOD->CRL&=0xF0F0F0F0;
GPIOD->CRL|=0x03030303;

GPIOC->CRH&=0xFFFF0FFF;
GPIOC->CRH|=0x00003000;

CarStop();

}

4.3  STM32小车端:  ESP8266 WIFI源码

#include "esp8266.h"
u8 ESP8266_IP_ADDR[16]; //255.255.255.255
u8 ESP8266_MAC_ADDR[18]; //硬件地址
/*
函数功能: ESP8266命令发送函数
函数返回值:0表示成功  1表示失败
*/
u8 ESP8266_SendCmd(char *cmd)
{
u8 i,j;
for(i=0;i<10;i++) //检测的次数--发送指令的次数
{
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
USARTx_StringSend(USART3,cmd);
delay_ms(200);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"OK"))
{
return 0;
}
}
}
return 1;
}

/*
函数功能: ESP8266硬件初始化检测函数
函数返回值:0表示成功  1表示失败
*/
u8 ESP8266_Init(void)
{
ESP8266_SendCmd("+++");
delay_ms(200);
ESP8266_SendCmd("+++");
delay_ms(200);
return ESP8266_SendCmd("AT\r\n");
}

/*
函数功能: 一键配置WIFI为AP+TCP服务器模式
函数参数:
char *ssid  创建的热点名称
char *pass  创建的热点密码 (最少8位)
u16 port    创建的服务器端口号
函数返回值: 0表示成功 其他值表示对应错误值
*/
u8 ESP8266_AP_TCP_Server_Mode(char *ssid,char *pass,u16 port)
{
char *p;
u8 i;
char tmp_buff[100];
/*1. 测试硬件*/
if(ESP8266_SendCmd("AT\r\n"))return 1;
/*2. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 2;
/*3. 设置WIFI模式*/
if(ESP8266_SendCmd("AT+CWMODE=2\r\n"))return 3;
/*4. 复位*/
ESP8266_SendCmd("AT+RST\r\n");
delay_ms(1000);
delay_ms(1000);
delay_ms(1000);
/*5. 关闭回显*/
if(ESP8266_SendCmd("ATE0\r\n"))return 5;
/*6. 设置WIFI的AP模式参数*/
sprintf(tmp_buff,"AT+CWSAP=\"%s\",\"%s\",1,4\r\n",ssid,pass);
if(ESP8266_SendCmd(tmp_buff))return 6;
/*7. 开启多连接*/
if(ESP8266_SendCmd("AT+CIPMUX=1\r\n"))return 7;
/*8. 设置服务器端口号*/
sprintf(tmp_buff,"AT+CIPSERVER=1,%d\r\n",port);
if(ESP8266_SendCmd(tmp_buff))return 8;
/*9. 查询本地IP地址*/
if(ESP8266_SendCmd("AT+CIFSR\r\n"))return 9;
//提取IP地址
p=strstr((char*)USART3_RX_BUFFER,"APIP");
if(p)
{
p+=6;
for(i=0;*p!='"';i++)
{
ESP8266_IP_ADDR[i]=*p++;
}
ESP8266_IP_ADDR[i]='\0';
}
//提取MAC地址
p=strstr((char*)USART3_RX_BUFFER,"APMAC");
if(p)
{
p+=7;
for(i=0;*p!='"';i++)
{
ESP8266_MAC_ADDR[i]=*p++;
}
ESP8266_MAC_ADDR[i]='\0';
}

//打印总体信息
printf("当前WIFI模式:AP+TCP服务器\n");
printf("当前WIFI热点名称:%s\n",ssid);
printf("当前WIFI热点密码:%s\n",pass);
printf("当前TCP服务器端口号:%d\n",port);
printf("当前TCP服务器IP地址:%s\n",ESP8266_IP_ADDR);
printf("当前TCP服务器MAC地址:%s\n",ESP8266_MAC_ADDR);
return 0;
}

/*
函数功能: TCP服务器模式下的发送函数
发送指令:
*/
u8 ESP8266_ServerSendData(u8 id,u8 *data,u16 len)
{
u8 i,j,n;
char ESP8266_SendCMD[100]; //组合发送过程中的命令
for(i=0;i<10;i++)
{
sprintf(ESP8266_SendCMD,"AT+CIPSEND=%d,%d\r\n",id,len);
USARTx_StringSend(USART3,ESP8266_SendCMD);
delay_ms(200);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,">"))
{
//继续发送数据
USARTx_DataSend(USART3,data,len);
//等待数据发送成功
delay_ms(200);
if(USART3_RX_FLAG)
{
USART3_RX_BUFFER[USART3_RX_CNT]='\0';
USART3_RX_FLAG=0;
USART3_RX_CNT=0;
if(strstr((char*)USART3_RX_BUFFER,"SEND OK"))
{
return 0;
}
}
}
}
}
return 1;
}

4.4  QT软件端代码布局

 

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: