STM32之增量式编码器电机测速

news2025/6/11 8:38:07

STM32之增量式编码器电机测速

  • 编码器
    • 编码器种类
      • 按监测原理分类
        • 光电编码器
        • 霍尔编码器
      • 按输出信号分类
        • 增量式编码器
        • 绝对式编码器
    • 编码器参数
      • 分辨率
      • 精度
      • 最大响应频率
      • 信号输出形式
    • 编码器倍频
  • STM32的编码器模式
    • 编码器模式
    • 编码器的计数方向
      • 仅在TI1计数
        • 电机正转,向上计数。
        • 电机反转,向下计数。
      • 仅在TI2计数
      • 在TI1和TI2上均计数
        • 电机正转,向上计数。
        • 电机反转,向下计数。
    • 编码器计数实例
      • TI1FP1和TI1FP2极性不反相:Rising
      • TI1FP1和TI1FP2极性反相:Falling
  • 正交式(霍尔传感器测速码盘)编码器电机测速
    • 模块介绍
      • TB6612FNG电机驱动模块
        • 真值表
        • 电机控制
      • JGB37-520编码器电机
    • 接线
      • TB6612FNG模块与STM32板子接线
      • TB6612FNG模块与520电机接线
      • 520电机与STM32板子接线
    • STM32CubeMX相关配置
      • 配置SYS
      • 配置RCC
      • 配置GPIO
      • 配置USART1
      • 配置定时器2、3、4
      • 配置NVIC
    • 文件编写
      • 添加文件motor.c
      • 添加文件motor.h
      • 修改文件usart.c
      • 修改文件usart.h
      • 修改文件tim.c
      • main.c文件编写

编码器

编码器,是一种用来测量机械旋转或位移的传感器。它能够测量机械部件在旋转或直线运动时的位移位置或速度等信息,并将其转换成一系列电信号。
.

编码器种类

按监测原理分类

光电编码器

光电编码器,是一种通过光电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。这是目前应用最多的传感器,光电编码器是由光源、光码盘和光敏元件组成。
在这里插入图片描述

  • 光栅盘是在一定直径的圆板上等分地开通若干个长方形孔。由于光电码盘与电动机同轴,电动机旋转时,光栅盘与电动机同速旋转,经发光二极管等电子元件组成的检测装置检测输出若干脉冲信号,通过计算每秒光电编码器输出脉冲的个数就能反映当前电动机的转速。
  • 为了判断旋转方向,码盘还可提供相位相差90°的两路脉冲信号。
    .

霍尔编码器

霍尔编码器是一种通过磁电转换将输出轴上的机械几何位移量转换成脉冲或数字量的传感器。在这里插入图片描述

  • 霍尔编码器是由霍尔码盘(磁环)和霍尔元件组成。

  • 霍尔码盘是在一定直径的圆板上等分地布置有不同的磁极。霍尔码盘与电动机同轴,电动机旋转时,霍尔元件检测输出若干脉冲信号,为判断转向,一般输出两组存在一定相位差的方波信号。
    .

按输出信号分类

增量式编码器

增量式编码器也称正交式编码器,是将设备运动时的位移信息变成连续的脉冲信号,脉冲个数表示位移量的大小。

特点:

  • 只有当设备运动时才会输出信号。

  • 一般会输出通道A和通道B 两组信号,并且有90° 的相位差(1/4个周期),同时采集这两组信号就可以计算设备的运动速度和方向。

  • 如下图,通道A和通道B的信号的周期相同,且相位相差1/4个周期,结合两相的信号值:

     当B相和A相先是都读到高电平(1 1),再B读到高电平,A读到低电平(1 0),则为顺时针转
    
     当B相和A相先是都读到低电平(0 0),再B读到高电平,A读到低电平(1 0),则为逆时针转
    
  • 除通道A、通道B 以外,还会设置一个额外的通道Z 信号,表示编码器特定的参考位置

  • 如下图,传感器转一圈后Z 轴信号才会输出一个脉冲,在Z轴输出时,可以通过将AB通道的计数清零,实现对码盘绝对位置的计算。

  • 增量式编码器只输出设备的位置变化和运动方向,不会输出设备的绝对位置。
    在这里插入图片描述
    .

绝对式编码器

绝对式编码器在总体结构上与增量式比较类似,都是由码盘、检测装置和放大整形电路构成,但是具体的码盘结构和输出信号含义不同。它是将设备运动时的位移信息通过二进制编码的方式(特殊的码盘)变成数字量直接输出。

特点:

  • 其码盘利用若干透光和不透光的线槽组成一套二进制编码,这些二进制码与编码器转轴的每一个不同角度是唯一对应的。

  • 绝对式编码器的码盘上有很多圈线槽,被称为码道,每一条(圈)码道内部线槽数量和长度都不同。它们共同组成一套二进制编码,一条(圈)码道对应二进制数的其中一个位(通常是码盘最外侧的码道表示最低位,最内侧的码道表示最高位)。

  • 码道的数量决定了二进制编码的位数,一个绝对式编码器有N 条码道,则它输出二进制数的总个数是2的N次方个。

  • 读取这些二进制码就能知道设备的绝对位置,所以称之为绝对式编码器。 编码方式一般采用自然二进制、格雷码或者BCD 码等。

     自然二进制的码盘易于理解,但当码盘的制造工艺有误差时,在两组信号的临界区域,所有码道的值可能不会同时变化,或因为所有传感器检测存在微小的时间差,导致读到错误的值。比如从000跨越到111,理论上应该读到111,但如果从内到外的3条码道没有完全对齐,可能会读到如001或其它异常值。
    
     格雷码的(相邻的两个2进制数只有1个位不同)码盘可以避免二进制码盘的数据读取异常,因为格雷码码盘的相邻两个信号组只会有1位的变化,就算制造工艺有误差导致信号读取有偏差,最多也只会产生1个偏差(相邻信号的偏差)
    

