STM32学习记录(七):ADC

news/2024/11/15 1:18:23/文章来源:https://www.cnblogs.com/qianxiaohan/p/18334868

STM32学习记录(七):ADC

模拟/数字转换器(Analog-to-digital converter:ADC)将模拟量转为数字量。STM32F103C8T6中的有2个12bit转换时间为1us的A/D转换器,内置了一个温度传感器,可以通过ADC读取。

ADC的系统框图

image

image

ADC读取温度传感器

STM32内部有一个温度传感器,只有使用ADC1时,内部温度传感器才是可用的。

使用单片机STM32F103C8T6的ADC1读取内部温度传感器的步骤:

  1. 配置ADC1的时钟、初始化结构体等
  2. 配置规则组或注入组的采样通道和采样时间,采样时间应在17.1us
  3. 使能温度传感器和内部参考电压通道
  4. 开启ADC1、重置ADC校准器、开始转换
  5. 读取数据寄存器的16位或者32位(仅在ADC1的双倍模式下)的值
  6. 将读取的值使用公式转换为温度:\((V_{25}-V_{SENCE})/AVG\_Slope+25\),其中\(V_{25}\)是25摄氏度时的\(V_{SENCE}\)值,查阅数据手册第5章《Electrical characteristics》,可得典型值\(V_{25}\) =1.43V、\(AVG\_Slope\) = 4.3mv/℃

STM32F103C8T6 ADC的模拟输入通道与GPIO的对应关系如下,共有10个可用的模拟输入通道。ADC1和ADC2的模拟输入通道是共用的。

ADC1/ADC2 GPIO
ADC12_IN0 PA0
ADC12_IN1 PA1
ADC12_IN2 PA2
ADC12_IN3 PA3
ADC12_IN4 PA4
ADC12_IN5 PA5
ADC12_IN6 PA6
ADC12_IN7 PA7
ADC12_IN8 PB0
ADC12_IN9 PB1

ADC1的通道16与内部温度传感器相连,ADC1的通道17与内部参考电压\(V_{REFER}\)相连。

ADC的时钟设置

PCLK2默认等于SYSCLK,也就是72MHz,而ADC最大频率为14MHz。查阅数据手册中的表格 "Table 47. RAIN max for fADC = 14 MHz"可知,在ADC时钟为14MHz、采样时间17.1us对应的采样时间(时钟周期为单位)为239.5个时钟周期。ADC要得到14MHz的时钟,HCLK的时钟应设置为56MHz,APB2预分频器再进行二分频可得14MHz的ADC时钟频率。HAL库编程时,使用STM32CubeMX很容易配置时钟。在STM32CubeMX的时钟配置中更加直观。

image

那么使用标准库时如何将系统时钟SYSCLK修改为56MHz?参照另一篇博客:STM32修改系统时钟频率

主要程序

ADC_InitTypeDef结构体的配置需查阅固件库函数手册和参考手册。

初始化ADC

因为温度传感器是芯片内部的传感器,温度传感器已经与ADC的通道16连接,内部参考电压\(V_{REFINT}\)已经与ADC的通道17连接。注意ADC必须要开启校准,否则得到的结果是不正确的。

ADC工作模式:ADC工作模式分独立模式(independent mode)和双ADC模式(dual mode)。 见参考手册11.9 Dual ADC mode

  • 独立模式:每个ADC单独工作
  • 双ADC模式:设备有2个或更多ADC的时候才能使用。双ADC模式包括以下模式,以下模式还可以进行组合
    • 同步注入模式
    • 同步规则模式
    • 快速交错模式
    • Slow interleaved mode
    • 交替触发模式

持续转换模式:开启后,持续进行数据转换

扫描模式:此模式用于扫描一组模拟通道。对于多通道,需要开启扫描模式;单通道无需开启。

数据右对齐:转换之后数据的右对齐。对于规则组而言,数据右对齐就是12bit数据从低位到高位的顺序存放在16位的内存或者寄存器中,前高4位补0。见参考手册Figure 27. Right alignment of data。其余各个取值参照参考手册。

