STM32F4_DAC数模转换

news2024/10/7 14:30:37

889321aa1eb9ee33340c6d2ee93d8af2.gif

目录

1. DAC简介

2. DAC框图

3. DAC功能介绍

3.1 DAC通道使能

3.2 DAC输出缓冲器使能

3.3 DAC数据格式

3.4 DAC转换

3.5 DAC输出电压

3.6 DAC触发选择

3.7 DMA请求

3.8 生成噪声

3.9 生成三角波

4. 相关寄存器

4.1 DAC控制寄存器:DAC_CR

4.2 DAC1通道12位右对齐数据保持寄存器:DAC_DHR12R1

5. 库函数配置DAC输出

6. 实验程序

6.1 main.c

6.2 DAC.c

6.3 DAC.h

6.4 ADC.c

6.5 ADC.h


1. DAC简介

DAC和ADC恰好相反,DAC模块是12位电压输出数模转换器。DAC可以按照8位或者12位模式进行配置,并且可以与DMA控制器配合使用。在12位模式下,数据可以采用左对齐或右对齐。DAC有两个输出通道,每个通道各有一个转换器。在DAC双通道模式下,每个通道可以单独进行转换;当两个通道组合在一起同步执行更新操作时,也可以同时进行转换。可通过一个输入参考电压引脚V_{REF+}(这个引脚是和ADC共享的)来提高分辨率。

DAC主要特性:

  •         两个DAC转换器:各对应一个输出通道
  •         12位模式下数据采用左对齐或右对齐
  •         同步更新功能
  •         生成噪声波
  •         生成三角波
  •         DAC双通道单独或同时转换
  •         每个通道都具有DMA功能
  •         DMA下溢错误检测
  •         通过外部触发信号进行转换
  •         输入参考电压V_{REF+}

2. DAC框图

图中VDDA和VSSA为DAC模块模拟部分的供电,而Vref+则是DAC模块的参考电压。DAC_OUTx就是DAC的输出通道(对应于PA4和PA5引脚)

从图中可以看到,DAC输出是受DORx寄存器直接控制的,但是我们不能直接往DORx寄存器中写入数据,而是通过DHRx间接的传给DORx寄存器,实现对DAC输出的控制。

注意:使能DACx通道后,相应的GPIO引脚(PA4或者PA5)将自动连接到模拟转换器输出DAC_OUTx。为了避免寄生电流消耗,应首先将PA4或PA5引脚配置为模拟模式(AIN)。

3. DAC功能介绍

3.1 DAC通道使能

DAC_CR控制寄存器中的相应位ENx位置1,即可接通对应的DAC通道。经过一段启动时间t_{WAKEUP}后,DAC通道被真正的使能。

注意:ENx位只会使能模拟DAC Channelx 宏单位。即使ENx位复位,DAC Channelx 数字接口仍处于使能状态。

3.2 DAC输出缓冲器使能

        DAC集成了两个输出缓冲器,可用来降低输出阻抗并在不增加外部运算放大器的情况下直接驱动外部负载。通过DAC_CR控制寄存器中的相应BOFFx位,可使能或禁止各DAC通道输出缓冲器。

3.3 DAC数据格式

对于DAC单通道x,有三种可能的方式:

        8位右对齐:软件必须将数据加载到DAC_DHR8Rx[7:0]位(存储到DHRx[11:4]位)。

        12位左对齐:软件必须将数据加载到DAC_DHR12Lx[15:4]位(存储到DHRx[11:0]位)。

        12位右对齐:软件必须将数据加载到DAC_DHR12Rx[11:0]位(存储到DHRx[11:0]位)。

根据加载的 DAC_DHRyyyx 寄存器,用户写入的数据将移位并存储到相应的 DHRx(数据保持寄存器 x,即内部非存储器映射寄存器)。之后,DHRx 寄存器将被自动加载,或者通过软件或外部事件触发加载到 DORx 寄存器。