在这里插入图片描述
.

编码器参数

分辨率

分辨率是指编码器能够分辨的最小单位。

  • 对于增量式编码器,其分辨率表示为编码器转轴旋转一圈所产生的脉冲数,即脉冲数/转(Pulse Per Revolution或PPR)。码盘上透光线槽的数目其实就等于分辨率,也叫多少线。
  • 对于绝对式编码器,内部码盘所用的位数就是它的分辨率,单位是位(bit),具体还分单圈分辨率和多圈分辨率。
    .

精度

精度是指编码器每个读数与转轴实际位置间的最大误差,通常用角度、角分或角秒来表示。

  • 精度由码盘刻线加工精度、转轴同心度、材料的温度特性、电路的响应时间等各方面因素共同决定。
  • 例如有些绝对式编码器参数表里会写±20′′,这个就表示编码器输出的读数与转轴实际位置之间存在正负20 角秒的误差。
    .

最大响应频率

最大响应频率是指编码器每秒输出的脉冲数,单位是Hz。

  • 计算公式:最大响应频率 = 分辨率 * 轴转速 / 60
    .

信号输出形式

  • 对于增量式编码器,每个通道的信号独立输出,输出电路形式通常有集电极开路输出、推挽输出、差分输出等。
  • 对于绝对式编码器,由于是直接输出几十位的二进制数,为了确保传输速率和信号质量,一般采用串行输出或总线型输出,例如同步串行接口(SSI)、RS485、CANopen或EtherCAT 等,也有一部分是并行输出,输出电路形式与增量式编码器相同。
    .

编码器倍频

增量式编码器输出的脉冲波形一般为占空比50% 的方波,通道A 和B 相位差为90°。

  • 如果只使用通道A(或通道B)计数,并且只捕获通道A(或通道B)的上升沿或下降沿,即为1倍频(没有倍频)。
  • 如果只使用通道A(或通道B)计数,并且捕获了通道A(或通道B)的上升沿和下降沿,则编码器转一圈的计数值翻倍,实现2倍频。
  • 如果既使用通道A计数,又使用通道B计数,而且都捕获了上升沿和下降沿,则实现了4倍频。
    在这里插入图片描述
    如果某个增量式编码器的分辨率为11PPR,能分辨的最小角度为0.6°,那么经过4倍频后它的分辨率能提高到44PPR,能分辨的最小角度为0.15°,即编码器进行倍频能提高其精度。
    .

STM32的编码器模式

在STM32中,高级定时器TIM1、TIM8和通用定时器TIM2、TIM3、TIM4、TIM5都提供编码器接口模式,不过该模式是适用于增量式编码器的。
.

编码器模式

  • 模式1:计数器仅在TI1的边沿处计数。(2倍频)
  • 模式2:计数器仅在TI2的边沿处计数。(2倍频)
  • 模式3:计数器既在TI1的边沿处计数,又在TI1的边沿处计数。(4倍频)
    .

编码器的计数方向

编码器模式下,计数器的计数方向(递增计数还是递减计数)会根据增量编码器的速度和方向自动进行修改,因此,其计数值始终表示编码器的位置。计数方向对应于所连传感器的旋转方向。在这里插入图片描述
STM32 的编码器接口在计数的时候,并不是单纯采集某一通道信号的上升沿或下降沿,而是需要综合另一个通道信号的电平。
.

TI1 <–> 通道A
.
TI2 <–> 通道B

仅在TI1计数

电机正转,向上计数。

假定电机正转时,编码器的通道A的信号比通道B提前1/4个周期(也即相位提前90度),在通道A的上升沿与下降沿均计数,因为计数的方向代表的电机转动的方向,所以,在正转的情况下:

  • 通道A上升沿,通道B为低电平,向上计数,代表电机正转。
  • 通道A下降沿,通道B为高电平,向上计数,代表电机正转。
    在这里插入图片描述
    .

电机反转,向下计数。

假定电机反转时,编码器的通道A的信号比通道B滞后1/4个周期(也即相位滞后90度),在通道A的上升沿与下降沿均计数,因为计数的方向代表的电机转动的方向,所以,在反转的情况下:

  • 通道A下降沿,通道B为低电平,向下计数,代表电机反转。
  • 通道A上升沿,通道B为高电平,向下计数,代表电机反转。
    在这里插入图片描述
    .

仅在TI2计数

同理与仅在TI1计数,不多赘述。
.

在TI1和TI2上均计数

电机正转,向上计数。

假定电机正转时,编码器的通道A的信号比通道B提前1/4个周期(也即相位提前90度),在通道A和通道B的上升沿与下降沿均计数,因为计数的方向代表的电机转动的方向,所以在正转的情况下:

  • 通道A上升沿,通道B为低电平,向上计数,代表电机正转。
  • 通道B上升沿,通道A为高电平,向上计数,代表电机正转。
  • 通道A下降沿,通道B为高电平,向上计数,代表电机正转。
  • 通道B下降沿,通道A为高电平,向上计数,代表电机正转。
    在这里插入图片描述
    .

电机反转,向下计数。

