详解DAC数模转换+DAC输出模拟电压的测量比对实验程序

前言:详解DAC数模转换原理+DAC输出模拟电压的测量比对实验程序(使用 DAC 通道 1 输出模拟电压,然后通过 ADC1 的通道 1 对该输出电压进行读取,并显示在 LCD 模块上面,DAC 的输出电压可以通过按键(或 USMART)进行调整。)

目录

1.数模转换DAC原理

硬件设计

2.实验程序讲解

源码


1.数模转换DAC原理

        STM32的DAC模块(数字/模拟转换模块)是12位数字输入, 电压输出型的DAC。DAC可以配置为8位或12位模式,也可以与DMA控制器配合使用。DAC工作在12位模式时,数据可以设置成左对齐或右对齐。DAC模块有2个输出通道,每个通道都有单独的转换器。在双DAC模式下,2个通道可以 独立地进行转换,也可以同时进行转换并同步地更新2个通道的输出。DAC可以通过引脚输入参考电压VREF+以获得更精确的转换结果。

1.1.STM32的DAC模块主要特点有

  • ①2个DAC转换器:每个转换器对应1个输出通道
  • ②8位或者12位单调输出
  • ③12位模式下数据左对齐或者右对齐
  • ④同步更新功能
  • ⑤噪声波形生成
  • ⑥三角波形生成
  • ⑦双DAC通道同时或者分别转换
  • ⑧每个通道都有DMA功能

1.2.DAC模块方图:

在DHRx相应寄存器写值就可以被控制写到DORx数据寄存器输出,

控制MAMPx和WAVEBx等寄存器可以相应的位可以生成三角波、噪音波,

下图中的左上角是触发控制,可以通过外部的定时器的事件触发或者软件触发。

VDDA和VSSA为DAC模块模拟部分的供电。

Vref+则是DAC模块的参考电压。(1.8v~13.3v)

DAC_OUTx就是DAC的输出通道了,F4的DAC1_OUT1对应PA4,DAC1_OUT2对应PA5引脚。

使用DAC时,引脚要配置为模拟模式(AIN)。

1.3.DAC转换:

1.4.DAC数据格式:

1.5.DAC触发选择:

1.6. DAC输出电压:

除以4095是因为是最高12位,参考电压一般都是3.3V 。

1.7.DAC通道使能:

1.8.DAC输出缓冲器使能:

1.9.DAC相关寄存器:

硬件设计

本次实验使用STM32F4的DAC引脚PA4,ADC引脚PA5。(DAC输出,ADC测量输入)

可以使用跳线帽将两个引脚连接到一起,实现例如输入100数值的DAC它的电压是不是0.3v?可以用内部的ADC再去测量这个电压,测量出来看一下是不是0.3v,进行一个比较。

用到的硬件资源有:
1 ) 指示灯 DS0
2 KEY_UP KEY1 按键
3 ) 串口
4 TFTLCD 模块
5 ADC
6 DAC
我们使用 DAC 通道 1 输出模拟电压,然后通过 ADC1 的通道 1 对该输出电压进行读取,并显示在 LCD 模块上面, DAC 的输出电压,我们通过按键(或 USMART )进行设置。
我们需要用到 ADC 采集 DAC 的输出电压,所以需要在硬件上把他们短接起来。 ADC 和 DAC 的连接原理图如下图 所示:

P12 是多功能端口,我们只需要通过跳线帽短接 P14 ADC DAC ,就可以开始做本
章实验了。如下图 所示:

2.实验程序讲解

        通过以上介绍,我们了解了 STM32F4 实现 DAC 输出的相关设置,我们将使用 DAC 模块的通道 1 来输出模拟电压。这里我们用到的库函数以及相关定义分布在文件 stm32f4xx_dac.c 以及头文件 stm32f4xx_dac.h 中。实现上面功能的详细设置步骤如下:
1 )开启 PA 口时钟,设置 PA4 为模拟输入。
STM32F407ZGT6 DAC 通道 1 是接在 PA4 上的,所以,我们先要使能 GPIOA 的时钟,然后设置 PA4 为模拟输入。 这里需要特别说明一下,虽然 DAC 引脚设置为输入,但是 STM32F4 内部会连接在 DAC 模拟输出上, 是引脚复用映射。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能 GPIOA 时
钟
 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
 GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
 GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