:本次我们使用的就是STM32的单DAC通道1,采用12位右对齐格式,所以使用的是上述单通道的第三种情况。

        如果没有选中硬件触发(寄存器DAC_CR1的TENx位置0),存入寄存器DAC_DHRx的数据会在一个APB1时钟周期后自动传至寄存器DAC_DORx。如果选中硬件触发(寄存器DAC_CR1的TENx位置1),数据传输在触发发生以后3个APB1时钟周期后完成。

        一旦数据从DAC_DHRx寄存器装入DAC_DORx寄存器,在经过时间t_{SEITLING}之后,输出即有效,这段时间的长短依电源电压和模拟输出负载的不同会有所变化。

对于DAC双通道,有三种可能的方式:

        8位右对齐:将DAC1通道的数据加载到DAC_DHR8RD[7:0]位(存储到DHR1[11:4]位),将DAC2通道的数据加载到DAC_DHR8RD[15:8]位(存储到DHR2[11:4]位)

        12位左对齐:将DAC1通道的数据加载到DAC_DHR12RD[15:4]位(存储到DHR1[11:0]位),将 DAC 2 通道的数据加载到 DAC_DHR12RD [31:20] 位(存储到 DHR2[11:0] 位)

        12 位右对齐:将 DAC 1 通道的数据加载到 DAC_DHR12RD [11:0] 位(存储到 DHR1[11:0] 位),将 DAC 2 通道的数据加载到 DAC_DHR12RD [27:16] 位(存储到 DHR2[11:0] 位)

根据加载的 DAC_DHRyyyD 寄存器,用户写入的数据将移位并存储到 DHR1 和 DHR2(数据保持寄存器,即内部非存储器映射寄存器)。之后,DHR1 和 DHR2 寄存器将被自动加载,或者通过软件或外部事件触发分别被加载到 DOR1 和 DOR2 寄存器。

3.4 DAC转换

DAC_DORx 无法直接写入,任何数据都必须通过加载 DAC_DHRx 寄存器(写入 DAC_DHR8Rx、DAC_DHR12Lx、DAC_DHR12Rx、DAC_DHR8RD、DAC_DHR12LD 或 DAC_DHR12LD)才能传输到 DAC 通道 x。

如果未选择硬件触发(DAC_CR 寄存器中的 TENx 位复位),那么经过一个 APB1 时钟周期后,DAC_DHRx 寄存器中存储的数据将自动转移到 DAC_DORx 寄存器。但是,如果选择硬件触发(置位 DAC_CR 寄存器中的 TENx 位)且触发条件到来,将在三个 APB1 时钟周期后进行转移。

当 DAC_DORx 加载了 DAC_DHRx 内容时,模拟输出电压将在一段时间 t_{SETTLING} 后可用,具体时间取决于电源电压和模拟输出负载。

3.5 DAC输出电压

经过线性转换后,数字输出会转换为0到V_{REF+}之间的输出电压。

各DAC通道引脚的模拟输出电压通过以下公式确定:

        DACoutput=V_{REF}\times\frac{ROD}{4095}

3.6 DAC触发选择

如果TENx控制位置1,则可通过外部事件(定时计数器、外部中断线)触发转换。TSELx[2:0]控制位将决定通过8个可能事件中的哪一个来触发转换,

每当DAC接口在所选定时器TRGO输出或所选外部中断线9上检测到上升沿时,DAC_DHRx寄存器中存储的最后一个数据即会转移到DAC_DORx寄存器中。发生触发后再经过三个APB1周期,DAC_DORx寄存器就会得到更新。

如果选择软件触发,一旦SWTRIG位置1,转换即会开始。DAC_DHRx寄存器内容加载到DAC_DORx寄存器中后,SWTRIG即由硬件复位。

ENx位置1时,无法更改TSELx[2:0]位。

如果选择软件触发,DAC_DHRx寄存器的内容只需一个APB1时钟周期即可转换到DAC_DORx寄存器。

3.7 DMA请求

每个 DAC 通道都具有 DMA 功能。两个 DMA 通道用于处理 DAC 通道的 DMA 请求。

当 DMAENx 位置 1 时,如果发生外部触发(而不是软件触发),则将产生 DAC DMA 请求。DAC_DHRx 寄存器的值随后转移到 DAC_DORx 寄存器。 在双通道模式下,如果两个 DMAENx 位均置 1,则将产生两个 DMA 请求。如果只需要一个 DMA 请求,应仅将相应 DMAENx 位置 1。这样,应用程序可以在双通道模式下通过一个 DMA 请求和一个特定 DMA 通道来管理两个 DAC 通道。

