基于STM32-Socket-Qt 遥控小车(一代)
创始人
2024-01-20 10:27:11

文章目录

  • 一、项目分析
    • 1. 项目简介
    • 2. 知识储备
    • 3. 硬件选择
  • 二、STM32部分
  • 三、QT部分
  • 四、遥控小车演示
    • 程序源码


一、项目分析

1. 项目简介

本项目本质为客户端与服务器之间的通信,通过发送不同的指令,服务器和客户端进行不同的操作。

客户端:基于STM32制作简单行驶小车
服务器:安卓手机,基于Socket编程下 用QT进行安卓开发,将app传输到手机上。
TCP通信:ESP8266

手机端发送不同指令,小车执行不同操作

2. 知识储备

  • STM32基础 可移步 “ STM32专栏 ” 进行知识充能
  • ESP8266WiFi模块 可移步 “ ESP8266WiFi模块的基本通信 ” 学习使用
  • Socket编程基础 可移步 “ Socket编程基础 ” 学习使用
  • QT_Socket_TCP 可移步 “ QT_Socket_tcp通信 ” 学习使用
  • QT_Android环境搭建 可移步 “ QT Android环境搭建 ” 学习使用

3. 硬件选择

1. esp8266WiFi模块
在这里插入图片描述
2. 直流电机
(笔者这里用编码器电机代替,普通直流电机即可)
在这里插入图片描述

3. STM32F103C8T8
在这里插入图片描述
4. 驱动电机模块
(笔者这里用的是TB6612,L298N啥的都行)
在这里插入图片描述
5. 烧写器 ST-Link
在这里插入图片描述
6. 安卓手机
在这里插入图片描述

7. 电池、杜邦线、螺母、轮胎等等

在这里插入图片描述

二、STM32部分

1. pwm

void TIM3_PWM_Init(u16 per,u16 psc)
{/*使能TIM4时钟*/RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3,ENABLE);/*使能GPIO*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);/*使能AFIO*/RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);/*配置GPIO*/GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA,&GPIO_InitStructure);GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);/*设置重映射*///GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE);//部分重映射	/*初始化定时器参数*/TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStructure;TIM_TimeBaseInitStructure.TIM_ClockDivision = TIM_CKD_DIV1;//选择时钟分频为1分频TIM_TimeBaseInitStructure.TIM_CounterMode = TIM_CounterMode_Up;//选择计数模式为向上计数TIM_TimeBaseInitStructure.TIM_Period = per;//配置周期(ARR自动重装器的值)TIM_TimeBaseInitStructure.TIM_Prescaler = psc;//配置PSC预分频器的值//TIM_TimeBaseInitStructure.TIM_RepetitionCounter = 0;//重复计数器的值,高级计数器才需配置TIM_TimeBaseInit(TIM3,&TIM_TimeBaseInitStructure);//TIM_ClearFlag(TIM4,TIM_FLAG_Update);//先清除标志位,避免刚初始化就进入中断/*初始化PWM参数*/TIM_OCInitTypeDef TIM_OCInitStructure;TIM_OCInitStructure.TIM_Pulse = 0;TIM_OCInitStructure.TIM_OCIdleState = TIM_OCIdleState_Reset;   //选择空闲状态下的非工作状态 低电平TIM_OCInitStructure.TIM_OCNIdleState = TIM_OCNIdleState_Set;  //选择互补空闲状态下的非工作状态 低电平TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//选择PWM1模式TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//输出极性:高电平有效TIM_OCInitStructure.TIM_OCNPolarity = TIM_OCNPolarity_Low;TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;  //输出比较使能TIM_OCInitStructure.TIM_OutputNState = TIM_OutputNState_Enable;  //互补输出比较使能TIM_OC1Init(TIM3,&TIM_OCInitStructure);TIM_OC2Init(TIM3,&TIM_OCInitStructure);TIM_OC3Init(TIM3,&TIM_OCInitStructure);TIM_OC4Init(TIM3,&TIM_OCInitStructure);/*使能TIMX在CCRX上的预装载寄存器*/TIM_OC1PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_OC2PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_OC3PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_OC4PreloadConfig(TIM3,TIM_OCPreload_Enable);TIM_CtrlPWMOutputs(TIM3,ENABLE);/*使能TIMX在ARR上的预装载寄存器允许位*///TIM_ARRPreloadConfig(TIM4,ENABLE);/*开启定时器*/TIM_Cmd(TIM3,ENABLE);
}	

