本文重点叙述如何使用单片机STM32F103RCT6的ADC外设进行电压采样并通过串口显示。
一、硬件连接
STM32F103RCT6共有三个ADC,本例中使用ADC1(对应数据手册中的ADC123)的通道1进行采样。ADC1的通道1对应的引脚为PA1。
注意:使用ADC采样时,必须要给ADC提供参考电压(即VREF),并且采样电压不可超过3.3V,如果待采样值超过3.3V或者过小,则需要是使用运放将其缩小或放大,为保证ADC被充分利用,待采样的最大值应接近3.3V,使得采样结果更为准确。
二、程序代码(HAL库)
“adc.h”文件
#ifndef __ADC_H
#define __ADC_H#include "./SYSTEM/sys/sys.h"
void adc_init(void); /* ADC初始化 */
u16 get_adc_result(u32 ch); /* 获得通道值 */
u16 get_adc_result_average(u32 ch, u8 times); /* 取平均值 */#endif
“adc.c”文件
#include "adc.h"
#include "./SYSTEM/delay/delay.h"ADC_HandleTypeDef ADC1_Handler;
/******************************* ADC初始化 ***********************************/
void adc_init()
{
RCC_PeriphCLKInitTypeDef ADC_CLKInit; /* 外设时钟初始化结构体 */
ADC_CLKInit.PeriphClockSelection = RCC_PERIPHCLK_ADC; /* 选择ADC时钟 */
ADC_CLKInit.AdcClockSelection = RCC_ADCPCLK2_DIV6; /* 选择ADC时钟分频系数 */
HAL_RCCEx_PeriphCLKConfig(&ADC_CLKInit); /* 选择ADC时钟源 */
ADC1_Handler.Instance = ADC1;
ADC1_Handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; /* 右对齐 */
ADC1_Handler.Init.ScanConvMode = DISABLE; /* 非扫描模式 */
ADC1_Handler.Init.ContinuousConvMode = DISABLE; /* 关闭连续转换 */
ADC1_Handler.Init.NbrOfConversion = 1; /* 1个转换在规则序列中 也就是只转换规则序列1 */
ADC1_Handler.Init.DiscontinuousConvMode = DISABLE; /* 禁止不连续采样模式 */
ADC1_Handler.Init.NbrOfDiscConversion = 0; /* 不连续采样通道数为0 */
ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;/* 软件触发 */
HAL_ADC_Init(&ADC1_Handler); /* 初始化 */
HAL_ADCEx_Calibration_Start(&ADC1_Handler); /* 启动校准 */
}/******************************* ADC底层驱动 ***********************************/
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_Initure;
__HAL_RCC_ADC1_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
GPIO_Initure.Pin = GPIO_PIN_1;
GPIO_Initure.Mode = GPIO_MODE_ANALOG;
GPIO_Initure.Pull = GPIO_NOPULL;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}/******************************* 获取ADC值 ***********************************/
u16 get_adc_result(u32 ch)
{
ADC_ChannelConfTypeDef ADC1_ChanConf;
ADC1_ChanConf.Channel = ch; /* 选择通道 */
ADC1_ChanConf.Rank = 1; /* 选择序列 */
ADC1_ChanConf.SamplingTime = ADC_SAMPLETIME_239CYCLES_5; /* 采样时间 */
HAL_ADC_ConfigChannel(&ADC1_Handler, &ADC1_ChanConf); /* 通道配置 */
HAL_ADC_Start(&ADC1_Handler); /* 开启ADC */
HAL_ADC_PollForConversion(&ADC1_Handler, 10); /* 轮询转换 */
return (u16) HAL_ADC_GetValue(&ADC1_Handler); /* 返回最近一次转换值 */
}/******************************* 获取平均值 ***********************************/
u16 get_adc_result_average(u32 ch, u8 times)
{
u32 temp_val = 0;
u8 t;
for(t=0;t<times;t++) /* 获取times次数据 */
{
temp_val += get_adc_result(ch);
delay_ms(5);
}
return temp_val/times; /* 返回平均值 */
}
“main.c”文件
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/ADC/adc.h"int main(void)
{
u16 adcx;
float temp;
HAL_Init();
Stm32_Clock_Init(RCC_PLL_MUL9);
delay_init(72);
uart_init(115200);
led_init();
adc_init();while(1)
{
printf("\r\nADC采样值为:");
adcx = get_adc_result_average(ADC_CHANNEL_1, 20); /* 获取通道1的转换值,20次取平均 */
printf("\r\n%u\r\n",adcx); /* 打印数据 */
temp=(float)adcx*(3.3/4096); /* 获取计算后的带小数的实际电压值,比如3.1111 */
printf("%f\r\n",temp); /* 打印数据 */
LED(1);
delay_ms(200);
LED(0);
delay_ms(200);
}
}