嵌入式项目:STM32平衡车详解 (基础知识篇) (基于STM32F103C8T6)

news2024/11/16 0:35:48

前言:

本文是基于B站草履虫编写的平衡车相关内容,包括模块和基础知识,结合代码进行讲解,将知识进行汇总

(由于本篇内容较长,请结合目录使用)

注:基于开源精神,本文仅供学习参考


目录

前言:

本文是基于B站草履虫编写的平衡车相关内容,包括模块和基础知识,结合代码进行讲解,将知识进行汇总

注:基于开源精神,本文仅供学习参考

1.基础知识

1.1输出模式

1.1.1推挽输出

1.1.2开漏输出

1.1.3复用推挽和开漏输出

1.2电阻

1.2.1 上拉电阻

1.2.2下拉电阻

1.3IIC通信协议(I2C)

1.3.1总线的概念

1.3.2 IIC通信规则

1.3.3IIC通信数据的发送和接收

1.4欧拉角

1.5H桥驱动电路

1.5.1基本电路图

1.5.2正反转

1.5.3调速

1.5.4死区

1.5.5刹车

1.6USART串口通信

1.6.1基本原理

1.6.2波形原理

2.点亮LED

2.1模块原理图

2.2工程

2.2.1配置外部时钟

2.2.2配置引脚

2.2.3下载程序

2.2.4创建工程

3.OLED模块

3.1模块配置

3.2模块原理图

3.3工程

3.3.1配置通信引脚

3.3.2配置时钟 

3.3.3配置OLED驱动代码

3.3.4简单改写驱动配置

3.3.5显示数字

3.3.6显示字符串

3.3.7显示汉字

3.3.8使用PCtoLCD2002生成汉字编码

3.3.9测试代码和现象

4.MPU6050

4.1MPU6050工作原理

4.2陀螺仪传感器

4.3加速度传感器

4.4精确欧拉角

4.5模块原理介绍

4.6模块原理图

4.7工程

4.7.1创建工程

4.7.2设置软件IIC通信

4.7.3添加.c文件

4.7.4添加.h文件

4.7.5详解代码与现象

5.超声波模块

5.1基本工作原理

5.2模块原理图

5.3工程

5.3.1思路

5.3.2创建工程

5.3.3配置工程

5.3.4使能内部时钟

5.3.5生成代码

5.3.5创建模块文件

 5.3.6代码

5.3.7现象

6.电机驱动

6.1TB6612驱动模块

6.1.2TB6612的引脚说明

6.1.3驱动原理

6.2工程

6.2.1创建工程

6.2.2打开定时器TIM

6.2.3配置预分频系数

6.2.4配置占空比

6.2.5配置控制方向GPIO

6.2.6创建模块文件

6.2.7代码

6.2.8现象

7.编码器测速

8.蓝牙模块

8.1JDY-31蓝牙模块

8.2模块原理图

8.3工程

8.3.1创建Uart文件

8.3.2配置USART

8.3.3生成代码

8.3.4发送数据

8.3.5缓存数据

8.3.6接收中断

​编辑

总结(必看):


1.基础知识

1.1输出模式

1.1.1推挽输出

如图推挽输出内部结构,PMOS管和NMOS管同一时间只有一个管子会导通

当PMOS管导通,此时输出一个高电平(VCC),称之为推

同理,当NMOS管导通,此时输出一个低电平(接地),称之为挽

1.1.2开漏输出

如图为开漏输出,与推挽输出相比,开漏少了一个PMOS管

当NMOS导通时,此时输出一个低电平(接地)

当NMOS断开时,此时电路为高阻态的状态(此时两个MOS管都为截断状态,可被视为电阻无穷大)

开漏输出不具有高电平的输出能力,所以我们外接一个上拉电阻(下面会讲)

使电路具备输出高电平的能力

1.1.3复用推挽和开漏输出

当我们使用高频芯片内部外设时(每秒钟电平变化上万次)

像 PWM、I2C、USART 等

使用复用功能会极大方便我们的编程

1.2电阻

1.2.1 上拉电阻

作用:将电路电平提升至一个高电平的状态(可将不确定电平拉为高电平)

1.2.2下拉电阻

作用:默认状态让电路为低电平,输入高电平时也可以让电路呈高电平状态

1.3IIC通信协议(I2C)

1.3.1总线的概念

非总线通信一般有:串口通信等

总线通信一般有:I2C通信等

总线优点:可以很轻松的增加与芯片通信的通信模块数量

