单片机
返回首页

keil5开发案例分享 基于STM32设计遥控小车

2023-06-05 来源:elecfans

一、环境介绍

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


poYBAGDYdXCAWkKMAAAAK8RNs4s030.pngpoYBAGDYdXCAWkKMAAAAK8RNs4s030.png


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png

三、相关硬件介绍


poYBAGDYdXCAWkKMAAAAK8RNs4s030.pngpoYBAGDYdXCAWkKMAAAAK8RNs4s030.png


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


四、程序源码

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

poYBAGDYdXCAWkKMAAAAK8RNs4s030.png


4.1 STM32小车端: main.c源码

#include 'stm32f10x.h'

#include 'led.h'

#include 'delay.h'

#include 'key.h'

#include 'usart.h'

#include 

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

8aef65a069af12c69f96d0664542f88a_watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3hpYW9sb25nMTEyNjYyNjQ5Nw==,size_16,color_FFFFFF,t_70.png

进入单片机查看更多内容>>
相关视频
  • RISC-V嵌入式系统开发

  • SOC系统级芯片设计实验

  • 云龙51单片机实训视频教程(王云,字幕版)

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

精选电路图
  • 家用电源无载自动断电装置的设计与制作

  • PIC单片机控制的遥控防盗报警器电路

  • 短波AM发射器电路设计图

  • 使用ESP8266从NTP服务器获取时间并在OLED显示器上显示

  • 如何构建一个触摸传感器电路

  • 基于TDA2003的简单低功耗汽车立体声放大器电路

    相关电子头条文章