假定电机反转时,编码器的通道A的信号比通道B滞后1/4个周期(也即相位滞后90度),在通道A和通道B的上升沿与下降沿均计数,因为计数的方向代表的电机转动的方向,所以在反转的情况下:

  • 通道A上升沿,通道B为高电平,向下计数,代表电机反转。
  • 通道A下降沿,通道B为高电平,向下计数,代表电机反转。
  • 通道B上升沿,通道A为低电平,向下计数,代表电机反转。
  • 通道B下降沿,通道A为高电平,向下计数,代表电机反转。在这里插入图片描述

编码器计数实例

TI1FP1和TI1FP2极性不反相:Rising

  • 电机正转时,编码器的通道A(TI1)的信号超前通道B(TI2),计数器向上计数。
  • 电机反转时,编码器的通道A(TI1)的信号滞后通道B(TI2),计数器向下计数。在这里插入图片描述
    .

TI1FP1和TI1FP2极性反相:Falling

极性反相可以改变计数器计数方向。

  • 电机正转时,编码器的通道A(TI1)的信号超前通道B(TI2),计数器向下计数。
  • 电机反转时,编码器的通道A(TI1)的信号滞后通道B(TI2),计数器向上计数。在这里插入图片描述

正交式(霍尔传感器测速码盘)编码器电机测速

使用TB6612FNG电机驱动模块来驱动电机,控制电机的正转、反转、制动、停止等功能,利用STM32的定时器作为编码器模式来获取电机在单位时间内产生的脉冲数来达到电机测速的目的。
.

模块介绍

TB6612FNG电机驱动模块

在这里插入图片描述
TB6612FNG是双驱动,也就是可以驱动两个电机,VM外接12V左右电源,GND连接一个即可。
.

真值表

输入输出
IN1IN2PWMSTBYO1O2电机状态
HighLowHighHighHighLow正转
LowHighHighHighLowHigh反转
HighHighxHighLowLow刹车
LowHighLowHighLowLow
HighLowLowHighLowLow
LowLowHighHighOFF自由刹车
xxxLowOFF待机
  • x:可以是High,也可以是Low。
  • 刹车:电机停止时,通过提供电源来将电机锁定在当前位置。这样可以防止电机继续旋转,也可以提供一定的力矩来抵消负载。
  • 自由刹车:将电机锁定在当前位置,不允许电机旋转,但也不提供额外的电源以保持电机的当前位置。
  • 待机:该模块不工作。
    .

电机控制

  • 如果PWM引脚给予一个高电平,那么通过IN1和IN2引脚就能控制电机的四个状态(电机旋转时为全速状态)。
  • 如果PWM引脚给予PWM波(有效电平为高电平,实测80kHz好用),那么可以通过PWM波的占空比大小来控制电机旋转时的速度,同样通过IN1和IN2引脚就能控制电机的四个状态。
    .

JGB37-520编码器电机

在这里插入图片描述
JGB37-520编码器电机(AB相增量式霍尔编码器)是一款直流减速电机,使用的是一款霍尔传感器测速码盘,配有 11 线强磁码盘(即编码器线数为11ppr),减速比为1:30(即减速前转速为330rpm)。在电机旋转一圈单相输出11个脉冲,在四倍频情况下电机旋转一圈输出11 * 30 * 4 = 1320个计数。
.

接线

TB6612FNG模块与STM32板子接线

  • PB3 <-> STBY
  • PB4 <-> AIN1
  • PB5 <-> AIN2
  • PA6(定时器3通道1输出PWM波) <-> PWMA
  • 12V左右外接电源 <-> VM
  • 单片机5V或3.3V <-> VCC
  • GND <-> GND(连接一个即可)
    .

TB6612FNG模块与520电机接线

  • M+(M1) <-> AO1
  • M-(M2) <-> AO2
    .

520电机与STM32板子接线

  • PA0(定时器2通道1,编码器模式) <-> A相
  • PA1(定时器2通道2,编码器模式) <-> B相
  • 单片机5V或3.3V <-> VCC
  • GND <-> GND
    .

STM32CubeMX相关配置

配置SYS

在这里插入图片描述
.

配置RCC

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

配置GPIO

  • PB3引脚配置成输出高电平模式。
  • PB4引脚配置成输出高电平模式。
  • PB5引脚配置成输出高电平模式。
    在这里插入图片描述
    .

配置USART1

在这里插入图片描述
.

配置定时器2、3、4

  • 配置定时器2为编码器模式。
  • 配置定时器3通道1输出PWM波(80kHZ好用)。
  • 配置定时器4定时1s产生溢出中断。
    .

配置定时器2为编码器模式。在这里插入图片描述在这里插入图片描述
.
.
配置定时器3通道1输出PWM波(80kHZ好用)。
在这里插入图片描述
在这里插入图片描述
.
.
配置定时器4定时1s产生溢出中断。在这里插入图片描述
.

配置NVIC

打开定时器4中断和USART1中断。
在这里插入图片描述
.

文件编写

添加文件motor.c

#include "gpio.h"
#include "motor.h"

#define STBY_pin GPIO_PIN_3

#define AIN1_pin GPIO_PIN_4
#define AIN2_pin GPIO_PIN_5

#define STBY(x)  do{ x ?  HAL_GPIO_WritePin(GPIOB, STBY_pin, GPIO_PIN_SET)  :  HAL_GPIO_WritePin(GPIOB, STBY_pin, GPIO_PIN_RESET); }while(0)

#define AIN1(x)  do{ x ?  HAL_GPIO_WritePin(GPIOB, AIN1_pin, GPIO_PIN_SET)  :  HAL_GPIO_WritePin(GPIOB, AIN1_pin, GPIO_PIN_RESET); }while(0)
#define AIN2(x)  do{ x ?  HAL_GPIO_WritePin(GPIOB, AIN2_pin, GPIO_PIN_SET)  :  HAL_GPIO_WritePin(GPIOB, AIN2_pin, GPIO_PIN_RESET); }while(0)


