我是用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语句一次都不能进入,至于清除标记位先不管
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); }