Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
hc-05蓝牙模块
串口接收
星火1号_spark_星火一号_开发板
[RT-Thread x 大学生夏令营]基于星火一号的蓝牙控制智能小车与掌上游戏机
发布于 2023-07-26 19:06:54 浏览:985
订阅该版
[tocm] RT-Thread夏令营实践作品设计文档 组号: 34 项目名称: 基于星火一号的蓝牙控制智能小车与掌上游戏机 小组成员:冯卓(组长)、张玉敏、周沛聪、邓恺琪 # 一、技术方案 ## 1、材料清单: RT-Spark 星火一号、STM32F103C8T6开发板、L298N、HC-05蓝牙模块、F105面包板、DC稳压模块、若干杜邦线 ## 2、技术路线与设计逻辑: **蓝牙控制智能小车:** (1) 初始化:启动小车时进行所有组件的初始化,包括传感器、电机驱动器和蓝牙通信模块等。 (2) 连接设置:在移动设备上安装相应的控制应用程序,并与小车的蓝牙模块建立连接。 (3) 用户界面:提供用户友好的界面,使用户可以直观地控制小车的移动、遥测数据和传感器反馈等。 (4) 控制处理:接收通过蓝牙通信发送的控制指令,并解析这些指令以确定小车的移动方向、速度和其他操作。 (5) 运动控制:根据接收的指令,结合车辆当前状态和环境信息,计算转向角度和速度,并发送控制信号给底盘电机驱动器。 (6) 反馈与更新:将实时数据和状态信息发送回移动设备,供用户查看或采取进一步操作,也用于进一步优化算法和改进设计。 **掌上贪吃蛇游戏机:** (1) 显示屏幕:利用星火一号上的LCD显示屏来显示。 (2) 控制按键:设计合适的按钮布局以实现游戏的控制。一般需要包括方向键(上、下、左、右)和一个确定键(如开始/暂停键)。这些按钮可以通过外部中断引脚与微控制器连接。 # 二、项目介绍 ## 1、作品简介: **蓝牙控制智能小车:** (1) 本项目基于星火一号和STM32F103C8T6实现了一款蓝牙控制智能小车。 (2) 通过使用蓝牙模块与手机进行通信,实现对小车的远程控制。 (3) 小车具备多种功能,包括前进、后退、左转、右转等。 **掌上贪吃蛇游戏机:** (1) 基于星火一号的掌上贪吃蛇游戏机是一款便携式游戏设备。 (2) 通过使用星火一号上的按键,实现对贪吃蛇的方向操作。 (3) 利用星火一号的LCD屏来显示丰富有趣的游戏界面。 ## 2、硬件整体框架设计原理图: **蓝牙控制智能小车:** ![硬件原理图.png](https://oss-club.rt-thread.org/uploads/20230726/321a76bbfe8288ea682948d66b241aef.png.webp) (1) 使用STM32单片机作为主控制器,具有高性能和低功耗的特点。 (2) 配置蓝牙模块与单片机进行通信。 (3) 添加电机驱动模块,控制小车运动。 ![小车实物图.png](https://oss-club.rt-thread.org/uploads/20230726/8ddae30a3227242af2bbf92b01073cd3.png.webp) 2.1 单片机与蓝牙模块间的数据传输示意图: ![数据传输示意图.png](https://oss-club.rt-thread.org/uploads/20230726/35bfe1123badfe1fde856c8da2db6633.png.webp) 2.2 L298N逻辑电平表: ![L298N.png](https://oss-club.rt-thread.org/uploads/20230726/a2243071687f7305e632d5108273d246.png) 2.3 HC-05蓝牙模块: ![HC-05蓝牙模块.jpg](https://oss-club.rt-thread.org/uploads/20230726/2922070a1f9cd51f48d1d235097ee4db.jpg) **掌上贪吃蛇游戏机:** ![贪吃蛇硬件设计.png](https://oss-club.rt-thread.org/uploads/20230726/91c9e90252f0d5307b9725cc47368737.png.webp) ![贪吃蛇实物图.jpg](https://oss-club.rt-thread.org/uploads/20230726/e968ffd45bed0e5bb8d5743d49c119a3.jpg.webp) ## 3、软件设计流程框架图: **掌上贪吃蛇游戏机:** ![贪吃蛇设计框架图.png](https://oss-club.rt-thread.org/uploads/20230726/0b4e150f839439e89bd7594c4e7aa594.png) **蓝牙控制智能小车:** ![小车设计框架图.png](https://oss-club.rt-thread.org/uploads/20230726/36232d731e75d47779af67a42bd5a0a1.png.webp) (1) 编写嵌入式C语言程序,控制STM32单片机的各个功能模块。 (2) 利用L298N控制电机驱动模块,实现对小车运动的控制。 (3) 通过蓝牙串口通信协议,与手机进行数据传输和通信。 ## 4、代码实现 **蓝牙控制智能小车:** **(1)motor.c函数** ```c #include "stm32f10x.h" // Device header #include "pwm.h" void Motor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2 | GPIO_Pin_3|GPIO_Pin_4; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); GPIO_SetBits(GPIOA, GPIO_Pin_1|GPIO_Pin_3); PWM_Init_Motor(); } void Go() { GPIO_SetBits(GPIOA, GPIO_Pin_2); GPIO_ResetBits(GPIOA, GPIO_Pin_1); GPIO_SetBits(GPIOA, GPIO_Pin_4); GPIO_ResetBits(GPIOA, GPIO_Pin_3); } void Back() { GPIO_SetBits(GPIOA, GPIO_Pin_1); GPIO_ResetBits(GPIOA, GPIO_Pin_2); GPIO_SetBits(GPIOA, GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_4); } void Left() { GPIO_SetBits(GPIOA, GPIO_Pin_1); GPIO_ResetBits(GPIOA, GPIO_Pin_2); GPIO_SetBits(GPIOA, GPIO_Pin_4); GPIO_ResetBits(GPIOA, GPIO_Pin_3); } void Right() { GPIO_SetBits(GPIOA, GPIO_Pin_2); GPIO_ResetBits(GPIOA, GPIO_Pin_1); GPIO_SetBits(GPIOA, GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_4); } void Stop() { GPIO_ResetBits(GPIOA, GPIO_Pin_1); GPIO_ResetBits(GPIOA, GPIO_Pin_2); GPIO_ResetBits(GPIOA, GPIO_Pin_3); GPIO_ResetBits(GPIOA, GPIO_Pin_4); } ``` **(2)usart.c函数** ```c #include "stm32f10x.h" #include "stdio.h" void USART_init(uint32_t bound) { GPIO_InitTypeDef GPIO_InitStruct; //定义GPIO结构体变量 USART_InitTypeDef USART_InitStruct; //定义串口结构体变量 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_USART1,ENABLE); //使能GPIOC的时钟 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; //配置TX引脚 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP; //配置PA9为复用推挽输出 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //配置PA9速率 GPIO_Init(GPIOA,&GPIO_InitStruct); //GPIO初始化函数 GPIO_InitStruct.GPIO_Pin=GPIO_Pin_10; //配置RX引脚 GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IN_FLOATING; //配置PA10为浮空输入 GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz; //配置PA10速率 GPIO_Init(GPIOA,&GPIO_InitStruct); //GPIO初始化函数 USART_InitStruct.USART_Mode=USART_Mode_Tx|USART_Mode_Rx; //发送接收模式 USART_InitStruct.USART_Parity=USART_Parity_No; //无奇偶校验 USART_InitStruct.USART_BaudRate=bound; //波特率 USART_InitStruct.USART_StopBits=USART_StopBits_1; //停止位1位 USART_InitStruct.USART_WordLength=USART_WordLength_8b; //字长8位 USART_InitStruct.USART_HardwareFlowControl=USART_HardwareFlowControl_None; //无硬件数据流控制 USART_Init(USART1,&USART_InitStruct); //串口初始化函数 USART_Cmd(USART1,ENABLE); //使能USART1 } int fputc(int ch,FILE *f) //printf重定向函数 { USART_SendData(USART1,(uint8_t)ch); //发送一字节数据. while(USART_GetFlagStatus(USART1,USART_FLAG_TXE) == RESET); //等待发送完成 return ch; } ``` **(3)main.c函数** #include "stm32f10x.h" // Device header #include "led.h" #include "delay.h" #include "usart.h" #include "motor.h" #include "pwm.h" int main() { LED_Init(); Delay_Init(); Motor_Init(); USART_init(9600); PWM_Init_Motor(); TIM3_Init(); PWM_SetCompareM3(0); PWM_SetCompareM4(0); while (1) { // 从蓝牙模块接收数据并根据数据控制电机 while (USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET); uint8_t RX_Data = USART_ReceiveData(USART1); if (RX_Data == '1') { Go(); printf("Go\r\n"); PWM_SetCompareM3(8000); // 设置M3电机速度 PWM_SetCompareM4(8000); // 设置M4电机速? Delay_ms(500); PWM_SetCompareM3(0); PWM_SetCompareM4(0); } else if (RX_Data == '2') { Back(); printf("Back\r\n"); PWM_SetCompareM3(5000); // 设置M3电机速度 PWM_SetCompareM4(5000); // 设置M4电机速度 Delay_ms(500); PWM_SetCompareM3(0); PWM_SetCompareM4(0); } else if (RX_Data == '3') { Left(); printf("Left\r\n"); PWM_SetCompareM3(2000); // 设置M3电机速度 PWM_SetCompareM4(8000); // 设置M4电机速度 Delay_ms(300); PWM_SetCompareM3(0); PWM_SetCompareM4(0); } else if (RX_Data == '4') { Right(); printf("Right\r\n"); PWM_SetCompareM3(8000); // 设置M3电机速度 PWM_SetCompareM4(2000); // 设置M4电机速度 Delay_ms(300); PWM_SetCompareM3(0); PWM_SetCompareM4(0); } else { Stop(); printf("Stop\r\n"); PWM_SetCompareM3(0); // 停止M3电机 PWM_SetCompareM4(0); // 停止M4电机 Delay_ms(500); PWM_SetCompareM3(0); PWM_SetCompareM4(0); } } } **掌上贪吃蛇游戏:** ```c /* * Copyright (c) 2006-2021, RT-Thread Development Team * * SPDX-License-Identifier: Apache-2.0 * * Change Logs: * Date Author Notes * 2023-5-10 ShiHao first version */ #include
#include
#include
#include
#include
#include
#include
#include
#include
#define PIN_KEY0 GET_PIN(C, 0) // PC0: KEY0 --> KEY 0,1,4////5 #define PIN_KEY1 GET_PIN(C, 1) // PC0: KEY0 --> KEY 0,1,4////5 #define PIN_KEY2 GET_PIN(C, 4) // PC0: KEY0 --> KEY 0,1,4////5 #define PIN_KEY3 GET_PIN(C, 5) // PC0: KEY0 --> KEY 0,1,4////5 #define PIN_LED_R GET_PIN(F, 12) #define DBG_TAG "main" #define DBG_LVL DBG_LOG #include
#define SNAKESIZE 100//蛇的身体最大节数 #define MAPWIDTH 240 //宽度 #define MAPHEIGHT 240//高度 //用来判断蛇是否吃掉了食物,这一步很重要,涉及到是否会有蛇身移动的效果以及蛇身增长的效果 volatile int changeFlag = 0; volatile int key = 3; int sorce = 0;//记录玩家的得分 //食物的坐标 struct { int x; int y; }food; //蛇的相关属性 struct { int speed;//蛇移动的速度 int len;//蛇的长度 int x[SNAKESIZE];//组成蛇身的每一个小方块中x的坐标 int y[SNAKESIZE];//组成蛇身的每一个小方块中y的坐标 }snake; void drawMap() { //打印上下边框 for (int i = 0; i <= MAPWIDTH/16+4; i++)//i+=2是因为横向占用的是两个位置 { //将光标移动依次到(i,0)处打印上边框 lcd_show_string(i*12,0,16,"@"); //将光标移动依次到(i,MAPHEIGHT)处打印下边框 lcd_show_string(i*12,MAPHEIGHT-16,16,"@"); } //打印左右边框 for (int i = 1; i < MAPHEIGHT/16; i++) { //将光标移动依次到(0,i)处打印左边框 lcd_show_string(0,i*16,16,"@"); //将光标移动依次到(MAPWIDTH, i)处打印左边框 lcd_show_string(MAPHEIGHT-16,i*16,16,"@"); } //随机生成初试食物 while (1) { srand((unsigned int)time(NULL)); food.x = rand() % (MAPWIDTH/16)*16 +16; food.y = rand() % (MAPHEIGHT/16)*16 +16; //生成的食物横坐标的奇偶必须和初试时蛇头所在坐标的奇偶一致,因为一个字符占两个字节位置,若不一致 //会导致吃食物的时候只吃到一半 if (food.x % 2 == 0) break; } //将光标移到食物的坐标处打印食物 lcd_show_string(food.x, food.y,16,"*"); //初始化蛇的属性 snake.len = 3; snake.speed = 2; //在屏幕中间生成蛇头 snake.x[0] = 160;//x坐标为偶数 snake.y[0] = 160; //打印蛇头 lcd_show_string(snake.x[0], snake.y[0],16,"@"); //生成初始的蛇身 for (int i = 1; i < snake.len; i++) { //蛇身的打印,纵坐标不变,横坐标为上一节蛇身的坐标值+2 snake.x[i] = (snake.x[i - 1] + 16); snake.y[i] = snake.y[i - 1]; lcd_show_string(snake.x[i], snake.y[i],16,"@"); } return; } void createFood() { if (snake.x[0] == food.x && snake.y[0] == food.y)//蛇头碰到食物 { //蛇头碰到食物即为要吃掉这个食物了,因此需要再次生成一个食物 int flag = 1; srand((unsigned int)time(NULL)); food.x = rand() % (MAPWIDTH/16-1)*16 ; food.y = rand() % (MAPHEIGHT/16-1)*16 ; //随机生成的食物不能在蛇的身体上 for (int i = 0; i < snake.len; i++) { if (snake.x[i] == food.x && snake.y[i] == food.y) { flag = 0; break; } } lcd_show_string(food.x, food.y,16,"*"); snake.len++;//吃到食物,蛇身长度加1 sorce += 10;//每个食物得10分 changeFlag = 1;//很重要,因为吃到了食物,就不用再擦除蛇尾的那一节,以此来造成蛇身体增长的效果 } int pre_key = key;//记录前一个按键的方向 if (changeFlag == 0) { lcd_show_string(snake.x[snake.len - 1], snake.y[snake.len - 1],16," "); } //将蛇的每一节依次向前移动一节(蛇头除外) for (int i = snake.len - 1; i > 0; i--) { snake.x[i] = snake.x[i - 1]; snake.y[i] = snake.y[i - 1]; } //打印出蛇头 lcd_show_string(snake.x[0], snake.y[0],16,"@"); //由于目前没有吃到食物,changFlag值为0 changeFlag = 0; //绘制食物 //判断蛇头应该往哪个方向移动 switch (pre_key) { case 3: snake.x[0] -= 16;//往左 break; case 4: snake.x[0] += 16;//往右 break; case 1: snake.y[0]=snake.y[0]-16;//往上 break; case 2: snake.y[0]=snake.y[0]+16;//往下 break; } return; } rt_bool_t snakeStatus() { //蛇头碰到上下边界,游戏结束 if (snake.y[0] == 16|| snake.y[0] == MAPHEIGHT/16-1) return RT_ERROR; //蛇头碰到左右边界,游戏结束 if (snake.x[0] == 16 || snake.x[0] == MAPWIDTH/16-1) return RT_ERROR; //蛇头碰到蛇身,游戏结束 for (int i = 1; i < snake.len; i++) { if (snake.x[i] == snake.x[0] && snake.y[i] == snake.y[0]) return RT_ERROR; } return RT_EOK; } void keyDown(void *args) { rt_kprintf("key %d \r\n",(int)args); key = (int)args; } int main(void) { drawMap(); rt_pin_mode(PIN_KEY0, PIN_MODE_INPUT_PULLUP); rt_pin_mode(PIN_KEY1, PIN_MODE_INPUT_PULLUP); rt_pin_mode(PIN_KEY2, PIN_MODE_INPUT_PULLUP); rt_pin_mode(PIN_KEY3, PIN_MODE_INPUT_PULLUP); rt_pin_attach_irq(PIN_KEY0, PIN_IRQ_MODE_FALLING, keyDown, 3); rt_pin_attach_irq(PIN_KEY1, PIN_IRQ_MODE_FALLING, keyDown, 2); rt_pin_attach_irq(PIN_KEY2, PIN_IRQ_MODE_FALLING, keyDown, 4); rt_pin_attach_irq(PIN_KEY3, PIN_IRQ_MODE_FALLING, keyDown, 1); rt_pin_irq_enable(PIN_KEY0, PIN_IRQ_ENABLE); rt_pin_irq_enable(PIN_KEY1, PIN_IRQ_ENABLE); rt_pin_irq_enable(PIN_KEY2, PIN_IRQ_ENABLE); rt_pin_irq_enable(PIN_KEY3, PIN_IRQ_ENABLE); while (1) { if (snakeStatus()) break; createFood(); rt_thread_mdelay(500); } lcd_show_string(MAPWIDTH / 2-32, MAPHEIGHT / 2,16,"Game Over!"); lcd_show_string(MAPWIDTH / 2-32, MAPHEIGHT / 2+16,16,"Score:"); rt_thread_mdelay(5000); return 0; } ``` ## 5、功能实现 **蓝牙控制智能小车:** **多方式远程控制** (1)手机上安装专用APP,连接蓝牙模块。通过APP页面点击按钮,向小车发送指令。 (2)通过星火一号与STM32F103C8T6之间的蓝牙通信,用星火一号输出信号控制小车,星火一号输出的信号可以通过:①按键控制(上下左右键);②六轴传感器控制(获取星火板的倾斜角度) (3)小车接收到指令后,根据指令控制电机驱动模块,实现对小车的运动。 **掌上贪吃蛇游戏机:** (1)贪吃蛇游戏逻辑:实现贪吃蛇游戏的基本逻辑,包括贪吃蛇的移动、食物的生成与消失、游戏得分的计算等。 (2)屏幕显示:通过星火一号上的LCD屏,将贪吃蛇游戏画面实时显示在屏幕上,并根据用户的操作更新画面。 (3)按钮控制:检测玩家按下的按钮,并根据按钮进行相应的移动操作,例如按下“向左”则使得贪吃蛇向左移动一格。 ## 6、技术亮点 **蓝牙控制智能小车:** (1)利用星火一号和STM32F103C8T6单片机实现了蓝牙通信和智能控制。 (2)设计简单、操作便捷,适用于各种场景。 (3)此外,我们还为用户设计了兼具美感和简洁的操作界面。用户在手机上下载HC蓝牙助手APP,即可连接HC-05蓝牙模块来控制小车运动: ![手机app控制.jpg](https://oss-club.rt-thread.org/uploads/20230726/c27e5d9fe0f61df57a7020afdfe9dae2.jpg) **掌上贪吃蛇游戏机:** (1) 硬件设计:采用星火一号作为主控,具有强大的处理能力和丰富的硬件资源。电路板设计精简紧凑,易于携带。LCD显示屏和按键布局合理,能够提供良好的用户体验。 (2) 软件开发:利用RT-Thread studio平台的开发环境,基于C语言进行软件编程。通过编写控制逻辑和图形界面,实现了经典的贪吃蛇游戏功能。游戏流畅且操作简单,适合不同年龄段的玩家。 (3) 电源管理:设备采用锂电池供电,具有较长的续航时间。同时添加了电池保护电路,确保使用安全可靠。 (4) 可拓展性:硬件接口留有扩展空间,可以添加更多的功能模块,如音频输出、外部存储等。同时,软件代码具备良好的可维护性和可拓展性。 # 三、小组分工 **蓝牙控制智能小车:** 主体逻辑编写:张玉敏 硬件部分组装:周沛聪 配置蓝牙模块:张玉敏、周沛聪 **掌上贪吃蛇游戏机:** 主体逻辑编写:冯卓、邓恺琪 PPT制作和设计文档编写:邓恺琪 # 四、总结与展望 **蓝牙控制智能小车方面:** (1)项目成功实现了基于星火一号和STM32F103C8T6的蓝牙控制智能小车的设计与开发。 (2)在以后的工作中,可以进一步优化系统性能,丰富小车的功能。 (3)希望本项目能够为智能交通系统和人工智能领域的发展做出贡献。 **掌上贪吃蛇游戏机方面:** (1)该掌上贪吃蛇游戏机在制作过程中充分发挥了STM32单片机的优势,通过合理的软硬件设计,实现了一款功能完善且易于操作的小型游戏设备。 (2)未来希望进一步优化电源管理:提高电池寿命,缩小外形尺寸,增加便携性和使用舒适度。 (3)基于星火一号的掌上贪吃蛇游戏机在技术和市场方面都具有较大的发展空间。随着技术的不断创新和用户需求的变化,该游戏机有望成为一款深受欢迎的小型游戏设备,并拓展到更广阔的市场领域。
3
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
zym_0208
这家伙很懒,什么也没写!
文章
1
回答
0
被采纳
0
关注TA
发私信
相关文章
1
STM32F103RCT6 串口接收数据不正确
2
串口怎样接收int类型数据?
3
串口缓存怎么清除????
4
STM32F407zgt6的串口
5
串口一边读数据,一边写数据
6
RT-thread studio串口发送,接收只能最大长度3位
7
micropython库串口问题
8
串口接受不定长数据为什么只返回第一个字节?
9
Ymodem的msh命令ry希望添加能自定义保存路径选项
10
libmodbus主机接收数据概率性丢失前3个字节和最后一个字节
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
I2C_IIC
ESP8266
UART
WIZnet_W5500
ota在线升级
cubemx
PWM
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
C++_cpp
MicroPython
本月问答贡献
出出啊
1518
个答案
343
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
5
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部