void motor_left_forward()
{
	STBY(1);
	
	AIN1(1);
	AIN2(0);
}
	
void motor_left_back()
{	
	STBY(1);
	
	AIN1(0);
	AIN2(1);
}

void motor_left_stop()
{
	STBY(1);
	
	AIN1(0);
	AIN2(0);
}

.

添加文件motor.h

void motor_left_forward(void);

void motor_left_back(void);

void motor_left_stop(void);

.

修改文件usart.c

/* USER CODE BEGIN Header */
/**
 ******************************************************************************
 * @file    usart.c
 * @brief   This file provides code for the configuration
 *          of the USART instances.
 ******************************************************************************
 * @attention
 *
 * Copyright (c) 2023 STMicroelectronics.
 * All rights reserved.
 *
 * This software is licensed under terms that can be found in the LICENSE file
 * in the root directory of this software component.
 * If no LICENSE file comes with this software, it is provided AS-IS.
 *
 ******************************************************************************
 */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "usart.h"

/* USER CODE BEGIN 0 */
 
#include <stdio.h>
#include <string.h>
 
#define USART_REC_LEN 200
 
// 串口接收缓存(1字节)
uint8_t buf = 0;
 
uint8_t UART1_RX_Buffer[USART_REC_LEN]; // 接收缓冲,串口接收的数据存放地点
 
// 串口接收状态,16位
uint16_t UART1_RX_STA = 0;
// bit15: 如果是1表示接收完成
// bit14: 如果是1表示接收到回车(0x0d)
// bit13~bit0: 接收到的有效字节数目
 
/* USER CODE END 0 */

UART_HandleTypeDef huart1;

/* USART1 init function */

