江协科技STM32学习- P22 实验-ADC单通道/ADC多通道

      🚀write in front🚀  
🔎大家好,我是黄桃罐头,希望你看完之后,能对你有所帮助,不足请指正!共同学习交流
🎁欢迎各位→点赞👍 + 收藏⭐️ + 留言📝​ 

💬本系列哔哩哔哩江科大STM32的视频为主以及自己的总结梳理📚 

🚀Projeet source code🚀   

💾工程代码放在了本人的Gitee仓库:iPickCan (iPickCan) - Gitee.com

引用:

STM32入门教程-2023版 细致讲解 中文字幕_哔哩哔哩_bilibili

Keil5 MDK版 下载与安装教程(STM32单片机编程软件)_mdk528-CSDN博客

STM32之Keil5 MDK的安装与下载_keil5下载程序到单片机stm32-CSDN博客

0. 江协科技/江科大-STM32入门教程-各章节详细笔记-查阅传送门-STM32标准库开发_江协科技stm32笔记-CSDN博客

【STM32】江科大STM32学习笔记汇总(已完结)_stm32江科大笔记-CSDN博客

江科大STM32学习笔记(上)_stm32博客-CSDN博客

STM32学习笔记一(基于标准库学习)_电平输出推免-CSDN博客

STM32 MCU学习资源-CSDN博客

stm32学习笔记-作者: Vera工程师养成记

stem32江科大自学笔记-CSDN博客

术语:

英文缩写描述
GPIO:General Purpose Input Onuput通用输入输出
AFIO:Alternate Function Input Output复用输入输出
AO:Analog Output模拟输出
DO:Digital Output数字输出
内部时钟源 CK_INT:Clock Internal内部时钟源
外部时钟源 ETR:External clock 时钟源 External clock 
外部时钟源 ETR:External clock mode 1外部时钟源 Extern Input pin 时钟模式1
外部时钟源 ETR:External clock mode 2外部时钟源 Extern Trigger 时钟模式2
外部时钟源 ITRx:Internal trigger inputs外部时钟源,ITRx (Internal trigger inputs)内部触发输入
外部时钟源 TIx:external input pin 外部时钟源 TIx (external input pin)外部输入引脚
CCR:Capture/Comapre Register捕获/比较寄存器
OC:Output Compare输出比较
IC:Input Capture输入捕获
TI1FP1:TI1 Filter Polarity 1Extern Input 1 Filter Polarity 1,外部输入1滤波极性1
TI1FP2:TI1 Filter Polarity 2Extern Input 1 Filter Polarity 2,外部输入1滤波极性2

正文:

0. 概述

从 2024/06/12 定下计划开始学习下江协科技STM32课程,接下来将会按照哔站上江协科技STM32的教学视频来学习入门STM32 开发,本文是视频教程 P2 STM32简介一讲的笔记。


定时器共四个部分,分为八个小节笔记。本小节为第一部分第一节。

🌳在第一部分,是定时器的基本定时的功能:定时中断功能、内外时钟源选择

🌳在第二部分,是定时器的输出比较功能,最常见的用途是产生PWM波形,用于驱动电机等设备

🌳在第三部分,是定时器的输入捕获功能和主从触发模式,来实现测量方波频率

🌳在第四部分,是定时器的编码器接口,能够更加方便读取正交编码器的输出波形,编码电机测速


1.🚢第一个代码:AD单通道

接线图:

电位器的内部结构是这样的:

左边和右边的两个引脚接的是电阻的两个固定端,中间这个引脚接的是滑动抽头。电位器外边这里有个十字形状的槽,可以拧,往左拧抽头就往左靠,往右拧,抽头就往右靠。所以外围电路这里,我们把左边的固定端接在负极,右边的固定端接在正极,中间就可以输出,从负极到正极可调的电压了,把可调的电压输出接在PA0。

2.🚢ADC初始化步骤

AD的初始化看这个结构图

ADC初始化的步骤具体的步骤:

🦄第一步,开启RCC时钟,包括ADC和GPIO的时钟。另外这里ADC CLK的分频器也需要配置一下。

🦄第二步,配置GPIO,把需要用的GPIO配置成模拟输入的模式。

🦄第三步,配置多路开关

把左边的通道接入到右边的规则组列表里。这个过程就是我们之前说的点菜,把各个通道的菜列在菜单里。

