STM32
直播中

张娟

7年用户 2101经验值
私信 关注
[问答]

怎样去设计一种基于STM32的四轮遥控小车

怎样去设计一种基于STM32的四轮遥控小车?

基于STM32的四轮遥控小车有哪些功能?

回帖(1)

王璐

2021-10-19 15:19:28
  一、环境介绍
  小车主控MCU: STM32F103ZET6
  STM32程序开发IDE: keil5
  STM32程序风格: 采用寄存器方式开发,注释齐全,执行效率高,方便移植
  手机APP: 采用QT设计,程序支持跨平台编译运行(Android、IOS、Windows、Linux都可以编译运行,对应平台上QT的环境搭建,之前博客已经发了文章讲解)
  硬件包含: 淘宝购买的完整一套4轮遥控小车(采用STM32F103ZET6作为主控板)、DHT11温湿度传感器、中科微GPS模块、ESP8266
  二、功能介绍
  这是基于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(“正在初始化请稍等。rn”);
  printf(“DHT11_Init:%drn”,DHT11_Init());//温湿度传感器初始化
  printf(“准备检测WIFI硬件,请稍等。..rn”);
  //初始化WIFI硬件
  if(ESP8266_Init())printf(“WIFI硬件错误。rn”);
  else
  {
  printf(“WIFI设备正常。..。rn”);
  //配置WIFI的模式 192.168.4.1
  printf(“WIFI配置状态:%drn”,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]=‘’;
  //解析经纬度
  GPS_GNRMC_Decoding((char*)USART2_RX_BUFFER,&Longitude,&latitude);
  USART2_RX_CNT=0;
  USART2_RX_FLAG=0;
  //打印到串口调试助手
  printf(“GPS:%f,%frn”,Longitude,latitude);
  }
  //接收到WIFI的数据
  if(USART3_RX_FLAG)
  {
  USART3_RX_BUFFER[USART3_RX_CNT]=‘’;
  printf(“WIFI:%srn”,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(“向前。..rn”);
  CarGo();
  }
  else if(strstr((char*)Buffer,“:b”))
  {
  printf(“后退。..rn”);
  CarBack();
  }
  else if(strstr((char*)Buffer,“:c”))
  {
  printf(“向左。..rn”);
  CarLeft();
  }
  else if(strstr((char*)Buffer,“:d”))
  {
  printf(“向右。..rn”);
  CarRight();
  }
  else if(strstr((char*)Buffer,“:e”))
  {
  printf(“停止。..rn”);
  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:%srn”,(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]=‘’;
  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(“ATrn”);
  }
  /*
  函数功能: 一键配置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(“ATrn”))return 1;
  /*2. 关闭回显*/
  if(ESP8266_SendCmd(“ATE0rn”))return 2;
  /*3. 设置WIFI模式*/
  if(ESP8266_SendCmd(“AT+CWMODE=2rn”))return 3;
  /*4. 复位*/
  ESP8266_SendCmd(“AT+RSTrn”);
  delay_ms(1000);
  delay_ms(1000);
  delay_ms(1000);
  /*5. 关闭回显*/
  if(ESP8266_SendCmd(“ATE0rn”))return 5;
  /*6. 设置WIFI的AP模式参数*/
  sprintf(tmp_buff,“AT+CWSAP=”%s“,”%s“,1,4rn”,ssid,pass);
  if(ESP8266_SendCmd(tmp_buff))return 6;
  /*7. 开启多连接*/
  if(ESP8266_SendCmd(“AT+CIPMUX=1rn”))return 7;
  /*8. 设置服务器端口号*/
  sprintf(tmp_buff,“AT+CIPSERVER=1,%drn”,port);
  if(ESP8266_SendCmd(tmp_buff))return 8;
  /*9. 查询本地IP地址*/
  if(ESP8266_SendCmd(“AT+CIFSRrn”))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]=‘’;
  }
  //提取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]=‘’;
  }
  //打印总体信息
  printf(“当前WIFI模式:AP+TCP服务器n”);
  printf(“当前WIFI热点名称:%sn”,ssid);
  printf(“当前WIFI热点密码:%sn”,pass);
  printf(“当前TCP服务器端口号:%dn”,port);
  printf(“当前TCP服务器IP地址:%sn”,ESP8266_IP_ADDR);
  printf(“当前TCP服务器MAC地址:%sn”,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,%drn”,id,len);
  USARTx_StringSend(USART3,ESP8266_SendCMD);
  delay_ms(200);
  if(USART3_RX_FLAG)
  {
  USART3_RX_BUFFER[USART3_RX_CNT]=‘’;
  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]=‘’;
  USART3_RX_FLAG=0;
  USART3_RX_CNT=0;
  if(strstr((char*)USART3_RX_BUFFER,“SEND OK”))
  {
  return 0;
  }
  }
  }
  }
  }
  return 1;
  }
  4.4 QT软件端代码布局
  
举报

更多回帖

发帖
×
20
完善资料,
赚取积分