对于 DAC 通道与引脚对应关系,这在 STM32F4 的数据手册引脚表上有列出,如下图:  

2 )使能 DAC1 时钟。
同其他外设一样,要想使用,必须先开启相应的时钟。 STM32F4 DAC 模块时钟是由APB1 提供的,所以我们先要在通过调用函数 RCC_APB1PeriphClockCmd 来使能 DAC1 时钟。
APB1 提供的,所以我们先要在通过调用函数 RCC_APB1PeriphClockCmd 来使能 DAC1 时
钟。
3 )初始化 DAC, 设置 DAC 的工作模式。
该部分设置全部通过 DAC_CR 设置实现,包括: DAC 通道 1 使能、 DAC 通道 1 输出 缓存关闭、不使用触发、不使用波形发生器等设置。这里 DAC 初始化是通过函数 DAC_Init 完成的:
void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct);
结构体类型 DAC_InitTypeDef 的定义:
typedef struct
{
 uint32_t DAC_Trigger; 
 uint32_t DAC_WaveGeneration; 
 uint32_t DAC_LFSRUnmask_TriangleAmplitude; 
 uint32_t DAC_OutputBuffer; 
}DAC_InitTypeDef;
这个结构体的定义还是比较简单的,只有四个成员变量,下面我们一一讲解。
第一个参数 DAC_Trigger 用来设置是否使用触发功能,前面已经讲解过这个的含义,这里
我们不是用触发功能,所以值为 DAC_Trigger_None
第二个参数 DAC_WaveGeneratio 用来设置是否使用波形发生,这里我们前面同样讲解过不
使用。所以值为 DAC_WaveGeneration_None
第三个参数 DAC_LFSRUnmask_TriangleAmplitude 用来设置屏蔽 / 幅值选择器,这个变量只
在使用波形发生器的时候才有用,这里我们设置为 0 即可,值为 DAC_LFSRUnmask_Bit0
第四个参数 DAC_OutputBuffer 是用来设置输出缓存控制位,前面讲解过,我们不使用输出
缓存,所以值为 DAC_OutputBuffer_Disable 。到此四个参数设置完毕。看看我们的实例代码:
DAC_InitTypeDef DAC_InitType;
DAC_InitType.DAC_Trigger=DAC_Trigger_None; //不使用触发功能 TEN1=0
DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;
DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ; //DAC1 输出缓存关闭
DAC_Init(DAC_Channel_1,&DAC_InitType); //初始化 DAC 通道 1
4 )使能 DAC 转换通道
初始化 DAC 之后,理所当然要使能 DAC 转换通道,库函数方法是:
DAC_Cmd(DAC_Channel_1, ENABLE); //使能 DAC 通道 1
5 )设置 DAC 的输出值。
通过前面 4 个步骤的设置, DAC 就可以开始工作了,我们使用 12 位右对齐数据格式, 所以我们通过设置 DHR12R1 ,就可以在 DAC 输出引脚( PA4 )得到不同的电压值了。设置 DHR12R1 的库函数是:
DAC_SetChannel1Data(DAC_Align_12b_R, 0); //12 位右对齐数据格式设置 DAC 值
第一个参数设置对齐方式,可以为 12 位右对齐 DAC_Align_12b_R ,12 位左对DAC_Align_12b_L 以及 8 位右对齐 DAC_Align_8b_R 方式。 第二个参数就是 DAC 的输入值了,这个很好理解,初始化设置为 0 。这里,还可以读出 DAC 对应通道最后一次转换的数值,函数是:
DAC_GetDataOutputValue(DAC_Channel_1);
设置和读出一一对应很好理解,这里就不多讲解了。
最后,再提醒一下大家,本例程,我们使用的是 3.3V 的参考电压,即 Vref+ 连接 VDDA
通过以上几个步骤的设置,我们就能正常的使用 STM32F4 DAC 通道 1 来输出不同的模拟电压了。

源码

main.c

#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "lcd.h"
#include "adc.h"
#include "dac.h"
#include "key.h"
#include "beep.h"


