STM32利用DMA方式采集多路ADC数值并周期传送

芯片使用的是STM32f103C8T6,编译器是Keil 5,使用的标准固件库3.5版本。

首先,配置时钟,配置NVIC就不说了。

开门见山,直接上代码吧:

1、配置ADC,DMA:

	GPIO_InitTypeDef GPIO_InitStructure;
	ADC_InitTypeDef ADC_InitStructure;
	DMA_InitTypeDef DMA_InitStructure;
	
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);
	
	GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
	GPIO_InitStructure.GPIO_Pin=GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_5|GPIO_Pin_4;
	GPIO_Init(GPIOA,&GPIO_InitStructure);
	
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr=(unsigned int)&(ADC1->DR);      
	DMA_InitStructure.DMA_MemoryBaseAddr=(unsigned int)ADC1_DMA1_Buffer;           
	DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;												
	DMA_InitStructure.DMA_BufferSize=4;                                       
	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_MemoryDataSize_HalfWord;					
	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);
	DMA_Cmd(DMA1_Channel1,ENABLE);
	
	ADC_DeInit(ADC1);
	ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;													
	ADC_InitStructure.ADC_ScanConvMode=ENABLE;															
	ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;												
	ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_T3_TRGO;			
	ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;										
	ADC_InitStructure.ADC_NbrOfChannel=4;							
	ADC_Init(ADC1,&ADC_InitStructure);
	
	ADC_RegularChannelConfig(ADC1,ADC_Channel_4,1,ADC_SampleTime_41Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_5,2,ADC_SampleTime_41Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_6,3,ADC_SampleTime_41Cycles5);
	ADC_RegularChannelConfig(ADC1,ADC_Channel_7,4,ADC_SampleTime_41Cycles5);

	
	ADC_DMACmd(ADC1,ENABLE);
	ADC_Cmd(ADC1,ENABLE);
	ADC_ResetCalibration(ADC1);
	while(ADC_GetResetCalibrationStatus(ADC1));
	ADC_StartCalibration(ADC1);
	while(ADC_GetCalibrationStatus(ADC1));
	ADC_ExternalTrigConvCmd(ADC1,ENABLE);

以上,配置ADC的同时,开启DMA传送的请求,也配置转换的DMA,注意转换的ADC模式,要选择独立模式,因为这里只涉及了单个ADC,不需要同步;连续采样模式,原理是完成一次采集后触发一次中断,接着继续进行下一次转换,不终止;开启扫描模式。触发方式采用ADC_ExternalTrigConv_T3_TRGO,是利用定时器3的周期中断触发DMA传输,这样实现周期传送数据。

2、配置TIM

这里采用TIM3:

	TIM_TimeBaseInitTypeDef  TIM_TimeBaseStructure;

	RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
  TIM_ClearITPendingBit(TIM3, TIM_IT_Update);
	
	TIM_TimeBaseStructure.TIM_Period=arr;
	TIM_TimeBaseStructure.TIM_Prescaler=psc;
	TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
	TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up;
	TIM_TimeBaseInit(TIM3,&TIM_TimeBaseStructure);
	TIM_SelectOutputTrigger(TIM3,TIM_TRGOSource_Update);

这里系统频率是HSI二分频后送入PLL,再通过PLL 16倍频到64MHz,所以,这里的TIM3的时钟频率为64MHz,在设置预分频系数的时候,将频率降低,分频后的数值,就是计数频率,也就是1S计数数值,再计算所要的周期数,即可填写重装载值。

例如:设置5ms的周期中断(1000/5=200Hz),预分频系数为3200时,分频后的计数频率为20000,也就是1s计2000个数,则重装值为20000/200=100。

再就是进入周期中断的时候要及时清中断标志位,防止下次进不去中断。
            TIM_ClearITPendingBit(TIM3, TIM_IT_Update);

3、读取数据的时候直接读取DMA缓存ADC1_DMA1_Buffer的值就可以,这里的值时根据Rank的顺序依次转换的。

以上。

  • 1
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
以下是一个基本的 STM32F4 DMA 数据传输的代码示例: ``` #include "stm32f4xx.h" #define BUFFER_SIZE 1024 uint32_t src_buffer[BUFFER_SIZE]; uint32_t dst_buffer[BUFFER_SIZE]; void init_DMA(void) { DMA_InitTypeDef dma_init; RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE); DMA_StructInit(&dma_init); dma_init.DMA_Channel = DMA_Channel_0; dma_init.DMA_PeripheralBaseAddr = (uint32_t)src_buffer; dma_init.DMA_Memory0BaseAddr = (uint32_t)dst_buffer; dma_init.DMA_DIR = DMA_DIR_PeripheralToMemory; dma_init.DMA_BufferSize = BUFFER_SIZE; dma_init.DMA_PeripheralInc = DMA_PeripheralInc_Enable; dma_init.DMA_MemoryInc = DMA_MemoryInc_Enable; dma_init.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Word; dma_init.DMA_MemoryDataSize = DMA_MemoryDataSize_Word; dma_init.DMA_Mode = DMA_Mode_Normal; dma_init.DMA_Priority = DMA_Priority_High; dma_init.DMA_FIFOMode = DMA_FIFOMode_Enable; dma_init.DMA_FIFOThreshold = DMA_FIFOThreshold_Full; dma_init.DMA_MemoryBurst = DMA_MemoryBurst_Single; dma_init.DMA_PeripheralBurst = DMA_PeripheralBurst_Single; DMA_Init(DMA2_Stream0, &dma_init); } int main(void) { init_DMA(); // 启动 DMA 传输 DMA_Cmd(DMA2_Stream0, ENABLE); while (1) { // 循环等待 DMA 传输完成 while (DMA_GetFlagStatus(DMA2_Stream0, DMA_FLAG_TCIF0) == RESET) {} DMA_ClearFlag(DMA2_Stream0, DMA_FLAG_TCIF0); // 处理数据 for (int i = 0; i < BUFFER_SIZE; i++) { // ... } // 重新启动 DMA 传输 DMA_Cmd(DMA2_Stream0, ENABLE); } } ``` 在这个代码中,我们首先定义了两个缓冲区 `src_buffer` 和 `dst_buffer`,它们的大小均为 `BUFFER_SIZE`。然后我们在 `init_DMA()` 函数中初始化了 DMA 控制器,并将 `src_buffer` 的地址作为外设地址,`dst_buffer` 的地址作为内存地址,设置了数据传输方向为外设到内存,以及传输数据的大小和增量等参数。 在 `main()` 函数中,我们启动了 DMA 的传输,并在一个无限循环中等待 DMA 的传输完成。一旦传输完成,我们处理数据,并再次启动 DMA 的传输。在这个无限循环中,DMA 将会不断地传输数据,直到程序结束。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值