精华内容
下载资源
问答
  • 本文主要介绍了DAC和ADC的56个常用技术术语解析。
  • 第9章 DAC和ADC

    2011-11-08 18:00:15
    数字逻辑基础ppt 第9章 DAC和ADC
  • DAC和ADC助力射频通信

    2020-10-24 04:17:24
    随着精密的光刻技术不断在一定芯片面积上实现更多的晶体管,数字技术水平也在不断提升。这些进步将对射频微...
  • 后来通过读手册发现 相邻三个引脚一般不建议同时使用dac和adc。也就是这两种功能,引脚分配至少隔离三个引脚。内部为了节省成本,共用了很多模拟通道。一般来说相邻三个引脚只有一条模拟通道,所以有可能用不了。 ...

      这种现象在早期的 使用stm8l151的dac 和adc相互干扰很厉害。后来通过读手册发现  相邻三个引脚一般不建议同时使用dac和adc。也就是这两种功能,引脚分配至少隔离三个引脚。内部为了节省成本,共用了很多模拟通道。一般来说相邻三个引脚只有一条模拟通道,所以有可能用不了。

    转载于:https://www.cnblogs.com/polar-lights/p/9873502.html

    展开全文
  • 这些进步将对射频微波设计带来巨大影响。例如,高速模数转换器(ADC)就为软件定义无线电(SDR)架构的实现铺平了道路,SDR被广泛运用于从蜂窝基站到军用无线电等众多应用中。由于有了高性能数模转换器,高精度、宽...
  •  从性能方面看,ADC和DAC是最多样化的电子元件产品之一。可从时钟速率、频率范围、位分辨率、噪音水平,功耗动态范围等各项性能指标来甄选一款转换器。转换器产品包括面向音频应用的低频24位分辨率转换器、面向...
  • 线性电路中DAC和ADC的校准

    千次阅读 2019-07-13 18:09:58
    一、DAC相关电路的校准 链接:https://pan.baidu.com/s/1LkailrGO5gzwC29dXViV4w 提取码:ohkc 复制这段内容后打开百度网盘手机App,操作更方便哦 图 1 DAC相关电路的校准 DAC校准的目的:使输出值Vout2与设置值 ...

    一、DAC相关电路的校准

    链接:https://pan.baidu.com/s/1LkailrGO5gzwC29dXViV4w 
    提取码:ohkc 
    复制这段内容后打开百度网盘手机App,操作更方便哦

    图 1 DAC相关电路的校准

    DAC校准的目的:使输出值Vout2与设置值 Vset相等。

    DAC输出的理论公式:   

    Vout = Vref *D/FullCode(式1)

    理论上DAC输出一个电压可通过(式1)计算D值写到DAC中得到。

    由图 1可知把要输出Vset’的值根据(式1)则有

    Vset’ = Vref *D/FullCode(式2)

    推出

    D= Vset’/ Vref* FullCode(式3)

    由于DAC输出有误差,所以有

    Vset’= k1* Vout1+b1(式4)

    又因

    Vout1= k2*Vout2+b2(式5)

    所以由(式4)、(式5)得

    Vset’ = k2*( k1* Vout2 +b1)+b2(式6)

    Vset’= k2*k1* Vout2+ k2*b1+b2(式7)

    令k2*k1=k,k2*b1+b2=b得

    Vset’ =k* Vout2 + b(式8)

    又因为Vout2= Vset(校准的目的)所以

    Vset’ =k* Vset + b(式9)

    然而在计算D值的时候(式2)、(式3)中当Vset’超出了Vref的范围,此时(式2)、(式3)就不再适用,主要是因为放大电路的存在;所以(式2)、(式3)改成(式10)、(式11)如下。

    Vset’ = (Vref*k2 )*D/FullCode(式10)

    D= Vset’/(Vref*k2)* FullCode(式11)

    实例应用:设Vref =3.5V,FullCode=65535,k2=10;Vout2的满量程为33V。在理想的情况下k=1,b=0由(式8)Vset’ = k* Vout2+ b可得Vset’ = Vout2即Vset’ =Vset;然而在实际情况下由器件和电路产生的偏差不可避免,因此需要进行校准。根据经验一般校准10%满量程和100%满量程两个点,因此Vset’取3.3V和33V两个点来校准。由(式3)D= Vset’/ (Vref*k2)* FullCode可算出D值分别为6179和61790。首先将D值分6179和61790分别写到DAC中,然后用标准表测端口输出值Vout2,分别得到3.321V和33.221V;再根据(式8)Vset’= k* Vout2+ b计算出k=0.993311;b=0.0012153。由此得出理想值Vset’与实际值Vout2的关系为Vset’= 0.993311* Vout2+ 0.0012153;又因Vout2= Vset,所以有Vset’= 0.993311* Vset+ 0.0012153;所以当我们设置输出电压Vset=10V的时候为了在端口上测到实际输出电压Vout2=10V就需要根据Vset’= 0.993311* Vset+ 0.0012153来计算实际要写入DAC中的电压值Vset’=9.9343253,再由(式3)D= Vset’/ (Vref*k2)* FullCode计算出相对应的D=18601。

    二、ADC相关电路的校准

    图 2 ADC相关电路的校准

    图 3 ADC相关电路的校准

    ADC校准的目的:使测量值Vdisplay与输入值 Vin1相等。

    ADC理论公式:   

    Vin = Vref *D/FullCode(式1)

    理论上ADC转换一个电压可通过读取ADC中D值再根据(式1)计算得到。

    由图 2可得

    Vdispaly’ = Vref *D/FullCode(式2)

    又由于ADC器件本身的误差所以有

    D= k2*Vin2/ Vref* FullCode+b2(式3)

    又由图2可得

    Vin2=k1*Vin1+b1(式4)

    根据(式2)(式3)(式3)可得

    Vdispaly’ = ( k2* k1*Vin1+k2*b1)+b2* Vref /FullCode(式5)

    Vdispaly’ = k2* k1*Vin1+k2*b1+b2* Vref /FullCode(式6)

    令k= k2* k1,b= k2*b1+b2* Vref /FullCode得

    Vdispaly’ = k*Vin1+b; (式7)

    由此可得

    Vin1=k Vdispaly’+b; (式8)

    代入数值由(式8)可得k,b的值

    又因Vdispaly= Vin1;

    所以由(式8)得

    Vdispaly=k Vdispaly’+b; (式9)

    实例应用:设Vref =3.5V,FullCode=65535;Vin1的满量程为330V。首先让标准源输出33V的电压,根据理论公式转换得出Vdispaly’1=0.326V;再让标准源输出330V的电压,根据理论公式转换得出Vdispaly’2=3.257V。由(式8)可求得k=101.330604,b= -0.033777;所以有Vdispaly=101.330604* Vdispaly’- 0.033777;所在330V量程下将由理论公式得出的Vdispaly’代入Vdispaly=101.330604* Vdispaly’- 0.033777中即得出测量显示的值。

    三、如何校准图四的系统

    图四 多DAC的校准

    在多网络的校准只要确定所有线路都是线性线路,只要校准两个端口的线性即可

     

    备注:四幅图片在链接中下载

    展开全文
  • ADC++DAC ADC++DAC

    2009-11-13 00:22:46
    ADC++DACADC++DACADC++DAC,供工程师学习参考。
  • STM32实战八 DAC/ADC

    千次阅读 2019-07-01 20:48:49
    这一章编写DAC和ADC程序,即数模/模数转换。程序中封装了两个DAC,各1个独立通道,对应输出脚为PA4和PA5,提供两个方法,ADDA::daDMA(Timer & tim)成员方法以DMA方式按预定数据生成两个正弦波,通道1(PA4)是半幅...

    这一章编写DAC和ADC程序,即数模/模数转换。程序中封装了两个DAC,各1个独立通道,对应输出脚为PA4和PA5,提供两个方法,ADDA::daDMA(Timer & tim)成员方法以DMA方式按预定数据生成两个正弦波,通道1(PA4)是半幅波形,通道2(PA5)是全幅波形。 ADDA::da()成员方法把指定内存的数据转换成模拟信号,未使用DMA,因为已经是一一对应。

    模数转换使用ADC1转换器,共有10个通道,采用硬件存储DMA,不占用CPU时间,包括8个端口通道,对应输入为PA0-7,其中PA4和PA5与DAC共用,可以从内部检测DA/AD的正确性。还有两个内部通道,CPU温度和基准电压。

    值得一提的是,参考代码中没有 “DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;    // 不限幅值” 这一行,造成daDMA程序有时能用,有时不能用,费了好多时间才找出问题。

    ADDA.h

    #ifndef __ADDA__
    #define __ADDA__
    
    extern "C" {				// 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
    #pragma diag_remark 368		//消除 warning:  #368-D: class "<unnamed>" defines no constructor to initialize the following:
    
    #include "stm32f10x.h"
    #include "stm32f10x_dma.h"
    
    #pragma diag_default 368	// 恢复368号警告
    }
    
    #include "IO.h"
    #include "Timer.h"
    
    #define DAC_DHR12RD_Address      0x40007420	// DAC地址
    #define ADC1_DR_Address    ((uint32_t)0x4001244C)	// ADC地址
    //ADC_DR(ADC规则数据寄存器),偏移量=0x4c  ADC1(0x40012400-0x400127ff)
    
    // 设置通道1数据
    #define SETDAC1( v ) *((__IO uint32_t *)(DAC_BASE + (u32)0x00000008 + DAC_Align_12b_R)) = (uint32_t)v
    // 设置通道2数据
    #define SETDAC2( v ) *((__IO uint32_t *)(DAC_BASE + (u32)0x00000014 + DAC_Align_12b_R)) = (uint32_t)v
    
    class ADDA : public IO
    {
    // Construction
    public:
    	ADDA();
    
    // Properties
    public:
    u16 m_adData[10];	// 10个ADC数据	PA0-7,CPU内部温度,内部基准电压
    
    private:
    
    // Methods
    public:
    	void daDMA(Timer & tim);	// 用DMA生成正弦波
    	inline void ad(void);		// ADc
    	inline void da(void);		// DAC
    
    // Overwrite
    public:
    };
    
    #endif
    

    ADDA.cpp

    /**
      ******************************************************************************
      * @file		ADDA.cpp
      * @author		Mr. Hu
      * @version	V1.0.0 STM32F103VET6
      * @date		06/07/2019
      * @brief		DMA,AD,DA
      *	@IO
      *		DMA2_Channel4	传送ADC1转换数据
      *		ADC1		数模转换器1
      *		ADC通道0-7	外部模拟量输入,对应PA0-5,其中PA4-5与DAC共用
      *		ADC通道16	CPU内部温度
      *		ADC通道17	内部基准电压值
      *		DAC通道1-2	模数转换器1-2,对应PA4-5与ADC共用
      *		PA0-7		ADC1的0-7通道
      *		PA4-5		ADC1的4-5通道,同时也是DAC的1-2通道
      ******************************************************************************
      * @remarks
      *	基于DMA的ADC,硬件转换和存储,不占CPU时间
      * DAC有两个方法,一个是单一数据转换,未用DMA,因为本来就是直接写内存。另一个方法是按
      * 指定数据生成正弦波,使用DMA。
      *	实现8个模拟量输入,2个模拟量输出,其中PA4-5两个IO口既是输入,又是输出,AD/DA共用,
      *	可以从软件中监视AD/DA的数据,实际应用用时只能用于DA输出
      *
      * 参考资料
      * https://blog.csdn.net/qq_38410730/article/details/80071349 ADC有端口分配图
      * https://blog.csdn.net/weixin_42653531/article/details/81123770
      * https://blog.csdn.net/iteye_3759/article/details/82547927
      * https://www.cnblogs.com/zhoubatuo/p/6118897.html
      */ 
    
    /* Includes ------------------------------------------------------------------*/
    extern "C" {				// 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
    #pragma diag_remark 368		//消除 warning:  #368-D: class "<unnamed>" defines no constructor to initialize the following:
    
    #include "stm32f10x_adc.h"
    #include "stm32f10x_dac.h"
    #include "stm32f10x_dma.h"
    #include "stm32f10x_tim.h"
    #include <stm32f10x.h>
    
    #pragma diag_default 368	// 恢复368号警告
    }
    
    #include "IO.h"
    #include "ADDA.h"
    
    /**
      * @date	06/07/2019
      * @brief  数模/模数转换
      *		IO(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_AIN, 2)
      *		占用PA0-PA7共8个ADC端口,其中PA4-5与DAC共用。
      * @param	None
      * @retval None
      */
    ADDA::ADDA()
    : IO(GPIOA, GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3 | GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7, GPIO_Mode_AIN, 2)	// GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
    {
    	for(u16 i = 0; i < sizeof(m_adData)/sizeof(m_adData[0]); i++)
    		m_adData[i] = 0;
    	
    	/* Enable peripheral clocks ------------------------------------------------*/
    	/* DMA2 clock enable */
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA2, ENABLE);
    
    	/* DAC Periph clock enable */
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
    	
    	da();	// 启动DAC
    	ad();	// 启动ADC
    }
    
    /**
      * @date	06/07/2019
      * @brief  数模转换,DMA方式按预定数据生成两个正弦波,通道1(PA4)是半幅波形,通道2(PA5)是全幅波形。
      * @param	tim 触发源
      * @retval None
      */
    void ADDA::daDMA(Timer & tim)
    {
    	TIM_TypeDef * ti = tim.m_pTIMx;
    	assert_param( ti == TIM2
    		|| ti == TIM4
    		|| ti == TIM5
    		|| ti == TIM6
    		|| ti == TIM7
    		|| ti == TIM8
    	);
     
    	/* TIMx TRGO selection */
    	TIM_SelectOutputTrigger(ti, TIM_TRGOSource_Update);
    	
    	u32 trigger = // 触发源
    		ti != TIM2 ? ti != TIM4 ? ti != TIM5 ? ti != TIM6 ? ti != TIM7 ? ti != TIM8
    		? 0		// 异常
    		: DAC_Trigger_T8_TRGO
    		: DAC_Trigger_T7_TRGO
    		: DAC_Trigger_T6_TRGO
    		: DAC_Trigger_T5_TRGO
    		: DAC_Trigger_T4_TRGO
    		: DAC_Trigger_T2_TRGO
    		;
    
    	/* DAC channel1 Configuration */
    	// 特别提示,参考代码中没有给DAC_LFSRUnmask_TriangleAmplitude赋值,
    	// 造成有时能用,有时不能用,赋值以后正常
    	DAC_InitTypeDef DAC_InitStructure;
    	DAC_InitStructure.DAC_Trigger = trigger;	// 设置触发源
    	DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_None;	// 不产生波形
    	DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Disable;	// 关闭输出缓存
    	DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_LFSRUnmask_Bit0;	// 不限幅值
    	DAC_Init(DAC_Channel_1, &DAC_InitStructure);	// 初始化通道1 PA4
    	DAC_Init(DAC_Channel_2, &DAC_InitStructure);	// 初始化通道2 PA5
     
    	// 正弦波数据
    	const uint16_t Sine12bit[32] = {		// 全幅
    		2047, 2447, 2831, 3185, 3498, 3750, 3939, 4056, 4095, 4056,
    		3939, 3750, 3495, 3185, 2831, 2447, 2047, 1647, 1263, 909, 
    		599, 344, 155, 38, 0, 38, 155, 344, 599, 909, 1263, 1647};
    	const uint16_t Sine12bitlow[32] = {		// 半幅
    		1024, 1224, 1415,1592,1749,1875,1970,2028,2048,2028,
    		1969, 1875, 1748,1592,1415,1224,1024,824,632,454,
    		300,172,78,19,0,19,78,172,300,454,632,824};
    	uint32_t DualSine12bit[32];    
    
    	//* Fill Sine32bit table *
    	for (u8 Idx = 0; Idx < 32; Idx++)
    	{
    		DualSine12bit[Idx] = (Sine12bit[Idx] << 16) + (Sine12bitlow[Idx]);
    	}
      
    	//* DMA2 channel4 configuration *
    	// DMA通道与DAC对应,不能换
    	DMA_DeInit(DMA2_Channel4);
    	DMA_InitTypeDef DMA_InitStructure;
    	DMA_InitStructure.DMA_PeripheralBaseAddr = DAC_DHR12RD_Address;		// 外设地址,双通道模式,其他模式请看手册
    	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&DualSine12bit;	// 原始数据指针,正弦数据
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;					// 传输方向外设到内存
    	DMA_InitStructure.DMA_BufferSize = 32;								// 缓存大小32个数据,每个数据对应两个通道
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;	// 外设地址固定
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;				// 内存地址自增
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word;	// 外设传输双字
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Word;		// 内存传输双字
    	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;						// 循环输出
    	DMA_InitStructure.DMA_Priority = DMA_Priority_High;					// 优先级为高
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;						// 禁止内存间传输
    	DMA_Init(DMA2_Channel4, &DMA_InitStructure);						// 初始化
    	/* Enable DMA2 Channel4 */
    	DMA_Cmd(DMA2_Channel4, ENABLE);
     
    	/* Enable DAC Channel1: Once the DAC channel1 is enabled, PA.04 is 
    	   automatically connected to the DAC converter. */
    	DAC_Cmd(DAC_Channel_1, ENABLE);
    	/* Enable DAC Channel2: Once the DAC channel2 is enabled, PA.05 is 
    	   automatically connected to the DAC converter. */
    	DAC_Cmd(DAC_Channel_2, ENABLE);
     
    	/* Enable DMA for DAC Channel2 */
    	DAC_DMACmd(DAC_Channel_2, ENABLE);
    }
    
    /**
      * @date	06/07/2019
      * @brief  数模转换,工作方式是循环转换指定的数据
      *		SETDAC1和SETDAC2 分别设置两个通道数据,模拟量输出到PA4,PA5
      * @param	None
      * @retval None
      */
    void ADDA::da()
    {
    	RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE );	  //使能DAC通道时钟 
    
    	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输出缓存关闭 BOFF1=1
    	DAC_Init(DAC_Channel_1,&DAC_InitType);	 //初始化DAC通道1
    	DAC_Init(DAC_Channel_2,&DAC_InitType);	 //初始化DAC通道1
    
    	DAC_Cmd(DAC_Channel_1, ENABLE);  //使能DAC1
    	DAC_Cmd(DAC_Channel_2, ENABLE);  //使能DAC1
    
    	DAC_SetChannel1Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
    	DAC_SetChannel2Data(DAC_Align_12b_R, 0);  //12位右对齐数据格式设置DAC值
    }
    
    /**
      * @date	06/07/2019
      * @brief  数模转换,用DMA方式,把结果存到m_adData[10]中
      *		m_adData[0]-[7]对应PA0-7的输入电压转换结果
      *		PA4,PA5与DAC共用
      *		m_adData[8]-[9]分别的CPU温度和内部基准电压
      * @param	None
      * @retval None
      */
    // https://blog.csdn.net/nicholas_dlut/article/details/80937036
    void ADDA::ad(void)
    {
    	ADC_TempSensorVrefintCmd(ENABLE); //开启内部温度传感器
    
    	/* Enable peripheral clocks ------------------------------------------------*/
    	/* Enable DMA1 clock */
    	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
    	/* Enable ADC1 and GPIOC clock */
    	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
    	
    	// DMA通道与ADC对应,不能换
    	/* DMA1 channel1 configuration ----------------------------------------------*/
    	DMA_InitTypeDef DMA_InitStructure;
    	DMA_DeInit(DMA1_Channel1); //选择DMA的通道1
    	//设定从ADC外设的数据寄存器(ADC1_DR_Address)转移到内存(ADCConcertedValue)
    	//每次传输大小16位,使用DMA循环传输模式
    	DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address;	// 外设地址
    	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)m_adData;//数据缓冲区的地址
    	//外设为数据源
    	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
    	//数据缓冲区,大小2半字
    	DMA_InitStructure.DMA_BufferSize = 10;
    	// 外设地址固定
    	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
    	//内存地址增加,多组adc时,使能,数据传输时,内存增加
    	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
    	//半字
    	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
    	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord;
    	//DMA循环传输
    	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
    	//优先级高
    	DMA_InitStructure.DMA_Priority = DMA_Priority_High;
    	//??
    	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
    	//执行
    	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
    	
    	/* Enable DMA1 channel1 */
        DMA_Cmd(DMA1_Channel1, ENABLE);
    	  
    	/* ADC1 configuration ------------------------------------------------------*/
    	ADC_InitTypeDef ADC_InitStructure;
    	//ADC独立模式 相对于双重模式
    	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;
    	//扫描模式用于多通道采集
    	ADC_InitStructure.ADC_ScanConvMode = ENABLE;
    	//开启连续转换模式   当转换完本组(可能是一个)继续重新开始执行
    	//相对于单次模式:转换一次后就结束
    	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
    	//不使用外部触发转换
    	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
    	//采集数据右对齐
    	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
    	//转换组的通道数目
    	ADC_InitStructure.ADC_NbrOfChannel = 10;
    	//执行
    	ADC_Init(ADC1, &ADC_InitStructure);
       
    	//配置ADC时钟,为PCLK2的8分频,即9Hz
    	RCC_ADCCLKConfig(RCC_PCLK2_Div8);
    	/* ADC1 regular channel11 configuration */ 
    	//配置ADC1的通道11为55.5个采样周期
    	//默认组,adc1 ,通道11,排序为1,55.5周期
    	//ADC1,ch17,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_0,1, ADC_SampleTime_239Cycles5);
    	//ADC1,ch16,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_1,2, ADC_SampleTime_239Cycles5);
    	//ADC1,ch4,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_2,3, ADC_SampleTime_239Cycles5);
    	//ADC1,ch5,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_3,4, ADC_SampleTime_239Cycles5);
    	//ADC1,ch6,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_4,5, ADC_SampleTime_239Cycles5);
    	//ADC1,ch7,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_5,6, ADC_SampleTime_239Cycles5);
    	//ADC1,ch6,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_6,7, ADC_SampleTime_239Cycles5);
    	//ADC1,ch7,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_7,8, ADC_SampleTime_239Cycles5);
    	//ADC1,ch10,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_16,9, ADC_SampleTime_239Cycles5);
    	//ADC1,ch11,序号1,55.5.。。
    	ADC_RegularChannelConfig(ADC1, ADC_Channel_17,10, ADC_SampleTime_239Cycles5);
    	//----------------------使能温度传感器----------------------------
    	ADC_TempSensorVrefintCmd(ENABLE);
    	/* Enable ADC1 DMA */
    	//使能ADC_DMA
    	ADC_DMACmd(ADC1, ENABLE);
    	
    	/* Enable ADC1 */
    	//使能ADC
    	ADC_Cmd(ADC1, ENABLE);
    	/* Enable ADC1 reset calibration register */ 
    	//使能ADC1的复位校准寄存器  
    	ADC_ResetCalibration(ADC1);
    	/* Check the end of ADC1 reset calibration register */
    	//等待校准完成
    	while(ADC_GetResetCalibrationStatus(ADC1));
    	/* Start ADC1 calibration */
    	//使能ADC1的开始校准寄存器
    	ADC_StartCalibration(ADC1);
    	/* Check the end of ADC1 calibration */
    	//等待完成
    	while(ADC_GetCalibrationStatus(ADC1));
    	   
    	/* Start ADC1 Software Conversion */ 
    	//使用软件触发,由于没有采用外部触发
    	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
    }
    

    Main.h

    
    #ifndef __MAIN__
    #define __MAIN__
    
    extern "C" {				// 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
    #pragma diag_remark 368		// 消除 warning:  #368-D: class "<unnamed>" defines no constructor to initialize the following:
    
    #include "stm32f10x.h"
    
    #pragma diag_default 368	// 恢复368号警告
    }
    
    s32 m_nCPUTemperate;		// CPU温度 x 100
    
    #endif
    

    Main.cpp

    /**
      ******************************************************************************
      * @file		Main.cpp
      * @author		Mr. Hu
      * @version	V1.0.0 STM32F103VET6
      * @date		05/18/2019
      * @brief		程序入口
      *	@io
      *		TIM3	PWM
      *		TIM4	Encode
      *		TIM7	通用定时器
      *		ADC1	ADC
      *		DAC1
      *		DAC2
      *
      *		PA0-PA7 ADC
      *		PA4		DAC1输出
      *		PA5		DAC2输出
      *		PA6 	ADC
      *		PA7 	ADC
      *		PA9 	板载串口
      *		PA10 	板载串口
      *		PA13	板载JLINK占用
      *		PA14	板载JLINK占用
      *		PA15	板载JLINK占用
      *
      *		PB1		板载SW2
      *		PB3		板载JLINK占用
      *		PB4		板载JLINK占用,部分映像的通道1不能用,所以用了没有得映像
      *		PB6		编码器 A
      *		PB7		编码器 B
      *		PB8		板载CAN
      *		PB9		板载CAN
      *		PB10	板载RS485
      *		PB11	板载RS485
      *		PB13	板载LED2
      *		PB14	板载LED3
      *		PB15	板载SW3
      *
      *		PC4		板载RS485
      *		PC5		板载RS485
      *		PC6		PWM1
      *		PC7		PWM2
      *		PC8		PWM预留
      *		PC9		PWM预留
      ******************************************************************************
      * @remarks
      *
      */ 
    
    extern "C" {	// 兼容C,按C语言编译,Keil5中的包含文件已经加入了C++兼容,不用再加这一段
    #pragma diag_remark 368			//消除 warning:  #368-D: class "<unnamed>" defines no constructor to initialize the following:
    
    #include "stm32f10x_tim.h"
    #include "stm32f10x_dac.h"
    
    #pragma diag_default 368	// 恢复368号警告
    }
    
    #include "stm32f10x_adc.h"
    #include "IO.h"
    #include "Timer.h"
    #include "GeneralTimer.h"
    #include "BoardLED.h"
    #include "PWM.h"
    #include "MedianFilter.h"
    #include "AverageFilter.h"
    #include "ADDA.h"
    #include "Main.h" 
    
    /**
      * @date	05/18/2019
      * @brief  主入口,主循环
      *			如果不正常运行,可能是栈设置不够 startup_stm32f10x_hd.s Stack_Size EQU 0x600
      * @param	None
      * @retval None
      */
    int main(void)
    {
    	m_nCPUTemperate = 0;
    
    	SystemInit();	// 配置系统时钟为72M
    
    	GeneralTimer tim(TIM2);		// 通用定时器,实际用TIM7,不占用IO,但软件仿真只有1-4,所以选2
    
    	ADDA adda;	// 定时器下紧跟启动ADDA,因为转换需要时间
    	//adda.daDMA(tim);	// DMA方式,按数据生成正弦波,使用这个功能时,注释下面的三角波代码
    	s16 dainc = 1;
    	u16 daval = 0;
    
    	BoardLED boardLED( &tim );	// 板载LED
    	
    	// 板载按键,PB1 SW2, PB2 SW3,不同的板子不一样。
    	IO key(GPIOC, GPIO_Pin_1 | GPIO_Pin_15, GPIO_Mode_IPU, 2);	// GPIOx, nPin, GPIO_Mode_IPU 上拉, 2 输入时无效
    	
    	// 使能按键滤波
    	//tim.inb[1].level = 1;		// SW2 PB1 上拉
    	tim.inb[1].enable = 1;		// SW2 PB1 使能
    	//tim.inb[15].level = 1;	// SW3 PB15 上拉
    	tim.inb[15].enable = 1;		// SW3 PB15
    	
    	u32 loopCount = 0;	// 主循环计数
    	
    	PWM pwm;
    	//pwm.orthogonal( 2 - 1, 1000 - 1 );	// 18kHz 移相正交波形
    	
    	for(int i = 0; i < 3600; i++)	// 延时大约1ms,等待AD转换后再往下接行,求平均时要以获得比较准确的初值
    	{
    		i++;	// 加一句,不然优化编译时会被删掉
    	}
    
    	// 计算方法
    	// float v2 = d * 5.f / 0xfff;	// 把测量数d(0-ffff)转换成电压,单片机用了5V电源,所以用5.f,否则改用3.3f
    	// (1.43f - v2) / 0.0043 + 25;	// 1.43f 25度时的电压值,v2 测量值,0.0043 每度电压变化
    	// 下面是简化后的公式,因为没有FPU,不能用浮点计算,结果单位为1/100度
    	#define CPUT ((s32)35756 - 1221 * adda.m_adData[8] / 43) /* adda.m_adData[8]是内部CPU温度 */
    	MedianFilter mfTemperate( CPUT, 2 );
    	AverageFilter afTemperate( CPUT, 3 );
    	
    	while(1)
    	{
    		tim.loop();	// 必须放在主循环的第一行,按键滤波和上下沿微分。
    		
    		// PWM
    		pwm.setData(0, 300);	// PWM1 PC6 30%的占空比
    		pwm.setData(1, 700);	// PWM2 PC7 70%的占空比
    		
    		// LED
    		// 测试时间
    		loopCount++;
    		if( !tim.m_t[2] )	// 定时器2
    		{
    			tim.m_t[2] = 1000;		// 延时1000ms
    			boardLED.m_nNum = 100 * 1000 / loopCount;	// 计算循环周期,1000*1000对应周期单位是1us,100*1000是10us,以此类推。
    			if( boardLED.m_nNum > 0xf )
    				boardLED.m_nNum = 0xf;		// 大于15时,显示15
    			loopCount = 0;
    		}
    		boardLED.showNumber();	// 显示四位二进制boardLED.m_nNum,用了m_t[0]
    		
    		// CPU温度 https://blog.csdn.net/qq_27970103/article/details/81325418
    		if(!tim.m_t[3])
    		{
    			s32 mf = mfTemperate.filter( CPUT );	// 中值滤波
    			m_nCPUTemperate = afTemperate.filter( mf );	// 平均滤波,效果最好
    			tim.m_t[3] = 100;	// 100ms 计算一次
    		}
    		
    		// 开关LED
    		if( tim.inb[1].down | tim.inb[15].down ) 	// 两个板载开关的下降沿
    		{
    			boardLED.showLED(GPIO_Pin_14, 1);		// 点亮LED3
    		}
    		else if( tim.inb[1].up | tim.inb[15].up )	// 两个板载开关的上升沿
    		{
    			boardLED.showLED(GPIO_Pin_14, 0);		// 熄灭LED3
    		}
    				
    		// DA-AD 测试,先设置数据,用DA转换成电压,再用AD转换成数字,用示波器观察,延后1ms
    		// 产生三角波
    		SETDAC2( daval );
    		daval += dainc;
    		if(daval > 4095)	// daval是无符号数,减过0以后是很大的数,所以只用一个判断
    		{
    			dainc = -dainc;		// 改变方向
    			daval += dainc;		// 调到范围内
    		}
    		u16 test1 = adda.m_adData[5];		// adda.m_adData[5]是PA5电压的转换结果,而PA5的电压是数字adda.m_daData.da2的转换结果,用了同一个IO脚,不用接线测试
    		SETDAC1(test1);	// 再把结果送到DAC通道1(adda.m_daData.da1 = test1)PA4,再用示波器观查,延后1ms,DA触发是1ms
    	}
    }
    

    Main.cpp中下面的代码是获取CPU温度,每100ms采样一次,先用中值滤波,去掉高幅值偶发性干扰,再用均值滤波减弱随机噪声,得到比较稳定的温度值,实测±0.6度内跳动。

    // CPU温度 https://blog.csdn.net/qq_27970103/article/details/81325418
    if(!tim.m_t[3])
    {
    	s32 mf = mfTemperate.filter( CPUT );		// 中值滤波
    	m_nCPUTemperate = afTemperate.filter( mf );	// 平均滤波
    	tim.m_t[3] = 100;	// 100ms 计算一次
    }
    

    下面的代码是ADC/DAC应用,daval是0-4095递加和递减的数据,通过SETDAC2(daval)变成0-5V的模拟信号,输出到PA5脚,adda.m_adData[5]把PA5的电压转换成数字,SETDAC1(test1)把这个数字转换电压,输出到PA4。下图是PA4和PA5的示波器测量波形。两个脚的波形差1ms。

    // DA-AD 测试,先设置数据,用DA转换成电压,再用AD转换成数字,用示波器观察,延后1ms
    // 产生三角波
    SETDAC2( daval );
    daval += dainc;
    if(daval > 4095)	// daval是无符号数,减过0以后是很大的数,所以只用一个判断
    {
    	dainc = -dainc;		// 改变方向
    	daval += dainc;		// 调到范围内
    }
    u16 test1 = adda.m_adData[5];		// adda.m_adData[5]是PA5电压的转换结果,而PA5的电压是数字adda.m_daData.da2的转换结果,用了同一个IO脚,不用接线测试
    SETDAC1(test1);	// 再把结果送到DAC通道1(adda.m_daData.da1 = test1)PA4,再用示波器观查,延后1ms,DA触发是1ms

    注释上面的三角波发生器,启用 adda.daDMA(tim); 以DMA方式生成正弦波,如下图,因为数据较小,锯齿较大。

     

    STM32实战系列源码,按键/定时器/PWM/ADC/DAC/DMA/滤波
    STM32实战一 初识单片机
    STM32实战二 新建工程
    STM32实战三 C++ IO.cpp
    STM32实战四 定时器和按键
    STM32实战五 板载LED显示数据
    STM32实战六 PWM加移相正交
    STM32实战七 数字滤波
    STM32实战八 DAC/ADC
    STM32实战九 编码器
    STM32开发过程的常见问题

     

    展开全文
  • ADC和DAC基础

    2010-05-25 11:02:30
    ADC和DAC基础 ADC和DAC基础
  • DAC+ADC+UART.zip

    2020-12-14 12:27:18
    1. 利用51单片机实现外部电路电压采集并串口输出 2. 利用51单片机实现可调频率的正弦波、方波、锯齿波三角波输出电路
  • 分享一个STMF103+ADC+DAC,实现录音播放的功能的源代码,经过验证,可以录音2s,数据采用DMA传输, 语音采集功放电路,可以私聊我,进行分享; 具体项目说明,参考博客:...
  • 视频IC: ADC----IA7113(替代SAA7113) DAC----IA7121(替代SAA7121) DAC----SDA7123(替代AD7123/ADV7125) RGB/VGA-NTSC/PAL编码器:SC725(替代AD725) 视频方案: 家用游戏方案-----基本型:480i/480p/576i/...
  • 高速ADC和DAC设计

    2020-09-29 11:35:43
    该文档对市面上的高速采集高速回放进行了比较全面的总结分析比对,对高速ADC和DAC常用的LVDSjesd204协议以及功能指标(分辨率、采样率、有效位数、SFDR等)进行了说明,模拟前端的DC耦合AC耦合进行了分析,...
  • 具有APB-BFM的DAC和ADC模型的UVM验证 这是一个小组项目。 具有APB BFM(总线功能模型)的UVM验证,已连接到两个只读DAC和两个只读ADC从器件。 该序列生成地址,并允许驱动程序告诉BFM选择哪个从站。 随后,四个监视...
  • 基于上述原因,提出一种利用MCU自带的10位ADC和DAC,结合运放、电容、电阻等元件搭建的外围硬件电路,实现将MCU自带的ADC转换为精度可调的ADC。软件设计是通过校正方法减小由硬件导致的ADC测量误差。实验结果表明,...
  • 本文主要讲了ADC和DAC基本原理及特点,希望对你的学习有所帮助。
  • ADC和DAC有什么区别
  • 高速adc和dac设计文档

    2013-10-21 20:44:27
    这是我设计adc和dac子板,请大家多提宝贵意见
  • 使用外扩的DAC8411,连线方式请看DAC8411的技术手册代码里dac.c的定义。本代码实现功能是用稳压电源输入任意电压(0-3.6v)在dac输出端输出同样电压。同时NOKIA5110上同步显示真实电压.
  • 本文教你如何挑选ADC和DAC,希望能为您带来帮助。
  • 该简易数控电源采用DAC0832 A/D转换把按键的数字信号转换成模拟电源信号,然后再把模拟信号转换为数字信号给单片机,通过数码管显示电压值,电压步进为0.1V,虽然我做的有点误差,但是里面的电路程序非常有借鉴...
  • PWM实现ADC和DAC

    千次阅读 2015-09-08 22:21:00
    PWM实现ADC和DAC 一、PWM实现AD 利用普通单片机的2个IO及一个运算放大器即可实现AD转换电路,而且很容易扩展成多通道。其占用资源少,成本低,AD 转换精度可以达到8位甚至更高,因此具有一定的实用价值。   ...

    PWM实现ADC和DAC

    一、PWM实现AD

    利用普通单片机的2个IO及一个运算放大器即可实现AD转换电路,而且很容易扩展成多通道。其占用资源少,成本低,AD 转换精度可以达到8位甚至更高,因此具有一定的实用价值。

     

    1.1 硬件电路说明

    图一中“RA0”和“RA1”为单片机的两个I/O脚,分别将其设置为输出与输入状态,在进行A/D转换时,在程序中通过软 件产生PWM,由RA0脚送出预设占空比的PWM波形。RA1脚用于检测比较器输出端的状态。 R1、C1构成滤波电路,对RA0脚送出的PWM波形进行平滑滤波。RA0输出的PWM波形经过R1、C1滤波并延时后,在U1点产 生稳定的电压值,其电压值U1=VDD*D1/(D1+D2),若单片机的工作电压为稳定的+5V,则U1=5V*D1/(D1+D2)。 图一中的LM324作为比较器使用,其输入负端的U1电压与输入正端的模拟量电压值进行比较,当U1大于模拟量输入电压 时,比较器的输出端为低电平,反之为高电平。

    1.2 AD转换过程

    如果使RA0输出PWM波形,其占空比由小到大逐渐变化,则U1的电压会由小到大逐渐变化,当U1电压超过被测电压时,比 较器的输出端由高电平变为低电平,因此可以认为在该变化的瞬间被测的模拟量与U1的电压相等。 由于U1的电压值=VDD*D1/(D1+D2),当VDD固定时,其电压值取决于PWM波形的占空比,而PWM的占空比由单片机软件 内部用于控制PWM输出的寄存器值决定,若软件中用1个8位寄存器A来存放RA0输出的PWM的占空比值D1,因此在RA1检测 到由“1”变为“0”的瞬间,A寄存器的值D1即为被测电压的A/D转换值,其A/D转换结果为8位。如果用16位寄存器来作 输出PWM的占空比,则A/D转换值可达到16位。

    1.3如何减少AD转换的误差

    AD转换的误差主要由以下几个方面决定,分别说明如下:

    (1)单片机的电源电压VDD:在该A/D转换中,VDD电压是造成A/D转换误差的主要原因,如果使VDD电压精度做到较高, 则A/D转换误差可以做到很小,在VDD电压精度为0.5%情况下,实际的A/D转换误差小于1%。

    (2)软件产生的PWM占空比:若用于产生PWM的软件设计不良,会使存放占空比的寄存器值与实际输出的PWM占空比不一 致,这会导致测量误差。

    (3)比较器输入端的失调电压:该电压对A/D转换精度有一定影响,但影响较小。

    (4)RC滤波电路的纹波:在R1、C1取值不当的情况下,U1处的电压纹波较大,并且延时时间不够,会使A/D转换产生误 差,因此R1、C1取值不能太小,但太大又会影响A/D转换速度,推荐使用图一中所示的R1、C1参数,在纹波合理的情况 下,其转换误差也可通过软件消除。

    AD转换误差的解决办法:

    (1)对VDD造成的误差,只能通过提高VDD电压精度来解决,它相当于A/D转换的基准电压。

    (2)对于软件中PWM设计不良导致的误差,可修改软件进行解决。

    (3)对比较器及RC滤波电路的纹波导致的误差,在软件中可通过上、下检测法进行消除,即先将PWM的占空比由小到大变化,使U1电压由低往高逐渐变化,在比较器输出端变化时记录其A/D转换值,再将PWM的占空比由大到小变化,使U1电压 由高到低变化,在比较器输出端变化时记录其A/D转换值,将两次的A/D转换值进行平均,可有效地消除这两种误差。

    (4)对A/D转换值进行数字滤波,如多次转换求平均值等。数字滤波消除误差的方法很多,在此不再赘述。

    1.4 如何提高AD转换的速度

    由于该A/D转换是通过PWM滤波后再进行比较来完成的,其PWM的产生与滤波都需要一定的时间,因此其A/D转换速度较 慢,适用于对A/D转换速度要求不高的产品中,其A/D转换速度取决于以下几个方面:

    (1)单片机的运行速度:单片机的运行速度越高则PWM的频率可以越高, RC值就可以取得越小,其延时时间也可以更 短,转换速度就更快。

    (2)被测电压值的大小:由于U1电压时是由小到大逐渐加大的,当被测电压值较小时,U1电压上升到相应值的时间就越 短,完成A/D转换的速度就越快。

    (3)初始占空比:初始占空比越高,U1电压较大,其上升到被测电压值的时间也就会越短,完成A/D转换的速度也就越 快。

    由上所述,A/D转换的速度可以通过提高单片机的工作频率,并在预知被测电压范围时尽可能地设置较高的初始占空比值 来加快转换速度,如果所要求的A/D转换精度要求不高,还可以在软件中缩短PWM输出的延时时间来提高A/D转换速度。若 单片机带有外部电平变换中断和定时器中断,其A/D转换的精度和速度还可以得到提高。

    二、PWM实现DA

    利用同样的原理,可使该电路很容易的只用单片机的一个I/O脚实现D/A转换功能。

    其输出的模拟量电压Vout=VDD*D1/ (D1+D2)。该输出电压带有纹波,当RC值足够大时,该纹波值几乎为零,可忽略不计。如图2所示。

    为进一步减小纹波,可使用两级RC滤波。 此处LM324作为一个跟随器,提高电路的负载能力。

     

    展开全文
  • 采集时间 采集时间是从释放保持状态(由采样-保持输入电路执行)到采样电容电压稳定至新输入值的1 LSB...为防止混叠,必须对所有有害信号进行足够的衰减,使得ADC不对其进行数字化。欠采样时,混叠可作为一种有利条件...
  • ADC和DAC接地

    2011-02-01 17:22:25
    大多数的ADC都有模拟地(AGnd)数字地(DGnd)引脚,但是太多的工程师datasheet作者都不确定该怎么进行连接。这篇文章考虑了这些引脚电流流动的本质,内部及外部噪声对于精确数据转换的影响,不同的接地,去耦...
  • ADC和DAC基础1,ADC和DAC基础2,ADC和DAC基础3,ADC和DAC基础4,ADC和DAC基础5.

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,408
精华内容 563
关键字:

dac和adc