int main(void)
{ 
	u16 adcx;
	float temp;
 	u8 t=0;	 
	u16 dacval=0;
	u8 key;	
	NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置系统中断优先级分组2
	delay_init(168);      //初始化延时函数
	uart_init(115200);		//初始化串口波特率为115200
	
	LED_Init();					//初始化LED 
 	LCD_Init();					//LCD初始化
	Adc_Init(); 				//adc初始化
	KEY_Init(); 				//按键初始化
	Dac1_Init();		 		//DAC通道1初始化	
	POINT_COLOR=RED; 
	LCD_ShowString(30,50,200,16,16,"Explorer STM32F4");	
	LCD_ShowString(30,70,200,16,16,"DAC TEST");	
	LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
	LCD_ShowString(30,110,200,16,16,"2024/6/12");	 
	LCD_ShowString(30,130,200,16,16,"WK_UP:+  KEY1:-");	 
	POINT_COLOR=BLACK;//设置字体为黄色      	 
	LCD_ShowString(30,150,200,16,16,"DAC VAL:");	      
	LCD_ShowString(30,170,200,16,16,"DAC VOL:0.000V");	      
	LCD_ShowString(30,190,200,16,16,"ADC VOL:0.000V");
 	
  DAC_SetChannel1Data(DAC_Align_12b_R,dacval);//初始值为0	
	while(1)
	{
		t++;
		key=KEY_Scan(0);			  
		if(key==WKUP_PRES)
		{		 
			if(dacval<4000)dacval+=200;
			DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
		}else if(key==2)	
		{
			if(dacval>200)dacval-=200;
			else dacval=0;
			DAC_SetChannel1Data(DAC_Align_12b_R, dacval);//设置DAC值
		}	 
		if(t==10||key==KEY1_PRES||key==WKUP_PRES) 	//WKUP/KEY1按下了,或者定时时间到了
		{	  
 			adcx=DAC_GetDataOutputValue(DAC_Channel_1);//读取前面设置DAC的值
			LCD_ShowxNum(94,150,adcx,4,16,0);     	   //显示DAC寄存器值
			temp=(float)adcx*(3.3/4096);			         //得到DAC电压值
			adcx=temp;
 			LCD_ShowxNum(94,170,temp,1,16,0);     	   //显示电压值整数部分
 			temp-=adcx;
			temp*=1000;
			LCD_ShowxNum(110,170,temp,3,16,0X80); 	   //显示电压值的小数部分
 			adcx=Get_Adc_Average(ADC_Channel_5,10);		//得到ADC转换值	  
			temp=(float)adcx*(3.3/4096);			        //得到ADC电压值
			adcx=temp;
 			LCD_ShowxNum(94,190,temp,1,16,0);     	  //显示电压值整数部分
 			temp-=adcx;
			temp*=1000;
			LCD_ShowxNum(110,190,temp,3,16,0X80); 	  //显示电压值的小数部分
			LED0=!LED0;	   
			t=0;
		}	    
		delay_ms(10);	 
			GPIO_ResetBits(GPIOF,GPIO_Pin_9);  //LED0????GPIOF.9??,?  ??LED0=0;
	  GPIO_SetBits(GPIOF,GPIO_Pin_10);   //LED1????GPIOF.10??,? ??LED1=1;
		GPIO_ResetBits(GPIOF,GPIO_Pin_8); //BEEP????, ??BEEP=0;
		delay_ms(800);  		   //??800ms
		GPIO_SetBits(GPIOF,GPIO_Pin_9);	   //LED0????GPIOF.0??,?  ??LED0=1;
		GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED1????GPIOF.10??,? ??LED1=0;
		delay_ms(800);                     //??800ms
		GPIO_SetBits(GPIOF,GPIO_Pin_9);	   //LED0????GPIOF.0??,?  ??LED0=1;
		GPIO_SetBits(GPIOF,GPIO_Pin_10); //LED1????GPIOF.10??,? ??LED1=1;
		delay_ms(1800);                     //??800ms
		GPIO_ResetBits(GPIOF,GPIO_Pin_9);	   //LED0????GPIOF.0??,?  ??LED0=0;
		GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED1????GPIOF.10??,? ??LED1=0;
  	GPIO_SetBits(GPIOF,GPIO_Pin_8);   //BEEP????, ??BEEP=1;
		delay_ms(1800);                     //??800ms			
		
	
		for(i=0;i<5;i++)
			{
			 GPIO_ResetBits(GPIOF,GPIO_Pin_8); //BEEP????, ??BEEP=0;
			 GPIO_SetBits(GPIOF,GPIO_Pin_9);	   //LED0????GPIOF.9??,?  ??LED0=1;
			 delay_ms(800);
			 GPIO_ResetBits(GPIOF,GPIO_Pin_9); //LED0????GPIOF.9??,? ??LED0=0;
			 delay_ms(800);     
			}
		for(i=0;i<5;i++)
			{
			 GPIO_SetBits(GPIOF,GPIO_Pin_10);	   //LED0????GPIOF.10??,?  ??LED1=1;
			 delay_ms(800);
			 GPIO_ResetBits(GPIOF,GPIO_Pin_10); //LED0????GPIOF.10??,? ??LED1=0;
			 delay_ms(800);     
			}	
	}	
}

