首页 新闻 会员 周边 捐助

STM32的DMA传输ADC采集数据,TCIF标志位无法判断

0
悬赏园豆:200 [已解决问题] 解决于 2023-09-06 11:04

我是用STM32F429IGTX做一个三重ADC单通道采集。我的构思是:ADC采集到数据之后DMA传输到指定的数组,然后我在主函数里面判断TCIF传输完成标志位(我的理解是,每传输一次都会将这个标志位置1)是否为1。为1我就处理ADC的数据。可是现在程序卡在这个判断语句入口。我找了好多资料都没解决。

这是主函数源码文件:在主函数中我如果把

 if(__HAL_DMA_GET_FLAG(&DMA_Init_Handle,DMA_FLAG_TCIF3_7))这个判断语句删掉,
那么程序可以正常打印电压值,说明DMA在正常运转,
我也查了DMA运行时的CR寄存器的值是0x00022D1F
说明CR寄存器的位4-TCIE是被使能的,说明DMA是使能DMA传输完成中断的,按道理应该每传输完成一次
都应该将TCIF置1才对。

 1 #include "sys.h"
 2 #include "delay.h"
 3 #include "usart.h"
 4 #include "led.h"
 5 #include "key.h"
 6 #include "lcd.h"
 7 #include "sdram.h"
 8 #include "adc.h"
 9 float calculateAverage(vu16 arr[], int size);
10 /*extern关键字,声明变量在别出已经定义*/
11 extern vu16   ADC_ConvertValue[3];/*extern关键字,声明变量在别出已经定义*/
12 extern DMA_HandleTypeDef DMA_Init_Handle;
13 // 局部变量,用于保存转换计算后的电压值      
14 float ADC_ConvertedValueLocal[3]={0}; 
15 int main(void)
16 { 
17       uint32_t hisr;
18       uint32_t tcifx;
19        u8 len;    
20       u16 times=0; 
21     u16 adcx;
22       float ADC_Value;
23       float Sensor_Vlaue;
24       float temp;
25     HAL_Init();                     //初始化HAL库   
26     Stm32_Clock_Init(240,25,2,8);   //设置时钟,此时HCLK是120MHZ,PCLK2是60HZ
27     delay_init(180);                //初始化延时函数
28     uart_init(115200);              //初始化USART
29     LED_Init();                     //初始化LED 
30     KEY_Init();   
31      //初始化按键
32    Rheostat_Init(); 
33 
34     while(1)
35         {    
36             times++;
37               if(times%30==0)
38                 LED0=!LED0;//闪烁LED,提示系统正在运行.
39               delay_ms(10);
40          if(__HAL_DMA_GET_FLAG(&DMA_Init_Handle,DMA_FLAG_TCIF3_7))
41               {
42             
43                          printf("\r\n The current  value = %f mm \r\n",Sensor_Vlaue);     
44                   __HAL_DMA_CLEAR_FLAG(&DMA_Init_Handle,DMA_FLAG_TCIF3_7);    
45                   ADC_Value=calculateAverage(ADC_ConvertValue, 3);
46                     Sensor_Vlaue=((ADC_Value*1000000)/3300000)*2;
47          }
48                 //USART_RX_STA是串口接受标志位
49                 //       if(USART_RX_STA&0x8000)
50                 //        {                       
51                 //            len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
52                 //        //    printf("ffff01020304");
53                 //            HAL_UART_Transmit(&UART1_Handler,(uint8_t*)USART_RX_BUF,len,1000);    //发送接收到的数据
54                 //            while(__HAL_UART_GET_FLAG(&UART1_Handler,UART_FLAG_TC)!=SET);        //等待发送结束
55                 //            USART_RX_STA=0;
56                 //        }
57     }  
58 }
59 void HAL_ADC_ConvHalfCpltCallback(ADC_HandleTypeDef* hadc)
60 {
61     printf("there");
62 }
63 
64 float calculateAverage(vu16 arr[], int size)
65     {
66     float sum = 0.0;
67     int i;
68 
69     for (i = 0; i < size; i++) 
70         {
71         sum += ((float)arr[i]*3.3/4096);
72     }
73 
74     return sum / size;
75  }

