基于STM32的蓝牙遥控小车:手机APP控制小车运动

发布时间:2024-12-19 08:32

空调遥控器没电了,可用手机蓝牙连接控制 #生活知识# #家庭维修常识# #空调维修服务#

这里写目录标题 一、智能双轮小车+蓝牙APP控制前后左右调速运动功能描述原理图设计PCB设计源码设计 二、更多功能小车网友推荐后开发...

在这里插入图片描述

一、智能双轮小车+蓝牙APP控制前后左右调速运动

功能描述

1、小车可以前后左右运动
2、可以调节小车的速度
3、使用两个电机驱动两个轮子,一个万向轮跟随运动
4、需要自己设计电机驱动电路,达到最小成本 (不超过1.5元)
5、设计一个手机APP可以蓝牙连接小车,进行控制

原理图设计

1、单片机最小系统电路,采用stm32f103c6t6单片机节省成本,包含复位电路、供电电路,下载接口
在这里插入图片描述

2、电源设计,电源可以用USB供电,也可以外接电池供电,4-7V都可以
加粗样式3、蓝牙模块电路,用来和手机进行通信,下发指令控制小车进行运动,当然小车也可以传输消息到手机进行显示,比如电量、速度等信息
在这里插入图片描述

4、电机驱动电路,这里是用了一个非常便宜的驱动芯片,大约1元一片的DRV8833,搭建一下外围电路就可以工作了,接线端子接入电机就可以正常驱动电机运转

在这里插入图片描述

PCB设计

下面就是我设计的PCB了,体积是非常小巧的,焊接好接上电机就可以正常使用啦
在这里插入图片描述
这是搭载到小车上的效果
在这里插入图片描述
小车的视频可以留意哔哩哔哩或者到我的咸鱼查看,账号名都是:化作尘my

源码设计

1、主函数代码设计
首先要初始化延时、串口、GPIO、电机驱动等外设
先让电机停止运转,while循环里面等待蓝牙指令处理

