stm32 f103 双通道adc采集+DMA搬运+TIME3_TRGO触发启动

       前面的博客我们介绍了单通道的模式,现在我们就在此基础之上来讨论下多通道的外部信号触发启动模式。

一.外部触发源

首先,stm32的adc启动大致分为两种一种软件触发,一种外部事件触发。

我们以ADC1为例,线面我们来看看具体有哪些外部信号能触发ADC:

如图我们只要是用TIM3_TRGO信号来触发adc。

下面我们来介绍下TIM3_TRGO信号。

TIM3_TRGO实际上就是定时器触发的一个信号,具体怎么触发这个信号了,我们可以查看管官方函数: TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update); //选择TRGO触发源为计时器更新事件 

这里我们选择TIM_TRGOSource_Update作为TIM3的TRGO信号的触发源,可以理解为每次计时器一更新那么TRGO这个信号就会变为有效信号、就能被其他需要这个信号的外设所识别,如果不指定触发源的话就是一个无效信号气的外设无法识别。

从这里可以看出,除了更新事件外还有其他的事件能够作为TRGO信号的触发源。。。

在使用外部触发源是要配置ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_TRGO ; //T3_TRGO(定时器3TRGO启动)外部触发。

二.dma配置的问题

u32 buffsize=5

DMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)(&a[2]),(u32)buffsize);  //dma初始化

在我们配置多通道DMA搬运时候(u32)(&a[2])缓冲区首地址参数我们要尽可能的传入数组首地址,如果是循环搬运那么如果我们传入的是A[2]地址当搬运到a[4]的时候就会继续将值从a【2】开始存,A[0],A[1]就不会存入值。。。

还有一个问题就是buffsize的值最好是和通道数一致这样每个通道的的数据就能和数组实现一一对应关系,如果buffsize比通道数大那么两者对应不上不容易查找数据。

例如双通道模式下buffsize=3即是a[3];一通道3.3v,一通道0v

第一次搬运:a[0]=3.3   a[1]=0   a[2]=3.3

第二次搬运:a[0]=0      a[1]=3.3  a[2]=0

如此下去不利于查找。

还有一个问题就是:在我们 设置DMA外设数据宽度,内存数据宽度的时候要相互对应,也就是说你的   外设数据宽度=内存数据宽度,否则容易出现数据错误。(很重要)一般都是查看外设数据寄存器的位数,然后根据这个值定义相应大小的数组。

附上完整代码:

DMA部分:

int DMA_Config(DMA_Channel_TypeDef* CHx,u32 PBaseAddr,u32 MBaseAddr,u32 buffsize)
{
    
    DMA_InitTypeDef DMA_InitStruct;
    
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
    
    DMA_DeInit(CHx);
    
    DMA_InitStruct.DMA_PeripheralBaseAddr=PBaseAddr; //外设基地址
    DMA_InitStruct.DMA_MemoryBaseAddr=MBaseAddr;          //内存寄存器
    DMA_InitStruct.DMA_DIR=DMA_DIR_PeripheralSRC;  //数据传输方向  外设到内存
    DMA_InitStruct.DMA_BufferSize=buffsize;              //通道缓存大小
    DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable; //外设寄存器地址不递增
    DMA_InitStruct.DMA_MemoryInc=DMA_MemoryInc_Enable;          //开启内存寄存器地址递增
    DMA_InitStruct.DMA_PeripheralDataSize=DMA_PeripheralDataSize_HalfWord; //外围数据宽度16位
    DMA_InitStruct.DMA_MemoryDataSize=DMA_MemoryDataSize_HalfWord;      //内存数据宽度
    DMA_InitStruct.DMA_Mode=DMA_Mode_Circular;                    //循环传输模式
    DMA_InitStruct.DMA_Priority=DMA_Priority_High;             //优先级
    DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;                    //不开启内存到内存
    DMA_Init(CHx ,&DMA_InitStruct);  //初始化DMA;
    DMA_Cmd(CHx ,ENABLE);
    return 1;
}
adc部分:

void Adc_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    ADC_InitTypeDef ADC_InitStruct;
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_ADC1,ENABLE);//使能时钟
    //配置GPIOA_5口模拟输入
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_5;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    //配置GPIOA_4口模拟输入
    GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AIN;
    GPIO_InitStruct.GPIO_Pin=GPIO_Pin_4;
    GPIO_Init(GPIOA,&GPIO_InitStruct);
    //ADC时钟分频因子
    RCC_ADCCLKConfig(RCC_PCLK2_Div6);
    //重置ADC寄存器
    ADC_DeInit(ADC1);
    ADC_InitStruct.ADC_Mode= ADC_Mode_Independent;//独立模式
    ADC_InitStruct.ADC_DataAlign=ADC_DataAlign_Right; //数据右对齐
    ADC_InitStruct.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_TRGO ; //T3_TRGO(定时器3TRGO启动)外部触发
    ADC_InitStruct.ADC_ContinuousConvMode=ENABLE;  //enable开启连续扫描
    ADC_InitStruct.ADC_NbrOfChannel=2;  //规则转换通道数目
    ADC_InitStruct.ADC_ScanConvMode=ENABLE;  //DISABLE单通道模式,enable多通道扫描模式
    ADC_Init(ADC1,&ADC_InitStruct);
    ADC_Cmd(ADC1,ENABLE);  //使能adc    必须先使能才校准,不然校准不通过的
    ADC_ResetCalibration(ADC1);//开启复位校准
    while(ADC_GetResetCalibrationStatus(ADC1));
    ADC_StartCalibration(ADC1);  //开启ad校准
    while(ADC_GetCalibrationStatus(ADC1));

}

定时器部分:

定时器部分主要就是加上TRGO出发的选择。

主函数:

const u16 buffsize=2;
 int main(void)
 {    
    u16 a[buffsize]={0}; 
    LedInit();
    delay_init();             //延时函数初始化      
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
    uart_init(9600);    //串口初始化为9600
    Adc_Init();       //adc初始化
    DMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)(&a[0]),(u32)buffsize);  //dma初始化
    TIM3_Int_Init(4999,7199);  //定时器3初始化
//    ADC_SoftwareStartConvCmd(ADC1,ENABLE);  //设置adc软件启动
    ADC_ExternalTrigConvCmd(ADC1,ENABLE);   //使能adc外部触发启动
    ADC_DMACmd(ADC1,ENABLE);    //使能adc的dma传输 
    ADC_RegularChannelConfig(ADC1,ADC_Channel_5,1,ADC_SampleTime_13Cycles5); //配置通道5的采样时间和规则序列表
    ADC_RegularChannelConfig(ADC1,ADC_Channel_4,2,ADC_SampleTime_13Cycles5); //配置通道4的采样时间和规则序列表
    while(1)
    {
    if(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC))
    {
        printf("a[0]=%.2f   ",a[0]*3.3/4096);
        printf("a[1]=%.2f   \r\n",a[1]*3.3/4096);
        delay_ms(1000);
    }
    }
 }

STM32F103是一款具有多通道ADC、TIM、DMA和FFT功能的微控制器。 首先,多通道ADC允许我们同时采集多个不同通道的模拟信号。这对于需要同时监测多个传感器或信号源的应用非常有用。通过配置ADC的多个通道,并设置相应的采样速率和分辨率,可以轻松实现高效的数据采集。 其次,TIM(定时器)模块允许我们生成精确的时间基准。在实时系统和定时器应用中,我们可以配置TIM来实现各种定时和计时功能。通过设置预分频器、计数器和比较器,我们可以准确地生成周期性的、定时的或脉冲宽度可变的信号。这对于控制和调度其他外设非常有用。 接下来,DMA(直接内存访问)控制器允许我们实现高速数据传输,而不需要CPU的干预。通过配置DMA通道并定义源和目标的地址、传输长度和传输方向,我们可以实现高效的数据传输操作。这对于处理大量数据、高速数据流或实时响应的应用非常有用。 最后,FFT(快速傅里叶变换)是一种用于信号处理和频谱分析的重要算法。通过使用STM32F103的FFT库,我们可以对采集到的模拟信号进行频谱分析,以提取信号的频率和幅度特征。这对于音频处理、通信系统、传感器数据分析等应用非常有用。 总之,STM32F103的多通道ADC、TIM、DMA和FFT功能为我们提供了丰富的数据采集、定时、数据传输和信号处理能力,使得我们可以设计出高度灵活、高效的嵌入式系统。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值