🦄第四步,配置ADC转换器,在库函数里是用结构体来配置的,可以配置这一大块电路的参数。

如果需要模拟看门狗,会有几个函数用来配置阈值和监测通道的。

如果想开启中断,就在中断输出控制里用ITconfig函数开启对应的中断输出,然后再在NVIC里配置一下优先级,这样就能触发中断了。

不过模拟看门狗中断我们本节暂时不用。

第五步,开关控制,调用一下ADC_Cmd的函数开启ADC。

这样ADC就配置完成了就能正常工作了。

第六步,校准

当然在开启ADC之后,根据手册里的建议,我们还可以对ADC进行一下校准,这样可以减小误差。在ADC工作的时候,如果想要软件触发转换,会有函数可以触发。如果想读取转换结果,也会有函数,可以读取结果。这个等会介绍扩函数的时候就可以看到了。

3.🚢ADC相关的库函数

首先我们看一下ADC CLK的配置函数,打开这个rcc.h文件,拖到最后。

这个函数是用来配置ADC CLK分频器的。它可以对APB2的72MHz时钟选择二、四、六、八分频,输入到ADC CLK,这就是这个函数的作用。

然后我们找一下ADC的库函数,打开adc.h文件,拖到最后。

三个初始化相关函数

这三个函数和其它模块的库函数一样,都是老朋友,不用多讲了。

ADC_Cmd

这个是用于给ADC上电的,也就是这里的开关控制

ADC_DMACmd

这个是用于开启DMA输出信号的。如果使用DMA转运数据,就得调用这个函数。这个我们下节讲DMA的时候再用。

ADC_ITConfig

中断输出控制,也就是这里用于控制某个中断能不能通过NVIC

四个校准相关函数

接下来这里有四个函数

分别是复位校准、获取复位校准状态、开始校准、获取开始校准状态,这就是用于控制校准的函数。我们在ADC初始化完成之后依次调用就行了。

ADC_SoftwareStartConvCmd

ADC软件开始转换控制这个就是用于软件触发的函数了调用一下就能软件触发转换了也就是这里的触发控制,我们目前使用软件触发。

ADC_GetSoftwareStartConvStatus

ADC获取软件开始转换状态,从名字上来看,这个函数好像是判断转换是不是正在进行的。我们是不是可以调用这个函数来判断转换是否已经结束?答案是不行的。这个函数就是用来获取CR2SWSTART这一位。

在手册里可以看到这一位的作用是开始转换规则通道由软件设置该位启动转换转换开始后硬件马上清除此位。

因此,ADC_SoftwareStartConvCmd这个函数就是给SWSTART位置1,以开始转换的。

而ADC_GetSoftwareStartConvStatus这个函数是返回SWSTART的状态。

由于SWSTART位在转换开始后立刻清零了。所以这个函数的返回值跟转换是否结束毫无关系。

那如何才能知道转换是否结束?

我们需要用到下面这个函数:

ADC_GetFlagStatus

获取标志位状态,然后参数给EOC的标志位,判断EOC标志位是不是置1了。如果转换结束,EOC标志位置1,然后调用这函数判断标志位。这样才是正确的判断转换是否结束的方法。

所以ADC_GetSoftwareStartConvStatus这个函数其实没啥用,我们一般不用,不要被它误导了。

然后下面这两个函数是用来配置间断模式的。

 第一个函数是每隔几个通道间断一次。第二个函数是是不是启用间断模式。需要间断模式的话,可以了解一下。

ADC_RegularChannelConfig

DC规则组通道配置,这个函数比较重要。它的作用就是给序列的每个位置填写指定的通道,就是填写点菜菜单的过程

第一个参数是ADCx,第二个ADC channel就是理想指定的通道。第三个rank就是序列几的位置。然后第四个sample time就是指定通道的采样时间。

ADC_ExternalTrigConvCmd

ADC外部触发转换控制,就是是否允许外部触发转换。

ADC_GetConversionValue

ADC获取转换值,这个函数也比较重要,就是获取AD转换的数据寄存器读取转换结果就要使用这个函数。

ADC_GetDualModeConversionValue

之后,ADC获取双模式转换值,这个是双ADC模式读取转换结果的函数,我们暂时不用。

