首页 > 其他分享 >基于stm32f103c8t6的蓝牙小车(可以控制车速,以及有数码管显示速度)

基于stm32f103c8t6的蓝牙小车(可以控制车速,以及有数码管显示速度)

时间:2024-08-04 23:25:16浏览次数:19  
标签:Pin TIM void 引脚 蓝牙 数码管 InitStructure stm32f103c8t6 GPIO

蓝牙模块的理解:

蓝牙可以理解为一个无线的串口,手机和单片机之间可以通过蓝牙来发送数据,控制单片机IO口,进而来控制小车,总体的逻辑是,手机发送数据给蓝牙,蓝牙将这个数据再发送给单片机。另外蓝牙的代码跟我们学的串口通信差不多。

usart2.c

#include "usart2.h"	  
 	 
void uart2_init( u32 bound )
{
	/* GPIO端口设置 */
	GPIO_InitTypeDef	GPIO_InitStructure;
	USART_InitTypeDef	USART_InitStructure;
 
 
	RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); 
	RCC_APB1PeriphClockCmd( RCC_APB1Periph_USART3, ENABLE );         /* 使能USART3,GPIOA时钟 */
 
	/* PB10 TXD3 */
	GPIO_InitStructure.GPIO_Pin	= GPIO_Pin_10;
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_AF_PP;
	GPIO_Init( GPIOB, &GPIO_InitStructure );
 
	/* PB11 RXD3 */
	GPIO_InitStructure.GPIO_Pin	= GPIO_Pin_11;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_IN_FLOATING;
	GPIO_Init( GPIOB, &GPIO_InitStructure );
 
 
	/* USART 初始化设置 */
	USART_InitStructure.USART_BaudRate		= bound;                                /* 串口波特率 */
	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( USART3, &USART_InitStructure );                                             /* 初始化串口1 */
	USART_Cmd( USART3, ENABLE );                                                            /* 使能串口 2 */
}

这里就是我的蓝牙模块的初始化代码,我用的是串口3,对应的RXD引脚是PB11,TXD引脚是PB10,详情看上面的代码。

蓝牙App的制作开发

相信很多小伙伴做这个项目更多是喜欢自己做一个遥控器,实现“自己生产化”,所以我就没有使用配套资料给我的app,自己做了一个。可以给大家参考下我自己制作的一个app

怎么制作这个app呢,我这个有链接,小伙伴可以自己去观看

EDA的蓝牙app制作视频

电机驱动模块:

stm32因为输出的电流电压比较小,所以我们 需要使用L298N模块来驱动电机,我这里使用的是直流电机。我大概说说怎么使用,L298N有4个IN端口,4个OUT端口,OUT是接电机的,OUT1 2是接一个电机的正负极,另外 OUT3 4接另外一个电机。IN端口接单片机IO端口。,输入不同的值可以让电机正反转,同时可以使用PWM模式来控制电机的转速。

具体的视频,我推荐一下链接,博主用的是51来讲解的,原理差不多,很容易懂:

L298N讲解

PWM调速

PWM设置占空比

这个板块针对的是一些小伙伴不怎么会使用stm32设置占空比的问题,我不过多讲述,我提供一个博主的视频,对大家有很大的帮助:

PWM设置

PWM.c

#include "stm32f10x.h"                  // Device header

