STM32f103 系列有 3 个 ADC,精度为 12 位,每个 ADC 最多有 18 个通道,包括 16 个外部通道和 2 个内部信号源。
ADC 的输入电压范围为: 0~3.3V
输入通道:
外部的 16 个通道在转换的时候又分为规则通道和注入通道,我们一般使用规则通道即可。
ADC 转换可以由ADC 控制寄存器 2: ADC_CR2 的 ADON 这个位来控制,写 1 的时候开始转换,写 0 的时候停止转换。还可以通过内部定时器触发和外部 IO 触发等触发源来触发AD转换。
ADC 输入时钟 ADC_CLK 由 PCLK2 经过分频产生,可以是 2/4/6/8 分频 ,分频后最大是 14M。一般我们设置 PCLK2=HCLK=72M ,那么6分频后最大就是12M。
ADC时钟周期就是 1/ADC_CLK。 采样周期最小是 1.5 个 时钟周期,也就是采样一次的最短时间。
ADC转换时间 = 采样时间 +12.5 个周期,即最短转换时间为14个周期。ADC时钟为12M的话最短的转换时间为 1.17us。
typedef struct
{
ADC_TypeDef *Instance; //寄存器基地址
ADC_InitTypeDef Init; //ADC初始化
DMA_HandleTypeDef *DMA_Handle; //DMA指针
HAL_LockTypeDef Lock; //互斥锁
__IO uint32_t State; //状态变量
__IO uint32_t ErrorCode; //保存错误代码的变量
}ADC_HandleTypeDef;
我们主要对ADC_InitTypeDef Init
进行初始化,这也是一个结构体。
typedef struct
{
uint32_t DataAlign; //数据对齐方式
uint32_t ScanConvMode; //是否使用扫描模式
uint32_t ContinuousConvMode; //单一/连续模式
uint32_t NbrOfConversion; //AD 转换通道数目
uint32_t DiscontinuousConvMode; //是否使用间断模式
uint32_t NbrOfDiscConversion; //间断模式中一个组的转换通道的数目
uint32_t ExternalTrigConv; //外部触发选择
}ADC_InitTypeDef;
typedef struct {
uint32_t Channel; //通道选择
uint32_t Rank; //转换顺序
uint32_t SamplingTime; //采样周期
}ADC_ChannelConfTypeDef;
void MX_ADC1_Init(void)
{
ADC_ChannelConfTypeDef sConfig = {0};//
//ADC1初始化
hadc1.Instance = ADC1;
hadc1.Init.ScanConvMode = ADC_SCAN_DISABLE;//单通道不使用扫描模式
hadc1.Init.ContinuousConvMode = ENABLE;//连续模式
hadc1.Init.DiscontinuousConvMode = DISABLE;
hadc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;//软件触发
hadc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;//数据右对齐
hadc1.Init.NbrOfConversion = 1;
//通道初始化
sConfig.Channel = ADC_CHANNEL_1;
sConfig.Rank = ADC_REGULAR_RANK_1;
sConfig.SamplingTime = ADC_SAMPLETIME_1CYCLE_5;
}
//ADC硬件初始化
void HAL_ADC_MspInit(ADC_HandleTypeDef* adcHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
/**ADC1 GPIO Configuration
PA1 ------> ADC1_IN1
*/
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_ANALOG;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
/* ADC1 interrupt Init */
HAL_NVIC_SetPriority(ADC1_2_IRQn, 0, 0);
HAL_NVIC_EnableIRQ(ADC1_2_IRQn);
}
#define user_main_printf(format, ...) printf( format "\r\n", ##__VA_ARGS__)
int fputc(int ch, FILE *f){
uint8_t temp[1] = {ch};
HAL_UART_Transmit(&huart1, temp, 1, 0xffff);
return ch;
}
/* USER CODE BEGIN PV */
uint16_t ADC_value; //AD转换值
float Real_value; //实际电压值
/* USER CODE END PV */
HAL_ADC_Start_IT(&hadc1);
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
ADC_value = HAL_ADC_GetValue(&hadc1);
}
while (1)
{
HAL_GPIO_TogglePin(GPIOA, GPIO_PIN_9);//指示AD转换正常完成
Real_value=(float)(ADC_value)/4096*3.3;//计算实际电压值4096=2^12
user_main_printf("The ADC_value is %d",ADC_value);
user_main_printf("The Real_value is %f\n\n",Real_value);
user_main_printf(" ");
HAL_Delay(500);
}
至此程序就完成了,连接好USB转串口模块。首先将ADC1转换通道1,即PA1与3.3V电压相连,然后拔掉3.3V供电,将PA0悬空,此时电压为1.6V左右