2. Car

void forward()
{GPIO_SetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_14);
}void back()
{GPIO_SetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_14);GPIO_ResetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_15);
}//  PB7,PB8:  右后	 
//	PB14,PB15:右前   
//	PB12,PB13:左前	 
//	PB10,PB11:左后   void turn_left()
{GPIO_SetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_10 | GPIO_Pin_13 | GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_14);
}void turn_left1()
{GPIO_SetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14);GPIO_ResetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_15);
}void turn_right()
{GPIO_SetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_14);
}void turn_right1()
{GPIO_SetBits(GPIOB,GPIO_Pin_8| GPIO_Pin_10 | GPIO_Pin_12 | GPIO_Pin_15);GPIO_ResetBits(GPIOB,GPIO_Pin_7| GPIO_Pin_11 | GPIO_Pin_13 | GPIO_Pin_14);
}void stop(void)
{GPIO_ResetBits(GPIOB,GPIO_Pin_8 | GPIO_Pin_7 | GPIO_Pin_10 | GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 | GPIO_Pin_15);
}

3. esp8266

void esp8266_start_trans(void)
{//printf("等待初始化\r\n");while(esp8266_send_cmd((u8 *)"AT",(u8 *)"OK",20));//设置工作模式 1:station模式   2:AP模式  3:兼容 AP+station模式while(esp8266_send_cmd((u8*)"AT+CWMODE=1",(u8*)"OK",20));//printf("设置工作模式成功\r\n");delay_ms(1000);//让模块连接上自己的路由while(esp8266_send_cmd((u8*)"AT+CWJAP=\"226\",\"226226226\"",(u8*)"WIFI GOT IP",200));//printf("连接路由器成功\r\n");delay_ms(1000);//=0:单路连接模式     =1:多路连接模式while(esp8266_send_cmd((u8*)"AT+CIPMUX=0",(u8*)"OK",200)){printf("设置单路连接模式失败\r\n");}//printf("设置单路连接模式成功\r\n");delay_ms(1000);while(esp8266_send_cmd((u8*)"AT+CIPSTART=\"TCP\",\"192.168.124.66\",8080",(u8*)"OK",500));//printf("TCP连接成功\r\n");delay_ms(1000);//是否开启透传模式  0:表示关闭 1:表示开启透传esp8266_send_cmd((u8*)"AT+CIPMODE=1",(u8*)"OK",200);//printf("开启透传模式\r\n");esp8266_send_cmd((u8*)"AT+CIPSEND",(u8*)"OK",50);//printf("开启透传成功\r\n");
}

4. usart

