STM32G474定时器触发1次引起ADC转换直至DMA请求传输完所有通道的数据

STM32G474使用定时器1触发1次ADC转换,然后交给DMA循环执行,实现多通道ADC转换和多通道数据传输。若定时器1停止工作,则ADC转换也会随之停止,当然也不会再有DMA数据传输。

1、ADC触发信号分配

2、DMA多路复合器分配,指定数据数据源

 

3、测试程序

ADC_HandleTypeDef hadc1;  //ADC句柄
DMA_HandleTypeDef  hDMA;  //DMA句柄
uint32_t ADC1_RESULT[2];
//虽然ADC的值为16位,但是HAL库用32位存放,否则会导致内存溢出
//DAM在搬运数据时,也要使用32位,否则读到的ADC值会超过0xFFF,这个HAL库中的问题

TIM_HandleTypeDef htim1;  //TIM1句柄

uint32_t TRGO_cnt;//触发计数器

void ADC1_Init(void);
void TIM1_Init(void);
void DMA1_Read_ADC_Value_Use_Tim1_Triger(void);

void ADC1_Init(void)
{
    ADC_ChannelConfTypeDef ADC1_ChanConf;    //定义ADC1相关结构体
    ADC_MultiModeTypeDef   multimode ;                 //定义ADC模式相关结构体
    
  __HAL_RCC_ADC12_CLK_ENABLE();
    //使能ADC1时钟
    //设置RCC->AHB2ENR寄存器bit13(ADC12EN位),ADC12EN=1,使能ADC1或ADC2时钟

    __HAL_RCC_DMA1_CLK_ENABLE();                                               //DMA1时钟使能
    __HAL_RCC_DMAMUX1_CLK_ENABLE();//设置RCC->AHB1ENR寄存器bit2(DMAMUX1EN位),令DMAMUX1EN=1,DMAMUX1时钟使能


    hadc1.Instance=ADC1;                                                //选中ADC1
    hadc1.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4;、

//4分频,ADCCLK=PCLK2/4=90/4=22.5MHZ
    //设置ADCx_CCR寄存器bit17:16(CKMODE[1:0]]),CKMODE[1:0]=11,adc_hclk/4

    hadc1.Init.Resolution=ADC_RESOLUTION_12B;
    //12位模式
    //设置ADC_CFGR寄存器bit4:3(RES[1:0]),令RES[1:0]=00b,AD转换结果为12位

    hadc1.Init.DataAlign=ADC_DATAALIGN_RIGHT;
    //右对齐
    //设置ADC_CFGR寄存器bit15(ALIGN位),令ALIGN=0,AD转换结果为“右对齐”

    hadc1.Init.ScanConvMode=ADC_SCAN_ENABLE;
    //ADC_SCAN_DISABLE:仅对一个通道进行转换
    //ADC_SCAN_ENABLE:按顺序对多个通道进行转换
    //由于我们是多通道,所以用“扫描模式”
    //转换以顺序模式执行,扫描方向是向上:从排名1到排名“n”。 

    hadc1.Init.ContinuousConvMode=DISABLE;
    //DISABLE:ADC 在每次转换完成后停止,适用于单次数据采集
    //ENABLE:ADC 在转换完成后自动开始下一次转换,适用于连续数据采集
    //这里采用“定时器1触发1次,则执行一次ADC转换”
    //设置ADC_CFGR寄存器bit13(CONT位),令CONT=1,ADC采用连续转换模式

    hadc1.Init.DiscontinuousConvMode=ENABLE;
    //ENABLE:每次触发仅进行指定数量的通道转换,然后等待下一个触发信号
    //DISABLE:在扫描模式下连续转换所有指定通道。
    //不用“间断模式”;注意:不连续采样模式,只适用于“扫描模式”
    //设置ADC_CFGR寄存器bit16(DISCEN位),令DISCEN=0,禁止不连续采样模式

    hadc1.Init.NbrOfDiscConversion=0;
    //设置ADC_CFGR寄存器bit19:17(DISCNUM[2:0]),令DISCNUM[2:0]=0,不连续采样通道数为0
    hadc1.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_RISING;
    //上升沿触发
    //设置ADC->CFGR寄存器bit11:10(EXTEN[1:0]),EXTEN[1:0]=01b,硬件触发检测为上升沿

    hadc1.Init.DMAContinuousRequests=ENABLE;                                                     
    //设置ADC_CFGR寄存器bit0(DMAEN),令DMAEN=1,使能DMA
  hadc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;
    //数据溢出覆盖;当过载发生时,使用ADC_DR的新值覆盖
    //设置ADC_CFGR寄存器bit12(OVRMOD),令OVRMOD=1,当检测到溢出时,将用最后一个转换结果覆盖ADC_DR寄存器

    hadc1.Init.SamplingMode=ADC_SAMPLING_MODE_BULB;
    //ADC转换采样阶段在转换结束后立即开始,并在触发事件时停止。
    //ADC_SAMPLING_MODE_NORMAL;
    //设置ADC_CFGR2寄存器bit26(BULB),令BULB=1

    hadc1.Init.GainCompensation = 0;
    //ADC增益设置为0
    //设置ADC_CFGR2寄存器bit16(GCOMP),令GCOMP=0,常规ADC工作模式

  hadc1.Init.OversamplingMode = DISABLE;
    //设置ADC_CFGR2寄存器bit0(ROVSE),令ROVSE=0,不使用数据溢出覆盖功能,禁止过采样

    hadc1.Init.NbrOfConversion=2;
    //转换通道个数,2个转换在规则序列中
    //设置ADC_SQR1寄存器的bit3:0(L[3:0]),令L[3:0]=2-1,表示“正则通道序列长度”为2,有2个AD转换

    hadc1.Init.LowPowerAutoWait = DISABLE;
    //关闭低功耗模式
    //配置ADC_CR寄存器bit29(DEEPPWD位),令DEEPPWD=0,ADC not in Deep-power down

    hadc1.Init.ExternalTrigConv=ADC_EXTERNALTRIG_T1_TRGO;
    //ADC group regular conversion trigger from external peripheral: TIM1_TRGO
    //ADC触发源选择“TIM1_TRGO”作为AD转换触发源

    hadc1.Init.EOCSelection=DISABLE;
    //关闭EOC中断
    //配置ADC_IER寄存器bit3(EOSIE位),EOSIE=0禁用ADC转换完成产生中断

    HAL_ADC_Init(&hadc1);//初始化ADC
    HAL_ADCEx_Calibration_Start(&hadc1, ADC_SINGLE_ENDED);
    //采用“单端输入”校准,而不是“差动输入”校准
    
    ADC1_ChanConf.Channel=ADC_CHANNEL_VREFINT;//内参考电压(Vrefint),连接到“ADC1_INP18通道”
    ADC1_ChanConf.Rank=ADC_REGULAR_RANK_1;
    //设置ADC_SQR1寄存器bit10:6(SQ1[4:0]),SQ1[4:0]=18,即AD通道18的序号为1
    //AD转换顺序排列:配置通道3位于“第1个序列”

    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_640CYCLES_5;
    //采样时间
    //设置ADC_SMPR1寄存器bit8:6(SMP2[2:0]),640.5 ADC clock cycles

    ADC1_ChanConf.OffsetNumber=ADC_OFFSET_NONE; //无偏移数量
    ADC1_ChanConf.Offset = 0;                    //偏移量=0
    ADC1_ChanConf.SingleDiff=ADC_SINGLE_ENDED;   //采用“单端输入”,而不是“差动输入”
    HAL_ADC_ConfigChannel(&hadc1,&ADC1_ChanConf);//通道配置
    
    ADC1_ChanConf.Channel=ADC_CHANNEL_TEMPSENSOR_ADC1;//内部温度传感器(VTS),连接到“ADC1_INP16通道”
    ADC1_ChanConf.Rank=ADC_REGULAR_RANK_2;
    //AD转换顺序排列:配置通道16位于“第2个序列”
    //设置ADC_SQR1寄存器bit16:12(SQ2[4:0]),SQ2[4:0]=16,即AD通道16的序号为2

    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_640CYCLES_5;
    //采样时间
    //设置ADC_SMPR1寄存器bit5:3(SMP1[2:0]),640.5 ADC clock cycles

    ADC1_ChanConf.OffsetNumber=ADC_OFFSET_NONE;   //无偏移数量
    ADC1_ChanConf.Offset = 0;                     //偏移量=0
    ADC1_ChanConf.SingleDiff=ADC_SINGLE_ENDED;    //采用“单端输入”,而不是“差动输入”
    HAL_ADC_ConfigChannel(&hadc1,&ADC1_ChanConf); //通道配置
    
    hDMA.Instance = DMA1_Channel1;        //使用DMA1的通道1
  hDMA.Init.Request = DMA_REQUEST_ADC1; //DMA需求来源ADC1
  hDMA.Init.Direction = DMA_PERIPH_TO_MEMORY;
    //设置DMA_CCRx寄存器bit4(DIR位),令DIR=0,数据传输方向:外设到内存
  hDMA.Init.PeriphInc = DMA_PINC_DISABLE;
    //设置DMA_CCRx寄存器bit6(PINC位),令PINC=0,外设地址不增加
  hDMA.Init.MemInc = DMA_MINC_ENABLE;
    //设置DMA_CCRx寄存器bit7(MINC位),令MINC=1,内存地址增加
  hDMA.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
    //设置DMA_CCRx寄存器bit9:8(PSIZE[1:0]位),令PSIZE[1:0]=10,外设数据宽度32bits
    //
在“ADC多通道DMA采集”中,不能使用DMA_PDATAALIGN_HALFWORD配置,否则会造成读到的数据是32位的
  hDMA.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
    //设置DMA_CCRx寄存器bit11:10(MSIZE[1:0]]位),令MSIZE[1:0]=10,内存数据宽度32bits
    //
在“ADC多通道DMA采集”中,不能使用DMA_MDATAALIGN_HALFWORD,否则会造成读到的数据是32位的
  hDMA.Init.Mode = DMA_CIRCULAR;
    //DMA_CIRCULAR:“DAM循环搬运数据”
    //DMA_NORMAL;若启动一次DMA,则DMA搬运一次数据
    //设置DMA_CCRx寄存器bit5(CIRC位),令CIRC=1,这里设置“DAM循环搬运数据”

  hDMA.Init.Priority = DMA_PRIORITY_VERY_HIGH ;
    //设置DMA_CCRx寄存器bit13:12(PL[1:0]),令PL[1:0]=11b,DMA抢占优先级最高
    HAL_DMA_Init(&hDMA);
    //初始化DMA

    __HAL_LINKDMA(&hadc1,DMA_Handle,hDMA);
    //将ADC2与DMA联系起来
    //把hadc1结构体的参数赋给DMA

  HAL_NVIC_SetPriority(DMA1_Channel1_IRQn, 0, 0);
    //设置NVIC中断分组4:4位抢占优先级,0位响应优先级
    //选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
    //DMA1_Channel1_IRQn抢占优先级为0,响应优先级为0

  HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);//使能DMA1_Channel1_IRQn中断

    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_RESULT,2);
    //启动DMA“循环搬运2个数据”,并保存到ADC1_RESULT[2]中
    //通过调用HAL_DMA_Start(),然后调用DMA_SetConfig()配置DMA_CPARx,DMA_CMARx和DMA_CNDTRx
    //DMA_CPARx寄存器bit31:0(MA[31:0]),MA[31:0]保存的是外设地址:ADC2_DR
    //DMA_CMARx寄存器bit31:0(MA[31:0]),MA[31:0]保存的是内存首地址:ADC1_RESULT[]数组的首地址
    //DMA_CNDTRx寄存器bit15:0(NDT[15:0]),NDT[15:0]保存的是有3个ADC通道在等待传输

  TIM1_Init();
    HAL_TIM_Base_Start(&htim1); //Start Timer trigger
}