以上这些函数就是对ADC的一些基本功能和规则组的配置。

九个配置ADC注入组的函数

然后接下来这里有一大批函数,里面都带了一个injected,就是注入组的意思。

这一大批函数都是对ADC注入组进行配置的。

三个模拟看门狗配置的函数

然后下面的这三个函数就是对模拟看门狗进行配置的。

第一个是是否启动模拟看门狗。第二个是配置高低阈值。第三个是配置看门的通道。

ADC_TempSensorVrefintCmd

 ADC温度传感器内部参考电压控制,这个是用来开启内部的两个通道的。如果你要用这两个通道,得调用一下这个函数开启一下,要不然是读不到正确的结果的。

四个获取或清除标志位函数

分别是获取标志位状态、清除标志位、获取中断状态、清除中断挂起位,这些函数也是常用函数了,不用多说。

看完这些函数我们来开始写代码。

4.🚢代码实现

//配置ADC是工作在独立模式,还是双ADC模式
//独立模式,ADC1和ADC2各转换各的
#define ADC_Mode_Independent                       ((uint32_t)0x00000000)
//其余的都是双ADC模式,相对比较复杂
#define ADC_Mode_RegInjecSimult                    ((uint32_t)0x00010000)
#define ADC_Mode_RegSimult_AlterTrig               ((uint32_t)0x00020000)
#define ADC_Mode_InjecSimult_FastInterl            ((uint32_t)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl            ((uint32_t)0x00040000)
#define ADC_Mode_InjecSimult                       ((uint32_t)0x00050000)
#define ADC_Mode_RegSimult                         ((uint32_t)0x00060000)
#define ADC_Mode_FastInterl                        ((uint32_t)0x00070000)
#define ADC_Mode_SlowInterl                        ((uint32_t)0x00080000)
#define ADC_Mode_AlterTrig                         ((uint32_t)0x00090000)

ADC校准,如下四个函数对应ADC校准的四个步骤

//1.复位校准
void ADC_ResetCalibration(ADC_TypeDef* ADCx);
//2.等地复位校准
FlagStatus ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx);
//3.开始校准
void ADC_StartCalibration(ADC_TypeDef* ADCx);
//4.等待校准完成
FlagStatus ADC_GetCalibrationStatus(ADC_TypeDef* ADCx);

4.1 实验1-单ADC转换

代码 AD.C

#include "stm32f10x.h"                  // Device header
#include "AD.h"void AD_Init(void)
{//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//APB2 GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//APB2 GPIOA时钟//RCC_ADC Clock预分频值RCC_ADCCLKConfig(RCC_PCLK2_Div6);	//RCC_ADC_Clock=72Mhz/6=12Mhz//GPIOA_Pin0配置为模拟输入//GPIOA_Pin0作为ADC1的输入通道1GPIO_InitTypeDef gpioInitStructure;gpioInitStructure.GPIO_Mode = GPIO_Mode_AIN;gpioInitStructure.GPIO_Pin = GPIO_Pin_0;gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStructure);//ADC模拟输入多路开关选择ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_55Cycles5);//ADC_Init初始化ADC_InitTypeDef ADC_InitStruct;ADC_StructInit(&ADC_InitStruct);ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//非外部触发,软件触发方式ADC_InitStruct.ADC_ScanConvMode = DISABLE;			//ADC使用非扫描模式ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;	//ADC使用非连续转换模式(单次模式)ADC_InitStruct.ADC_NbrOfChannel = 1;				//ADC规则组转换列表里的数目ADC_Init(ADC1, &ADC_InitStruct);//ADC开关ADC_Cmd(ADC1, ENABLE);//ADC校准ADC_ResetCalibration(ADC1);							//软件置标志位while(ADC_GetResetCalibrationStatus(ADC1) == SET);	//当校准完成之后,硬件自动清除标志位ADC_StartCalibration(ADC1);							//软件置标志位while(ADC_GetCalibrationStatus(ADC1) == SET);		//当校准完成之后,硬件自动清除标志位
}uint16_t GetValue(void)
{uint16_t ADCValue;//软件ADC触发转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);//等待ADC完成while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);ADCValue = ADC_GetConversionValue(ADC1);	//读取清除EOC标志位return ADCValue;
}

代码AD.h