dac.c

#include "dac.h"

//DAC通道1输出初始化
void Dac1_Init(void)
{  
  GPIO_InitTypeDef  GPIO_InitStructure;
	DAC_InitTypeDef DAC_InitType;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);//使能DAC时钟
	   
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化

	DAC_InitType.DAC_Trigger=DAC_Trigger_None;	//不使用触发功能 TEN1=0
	DAC_InitType.DAC_WaveGeneration=DAC_WaveGeneration_None;//不使用波形发生
	DAC_InitType.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;//屏蔽、幅值设置
	DAC_InitType.DAC_OutputBuffer=DAC_OutputBuffer_Disable ;	//DAC1输出缓存关闭 BOFF1=1
  DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1

	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC通道1
  
  DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
}
//设置通道1输出电压
//vol:0~3300,代表0~3.3V
void Dac1_Set_Vol(u16 vol)
{
	double temp=vol;
	temp/=1000;
	temp=temp*4096/3.3;
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);//12位右对齐数据格式设置DAC值
}

adc.c

#include "adc.h"
#include "delay.h"		 


//初始化ADC
//这里我们仅以规则通道为例
//我们默认仅开启通道1																	   
void  Adc_Init(void)
{    
 
  GPIO_InitTypeDef  GPIO_InitStructure;
	ADC_CommonInitTypeDef ADC_CommonInitStructure;
	ADC_InitTypeDef       ADC_InitStructure;
	
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);//使能GPIOA时钟
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);//使能ADC1时钟

//先初始化IO口
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;//模拟输入
  GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化  
 
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,ENABLE);	//ADC1复位
	RCC_APB2PeriphResetCmd(RCC_APB2Periph_ADC1,DISABLE);	//复位结束	 
 
 
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;//独立模式
  ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
  ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_Disabled; //DMA失能
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2; 
  ADC_CommonInit(&ADC_CommonInitStructure);
	
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;//12位模式
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;//非扫描模式	
  ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;
  ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;//禁止触发检测,使用软件触发
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;//右对齐	
  ADC_InitStructure.ADC_NbrOfConversion = 1;//1个转换在规则序列中 也就是只转换规则序列1 
  ADC_Init(ADC1, &ADC_InitStructure);
	
 
	ADC_Cmd(ADC1, ENABLE);//开启AD转换器	 
}				  
//获得ADC值
//ch:通道值 0~16
//返回值:转换结果
u16 Get_Adc(u8 ch)   
{
	  	//设置指定ADC的规则组通道,一个序列,采样时间
	ADC_RegularChannelConfig(ADC1, ch, 1, ADC_SampleTime_480Cycles );	//ADC1,ADC通道,480个周期,提高采样时间可以提高精确度			    
  
	ADC_SoftwareStartConv(ADC1);		//使能指定的ADC1的软件转换启动功能	
	 
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待转换结束

	return ADC_GetConversionValue(ADC1);	//返回最近一次ADC1规则组的转换结果
}
//获取通道ch的转换值,取times次,然后平均 
//ch:通道编号
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u8 ch,u8 times)
{
	u32 temp_val=0;
	u8 t;
	for(t=0;t<times;t++)
	{
		temp_val+=Get_Adc(ch);
		delay_ms(5);
	}
	return temp_val/times;
} 
	 

相关知识:

 一、运算放大器(Operational Amplifier,简称 Op-Amp 或 运放)是一种高度灵活且多功能的电子组件,具有非常高的电压增益、高输入阻抗和低输出阻抗的特性。它在电子电路中扮演着核心角色,可以执行一系列复杂的信号处理任务。

 以下是运算放大器的一些主要作用:

1. **信号放大**:    - 运算放大器可以放大微弱的输入信号,使之达到足够的幅度,以便于后续电路处理或测量。它可以用于电压放大,既可以在同相配置中使用,也可以在反相配置中使用。

2. **数学运算**:    - 运放可以实现信号的加法、减法、积分和微分等数学运算,这些功能对于信号处理、控制系统和数据转换等领域至关重要。

3. **滤波**:    - 结合电阻和电容,运算放大器可以构成各种类型的滤波器,包括低通、高通、带通和带阻滤波器,用于信号的清洁和频率选择。

4. **比较器**:    - 运放可以用于比较两个电压信号,当输入信号超过某个阈值时,产生逻辑电平的变化,这在过零检测和电压监控电路中很常见。

5. **阻抗变换**:    - 运放可以用作缓冲器,将高阻抗信号转换为低阻抗信号,以匹配不同电路的阻抗要求。

6. **精密整流和稳压**:    - 在某些配置下,运放可以用于精密整流电路,以及作为反馈环路的一部分来实现稳压。

7. **信号转换**:    - 运放可以将电压信号转换为电流信号,反之亦然,这对于驱动负载或与电流敏感设备接口很有用。

8. **频率和脉冲生成**:    - 运算放大器可以用于产生特定频率的信号,如正弦波、方波或三角波,以及用于脉冲宽度调制(PWM)。

9. **数据转换**:    - 在模数转换器(ADC)和数模转换器(DAC)中,运放通常用于信号的调节和校准。

由于运算放大器的灵活性和多功能性,它几乎存在于所有现代电子设备中,从简单的音频放大器到复杂的工业控制系统,再到高精度测量仪器,都有其身影。

二、引脚复用和重映射

复用功能
首先、我们可以这样去理解stm32引脚的复用功能。以stm32F103RCT6芯片引脚PA9、PA10为例。
这两个芯片引脚定义如下:
PA9引脚: PA9/USART1_TX/TIM1_CH2
PA10引脚:PA10/USART1_RX/TIM1_CH3
1、这里的PA9引脚和PA10引脚我们可以理解为引脚名,用于区分两个不同的引脚。
2、可以看到PA9引脚、PA10引脚都有三种功能。其中第一项PA9和PA10是其默认功能,默认功能为GPIO功能,也即是作为通用的输入输出端口使用。
3、这样我们就知道,当PA9引脚和PA10引脚不在作为默认的GPIO功能使用,而是作为USART1_TX/USART1_RX或者作为TIM1_CH2/TIM1_CH3功能使用时,就是对PA9引脚和PA10引脚的复用。
4、总而言之,对于stm32来说,由于其内部各种外设的存在,往往每个引脚都会有几种不同的功能,这几种不同的功能都可以使用这一个端口引脚。但是由于stm32的端口引脚都有一个自己的默认功能存在,当该引脚不在作为默认功能使用时对于该引脚来说就是复用。由于大多数引脚的默认功能和其引脚名称PA9引脚或者PA10引脚一样都是作为GPIO功能使用,因此当不在作为GPIO功能而是作为其他外设的相关功能使用时就是对引脚的复用。

重映射功能
为了让工程师能够更好的安排布局及方便布线,在stm32中引入了外设引脚的重映射功能。即一个外设的引脚除了具有默认的引脚外还可以通过配置重映射寄存器的方式将这个外设的引脚映射到其他的引脚上去。
同样的以PA9引脚和PA10引脚为例,对于stm32F103RCT6芯片来说,有如下引脚定义:
PA9引脚: PA9/USART1_TX/TIM1_CH2
PA10引脚:PA10/USART1_RX/TIM1_CH3
PB6引脚: PB6/I2C1_SCL/TIM4_CH1/USART1_TX
PB7引脚: PB7/I2C1_SDA/FSMC_NADV/TIM4_CH2/USART1_RX

