关乎STM32,在使用官方库的情况下,你想要的各种功能的配置,无非就是你对于相应外设的每个参数的设置 STM32的库函数,相关的一些参数,参数有效值,都可以在相关库文件** .c / .h **看到详细解释,就以ADC的初始化函数 ADC_Init 为例 其中,有很多代码,但是,真正配置能用到的无非就是 assert_param 这个函数的那些,至于这个函数是什么,也不重要,你只需要了解到里面的参数就是你需要配置的那些功能。 在官方库函数,前面有几句注释 这就不得不提到C语言的精髓, 结构体 & 指针! 至于结构体,我自己的理解就是,他就是一个特殊的数组,只不过这个数组的成员之间的数据长度可能不太一样长,但是用法还有一些其他的东西,完全和数组类似,具体的解释,我会重新开一个博客来具体介绍,这里就先谈到这里。 简而言之,就是,你需要先定义一个保存很多数据的数据类型,来将你的对于这个ADC的使用功能告诉给这函数,然后,他来一条一条分析你这个数据类型的每个数据,当然,你也可以把这些参数一个一个的加在库函数的输入参数里面,比如说ADC_Mode,ADC_ScanConvMode,ADC_ContinuousConvMode,ADC_ExternalTrigConv,ADC_DataAlign,ADC_NbrOfChannel assert_param(IS_ADC_MODE(ADC_InitStruct->ADC_Mode)); 至于说这个保存很多数据的数据类型,在库里面,人家也很贴心的给你准备了(.h文件) 所以,一切的一切,在库函数你都可以找到相关的说明,接下来,你就会问了,那这些参数,我要怎么配置,才会让程序来识别我想要的功能,Look down: #define ADC_Mode_Independent ((uint32_t)0x00000000) OK,介绍了这么多,咱们开始步入正题: 图中可以看到,ADC12_IN10在PC0引脚,ADC12_IN11在PC1引脚.。。。 以ADC12_IN10 / ADC12_IN11 / ADC12_IN12 / ADC12_IN13为例 至于具体每个参数的作用,可以参考这个博文:STM32之ADC配置,ADC_Mode模式理解 这个建议做一个全局变量,以方便被其他文件调取使用 STM32共有两个DMA控制器,其中DMA1共有7个通道,DMA2有5个通道,在参考手册中DMA章节有具体说明
序
库函数介绍
/ ** * @brief根据ADC_InitStruct中的指定参数 * 初始化ADCx外设。 * @param ADCx:其中x可以是1、2或3以选择ADC外设。 * @param ADC_InitStruct:指向ADC_InitTypeDef结构的指针,该结构包含 * 指定ADC外设的配置信息。 * * @retval无 * * / ADC_Init ( ADC_TypeDef * ADCx , ADC_InitTypeDef * ADC_InitStruct ){ uint32_t tmpreg1 = 0 ; uint8_t tmpreg2 = 0 ; / *检查参数* / 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配置----------------- * / / *获取使用ADCx CR1值* / tmpreg1 = ADCx - > CR1 ; / *清除DUALMOD和SCAN位* / tmpreg1 &==CR1_CLEAR_Mask ; / *配置ADCx:双模式和扫描转换模式* / / *根据ADC_Mode值设置DUALMOD位* / / *根据ADC_ScanConvMode值设置SCAN位* / tmpreg1 | = ( uint32_t )( ADC_InitStruct- > ADC_Mode | (( uint32_t ) ADC_InitStruct- > ADC_ScanConvMode << 8 )); / *写入ADCx CR1 * / ADCx - > CR1 = tmpreg1 ; / * ---------------------------- ADCx CR2配置----------------- * / / *获取使用ADCx CR2值* / tmpreg1 = ADCx - > CR2 ; / *清除CONT,ALIGN和EXTSEL位* / tmpreg1 &= CR2_CLEAR_Mask ; / *配置ADCx:外部触发事件和连续转换模式* / / *根据ADC_DataAlign值设置ALIGN位* / / *根据ADC_ExternalTrigConv值设置EXTSEL位* / / *根据ADC_ContinuousConvMode值设置CONT位* / tmpreg1 | = ( uint32_t )( ADC_InitStruct- > ADC_DataAlign | ADC_InitStruct- > ADC_ExternalTrigConv | (( uint32_t ) ADC_InitStruct- > ADC_ContinuousConvMode << 1 )); / *写入ADCx CR2 * / ADCx - > CR2 = tmpreg1 ; / * ---------------------------- ADCx SQR1配置----------------- * / / *获取使用ADCx SQR1值* / tmpreg1 = ADCx - > SQR1 ; / *清除L位* / 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 ; / *写入ADCx SQR1 * / ADCx - > SQR1 = tmpreg1 ; }
什么意思呢?
这个函数有两个参数,其中ADCx的意思是,你需要配置哪个ADC,比如:ADC1 或者 ADC2 ADC3;而ADC_InitStruct的意思是,你需要将外设的功能定义以ADC_InitTypeDef类型的结构体指针的方式传递过去。
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));typedef struct { uint32_t ADC_Mode; /*!< Configures the ADC to operate in independent or dual mode. This parameter can be a value of @ref ADC_mode */ FunctionalState ADC_ScanConvMode; /*!< Specifies whether the conversion is performed in Scan (multichannels) or Single (one channel) mode. This parameter can be set to ENABLE or DISABLE */ FunctionalState ADC_ContinuousConvMode; /*!< Specifies whether the conversion is performed in Continuous or Single mode. This parameter can be set to ENABLE or DISABLE. */ uint32_t ADC_ExternalTrigConv; /*!< Defines the external trigger used to start the analog to digital conversion of regular channels. This parameter can be a value of @ref ADC_external_trigger_sources_for_regular_channels_conversion */ uint32_t ADC_DataAlign; /*!< Specifies whether the ADC data alignment is left or right. This parameter can be a value of @ref ADC_data_align */ uint8_t ADC_NbrOfChannel; /*!< Specifies the number of ADC channels that will be converted using the sequencer for regular channel group. This parameter must range from 1 to 16. */ }ADC_InitTypeDef;
这时候,你只需要在.h文件里面继续往下翻就会看到
#define ADC_Mode_RegInjecSimult ((uint32_t)0x00010000)
#define ADC_Mode_RegSimult_AlterTrig ((uint32_t)0x00020000)
#define ADC_Mode_InjecSimult_FastInterl ((uint32_t)0x00030000)
#define ADC_Mode_InjecSimult_SlowInterl ((uint32_t)0x00040000)
#define ADC_Mode_InjecSimult ((uint32_t)0x00050000)
#define ADC_Mode_RegSimult ((uint32_t)0x00060000)
#define ADC_Mode_FastInterl ((uint32_t)0x00070000)
#define ADC_Mode_SlowInterl ((uint32_t)0x00080000)
#define ADC_Mode_AlterTrig((uint32_t)0x00090000)
……初始化函数配置
首先,你得知道你要使用的是哪个ADC引脚?至于引脚配置,在官方的芯片手册中第三节的引脚功能定义中找到。
其次,将你需要使用的引脚进行初始化,记得把引脚配置为 模拟输入(GPIO_Mode_AIN)
void GPIOC_Init(){ //GPIO引脚初始化 GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC, ENABLE); //使能外设时钟 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 | GPIO_Pin_3; //端口配置 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //输出模式配置,模拟输入 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz GPIO_Init(GPIOC, &GPIO_InitStructure); //根据设定参数初始化GPIOC }
然后,就是对你所需要的ADC功能的配置了
Void ADC1_Init(){ //ADC1初始化 ADC_InitTypeDef ADC_InitStructure; RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE); //使能外设时钟 RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC的分频因子,APB2的6分频 72M/6 = 12M,如果ADC频率超过12MHz,可能导致采样值误差 ADC_DeInit(ADC1); //设置ADC1为默认值 ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //独立模式,此模式表示只是单独使用ADC1,不与ADC2进行联合使用 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数据右对齐 ADC_InitStructure.ADC_NbrOfChannel = 4; //顺序进行转换的ADC通道的数目 ADC_Init(ADC1, &ADC_InitStructure); ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 1, ADC_SampleTime_55Cycles5 ); //ADC规则通道配置 ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 2, ADC_SampleTime_55Cycles5 ); //ADC规则通道配置 ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5 ); //ADC规则通道配置 ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5 ); //ADC规则通道配置 ADC_Cmd(ADC1, ENABLE); //使能ADC1 ADC_ResetCalibration(ADC1); //使能复位校准 while(ADC_GetResetCalibrationStatus(ADC1)); //等待ADC校准结束 ADC_StartCalibration(ADC1); //开启AD校准 while(ADC_GetCalibrationStatus(ADC1)); //等待AD校准结束 ADC_SoftwareStartConvCmd(ADC1, ENABLE); //进行一次采集 /* 等待转换结束 */ while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC)); }
OK,完成了ADC配置,你还需要创建一个数组,以保证ADC采集到的数据可以有存储的地方
/* 转换值 */ unsigned int adc_data[4];
你已经有了采集的接口,存放采集数据的地方,最后,你要做的就是为他们两者之间建立一个通道,这就是DMA存在的意义
这次我们使用的是ADC1的传输,所以,需要选择DMA1的通道1void DMA1_Init(void) { DMA_InitTypeDef DMA_InitStruct; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA外设时钟 DMA_DeInit(DMA1_Channel1); /将DMA1通道1重设为默认值 DMA_InitStruct.DMA_PeripheralBaseAddr = (uint32_t)&ADC1->DR;//外设基地址 DMA_InitStruct.DMA_MemoryBaseAddr = (uint32_t)&adc_data;//存储器基地址 DMA_InitStruct.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向 外设到存储器 DMA_InitStruct.DMA_BufferSize = 4; //通道传输数据量 DMA_InitStruct.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //不开启外设增量模式 DMA_InitStruct.DMA_MemoryInc = DMA_MemoryInc_Enable; //开启储存器地址增量模式 DMA_InitStruct.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据长度(16位) DMA_InitStruct.DMA_MemoryDataSize = DMA_PeripheralDataSize_HalfWord; //存储器数据长度 DMA_InitStruct.DMA_Mode = DMA_Mode_Normal; //传输是否循环 不循环 DMA_InitStruct.DMA_Priority = DMA_Priority_Medium; //DMA优先级 中等 DMA_InitStruct.DMA_M2M = DMA_M2M_Disable; //是否存储器到存储器方式 不是 DMA_Init(DMA_CHx, &DMA_InitStruct); DMA_Cmd(DMA1_Channel1, ENABLE); //使能DMA1的通道1传输 }
最后的最后,就是搞一个main函数,将各种初始化集合在一起使用
int main(void) { GPIOC_Init(); //GPIO配置 DMA1_Init(); //DMA1配置 ADC1_Init(); //ADC1配置 while(1) { …… } }
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算