外部触发:转换可以由外部事件触发(例如定时器捕获、EXTI线)。事件(event)和中断(interrupt)是不同的,外部中断线配置为事件模式时,中断请求寄存器是不会被置位的,仅仅是通过脉冲发生器产生一个脉冲。

void ADC_Configuration(void)
{/* 开启GPIO、ADC1时钟 */RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHzRCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);/* 配置ADC */ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//独立工作模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式ADC_InitStructure.ADC_ScanConvMode = DISABLE;	//关闭多通道扫描模式,只有1个通道ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发,由软件触发ADC_InitStructure.ADC_NbrOfChannel = 1;	//1个ADC通道ADC_Init(ADC1, &ADC_InitStructure);/* Configures ADC1 Channel16 as: first converted channel with an 239 cycles sample time */ ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); //采样时间239.5/14MHz = 17.1us/* 使能温度传感器和内部参考电压通道 */ ADC_TempSensorVrefintCmd(ENABLE); /* 开启ADC */ADC_Cmd(ADC1, ENABLE);/* 重置ADC校准寄存器 */ADC_ResetCalibration(ADC1);/* 检查复位ADC校准是否结束 */while(ADC_GetResetCalibrationStatus(ADC1));/* 开启ADC校准 */ADC_StartCalibration(ADC1);/* 检查校准是否结束 */while(ADC_GetCalibrationStatus(ADC1));/* 开始ADC软件转换 */ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

读取数据

可以选择读取多次的数据,然后求平均值,这里演示没有多次读取并求平均值。

int main()
{COM_Init();ADC_Configuration();while(1){showTemperature();delay_ms(1000);}
}void showTemperature(void)
{/*Returns the ADC1 Master data value of the last converted channel*/ uint16_t DataValue = 0; DataValue = ADC_GetConversionValue(ADC1);// ADC精度:(VDDA/4096),VDDA是ADC供电电压,使用的是3.3v// VSENSE = DataValue*(3.3/4096);// Temperature (in °C) = {(V25 - VSENSE ) / Avg_Slope} + 25.// v25典型值1.43V  Avg_Slope 4.3mv/°c VSENSE=DataValue//精度Vdda/4096double temperature;double VSENSE = DataValue*(3.3/4096);temperature = (1.43 - VSENSE) / (0.0043) + 25;printf("VSENSE: %.2f, temperature: %.2f",VSENSE, temperature);	//向串口发送消息
}

演示结果

以下是没有加ADC校准得到的错误结果。正确的演示结果参照后面的演示结果。

image

ADC使用DMA多通道读取

什么是DMA?引用参考手册第13章:

Direct memory access (DMA) is used in order to provide high-speed data transfer between peripherals and memory as well as memory to memory. Data can be quickly moved by DMA without any CPU actions. This keeps CPU resources free for other operations.

DMA用于外设和内存之间的高速数据传输,数据通过DMA能够没有在CPU的参与下进行快速传输,DMA减轻了CPU的压力。STM32F103C8T6有一个7通道的DMA控制器,支持的外设包括ADC、SPI、I2C、USART。

ADC1在独立工作模式下的数据寄存器只有16位,对于ADC的多通道采样有两种方式:

  1. 不使用DMA。ADC应当被配置为:单次转换、关闭扫描模式、采样通道为1。通过软件设置采样通道来读取不同通道的数据
  2. 使用DMA。ADC将多个通道按照设置的采样顺序,将数据经过DMA的传输,传输到一个用户设置的缓冲区,只需读取这个缓冲区的值就可以获得每个通道的采样数据

这里介绍使用DMA的方式,ADC1的通道0、通道7、通道16这3个通道完成,连线:

  • 寻迹传感器(反射式光电传感器)AO引脚接PA0
  • 光敏电阻传感器接AO口接PA7
  • STM32内部温度传感器与通道16已经相连无需连接GPIO。

