一、添加ADC外设到项目中(省略)
二、阅读ADC外设的头文件
在STM32中库编程中所有的外设的功能设置都是以结构体来组织的,ADC的结构体只有1个,如下:
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;
其中第一个是ADC_Mode,他的取值集合如下:
/** @defgroup ADC_mode
* @{
*/
#define ADC_Mode_Independent ((uint32_t)0x00000000)
#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)
#define IS_ADC_MODE(MODE) (((MODE) == ADC_Mode_Independent) || \\
((MODE) == ADC_Mode_RegInjecSimult) || \\
((MODE) == ADC_Mode_RegSimult_AlterTrig) || \\
((MODE) == ADC_Mode_InjecSimult_FastInterl) || \\
((MODE) == ADC_Mode_InjecSimult_SlowInterl) || \\
((MODE) == ADC_Mode_InjecSimult) || \\
((MODE) == ADC_Mode_RegSimult) || \\
((MODE) == ADC_Mode_FastInterl) || \\
((MODE) == ADC_Mode_SlowInterl) || \\
((MODE) == ADC_Mode_AlterTrig))
/**
* @}
*/
其中ADC_Mode_Independent这些都是什么意思呢?我们不清楚,但我们知道这个结构体是在ADC初始化函数中要用到的,那我们就去初始化函数中看看:
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;
}
这个函数的作用就是根据ADC初始化结构体的成员值去设置ADC相关寄存器,我们可以看到ADC_mode这个成员变量所在的语句是以下几行代码:
/*---------------------------- 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;
这几句代码的作用是:
1、先读出CR1寄存器的值,然后和我们要设置的值做与或者或运算,然后把运算之后的值重新赋值给CR1寄存器,我们返回去看ADC_mode可以选择的值:
#define ADC_Mode_Independent ((uint32_t)0x00000000)
#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_mode中每种模式的值都是从第17位开始的,结合以上追溯出的ADC_mode的设置最终是设置CR1寄存器,可以知道ADC_mode设置的其实是CR1寄存器的第16位和十六位以后的值,那么我们打开《STM32参考手册》第171页,可以看到CR1寄存器的解释:
从这个简介中很明显可以看出CR1寄存器的16-19四个位是DUALMOD[3:0],然后看下面对这三个位的注释为:
也就是说是用来选择这些模式的,这就和代码一一对应起来了(我给添加了注释如下):
#define ADC_Mode_Independent ((uint32_t)0x00000000)//独立模式
#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初始化结构体的ADC_Mode这个结构体成员变量了。
对于其他的结构体成员变量设置也是同样的,追溯到源头,你就会看到他的具体作用,然后根据你的需求进行设置。
三、代码编写(省略)
明白了以上的原理,就可以根据自己的需求进行设置了。
四、题外话(关于markdown编辑的使用,以代码框实现为例)
在写这篇文章的时候,是我第一次使用插入代码,搞不懂他们写的文章代码框是怎么加的,在网上搜了之后看到说是三个、、、,然后我就各种尝试,结果发现这三个点是怎么敲出来的呢,普通键盘的ESC下面不是有一个波浪线的键吗,在英文输入法下敲出来的就是我们要的`,连敲三个,代码前面三个后面三个,编辑完就是你说看到的代码框:
这是在markdown编辑模式下实现的,所以在实现这样的标签语言前首先要在设置里把编辑模式的富文本模式切换为markdown模式,切换设置见下图:
设置好之后,页面下拉到最下面会有个保存按钮,保存之后新建文章就可以使用标记语言了,包括图片添加,标题设置都是用标记语言实现的,非常简单使用,关于markdown的详细介绍见下面链接:
http://www.jianshu.com/p/1e402922ee32/
喜欢请关注公众号"电子开发学习"