void PWM_Init(void)
{
	    GPIO_InitTypeDef GPIO_InitStructure;
      TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
      TIM_OCInitTypeDef TIM_OCInitStructure;

      //使能定时器TIM4时钟,注意TIM4时钟为APB1
      RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM4, ENABLE);
      //使能PWM输出GPIO时钟
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB , ENABLE); 
                                                                          
      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;//定时器TIM4的PWM输出通道1,TIM4_CH1
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7;//定时器TIM4的PWM输出通道2,TIM4_CH2
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;//定时器TIM4的PWM输出通道3,TIM4_CH3
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

      GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;//定时器TIM4的PWM输出通道4,TIM4_CH4
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
      GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
      GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIO

      TIM_TimeBaseStructure.TIM_Period = 100 - 1;//arr;//自动重装值
      TIM_TimeBaseStructure.TIM_Prescaler =36 - 1;//psc; //时钟预分频数
      TIM_TimeBaseStructure.TIM_ClockDivision = 0;
      TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//TIM向上计数模式
      TIM_TimeBaseInit(TIM4, &TIM_TimeBaseStructure); //初始化TIM4
     
      //初始化TIM4_CH1的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;//??PWM??1
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;//??????
      TIM_OCInitStructure.TIM_Pulse = 0; //
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;//??????
      TIM_OC1Init(TIM4, &TIM_OCInitStructure);//???TIM4_CH1

      //初始化TIM4_CH2的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
       //TIM4_CH2初始化,OC2
      TIM_OC2Init(TIM4, &TIM_OCInitStructure);

       //初始化TIM4_CH3的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC3Init(TIM4, &TIM_OCInitStructure);

      //初始化TIM4_CH4的PWM模式
      TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
      TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
      TIM_OCInitStructure.TIM_Pulse = 0;
      TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High;
      TIM_OC4Init(TIM4, &TIM_OCInitStructure);

      //使能4个通道的预装载寄存器
      TIM_OC1PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC1
      TIM_OC2PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC2
      TIM_OC3PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC3
      TIM_OC4PreloadConfig(TIM4, TIM_OCPreload_Enable);//OC4
      TIM_ARRPreloadConfig(TIM4, ENABLE); //使能重装寄存器

      TIM_Cmd(TIM4, ENABLE);//使能定时器TIM4,准备工作 
}

数码管显示车速:

!!!!注意我使用的是共阳极数码管

LED.c

#include "stm32f10x.h"                  // Device header
#include "LED.h"
void LED_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_0 |GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
	//灯暗
	GPIO_SetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2|GPIO_Pin_0 |GPIO_Pin_3 |GPIO_Pin_4 |GPIO_Pin_5 |GPIO_Pin_6|GPIO_Pin_7);
}

void s0(void){
  // 设置所有引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_3);
  // 设置第7引脚为高电平
  GPIO_SetBits(GPIOA, GPIO_Pin_7| GPIO_Pin_6 );
}

void s1(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7);
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2);
}

void s2(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA, GPIO_Pin_2 | GPIO_Pin_5 | GPIO_Pin_7);
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3| GPIO_Pin_4| GPIO_Pin_6| GPIO_Pin_0);
}

void s3(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA, GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_7);
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_3| GPIO_Pin_2| GPIO_Pin_6| GPIO_Pin_0);
}

void s4(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA, GPIO_Pin_0 | GPIO_Pin_3 | GPIO_Pin_7| GPIO_Pin_4);
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6);
}

void s5(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA,  GPIO_Pin_1 | GPIO_Pin_7| GPIO_Pin_4);
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_0 |GPIO_Pin_3);
}


void s6(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA,  GPIO_Pin_1 | GPIO_Pin_7 );
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_0 |GPIO_Pin_3| GPIO_Pin_4);
}

void s7(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA,  GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_4 |GPIO_Pin_7 );
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}

void sz8(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA,  GPIO_Pin_7 );
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_4 |GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}


void s9(void){
  // 设置所有引脚为高电平,除了第0引脚和第2引脚
  GPIO_SetBits(GPIOA,  GPIO_Pin_7|GPIO_Pin_4  );
  // 设置第0引脚和第2引脚为低电平
  GPIO_ResetBits(GPIOA, GPIO_Pin_3| GPIO_Pin_5| GPIO_Pin_6|GPIO_Pin_2| GPIO_Pin_1|GPIO_Pin_0);
}


 
 

按键模块:

我需要对这里进行解释说明,我的板子上面有一个按钮,按下去,才可以正常使用车的功能,所以这里有一个按键模块

KEY.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"

void Key_Init(void)
{
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
	
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_15;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIOA, &GPIO_InitStructure);
}

