STM32
直播中

敷衍作笑谈

9年用户 950经验值
擅长:制造/封装 连接器 光电显示 接口/总线/驱动 RF/无线
私信 关注
[问答]

stm32上的ADC与DAC有何应用呢

STM32上的ADC有何应用呢?

stm32上的DAC有何应用呢?

回帖(1)

彭瑾

2021-11-15 15:10:18
  一.stm32上ADC,DAC的应用说明:
  1.首先ADC是将模拟信号转成数字信号,DAC则相反。
  (模拟信号可以简单的理解为温度,光照,压力等,数字信号则可以是电压等),
  2.一般某些传感器上会标出AO,DO,AI,DI。
  其中AO叫做模拟量输出,DO数字信号输出。AI,DI则对应着输入。
  (未知)AO–》转化–》DI(对应的数字信号)。
  进一步解读:可以看成AO是模拟信号采集以后输出给数字信号DI接收后经过数据处理就得到了对应的电压数值,而这些电压数字一般和模拟量之间存在这一些数学转换公式,此过程就是ADC采集数据。
  (已知)DO-》处理-》AI(对应的模拟量)。
  此处解读:可以看成是通过改变数字信号(电压)DO输出给模拟信号AI接受后使模拟量发生改变,对应DAC。
  3.认识ADC在引脚上的位置
  
  此处ADC123,指该芯片上的三个ADC,
  _IN1,指通道1。
  
  stm32fxxadc.h中主要有两个结构体需注意。
  typedef struct
  {
  uint32_t ADC_Resolution; //ADC 分辨率选择
  FunctionalState ADC_ScanConvMode; //ADC 扫描选择
  FunctionalState ADC_ContinuousConvMode; //ADC 连续转换模式选择
  uint32_t ADC_ExternalTrigConvEdge; //ADC 外部触发极性
  uint32_t ADC_ExternalTrigConv; //ADC 外部触发选择
  uint32_t ADC_DataAlign; //输出数据对齐方式
  uint8_t ADC_NbrOfChannel; //转换通道数目
  } ADC_InitTypeDef;
  typedef struct
  {
  uint32_t ADC_Mode; //ADC 模式选择
  uint32_t ADC_Prescaler; //ADC 分频系数
  uint32_t ADC_DMAAccessMode; //DMA 模式配置
  uint32_t ADC_TwoSamplingDelay; //采样延迟
  } ADC_CommonInitTypeDef;
  不使用dma时adc初始化函数:
  static void _ADC_Mode_Config(void)
  {
  ADC_InitTypeDef ADC_InitStructure;
  ADC_CommonInitTypeDef ADC_CommonInitStructure;
  // 开启 ADC 时钟
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_ADCx , ENABLE);
  // -------------------ADC Common 结构体 参数 初始化--------------------
  // 独立 ADC 模式
  ADC_CommonInitStructure.ADC_Mode = ADC_Mode_Independent;
  // 时钟为 fpclk x 分频 (ADC输入时钟fpck=HCLK/分频系数,此处的HCLK就是设置的系统时钟:fpck=hack/4=168/4=42Mhz)
  ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div2;
  // 禁止 DMA 直接访问模式
  ADC_CommonInitStructure.ADC_DMAAccessMode=ADC_DMAAccessMode_Disabled;
  // 采样时间间隔 周期=1/42=0.023 T=5+12=17(周期)=17*0.023= 0.4us 采集一次
  ADC_CommonInitStructure.ADC_TwoSamplingDelay=ADC_TwoSamplingDelay_20Cycles;
  ADC_CommonInit(&ADC_CommonInitStructure);
  // -------------------ADC Init 结构体 参数 初始化---------------------
  // ADC 分辨率可选的分辨率有 12位、10位、8位和 6 位。分辨率越高,AD 转换数据精度越高,转换时间也越长
  ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
  // 禁止扫描模式,多通道采集才需要
  ADC_InitStructure.ADC_ScanConvMode = DISABLE;
  // 连续转换
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
  //禁止外部边沿触发
  ADC_InitStructure.ADC_ExternalTrigConvEdge =ADC_ExternalTrigConvEdge_None;
  //使用软件触发,外部触发不用配置,注释掉即可
  //ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T1_CC1;
  //数据右对齐
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
  //转换通道 1 个
  ADC_InitStructure.ADC_NbrOfConversion = 1;
  ADC_Init(ADCx, &ADC_InitStructure);
  //------------------------------------------------------------------
  // 配置 ADC 通道转换顺序和采样周期
  ADC_RegularChannelConfig(ADCx, ADC_Channel_x,1, ADC_SampleTime_56Cycles);
  // ADC 转换结束产生中断,在中断服务程序中读取转换值
  ADC_ITConfig(ADCx, ADC_IT_EOC, ENABLE);
  // 使能 ADC
  ADC_Cmd(ADCx, ENABLE);
  //开始 adc 转换,软件触发
  ADC_SoftwareStartConv(ADCx);
  }
  //中断服务函数
  void ADC_IRQHandler(void)
  {
  if (ADC_GetITStatus(ADCx,ADC_IT_EOC)==SET)
  {
  // 读取 ADC 的转换值
  ADC_ConvertedValue = ADC_GetConversionValue(ADCx);
  }
  ADC_ClearITPendingBit(ADCx,ADC_IT_EOC);
  }
  //在中断服务函数中将adc采集的数据存放至ADC_ConvertedValue该变量中,
  //在主函数中调用时对采取的模拟信号量处理转化成电压这种数字信号:
  // float ADC_Vol =(float)(ADC_ConvertedValue*3.3/4096);
  使用dma接收adc采集的数据
  static void _ADC_DMA_Config(void)
  {
  DMA_InitTypeDef DMA_InitStructure;
  // ------------------DMA Init 结构体参数 初始化------------------------
  // ADC1 使用 DMA2,数据流 0,通道 0,这个是手册固定死的
  // 开启 DMA 时钟
  RCC_AHB1PeriphClockCmd( RCC_AHB1Periph_DMA2, ENABLE);
  // 外设基址为:ADC 数据寄存器地址(可以看成是 ADC CDR 寄存器没进行宏定义,ADC 转换后的数字值则存放在这里)
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40012308);
  // 存储器地址,实际上就是一个内部SRAM的变量(直白来讲就是你定义的变量或数组)----------------------
  DMA_InitStructure.DMA_Memory0BaseAddr = (u32)&ADC_ConvertedValue;
  // 数据传输方向为外设到存储器
  DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
  // 缓冲区大小为,指一次传输的数据量(此处可以看成是使用adc的个数)
  DMA_InitStructure.DMA_BufferSize = 1;
  // 外设寄存器只有一个,地址不用递增
  DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
  // 存储器地址固定
  DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
  // // 外设数据大小为半字,即两个字节
  DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord;
  // 存储器数据大小也为半字,跟外设数据大小相同
  DMA_InitStructure.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord;
  // 循环传输模式
  DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
  // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
  DMA_InitStructure.DMA_Priority = DMA_Priority_High;
  // 禁止DMA FIFO ,使用直连模式
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  // FIFO 大小,FIFO模式禁止时,这个不用配置
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  // 选择 DMA 通道,通道存在于流中
  DMA_InitStructure.DMA_Channel = DMA_Channel_x;
  //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
  DMA_Init( DMAx_Streamx, &DMA_InitStructure);
  // 使能DMA流
  DMA_Cmd( DMAx_Streamx, ENABLE);
  }
  当需要使用dma时可参考dma所示的流和通道。大大缩减我们查阅数据手册的时间,此处的为标准库的配置,需要cube库的请至其他处参考。
  
  我们一般在设计原理图的时候会把 ADC的输入电压范围设定在:0~3.3v,如果设置
  ADC 为 12 位的,那么 12 位满量程对应的就是 3.3V,12 位满量程对应的数字值是:2^12。
  数值 0对应的就是 0V。如果转换后的数值为 X ,X 对应的模拟电压为 Y,那么会有这么
  一个等式成立: 2^12 / 3.3 = X / Y,=》 Y = (3.3 * X ) / 2^12。参考如下:
  
  DAC配置
  
  根据这个可类似的求出三角波,方波等其他波的频率,也可根据此定时器配置进行设置频率大小。
  static void DAC_Config(void)
  {
  DAC_InitTypeDef DAC_InitStructure;
  /* 使能GPIOA时钟 */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_DAC, ENABLE);
  /* 配置DAC 通道1 */
  DAC_InitStructure.DAC_Trigger = DAC_Trigger_T2_TRGO; //使用TIM2作为触发源
  DAC_InitStructure.DAC_WaveGeneration = DAC_WaveGeneration_Triangle; //使用波形发生器(三角波)
  DAC_InitStructure.DAC_OutputBuffer = DAC_OutputBuffer_Enable; //使用DAC输出缓冲
  //三角波振幅
  DAC_InitStructure.DAC_LFSRUnmask_TriangleAmplitude = DAC_TriangleAmplitude_4095;
  DAC_Init( DAC_Channel_1, &DAC_InitStructure);
  /* 配置DAC 通道2 */
  DAC_Init( DAC_Channel_2, &DAC_InitStructure);
  /* 配置DAC 通道1、2 */
  DAC_Cmd(DAC_Channel_1, ENABLE);
  DAC_Cmd(DAC_Channel_2, ENABLE);
  /* 使能 DAC的DMA请求 */
  DAC_DMACmd(DAC_Channel_1, ENABLE);
  }
  //定时器配置,一般dac输出都需要定时器来提供频率
  static void DAC_TIM_Config(void)
  {
  TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
  /* 使能TIM2时钟,TIM2CLK 为168M */
  RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
  /* TIM2基本定时器配置 用于调节波形频率*/
  TIM_TimeBaseStructure.TIM_Period = 19; //定时周期 20
  TIM_TimeBaseStructure.TIM_Prescaler = 0x0; //预分频,不分频 168M / (0+1) = 168M
  TIM_TimeBaseStructure.TIM_ClockDivision = 0x0; //时钟分频系数
  TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //向上计数模式
  TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
  /* 配置TIM2触发源 */
  TIM_SelectOutputTrigger(TIM2, TIM_TRGOSource_Update);
  /* 使能TIM2 */
  TIM_Cmd(TIM2, ENABLE);
  }
  //dma初始化配置
  static void DAC_DMA_Config(void)
  {
  DMA_InitTypeDef DMA_InitStructure;
  /* DAC1使用DMA1 通道7 数据流5时钟 */
  RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA1, ENABLE);
  /* 配置DMA2 */
  DMA_InitStructure.DMA_Channel = DMA_Channel_X;
  DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)0x40007420 ;//外设数据地(DAC_BASE+0x20)
  DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)&DualSine12bit ; //内存数据地(数组或变量)DualSine12bit
  DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; //数据传输方向内存至外设
  DMA_InitStructure.DMA_BufferSize = 128; //缓存大小为32字节 (128位)
  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通道优先级
  DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
  DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
  DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
  DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
  DMA_Init(DMAx_Streamx, &DMA_InitStructure);
  /* 使能 DMA_Stream */
  DMA_Cmd(DMAx_Streamx, ENABLE);
  }
举报

更多回帖

发帖
×
20
完善资料,
赚取积分