1.3.2 IIC通信规则

这里我们着重介绍I2C (IIC - Inter - Integrated Circuit 内部集成电路)

SCL:传输时钟信号

SDA:传输数据信号

通信规则:

1.所有设备SCL/SDA引脚必须连接到主线SCL/SDA线上

2.同一时间只允许一个设备向外发送数据

3.仅主机主动产生SCL信号控制波特率(通信速度)

4.仅主机主动发起数据传输,从机无控制权(主机主动发送数据或接收数据)

5.传输方向:主机->从机,从机->主机,不存在从机->从机

1.3.3IIC通信数据的发送和接收

从机地址最后一个比特位(x)表示数据通信方向:

x=0:主机发数据给从机

x=1:主机从 从机读取数据

1.4欧拉角

欧拉角:以运动物体建立坐标系,通过绕轴旋转来表示运动物体当前的姿态

Yaw -偏航角:表示飞机绕Z轴旋转的角度,决定了飞机在水平方向上的朝向(决定飞机航行向)

Roll-翻滚角:表示飞机绕X轴旋转的角度

Pitch -俯仰角:表示飞机绕Y轴旋转的角度

一般我们可以通过加速度计和陀螺仪测量欧拉角

1.5H桥驱动电路

1.5.1基本电路图

Q1和Q3称为上桥

Q2和Q4称为下桥

单片机的4个IO口分别控制H桥的四个MOS(Qx)管,就可以实现电机的正反转、调速、刹车

(M为电机)

1.5.2正反转

打开Q1和Q4(假设此情况为正转)

电流方向Q1->M->Q4(如图所示)

打开Q3和Q2(那么此情况为反转)

1.5.3调速

单片机的PWM的输入可以给到上桥也可以给到下桥

调节PWM的占空比,占空比越大,电机转速越大,占空比越小电机转速越小

占空比即PWM在一个周期中高电平的时间与单位周期的比值

1.5.4死区

这里不过多解释,本质就是,单边上下桥不能同时导通(例如Q1和Q2不能同时导通)

否则会烧坏模块(即电源和GND短接)

1.5.5刹车

刹车基本原理:电机正负极相接

在H桥中我们可以同时打开两个上桥或两个下桥,实现刹车

1.6USART串口通信

1.6.1基本原理

在单片机中我们常用Tx表示发送端,Rx表示接收端,USART串口通信将Tx和Rx用导线相接

1.6.2波形原理

发送和接收的每条数据都有一条方形波

一条数据包括一个起始位和一个停止位

起始位永远是低电平,停止位永远是高电平

高电平发送二进制1

低电平发送二进制0

1-8为位代表数据位,为二进制,按十进制数值来算,最大可发送数字128,这个数字对应ASCII表

并且是倒过来读数

此图数据为01000001,对应ASCII码值为'A'

注意两个设备实现USART串口通信必须波特率相同


2.点亮LED

2.1模块原理图

2.2工程

2.2.1配置外部时钟

 使用外部时钟的原因:比内部时钟更精准,所以通常情况我们都会使用外部时钟

打开STM32CubeMX并配置外部晶振(Crystal/Ceramic Resonator)

并将HCLK设置成72MHz(最大)

2.2.2配置引脚

打开PC13引脚

接着配置PC13引脚的模式

GPIO Output level  -> Low

GPIO Mode -> Push Pull

GPIO  Pull-up/Pull-down -> No

Maximum output speed -> High

User Label ->LED

1. 根据上面的原理图,PC13连接LED负极,也就是说PC13高电平LED会灭,低电平LED就会亮

2.输出模式默认是推挽输出,开漏输出用的不多,特殊情况再用

3.推挽输出不需要上下拉电阻,推挽相当于直接接负极或正极

4.点亮LED对速度(芯片功耗)无要求,特殊情况再讨论

5.给PC13重新起名字 LED

2.2.3下载程序

在这里我们选择Serial Wire 的下载方式

因为我们的芯片就是通过电脑连接芯片SWCLK和SWDIO引脚下载程序的

2.2.4创建工程

注意IDE这一栏选择MDK-ARM

接着生成代码

驱动已经用软件配置好了,下面写一下主函数

int main(void)
{

  
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
 
  while (1)
  {
		HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); //亮
		HAL_Delay(500); //延时500毫秒
		HAL_GPIO_WritePin(LED_GPIO_Port,LED_Pin,GPIO_PIN_RESET); //灭
		HAL_Delay(500); 	
  }

}

接着编译,调试(烧录)就行了


3.OLED模块

3.1模块配置

本项目使用的OLED模块配置

屏幕大小:0.96寸

像素点:128*64

PIN:

GND:OLED电源接地

VCC:OLED电源正极(可接3.3V/5V)

SCL:通信,时钟信号线(I2C)

SDA:通信,数据信号线(I2C)

3.2模块原理图

注意:通信引脚通常需要后期配置,这里是通用的原理图

3.3工程

3.3.1配置通信引脚

根据原理图,OLED通信引脚SCL- PB8  SDA-PB9

在软件左边配置框里找到I2C1并进行配置

其它选项默认即可

3.3.2配置时钟 

跟LED一样,时钟设置为72兆

3.3.3配置OLED驱动代码

将驱动代码(驱动代码在文章结尾)放在指定路径里

OLED\Core\Inc 放入 oled.h  oledfont.h

OLED\Core\Src 放入 oled.c

3.3.4简单改写驱动配置

在include 沙盒里添加 olde.h

在工程里把.c文件添加进去(前面文件操作时.h文件已经自动添加了,.c文件需手动添加)

在oled.h检查引脚

SCK ->PB8

SDA ->PB9

跟在Cube里设置的一样,不用修改

3.3.5显示数字

 OLED_ShowNum(0,0,123456,6,16);

 OLED_ShowNum函数五个参数:

x坐标-1代表1个像素点

y坐标-1代表8个像素点

显示数字

数字长度

数字大小(16像素:8*16,12像素:6*12)

3.3.6显示字符串

 OLED_ShowString(0,2,"hello world!",16);

 OLED_ShowString函数四个参数:

x坐标-1代表1个像素点

y坐标-1代表16个像素点

显示字符串

字符串大小(16像素:8*16,12像素:6*12)

3.3.7显示汉字

着重说一下输出汉字

一个汉字像素——16*16

 OLED_ShowCHinese(0,4,0);

 OLED_ShowCHinese函数三个参数:

x坐标

y坐标

Hzk库

Hzk:汉字库

Hzk汉字库是用软件生成的,生成软件(PCtoLCD2002)在文章结尾

想要输入什么汉字,就用软件生成数组,写到Hzk库里,用0-x(字符数组)数字表示

3.3.8使用PCtoLCD2002生成汉字编码

首先设置基本格式

复制生成的编码到Hzk库里

3.3.9测试代码和现象

首先在主函数里添加这两个函数   

 OLED_Init(); //初始化
 OLED_Clear();//清屏

然后添加输出函数,并配置函数的参数,下面是主函数

int main(void)
{

  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();

	OLED_Init(); //初始化
	OLED_Clear();//清屏
	OLED_ShowNum(0,0,123456,6,16);
	OLED_ShowString(0,2,"hello world!",16);
	OLED_ShowCHinese(0,4,0 );
	OLED_ShowCHinese(16,4,1);
	OLED_ShowCHinese(32,4,2);

  while (1)
  {

  }

}

结果


4.MPU6050

4.1MPU6050工作原理

MPU6050 内部整合了 3 轴陀螺仪和 3 轴加速度传感器,并且含有一个第二 IIC 接口,可用于连接外部磁力传感器即AUX_CL 和 AUX_DA,并利用自带的数字运动处理器(DMP: DigitalMotion Processor)硬件加速引擎,通过主 IIC 接口,向应用端输出完整的 9 轴融合演算数据

在mpu6050中我们基于欧拉角()用陀螺仪传感器测角度,用加速度传感器测加速度

4.2陀螺仪传感器

在MPU6050中有三轴陀螺仪

陀螺仪工作原理:测量角速度进而求出欧拉角

g(x/y/z):绕x/y/z轴旋转的角速度

计算公式:

4.3加速度传感器

在MPU6050中有三轴加速度计

加速度计工作原理:分解g(重力加速度),得到X/Y/Z三轴上的加速度

a(x/y/z):飞机在x/y/z轴上的加速度

利用三角关系求出各个方向上的加速度

4.4精确欧拉角

这两个传感器各有优缺点

我们根据实际情况分配给他们权重,以此来精确欧拉角

计算公式

α一般取值:

Δt:读取传感器的时间间隔(例如200Hz)

t:加速度计对陀螺仪纠偏时间(一般取0.1)

4.5模块原理介绍

4.6模块原理图

4.7工程

4.7.1创建工程

复制OLED工程

接着创建工程

将MPU6050驱动函数放入工程文件夹里

4.7.2设置软件IIC通信

打开工程,设置软件IIC通信(用软件编程的方式模拟IIC,因为PB3/4无IIC硬件接口)(硬件软件IIC通信效果无差别)

4.7.3添加.c文件

4.7.4添加.h文件

4.7.5详解代码与现象

main.c

初始化

定义三个角度的参数

在主函数里调用这三个参数

定义一个用于缓存的变量

添加库#include "stdio.h",用于sprintf

(sprintf函数打印到字符串中(要注意字符串的长度要足够容纳打印的内容,否则会出现内存溢出),printf函数打印输出到屏幕上)

姿态在OLED中的显示

语句sprintf((char*)display_buf, "pich:%.2f",pitch);解读:

因为OLED打印字符串,将display_buf强制类型转换成char类型,并将pitch打印到display_buf中

测试结果(数字为动态变化)

完整代码(仅显示头文件和进程部分)

#include "main.h"
#include "i2c.h"
#include "gpio.h"


#include "oled.h"
#include "IIC.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "mpu6050.h"
#include "stdio.h"


float pitch,roll,yaw; //定义三个角度的参数
uint8_t display_buf[20];  //显示缓存

void SystemClock_Config(void);


int main(void)
{

  HAL_Init();


  SystemClock_Config();


  MX_GPIO_Init();
  MX_I2C1_Init();
 
	OLED_Init(); //初始化
	OLED_Clear();//清除
	
	MPU_Init(); //初始化MPU
	mpu_dmp_init();
	OLED_ShowString(0,00,"Init succeed",16);
	

  while (1)
  {
		HAL_Delay(10);
		mpu_dmp_get_data(&pitch,&roll,&yaw);
		
		sprintf((char*)display_buf, "pich:%.2f   ",pitch);
		OLED_ShowString(0,2,display_buf,16);
		sprintf((char*)display_buf, "pich:%.2f   ",roll);
		OLED_ShowString(0,4,display_buf,16);
		sprintf((char*)display_buf, "pich:%.2f   ",yaw);
		OLED_ShowString(0,6,display_buf,16);
  }

}

5.超声波模块

5.1基本工作原理

本项目使用HC-SR04 超声波测距模块,可提供 2cm-400cm(实际上到200cm) 的非接触式距离感测功能,测距精度可达高到的非接触式距离感测功能,测距精度可达高到 3mm

(1)采用 IO 口 TRIG 触发测距,给最少 10us 的高电平信呈。
(2)模块自动发送 8 个 40khz 的方波,自动检测是否有信号返回;
(3)有信号返回,通过 IO 口 ECHO 输出一个高电平,高电平持续的时间就是超声
波从发射到返回的时间。

公式

测试距离=(高电平时间*声速(340M/S))/2;

超声波时序图

原理:提供一个 10uS 以上脉冲触发信号,该模块内部将发出 8 个 40kHz 周期电平并检测回波。一旦检测到有回波信号则输出回响信号 。回响信号的脉冲宽度与所测的距离成正比。由此通过发射信号到收到的回响信号时间间隔可以计算得到距离

建议测量周期为 60ms 以上,以防止发射信号对回响信号的影响

该内容摘自HC-SR04超声波测距模块的原理介绍与代码实现-CSDN博客,详细内容参考以上链接

5.2模块原理图

Vcc:+5V电源供电
Trig:输入触发信号(可以触发测距)
Echo:传出信号回响(可以传回时间差)
Gnd:接地

注:
1 、此模块不宜带电连接,若要带电连接,则先让模块的 GND 端先连接,否则会影响模块的正常工作。
2 、测距时,被测物体的面积不少于 0.5 平方米且平面尽量要求平整,否则影响测量的结果

5.3工程

5.3.1思路

1.触发信号只需要输出10ms的高电平,所以触发引脚我们直接设置为GPIO(利用GPIO输出15ms的高电平)

2.回响信号使用外部中断(回响引脚配置成外部中断)

3.在回响信号上升沿时产生中断,利用单片机内部定时器定时,下降沿时再产生一次中断,这时读取定时器的值

4.利用定时器里的值(产生高电平的时间)根据公式计算结果

测试距离=高电平时间*声速(340M/S))/2;

5.3.2创建工程

创建MPU6050文件夹副本并改名为HC-SR04

打开副本里的CubeMx

5.3.3配置工程

设置

PA2-GPIO_EXTI2

PA3-GPIO_Output

将PA3引脚速度设置为High

选择PA2中断模式(上升沿下降沿都中断)

打开EXTI Line(不打开中断无任何作用)

5.3.4使能内部时钟

使能内部时钟并设置预分频系数为71

分频系数计算公式

5.3.5生成代码

5.3.5创建模块文件

创建并添加模块文件

sr04.c、sr04.h

 5.3.6代码

main.c

#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"



#include "oled.h"
#include "IIC.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "mpu6050.h"
#include "stdio.h"
#include "sr04.h"


float pitch,roll,yaw; //定义三个角度的参数
uint8_t display_buf[20];  //显示缓存
extern float distance;


void SystemClock_Config(void);

int main(void)
{

  HAL_Init();


  SystemClock_Config();


  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();
  
	OLED_Init(); //初始化
	OLED_Clear();//清除
	
	MPU_Init(); 
	mpu_dmp_init();
	OLED_ShowString(0,00,"Init succeed",16);
	


  while (1)
  {
		HAL_Delay(100);
		mpu_dmp_get_data(&pitch,&roll,&yaw);
		

		sprintf((char*)display_buf, "pich:%.2f   ",roll);
		OLED_ShowString(0,2,display_buf,16);
		GET_Distance();
		sprintf((char*)display_buf, "distance:%.2f   ",distance);
		OLED_ShowString(0,4,display_buf,12);

  }

}

sr04.c

#include "sr04.h"

uint16_t count; //1count=1us
float distance; //保存距离(cm)


extern TIM_HandleTypeDef htim3; //声明外部定义变量

void RCCdelay_us(uint32_t udelay)
{
  __IO uint32_t Delay = udelay * 72 / 8;//(SystemCoreClock / 8U / 1000000U)
    //见stm32f1xx_hal_rcc.c -- static void RCC_Delay(uint32_t mdelay)
  do
  {
    __NOP();
  }
  while (Delay --);
}//us级延时函数

void GET_Distance(void) //发送触发信号
{
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_SET); //输出高电平
	RCCdelay_us(12); //信号持续时间为10us,保险起见设置为12us
	HAL_GPIO_WritePin(GPIOA, GPIO_PIN_3,GPIO_PIN_RESET); //输出低电平
}

//中断函数
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	//判断上升沿还是下降沿
	if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_2)==GPIO_PIN_SET)
	{
		__HAL_TIM_SetCounter(&htim3,0);
		HAL_TIM_Base_Start(&htim3); //打开计时器时钟让它开始计时
	}
	else
	{
		HAL_TIM_Base_Stop(&htim3); //停止计时
		count = __HAL_TIM_GetCounter(&htim3);
		distance = count*0.017;//count/1000000*340*100/2;
	}
	
}

sr04.h

#ifndef _SR04_H
#define	_SR04_H

#include "stm32f1xx_hal.h"

void GET_Distance(void);


#endif

5.3.7现象


6.电机驱动

6.1TB6612驱动模块

本项目使用TB6612模块驱动电机

6.1.2TB6612的引脚说明

6.1.3驱动原理

1. AIN1和AIN2、BIN1和BIN2分别与AO1、AO2和BO1、BO2配合使用来控制电机的方向和速度

2.通过PWM信号控制PWMA和PWMB可以调节电机的转速

3.YSTB用于控制模块的工作状态

4.VM和VCC分别提供电机驱动和逻辑电路的电源

5.该驱动模块为高电平时有效,否则,直流电机处于停止状态

具体参考本篇第1.5节

(本篇参考stm32学习探究:利用TB6612驱动直流电机-CSDN博客)

6.2工程

6.2.1创建工程

创建HC-SR04文件夹副本并改名为MOTOR

6.2.2打开定时器TIM

我们使用定时器TIM输出PWM波

打开PA11和PA8的时钟(对应原理图)

6.2.3配置预分频系数

配置预分频系数即配置PWM输出频率(常用10KHz)(两个TIM输出频率相同,占位比可不相同)

公式以及参数:

F:频率

HCLK:主时钟(72M)

PSC+1:预分频系数

ARR:用于设置定时器的计数周期

10^4:10KHz

7200:PSC=0,ARR=7199(数字可适当不同分配,71和99有利于调占空比)

6.2.4配置占空比

公式以及参数

1:期望的比值(全速)

Pulse:信号

6.2.5配置控制方向GPIO

AIN1:PB13

AIN2:PB12

BIN1:PB14

BIN2:PB15

6.2.6创建模块文件

motor.c和motor.h

6.2.7代码

main.c


#include "main.h"
#include "i2c.h"
#include "tim.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "oled.h"
#include "IIC.h"
#include "inv_mpu.h"
#include "inv_mpu_dmp_motion_driver.h"
#include "mpu6050.h"
#include "stdio.h"
#include "sr04.h"
#include "motor.h"



float pitch,roll,yaw; //定义三个角度的参数
uint8_t display_buf[20];  //显示缓存
extern float distance;

/* USER CODE END PV */

void SystemClock_Config(void);

int main(void)
{
 
  HAL_Init();

  SystemClock_Config();

  MX_GPIO_Init();
  MX_I2C1_Init();
  MX_TIM3_Init();
  MX_TIM1_Init();
  /* USER CODE BEGIN 2 */
	OLED_Init(); //初始化
	OLED_Clear();//清除
	
	MPU_Init(); 
	mpu_dmp_init();
	OLED_ShowString(0,00,"Init succeed",16);
	
	//使能PWM
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1);
	HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_4);
	
	Load(1000,1000); //转速 ,注意:1000可能数值有点小,如果出现轮子不动的情况,请改大数值


 
  while (1)
  {
		HAL_Delay(100);
		mpu_dmp_get_data(&pitch,&roll,&yaw);
		

		sprintf((char*)display_buf, "pich:%.2f   ",roll);
		OLED_ShowString(0,2,display_buf,16);
		GET_Distance();
		sprintf((char*)display_buf, "distance:%.2f   ",distance);
		OLED_ShowString(0,4,display_buf,12);

  }

}

注意:1000可能数值有点小,如果出现轮子不动的情况,请改大数值

motor.c

#include "motor.h"

extern TIM_HandleTypeDef htim1;

int abs(int p)
{
	if(p>0)
		return p;
	else
		return -p;
}

//参数:左右电机转速   范围-7200~7200
void Load(int moto1,int moto2)			
{
	//两个
	if(moto1<0) //左电机
	{
		//AIN1和AIN0一个高电平一个低电平才能驱动电机,BIN同理
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_RESET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_13,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_12,GPIO_PIN_SET);
	}
	//配置占空比
	__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_4,abs(moto1));
	
	if(moto2<0)//右电机
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_SET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);
	}
	else
	{
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_14,GPIO_PIN_RESET);
		HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
	}
	__HAL_TIM_SetCompare(&htim1,TIM_CHANNEL_1,abs(moto2));
}

motor.h

#ifndef _MOTOR_H
#define	_MOTOR_H

#include "stm32f1xx_hal.h"


void Load(int moto1, int moto2);

#endif

6.2.8现象

两个轮以一定速度转动


7.编码器测速

为了方便大家理解,本篇放入<调试篇>讲解,谢谢大家

请大家下载 6.Encoder代码以便蓝牙模块的测试


8.蓝牙模块

8.1JDY-31蓝牙模块

本项目使用JDY-31蓝牙模块

8.2模块原理图

8.3工程

8.3.1创建Uart文件

将Encoder的副本重命名为Uart

8.3.2配置USART

1.打开PB10、PB11引脚,并设置为USART

2.设置基本的串口通信模式Asynchronous(异步)

3.打开全局中断(设备需要接收信息,需要打开全局中断)

记录和确保两台设备波特率相同

(参考8.1的数据)

Tx:接收数据

Rx:发送数据

(具体可参考1.6USART串口通信)

8.3.3生成代码

8.3.4发送数据

两种发送数据方式

8.3.5缓存数据

在 stm32f1xx_it.c中定义缓存数据数组

8.3.6接收中断

打开接收中断

rx_buf:缓存数组

1:每接收到一个字节就进入一次中断

每次中断需要执行HAL_UART_Receive_IT

总结(必看):

本篇资源来自:

【草履虫都能学会的STM32平衡小车教程(基础篇)】https://www.bilibili.com/video/BV1Gc411v73h?p=8&vd_source=066060e5c72e1d7ec627401517cd9584(源代码部分修改)

【[铁头山羊stm32入门教程] 课程介绍】https://www.bilibili.com/video/BV1dQ4y1J7pD?vd_source=066060e5c72e1d7ec627401517cd9584

本项目资料汇总:
链接:https://pan.baidu.com/s/1uZ7UJ_uKbrhnDnoxRR4gAw?pwd=Ucar 
提取码:Ucar 

作者留言:本人学生党,制作不易,字数共1w+,如有侵权,有错误或不恰当的地方,及时沟通

如有任何问题可在评论区提问,3小时内解答

2024.9.20-2024.9.26

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2169226.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于Node.js+Express+MySQL+VUE实现的计算机毕业设计旅游推荐网站

猜你喜欢评论 登录注册搜索 推荐定制景点/springboot/javaWEB/J2EE/MYSQL数据库/vue前后分离小程序 功能图如下所示&#xff1a; 一、设计目标 本次计算机毕业设计项目的主要目标是设计和开发一款功能完善、用户友好的旅游推荐网站。该网站旨在为广大旅游爱好者提供一个便捷、…

蓝桥杯--STM32G431RBT6(TIM定时器的输出频率和占空比,含详细原理介绍和使用方法)

目录 一、前言 二、代码 实现功能&#xff1a;​编辑 按如图配置 定义变量 编写执行代码 显示在LCD上 加入按键效果 三、效果展示 四、代码开源 一、前言 ARR 即自动重装载值&#xff08;Auto Reload Register&#xff09;。相当于一个水杯&#xff0c;水杯容量&am…

sqlserver迁移数据库文件存储位置

业务背景&#xff1a;由于C盘爆满&#xff0c;需要将数据库文件迁移到别处比如D盘 下面以某一个数据库转移为示例&#xff1a;&#xff08;可以用SSMS工具&#xff0c;新建查询配合使用&#xff09; 1.查询数据库文件存储路径 sql语句&#xff1a; -- 查询路径 USE QiangTes…

[Redis][哨兵][上]详细讲解

目录 0.前言1.基本概念1.相关名词解释2.主从复制的问题3.人工恢复主节点故障4.哨兵自动恢复主节点故障 0.前言 说明&#xff1a;该章节相关操作不需要记忆&#xff0c;理解流程和原理即可&#xff0c;用的时候能自主查到即可Redis的主从复制模式下&#xff0c;⼀旦主节点由于故…

使用豆包MarsCode 实现高可用扫描工具

以下是「 豆包MarsCode 体验官」优秀文章&#xff0c;作者郝同学测开笔记。 前言&#xfeff; 最近接触K8s&#xff0c;了解到K8s提供了非常方便的实现高可用的能力&#xff0c;再加上掘金推出「豆包MarsCode初体验」征文活动&#xff0c;所以打算使用豆包 MarsCode IDE来实现…

UniApp基于xe-upload实现文件上传组件

xe-upload地址&#xff1a;文件选择、文件上传组件&#xff08;图片&#xff0c;视频&#xff0c;文件等&#xff09; - DCloud 插件市场 致敬开发者&#xff01;&#xff01;&#xff01; 感觉好用的话&#xff0c;给xe-upload的作者一个好评 背景&#xff1a;开发中经常会有…

Dubbo快速入门(一):分布式与微服务、Dubbo基本概念

文章目录 一、分布式与微服务概念1.大型互联网架构目标2.集群和分布式&#xff08;1&#xff09;集群 (Cluster)&#xff08;2&#xff09;分布式计算 (Distributed Computing)&#xff08;3&#xff09;集群与分布式的关系&#xff08;4&#xff09;实践中的应用案例 3.架构演…

【AI大模型】向量及向量知识库

一、词向量与向量 什么是词向量 在机器学习和自然语言处理&#xff08;NLP&#xff09;中&#xff0c;词向量&#xff08;word embedding&#xff09;是一种以单词为单位将每个单词转化为实数向量的技术。这些实数向量可以被计算机更好地理解和处理。 词向量背后的主要想法是…

.NET 6 中,使用 ActionFilterAttribute 实现 AOP(面向切面编程)

AOP概述&#xff1a;AOP&#xff08;面向切面编程&#xff09;是一种编程规范的风格&#xff0c;通过横切的思想&#xff0c;将系统功能和业务功能分离开&#xff0c;以提高代码的可维护性和清晰度。 系统功能模块&#xff1a; 1、缓存模块&#xff1a; 作用&#xff1a;提高…

OpenHarmony(鸿蒙南向)——平台驱动指南【MIPI CSI】

往期知识点记录&#xff1a; 鸿蒙&#xff08;HarmonyOS&#xff09;应用层开发&#xff08;北向&#xff09;知识点汇总 鸿蒙&#xff08;OpenHarmony&#xff09;南向开发保姆级知识点汇总~ 持续更新中…… 概述 功能简介 CSI&#xff08;Camera Serial Interface&#xf…

