一、环境介绍
小车主控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软件端代码布局