#ifndef __AD_H__
#define __AD_H__void AD_Init(void);
uint16_t GetValue(void);#endif

代码 main.c

#include "stm32f10x.h"                  // Device header
#include "oled.h"
#include "Countersensor.h"
#include "Encoder.h"
#include "Timer.h"
#include "AD.h"
#include "Delay.h"extern uint16_t Num;int main(int argc, char *argv[])
{	uint16_t ADValue;OLED_Init();OLED_ShowString(1, 1, "Cnt:");AD_Init();OLED_ShowString(1, 1, "ADValue:");while(1){ADValue = GetValue();OLED_ShowNum(2, 1, ADValue, 6);Delay_ms(100);}return 1;
}

实验结果:

如果想显示一下实际的电压值怎么办?

这只需要对这个数据进行一个线性变换就行了。我们在上面定义一个变量表示电压

然后我们将转换的结果再进行一下运算Voltage = (float)ADValue / 4095 * 3.3;,这样就能得到电压值。

另外这里要注意因为AD value是整数,在除4095之后会舍弃掉小数部分,这样会导致计算错误。所以我们先把AD value类型强转为float,这样再除才不会出问题。

由于目前我们的OLED驱动还没有显示浮点数的函数(这个之后讲OLED的时候再加)。目前这里我们如果想显示浮点数,可以用显示整数的函数来操作。

如果直接用显示整数的函数的话,小数就会舍弃掉,所以我们要用两个显示整数的函数,将第二个显示整数的函数的值再进行一下处理变成小数显示出来,也就是先把书扩大100倍,比如原来是1.23,现在就是123,然后再对100取余,就是23,这样就把1.23的小数部分取出来了。

另外由于浮点数是不能取余的,所以(Voltage * 100)要括起来,然后再进行强制类型转换变成整数,再对它取余。这样就可以显示浮点数了。

这里实际上AD值等于4096时才对应3.3V负,会有一个数的偏差,所以AD值最大的4095实际上对应的应该是比3.3V小一丢丢,没有办法达到满量程3.3V,这个是受限于ADC的结构,具体就不再细说了。总之就是认为4095对应3.3V伏可以,认为,4096对应3.3V也可以,只有一点点偏差,也看不出来差别。

如果就只是进行阈值判断数据记录的话,也可以不进行变换,直接使用原始的AD数据,这样也是可以

连续转换模式

目前我们使用的是第一种转换方式:单次转换、非扫描

我们还可以使用第二种转换方式:连续转换、非扫描。这个模式的好处就是不需要不断的触发,也不需要等待转换完成的。

这种模式只要对程序稍作修改就行。我们要切换为连续转换模式,那么这个参数就要改成enable。

连续转换仅需要在最开始触发一次就行了,所以这里软件触发转换的函数就可以挪到初始化的最后,即在初始化完成之后,触发一次就行了。

所以在这里就不需要判断标志位这行代码了,

直接return数据寄存器的值就行了。这样程序就是单通道连续转换非扫描的模式。

下载程序现象和刚才是一样的,也能实现单通道的AD转换。这就是连续转换非车描的模式。

 4.2 实验2,多通道ADC

接线图:

在这里我们使用了四个AD通道,第一个通道还是电位器,接在PA0口。之后上面又接了三个传感器模块,分别是光敏传感器,热敏传感器、反射式红外传感器,它们的vcc和gnd都分别接在面包板的正负极。然后这个AO就是模拟量的输出引脚,三个模块的AO分别接在PA1,PA2和PA3口,加上电位器的PA0,总共是四个输入通道,同样这些GPIO口也是可以在PA0到PB1之间任意选择的。这里就选择前四个。

如何实现多通道采集?

我们首先想到的应该是后面这两种扫描模式

利用这个列表把四个通道都填进去,然后触发转换,这样就能实现多通道了。

这样确实是一种不错的方法,但是有个数据覆盖的问题。

如果想要用扫描模式实现多通道,最好要配合DMA来实现。我们下节讲完DMA之后,再来试一下扫描模式。

那我们一个通道转换完成之后,手动把数据转运出来不就行了吗?为啥非要用DMA来转运?

这个方案看似简单,但是实际操作起来会有一些问题。

  • 第一个问题就是在扫描模式下,启动列表之后,它里面每一个单独的通道转换完成之后,不会产生任何的标志位,也不会触发中断。你不知道某一个通道是不是转换完了。它只有在整个列表都转换完成之后,才会产生一次EOC标志位,才能触发中断。而这时前面的数据就已经覆盖丢失了。
  • 第二个问题就是AD转换是非常快的,刚才我们也计算过转换一个通道,大概只有几微秒。也就是说,如果你不能在几微秒的时间内把数据转运走,数据就会丢失,这对我们程序手动转移数据要求就比较高了。

 所以在扫描模式下,手动转移数据是比较困难的。不过比较困难,也不是说手动转运不可行,我们可以使用间断模式,在扫描的时候,每转换一个通道就暂停一次,等我们手动把数据转运走之后再继续触发,继续下一次转换。这样可以实现手动转移数据的功能。

但是由于单个通道转换完成之后,没有标志位。所以启动转换完成之后,只能通过Delay延时的方式,延时足够长的时间,才能保证转换完成,这种方式既不能让我们省心,也不能提高效率。所以我们暂时不推荐使用。

这些方法都不行,我们本节是不是就不能实现多通道了?答案是能实现,而且非常简单,怎么实现?

我们可以使用单次转换非扫描的模式来实现多通道。只需要在每次触发转换之前手动更改一下列表第一个位置的通道就行了。

比如,第一次转换,先写入通道0,之后触发,等待、读值。第二次转换,再把通道0,改成通道1,之后触发,等待、读值。第三次转换,再先改成通道二修改......这样在转换前先指定一下通道,再启动转换,就可以轻松的实现多通道转换的功能了。

那么我们本次的代码就比较简单,只需要做一些简单的修改就行了。

我们可以把这个填充通道的这一句代码剪切,

然后放到触发转换之前

然后我们想指定的通道,可以作为成AD_GetValue函数的参数

这样就行了。

这样我们在调用AD_GetValue进行转换时,只需要指定一个转换的通道,返回值就是我们指定通道的结果了。

接下来我们现在要指定的通道是通道0/1/2/3,所以上面这里的GPIO初始化也不要忘了加上这几个引脚。

源码如下:

AD.c

#include "stm32f10x.h"                  // Device header
#include "AD.h"void AD_Init(void)
{//开启RCC时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	//APB2 GPIOA时钟RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	//APB2 GPIOA时钟//RCC_ADC Clock预分频值RCC_ADCCLKConfig(RCC_PCLK2_Div6);	//RCC_ADC_Clock=72Mhz/6=12Mhz//GPIOA_Pin0配置为模拟输入//GPIOA_Pin0作为ADC1的输入通道1GPIO_InitTypeDef gpioInitStructure;gpioInitStructure.GPIO_Mode = GPIO_Mode_AIN;gpioInitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3;gpioInitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &gpioInitStructure);//ADC_Init初始化ADC_InitTypeDef ADC_InitStruct;ADC_StructInit(&ADC_InitStruct);ADC_InitStruct.ADC_Mode = ADC_Mode_Independent;ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//非外部触发,软件触发方式ADC_InitStruct.ADC_ScanConvMode = DISABLE;			//ADC使用非扫描模式ADC_InitStruct.ADC_ContinuousConvMode = DISABLE;	//ADC使用非连续转换模式(单次模式)//ADC_InitStruct.ADC_ContinuousConvMode = ENABLE;	//ADC使用非连续转换模式(单次模式)ADC_InitStruct.ADC_NbrOfChannel = 1;				//ADC规则组转换列表里的数目ADC_Init(ADC1, &ADC_InitStruct);//ADC开关ADC_Cmd(ADC1, ENABLE);//ADC校准ADC_ResetCalibration(ADC1);							//软件置标志位while(ADC_GetResetCalibrationStatus(ADC1) == SET);	//当校准完成之后,硬件自动清除标志位ADC_StartCalibration(ADC1);							//软件置标志位while(ADC_GetCalibrationStatus(ADC1) == SET);		//当校准完成之后,硬件自动清除标志位}uint16_t GetValue(uint8_t ADC_Channel)
{uint16_t ADCValue;//ADC模拟输入多路开关选择ADC_RegularChannelConfig(ADC1, ADC_Channel, 1, ADC_SampleTime_55Cycles5);//软件ADC触发转换ADC_SoftwareStartConvCmd(ADC1, ENABLE);//等待ADC完成while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);ADCValue = ADC_GetConversionValue(ADC1);	//读取清除EOC标志位return ADCValue;
}

AD.h

#ifndef __AD_H__
#define __AD_H__void AD_Init(void);
uint16_t GetValue(uint8_t ADC_Channel);#endif

main.c

#include "stm32f10x.h"                  // Device header
#include "oled.h"
#include "Countersensor.h"
#include "Encoder.h"
#include "Timer.h"
#include "AD.h"
#include "Delay.h"extern uint16_t Num;int main(int argc, char *argv[])
{	uint16_t ADValue;float voltage;OLED_Init();OLED_ShowString(1, 1, "Cnt:");AD_Init();OLED_ShowString(1, 1, "AD1:0000");OLED_ShowString(2, 1, "AD2:0000");OLED_ShowString(3, 1, "AD3:0000");OLED_ShowString(4, 1, "AD3:0000");while(1){ADValue = GetValue(ADC_Channel_0);OLED_ShowNum(1,5,ADValue,4);ADValue = GetValue(ADC_Channel_1);OLED_ShowNum(2,5,ADValue,4);ADValue = GetValue(ADC_Channel_2);OLED_ShowNum(3,5,ADValue,4);ADValue = GetValue(ADC_Channel_3);OLED_ShowNum(4,5,ADValue,4);Delay_ms(100);}return 1;
}

实验结果:

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

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

相关文章

【数据结构】树-二叉树-堆(下)

🍃 如果觉得本系列文章内容还不错,欢迎订阅🚩 🎊个人主页:小编的个人主页 🎀 🎉欢迎大家点赞👍收藏⭐文章 ✌️ 🤞 🤟 🤘 🤙 👈 &…

-XSS-

链接 https://github.com/do0dl3/xss-labs 搭建过程非常容易的 搭建好之后,就可以点击图片开始闯关了 第一关--JS弹窗函数alert() 显示payload的长度是4 level1.php?nametest level1.php?nametest1 发现只要改变name的值就显示什么在页面上 没有什么过滤的 …

【数据结构与算法】《Java 算法宝典:探秘从排序到回溯的奇妙世界》

目录 标题:《Java 算法宝典:探秘从排序到回溯的奇妙世界》一、排序算法1、冒泡排序2、选择排序3、插入排序4、快速排序5、归并排序 二、查找算法1、线性查找2、二分查找 三、递归算法四、动态规划五、图算法1. 深度优先搜索(DFS)2…

transformControls THREE.Object3D.add: object not an instance of THREE.Object3D.

把scene.add(transformControls);改为scene.add(transformControls.getHelper());

计算机视觉专栏(1)【LeNet】论文详解

Lenet 系列 论文精讲部分0.摘要1.引言2.CNN3.结果分析4.总结 论文精讲部分 本专栏旨在深入解析计算机视觉模型的论文及其发展背景,并通过代码部分的实际实验来加深理解。读者可以根据自己的需要参考其中的内容。其主体为原文,笔者理解内容会采用引用格式…

[ 问题解决篇 ] 解决windows虚拟机安装vmtools报错-winserver2012安装vmtools及安装KB2919355补丁 (附离线工具)

🍬 博主介绍 👨‍🎓 博主介绍:大家好,我是 _PowerShell ,很高兴认识大家~ ✨主攻领域:【渗透领域】【数据通信】 【通讯安全】 【web安全】【面试分析】 🎉点赞➕评论➕收藏 养成习…

Window on ARM解锁所有的TTS语音包供python调用

Window on ARM解锁所有的TTS语音包供python调用 可用的语音包查看查看TTS可用的语音包解锁语音包设置升级系统打开注册表导出注册表修改注册表导入新的注册表可用的语音包查看 微软的Windows 10操作系统为设备上安装的每种语言提供了一套语音。但只有部分已安装的语音能在整个…

EPLAN创建宏并自定义部件库详细案例操作(三)

#通过导入EDZ格式部件库的样式,模仿制作一个自定义的部件库# 续 EPLAN创建宏并自定义部件库详细案例操作(二) 需要部件库文件(EDZ)格式,可以在此下载: https://download.csdn.net/download/weixin_44166380/89935582 五、创建部件库 本章节的部分操作忽略,具体可参见…

电子电气架构 --- 车载芯片现状

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 所有人的看法和评价都是暂时的,只有自己的经历是伴随一生的,几乎所有的担忧和畏惧…

我docker拉取mysql镜像时用的是latest,我该怎么看我的镜像版本是多少?可以通过一下三种方法查看

我docker拉取mysql镜像时用的是latest,我该怎么看我的镜像版本是多少? 方法一:查看 Docker 镜像标签 你可以查看 Docker 镜像的标签信息,了解当前使用的 MySQL 镜像版本。 具体步骤如下: 1. 列出本地 Docker 镜像&am…

识别风险的提示清单

在PMBOK(《项目管理体系指南》)中,介绍了这样一个概念,在识别风险时,可以提供一个参考清单,让大家基于一个清单来思考,这个项目可能有哪些具体的风险。 PMBOK中的风险提示清单,包括…

Unreal Engine 5 C++(C#)开发:使用蓝图库实现插件(二)编辑BPLibrary.h中的枚举及结构体

目录 引言 一、头文件编写 1.1Kismet/BlueprintFunctionLibrary.h 1.2BPLibrary.generated.h的作用 1.3IImageWrapper.h 1.4 IImageWrapperModule.h 1.5 Engine/Texture2D.h 1.6CoreMinimal.h 二、定义图片/路径类型的枚举 2.1图片枚举类EImageType 2.2路径枚举类EPath…

Vuestic 整理使用

简单示例 1. 条件渲染 2. 列表渲染 3. 组件插槽 4. 插值语法 5. 前后端路由的区别(还是转一下,可以减少代码量)SFC 构建 … … Okay,可以干活了,通顺 数据表的操作更加简化了 数据类别通过后端路由区别,但是还得由前端路由转一下 简单了许多呀,上脚手…

ssm017网上花店设计+vue(论文+源码)_kaic

设计题目:网上花店的设计与实现 摘 要 网络技术和计算机技术发展至今,已经拥有了深厚的理论基础,并在现实中进行了充分运用,尤其是基于计算机运行的软件更是受到各界的关注。加上现在人们已经步入信息时代,所以对于信…

网页上视频没有提供下载权限怎么办?

以腾讯会议录屏没有提供下载权限为例,该怎么办呢? 最好的办法就是找到管理员,开启下载权限。如果找不到呢,那就用这个办法下载。 1.打开Microsoft Edge浏览器的扩展 2.搜索“视频下载”,选择“视频下载Pro” 3.点击“…

使用pyecharts绘制词云图

一、什么是词云图? 词云图是一种用来展现高频关键词的可视化表达,通过文字、色彩、图形的搭配,产生有冲击力地视觉效果,而且能够传达有价值的信息。 制作词云图的网站有很多,简单方便,适合小批量操作。 …

一、ARMv8寄存器之通用、状态、特殊寄存器

ARMV8核心寄存器数量是非常大的,为了更好的学习,可以划分为以下几大类: 通用寄存器。这类寄存器主要是用来暂存数据和参与运算。通过load\store指令操作。状态寄存器。AArch64体系结构使用PSTATE寄存器表示当前处理器状态。特殊寄存器。有专门…

云渲染突破酒店3D动画渲染速度与成本瓶颈!

3D动画已经成为众多行业,尤其是酒店业,用于营销和展示其独特卖点的重要工具。通过生动的3D动画,酒店能够突出其特色和优势,从而吸引更多潜在客户。然而,在3D动画制作过程中,渲染环节往往是一个耗时且技术要…

LabVIEW偏振调制激光高精度测距系统

在航空航天、汽车制造、桥梁建筑等先进制造领域,许多大型零件的装配精度要求越来越高,传统的测距方法在面对大尺寸、高精度测量时,难以满足工业应用的要求。绝对测距技术在大尺度测量上往往会因受环境影响大、测距精度低而无法满足需求。基于…

WPF+MVVM案例实战(六)- 自定义分页控件实现

文章目录 1、项目准备2、功能实现1、分页控件 DataPager 实现2、分页控件数据模型与查询行为3、数据界面实现 3、运行效果4、源代码获取 1、项目准备 打开项目 Wpf_Examples,新建 PageBarWindow.xaml 界面、PageBarViewModel.cs ,在用户控件库 UserControlLib中创建…