DMA下溢

DAC DMA请求没有缓冲队列。这样,如果第二个外部触发到达时尚未收到第一个外部触发的确认,将不会发出新的请求,并且DAC_SR寄存器中的DAM通道下溢标志DMAUDRx将置1,以报告这一错误状况。DMA数据传输随即禁止,并且不再处理其他DMA请求。DAC通道仍将继续转换旧有数据。

软件应通过写入“1”来将 DMAUDRx 标志清零,将所用 DMA 数据流的 DMAEN 位清零, 并重新初始化 DMA 和 DAC 通道,以便正确地重新开始 DMA 传输。软件应修改 DAC 触发 转换频率或减轻 DMA 工作负载,以避免再次发生 DMA 下溢。最后,可通过使能 DMA 数据 传输和转换触发来继续完成 DAC 转换。

对于各 DAC 通道,如果使能 DAC_CR 寄存器中相应的 DMAUDRIEx 位,还将产生中断。

3.8 生成噪声

为了生成可变振幅的伪噪声,可使用LFSR(线性反馈移位寄存器)。将WAVEx[1:0]置为 “01” 即可选择生成噪声。LFSR中的预加载值为0xAAA。在每次发生触发事件后,经过三个APB1时钟周期,该寄存器会依照特定的计算算法完成更新。

3.9 生成三角波

可以在直流电流或满变信号上叠加一个小幅三角波。将WAVEx[1:0]置为 “10” 即可选择DAC生成三角波。振幅通过DAC_CR寄存器中的MAMPx[3:0]位进行配置。每次发生触发事件后,经过三个APB1时钟周期,内部三角波计数器将会递增。在不发生溢出的情况下,该计数器的值将与DAC_DHRx寄存器内容相加,所得总和将存储到DAC_DORx寄存器中。只要小于MAMPx[3:0]位定义的最大振幅,三角波计数器就会一直递增。一旦达到配置的振幅,计数器将会递减至0,然后在递增,以此类推。

可以通过复位WAVEx[1:0]位来将三角波产生功能关闭。

4. 相关寄存器

4.1 DAC控制寄存器:DAC_CR

DAC控制寄存器:DAC_CR(DAC control register)

DAC控制寄存器的低16位用于控制通道1,高16位用于控制通道2。本实验我们使用的是通道1,所以着重介绍最低8位控制通道1。

位[7:6]:WAVE1[1:0]:DAC1通道噪声/三角波生成使能

                这些位有软件置1和清零。

                00:禁止生成波

                01:使能生成噪音波

                1x:使能生成三角波

位[5:3]:TSEL1[2:0]:DAC1通道触发器选择

                000:定时器6 TRGO事件

                001:定时器8 TRGO事件

                010:定时器7 TRGO事件

                011:定时器5 TRGO事件

                100:定时器2 TRGO事件

                101:定时器4 TRGO事件

                110:外部中断线9

                111:软件触发

位2:TEN1:DAC1通道触发使能

                此位由软件置1和清零,以使能/禁止DAC1通道触发。

                0:禁止DAC1通道触发,写入DAC_DHRx寄存器的数据在一个APB1时钟周期之后转移到DAC_DOR1寄存器

                1:使能DAC1通道触发,DAC_DHRx寄存器的数据在三个APB1时钟周期之后转移到DAC_DOR1寄存器

位1:BOFF1:DAC1通道输出缓冲器禁止

                此位由软件置1和清零,以使能/禁止DAC1通道输出缓冲器

                0:使能DAC1通道输出缓冲器

                1:禁止DAC1通道输出缓冲器

位0:EN1:DAC1通道使能

                此位由软件置1和清零,以使能/禁止DAC1通道。

                0:禁止DAC1通道

                1:使能DAC1通道

首先位0使能位(EN1),该位是用来控制DAC通道1使能的,我们要使用DAC通道1,那么该位要设置为1。

DAC通道1触发使能位(TEN1),该位用来控制是否使用触发,如果不使用触发,那么将该位设置为0即可。

DAC通道1触发选择位(TSEL1[2:0]),该位是用来设置是否使用外部触发,如果不使用,那么该位设置为0即可。