void TIM1_Init(void)
{
    RCC_ClkInitTypeDef    clkconfig;
    uint32_t              uwTimclock = 0;
    uint32_t              pFLatency;
    uint32_t              uwPrescalerValue = 0;
  TIM_ClockConfigTypeDef sClockSourceConfig = {0};
  TIM_MasterConfigTypeDef sMasterConfig = {0};
  TIM_BreakDeadTimeConfigTypeDef sBreakDeadTimeConfig = {0};

  __HAL_RCC_TIM1_CLK_ENABLE();//使能“定时器1”的时钟,Enable TIM1 clock
  HAL_RCC_GetClockConfig(&clkconfig, &pFLatency);//Get clock configuration
  uwTimclock = HAL_RCC_GetPCLK2Freq();
    //读取PCLK2的时钟频率,Return the PCLK2 frequency
    //若PCLK2的分频器值为1,则和SystemCoreClock的值相等
    uwPrescalerValue = (uint32_t) ((uwTimclock / 10000U) - 1U);
    //uwPrescalerValue=17000

  htim1.Instance = TIM1;
  htim1.Init.Period = (1000000U / 1000U) - 1U;
    //定时器周期999
  htim1.Init.Prescaler = uwPrescalerValue;
    //设置TIM1预分频器为uwPrescalerValue
  htim1.Init.ClockDivision = TIM_CLOCKDIVISION_DIV1;
    //设置时钟分频系数,TIM1_CR1中的CKD[9:8]=00b,tDTS=ttim_ker_ck;
    //溢出时间为(999+1)*1*17000/170000000/1=0.1秒

  htim1.Init.CounterMode = TIM_COUNTERMODE_UP;
  htim1.Init.RepetitionCounter = 0;//重复计数(1-0),产生一次中断
  htim1.Init.AutoReloadPreload = TIM_AUTORELOAD_PRELOAD_ENABLE;//TIM_AUTORELOAD_PRELOAD_DISABLE;
  HAL_TIM_Base_Init(&htim1);

  sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;
    //TIM1_TRGO是adc_ext_trg9,用来触发ADC1/2/3/4/5
//  sMasterConfig.MasterOutputTrigger2 = TIM_TRGO2_RESET;
    //TIM1_TRGO2是adc_ext_trg10,用来触发ADC1/2/3/4/5

  sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;
  HAL_TIMEx_MasterConfigSynchronization(&htim1, &sMasterConfig);
    //Configures the TIM in master mode.

   HAL_TIM_Base_Start_IT(&htim1);
   HAL_NVIC_EnableIRQ(TIM1_UP_TIM16_IRQn);//使能TIM1产生中断
   HAL_NVIC_SetPriority(TIM1_UP_TIM16_IRQn, 5, 0U);
     //设置NVIC中断分组4:4位抢占优先级,0位响应优先级
     //选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
    //这里设置TIM1中断优先级为5

}