void USART2_init(u32 bound)
{  NVIC_InitTypeDef NVIC_InitStructure;GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	// GPIOB时钟RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //串口3时钟使能USART_DeInit(USART2);  //复位串口3//USART2_TX   PB10GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PB10GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PB10//USART2_RX	  PB11GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PB11USART_InitStructure.USART_BaudRate = bound;//波特率一般设置为9600;USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;	//收发模式USART_Init(USART2, &USART_InitStructure); //初始化串口	3USART_Cmd(USART2, ENABLE);                    //使能串口 //使能接收中断USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断   //设置中断优先级NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器TIM2_Int_Init(1000-1,7200-1);		//10ms中断USART2_RX_STA=0;		//清零TIM_Cmd(TIM2,DISABLE);			//关闭定时器7}

5. time2

void TIM2_IRQHandler(void)
{ 	if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)//是更新中断{	 			   USART2_RX_STA|=1<<15;	//标记接收完成TIM_ClearITPendingBit(TIM2, TIM_IT_Update  );  //清除TIM2更新中断标志    TIM_Cmd(TIM2, DISABLE);  //关闭TIM2 }	    
}//通用定时器7中断初始化,这里时钟选择为APB1的2倍
//arr:自动重装值 psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz 
//通用定时器中断初始化 
void TIM2_Int_Init(u16 arr,u16 psc)
{	NVIC_InitTypeDef NVIC_InitStructure;TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//TIM2时钟使能    //定时器TIM2初始化TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值	TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_timTIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;  //TIM向上计数模式TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据指定的参数初始化TIMx的时间基数单位TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE ); //使能指定的TIM2中断,允许更新中断TIM_Cmd(TIM2,ENABLE);//开启定时器7NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器}

6. main

int main(void)
{unsigned char*	m=NULL;int k1,k2,k3,k4,flag,f1,f2,f3;delay_init();	    	 			//延时函数初始化	  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); 			//设置NVIC中断分组2:2位抢占优先级,2位响应优先级uart_init(115200);	 				//串口初始化为115200USART2_init(115200);	 				//串口初始化为115200esp8266_quit_trans();esp8266_start_trans();							//esp8266进行初始化GPIOB_Init();TIM3_PWM_Init(100-1,72-1);int i,j=15;flag=1;while(1){m=WIFI_Rece_Data();	if(flag == 1) {m[0]='S';flag = 0;}else if(m[0]=='F')  i=0;else if(m[0]=='L')  i=1;else if(m[0]=='R')  i=3;else if(m[0]=='S')  i=5;else if(m[0]=='B')  i=7;else if(m[0]=='u'&& m[1]=='p')  i=2;else if(m[0]=='u'&& m[1]=='d')  i=4;switch(i){case 0:f1=1;setpwm(j);forward();break;case 1:f2=1;k1=j-15;k2=j+15;if(k1<=0) 	k1=0;if(k2>=100) k2=100;setpwm1(k1,k2);if(f1==1)  turn_left();	if(f1==-1) turn_left1();	break;case 3:f3=1;k3=j+15;k4=j-15;if(k3>=100) k3=100;if(k4<=0) 	k4=0;setpwm1(k3,k4);if(f1==1)  turn_right();if(f1==-1) turn_right1();break;case 5:stop();	break;case 7:f1=-1;setpwm(j);back();break;case 2:if(f2==1) { k1+=2;k2+=10; if(k1>=30) k1=30; if(k2>=100) k2=100; setpwm1(k1,k2);delay_ms(20);f2=0;break;} else if(f3==1) { k3+=10;k4+=2; if(k3>=100) k3=100; if(k4>=30) k4=30; setpwm1(k3,k4);delay_ms(20);f3=0;break;} else {if(j>=100) j=100;	setpwm(j);j++;delay_ms(50);break;}case 4:if(f2==1) { k1-=2;k2-=5; if(k1<=0) k1=0; if(k2<=30) k2=30; setpwm1(k1,k2); delay_ms(20);f2=0; break;} else if(f3==1) { k3-=5;k4-=2; if(k3<=30) k3=30; if(k4<=0) k4=0; setpwm1(k3,k4); delay_ms(20); f3=0;break;} else{if(j<=0) j=0;setpwm(j);j--;delay_ms(50);break;}				}		}
}

三、QT部分

Server

server::server(QWidget *parent) :QWidget(parent),ui(new Ui::server)
{ui->setupUi(this);tcpserver=nullptr;tcpsocket=nullptr;//创建监听套接字tcpserver=new QTcpServer(this);//指定父对象 回收空间//bind+listentcpserver->listen(QHostAddress::Any,8080);//绑定当前网卡所有的ip 绑定端口 也就是设置服务器地址和端口号//服务器建立连接connect(tcpserver,&QTcpServer::newConnection,[=](){//取出连接好的套接字tcpsocket=tcpserver->nextPendingConnection();//获得通信套接字的控制信息QString ip=tcpsocket->peerAddress().toString();//获取连接的 ip地址quint16 port=tcpsocket->peerPort();//获取连接的 端口号QString temp=QString("[%1:%2] 客服端连接成功").arg(ip).arg(port);//显示连接成功ui->textEditRead->setText(temp);});
}void server::on_forward_clicked()
{if(tcpsocket==nullptr)  return ;QString str="F";tcpsocket->write(str.toUtf8().data());
}void server::on_back_clicked()
{if(tcpsocket==nullptr)  return ;QString str="B";tcpsocket->write(str.toUtf8().data());
}void server::on_turn_left_clicked()
{if(tcpsocket==nullptr)  return ;QString str="L";tcpsocket->write(str.toUtf8().data());
}void server::on_turn_right_clicked()
{if(tcpsocket==nullptr)  return ;QString str="R";tcpsocket->write(str.toUtf8().data());
}void server::on_stop_clicked()
{if(tcpsocket==nullptr)  return ;QString str="S";tcpsocket->write(str.toUtf8().data());
}void server::on_speed_up_clicked()
{if(tcpsocket==nullptr)  return ;QString str="up";tcpsocket->write(str.toUtf8().data());
}void server::on_speed_down_clicked()
{if(tcpsocket==nullptr)  return ;QString str="ud";tcpsocket->write(str.toUtf8().data());
}

四、遥控小车演示

基于STM32-Socket-Qt 遥控小车(一代)

程序源码

若需程序源码 可评论区留言QQ邮箱 或 直接私信即可

相关内容

热门资讯

埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
阳澄湖在哪里哪个省的 阳澄湖是... 点击题目下方苏州生活指南有用 有趣 有态度近期的阳澄湖度很高,3月24日,央视二套《第一时间》直播连...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
应用未安装解决办法 平板应用未... ---IT小技术,每天Get一个小技能!一、前言描述苹果IPad2居然不能安装怎么办?与此IPad不...
脚上的穴位图 脚面经络图对应的... 人体穴位作用图解大全更清晰直观的标注了各个人体穴位的作用,包括头部穴位图、胸部穴位图、背部穴位图、胳...
长白山自助游攻略 吉林长白山游... 昨天介绍了西坡的景点详细请看链接:一个人的旅行,据说能看到长白山天池全凭运气,您的运气如何?今日介绍...
猫咪吃了塑料袋怎么办 猫咪误食... 你知道吗?塑料袋放久了会长猫哦!要说猫咪对塑料袋的喜爱程度完完全全可以媲美纸箱家里只要一有塑料袋的响...
世界上最漂亮的人 世界上最漂亮... 此前在某网上,选出了全球265万颜值姣好的女性。从这些数量庞大的女性群体中,人们投票选出了心目中最美...
北京的名胜古迹 北京最著名的景... 北京从元代开始,逐渐走上帝国首都的道路,先是成为大辽朝五大首都之一的南京城,随着金灭辽,金代从海陵王...
金属硬度排行 各种金属硬度 世界上最硬的东西排名分别为硫化碳块,石墨烯,金刚石,金属玻璃和金属锇。这五种物体几乎是整个世界上最坚...
埃菲尔铁塔在哪 中国仿建埃菲尔... 2019年4月26日,广西南宁市,街头惊现一座巨型山寨版埃菲尔铁塔,高约20米,白色塔身,造型逼真,...
苗族的传统节日 贵州苗族节日有... 【岜沙苗族芦笙节】岜沙,苗语叫“分送”,距从江县城7.5公里,是世界上最崇拜树木并以树为神的枪手部落...