void MX_USART1_UART_Init(void)
{

  /* USER CODE BEGIN USART1_Init 0 */
 
  /* USER CODE END USART1_Init 0 */

  /* USER CODE BEGIN USART1_Init 1 */
 
  /* USER CODE END USART1_Init 1 */
  huart1.Instance = USART1;
  huart1.Init.BaudRate = 115200;
  huart1.Init.WordLength = UART_WORDLENGTH_8B;
  huart1.Init.StopBits = UART_STOPBITS_1;
  huart1.Init.Parity = UART_PARITY_NONE;
  huart1.Init.Mode = UART_MODE_TX_RX;
  huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;
  huart1.Init.OverSampling = UART_OVERSAMPLING_16;
  if (HAL_UART_Init(&huart1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN USART1_Init 2 */
 
    /* 开启串口1的接收中断 */
    HAL_UART_Receive_IT(&huart1, &buf, 1); /* 每接收一个串口数据调用一次串口接收完成回调函数 */
		printf("usart1 is ok\r\n");
  /* USER CODE END USART1_Init 2 */

}

void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspInit 0 */
 
  /* USER CODE END USART1_MspInit 0 */
    /* USART1 clock enable */
    __HAL_RCC_USART1_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    GPIO_InitStruct.Pin = GPIO_PIN_9;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    GPIO_InitStruct.Pin = GPIO_PIN_10;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_NOPULL;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */
    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspInit 1 */
 
  /* USER CODE END USART1_MspInit 1 */
  }
}

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{

  if(uartHandle->Instance==USART1)
  {
  /* USER CODE BEGIN USART1_MspDeInit 0 */
 
  /* USER CODE END USART1_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_USART1_CLK_DISABLE();

    /**USART1 GPIO Configuration
    PA9     ------> USART1_TX
    PA10     ------> USART1_RX
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);

    /* USART1 interrupt Deinit */
    HAL_NVIC_DisableIRQ(USART1_IRQn);
  /* USER CODE BEGIN USART1_MspDeInit 1 */
 
  /* USER CODE END USART1_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */
 
/* 重写stdio.h文件中的prinft()里的fputc()函数 */
int fputc(int my_data, FILE *p)
{
    unsigned char temp = my_data;
    // 改写后,使用printf()函数会将数据通过串口一发送出去
    HAL_UART_Transmit(&huart1, &temp, 1, 0xffff); // 0xfffff为最大超时时间
    return my_data;
}
 
/* 串口接收完成回调函数 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
    // 判断中断是哪个串口触发的
    if (huart->Instance == USART1)
    {
 
        // 判断接收是否完成,即判断UART1_RX_STA的bit15是否为1
        if (!(UART1_RX_STA & 0x8000))
        { // 如果没接收完成就进入接收流程
 
            // 判断是否接收到回车0x0d
            if (UART1_RX_STA & 0x4000)
            {
 
                // 判断是否接收到换行0x0a
                if (buf == 0x0a)
                {
 
                    // 如果回车和换行都接收到了,则表示接收完成,即把bit15拉高
                    UART1_RX_STA |= 0x8000;
                }
                else
                { // 如果接收到回车0x0d没有接收到换行0x0a
 
                    // 则认为接收错误,重新开始接收
                    UART1_RX_STA = 0;
                }
            }
            else
            { // 如果没有接收到回车0x0d
 
                // 则判断收到的这个字符是否是回车0x0d
                if (buf == 0x0d)
                {
 
                    // 如果这个字符是回车,则将将bit14拉高,表示接收到回车
                    UART1_RX_STA |= 0x4000;
                }
                else
                { // 如果不是回车
 
                    // 则将这个字符存放到缓存数组中
                    UART1_RX_Buffer[UART1_RX_STA & 0x3ffff] = buf;
                    UART1_RX_STA++;
 
                    // 如果接收数据大于UART1_REC_LEN(200字节),则重新开始接收
                    if (UART1_RX_STA > USART_REC_LEN - 1)
                    {
                        UART1_RX_STA = 0;
                    }
                }
            }
        }
        // 如果接收完成则重新开启串口1的接收中断
        HAL_UART_Receive_IT(&huart1, &buf, 1);
    }
}
 
/* 对串口接收数据的处理 */
void usart1_receive_data_handle()
{
    /* 判断判断串口是否接收完成 */
    if (UART1_RX_STA & 0x8000)
    {
        printf("接收完成\r\n");
 
        // 串口接收完数据后,对串口数据进行处理
        if (!strcmp((const char *)UART1_RX_Buffer, "haozige"))
        {
            printf("浩子哥\r\n");
        }

        // 接收到其他数据,进行报错
        else
        {
						printf("%s\r\n", "输入错误,请重新输入");
        }
 
        // 换行,重新开始下一次接收
        memset(UART1_RX_Buffer, 0, USART_REC_LEN);
        UART1_RX_STA = 0;
    }
}
 
/* USER CODE END 1 */

.

修改文件usart.h

.

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    usart.h
  * @brief   This file contains all the function prototypes for
  *          the usart.c file
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USART_H__
#define __USART_H__

#ifdef __cplusplus
extern "C" {
#endif

/* Includes ------------------------------------------------------------------*/
#include "main.h"

/* USER CODE BEGIN Includes */

/* USER CODE END Includes */

extern UART_HandleTypeDef huart1;

/* USER CODE BEGIN Private defines */

/* USER CODE END Private defines */

void MX_USART1_UART_Init(void);

/* USER CODE BEGIN Prototypes */

void usart1_receive_data_handle(void);

/* USER CODE END Prototypes */

#ifdef __cplusplus
}
#endif

#endif /* __USART_H__ */


修改文件tim.c

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file    tim.c
  * @brief   This file provides code for the configuration
  *          of the TIM instances.
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "tim.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

TIM_HandleTypeDef htim2;
TIM_HandleTypeDef htim3;
TIM_HandleTypeDef htim4;

/* TIM2 init function */
void MX_TIM2_Init(void)
{

  /* USER CODE BEGIN TIM2_Init 0 */
	
	//编码器
	
  /* USER CODE END TIM2_Init 0 */

  TIM_Encoder_InitTypeDef sConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM2_Init 1 */

  /* USER CODE END TIM2_Init 1 */
  htim2.Instance = TIM2;
  htim2.Init.Prescaler = 0;
  htim2.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim2.Init.Period = 65535;
  htim2.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim2.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_DISABLE;
  sConfig.EncoderMode = TIM_ENCODERMODE_TI12;
  sConfig.IC1Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC1Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC1Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC1Filter = 6;
  sConfig.IC2Polarity = TIM_ICPOLARITY_RISING;
  sConfig.IC2Selection = TIM_ICSELECTION_DIRECTTI;
  sConfig.IC2Prescaler = TIM_ICPSC_DIV1;
  sConfig.IC2Filter = 6;
  if (HAL_TIM_Encoder_Init(&htim2, &sConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim2, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM2_Init 2 */
	
	__HAL_TIM_SetCounter(&htim2,0);	 //设置定时器2的计数值为0
	__HAL_TIM_ENABLE(&htim2);  //使能定时器2
	HAL_TIM_Encoder_Start(&htim2,TIM_CHANNEL_ALL);  //开启TIM2的编码器模式
	
  /* USER CODE END TIM2_Init 2 */

}
/* TIM3 init function */
void MX_TIM3_Init(void)
{

  /* USER CODE BEGIN TIM3_Init 0 */

	//输出PWM
	
  /* USER CODE END TIM3_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_OC_InitTypeDef sConfigOC = {0};

  /* USER CODE BEGIN TIM3_Init 1 */

  /* USER CODE END TIM3_Init 1 */
  htim3.Instance = TIM3;
  htim3.Init.Prescaler = 8;
  htim3.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim3.Init.Period = 99;
  htim3.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim3.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim3, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  if (HAL_TIM_PWM_Init(&htim3) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim3, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sConfigOC.OCMode = TIM_OCMODE_PWM1;
  sConfigOC.Pulse = 0;
  sConfigOC.OCPolarity = TIM_OCPOLARITY_HIGH;
  sConfigOC.OCFastMode = TIM_OCFAST_DISABLE;
  if (HAL_TIM_PWM_ConfigChannel(&htim3, &sConfigOC, TIM_CHANNEL_1) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM3_Init 2 */
	
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);  开启定时器3的通道1的PWM
	
  /* USER CODE END TIM3_Init 2 */
  HAL_TIM_MspPostInit(&htim3);

}
/* TIM4 init function */
void MX_TIM4_Init(void)
{

  /* USER CODE BEGIN TIM4_Init 0 */

	//定时1s
	
  /* USER CODE END TIM4_Init 0 */

  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};

  /* USER CODE BEGIN TIM4_Init 1 */

  /* USER CODE END TIM4_Init 1 */
  htim4.Instance = TIM4;
  htim4.Init.Prescaler = 7199;
  htim4.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim4.Init.Period = 9999;
  htim4.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
  htim4.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;
  if (HAL_TIM_Base_Init(&htim4) != HAL_OK)
  {
    Error_Handler();
  }
  sClockSourceConfig.ClockSource = TIM_CLOCKSOURCE_INTERNAL;
  if (HAL_TIM_ConfigClockSource(&htim4, &sClockSourceConfig) != HAL_OK)
  {
    Error_Handler();
  }
  sMasterConfig.MasterOutputTrigger = TIM_TRGO_RESET;
  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  if (HAL_TIMEx_MasterConfigSynchronization(&htim4, &sMasterConfig) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN TIM4_Init 2 */

	HAL_TIM_Base_Start_IT(&htim4);  //启动定时器4,并使能中断
	
  /* USER CODE END TIM4_Init 2 */

}

void HAL_TIM_Encoder_MspInit(TIM_HandleTypeDef* tim_encoderHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(tim_encoderHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspInit 0 */

  /* USER CODE END TIM2_MspInit 0 */
    /* TIM2 clock enable */
    __HAL_RCC_TIM2_CLK_ENABLE();

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM2 GPIO Configuration
    PA0-WKUP     ------> TIM2_CH1
    PA1     ------> TIM2_CH2
    */
    GPIO_InitStruct.Pin = GPIO_PIN_0|GPIO_PIN_1;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Pull = GPIO_PULLUP;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM2_MspInit 1 */

  /* USER CODE END TIM2_MspInit 1 */
  }
}

void HAL_TIM_Base_MspInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspInit 0 */

  /* USER CODE END TIM3_MspInit 0 */
    /* TIM3 clock enable */
    __HAL_RCC_TIM3_CLK_ENABLE();
  /* USER CODE BEGIN TIM3_MspInit 1 */

  /* USER CODE END TIM3_MspInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspInit 0 */

  /* USER CODE END TIM4_MspInit 0 */
    /* TIM4 clock enable */
    __HAL_RCC_TIM4_CLK_ENABLE();

    /* TIM4 interrupt Init */
    HAL_NVIC_SetPriority(TIM4_IRQn, 0, 0);
    HAL_NVIC_EnableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspInit 1 */

  /* USER CODE END TIM4_MspInit 1 */
  }
}
void HAL_TIM_MspPostInit(TIM_HandleTypeDef* timHandle)
{

  GPIO_InitTypeDef GPIO_InitStruct = {0};
  if(timHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspPostInit 0 */

  /* USER CODE END TIM3_MspPostInit 0 */

    __HAL_RCC_GPIOA_CLK_ENABLE();
    /**TIM3 GPIO Configuration
    PA6     ------> TIM3_CH1
    */
    GPIO_InitStruct.Pin = GPIO_PIN_6;
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

  /* USER CODE BEGIN TIM3_MspPostInit 1 */

  /* USER CODE END TIM3_MspPostInit 1 */
  }

}

void HAL_TIM_Encoder_MspDeInit(TIM_HandleTypeDef* tim_encoderHandle)
{

  if(tim_encoderHandle->Instance==TIM2)
  {
  /* USER CODE BEGIN TIM2_MspDeInit 0 */

  /* USER CODE END TIM2_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM2_CLK_DISABLE();

    /**TIM2 GPIO Configuration
    PA0-WKUP     ------> TIM2_CH1
    PA1     ------> TIM2_CH2
    */
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_0|GPIO_PIN_1);

  /* USER CODE BEGIN TIM2_MspDeInit 1 */

  /* USER CODE END TIM2_MspDeInit 1 */
  }
}

void HAL_TIM_Base_MspDeInit(TIM_HandleTypeDef* tim_baseHandle)
{

  if(tim_baseHandle->Instance==TIM3)
  {
  /* USER CODE BEGIN TIM3_MspDeInit 0 */

  /* USER CODE END TIM3_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM3_CLK_DISABLE();
  /* USER CODE BEGIN TIM3_MspDeInit 1 */

  /* USER CODE END TIM3_MspDeInit 1 */
  }
  else if(tim_baseHandle->Instance==TIM4)
  {
  /* USER CODE BEGIN TIM4_MspDeInit 0 */

  /* USER CODE END TIM4_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_TIM4_CLK_DISABLE();

    /* TIM4 interrupt Deinit */
    HAL_NVIC_DisableIRQ(TIM4_IRQn);
  /* USER CODE BEGIN TIM4_MspDeInit 1 */

  /* USER CODE END TIM4_MspDeInit 1 */
  }
}

/* USER CODE BEGIN 1 */

/* USER CODE END 1 */

.

main.c文件编写

/* USER CODE BEGIN Header */
/**
  ******************************************************************************
  * @file           : main.c
  * @brief          : Main program body
  ******************************************************************************
  * @attention
  *
  * Copyright (c) 2023 STMicroelectronics.
  * All rights reserved.
  *
  * This software is licensed under terms that can be found in the LICENSE file
  * in the root directory of this software component.
  * If no LICENSE file comes with this software, it is provided AS-IS.
  *
  ******************************************************************************
  */
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include <stdio.h>
#include "motor.h"

/* USER CODE END Includes */

/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */

/* USER CODE END PTD */

/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */

/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */

/* USER CODE END PM */

/* Private variables ---------------------------------------------------------*/

/* USER CODE BEGIN PV */

/* USER CODE END PV */

/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */

/* USER CODE END PFP */

/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */

short encoder; //定义编码值
short pulse;	  //定义电机实际脉冲值
float speed;

/* 获取定时器2计数值 */
short get_left_encoder(void)  //使用计数值  
{
	short encoder_cnt;
	
	encoder_cnt = (short)__HAL_TIM_GetCounter(&htim2);		//获取定时器2的脉冲值
	
	__HAL_TIM_SetCounter(&htim2,0);	  //将定时器2计数值清0
	return encoder_cnt;	
}

/* 定时器中断的回调函数 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    // 如果是定时器4产生的中断(1s产生一次中断)
    if (htim4.Instance == TIM4)
    {
			encoder = get_left_encoder();
			
			pulse = encoder / 4;  //4倍频
			
			speed = (float)encoder / 1320;
			
			printf("encoder: %d\r\n",encoder);
			printf("pulse: %d\r\n",pulse);
			printf("speed: %0.2f c/s\r\n",speed);
		}
}

	

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */

  /* USER CODE END 1 */

  /* MCU Configuration--------------------------------------------------------*/

  /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  HAL_Init();

  /* USER CODE BEGIN Init */

  /* USER CODE END Init */

  /* Configure the system clock */
  SystemClock_Config();

  /* USER CODE BEGIN SysInit */

  /* USER CODE END SysInit */

  /* Initialize all configured peripherals */
  MX_GPIO_Init();
  MX_TIM2_Init();
  MX_TIM3_Init();
  MX_TIM4_Init();
  MX_USART1_UART_Init();
  /* USER CODE BEGIN 2 */

	__HAL_TIM_SetCompare(&htim3, TIM_CHANNEL_1, 22);  //修改PWM占空比

	motor_left_back();
	//motor_left_forward();
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
		usart1_receive_data_handle();
		
  }
  /* USER CODE END 3 */
}