uint8_t Key_GetNum(void)
{
	if (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0)//检测按键有没有按下
	{
		Delay_ms(20);
		while (GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_15) == 0);
		Delay_ms(20);
		return 1;
	}
	return 0;
}



小车运动模块

这里我需要解释一下,有些朋友可能会疑惑,只有电机,车怎么左右转起来的,其实这里有个秘诀,如果要左转的话,我只需要让左边的轮子不动或者向后转动,让右边的轮子转动起来就可以,简单概括就是右边的轮子要比左边的轮子运动快就可以实现了,然后我的一个轮子是自由轮子,具体看图:

上面那个是自由轮子

主函数模块:

main.c

#include "stm32f10x.h"                  // Device header
#include "Delay.h"
#include "robot.h"
#include "Key.h"
#include "LED.h"
uint8_t i;
uint16_t flag_key=0;
uint8_t state;
void speed_con(int t){
  if(state=='s'){makerobo_Spin_Left(t);}
	else if(state=='f'){makerobo_run(t);}
	else if(state=='t'){makerobo_Spin_Right(t);}
	else if(state=='l'){makerobo_Left(t);}
	else if(state=='p'){makerobo_brake();}
	else if(state=='r'){makerobo_Right(t);}
}
int main(void)
{
	int data;
	LED_Init();
	robot_Init();    // 机器人初始化
	Key_Init();      // 按键初始化
	uart2_init(9600);
	while (1)
	{
		if(Key_GetNum() == 1)
		{
			flag_key=!flag_key;
		}
		if(flag_key==1){
			if(USART_GetFlagStatus(USART3,USART_FLAG_RXNE)==1)     
		  {
			data=USART_ReceiveData(USART3);
			switch(data){//检测运动状态按键是否按下
				case 10:  //case多少是根据我设计的那个app决定的所以前面的视频需要先看一下
					makerobo_Spin_Left(100);
				  s9();
				  state='s';//state是记录车子当前运动的状态,方便后面我给他设置挡位时候,数码管可以显示出来
				break;
				case 11:
					makerobo_run(100);
				  s9();
					state='f';
				break;
				case 12:
					makerobo_Spin_Right(100);
					s9();
				  state='t';
				break;
				case 13:
					makerobo_Left(100);
					s9();
				  state='l';
				break;
				case 14:
					makerobo_brake();
				  s9();
				  state='p';
				break;
				case 15:
					makerobo_Right(100);
					s9();
				  state='r';
				break;
				case 16:
					makerobo_back(100);
				  s9();
				  state='b';
				break;		
			}
			if(data==1|data==2|data==3|data==4|data==5|data==6|data==7|data==8|data==9){ //检测挡位按键是否按下
				speed_con(data*10);
				if(data==1) s1(); //占空比10%,记为1档
				if(data==2) s2();
				if(data==3) s3();
				if(data==4) s4();
				if(data==5) s5();
				if(data==6) s6();
				if(data==7) s7();
				if(data==8) sz8();
				if(data==9) s9();
			}
		}
	}
}
	}

开发板原理图:

各位朋友,请给我点点免费的赞 谢谢支持啦

标签:Pin,TIM,void,引脚,蓝牙,数码管,InitStructure,stm32f103c8t6,GPIO
From: https://blog.csdn.net/jdjeng/article/details/140913331