//TIM1更新中断和TIM16全局中断,他们公用一个中断源
void TIM1_UP_TIM16_IRQHandler(void)
{
  HAL_TIM_IRQHandler(&htim1);
//    HAL_ADC_Start_DMA(&hadc1,(uint32_t*)ADC1_RESULT,2);
    //启动DMA“循环搬运2个数据”,并保存到ADC1_RESULT[2]中
    //通过调用HAL_DMA_Start(),然后调用DMA_SetConfig()配置DMA_CPARx,DMA_CMARx和DMA_CNDTRx
    //DMA_CPARx寄存器bit31:0(MA[31:0]),MA[31:0]保存的是外设地址:ADC2_DR
    //DMA_CMARx寄存器bit31:0(MA[31:0]),MA[31:0]保存的是内存首地址:ADC1_RESULT[]数组的首地址
    //DMA_CNDTRx寄存器bit15:0(NDT[15:0]),NDT[15:0]保存的是有3个ADC通道在等待传输
    TRGO_cnt++;
  
 if(TRGO_cnt>20)
    {
        TRGO_cnt=0;
       __HAL_TIM_DISABLE(&htim1);
      
//TIMx_CR1寄存器bit0(CEN),令CEN=0,定时器计数器停止计数,ADC失去触发源,则也会停止
    }
//    LED1_Toggle(); //LED1引脚输出电平翻转
}