/**
  * @brief System Clock Configuration
  * @retval None
  */
void SystemClock_Config(void)
{
  RCC_OscInitTypeDef RCC_OscInitStruct = {0};
  RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};

  /** Initializes the RCC Oscillators according to the specified parameters
  * in the RCC_OscInitTypeDef structure.
  */
  RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
  RCC_OscInitStruct.HSEState = RCC_HSE_ON;
  RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
  RCC_OscInitStruct.HSIState = RCC_HSI_ON;
  RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
  RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
  RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
  if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
  {
    Error_Handler();
  }

  /** Initializes the CPU, AHB and APB buses clocks
  */
  RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
                              |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
  RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
  RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
  RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
  RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

  if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
  {
    Error_Handler();
  }
}

/* USER CODE BEGIN 4 */

/* USER CODE END 4 */

/**
  * @brief  This function is executed in case of error occurrence.
  * @retval None
  */
void Error_Handler(void)
{
  /* USER CODE BEGIN Error_Handler_Debug */
  /* User can add his own implementation to report the HAL error return state */
  __disable_irq();
  while (1)
  {
  }
  /* USER CODE END Error_Handler_Debug */
}

#ifdef  USE_FULL_ASSERT
/**
  * @brief  Reports the name of the source file and the source line number
  *         where the assert_param error has occurred.
  * @param  file: pointer to the source file name
  * @param  line: assert_param error line source number
  * @retval None
  */