wx小程序中,商城订单详情显示还有多少分钟关闭

问题&#xff1a;wx小程序中&#xff0c;商城订单详情需要显示还有多少分钟关闭 思路&#xff1a;创建订单时间戳和当前时间戳相减&#xff0c;得到时间差&#xff0c;再除1000&#xff0c;得到相差秒数&#xff0c;然后除60&#xff0c;向下取整&#xff0c;得到分钟。 代码如…

物联网行业中模组的AT指令详解以及使用

01 概述 AT 命令&#xff08;AT Commands&#xff09;最早是由发明拨号调制解调器&#xff08;MODEM&#xff09;的贺氏公司&#xff08;Hayes&#xff09;为了控制 MODEM 而发明的控制协议。后来随着网络带宽的升级&#xff0c;速度很低的拨号 MODEM 基本退出一般使用市场&am…

凌晨1点开播!Meta Connect 2024开发者大会,聚焦Llama新场景和AR眼镜

作者&#xff1a;十九 编辑&#xff1a;李宝珠 北京时间 9 月 26 日凌晨 1 点&#xff0c;Meta Connect 2024 开发者大会即将举行&#xff0c;马克扎克伯格将聚焦 AI 和元宇宙&#xff0c;向大家分享 Llama 模型的更多潜在应用&#xff0c;并介绍 Meta 最新产品 AR 眼镜和 Meta…

java基础 之 实现一个链表

文章目录 引言链表节点单向链表双向链表链表的优缺点 java封装的链表自己实现一下链表LinkNode节点类LinkedList类实现示例图代码 引言 1、新建的节点需要两个值&#xff1a;value 和 节点 next&#xff1b; 2、新建的节点链表需要有一个head&#xff1b; 3、根据位置对链表进行…

The Open Group 2024生态系统架构·可持续发展年度大会全面解读

在全球数字化转型加速的时代背景下&#xff0c;人工智能技术正以前所未有的速度重塑各行各业的生态系统。尤其是随着ChatGPT、Sora等技术的爆发&#xff0c;AIGC&#xff08;人工智能生成内容&#xff09;技术在多个领域展现出超越人类的能力&#xff0c;AGI&#xff08;通用人…

Llama 3.2:利用开放、可定制的模型实现边缘人工智能和视觉革命

在我们发布 Llama 3.1 模型群后的两个月内&#xff0c;包括 405B - 第一个开放的前沿级人工智能模型在内&#xff0c;它们所产生的影响令我们兴奋不已。 虽然这些模型非常强大&#xff0c;但我们也认识到&#xff0c;使用它们进行构建需要大量的计算资源和专业知识。 我们也听到…

成都网安周暨CCS2024 | 大模型安全与产业应用创新研讨活动成功举办

9月11日-12日&#xff0c;作为2024年国家网络安全宣传周成都系列活动的重磅活动之一&#xff0c;CCS 2024成都网络安全系列活动在成都举行。“大模型安全与产业应用创新研讨活动”同期举办&#xff0c;本场活动由百度安全、成都无糖信息联合承办&#xff0c;特邀云安全联盟CSA大…

MYSQL求月份同比数据和环比数据

1.需求题目如下 1.首先求出每月每个account_id 对应的amount金额 2.利用表自关联&#xff0c;获取上月&#xff0c;上年对应月份及金额&#xff0c; 关联条件利用 主表月份-1个月上月月份 和 主表月份-1年上年月份 3.最后求同比和环比 附代码及测试数据 CREATE TABLE transa…

HTML·第3章 表格布局与表单交互

3.1 表格概述 3.1.1 表格的结构 表格是由行和列组成的二维表&#xff0c;而每行又由一个或多个单元格组成&#xff0c;用于放置数据或其他内容。表格中的单元格是行与列的交叉部分&#xff0c;是组成表格的最基本单元。单元格的内容是数据&#xff0c;也称数据单元格。数据单元…

如何在 macOS(MacBook Pro、Air 和 iMac)上恢复未保存的 Word 文档

Microsoft Word 在许多用户中很受欢迎&#xff0c;并且有多种用途。无论是为学校写论文、在办公室写报告还是其他许多事情。但是不保存文档并丢失数据可能是您可能面临的最可怕的噩梦。但是&#xff0c;也有几种方法可以在 macOS 上恢复未保存的 Word 文档。 用户在 Windows P…