DAC通道1噪声/三角波生成使能位(WAVE1[1:0]),在用到波形发生器时,才需要设置该位,不需要使用波形发生器时,将该位设置为0即可。

DAC通道1屏蔽/复制选择器(MAMP[3:0]),在用到波形发生器时才会使用屏蔽/复制发生器,没用到时,该位设置为0即可。

DAC通道1 DMA使能位(DMAEN1),在需要用到DMA功能时,才需要将该位设置为1。

4.2 DAC1通道12位右对齐数据保持寄存器:DAC_DHR12R1

DAC1通道12位右对齐数据保持寄存器:DAC_DHR12R1(DAC channel1 12-bit right-aligned data holding register)

位31:12   保留,必须保持复位值

位11:0   DACC1DHR[11:0]DAC1通道12位右对齐数据

                这些位由软件写入,用于为DAC1通道指定12位数据。

该寄存器用来设置DAC输出,通过写入12位数据到该寄存器,就可以在DAC输出通道1(PA4)得到我们所要的结果。

5. 库函数配置DAC输出

1. 开启PA口时钟,设置PA4为模拟输入

RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);  //使能GPIOA时钟 

GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;  //设置PA4引脚

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AN;   //模拟输入 

GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;     //下拉 

GPIO_Init(GPIOA, &GPIO_InitStructure);     //初始化 

2. 使能DAC1时钟

RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);     //使能DAC时钟 

3. 初始化DAC,设置DAC工作模式

初始化DAC主要通过DAC_CR控制寄存器设置来实现,包括:DAC通道1使能、DAC通道1输出缓存关闭、不使用触发、不使用波形发生器等。

void DAC_Init(uint32_t DAC_Channel, DAC_InitTypeDef* DAC_InitStruct); 

typedef struct
{
    uint32_t DAC_Trigger;   //用来设置是否使用触发功能
    uint32_t DAC_WaveGeneration;   //用来设置是否使用波形发生
    uint32_t DAC_LFSRUnmask_TriangleAmplitude;  //用来设置屏蔽/幅值选择器,这个变量只有在使用波形发生器时才使用
    uint32_t DAC_OutputBuffer;  //用来设置输出缓存控制位
}DAC_InitTypeDef;

//本实验中不使用触发,也不使用波形发生,也不用波形发生器,同时也不使用输出缓存

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);

4. 使能DAC转换通道

DAC_Cmd(DAC_Channel_1, ENABLE);     // 使能DAC通道1 

5. 设置DAC输出值

通过前四步 DAC 就可以正常工作了,因为我们使用的是 12 位右对齐数据格式,所以需要设置 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_GetDataOutputValue(DAC_Channel_1);    // 读出DAC对应通道最后一次转换的数值

6. 实验程序

        本次实验,使用ADC采集DAC输出电压,需要使用DAC通道1输出模拟电压,然后通过ADC1的通道1对该输出电压进行读取,并且显示在LCD模块上,DAC输出电压,通过按键进行设置,因为需要使用ADC来采集DAC输出电压,所以需要在开发板上通过跳线帽短接ADC和DAC。

6.1 main.c

#include "stm32f4xx.h"
#include "delay.h"
#include "usart.h"
#include "LED.h"
#include "lcd.h"
#include "usmart.h"
#include "ADC.h"
#include "KEY.h"
#include "DAC.h"

