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

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

一、环境介绍

小车主控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。

image.png

image.png

image.png

三、相关硬件介绍

image.png

image.png

image.png

image.png

四、程序源码

硬件连接说明:  

GPS接的串口1:   PA3(RX)   --5V~3.3V

WIFI接的串口3:  PB10(TX)--->接ESP8266的RX    PB11(RX)--->接ESP8266的TX    --3.3V

DHT11温湿度接:  PA7  

image.png

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软件端代码布局

image.png

目录
相关文章
|
2月前
|
移动开发 Android开发 数据安全/隐私保护
移动应用与系统的技术演进:从开发到操作系统的全景解析随着智能手机和平板电脑的普及,移动应用(App)已成为人们日常生活中不可或缺的一部分。无论是社交、娱乐、购物还是办公,移动应用都扮演着重要的角色。而支撑这些应用运行的,正是功能强大且复杂的移动操作系统。本文将深入探讨移动应用的开发过程及其背后的操作系统机制,揭示这一领域的技术演进。
本文旨在提供关于移动应用与系统技术的全面概述,涵盖移动应用的开发生命周期、主要移动操作系统的特点以及它们之间的竞争关系。我们将探讨如何高效地开发移动应用,并分析iOS和Android两大主流操作系统的技术优势与局限。同时,本文还将讨论跨平台解决方案的兴起及其对移动开发领域的影响。通过这篇技术性文章,读者将获得对移动应用开发及操作系统深层理解的钥匙。
|
1月前
|
传感器 测试技术 芯片
基于STM32的环境监测系统 (esp8266)(上)
基于STM32的环境监测系统 (esp8266)(上)
307 0
|
4月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现(源码+lw+部署文档+讲解等)
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现(源码+lw+部署文档+讲解等)
|
4月前
|
存储 移动开发 Android开发
使用kotlin Jetpack Compose框架开发安卓app, webview中h5如何访问手机存储上传文件
在Kotlin和Jetpack Compose中,集成WebView以支持HTML5页面访问手机存储及上传音频文件涉及关键步骤:1) 添加`READ_EXTERNAL_STORAGE`和`WRITE_EXTERNAL_STORAGE`权限,考虑Android 11的分区存储;2) 配置WebView允许JavaScript和文件访问,启用`javaScriptEnabled`、`allowFileAccess`等设置;3) HTML5页面使用`<input type="file">`让用户选择文件,利用File API;
|
4月前
|
JavaScript Java 测试技术
基于springboot+vue.js+uniapp的多功能智能手机阅读APP附带文章源码部署视频讲解等
基于springboot+vue.js+uniapp的多功能智能手机阅读APP附带文章源码部署视频讲解等
79 1
|
4月前
|
机器学习/深度学习 人工智能 视频直播
AI直播手机APP震撼发布!3大场景直播,60秒一键开播!
🎉 青否数字人AI直播APP发布!🚀 在抖音等平台60秒一键开播,简化直播流程。💡 3种AI直播模式,融合6大AIGC技术,助力新手轻松直播带货且避免违规。💪 AI主播、声音克隆,实时话术改写,智能互动与讲品同步,提升转化。📊 实景与视频直播结合,适应多种场景。🌐 独立部署,自定义版权,1年免费升级,专业售后支持。🚀 (直播: zhibo175) #青否数字人 #AI直播
AI直播手机APP震撼发布!3大场景直播,60秒一键开播!
|
3月前
|
Java Android开发 UED
安卓scheme_url调端:如果手机上多个app都注册了 http或者https 的 intent。 调端的时候,调起哪个app呢?
当多个Android应用注册了相同的URL Scheme(如http或https)时,系统会在尝试打开这类链接时展示一个选择对话框,让用户挑选偏好应用。若用户选择“始终”使用某个应用,则后续相同链接将直接由该应用处理,无需再次选择。本文以App A与App B为例,展示了如何在`AndroidManifest.xml`中配置对http与https的支持,并提供了从其他应用发起调用的示例代码。此外,还讨论了如何在系统设置中管理这些默认应用选择,以及建议开发者为避免冲突应注册更独特的Scheme。
|
5月前
|
JavaScript Java 测试技术
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现
基于SpringBoot+Vue+uniapp的多功能智能手机阅读APP的详细设计和实现
83 12
|
6月前
|
开发工具 iOS开发
如何导出iPhone手机中app共享文件夹的文件与闪退日志的收集
如何导出iPhone手机中app共享文件夹的文件与闪退日志的收集
89 1
|
6月前
|
存储 定位技术 芯片
为何手机gps定位需要流量,而车载不需要?
为何手机gps定位需要流量,而车载不需要?
147 0
为何手机gps定位需要流量,而车载不需要?
下一篇
无影云桌面