在这里传感器不做介绍。

主要程序

初始化以及配置DMA1

__IO uint16_t ADCConvertedValue[3]; //缓冲区,存放DMA将读取到的数据void DMA_Configuration(void)
{/* 开启DMA时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);/* 反初始化DMA1通道1 */DMA_DeInit(DMA1_Channel1);/* 配置DMA初始化结构体 */DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);		//配置外设基地址,这里是ADC1数据寄存器的地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;	//外设数据大小,16位DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;	//配置内存基地址,这里是存数据的内存地址DMA_InitStructure.DMA_BufferSize = 3;		//缓存区中数据的个数DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	//外设作为数据传输的来源 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	//关闭DMA的内存到内存模式DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;	//内存数据大小,16位DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable;	//内存地址递增,缓冲区要存放3个数据DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;		//循环缓存模式,即多次读取数据到缓冲区DMA_InitStructure.DMA_Priority = DMA_Priority_High;		//优先级高DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//外设地址不递增DMA_Init(DMA1_Channel1, &DMA_InitStructure);	//初始化DMADMA_Cmd(DMA1_Channel1, ENABLE);	//使能DMA
}

配置ADC

void ADC_Configuration(void)
{/* 开启GPIO、ADC1时钟 */RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);/* 配置ADC */ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;	//独立工作模式ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//关闭多通道扫描模式,只有1个通道ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发,由软件触发ADC_InitStructure.ADC_NbrOfChannel = 3;	//1个ADC通道ADC_Init(ADC1, &ADC_InitStructure);/* ADC通道按照0、7、16的顺序进行采样,采样时间为239.5个时钟周期 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1usADC_RegularChannelConfig(ADC1, ADC_Channel_7, 2, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1usADC_RegularChannelConfig(ADC1, ADC_Channel_16, 3, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us/* 打开ADC内部温度传感器通道、参考电压通道 */ ADC_TempSensorVrefintCmd(ENABLE); /* 开始ADC1的DMA模式 */ADC_DMACmd(ADC1, ENABLE);/* ADC校准是固定流程,且是必须要的 *//* 开启ADC1 */ADC_Cmd(ADC1, ENABLE);/* 重置ADC校准寄存器 */ADC_ResetCalibration(ADC1);/* 检查复位ADC校准是否结束 */while(ADC_GetResetCalibrationStatus(ADC1));/* 开启ADC校准 */ADC_StartCalibration(ADC1);/* 检查校准是否结束 */while(ADC_GetCalibrationStatus(ADC1));/* ADC1开始转换 */ADC_SoftwareStartConvCmd(ADC1,ENABLE);
}

读取数据

将ADC1采样的数据读取到自行设置的缓冲区中,DMA会直接将ADC1的数据读取到地址为ADCConvertedValue的内存单元,不再使用ADC_GetConversionValue(ADC1)读取ADC1的数据,DMA的存在减少了CPU的负担,CPU不再处理ADC1的读取操作,而是直接读从DMA读取出来的数据

int main(void)
{COM_Init();		//串口初始化GPIO_Configuration()DMA_Configuration();	ADC_Configuration();while (1){showData();delay_ms(3000);	//每3s读取一次采样数据}
}void showData(void)
{double temperature;double VSENSE = (double)ADCConvertedValue[2]*(3.3/4096);temperature = (1.43 - VSENSE) / (0.0043) + 25;/* 分别打印出3个采样到的数据,下标为0:寻迹传感器的数据,1:光敏电阻传感器的数据 */printf("ch1: %d, ch2: %d, ch3: %.2f", ADCConvertedValue[0], ADCConvertedValue[1], temperature);
}void GPIO_Configuration()
{RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);/* 配置GPIO */GPIO_InitTypeDef GPIO_InitStructure;/*	配置通道7、通道0对应的GPIO口 */GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7  | GPIO_Pin_0;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOA, &GPIO_InitStructure);
}

演示结果