1、首先、我们要明确一点,重映射的概念是对于芯片的各种外设本身来说的而非GPIO。因为引脚作为GPIO功能使用时一般是其默认的功能,而重映射的概念是建立在对引脚的复用功能上的。也即是当引脚复用为非GPIO功能时才可能会使用到重映射的功能。
2、USART1_REMAP=0表示没有使用重映射功能的情况;USART1_REMAP=1则表示使用重映射功能的情况。
3、从上面表中可以看到,默认情况下(没有使用重映射),USART1的TX和RX引脚默认使用的就是PA9引脚和PA10引脚。
4、在开启重映射功能时,USART1的TX和RX引脚还可以重映射到PB6和PB7引脚上去。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PostgreSQL的学习心得和知识总结(一百四十五)|深入理解PostgreSQL数据库之ShowTransactionState的使用及父子事务有限状态机

目录结构 注&#xff1a;提前言明 本文借鉴了以下博主、书籍或网站的内容&#xff0c;其列表如下&#xff1a; 1、参考书籍&#xff1a;《PostgreSQL数据库内核分析》 2、参考书籍&#xff1a;《数据库事务处理的艺术&#xff1a;事务管理与并发控制》 3、PostgreSQL数据库仓库…

Kubernetes部署Kanboard看板管理平台

【云原生】Kubernetes部署Kanboard项目管理平台 文章目录 【云原生】Kubernetes部署Kanboard项目管理平台介绍资源列表基础环境一、检查k8s环境1.1、检查工作节点状态1.2、检查系统pod状态 二、编辑kanboard.yaml文件2.1、创建项目目录2.2、编辑kanboard.yaml文件 三、部署Kanb…

Hadoop三大组件原理详解:hdfs-yarn-MapReduce(第9天)

系列文章目录 一、HDFS读写原理【重点】 二、YARN提交mr流程【重点】 三、MapReduce计算流程【重点】 文章目录 系列文章目录前言一、HDFS读写原理[面试]1、HDFS数据写入解析2、HDFS数据读取解析 二、YARN提交mr流程[面试]1. YARN提交mr过程解析 三、MapReduce计算流程[面试]1…

探索监管沙箱在金融科技行业中的应用

一、引言 随着金融科技的快速发展&#xff0c;传统金融机构与科技企业之间的竞争也日趋激烈。为了平衡金融科技创新与风险防控&#xff0c;各国监管机构纷纷引入监管沙箱&#xff08;Regulatory Sandbox&#xff09;机制。监管沙箱作为一个受监督的安全测试区&#xff0c;允许金…

MySQL 面试突击指南:核心知识点解析1

MySQL中有哪些存储引擎? InnoDB存储引擎 InnoDB是MySQL的默认事务型引擎,也是最重要、使用最广泛的存储引擎,设计用于处理大量短期事务。 MyISAM存储引擎 在MySQL 5.1及之前版本,MyISAM是默认的存储引擎。它提供了全文索引、压缩、空间函数(GIS)等特性,但不支持事务和…

台积电(TSMC)正在探索采用新型先进芯片封装技术

台积电&#xff08;TSMC&#xff09;正在探索采用新型先进芯片封装技术&#xff0c;使用类似面板的矩形基板&#xff0c;以应对日益增长的先进多芯片组处理器需求。据日经亚洲报道&#xff0c;这项开发仍处于早期阶段&#xff0c;可能需要数年时间才能商业化&#xff0c;但如果…

Python酷库之旅-第三方库openpyxl(01)

目录 一、 openpyxl库的由来 1、背景 2、起源 3、发展 4、特点 4-1、支持.xlsx格式 4-2、读写Excel文件 4-3、操作单元格 4-4、创建和修改工作表 4-5、样式设置 4-6、图表和公式 4-7、支持数字和日期格式 二、openpyxl库的优缺点 1、优点 1-1、支持现代Excel格式…

【C语言 || 数据结构】二叉树

文章目录 前言 二叉树1.树1.1树的定义1.2 树的结构 2.特殊的树&#xff08;二叉树&#xff09;2.1 二叉树的概念2.2 特殊的二叉树2.3 二叉树的储存2.3.1 顺序储存二叉树2.3.2 链表储存二叉树 2.4 二叉树的遍历2.4.1 二叉树的中序遍历2.4.2 二叉树的前序遍历2.4.3 二叉树的后序遍…

【React】使用Token做路由权限控制

