ADC实验
对应实验名称:LTDC LCD(RGB屏)实验
笔记基于正点原子官方视频
视频连接https://www.bilibili.com/video/BV1Wx411d7wT?p=71&spm_id_from=333.1007.top_right_bar_window_history.content.click
如有侵权,联系删除
一、实验准备
1.实验目的
ADC1的通道5(采集PA5口电压)进行单次转化
2.实验步骤
① 开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
② 初始化ADC1,包括预分频系数,对齐方式,分辨率等
HAL_ADC_Init();
③ 配置ADC规则通道序列。
HAL_ADC_ConfigChannel();
④开启ADC1。
HAL_ADC_Start();
⑤ 等待转换完成
HAL_ADC_PollForConversion();
⑥读取转换结果:
HAL_ADC_GetValue();
二、实验具体步骤
1.引入相关文件
添加完成后再次编译文件
2.开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
__HAL_RCC_GPIOA_CLK_ENABLE(); //开启GPIOA时钟
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟
编写回调函数
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_Initure; //定义GPIO结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
GPIO_Initure.Pin=GPIO_PIN_5; //PB5
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟模式
GPIO_Initure.Pull=GPIO_NOPULL; //不进行上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
3.初始化ADC1,包括预分频系数,对齐方式,分辨率等
查看HAL_ADC_Init()定义如下:
其内部变量为一个结构体变量
我们这里需要定义一个结构体指针来指向结构体内部的成员变量
ADC_HandleTypeDef adc_handler;
void MY_ADC1_Init(void)
{
HAL_ADC_Init(&adc_handler);
}
下面配置ADC初始化的成员变量,如下:
ADC_HandleTypeDef adc_handler;
void MY_ADC_Init(void)
{
adc_handler.Instance = ADC1;
adc_handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //时钟分频系数,选择4分频,108Mhz/4=27Mhz
adc_handler.Init.ContinuousConvMode = DISABLE; //连续转换模式,不开启
adc_handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据对齐方式,右对齐
adc_handler.Init.DiscontinuousConvMode = DISABLE; //不连续转换模式,不开启
adc_handler.Init.DMAContinuousRequests = DISABLE; //DMA这里没有用到
adc_handler.Init.EOCSelection = DISABLE; //是否开启EOC中断
adc_handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //外部触发方式,选择软件触发
adc_handler.Init.NbrOfConversion = 1; //配置转换通道
adc_handler.Init.NbrOfDiscConversion = 0;
adc_handler.Init.Resolution = ADC_RESOLUTION_12B; //分辨率12位
adc_handler.Init.ScanConvMode = DISABLE; //扫面模式,没有用到,关闭
HAL_ADC_Init(&adc_handler);
}
4.配置ADC规则通道序列(一个通道,单次转换)
HAL_ADC_ConfigChannel();
u16 Get_Adc(u32 ch) //配置规则通道,并获取其转换结果
{
ADC_ChannelConfTypeDef channalConfig; //定义通道结构体指针
channalConfig.Channel = ch; //通道赋值
channalConfig.Rank = 1; //序列
channalConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间,480个时钟周期
channalConfig.Offset = 0;
HAL_ADC_ConfigChannel(&adc_handler,&channalConfig);
}
5.开启ADC1、等待转换完成、读取转换结果
开启ADC1
HAL_ADC_Start();
等待转换完成
HAL_ADC_PollForConversion();
读取转换结果
HAL_ADC_GetValue();
u16 Get_Adc(u32 ch) //配置规则通道,并获取其转换结果
{
ADC_ChannelConfTypeDef channalConfig; //定义通道结构体指针
channalConfig.Channel = ch; //通道赋值
channalConfig.Rank = 1; //序列
channalConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间,480个时钟周期
channalConfig.Offset = 0;
HAL_ADC_ConfigChannel(&adc_handler,&channalConfig);
HAL_ADC_Start(&adc_handler); //开启ADC
HAL_ADC_PollForConversion(&adc_handler,10); //等待转换完成,等待时间10个时钟周期
return HAL_ADC_GetValue(&adc_handler); //获取转换结果,并返回给ch
}
6.多次采集取平均值
u16 Get_Adc_Average(u32 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
7.main函数编写
主要是调用ADC1通道5,编写液晶显示程序,和对ADC采集到的具体数值进行转换然后显示
8.至此所有函数编写完毕,main.c代码如下
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
ADC_HandleTypeDef adc_handler;
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
GPIO_InitTypeDef GPIO_Initure; //定义GPIO结构体
__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟
__HAL_RCC_ADC1_CLK_ENABLE(); //使能ADC1时钟
GPIO_Initure.Pin=GPIO_PIN_5; //PB5
GPIO_Initure.Mode=GPIO_MODE_ANALOG; //模拟模式
GPIO_Initure.Pull=GPIO_NOPULL; //不进行上下拉
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
void MY_ADC_Init(void)
{
adc_handler.Instance = ADC1;
adc_handler.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4; //时钟分频系数,选择4分频,108Mhz/4=27Mhz
adc_handler.Init.ContinuousConvMode = DISABLE; //连续转换模式,不开启
adc_handler.Init.DataAlign = ADC_DATAALIGN_RIGHT; //数据对齐方式,右对齐
adc_handler.Init.DiscontinuousConvMode = DISABLE; //不连续转换模式,不开启
adc_handler.Init.DMAContinuousRequests = DISABLE; //DMA这里没有用到
adc_handler.Init.EOCSelection = DISABLE; //是否开启EOC中断
adc_handler.Init.ExternalTrigConv = ADC_SOFTWARE_START; //外部触发方式,选择软件触发
adc_handler.Init.NbrOfConversion = 1; //配置转换通道
adc_handler.Init.NbrOfDiscConversion = 0;
adc_handler.Init.Resolution = ADC_RESOLUTION_12B; //分辨率12位
adc_handler.Init.ScanConvMode = DISABLE; //扫面模式,没有用到,关闭
HAL_ADC_Init(&adc_handler);
}
u16 Get_Adc(u32 ch) //配置规则通道,并获取其转换结果
{
ADC_ChannelConfTypeDef channalConfig; //定义通道结构体指针
channalConfig.Channel = ch; //通道赋值
channalConfig.Rank = 1; //序列
channalConfig.SamplingTime = ADC_SAMPLETIME_480CYCLES; //采样时间,480个时钟周期
channalConfig.Offset = 0;
HAL_ADC_ConfigChannel(&adc_handler,&channalConfig);
HAL_ADC_Start(&adc_handler); //开启ADC
HAL_ADC_PollForConversion(&adc_handler,10); //等待转换完成,等待时间10个时钟周期
return HAL_ADC_GetValue(&adc_handler); //获取转换结果,并返回给ch
}
//获取指定通道的转换值,取times次,然后取平均
//times:获取次数
//返回值:通道ch的times次转换结果平均值
u16 Get_Adc_Average(u32 ch,u8 times)
{
u32 temp_val=0;
u8 t;
for(t=0;t<times;t++)
{
temp_val+=Get_Adc(ch);
delay_ms(5);
}
return temp_val/times;
}
int main(void)
{
u16 adcx;
float temp;
HAL_Init(); //初始化HAL库
Stm32_Clock_Init(360,25,2,8); //设置时钟,180Mhz
delay_init(180); //初始化延时函数
uart_init(115200); //初始化USART
LED_Init(); //初始化LED
KEY_Init(); //初始化按键
SDRAM_Init(); //初始化SDRAM
LCD_Init(); //初始化LCD
MY_ADC_Init(); //初始化ADC1通道5
POINT_COLOR=RED;
LCD_ShowString(30,50,200,16,16,"Apollo STM32F4/F7");
LCD_ShowString(30,70,200,16,16,"ADC TEST");
LCD_ShowString(30,90,200,16,16,"ATOM@ALIENTEK");
LCD_ShowString(30,110,200,16,16,"2016/1/13");
POINT_COLOR=BLUE; //设置字体为蓝色
LCD_ShowString(30,130,200,16,16,"ADC1_CH5_VAL:");
LCD_ShowString(30,150,200,16,16,"ADC1_CH5_VOL:0.000V"); //先在固定位置显示小数点
while(1)
{
adcx=Get_Adc_Average(ADC_CHANNEL_5,20); //获取通道5的转换值,20次取平均
LCD_ShowxNum(134,130,adcx,4,16,0); //显示ADCC采样后的原始值
temp=(float)adcx*(3.3/4096); //获取计算后的带小数的实际电压值,比如3.1111
adcx=temp; //赋值整数部分给adcx变量,因为adcx为u16整形
LCD_ShowxNum(134,150,adcx,1,16,0); //显示电压值的整数部分,3.1111的话,这里就是显示3
temp-=adcx; //把已经显示的整数部分去掉,留下小数部分,比如3.1111-3=0.1111
temp*=1000; //小数部分乘以1000,例如:0.1111就转换为111.1,相当于保留三位小数。
LCD_ShowxNum(150,150,temp,3,16,0X80); //显示小数部分(前面转换为了整形显示),这里显示的就是111.
LED0=!LED0;
delay_ms(250);
}
}
实验现象如下: