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

前言:

本文是基于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(); //初始化MPUmpu_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,保险起见设置为12usHAL_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);//使能PWMHAL_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;elsereturn -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.xdnf.cn/news/1547329.html

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

相关文章

滑动窗口 -- 限制窗口内某元素的数量/种类

目录 长度最小的数组 题解&#xff1a; 将x减到0的最小操作数 题解&#xff1a; 最大连续1的个数 题解&#xff1a; 无重复字符的最长子串&#xff08;限制数量&#xff09; 题解&#xff1a; 水果成篮&#xff08;限制种类&#xff09; 题解&#xff1a; 找到字符串中…

Studying-图论包含的算法总结

目录 1.DFS&#xff08;深度优先搜索&#xff09; 代码框架&#xff1a; 2. BFS&#xff08;广度优先搜索&#xff09; 代码框架&#xff1a; 3. 并查集 4.最小生成树之Prim 5.最小生成树之Kruskal 6.拓扑排序 7. 最短路径之-dijkstra&#xff08;朴素版&#xff…

淘宝霸屏必备工具:淘宝商品评论电商API接口

淘宝商品评论电商API接口是指用于获取淘宝商品评论信息的一种接口&#xff0c;通过该接口可以获取淘宝网上商品的评价内容、评价等级、评价数量等信息。通过了解并使用该接口&#xff0c;能够帮助电商了解消费者对商品的评价情况&#xff0c;做好商品的推广和销售工作。 接口使…

Leetcode - 周赛416

目录 一&#xff0c;3295. 举报垃圾信息 二&#xff0c;3296. 移山所需的最少秒数 三&#xff0c;3297. 统计重新排列后包含另一个字符串的子字符串数目 I 四&#xff0c;3298. 统计重新排列后包含另一个字符串的子字符串数目 II 一&#xff0c;3295. 举报垃圾信息 本题就是…

消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许

业务场景&#xff1a; 在做发票校验时&#xff0c;报错“消息号 FS215 对科目 2221010200 7333允许销项税, J1 不允许”而且计算税额失效&#xff0c;红灯报错。 初步怀疑是税码配置问题 FTXP J1是进项税&#xff0c;但是这里维护了销项税和均一税&#xff0c;在这里删除是需…

SQLSERVER通过触发器限制客户端IP地址

方法一&#xff1a;SQL Server 2005 SP2或更高版本(触发器) 当SQL Server 2005升级到SP2或者更高的版本的时候&#xff0c;还可以通过新增的触发器来实现控制。 执行下面的T-SQL后&#xff0c;将使除IP地址为192.168.1.1之外的客户端连接失败。 USE master; GO CREATE TRIGGE…

CMA软件检测机构人员职责分类、要求、档案资料

一、CMA软件检测机构人员职责分类&#xff1a; 1、最高管理者 2、授权签字人 3、技术负责人 4、质量负责人 5、软件测试人员 &#xff08;从事软件测试项目管理、测试需求分析、测试策划和测试设计活动的人员、软件测试执行人员&#xff09; 6、报告编制员 7、报告审核…

革新体验:细数3D在线预览在多个行业的广泛应用

‌3D在线预览展示技术的应用领域非常广泛&#xff0c;涵盖了从电子商务、产品设计、建筑设计到文化遗产保护等多个方面。‌ ‌1、电子商务‌&#xff1a; 在电商领域&#xff0c;3D展示技术为商品提供了全方位的展示&#xff0c;包括产品的外观、功能和卖点。这种交互式的购物…

【Docker】01-Docker常见指令

1. Docker Docker会下载镜像&#xff0c;运行的时候&#xff0c;创建一个隔离的环境&#xff0c;称为容器。 docker run -d \ # 创建并运行一个容器&#xff0c;-d表示后台运行 --name mysql \ # 容器名称-p 3307:3306 \ # 端口映射&#xff0c;宿主机端口映射到容器端口-e TZ…

buuctf [ACTF2020 新生赛]Include

学习笔记。 开启靶机。 进入靶场&#xff1a; 我们跟进 tips瞅瞅&#xff1a; 额&#xff0c;纯小白&#xff0c;能想到的就是先F12看看&#xff0c;在CTRLu、以及抓包。 得&#xff0c;不会了&#xff0c;看wp呗&#xff0c;不会死磕没脑子0,0&#xff1f; 参考&#xff1a;…

