打铁还是得趁热,前几天期末复习去了,几天没碰32,又差点提不起劲了,不过,我岂是这么容易就放弃的人,哈哈。今天我们来学习STM32的ADC(模拟/数字转换器)模块。
在此之前,做几点说明:
1、以后的代码分析全部基于Debug调试,因为这样的确能节约很多的时间,而且代码运行的结果更加准确。
2、之前的文章篇幅实在是太大,所以从这篇文章开始尽量精简篇幅,只分析较重要的知识点与代码。
一、GPIO配置
/** * @brief 使能ADC1和DMA1的时钟,初始化PC.01 * @param 无 * @retval 无 */ static void ADC1_GPIO_Config(void) { GPIO_InitTypeDef GPIO_InitStructure; /* Enable DMA clock */ RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); /* Enable ADC1 and GPIOC clock */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE); /* Configure PC.01 as analog input */ GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &GPIO_InitStructure);// PC1,因为是输入模式,所以不用设置速率 }
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
因为DMA1挂载于AHB总线上,所以开启AHB时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
开启ADC1、GPIOC的时钟,它们挂载于APB2总线上。
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; GPIO_Init(GPIOC, &GPIO_InitStructure);// PC1,因为是输入模式,所以不用设置速率
引脚选为GPIOC->Pin1脚,IO模式为模拟输入。
因为PC1为ADC1的第11输入通道,而我们选择这个通道来实现ADC功能,所以要选中PC1引脚。
由上图可知,不管是使用ADC还是DAC功能,其所在引脚均应配置为模拟模式。所以我们将PC1配置为模拟输入。
最后调用库函数GPIO_Init()初始化GPIOC->Pin1脚,IO口配置完毕。
二、ADC配置
/** * @brief 配置ADC1的工作模式为DMA模式 * @param 无 * @retval 无 */ static void ADC1_Mode_Config(void) { DMA_InitTypeDef DMA_InitStructure; ADC_InitTypeDef ADC_InitStructure; /* DMA channel1 configuration */ DMA_DeInit(DMA1_Channel1); DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //ADC地址 DMA_InitStructure.DMA_MemoryBaseAddr = (u32)&ADC_ConvertedValue;//内存地址 DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;//外设地址固定 DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; //内存地址固定 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); /* Enable DMA channel1 */ DMA_Cmd(DMA1_Channel1, ENABLE); /* ADC1 configuration */ ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;//独立ADC模式 ADC_InitStructure.ADC_ScanConvMode = DISABLE ; //禁止扫描模式,扫描模式用于多通道采集 ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//开启连续转换模式,即不停地进行ADC转换 ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发转换 ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 1; //要转换的通道数目1 ADC_Init(ADC1, &ADC_InitStructure); /*配置ADC时钟,为PCLK2的8分频,即9MHz*/ RCC_ADCCLKConfig(RCC_PCLK2_Div8); /*配置ADC1的通道11为55.5个采样周期,序列为1 */ ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5); /* Enable ADC1 DMA */ ADC_DMACmd(ADC1, ENABLE); /* Enable ADC1 */ ADC_Cmd(ADC1, ENABLE); /*初始化校准寄存器 */ ADC_ResetCalibration(ADC1); /*等待校准寄存器初始化完成 */ while(ADC_GetResetCalibrationStatus(ADC1)); /* ADC校准 */ ADC_StartCalibration(ADC1); /* 等待校准完成*/ while(ADC_GetCalibrationStatus(ADC1)); /* 由于没有采用外部触发,所以使用软件触发ADC转换 */ ADC_SoftwareStartConvCmd(ADC1, ENABLE); }
先定义结构体ADC_InitStructure,其类型为ADC_InitTypeDef,成员为ADC相关配置:模式、扫描转换、连续转换、外部触发、数据对齐、要转换的通道数目。
DMA_DeInit(DMA1_Channel1);
DMA1通道1的参数初始化为缺省值。
DMA各参数的定义如下:
#define ADC1_DR_Address ((u32)0x40012400+0x4c)
因为ADC1的基地址为0x4001 2400,而其数据寄存器相对于基地址的偏移为0x4c,所以外设地址为两者之和(0x4001 2400 + 0x4c)。
__IO uint16_t ADC_ConvertedValue; #define DMA_DIR_PeripheralSRC ((uint32_t)0x00000000) #define DMA_PeripheralInc_Disable ((uint32_t)0x00000000) #define DMA_MemoryInc_Disable ((uint32_t)0x00000000) #define DMA_PeripheralDataSize_HalfWord ((uint32_t)0x00000100) #define DMA_MemoryDataSize_HalfWord ((uint32_t)0x00000400) #define DMA_Mode_Circular ((uint32_t)0x00000020) #define DMA_Priority_High ((uint32_t)0x00002000) #define DMA_M2M_Disable ((uint32_t)0x00000000)
根据上述参数值对DMA进行初始化
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Init()函数定义如下:
/** * @brief Initializes the DMAy Channelx according to the specified * parameters in the DMA_InitStruct. * @param DMAy_Channelx: where y can be 1 or 2 to select the DMA and * x can be 1 to 7 for DMA1 and 1 to 5 for DMA2 to select the DMA Channel. * @param DMA_InitStruct: pointer to a DMA_InitTypeDef structure that * contains the configuration information for the specified DMA Channel. * @retval None */ void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct) { uint32_t tmpreg = 0; /* Check the parameters */ assert_param(IS_DMA_ALL_PERIPH(DMAy_Channelx)); assert_param(IS_DMA_DIR(DMA_InitStruct->DMA_DIR)); assert_param(IS_DMA_BUFFER_SIZE(DMA_InitStruct->DMA_BufferSize)); assert_param(IS_DMA_PERIPHERAL_INC_STATE(DMA_InitStruct->DMA_PeripheralInc)); assert_param(IS_DMA_MEMORY_INC_STATE(DMA_InitStruct->DMA_MemoryInc)); assert_param(IS_DMA_PERIPHERAL_DATA_SIZE(DMA_InitStruct->DMA_PeripheralDataSize)); assert_param(IS_DMA_MEMORY_DATA_SIZE(DMA_InitStruct->DMA_MemoryDataSize)); assert_param(IS_DMA_MODE(DMA_InitStruct->DMA_Mode)); assert_param(IS_DMA_PRIORITY(DMA_InitStruct->DMA_Priority)); assert_param(IS_DMA_M2M_STATE(DMA_InitStruct->DMA_M2M)); /*--------------------------- DMAy Channelx CCR Configuration -----------------*/ /* Get the DMAy_Channelx CCR value */ tmpreg = DMAy_Channelx->CCR; /* Clear MEM2MEM, PL, MSIZE, PSIZE, MINC, PINC, CIRC and DIR bits */ tmpreg &= CCR_CLEAR_Mask; /* Configure DMAy Channelx: data transfer, data size, priority level and mode */ /* Set DIR bit according to DMA_DIR value */ /* Set CIRC bit according to DMA_Mode value */ /* Set PINC bit according to DMA_PeripheralInc value */ /* Set MINC bit according to DMA_MemoryInc value */ /* Set PSIZE bits according to DMA_PeripheralDataSize value */ /* Set MSIZE bits according to DMA_MemoryDataSize value */ /* Set PL bits according to DMA_Priority value */ /* Set the MEM2MEM bit according to DMA_M2M value */ tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode | DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc | DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize | DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M; /* Write to DMAy Channelx CCR */ DMAy_Channelx->CCR = tmpreg; /*--------------------------- DMAy Channelx CNDTR Configuration ---------------*/ /* Write to DMAy Channelx CNDTR */ DMAy_Channelx->CNDTR = DMA_InitStruct->DMA_BufferSize; /*--------------------------- DMAy Channelx CPAR Configuration ----------------*/ /* Write to DMAy Channelx CPAR */ DMAy_Channelx->CPAR = DMA_InitStruct->DMA_PeripheralBaseAddr; /*--------------------------- DMAy Channelx CMAR Configuration ----------------*/ /* Write to DMAy Channelx CMAR */ DMAy_Channelx->CMAR = DMA_InitStruct->DMA_MemoryBaseAddr; }
tmpreg = DMAy_Channelx->CCR;
即tmpreg = 0;
tmpreg &= CCR_CLEAR_Mask;
0与上任何数仍旧为0,所以tmpreg = 0;
tmpreg |= DMA_InitStruct->DMA_DIR | DMA_InitStruct->DMA_Mode | DMA_InitStruct->DMA_PeripheralInc | DMA_InitStruct->DMA_MemoryInc | DMA_InitStruct->DMA_PeripheralDataSize | DMA_InitStruct->DMA_MemoryDataSize | DMA_InitStruct->DMA_Priority | DMA_InitStruct->DMA_M2M;
即temreg = 0 | 0x0000 0000 | 0x0000 0020 | 0x0000 0000 | 0x0000 0000 | 0x0000 0100 | 0x0000 0400 | 0x0000 2000 | 0x0000 0000 = 0x0000 2520;
DMAy_Channelx->CCR = tmpreg;
即DMA1_Channel1->CCR = 0x0000 2520;由DMA的CCR寄存器描述
可知,DMA1的通道1被配置为:非存储器到存储器模式、通道优先级为高、存储器数据宽度为16位、外设数据宽度为16位、不执行存储器地址增量操作、不执行外设地址增量操作、执行循环操作、从外设读(即外设为数据源)。
DMA_Cmd(DMA1_Channel1, ENABLE);
使能DMA1通道1,这里说明一下,ADC1的DMA请求是通过DMA1的通道1来实现的(具体可参考DMA请求映像图)。
ADC各参数的定义如下:
#define ADC_Mode_Independent ((uint32_t)0x00000000) typedef enum {DISABLE = 0, ENABLE = !DISABLE} FunctionalState; #define ADC_ExternalTrigConv_None ((uint32_t)0x000E0000) /*!< For ADC1, ADC2 and ADC3 */ #define ADC_DataAlign_Right ((uint32_t)0x00000000)
根据上述参数值对ADC进行初始化:
ADC_Init(ADC1, &ADC_InitStructure);
库函数ADC_Init()的定义如下:
/** * @brief Initializes the ADCx peripheral according to the specified parameters * in the ADC_InitStruct. * @param ADCx: where x can be 1, 2 or 3 to select the ADC peripheral. * @param ADC_InitStruct: pointer to an ADC_InitTypeDef structure that contains * the configuration information for the specified ADC peripheral. * @retval None */ void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct) { uint32_t tmpreg1 = 0; uint8_t tmpreg2 = 0; /* Check the parameters */ assert_param(IS_ADC_ALL_PERIPH(ADCx)); assert_param(IS_ADC_MODE(ADC_InitStruct->ADC_Mode)); assert_param(IS_FUNCTIONAL_STATE(ADC_InitStruct->ADC_ScanConvMode)); assert_param(IS_FUNCTIONAL_STATE(ADC_InitStruct->ADC_ContinuousConvMode)); assert_param(IS_ADC_EXT_TRIG(ADC_InitStruct->ADC_ExternalTrigConv)); assert_param(IS_ADC_DATA_ALIGN(ADC_InitStruct->ADC_DataAlign)); assert_param(IS_ADC_REGULAR_LENGTH(ADC_InitStruct->ADC_NbrOfChannel)); /*---------------------------- ADCx CR1 Configuration -----------------*/ /* Get the ADCx CR1 value */ tmpreg1 = ADCx->CR1; /* Clear DUALMOD and SCAN bits */ tmpreg1 &= CR1_CLEAR_Mask; /* Configure ADCx: Dual mode and scan conversion mode */ /* Set DUALMOD bits according to ADC_Mode value */ /* Set SCAN bit according to ADC_ScanConvMode value */ tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_Mode | ((uint32_t)ADC_InitStruct->ADC_ScanConvMode << 8)); /* Write to ADCx CR1 */ ADCx->CR1 = tmpreg1; /*---------------------------- ADCx CR2 Configuration -----------------*/ /* Get the ADCx CR2 value */ tmpreg1 = ADCx->CR2; /* Clear CONT, ALIGN and EXTSEL bits */ tmpreg1 &= CR2_CLEAR_Mask; /* Configure ADCx: external trigger event and continuous conversion mode */ /* Set ALIGN bit according to ADC_DataAlign value */ /* Set EXTSEL bits according to ADC_ExternalTrigConv value */ /* Set CONT bit according to ADC_ContinuousConvMode value */ tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_ExternalTrigConv | ((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1)); /* Write to ADCx CR2 */ ADCx->CR2 = tmpreg1; /*---------------------------- ADCx SQR1 Configuration -----------------*/ /* Get the ADCx SQR1 value */ tmpreg1 = ADCx->SQR1; /* Clear L bits */ tmpreg1 &= SQR1_CLEAR_Mask; /* Configure ADCx: regular channel sequence length */ /* Set L bits according to ADC_NbrOfChannel value */ tmpreg2 |= (uint8_t) (ADC_InitStruct->ADC_NbrOfChannel - (uint8_t)1); tmpreg1 |= (uint32_t)tmpreg2 << 20; /* Write to ADCx SQR1 */ ADCx->SQR1 = tmpreg1; }
tmpreg1 = ADCx->CR1;
即tmpreg1 = 0;
tmpreg1 &= CR1_CLEAR_Mask;
0与上任何数都为0,所以tmpreg1 = 0;
tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_Mode | ((uint32_t)ADC_InitStruct->ADC_ScanConvMode << 8));
即tmpreg1 = 0 | (0x0000 0000) | (0 << 8) = 0;
ADCx->CR1 = tmpreg1;
即ADC1->CR1 = 0;由ADC的CR1寄存器描述
可知,ADC1被配置为:独立模式、关闭扫描模式。
tmpreg1 = ADCx->CR2;
即tmpreg1 = 0;
tmpreg1 &= CR2_CLEAR_Mask;
即tmpreg1 = 0;
tmpreg1 |= (uint32_t)(ADC_InitStruct->ADC_DataAlign | ADC_InitStruct->ADC_ExternalTrigConv | ((uint32_t)ADC_InitStruct->ADC_ContinuousConvMode << 1));
即tmpreg1 = 0 | 0x0000 0000 | 0x000E 0000 | (0x01 << 1) = 0x000E 0002;
ADCx->CR2 = tmpreg1;
即ADC1->CR2 = 0x000E 0002;由ADC的CR2寄存器描述
可知,ADC1被配置为:选择SWSTART为触发事件、连续转换模式。
tmpreg1 = ADCx->SQR1;
即tmpreg1 = 0;
tmpreg1 &= SQR1_CLEAR_Mask;
即tmpreg1 = 0;
tmpreg2 |= (uint8_t) (ADC_InitStruct->ADC_NbrOfChannel - (uint8_t)1);
即tmpreg2 = 0 | (1 - 1) = 0;
tmpreg1 |= (uint32_t)tmpreg2 << 20;
即tmpreg1 = 0 | (0 << 20) = 0;
ADCx->SQR1 = tmpreg1;
即ADC1->SQR1 = 0;由ADC的SQR1寄存器描述
可知,ADC1被配置为:1个转换。
RCC_ADCCLKConfig(RCC_PCLK2_Div8);
/** * @brief Configures the ADC clock (ADCCLK). * @param RCC_PCLK2: defines the ADC clock divider. This clock is derived from * the APB2 clock (PCLK2). * This parameter can be one of the following values: * @arg RCC_PCLK2_Div2: ADC clock = PCLK2/2 * @arg RCC_PCLK2_Div4: ADC clock = PCLK2/4 * @arg RCC_PCLK2_Div6: ADC clock = PCLK2/6 * @arg RCC_PCLK2_Div8: ADC clock = PCLK2/8 * @retval None */ void RCC_ADCCLKConfig(uint32_t RCC_PCLK2) { uint32_t tmpreg = 0; /* Check the parameters */ assert_param(IS_RCC_ADCCLK(RCC_PCLK2)); tmpreg = RCC->CFGR; /* Clear ADCPRE[1:0] bits */ tmpreg &= CFGR_ADCPRE_Reset_Mask; /* Set ADCPRE[1:0] bits according to RCC_PCLK2 value */ tmpreg |= RCC_PCLK2; /* Store the new value */ RCC->CFGR = tmpreg; }
根据上述RCC_ADCCLKConfig()函数定义及Debug调试
可得:RCC->CFGR = 0x001D C40A;由RCC的CFGR寄存器描述
可知,ADC时钟被配置为:PCLK2的8分频(72 / 8 = 9 MHz)。
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 1, ADC_SampleTime_55Cycles5);
ADC_RegularChannelConfig()函数定义如下:
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime) { uint32_t tmpreg1 = 0, tmpreg2 = 0; /* Check the parameters */ assert_param(IS_ADC_ALL_PERIPH(ADCx)); assert_param(IS_ADC_CHANNEL(ADC_Channel)); assert_param(IS_ADC_REGULAR_RANK(Rank)); assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime)); /* if ADC_Channel_10 ... ADC_Channel_17 is selected */ if (ADC_Channel > ADC_Channel_9) { /* Get the old register value */ tmpreg1 = ADCx->SMPR1; /* Calculate the mask to clear */ tmpreg2 = SMPR1_SMP_Set << (3 * (ADC_Channel - 10)); /* Clear the old channel sample time */ tmpreg1 &= ~tmpreg2; /* Calculate the mask to set */ tmpreg2 = (uint32_t)ADC_SampleTime << (3 * (ADC_Channel - 10)); /* Set the new channel sample time */ tmpreg1 |= tmpreg2; /* Store the new register value */ ADCx->SMPR1 = tmpreg1; } else /* ADC_Channel include in ADC_Channel_[0..9] */ { /* Get the old register value */ tmpreg1 = ADCx->SMPR2; /* Calculate the mask to clear */ tmpreg2 = SMPR2_SMP_Set << (3 * ADC_Channel); /* Clear the old channel sample time */ tmpreg1 &= ~tmpreg2; /* Calculate the mask to set */ tmpreg2 = (uint32_t)ADC_SampleTime << (3 * ADC_Channel); /* Set the new channel sample time */ tmpreg1 |= tmpreg2; /* Store the new register value */ ADCx->SMPR2 = tmpreg1; } /* For Rank 1 to 6 */ if (Rank < 7) { /* Get the old register value */ tmpreg1 = ADCx->SQR3; /* Calculate the mask to clear */ tmpreg2 = SQR3_SQ_Set << (5 * (Rank - 1)); /* Clear the old SQx bits for the selected rank */ tmpreg1 &= ~tmpreg2; /* Calculate the mask to set */ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 1)); /* Set the SQx bits for the selected rank */ tmpreg1 |= tmpreg2; /* Store the new register value */ ADCx->SQR3 = tmpreg1; } /* For Rank 7 to 12 */ else if (Rank < 13) { /* Get the old register value */ tmpreg1 = ADCx->SQR2; /* Calculate the mask to clear */ tmpreg2 = SQR2_SQ_Set << (5 * (Rank - 7)); /* Clear the old SQx bits for the selected rank */ tmpreg1 &= ~tmpreg2; /* Calculate the mask to set */ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 7)); /* Set the SQx bits for the selected rank */ tmpreg1 |= tmpreg2; /* Store the new register value */ ADCx->SQR2 = tmpreg1; } /* For Rank 13 to 16 */ else { /* Get the old register value */ tmpreg1 = ADCx->SQR1; /* Calculate the mask to clear */ tmpreg2 = SQR1_SQ_Set << (5 * (Rank - 13)); /* Clear the old SQx bits for the selected rank */ tmpreg1 &= ~tmpreg2; /* Calculate the mask to set */ tmpreg2 = (uint32_t)ADC_Channel << (5 * (Rank - 13)); /* Set the SQx bits for the selected rank */ tmpreg1 |= tmpreg2; /* Store the new register value */ ADCx->SQR1 = tmpreg1; } }
Debug调试得:
ADC1->SMPR1 = 0x0000 0028;由SMPR1寄存器描述
可知,ADC1被配置为:采样时间为55.5个周期。
ADC1->SQR3 = 0x0000 000B;由SQR3寄存器描述
可知,ADC1被配置为:规则序列中的第1个转换。
ADC_DMACmd(ADC1, ENABLE); ADC_Cmd(ADC1, ENABLE);
使能ADC1的DMA模式、使能ADC1。
/*初始化校准寄存器 */ ADC_ResetCalibration(ADC1); /*等待校准寄存器初始化完成 */ while(ADC_GetResetCalibrationStatus(ADC1)); /* ADC校准 */ ADC_StartCalibration(ADC1); /* 等待校准完成*/ while(ADC_GetCalibrationStatus(ADC1));
注意:在开始ADC转换之前,建议对ADC进行校准,上面即为校准代码,限于篇幅不再详细介绍。
ADC_SoftwareStartConvCmd(ADC1, ENABLE);
ADC_SoftwareStartConvCmd()函数定义如下:
void ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_ADC_ALL_PERIPH(ADCx)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { /* Enable the selected ADC conversion on external event and start the selected ADC conversion */ ADCx->CR2 |= CR2_EXTTRIG_SWSTART_Set; } else { /* Disable the selected ADC conversion on external event and stop the selected ADC conversion */ ADCx->CR2 &= CR2_EXTTRIG_SWSTART_Reset; } }
即ADC1->CR2 = 0x005E 0103(这里的调试结果(0x001E 0103)我觉得有问题,前面是我自己的结果),再由CR2描述
可知,ADC1被配置为:使用外部触发信号启动转换、开始转换规则通道。
ADC_ConvertedValueLocal =(float) ADC_ConvertedValue/4096*3.3;
最后计算AD转换的结果,它是以参考电压值(这里是3.3V)为一个单位,即把3.3V等分成4096份来计算的。
注意:
ADC输入电压范围:VREF- <= VIN <= VREF+
VREF+电压范围: 2.4V <= VREF+ <= VDDA
VDDA电压范围: 2.4V <= VDDA <= VDD(3.6V)
故:ADC输入电压最高不超过3.6V。
到此为止,STM32的ADC功能就配置完成了,我们可以对从PC1脚输入的电压进行测量并通过串口或LCD来显示电压的具体数值(可测量电压范围:0 ~ 3.3V)。
由于作者学识有限,文中的错误及疏漏之处敬请读者批评指正。
原创作品