手指按住STM32芯片,温度会明显上升。ch1是通道0采样的数据,ch2是通道7采样的数据,ch3是通道16采样的数据

image

双ADC模式:规则同步模式

举个例子说明双ADC模式下的规则同步模式(Regular simultaneous mode)。双ADC模式下每次转换的通道不能相同,比如ADC1使用通道1时,ADC2不要同时使用通道1进行转换。

参考手册11.9.2 Regular simultaneous mode写道:

At the end of conversion event on ADC1 or ADC2:

  • A 32-bit DMA transfer request is generated (if DMA bit is set) which transfers to SRAM the ADC1_DR 32-bit register containing the ADC2 converted data in the upper halfword and the ADC1 converted data in the lower halfword.
  • An EOC interrupt is generated (if enabled on one of the two ADC interfaces) when ADC1/ADC2 regular channels are all converted.

大致意思是说,当ADC转换完成时,一个32位的DMA传输请求就会生成,DMA将32位的数据传输值SRAM中。双ADC模式下,32位的数据寄存器ADC1_DR高16位存放的是ADC2转换后的数据,低16位存放的是ADC1转换后的数据

主要程序

大致流程图如下:

flowchart TBid["开启GPIO、ADC1、ADC2、DMA1时钟"] --> id6["配置GPIO为模拟输入模式"] -->id1["配置DMA1初始化结构体,开启DMA1"] --> id2["配置ADC1、ADC2初始化结构体"] --> id3["配置ADC1、ADC2的模拟输入通道"]--> id4["打开ADC1的DMA请求"] --> id5["校准ADC1、ADC2,并开启ADC1、ADC2的转换"]

开启时钟、配置GPIO

void RCC_Configuration(void)
{/* 对PCLK2进行二分频 */RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us /* 开启GPIOB、ADC1时钟 */RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA | RCC_APB2Periph_ADC2, ENABLE);/* 开启DMA时钟 */RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
}void GPIO_Configuration(void)
{/* 配置GPIO */    GPIO_InitTypeDef GPIOInitStructure;GPIOInitStructure.GPIO_Mode = GPIO_Mode_AIN;	//模拟输入GPIOInitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_7;	//PA0:通道0,PA7:通道7GPIOInitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIOInitStructure);
}

初始化以及配置DMA1

__IO uint32_t ADCConvertedValue[2]; //缓存区,DMA将读取到的数据存放到其中void DMA_Configuration(void)
{/* 反初始化DMA1通道1 */DMA_DeInit(DMA1_Channel1);/* 配置DMA初始化结构体 */DMA_InitTypeDef DMA_InitStructure;DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)&(ADC1->DR);		//配置外设基地址,这里是ADC1数据寄存器的地址DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	//外设数据大小,32位, 双ADC模式DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)ADCConvertedValue;		//配置内存基地址,这里是数据存放的内存地址DMA_InitStructure.DMA_BufferSize = 2;		//缓存区中数据的个数DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;	//外设作为数据传输的来源 DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;	//关闭DMA的内存到内存模式DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;	//内存数据大小,32位DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;	//内存地址需要递增,缓存区中数据个数>1DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;		//循环缓存模式,即多次读取数据到缓冲区DMA_InitStructure.DMA_Priority = DMA_Priority_High;		//优先级高DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	//外设地址不递增DMA_Init(DMA1_Channel1, &DMA_InitStructure);	//初始化DMADMA_Cmd(DMA1_Channel1, ENABLE);	//使能DMA
}

配置ADC