void DMA1_Channel1_IRQHandler(void)
{
    if(__HAL_DMA_GET_FLAG(&hDMA, DMA_FLAG_TC1)!=RESET)
    {
        __HAL_DMA_CLEAR_FLAG(&hDMA, DMA_FLAG_TC1);
        //清除DMA1通道1的中断标志位
        LED1_Toggle(); //LED1引脚输出电平翻转
    }
  HAL_DMA_IRQHandler(&hDMA);
}

void DMA1_Read_ADC_Value_Use_Tim1_Triger(void)
{
    float f;

  printf("ADC1_RESULT[0]=0x%X\r\n",ADC1_RESULT[0]);
    printf("ADC1_RESULT[1]=0x%X\r\n",ADC1_RESULT[1]);
  f=ADC1_RESULT[0];f=f/4096;f=f*3300;
    printf("Vrefint=%0.1fmV\r\n",f);


    f=ADC1_RESULT[1];f=f*3300;f=f/4096;
    f=CalculateInternalTemperature(f);
    printf("Temperature=%0.1f\r\n",f);
}
 

4、测试结果

 当 __HAL_TIM_DISABLE(&htim1);
    TIMx_CR1寄存器bit0(CEN),令CEN=0,定时器计数器停止计数,ADC转换也会停止。

CPU reset!
fHCLK=170MHz
fPCLK1=170MHz
fPCLK2=170MHz
ADC1_RESULT[0]=0x0
ADC1_RESULT[1]=0x3CF
Vrefint=1237.5mV
Temperature=23.7
ADC1_RESULT[0]=0x609
ADC1_RESULT[1]=0x3D5
Vrefint=1244.8mV
Temperature=25.6
ADC1_RESULT[0]=0x607
ADC1_RESULT[1]=0x3D3
Vrefint=1243.1mV
Temperature=25.0
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D4
Vrefint=1243.9mV
Temperature=25.3
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D4
Vrefint=1243.9mV
Temperature=25.3
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D4
Vrefint=1243.9mV
Temperature=25.3
ADC1_RESULT[0]=0x607
ADC1_RESULT[1]=0x3D4
Vrefint=1243.1mV
Temperature=25.3
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D4
Vrefint=1243.9mV
Temperature=25.3
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D4
Vrefint=1243.9mV
Temperature=25.3
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x609
ADC1_RESULT[1]=0x3D6
Vrefint=1244.8mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D5
Vrefint=1243.9mV
Temperature=25.6
ADC1_RESULT[0]=0x607
ADC1_RESULT[1]=0x3D6

Vrefint=1243.1mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6

Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x607
ADC1_RESULT[1]=0x3D6

Vrefint=1243.1mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6

Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608   后面的数据不变化了,说明定时器1停止触发,导致ADC停止
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9
ADC1_RESULT[0]=0x608
ADC1_RESULT[1]=0x3D6
Vrefint=1243.9mV
Temperature=25.9

  • 5
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值