这是ADC和DMA初始化源码文件

  1 #include "adc.h"
  2 #include "delay.h"
  3 
  4 
  5 vu16  ADC_ConvertValue[3]={0};
  6 /*DMA、ADC1、ADC2、ADC3句柄*/
  7 DMA_HandleTypeDef DMA_Init_Handle;
  8 ADC_HandleTypeDef ADC_Handle1;
  9 ADC_HandleTypeDef ADC_Handle2;
 10 ADC_HandleTypeDef ADC_Handle3;
 11 /*绑定 ADC 通道转换顺序和采样时间*/
 12 ADC_ChannelConfTypeDef ADC_Config;
 13 
 14 /*步骤1初始化三个ADC共用的引脚为模拟输入模式*/
 15 static void Rheostat_ADC_GPIO_Config(void)
 16 {
 17     GPIO_InitTypeDef GPIO_InitStructure;
 18     // 使能 GPIO 时钟
 19     RHEOSTAT_ADC_GPIO_CLK_ENABLE();    
 20     // 配置 IO
 21     GPIO_InitStructure.Pin = RHEOSTAT_ADC_GPIO_PIN;
 22     GPIO_InitStructure.Mode = GPIO_MODE_ANALOG;        
 23     GPIO_InitStructure.Pull = GPIO_NOPULL ; //不上拉不下拉
 24     HAL_GPIO_Init(RHEOSTAT_ADC_GPIO_PORT, &GPIO_InitStructure);
 25 }
 26 static void Rheostat_ADC_Mode_Config(void)
 27 {
 28     ADC_MultiModeTypeDef   mode;
 29      // ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
 30     // 开启DMA时钟
 31     RHEOSTAT_ADC_DMA_CLK_ENABLE();
 32     // 数据传输通道
 33     DMA_Init_Handle.Instance = RHEOSTAT_ADC_DMA_STREAM;
 34     // 数据传输方向为外设到存储器    
 35     DMA_Init_Handle.Init.Direction = DMA_PERIPH_TO_MEMORY;    
 36     // 外设寄存器只有一个,地址不用递增,外设寄存器的地址是ADC_CDR寄存器的地址
 37     DMA_Init_Handle.Init.PeriphInc = DMA_PINC_DISABLE;
 38     // 存储器地址递增
 39     DMA_Init_Handle.Init.MemInc = DMA_MINC_ENABLE; 
 40     // // 外设数据大小为半字,即两个字节 
 41     DMA_Init_Handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD; 
 42     //    存储器数据大小也为半字,跟外设数据大小相同
 43     DMA_Init_Handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;    
 44     // 循环传输模式
 45     DMA_Init_Handle.Init.Mode = DMA_CIRCULAR;
 46     // DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
 47     DMA_Init_Handle.Init.Priority = DMA_PRIORITY_HIGH;
 48     // 禁止DMA FIFO    ,使用直连模式
 49     DMA_Init_Handle.Init.FIFOMode = DMA_FIFOMODE_DISABLE;  
 50     // FIFO 大小,FIFO模式禁止时,这个不用配置    
 51     DMA_Init_Handle.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_HALFFULL;
 52     DMA_Init_Handle.Init.MemBurst = DMA_MBURST_SINGLE;
 53     DMA_Init_Handle.Init.PeriphBurst = DMA_PBURST_SINGLE;  
 54     // 选择 DMA 通道,通道存在于流中,通道0
 55     DMA_Init_Handle.Init.Channel = RHEOSTAT_ADC_DMA_CHANNEL; 
 56        
 57 
 58     //初始化DMA流,流相当于一个大的管道,管道里面有很多通道
 59     HAL_DMA_Init(&DMA_Init_Handle);
 60 
 61         
 62         
 63      // 开启ADC时钟
 64     RHEOSTAT_ADC1_CLK_ENABLE();
 65     RHEOSTAT_ADC2_CLK_ENABLE();
 66     RHEOSTAT_ADC3_CLK_ENABLE();
 67         // -------------------ADC1 Init 结构体 参数 初始化------------------------
 68     // ADC1
 69     ADC_Handle1.Instance = RHEOSTAT_ADC1;
 70     // 时钟为fpclk 2分频    因为ADC的时钟是由PCLK2分频产生,且此时PCLK2是60MHZ
 71     ADC_Handle1.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
 72     // ADC 分辨率
 73     ADC_Handle1.Init.Resolution = ADC_RESOLUTION_12B;
 74     // 禁止扫描模式,多通道采集才需要    
 75     ADC_Handle1.Init.ScanConvMode = DISABLE; 
 76     // 连续转换    
 77     ADC_Handle1.Init.ContinuousConvMode = ENABLE;
 78     // 非连续转换    
 79     ADC_Handle1.Init.DiscontinuousConvMode = DISABLE;
 80     // 非连续转换个数
 81     ADC_Handle1.Init.NbrOfDiscConversion   = 0;
 82     //禁止外部边沿触发    
 83     ADC_Handle1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
 84     //使用软件触发,外部触发不用配置,注释掉即可
 85     //ADC_Handle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;
 86     //数据右对齐    
 87     ADC_Handle1.Init.DataAlign = ADC_DATAALIGN_RIGHT;
 88     //转换通道个数
 89     ADC_Handle1.Init.NbrOfConversion = 1;
 90     //使能连续转换请求
 91     ADC_Handle1.Init.DMAContinuousRequests = ENABLE;
 92     //转换完成标志
 93     ADC_Handle1.Init.EOCSelection          = DISABLE;    
 94     // 初始化ADC                              
 95     HAL_ADC_Init(&ADC_Handle1);
 96     //---------------------------------------------------------------------------
 97     // 配置 ADC1 通道13转换顺序为1,第一个转换,采样时间为3个时钟周期
 98     ADC_Config.Channel      = RHEOSTAT_ADC_CHANNEL;
 99     ADC_Config.Rank         = 1;    
100     ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES;// 采样时间间隔    
101     ADC_Config.Offset       = 0;
102     HAL_ADC_ConfigChannel(&ADC_Handle1, &ADC_Config);
103     
104     // -------------------ADC2 Init 结构体 参数 初始化------------------------
105     // ADC2
106     ADC_Handle2.Instance = RHEOSTAT_ADC2;
107     // 时钟为fpclk 2分频    
108     ADC_Handle2.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
109     // ADC 分辨率
110     ADC_Handle2.Init.Resolution = ADC_RESOLUTION_12B;
111     // 禁止扫描模式,多通道采集才需要    
112     ADC_Handle1.Init.ScanConvMode = DISABLE; 
113     // 连续转换    
114     ADC_Handle2.Init.ContinuousConvMode = ENABLE;
115     // 非连续转换    
116     ADC_Handle2.Init.DiscontinuousConvMode = DISABLE;
117     // 非连续转换个数
118     ADC_Handle2.Init.NbrOfDiscConversion   = 0;
119     //禁止外部边沿触发    
120     ADC_Handle2.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
121     //使用软件触发,外部触发不用配置,注释掉即可
122     //ADC_Handle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;
123     //数据右对齐    
124     ADC_Handle2.Init.DataAlign = ADC_DATAALIGN_RIGHT;
125     //转换通道个数
126     ADC_Handle2.Init.NbrOfConversion = 1;
127     //使能连续转换请求
128     ADC_Handle2.Init.DMAContinuousRequests = ENABLE;
129     //转换完成标志
130     ADC_Handle2.Init.EOCSelection          = DISABLE;    
131     // 初始化ADC                              
132     HAL_ADC_Init(&ADC_Handle2);
133     // 配置 ADC2 通道13转换顺序为1,第一个转换,采样时间为3个时钟周期
134     ADC_Config.Channel      = RHEOSTAT_ADC_CHANNEL;
135     ADC_Config.Rank         = 1;
136     ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES; // 采样时间间隔    
137     ADC_Config.Offset       = 0;
138     HAL_ADC_ConfigChannel(&ADC_Handle2, &ADC_Config);
139     
140     // -------------------ADC33 Init 结构体 参数 初始化------------------------
141     // ADC3
142     ADC_Handle3.Instance = RHEOSTAT_ADC3;
143     // 时钟为fpclk 2分频    
144     ADC_Handle3.Init.ClockPrescaler = ADC_CLOCKPRESCALER_PCLK_DIV2;
145     // ADC 分辨率
146     ADC_Handle3.Init.Resolution = ADC_RESOLUTION_12B;
147     // 禁止扫描模式,多通道采集才需要    
148     ADC_Handle1.Init.ScanConvMode = DISABLE; 
149     // 连续转换    
150     ADC_Handle3.Init.ContinuousConvMode = ENABLE;
151     // 非连续转换    
152     ADC_Handle3.Init.DiscontinuousConvMode = DISABLE;
153     // 非连续转换个数
154     ADC_Handle3.Init.NbrOfDiscConversion   = 0;
155     //禁止外部边沿触发    
156     ADC_Handle3.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;
157     //使用软件触发,外部触发不用配置,注释掉即可
158     //ADC_Handle.Init.ExternalTrigConv      = ADC_EXTERNALTRIGCONV_T1_CC1;
159     //数据右对齐    
160     ADC_Handle3.Init.DataAlign = ADC_DATAALIGN_RIGHT;
161     //转换通道个数
162     ADC_Handle3.Init.NbrOfConversion = 1;
163     //使能连续转换请求
164     ADC_Handle3.Init.DMAContinuousRequests = ENABLE;
165     //转换完成标志
166     ADC_Handle3.Init.EOCSelection          = DISABLE;    
167     // 初始化ADC                              
168     HAL_ADC_Init(&ADC_Handle3);
169     // 配置 ADC3 通道13转换顺序为1,第一个转换,采样时间为3个时钟周期
170     ADC_Config.Channel      = RHEOSTAT_ADC_CHANNEL;
171     ADC_Config.Rank         = 1;        
172     ADC_Config.SamplingTime = ADC_SAMPLETIME_3CYCLES;// 采样时间间隔
173     ADC_Config.Offset       = 0;
174     HAL_ADC_ConfigChannel(&ADC_Handle3, &ADC_Config);   /*该函数用于绑定
175         ADC通道转换顺序和采样时间 */
176           /*配置三重AD采样*/
177     /*这个mode 是ADC_MultiModeTypeDef结构体变量,用来配置ADC为三重ADC交替模式,分屏系数为4,
178     并且需要设置DMA为模式2,10个采样周期延迟*/
179     mode.Mode = ADC_TRIPLEMODE_INTERL;
180     mode.DMAAccessMode = ADC_DMAACCESSMODE_2;
181     mode.TwoSamplingDelay = ADC_TWOSAMPLINGDELAY_5CYCLES;
182     /*该函数用于控制是否使能ADC的DMA请求,只有使能了DMA请求,并调用HAL_ADCEx_MultiModeStart_DMA使能DMA,
183         则在ADC转换完成后,就会自动请求DMA实现数据传输,并且三重模式只需要使能ADC1的DMA通道即可*/
184     HAL_ADCEx_MultiModeConfigChannel(&ADC_Handle1, &mode);
185     
186     HAL_ADC_Start(&ADC_Handle2);
187     HAL_ADC_Start(&ADC_Handle3);
188     /*连接ADC句柄和DMA句柄的,想要通过DMA转移ADC数据必须要这一步*/
189     __HAL_LINKDMA(&ADC_Handle1, DMA_Handle, DMA_Init_Handle);
190     __HAL_LINKDMA(&ADC_Handle2, DMA_Handle, DMA_Init_Handle);
191     __HAL_LINKDMA(&ADC_Handle3, DMA_Handle, DMA_Init_Handle);    
192     HAL_ADCEx_MultiModeStart_DMA(&ADC_Handle1, (uint32_t *)ADC_ConvertValue, 3);
193 
194 
195 
196 }
197 
198 void Rheostat_Init(void)
199 {
200     Rheostat_ADC_GPIO_Config();
201     
202     Rheostat_ADC_Mode_Config();
203 
204 }
问题补充:

现在的问题是if语句一次都不能进入,至于清除标记位先不管

wuwuy的主页 wuwuy | 初学一级 | 园豆:24
提问于:2023-09-05 18:05
< >
分享
最佳答案
0

if语句中的标志位判断错误,DMA2Channel0Strem0,的传输完成中断标志位应该是0。TCIF0,由于我对DMA的了解不多,阅读手册也不够仔细导致没注意到这一点。解决方案将代码改一下即可。

 if(__HAL_DMA_GET_FLAG(&DMA_Init_Handle,DMA_FLAG_TCIF0_4))
              {
                    //__HAL_DMA_CLEAR_FLAG(&DMA_Init_Handle,DMA_FLAG_TCIF0_4);    
                  ADC_Value=calculateAverage(ADC_ConvertValue, 3);
                    Sensor_Vlaue=((ADC_Value*1000000)/3300000)*2;
                  printf("\r\n The current  value = %f mm \r\n",Sensor_Vlaue); 
          }
wuwuy | 初学一级 |园豆:24 | 2023-09-06 11:03
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册