void ADC_Configuration(void)
{/* 开启GPIO、ADC1时钟 */RCC_ADCCLKConfig(RCC_PCLK2_Div2);	//PCLK2进行2分频:28 / 2 = 14MHz  = 0.083us RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_ADC2, ENABLE);/* 配置ADC1 */ADC_InitTypeDef ADC_InitStructure;ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	//常规同步模式Regular simultaneous modeADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//开启扫描转换模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发ADC_InitStructure.ADC_NbrOfChannel = 2;	//2个ADC通道ADC_Init(ADC1, &ADC_InitStructure);/* 配置ADC1规则组通道 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_16, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1usADC_RegularChannelConfig(ADC1, ADC_Channel_0, 2, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us/* 打开温度传感器通道和内部参考电压通道 */ ADC_TempSensorVrefintCmd(ENABLE); /* 开始ADC1的DMA模式 */ADC_DMACmd(ADC1, ENABLE);/* 配置ADC2 */ADC_InitStructure.ADC_Mode = ADC_Mode_RegSimult;	//常规同步模式Regular simultaneous modeADC_InitStructure.ADC_ContinuousConvMode = ENABLE;	//开启持续转换模式ADC_InitStructure.ADC_ScanConvMode = ENABLE;	//开启扫描转换模式ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;	//数据对齐方式:右对齐ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//无外部触发ADC_InitStructure.ADC_NbrOfChannel = 1;	//1个ADC通道ADC_Init(ADC2, &ADC_InitStructure);ADC_RegularChannelConfig(ADC2, ADC_Channel_7, 1, ADC_SampleTime_239Cycles5); //采样时间0.083us * 239.5 = 17.1us/* 开启ADC1 */ADC_Cmd(ADC1, ENABLE);/* 重置ADC校准寄存器 */ADC_ResetCalibration(ADC1);/* 检查复位ADC校准是否结束 */while(ADC_GetResetCalibrationStatus(ADC1));/* 开启ADC校准 */ADC_StartCalibration(ADC1);/* 检查校准是否结束 */while(ADC_GetCalibrationStatus(ADC1));/* 开启ADC2 */ADC_Cmd(ADC2, ENABLE);/* 重置ADC校准寄存器 */ADC_ResetCalibration(ADC2);/* 检查复位ADC校准是否结束 */while(ADC_GetResetCalibrationStatus(ADC2));/* 开启ADC校准 */ADC_StartCalibration(ADC2);/* 检查校准是否结束 */while(ADC_GetCalibrationStatus(ADC2));/* ADC1、ADC2开始转换 */ADC_SoftwareStartConvCmd(ADC1, ENABLE);ADC_SoftwareStartConvCmd(ADC2, ENABLE);/* 测试DMA1是否传输完成 */while(!DMA_GetFlagStatus(DMA1_FLAG_TC1));/* 清除DMA1传输完成标志位 */DMA_ClearFlag(DMA1_FLAG_TC1);	
}

读取数据

\(f_{ADC}=14MHz\)下,ADC的转换时间为1us,见参考手册中11章的内容:11.6 Channel-by-channel programmable sample time。因此无需判断标志位,直接读取结果即可。

__IO uint32_t ADCConvertedValue[2]; //缓存区,DMA将读取到的数据存放到其中int main()
{COM_Init();				//串口初始化,用于输出采样结果RCC_Configuration();	//时钟配置GPIO_Configuration();	//GPIO配置DMA_Configuration();	//DMA配置	ADC_Configuration();	//ADC配置while (1){parseData();delay_ms(1000);	//delay 1s}
}void parseData(void)
{double temperature;uint16_t adc1_data, adc2_data, adc1_data2;/* 低16位是ADC1的数据,高16位是ADC2的数据 */adc1_data = ADCConvertedValue[0] & 0xffff;adc2_data = (ADCConvertedValue[0] >> 16) ;adc1_data2 = ADCConvertedValue[1] & 0xffff;double VSENSE = (double)adc1_data*(3.3/4096);temperature = (1.43 - VSENSE) / (0.0043) + 25;printf("t: %.2f, d1: %d, d2: %d", temperature, adc2_data, adc1_data2);
}

演示结果

image

参考资料

《STM32F103xx固件函数库用户手册》

《STM32F10xxx Reference manual》

https://doc.embedfire.com/mcu/stm32/f103zhinanzhe/std/zh/latest/book/ADC.html

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

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

相关文章

国内备受好评PostgreSQL数据库性能如何?

