当前位置:   article > 正文

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

stm32 socket


一、项目分析

1. 项目简介

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

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

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

2. 知识储备

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);
}	

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67

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);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45

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");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

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   PB10
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PB10
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	//复用推挽输出
  GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PB10
   
    //USART2_RX	  PB11
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);  //初始化PB11
	
	USART_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); //初始化串口	3
  

	USART_Cmd(USART2, ENABLE);                    //使能串口 
	
	//使能接收中断
  USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断   
	
	//设置中断优先级
	NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2 ;//抢占优先级3
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;		//子优先级3
	NVIC_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

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48

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_tim
	TIM_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);//开启定时器7
	
	NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		//子优先级2
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;			//IRQ通道使能
	NVIC_Init(&NVIC_InitStructure);	//根据指定的参数初始化VIC寄存器
	
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

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);	 				//串口初始化为115200
	USART2_init(115200);	 				//串口初始化为115200
	 
	esp8266_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;
					}				
		}		
	}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124

三、QT部分

Server

server::server(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::server)
{
    ui->setupUi(this);
    tcpserver=nullptr;
    tcpsocket=nullptr;
    //创建监听套接字
    tcpserver=new QTcpServer(this);//指定父对象 回收空间

    //bind+listen
    tcpserver->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());
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82

四、遥控小车演示

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

程序源码

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/2023面试高手/article/detail/630620
推荐阅读
相关标签
  

闽ICP备14008679号