开发板是原子的迷你板stm32f103RCT6
我用ADC1的通道6也就是PA6进行采样,然后用TIM2_CH2触发ADC1转换,转换的数据再用DMA1搬运到一个数组里

我设置的是ADC独立模式,单次转换,禁止扫描,使能定时器的触发转换
定时器TIM2配置的是PWM1输出比较,向上计数,周期为500us,每500us触发转换一个采样点
DMA1配置的是正常缓存模式,内存地址递增,使能传输完成中断
我在代码中设置的是采样10个点,在DMA传输中断函数中让LED1点亮来指示采样了10个点
现在的问题是,DMA没有进入中断,理由是LED1没有被点亮,不知道是不是配置错误
目前我还对一下问题存在疑惑:
第一:DMA配置结构体里有一个DMA_InitStructure.DMA_BufferSize设置DMA缓存的是不是采样多少个点就设置多少??
第二:DMA的传输完成中断是指传完一个采样点的数据就进入中断,还是传完DMA_InitStructure.DMA_BufferSize个数据才进入中断
第三:DMA是在每次ADC转换完成了才传输一次,还是在第一次触发后就不管有没有更新,一直传DMA_InitStructure.DMA_BufferSize个数据
第四:ADC应该配置为单次转换还是循环转换
第五:定时器要不要下面两行代码,我看有些博客写了,有些又没写
TIM_InternalClockConfig(TIM2); TIM_UpdateDisableConfig(TIM2, DISABLE);
下面是各模块文件的代码
- #include "gpio.h"
- void rcc_Clock_Init(void)
- {
- //使能PA,PD端口时钟,ADC1时钟
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA|RCC_APB2Periph_GPIOD|RCC_APB2Periph_ADC1, ENABLE);
-
- RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);//使能TIM2时钟
- RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA传输
-
- }
- void gpio_Init(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
-
- //PA6 作为模拟通道输入引脚
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;
- //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//作为模拟输入口要不要设置速度??
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
- GPIO_Init(GPIOA, &GPIO_InitStructure);
-
- //初始化PA8和PD2,PA8和PD2是连接LED0和LED1的
- //LED IO初始化
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8; //LED0-->PA.8 端口配置
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
- GPIO_Init(GPIOA, &GPIO_InitStructure); //根据设定参数初始化GPIOA.8
- GPIO_SetBits(GPIOA,GPIO_Pin_8); //PA.8 输出高
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //LED1-->PD.2 端口配置, 推挽输出
- GPIO_Init(GPIOD, &GPIO_InitStructure); //推挽输出 ,IO口速度为50MHz
- GPIO_SetBits(GPIOD,GPIO_Pin_2); //PD.2 输出高
- }
复制代码- #include "adc.h"
-
- void Adc_Init(void)
- {
- ADC_InitTypeDef ADC_InitStructure;
- RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M
- ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
- ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC工作模式:独立模式
- ADC_InitStructure.ADC_ScanConvMode = DISABLE; //模数转换工作在单通道模式
- ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //模数转换工作在单次转换模式
- ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2; //转换由外部触发启动
- ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐
- ADC_InitStructure.ADC_NbrOfChannel = 1; //顺序进行规则转换的ADC通道的数目
- ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
-
-
- ADC_RegularChannelConfig(ADC1,ADC_Channel_6, 1, ADC_SampleTime_239Cycles5 );
-
- //使能ADC、DMA
- ADC_DMACmd(ADC1,ENABLE);
- ADC_Cmd(ADC1,ENABLE);
-
- ADC_ResetCalibration(ADC1); //使能复位校准
-
- while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
-
- ADC_StartCalibration(ADC1); //开启AD校准
-
- while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
-
- ADC_ExternalTrigConvCmd(ADC1, ENABLE); //设置外部触发模式使能
- }
复制代码- #include "dma.h"
- DMA_InitTypeDef DMA_InitStructure;
- NVIC_InitTypeDef NVIC_InitStructure;
- //DMA1的各通道配置
- //这里的传输形式是固定的,这点要根据不同的情况来修改
- //从存储器->外设模式/8位数据宽度/存储器增量模式
- //DMA_CHx:DMA通道CHx
- //cpar:外设地址
- //cmar:存储器地址
- //cndtr:数据传输量
- void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
- {
-
-
- DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
- DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设ADC基地址
- DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
- DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从内存读取发送到外设
- DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
- DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
- DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
- DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //数据宽度为16位
- DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //数据宽度为16位
- DMA_InitStructure.DMA_Mode = DMA_Mode_Normal; //工作在正常缓存模式
- DMA_InitStructure.DMA_Priority = DMA_Priority_VeryHigh; //DMA通道 x拥有超高优先级
- DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
- DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道所标识的寄存器
-
- DMA_ITConfig(DMA1_Channel1,DMA_IT_TC, ENABLE); //使能传输完成中断
-
- NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
- NVIC_Init(&NVIC_InitStructure);
-
- DMA_Cmd(DMA1_Channel1,ENABLE);
- }
复制代码- #include "timer.h"
- //PWM输出初始化
- //arr:自动重装值
- //psc:时钟预分频数
- void TIM2_Init(u16 arr,u16 psc)
- {
- TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
- TIM_OCInitTypeDef TIM_OCInitStructure;
-
- TIM_TimeBaseStructure.TIM_Period = arr; //设置在下一个更新事件装入活动的自动重装载寄存器周期的值 80K
- TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置用来作为TIMx时钟频率除数的预分频值 不分频
- TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割:TDTS = Tck_tim
- TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM向上计数模式
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure); //根据TIM_TimeBaseInitStruct中指定的参数初始化TIMx的时间基数单位
-
- TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式1
- TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
- TIM_OCInitStructure.TIM_Pulse = (arr+1)/2; //设置待装入捕获比较寄存器的脉冲值
- TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
- TIM_OC1Init(TIM2, &TIM_OCInitStructure); //根据TIM_OCInitStruct中指定的参数初始化外设TIM2
- TIM_CtrlPWMOutputs(TIM2,ENABLE); //MOE 主输出使能
- TIM_InternalClockConfig(TIM2);
- TIM_OC2PreloadConfig(TIM2, TIM_OCPreload_Enable); //CH1预装载使能
- TIM_UpdateDisableConfig(TIM2, DISABLE);
- TIM_ARRPreloadConfig(TIM2, ENABLE); //使能TIM2在ARR上的预装载寄存器
-
- TIM_Cmd(TIM2, ENABLE); //使能TIM2
-
-
- }
复制代码 main文件如下:
- #include "delay.h"
- #include "sys.h"
- #include "gpio.h"
- #include "timer.h"
- #include "adc.h"
- #include "dma.h"
- #include "usart.h"
- #define ADC1_DR_Address ((u32)0x4001244C) //ADC1的数据寄存器的地址
- #define buf_len 10 //采样点数10个,同时也是采样存储数据的数组ADC1_ConvertedValue[]的长度
- u8 ADC1_Full_Flag = 0;//采样buf_len个点数完成标志,若DMA传输完所有点数,则由DMA传输中断置1
- u16 ADC_ConvertedValue[buf_len];//该数组用于存储DMA1从采样数据寄存器传过来的数据
- int main(void)
- {
- u8 i=0;
- u16 times = 0;
- rcc_Clock_Init(); //时钟初始化
- delay_init(); //延时函数初始化
- uart_init(9600); //串口初始化
- gpio_Init(); //初始化GPIO
- Adc_Init(); //初始化ADC1
- MYDMA_Config(DMA1_Channel1,(u32)ADC1_DR_Address,(u32)ADC_ConvertedValue,buf_len);//DMA1初始化
- TIM2_Init(499,71);//72分频。采样周期=(499+1)*(71+1)/72Mhz=500us ,即每500us采样一次,采样点数由len_buf控制
- while(1)
- {
- if(ADC1_Full_Flag)//如果采样len_buf个点完成
- {
- DMA_Cmd(DMA1_Channel1, DISABLE );//关闭DMA传输通道
- TIM_Cmd(TIM2, DISABLE);//关闭定时器,定时采样也结束了
- LED1 = 0; //点亮LED1,指示采样完成
- ADC1_Full_Flag = 0;
- }
- else if(USART_RX_STA&0x8000)//串口有数据发送过来,表示电脑端准备好接收数据了
- {
- //开始发送数据给电脑
- printf("\r\n开始发送数据:\r\n");
- for(i=0;i<buf_len;i++)
- {
- //由于串口一次只能传一个字节,但采样数据是两个字节的,所以分两次传送
- USART1->DR = (ADC_ConvertedValue[i]>>8);//发送高8位
- while((USART1->SR&0X40)==0);//等待发送结束(判断状态寄存器的TC标志位,若为1则发送完成)
- USART1->DR=(ADC_ConvertedValue[i])&0x00ff;//发送低8位
- while((USART1->SR&0X40)==0);//等待发送结束(判断状态寄存器的TC标志位,若为1则发送完成)
- }
- printf("\r\n发送完成\r\n");
- USART_RX_STA=0;
- }
- else
- {
- times++;
- if(times%50==0)LED0=!LED0;//闪烁LED0,提示系统正在运行(若在进行串口通信,LED0不再闪烁)
- delay_ms(5);
- }
- }
- }
- //DMA1传输完成中断
- void DMA1_Channel1_IRQHandler(void)
- {
- if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
- {
- ADC1_Full_Flag = 1;
- LED1=0;//传送完成则点亮LED1
- DMA_ClearITPendingBit(DMA1_IT_TC1);
- }
- }
复制代码
|