//LCD状态设置函数
void led_set(u8 sta)//只要工程目录下有usmart调试函数,主函数就必须调用这两个函数
{
	LED1=sta;
}
//函数参数调用测试函数
void test_fun(void(*ledset)(u8),u8 sta)
{
	led_set(sta);
}
int main(void)
{
	u16 adcx;
	float temp;
	u8 t=0,key;
	u16 dacval=0;
	delay_init(168);
	uart_init(115200);
	LED_Init();
	LCD_Init();
	Adc_Init();
	Key_Init();
	Dac1_Init();
	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,"2023/05/18");
	LCD_ShowString(30,130,200,16,16,"WK_UP:+  KEY1:-");
	POINT_COLOR=BLUE;
	LCD_ShowString(30,150,200,16,16,"DAC VAL");
	LCD_ShowString(30,170,200,16,16,"DAC VAL:0.000V");
	LCD_ShowString(30,190,200,16,16,"ADC VAL:0.000V");
	
	DAC_SetChannel1Data(DAC_Align_12b_R,dacval);  //12位数据对齐格式设置DAC初始值为0
	
	while(1)
	{
		t++;
		key=KEY_Scan(0);
		if(key==4)  //KEY_UP按键按下
		{
			if(dacval<4000)
				dacval=dacval+200;
			DAC_SetChannel1Data(DAC_Align_12b_R,dacval);  //设置DAC的值
		}
		else if(key==2) //KEY1按键按下
		{
			if(dacval>200)
				dacval=dacval-200;
			else
				dacval=0;
			DAC_SetChannel1Data(DAC_Align_12b_R,dacval);//设置DAC值 
		}
		if(t==10||key==2||key==4)// 有按键按下了,或者定时时间到了
		{
			adcx=DAC_GetDataOutputValue(DAC_Channel_1);  //读取DAC值
			
			LCD_ShowxNum(30+8*8,150,adcx,4,16,0);  //显示DAC寄存器的值
			temp=(float)adcx*(3.3/4096);  //计算得到DAC电压值
			adcx=temp;
			LCD_ShowxNum(30+8*8,170,temp,1,16,0);  //显示电压值的整数部分
			temp=temp-adcx;  //减掉整数部分,保留下来小数部分
			temp=temp*1000;   //乘以1000,相当于保留了三位小数
			LCD_ShowxNum(30+10*8,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(30+8*8,190,temp,1,16,0);  //显示电压值整数部分
			temp=temp-adcx;
			temp=temp*1000;
			LCD_ShowxNum(30+8*10,190,temp,3,16,0x80);  //显示电压值小数部分
			LED0=!LED0;
			t=0;
		}
		delay_ms(10);
	}
}

6.2 DAC.c

#include "stm32f4xx.h"                
#include "DAC.h"

void Dac1_Init(void)
{
	RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);  //使能GPIOA时钟
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC,ENABLE);  //使能DAC时钟
	
	//初始化GPIOA
	GPIO_InitTypeDef GPIO_InitStructure;
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AN;  //模拟输入
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_4;  //PA4引脚
	GPIO_InitStructure.GPIO_PuPd=GPIO_PuPd_DOWN;  //下拉
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	//初始化DAC通道1
	DAC_InitTypeDef DAC_InitStructure;
	DAC_InitStructure.DAC_Trigger=DAC_Trigger_None;  //不使用触发功能
	DAC_InitStructure.DAC_OutputBuffer=DAC_OutputBuffer_Disable; //输出缓存关闭
	DAC_InitStructure.DAC_WaveGeneration=DAC_WaveGeneration_None; //不使用波形发生
	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude=DAC_LFSRUnmask_Bit0;  //屏蔽、幅值设置
	DAC_Init(DAC_Channel_1,&DAC_InitStructure);
	
	DAC_Cmd(DAC_Channel_1,ENABLE);   //使能DAC通道1
	
	DAC_SetChannel1Data(DAC_Align_12b_R,0);  //12位右对齐数据格式
}
//设置通道1输出电压
//vol:0~3300,代表0-3.3V
void Dac1_Set_Vol(u16 vol)  //将电压值转换为DAC输出值
{	
	double temp=vol; //设置浮点型变量temp接收电压值
	temp=temp/1000;
	temp=temp*4096/3.3;  //通过公式计算出电压值,其实就是公式中的ROD;
	DAC_SetChannel1Data(DAC_Align_12b_R,temp);  //计算后的电压值放在数据寄存器中使用的是12位右对齐数据格式
}

6.3 DAC.h

#ifndef _DAC__H_
#define _DAC__H_


void Dac1_Init(void);

void Dac1_Set_Vol(u16 vol);


#endif

6.4 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;
} 

6.5 ADC.h

#ifndef __ADC_H
#define __ADC_H	
#include "sys.h" 

 							   
void Adc_Init(void); 				//ADC通道初始化
u16  Get_Adc(u8 ch); 				//获得某个通道值 
u16 Get_Adc_Average(u8 ch,u8 times);//得到某个通道给定次数采样的平均值  
#endif 

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

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

相关文章

1-《java基础》