相关文章

  • 1388、STM32单片机心率(脉搏)MAX30102血氧体温检测阈值报警无线蓝牙远程(程序+原理图+
    毕设帮助、开题指导、技术解答(有偿)见文未 目录方案选择单片机的选择显示器选择方案一、设计功能二、实物图三、原理图四、程序源码五、PCB图六、proteus仿真程序流程图:原理图文字讲解:参考论文:资料包括:需要完整的资料可以点击下面的名片加下我,找我要资源压缩......
  • 1386、STM32单片机心率(脉搏)体温检测阈值设置报警无线蓝牙远程设计(程序+原理图+PCB
    毕设帮助、开题指导、技术解答(有偿)见文未 目录方案选择单片机的选择显示器选择方案一、设计功能二、实物图三、原理图四、程序源码五、PCB图六、proteus仿真程序流程图:原理图文字讲解:参考论文:资料包括:需要完整的资料可以点击下面的名片加下我,找我要资源压缩......
  • Android Studio开发学习(七、蓝牙模块java)
    引言    上篇我们已经介绍了蓝牙模块相关布局,所以,今天我们来学习一下功能实现,如何打开关闭蓝牙。(这里DataActivity为蓝牙列表点击设备名连接后跳转界面函数,这里暂时没有设置,只是默认空白界面)先来介绍一下蓝牙相关概念        蓝牙是一种无线技术标准,用于短......
  • FPGA开发——数码管的使用(二)
    一、概述   在上一篇文章中我们针对单个数码管的静态显示和动态显示进行了一个设计和实现,这篇文章中我们针对多个数码管同时显示进行一个设计。这里和上一篇文章唯一不同的是就是数码管位选进行了一个改变,原来是单个数码管的显示,所以位选就直接赋值就可以了,但在本篇文章......
  • FPGA开发——按键控制数码管的设计
    一、概述按键控制数码管是一种常见的电子显示技术,它结合了按键输入与数码管显示的功能。在这一设计中,用户通过按下不同的按键来发送指令,这些指令随后被处理并转换为数码管上显示的数字或字符。按键通常作为输入设备,通过电路连接到微控制器(如FPGA、单片机等)的输入引脚,而数码管......
  • 【STM32 HAL库】HC-05 蓝牙通信
    【STM32HAL库】蓝牙通信理论模块功能接线应用CubeMX配置轮询模式发送DMA模式发送Keil5代码理论模块功能将复杂的蓝牙协议简化为串口透传即以HC-05作为串口与主机之间通信的桥梁,实现串口与主机的通信本质上就是无线的串口通信接线HC-05STM32TXRXRXTXGNDGNDV......
  • 基于bluez的蓝牙ble开发
    linux蓝牙协议栈bluez(https://github.com/bluez/bluez/tree/master),提供了丰富的蓝牙开发工具和示例。bluez5主要提供基于HCI和基于DBUS的接口,基于HCI的接口主要用于更细致控制蓝牙硬件模块,而基于DBUS的接口提供大量的蓝牙上层协议,能更好的管理蓝牙。轻量级开发:不使用glib、dbus,......
  • App Inventor 2 低功耗蓝牙 BlueToothLE 拓展中文文档(完整翻译加强版)
    低功耗蓝牙,也称为蓝牙LE或简称BLE,是一种类似于经典蓝牙的新通信协议,不同之处在于它旨在消耗更少的功耗和成本,同时保持同等的功能。因此,低功耗蓝牙是与耗电资源有限的物联网设备进行通信的首选。BluetoothLE扩展需要Android5.0或更高版本。BlueToothLE拓展中文文档入口......
  • 蓝牙耳机中来电铃声不同步/蓝牙耳机与扬声器来电铃声不一致
    在Android13上发现手机连接上蓝牙耳机后,有电话打进来,手机扬声器中播放的铃声与蓝牙耳机中的铃声不一致,蓝牙耳机播放嘟嘟嘟的铃声。根据网上搜索,这个与手机的inbandringing功能有关,该功能由isInbandRingingEnabled()方法控制:HeadsetService.javabooleanisInbandRingingE......
  • 300元内蓝牙耳机怎么选?四款百元平价必入机型盘点
    在当今市场上,蓝牙耳机品牌与型号众多,功能和设计各异,价格从几十元到上千元不等,使得消费者的选择范围既广泛又复杂,对于预算有限的用户来说,300元内蓝牙耳机怎么选?成为了许多消费者的难题,那么接下来的内容将帮助你在这个价位区间内作出明智的选择,我带来了四款百元平价必入机型盘点,......