在components/AuthRoute/index.js中 import { getToken } from /utils import { Navigate } from react-router-domconst AuthRoute ({ children }) > {const isToken getToken()if (isToken) {return <>{children}</>} else {return <Navigate to"/…

Solr9 如何使用 DIH 读取数据库索引数据

使用 Solr 9 中的数据导入处理程序&#xff08;DIH&#xff09; DIH&#xff08;Data Import Handler&#xff09;提供了一种可配置的方式向 Solr 中导入数据。 从 Solr 9 开始&#xff0c;数据导入处理程序&#xff08;DIH&#xff09;已经不再直接包含在 Solr 中&#xff0c…

【Linux】关于在华为云中开放了端口后仍然无法访问的问题

已在安全组中添加规则: 通过指令: netstat -nltp | head -2 && netstat -nltp | grep 8080 运行结果: 可以看到服务器确实处于监听状态了. 通过指令 telnet 公网ip port 也提示: "正在连接xxx.xx.xx.xxx...无法打开到主机的连接。 在端口 8080: 连接失败"…

[WTL/Win32]_[中级]_[MVP架构在实际项目中的应用]

场景 在开发Windows和macOS的界面软件时&#xff0c;Windows用的是WTL/Win32技术&#xff0c;而macOS用的是Cocoa技术。而两种技术的本地语言一个主打是C,另一个却是Object-c。界面软件的源码随着项目功能增多而增多&#xff0c;这就会给同步Windows和macOS的功能造成很大负担…

数据驱动制造:EMQX ECP 指标监测功能增强生产透明度

迈向未来的工业生产&#xff0c;需要的不仅是自动化&#xff0c;更是智能化。如果工业企业的管理者能够实时监测每一生产环节的设备运行状态&#xff0c;每一数据点位情况&#xff0c;洞察和优化每一步生产流程&#xff0c;他们将能够做出更精准的决策&#xff0c;提高生产效率…

记录SpringBoot启动报错解决

记录SpringBoot启动报错解决 报错现场 Failed to configure a DataSource: url attribute is not specified and no embedded datasource could be configured. Reason: Failed to determine a suitable driver class Action: Consider the following:If you want an embedde…

紧凑型计算微型仿生复眼

欢迎关注&#xff1a;GZH《光场视觉》 图1 研制的计算微型复眼的成像原理 1. 导读 微型曲面复眼由于具有大视场成像、大景深成像、体积较小的优势&#xff0c;在机器视觉、无人机导航、生物灵感机器人等领域引起了广泛关注。然而&#xff0c;传统的微型曲面复眼存在设计/加工…

44、基于深度学习的癌症检测(matlab)

1、基于深度学习的癌症检测原理及流程 基于深度学习的癌症检测是利用深度学习算法对医学影像数据进行分析和诊断&#xff0c;以帮助医生准确地检测癌症病变。其原理和流程主要包括以下几个步骤&#xff1a; 数据采集&#xff1a;首先需要收集包括X光片、CT扫描、MRI等医学影像…

Shiro721 反序列化漏洞(CVE-2019-12422)

目录 Shiro550和Shiro721的区别 判断是否存在漏洞 漏洞环境搭建 漏洞利用 利用Shiro检测工具 利用Shiro综综合利用工具 这一篇还是参考别的师傅的好文章学习Shiro的反序列化漏洞 上一篇也是Shiro的反序列化漏洞&#xff0c;不同的是一个是550一个是721&#xff0c;那么这…

基于SSM+Jsp的水果销售管理网站

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

技术速递|Java on Azure Tooling 5月更新 - Java 对 Azure 容器应用程序的入门指南支持

作者&#xff1a;Jialuo Gan 排版&#xff1a;Alan Wang 大家好&#xff0c;欢迎阅读 Java on Azure 工具 5 月份更新。在本次更新中&#xff0c;我们将介绍 Java 在 Azure 上的容器应用程序的入门指南。希望您喜欢这些更新&#xff0c;并享受使用 Azure 工具包的流畅体验。请下…

在4面体空间内2点结构占比

有一个4面体状空间&#xff0c;由3层甲烷状分子堆积而成&#xff0c;单个甲烷4面体边长10. 内有30个点&#xff0c;在30个点中取2点&#xff0c;有30*29/2435种取法。这里要求两个点的距离必须为6.123 在435个结构中只有40个符合要求 序数 结构 序数 结构 3 1 282 3 7…