1-《java基础》 一.java基本数据类型和引用类型1.基本数据类型&#xff1a;2.引用数据类型3.基本数据类型和引用数据类型区别3.1 存储位置3.2 传递方式 4.自动装箱&#xff0c;自动拆箱 二.equals和的区别三.static1.static关键字的用途2.static方法3.static变量4.static代码块…

Unity中级客户端开发工程师的进阶之路

上期UWA技能成长系统之《Unity高级客户端开发工程师的进阶之路》得到了很多Unity开发者的肯定。通过系统的学习&#xff0c;可以掌握游戏性能瓶颈定位的方法和常见的CPU、GPU、内存相关的性能优化方法。 UWA技能成长系统是UWA根据学员的职业发展目标&#xff0c;提供技能学习的…

加密解密软件VMProtect教程(六):主窗口之控制面板“项目”部分(3)

VMProtect 是新一代软件保护实用程序。VMProtect支持德尔菲、Borland C Builder、Visual C/C、Visual Basic&#xff08;本机&#xff09;、Virtual Pascal和XCode编译器。 同时&#xff0c;VMProtect有一个内置的反汇编程序&#xff0c;可以与Windows和Mac OS X可执行文件一起…

wpf字符串格式化来实现空格占位 对齐问题Arial字符宽度不一致ChitGPT真牛

console是正常的。xml界面不正常&#xff0c;对不齐。 可能的原因各字符宽度不一致导致的。换个字体试试。黑体就正常。默认的Arial就不对。 在 C# 中&#xff0c;可以使用字符串格式化来实现空格占位。具体的做法是在格式字符串中使用占位符 {n}&#xff0c;其中 n 表示要占用…

一单一结,靠Python爬虫赚外快,在家就能做

今年以来我们听到了太多负面声音&#xff0c;“互联网寒冬”“裁员”“优化”“失业”&#xff0c;同时也听到了许多朋友迷茫的声音&#xff1a; 面对未来的焦虑&#xff1a;未来我应该往哪方面发展&#xff1f; 面对裁员的迷茫&#xff1a;被裁&#xff0c;下一份工作如何选…

Playwright系列:第11章 CI/CD集成(Jenkins/Gitlab)

下方查看历史精选文章 重磅发布 - 自动化框架基础指南pdfv1.1大数据测试过程、策略及挑战 测试框架原理&#xff0c;构建成功的基石 在自动化测试工作之前&#xff0c;你应该知道的10条建议 在自动化测试中&#xff0c;重要的不是工具 CI/CD即持续集成/持续交付,是软件开发的一…

UDP通信相关

Linux网络编程-UDP单播服务客户端代码实现 1、服务端 只接收一个字符串 #include <stdio.h> #include <stdlib.h> #include <stdbool.h> #include <string.h> #include <errno.h> #include <unistd.h> #include <sys/types.h> #…

部署问题集合(十四)VMware复制完整的虚拟机

前言&#xff1a; 由于原先的服务器内存和磁盘空间都不太够&#xff0c;所以需要将其中的程序部署到新的服务器上但部署过程总因为各种奇奇怪怪的问题报错&#xff0c;所以干脆想着将整个虚拟机都复制到新的服务器上&#xff0c;这样需要改动的东西最少&#xff0c;仅需要处理…

黄金圈法则/思维

黄金圈法则/思维 美国作家西蒙.斯涅克因&#xff08;国际知名广告、营销专家&#xff09;在TED演讲中提出黄金圈法则而一举扬名。 模型介绍 黄金圈法则的核心思想是&#xff1a;在沟通表达的时候&#xff0c;按照一个特定的结构why->how->what进行表达。它本质也是一种思…

乔哈里窗模型

乔哈里窗由心理学家乔瑟夫和哈里在20世纪50年代提出的&#xff0c;也常被称之为"自我意识的发现/反馈模型”&#xff0c;或“信息交流过程管理工具”。 模型介绍 该模型把人的内心信息分成四个区域&#xff0c;即&#xff1a; 第一个区域&#xff0c;我知道&#xff0c;你…

104. 二叉树的最大深度

