打印
[STM32F1]

开启DMA后,程序无法启动

[复制链接]
313|17
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
各位大侠好:小弟新学32,编了个测8路数据的程序,其他都还正常。就是当开启使用ADC1的DMA1后,程序编译下载后就无法启动,小弟照着手册例程改了好多遍仍旧无法启动。没办法了,在这向各位大侠请教!!请各位大侠看看,小弟感激不尽,如要程序截图和调试截图都可以奉上,谢谢了!!!

使用特权

评论回复
沙发
pangb| | 2020-4-4 14:23 | 只看该作者

楼主程序可以公开吗?贴程序看下吧,这么说看不出什么原因

使用特权

评论回复
板凳
juventus9554|  楼主 | 2020-4-4 14:26 | 只看该作者
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
     IMPORT  __main
     IMPORT  SystemInit
                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                BX      R0     //单步调试程序卡在这里,下不去了
                 ENDP

使用特权

评论回复
地板
juventus9554|  楼主 | 2020-4-4 14:29 | 只看该作者

使用特权

评论回复
5
juventus9554|  楼主 | 2020-4-4 16:19 | 只看该作者
哪位大侠能帮助小弟找到原因小弟感激不尽,下面是程序截图://这是ADC部分,其中:GetADCValue()函数在TIM3中断中调用,用以读出转换值:
void ADCInit(void) //初始化ADC
{ unsigned char t;
  GPIO_InitTypeDef GPIO_InitStructure;
  ADC_InitTypeDef  ADC_InitStructure;
  RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC时钟分频系数,ADC时钟最大不超过14M
  RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1|
                         RCC_APB2Periph_GPIOA, ENABLE);//开启ADC1和GPIOA时钟
        //初始化ADC对应的GPIO口
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3|
                                                                GPIO_Pin_4 | GPIO_Pin_5 | GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入
  GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化ADC1对应的GPIO口
  //ADC1设置
  ADC_DeInit(ADC1);  //复位ADC外设寄存器.
  ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式
  ADC_InitStructure.ADC_ScanConvMode = ENABLE;       //多通道
  ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续工作
  ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;  //由软件触发工作
  ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;  //右对齐
  ADC_InitStructure.ADC_NbrOfChannel = 8;                                                                  //8通道
  ADC_Init(ADC1, &ADC_InitStructure);                //初始化设置                  
  ADC_DMACmd(ADC1, ENABLE);        //使能ADC1对应的DMA
  ADC_Cmd(ADC1, ENABLE);                //使能ADC1

  ADC_ResetCalibration(ADC1); //复位ADC校准寄存器
  while(ADC_GetResetCalibrationStatus(ADC1)); //等待ADC1校准寄存器复位
  ADC_StartCalibration(ADC1); //开始校准ADC1
  while(ADC_GetCalibrationStatus(ADC1)); //等待校准完成
   // 指定ADC1规则组通道号,顺序及采样周期
  ADC_RegularChannelConfig(ADC1, ADC_Channel_0, 1,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_1, 2,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_2, 3,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 4,  ADC_SampleTime_41Cycles5);
        
  ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 5,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 6,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_6, 7,  ADC_SampleTime_41Cycles5);
  ADC_RegularChannelConfig(ADC1, ADC_Channel_7, 8,  ADC_SampleTime_41Cycles5);

        for(t=0;t<8;t++)
        {
         CH_ADCValue[t]=0;
         CH8_MinADC[t]=0;
         CH8_MaxADC[t]=0;
         CH_ADC1TSum[t]=0;
         CH_Adc_1TAverage[t]=0;
         CH8_Id[t]=0;
         CH8_Temp[t]=0;
         CH_ADC50TSum[t]=0;
         CH_Adc_50TAverage[t]=0;                  
        }
        ADCCnt=0;
        Adc_TCnt=0;
        IsStartAdjTable=0;
}