如何在 VitePress 站点中集成 Gitalk 评论插件及其关键注意事项

你好&#xff0c;我是陈明勇&#xff0c;一名热爱技术、乐于分享的开发者&#xff0c;同时也是开源爱好者。 成功的路上并不拥挤&#xff0c;有没有兴趣结个伴&#xff1f; 个人网站&#xff1a;https://chenmingyong.cn 文章持续更新&#xff0c;如果本文能让您有所收获&#…

OJ在线评测系统 后端 用策略模式优化判题机架构

判题机架构优化(策略模式) 思考 我们的判题策略可能会有很多种 比如 我们的代码沙箱本身执行程序需要消耗时间 这个时间可能不同的编程语言是不同的 比如沙箱执行Java要额外花费2秒 我们可以采用策略模式 针对不同的情况 定义不同独立的策略 而不是把所有情况全部放在一个i…

二分图算法模板以及简单应用

染色法判断二分图 给定一个 n 个点 m 条边的无向图&#xff0c;图中可能存在重边和自环。 请你判断这个图是否是二分图。 输入格式 第一行包含两个整数 n 和 m。 接下来 m 行&#xff0c;每行包含两个整数 u 和 v&#xff0c;表示点 u 和点 v 之间存在一条边。 输出格式 …

Matplotlib | 一文搞定Matplotlib从入门到实战演练!

文章目录 1 什么是Matplotlib1.1 Matplotlib的安装1.2 Matplotlib的基本使用 2 绘制直线3 绘制折线设置标签文字和线条粗细设置中文标题风格的设置 4 绘制曲线绘制曲线yx^2绘制正弦曲线和余弦曲线画布分区 5 绘制散点图绘制不同种类不同颜色的线 6 绘制条形图&#xff08;柱状&…

1. Linux系统(CentOS7.9)安装

toc 一、Linux概述介绍 1、Linux系统介绍 Linux, 一类操作系统的统称 部署在服务器上&#xff0c;部署项目、应用 服务器: 硬件设备, 柜式服务器&#xff0c;(华为、浪潮、联想) 提供服务的机器 2、Linux的优势 开源, open source , 开放源代码稳定性最大化发挥硬件资源 …

【电子通识】案例:连接器接线顺序评估为什么新人总是评估不到位?

在一个IC卡切换的工装板(一切多)中,设计需求是一张PCB(充当活动卡片)插入读卡器,将卡片中的所有信号引出通过连接器连接到后级设备。 比如下图所示是一种IC卡压力测试设备,使用钢片卡片将压力信号通过连接器引入测试设备。 最后根据ISO/IEC 7816-2标准中我们看到…

Mortise AI编程智能体产品 | OPENAIGC开发者大赛企业组AI创作力奖

在第二届拯救者杯OPENAIGC开发者大赛中&#xff0c;涌现出一批技术突出、创意卓越的作品。为了让这些优秀项目被更多人看到&#xff0c;我们特意开设了优秀作品报道专栏&#xff0c;旨在展示其独特之处和开发者的精彩故事。 无论您是技术专家还是爱好者&#xff0c;希望能带给…

c++ 杂项

简答题 1、什么是虚函数&#xff1f;什么是纯虚函数&#xff1f; 虚函数是在类中定义函数时&#xff0c;在函数前加 virtual 关键字。父子类中只有一个该函数。 如果子类中没有重写该虚函数。那么父子类空间中使用的都是父类定义的该函数。 如果子类中重写了该虚函数&#xff…

Leetcode面试经典150题-322.零钱兑换

给你一个整数数组 coins &#xff0c;表示不同面额的硬币&#xff1b;以及一个整数 amount &#xff0c;表示总金额。 计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额&#xff0c;返回 -1 。 你可以认为每种硬币的数量是无限的。 示…

9.26作业

C 面试题 1,什么是虚函数?什么是纯虚函数? 虚函数&#xff1a;父子类中&#xff0c;在父类中的函数需要在子类中进行重写&#xff0c;重写后父子类空间中使用的都是重写后的函数&#xff0c;该函数就是虚函数&#xff0c;虚函数的声明需要在函数前加virtual。 纯虚函数&…