104. 二叉树的最大深度 原题链接&#xff1a;完成情况&#xff1a;解题思路&#xff1a;参考代码&#xff1a; 原题链接&#xff1a; 104. 二叉树的最大深度 https://leetcode.cn/problems/maximum-depth-of-binary-tree/ 完成情况&#xff1a; 解题思路&#xff1a; //想…

【开发者指南】如何在MyEclipse中使用HTML或JSP设计器?(上)

MyEclipse v2022.1.0正式版下载 一、HTML & JSP 可视化设计器 本文简要介绍了 MyEclipse HTML 和 JSP Web 设计器的概念、功能和基本操作过程。这两个设计器具有相似的功能和相同的操作模型&#xff0c;但本文为专门针对其类型的内容。本文档中的示例是使用 MyEclipse HT…

国货大佬“卡脖子”后王者风范不减?小米卷出光学拍摄“天花板”?| 手机行业社媒心智品牌榜出炉

Social Power 核心解读 1、智能手机“乍暖还寒”&#xff0c;龙头品牌仍稳占消费者心智 比拼屏幕、赶超系统、迭代形态、拓展概念&#xff1f;眼花缭乱过后&#xff0c;产品精益求精&#xff0c;建立稳固的消费者认知&#xff0c;才是“保鲜”关键。在最新发布的数说故事5月…

Text-to-SQL提示工程【Prompt Engineering】

我们刚刚启动了一个开源项目pg-text-query&#xff0c;目标是为文本到 SQL 制作生产就绪的大型语言模型 (LLM) 提示。 我们的目标是 利用 LLM、我们自己对 PostgreSQL 数据库的深入了解以及严格的测试来开发一流的文本到 SQL 的翻译。 推荐&#xff1a;用 NSDT设计器 快速搭建…

T-GCN:用于交通流预测的时序图卷积网络

1.文章信息 本次介绍的文章是2020年发表在IEEE 智能交通系统汇刊上的《T-GCN: A Temporal Graph Convolutional Network for Traffic Prediction》。 2.摘要 为了同时捕获空间和时间依赖性&#xff0c;本文提出了一种新的基于神经网络的交通流预测方法——时间图卷积网络(T-GCN…

Java中的Socket通信和HTTP通信有什麽不同

文章目录 Socket通信HTTP通信两者之间的区别总结 Java中的Socket通信和HTTP通信是两种不同的网络通信方式。Socket通信是一种面向连接的通信协议&#xff0c;而HTTP通信则是基于TCP/IP协议的无连接的应用层协议。在本文中&#xff0c;我将会简要介绍两者的区别&#xff0c;并且…

开放原子训练营(第三季)inBuilder低代码开发实验室初体验

一、活动介绍 开放原子训练营开启inBuilder低代码实验室活动。无论您是计算机行业相关从业者、低代码开发爱好者还是普通用户&#xff0c;都可以基于inBuilder低代码开发平台社区版&#xff08;基于UBML开源项目的一个可以广泛使用的发行版&#xff09;&#xff0c;体验向导式、…

基于FPGA的车牌识别

基于FPGA进行车牌识别 基于FPGA进行车牌识别 1. 文件说明2. 程序移植说明3. 小小的编程感想 本项目的原理讲解视频已经上传到B站“基于FPGA进行车牌识别”。 本项目全部开源&#xff0c;见我本人的Github仓库“License-Plate-Recognition-FPGA”。 1. 文件说明 小技巧&…

chatgpt赋能Python-pyecharts_雷达图

Pyecharts雷达图&#xff1a;最佳数据可视化工具 Pyecharts是一个流行的Python库&#xff0c;用于创建美观、交互式和动态数据可视化。其中一个强大的工具是雷达图&#xff0c;它可以帮助你更好地理解数据趋势和关系。 现在&#xff0c;我们将深入研究Pyecharts雷达图&#xf…

深度学习 - 49.SIM 搜索兴趣网络 GSU 与 Soft Search 简单实现 By Keras

目录 一.引言 二.GSU 结构分析 1.Input Layer 输入层 2.Embedding Layer 嵌入层 3.Pooling Layer 池化层 4.MLP 深层网络 5.Soft Search 软搜索 三.GSU 结构实现 1.Init 初始化 2.Build 构建 3.call 调用 4.GSU Layer 完整代码 四.GSU 模型训练 1.Input Layer …