void GetADCValue(void)//得到8通道ADC数据
{   DMA_InitTypeDef DMA_InitStructure;
        ADC_SoftwareStartConvCmd(ADC1,ENABLE); //开启AD转换
    while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));//等待AD装换结束
        DMA_Cmd(DMA1_Channel1, DISABLE);      //关闭DMA_CHx所指示的通道
        DMA_InitStructure.DMA_PeripheralBaseAddr =(u32)&ADC1->DR;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&CH_ADCValue;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读到内存
        DMA_InitStructure.DMA_BufferSize = 8;  //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_Circular;  //工作在循环模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA1_Channel1, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器        
        DMA_Cmd(DMA1_Channel1, ENABLE);
    if(DMA_GetFlagStatus(DMA1_FLAG_TC1)!=RESET)//等待通道1传输完成  
    {
    ADC_Cmd(ADC1, DISABLE);//关闭ADC转换
        BackCH_ADCValue[0]=CH_ADCValue[0]; //将ADC数据暂存出来
        BackCH_ADCValue[1]=CH_ADCValue[1];
        BackCH_ADCValue[2]=CH_ADCValue[2];
        BackCH_ADCValue[3]=CH_ADCValue[3];
        BackCH_ADCValue[4]=CH_ADCValue[4];
        BackCH_ADCValue[5]=CH_ADCValue[5];
        BackCH_ADCValue[6]=CH_ADCValue[6];
        BackCH_ADCValue[7]=CH_ADCValue[7];  
        ADC_Cmd(ADC1,ENABLE);//关闭ADC转换
        DMA_ClearFlag(DMA1_FLAG_TC1);//清除通道1 传输完成标志
        ++ADCCnt;        //当前采样次数
        }
}


//这个是在主函数中对DMA的初始化:
int main(void)
{        
        delay_init();            //延时函数初始化
        NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
        TIM3_Int_Init(224,99);//定时时间为:20mS/64 (us)
        AT24CXX_Init();
        while(RTCInit(2018,06,18,23,17,00)) //如果时钟初始化失败则停止运行
        {
                SetLedDisp(DISP_E,DISP_R,DISP_R,DISP_0,DISP_0,DISP_1);
        }
        GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable , ENABLE);        
   //改变指定管脚映射 GPIO_Remap_SWJ_JTAGDisable ,JTAG-DP 禁用 + SW-DP 使能
        ADCInit(); //初始化ADC
        InitDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)&CH_ADCValue,8); //初始化DMA
        SysParamInit();
        DispAllInit();
        DispProvision();  
        KeyInit(); //按键初始化;
        MenuInit();
        DoInit();
        BeepInit();//初始化Beep
        DIInit(); //DI初始化
        while(AT24CXX_Check()) //检测不到AT24C04
        {
                SetLedDisp(DISP_E,DISP_R,DISP_R,DISP_0,DISP_0,DISP_2);
        }
        uart_init(BackMenuData.Conn_Add,BackMenuData.Conn_Baud);         //串口初始化为9600                 
        delay_ms(2000); //等待2S                 
        while(1)
        {           
           Rcv_End_Disposal();
           MenuDispFromKey(); //根据按键显示对应菜单
           DoMenuStart(MenuData.DO_Type);
           DIMenuStart(MenuData.DI_type);
           BeepMenuStart(MenuData.Beep_Type);
           Adc_1SAverage();   //计算ADC值.
    }         
}                        

其中InitDMA_Config函数定义如下:
u16 DMA1_MEM_LEN; //表示DMA每次传输数据长度

void InitDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 DMA_Addr,u32 Mem_Addr,u16 DMA_Buffer)
//参数1:DMA通道号; DMA_Addr:DMA基地址;Mem_Addr:内存基地址;DMA_Buffer:DMA通道的DMA缓存的大小
{   DMA_InitTypeDef DMA_InitStructure;
        
        RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);        //开启DMA时钟
    DMA_DeInit(DMA_CHx);   //将DMA的通道1寄存器重设为缺省值
        DMA1_MEM_LEN=DMA_Buffer;
        DMA_InitStructure.DMA_PeripheralBaseAddr =DMA_Addr;  //DMA外设ADC基地址
        DMA_InitStructure.DMA_MemoryBaseAddr = Mem_Addr;  //DMA内存基地址
        DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;  //数据传输方向,从外设读到内存
        DMA_InitStructure.DMA_BufferSize = DMA_Buffer;  //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_Circular;  //工作在循环模式
        DMA_InitStructure.DMA_Priority = DMA_Priority_Medium; //DMA通道 x拥有中优先级
        DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;  //DMA通道x没有设置为内存到内存传输
        DMA_Init(DMA_CHx, &DMA_InitStructure);  //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器        
}

使用特权

评论回复
6
dingy| | 2020-4-4 16:32 | 只看该作者
话说我真的看不懂汇编

使用特权

评论回复
7
juventus9554|  楼主 | 2020-4-4 16:35 | 只看该作者
我也看不懂,郁闷啊!!想不通我只是开启了DMA怎么程序就不运行了???,把ADC采样部分注释掉。程序立马好了!!无语啊

使用特权

评论回复
8
liuzaiy| | 2020-4-4 16:38 | 只看该作者
是不是数据传输太长卡死了?

使用特权

评论回复
9
pangb| | 2020-4-4 16:42 | 只看该作者
太复杂了,搞一堆DMA。

使用特权

评论回复
10
juventus9554|  楼主 | 2020-4-4 16:44 | 只看该作者
不是,刚测试了,只开了一个通道,还是不运行,郁闷

使用特权

评论回复
11
juventus9554|  楼主 | 2020-4-4 16:49 | 只看该作者
不是,刚测试了,只开了一个通道,还是不运行,郁闷

使用特权

评论回复
12
juventus9554|  楼主 | 2020-4-4 16:51 | 只看该作者
为了测试,开始写得很简单,不行,所以重写一遍,写得很详细,看是不是哪里漏了。结果还是不行,哎

使用特权

评论回复
13
guoyt| | 2020-4-4 16:53 | 只看该作者
看你的代码。主函数main都没进去,配置有问题吧。

使用特权

评论回复
14
juventus9554|  楼主 | 2020-4-4 16:56 | 只看该作者

配置应该没问题吧?对了,我今天将AdC1,和DMA1的启动放在了初始化中, GetADCValue中只保存数据,结果可以启动了,但读的数据不对。但是不明白为什么不能再中断中启动DMA( GetADCValue,函数放在TIM3中断函数中的)
void GetADCValue(void)//得到8通道ADC数据
{  
        BackCH_ADCValue[0]=CH_ADCValue[0]; //将ADC数据暂存出来
        BackCH_ADCValue[1]=CH_ADCValue[1];
        BackCH_ADCValue[2]=CH_ADCValue[2];
        BackCH_ADCValue[3]=CH_ADCValue[3];
        BackCH_ADCValue[4]=CH_ADCValue[4];
        BackCH_ADCValue[5]=CH_ADCValue[5];
        BackCH_ADCValue[6]=CH_ADCValue[6];
        BackCH_ADCValue[7]=CH_ADCValue[7];
        IsADCNew=1;        //当前单次采样完成标志
}

使用特权

评论回复
15
langgq| | 2020-4-4 16:59 | 只看该作者
现在解决了吗?

使用特权

评论回复
16
juventus9554|  楼主 | 2020-4-4 17:02 | 只看该作者
谢谢询问!现在我ADC和DMA都用自动循环方式,定时器中断里只保留传过来的数据,不开关ADC和DMA,可以了

使用特权

评论回复
17
juventus9554|  楼主 | 2020-4-4 17:05 | 只看该作者
不过,现在处理ADC数据时,又遇到了一些问题,算出来的结果和实际不对,浮点数方面的。我先查查不行还得向各位大侠请教

使用特权

评论回复
18
juventus9554|  楼主 | 2020-4-4 17:09 | 只看该作者
我再好好缕一缕吧,有了好消息及时通知大家

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

900

主题

12190

帖子

3

粉丝