void assert_failed(uint8_t *file, uint32_t line)
{
  /* USER CODE BEGIN 6 */
  /* User can add his own implementation to report the file name and line number,
     ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
  /* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */

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

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

相关文章

卷麻了,00后测试用例写的比我还好,简直无地自容.....

前言 作为一个测试新人&#xff0c;刚开始接触测试&#xff0c;对于怎么写测试用例很头疼&#xff0c;无法接触需求&#xff0c;只能根据站在用户的角度去做测试&#xff0c;但是这样情况会导致不能全方位的测试APP&#xff0c;这种情况就需要一份测试用例了&#xff0c;但是不…

服务(第五篇)Nginx!!!

Nginx和Apache的差异? Nginx是一个基于事件的Web服务器&#xff0c;Apache是一个基于流程的Web服务器; Nginx所有请求都由一个线程处理&#xff0c;Apache单个线程处理单个请求; Nginx异步非阻塞的&#xff0c;Apache是阻塞的; Nginx在内存消耗和连接方面更好&#xff0c;Apa…

【JAVA】#详细介绍!!! synchronized 加锁 详解(2)

本篇主要是针对 synchronized锁的优化过程来介绍&#xff0c;针对synchronized的加锁优化过程来了解上篇所提到的synchronized的锁特性。 目录 1. synchronized锁的特性 2.synchronized 锁的升级过程 2.1 总过程&#xff1a; 2.2 偏向锁 2.3 轻量级锁 2.3.1自旋锁vs自适应…

网络安全之认识勒索病毒

一、什么是勒索病毒 勒索病毒&#xff0c;是一种新型电脑病毒&#xff0c;伴随数字货币兴起&#xff0c;主要以邮件、程序木马、网页挂马、服务器入侵、捆绑软件等多种形式进行传播&#xff0c;一旦感染将给用户带来无法估量的损失。如果遭受勒索病毒攻击&#xff0c;将会使绝…

Flink任务提交流程

抽象流程 抽象级别&#xff1a;不管是什么模式&#xff0c;大体上就是上面这个流程。 任务提交给分发器分发器把任务提交给JobManager上的JobMaster组件JobMaster收到任务之后&#xff0c;就会想JobManager上的ResourceManager去请求SlotJobManager上的ResourceManager会提供给…

3.1.2栈的顺序存储实现

&#xff08;1&#xff09;初始化一个顺序栈/栈的判空操作 与顺序表的声明类似 就是要加上一个栈顶指针top 然后把别名SqList改为SqStack 我们发现top指针的大小就是数组下标。 当空栈时&#xff0c;top指针为-1. &#xff08;2&#xff09;进栈操作 ep&#xff1a;插入一…

版本控制:git的基本使用

1.git基本介绍及安装 学习网址&#xff1a;Git - Book 安装步骤: Git - 安装 Git 安装完可以在本地电脑上查看&#xff1a; cmd为windows环境 bash为linux的环境 2. Git常用命令 牛客网项目——前置技术&#xff08;五&#xff09;&#xff1a;版本控制_平什么阿的博客-C…

ffmpeg关于视频前几秒黑屏的问题解决

关于音频播放器视频前两秒黑屏的解决&#xff0c;及QtAV和ffmpeg的环境搭建&#xff08;软件包可以找李青璠提供&#xff0c;也可以自己下&#xff09;首先我们可以参考下面两个博客进行ffmpeg的搭建&#xff0c;第一个博客的问题可以在第二个博客里寻求方法解决。其中第一个博…

服务器上后台运行python程序

Linux中将代码nohup后台执行、查看正在运行代码、结束进程写在最前面环境代码示例nohup指令& 后台运行2>&1 错误内容重定向到标准输出查看当前python相关进程结束进程nohup后台pip下载安装写在最前面 一直是pycharm运行服务器上代码&#xff0c;但存在问题&#xf…

3.1、线程概述

3.1、线程概述1.线程概述2.线程和进程区别3.线程和进程虚拟地址空间4.线程之间共享和非共享资源①共享资源②非共享资源5.线程版本NPTL1.线程概述 与进程&#xff08;process&#xff09;类似&#xff0c;线程&#xff08;thread&#xff09;是允许应用程序并发执行多个任务的…

通达信指标没有了怎么找回

通达信指标没有了可以恢复&#xff0c;不用太慌张&#xff0c;通达信会自动备份指标公式&#xff0c;可以通过备份文件找回。 1、找到通达信安装文件夹&#xff0c;一般是new_tdx&#xff0c;但是版本不同&#xff0c;安装文件夹可能有区别。本文以new_tdx这个文件夹为例。 如…

什么是零代码与低代码?有什么区别与联系?未来趋势

目前传统软件开发模式并不能很好地满足企业的需求&#xff1a;高人力成本、长研发时间、运维复杂&#xff0c;需求变化快&#xff0c;技术更新快&#xff0c;人员流失。这时零代码或低代码工具出现在市面上并被关注就是必然趋势了。对于不太了解两者的人来说&#xff0c;零代码…

【mysql性能调优 • 三】字符集和校验规则

前言 MySQL是一个关系型数据库管理系统&#xff0c;由瑞典MySQL AB 公司开发&#xff0c;属于 Oracle 旗下产品。MySQL是最流行的关系型数据库管理系统之一&#xff0c;在 WEB 应用方面&#xff0c;MySQL是最好的 RDBMS (Relational Database Management System&#xff0c;关系…

Linux下Nginx配置SSL模块,Nginx安装SSL,Nginx支持https配置详细教程

前提&#xff1a;Linux安装Nginx&#xff0c;参考教程&#xff1a;CentOS7安装Nginx完整教程&#xff0c;Linux系统下保姆式安装Nginx教程 | 老麻 安装好Nginx之后&#xff0c;需要支持SSL时&#xff0c;要单独安装SSL模块&#xff0c;方法如下&#xff1a; 输入 ./nginx –V 命…

2345看图王阻止文件删除和U盘弹出 - 解决方案

2345看图王阻止文件删除和U盘弹出 - 解决方案前言2345看图王解决方案临时方案永久方案前言 用户在使用2345看图王查看图片后&#xff0c;可能会出现图片文件/文件夹无法删除或U盘无法弹出等问题&#xff0c;这是因为2345看图王的辅助模块正在占用图片文件&#xff0c;因此无法…

设计分布式日志系统

一、日志 1.1、什么是日志 日志是一种按照时间顺序存储记录的数据&#xff0c;它记录了什么时间发生了什么事情&#xff0c;提供精确的系统记录&#xff0c;根据日志信息可以定位到错误详情和根源。按照APM概念的定义&#xff0c;日志的特点是描述一些离散的&#xff08;不连…

Spark----DataFrame和DataSet

Spark之DataFrame和DataSet 文章目录Spark之DataFrame和DataSetDataFrameDSL 语法创建DataFrame查看DataFrame的Schema信息只查看列数据的6种方式按照“age”分区&#xff0c;查看数据条数增加列withColumn修改列名withColumnRenamedRDD 转换为 DataFrameDataFrame 转换为 RDD转…

如何使用双轴XY平台绘制斜向多边形

1. 功能说明 本文示例将实现双轴XY平台绘制斜向多边形的功能。 2. 直角坐标机器人的结构设计 直角坐标机器人各个运动轴通常对应直角坐标系中的X轴、Y轴和Z 轴&#xff0c;其中X 轴和Y 轴是水平面内运动轴&#xff0c;Z轴是上下运动轴。在绝大多数情况下直角坐标机器人的各个直…

SpringBoot集成Easy-Es

文章目录SpringBoot集成Easy-Es一、集成demo二、索引CRUD创建索引查询索引更新索引删除索引三、数据CURD四、参数文档SpringBoot集成Easy-Es Easy-Es&#xff08;简称EE&#xff09;是一款基于ElasticSearch(简称Es)官方提供的RestHighLevelClient打造的ORM开发框架&#xff0c…

C语言—实用调试技巧

实用调试技巧什么是bug&#xff1f;调试是什么&#xff1f;有多重要&#xff1f;什么是调试调试的基本步骤Debug和Release的介绍Windows环境调试介绍调试环境的准备快捷键的使用调试的时候查看程序当前信息查看断点信息查看临时变量的值查看局部变量的值查看内存信息查看汇编信…