int main(void) { delay_init(); //延时函数初始化 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级 uart_init(9600);//串口初始化为115200usart2_init(usart2_baund);//串口2初始化为usart2_baund printf("uart_init OK\r\n"); GPIO_Config(); //GPIO初始化Drv8833_Init(); //电机驱动初始化set_drv8833_para(AIN_NUM,DIR_STOP,0);//停止电机转动set_drv8833_para(BIN_NUM,DIR_STOP,0);//停止电机转动 while(1){Query_IN_Response(); //蓝牙串口指令处理 delay_ms(1);} }

1234567891011121314151617

2、电机驱动代码
这里由于电机只有两个,比较少,为了灵活运用普通IO口驱动电机,我使用了GPIO模拟输出PWM的方法,用一个定时器定时10us,并设定参数让IO口在定时中断里面定时翻转,比如100个周期内高电平为50个低电平为50个,那么就得到一个周期为1ms,脉宽为50%的PWM

//驱动接口初始化 void Drv8833_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE); GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz#if 0TIM_PWM_Init();#else GPIO_InitStructure.GPIO_Pin = nSLEEP_PIN; GPIO_Init(nSLEEP_PORT, &GPIO_InitStructure); nSLEEP_DISABLE();#endif #if (DRV8833_NUM >= 1) GPIO_InitStructure.GPIO_Pin = AIN1_PIN; GPIO_Init(AIN1_PORT, &GPIO_InitStructure); AIN1_L(); GPIO_InitStructure.GPIO_Pin = AIN2_PIN; GPIO_Init(AIN2_PORT, &GPIO_InitStructure); AIN2_L(); GPIO_InitStructure.GPIO_Pin = BIN1_PIN; GPIO_Init(BIN1_PORT, &GPIO_InitStructure); BIN1_L(); GPIO_InitStructure.GPIO_Pin = BIN2_PIN; GPIO_Init(BIN2_PORT, &GPIO_InitStructure); BIN2_L(); #endif #if (DRV8833_NUM >= 2) GPIO_InitStructure.GPIO_Pin = CIN1_PIN; GPIO_Init(CIN1_PORT, &GPIO_InitStructure); CIN1_L(); GPIO_InitStructure.GPIO_Pin = CIN2_PIN; GPIO_Init(CIN2_PORT, &GPIO_InitStructure); CIN2_L(); GPIO_InitStructure.GPIO_Pin = DIN1_PIN; GPIO_Init(DIN1_PORT, &GPIO_InitStructure); DIN1_L(); GPIO_InitStructure.GPIO_Pin = DIN2_PIN; GPIO_Init(DIN2_PORT, &GPIO_InitStructure); DIN2_L(); #endif TIM2_Int_Init(100 - 1, 1);//10Us中断 } //定时器2中断服务程序 void TIM2_IRQHandler(void) //TIM2中断 {if (TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET) //检查指定的TIM中断发生与否:TIM 中断源{TIM_ClearITPendingBit(TIM2, TIM_IT_Update ); //清除TIMx的中断待处理位:TIM 中断源set_drv8833_ctrl();} } //设置DRV8833的参数 num 电机编号 dir 前后 speed 速度 void set_drv8833_para(WEL_NUM num,DIR_TypeDef dir,u8 speed) {drv[num].drv_speed = speed;drv[num].drv_dir = dir; }

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879

3、蓝牙控制部分代码,这里把接收到手机发过来的摇杆数据,处理成每个电机的速度、前后。

u8 Query_IN_Response(void) { u8 buff[USART2_MAX_RECV_LEN] = {0}; //接收数据缓冲区 u8 recv_flag = 0; // 1:接收完成 u16 Num = 0; u8 retn = 0; u8 i; u8 *ptemp = buff; if (USART2_RX_STA & 0x8000) //接收完成 { recv_flag = 1; Num = USART2_RX_STA & 0x3fff; memcpy(buff, (const char *)USART2_RX_BUF, Num); //拷贝数据 USART2_RX_BUF[Num] = '\0'; buff[Num] = '\0'; //加上字符串结束符; USART2_RX_STA = 0; //清楚接收完成标志 { // printf("\r\n接收完成: \""); // for(i = 0; i < Num; i++) // printf("%c", buff[i]); // printf("\"\r\n"); } } if (recv_flag) //接收完成 { if (strncmp((const char *)ptemp, "SPEED:", sizeof("SPEED:") - 1) == 0) //接收到正确的指令 { retn = 1; } else if (strncmp((const char *)ptemp, "DIR:", sizeof("DIR:") - 1) == 0) //接收到正确的指令 { retn = 2; } else if (strncmp((const char *)ptemp, "ROCKER:", sizeof("ROCKER:") - 1) == 0) //接收到正确的指令 { ptemp += sizeof("ROCKER:[") - 1; sysFlag.rocker.x = atoi((const char *)ptemp); //读取while(ptemp != NULL && *ptemp != '\0'){ptemp++;if(*ptemp == ','){sysFlag.rocker.y = atoi((const char *)(ptemp+1)); //读取break;}}if(sysFlag.rocker.y < 0){if(sysFlag.rocker.x>0){int speed1,speed2;if(sysFlag.rocker.x<PIANYI)sysFlag.rocker.x = 0;else sysFlag.rocker.x -= PIANYI;speed1 = (abs(sysFlag.rocker.y)+sysFlag.rocker.x/2);if(speed1 > 100 )speed1 = 100;speed2 = (abs(sysFlag.rocker.y)-sysFlag.rocker.x/2);if(speed2 < 0 )speed2 = 0;set_drv8833_para(AIN_NUM,DIR_FRONT,speed1);set_drv8833_para(BIN_NUM,DIR_FRONT,speed2);printf("右前 speed %d \t%d\r\n",speed1,speed2);}else{int speed1,speed2;if(sysFlag.rocker.x>-PIANYI)sysFlag.rocker.x = 0;else sysFlag.rocker.x += PIANYI;speed1 = (abs(sysFlag.rocker.y)+sysFlag.rocker.x/2);if(speed1 < 0 )speed1 = 0;speed2 = (abs(sysFlag.rocker.y)-sysFlag.rocker.x/2);if(speed2 > 99 )speed2 = 100;set_drv8833_para(AIN_NUM,DIR_FRONT,speed1);set_drv8833_para(BIN_NUM,DIR_FRONT,speed2);printf("左前 speed %d \t%d\r\n",speed1,speed2);}}else if(sysFlag.rocker.y > 0){if(sysFlag.rocker.x>0){int speed1,speed2;if(sysFlag.rocker.x<PIANYI)sysFlag.rocker.x = 0;else sysFlag.rocker.x -= PIANYI;speed1 = (abs(sysFlag.rocker.y)+sysFlag.rocker.x/2);if(speed1 > 100 )speed1 = 100;speed2 = (abs(sysFlag.rocker.y)-sysFlag.rocker.x/2);if(speed2 < 0 )speed2 = 0;set_drv8833_para(AIN_NUM,DIR_BACK,speed1);set_drv8833_para(BIN_NUM,DIR_BACK,speed2);printf("右后 speed %d \t%d\r\n",speed1,speed2);}else{int speed1,speed2;if(sysFlag.rocker.x>-PIANYI)sysFlag.rocker.x = 0;else sysFlag.rocker.x += PIANYI;speed1 = (abs(sysFlag.rocker.y)+sysFlag.rocker.x/2);if(speed1 < 0 )speed1 = 0;speed2 = (abs(sysFlag.rocker.y)-sysFlag.rocker.x/2);if(speed2 > 99 )speed2 = 100;set_drv8833_para(AIN_NUM,DIR_BACK,speed1);set_drv8833_para(BIN_NUM,DIR_BACK,speed2);printf("左后 speed %d \t%d\r\n",speed1,speed2);}}else if(sysFlag.rocker.y == 0 && sysFlag.rocker.x == 0){set_drv8833_para(AIN_NUM,DIR_STOP,0);set_drv8833_para(BIN_NUM,DIR_STOP,0);} //printf("rocker[%d, %d ]",sysFlag.rocker.x,sysFlag.rocker.y); retn = 3; } if(retn) { // printf("处理OK\r\n"); sysFlag.drv_chg_flag = 1; } } return retn; }

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116

5、手机APP设计
手机APP是使用的QT5设计,大家要是想要做这个项目的话一定要先下载一个APP看看是否可以搜索到蓝牙,因为有少部分网友说他的手机用这个APP是搜索不到蓝牙的,导致用不了这个APP进行连接,解决方法就是要换一个手机

在这里插入图片描述
在这里插入图片描述

二、更多功能小车网友推荐后开发…

网址:基于STM32的蓝牙遥控小车:手机APP控制小车运动 https://www.yuejiaxmz.com/news/view/516399

相关内容

基于STM32声控智能小车
基于STM32的智能家居系统设计与实现:手机APP与语音控制家电
基于STM32的智能家居环境监测与控制系统毕业设计
基于STM32智能家电无线控制系统设计
智能家居系统——基于STM32的智能控制方案
STM32语音控制小车(文末附代码)
手机遥控app大全
基于智能家居环境控制器的设计
基于STM32的智能教室控制系统设计
基于stm32的智能照明控制系统设计

随便看看