为什么国内很多数据库采用PostgreSQL数据库作为基础,再次开发自己的产品呢?不仅仅是因为PostgreSQL数据库开源免费、PostgreSQL 数据库的性能也是相当出色的,具有以下几个方面的特点: 1. 处理大规模数据: - 能够有效地管理和处理海量的数据。例如,在大型电商网站中,面对…

Springboot集成Flyway详解

1、背景 随着项目的增多,各个项目的版本之间存在差异,因此在升级时,维护项目版本和最新版本之间增量的sql脚本成为一个严重的问题,非常耗时耗力,因此引入一个数据库变更管理工具迫在眉睫。目前比较常用的有flyway和liquibase,liquibase使用xml文件来定义和管理数据库脚本…

IO体系

IO,即in和out,也就是输入和输出,指应用程序和外部设备之间的数据传递,常见的外部设备包括文件、管道、网络连接。 Java 中是通过流处理IO 的,那么什么是流? 流(Stream),是一个抽象的概念,是指一连串的数据(字符或字节),是以先进先出的方式发送信息的通道。 当程序…

Java JDK8新增时间类

生成的都是不可变对象,改动内容会存入新对象,原对象不变

C#使用Spire.Doc打印时候出现红字Evaluation Warning: The document was created with Spire.Doc for .NET.

问题 1.使用Spire.Doc 功能输出word 时,文件头部出现 解决方案 2.使用免费版的包 FreeSpire.Docdotnet add package FreeSpire.Doc

记一次 信息服务平台 “维权”

记录一次找寻网站售后客服的“小苦难”记录一次 爱合租 网站找寻客服的小艰辛太长不看: 最后借助于 风鸟 查询企业名, 从而联系上了相关人员 背景 涉及平台是一个软件服务"发车"平台, 简单来说就是为其用户提供各家软件会员合订的一个平台 我自己在上面当了一段时间的…

Kubernetes externalIPs 类型服务

背景:在k8s中用到的比较到多的是ClusterIP和NodePort类型的service,externalIPs则很少使用。我们现在了解一下其用法和它的一些优缺点。 官方定义: 如果有路由到一个或多个集群节点的外部 IP,则可以在这些 IP 上公开 Kubernetes 服务。在服务端口上使用外部 IP(作为目标 I…

智慧校园:定义未来教育的蓝图

智慧校园管理平台,是集信息技术与教育教学深度融合的产物,它以大数据、云计算、物联网、人工智能等前沿技术为核心,构建了一个高度信息化、智能化的校园生态系统。这一平台不仅仅是技术的堆砌,更是教育理念与管理模式的全面升级,旨在打造安全、高效、个性化的学习环境,促…

Jmeter简单接口测试

说明:Jmeter和对应jdk的下载及安装说明,在笔者的其他文章里面可以找到,这里不再赘述,笔者使用的是Jmeter5.3和jdk1.8 1.在开始讲之前,先讲一下如何看接口信息,一般情况下,开发会有接口文档,如果没有的话,可以在谷歌浏览器按F12抓包,看接口的信息,包括服务器地址,端…

前端部署工具

前端部署工具 用electron写了一个通用的前端部署工具,支持SSH的理论上都可以使用该工具,使用nodejs实现模拟登陆以及上传文件到服务器并解压 链接: https://pan.baidu.com/s/1rGnAO4X_xfv90UecuAMFkA?pwd=2mte 提取码: 2mte本文来自博客园,作者:小万子呀,转载请注明原文链…

Go--创建以当前时间命名的excel文件

下载依赖包go get -u github.com/xuri/excelize/v2 代码package mainimport ("fmt""github.com/xuri/excelize/v2""time" )func main() {// 获取当前时间now := time.Now()filename := fmt.Sprintf("%s.xlsx", now.Format("2006…

今日迷惑行为大赏

多测的意义何在?是好兄弟就 一起不换行我本地真的过编了1 我本地真的过编了2本地-LOCAL确实能过编,但你交上去呢