备注:此实验是根据正点原子视频所写。初学STM32,完全是用于自我记录,若有问题,麻烦指正。
实验目的:ADC1的通道5(PA5)进行单次转换
1.开启PA口时钟和ADC1时钟,设置PA1为模拟输入。
这其中需要用到回调函数:void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc)。进入定义去看,这是一个弱函数。笔者找到的答案在如下:关于HAL库中HAL_XX_Init 与HAL_XX_MspInit的问题https://blog.csdn.net/weixin_42717898/article/details/112346671?utm_medium=distribute.pc_aggpage_search_result.none-task-blog-2~aggregatepage~first_rank_ecpm_v1~rank_v31_ecpm-1-112346671.pc_agg_new_rank&utm_term=MspDeInit+MspInit+%E5%92%8C&spm=1000.2123.3001.4430
但还是没有理解何时使用HAL_PPP_MspDeInit函数。其具体代码如下:
//¿ªÆôPA¿ÚʱÖÓºÍADC1ʱÖÓ
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) //»Øµ÷º¯Êý
{
__HAL_RCC_GPIOA_CLK_ENABLE(); // ʹÄÜGPIOA
__HAL_RCC_ADC1_CLK_ENABLE(); //ʹÄÜADC1
GPIO_InitTypeDef GPIO_Initure; //¶¨Òå½á¹¹Ìå
GPIO_Initure.Mode=GPIO_MODE_ANALOG;
GPIO_Initure.Pin=GPIO_PIN_5;
GPIO_Initure.Pull=GPIO_NOPULL;
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
其中需要特别注意,此时GPIO_Initure.Mode=GPIO_MODE_ANALOG//模拟量,与此前做跑马灯的实验不同。
2.初始化ADC1,包括预分频系数等。
调用HAL_ADC_Init()函数。进入定义看, 有一个入口参数。则先定义一个结构体:ADC_HandleTypeDef adc_handler; 再进行参数初始化。又因为Init为结构体,再对其成员变量进行初始化。
ClockPrescaler:为分频系数,有2/4/6/8,F4不能超过36MHz。
ContinuousConvMode:开启连续转换模式或者单次转换模式。
DataAlign:数据对齐方式,左对齐或者右对齐。规则组可采用右对齐,不用移位,可直接读出。
DiscontinuousConvMode:不连续采样模式。
DMAContinuousRequests:开启DMA请求连续模式或者单独模式。
EOCSelection:是否开启EOC中断。
ExternalTrigConv:外部触发方式。
ExternalTrigConvEdge:外部触发边沿。
NbrOfConversion:规则序列中有多少个转换
NbrOfDiscConversion:不连续采样通道。
Resolution:分辨率,12/10/8/6位。位数越高,越精确。
ScanConvMode:扫描模式,对于多通道而言,此实验为单通道。
3.配置ADC通道序列。
需要用到HAL_ADC_ConfigChannel();函数。
HAL_StatusTypeDef HAL_ADC_ConfigChannel(ADC_HandleTypeDef* hadc, ADC_ChannelConfTypeDef* sConfig)
从定义可知,有两个入口参数。第一个入口参数已经定义过,进入定义,看第二个入口参数:
typedef struct
{
uint32_t Channel;
uint32_t Rank;
uint32_t SamplingTime;
uint32_t Offset;
}ADC_ChannelConfTypeDef;
Channel:ADC通道。
Rank:规则通道中第几个转换。
SamplingTime:采样时间。
Offset:对于注入通道而言的,此实验为规则通道。
单通道的转换时间公式为:Tconv = Sampling time + 12.5 cycles。
4.开启ADC1。
HAL_ADC_Statt();。
5.等待转换完成。
HAL_ADC_PollForConversion();。
6.读取转换结果。
HAL_ADC_GetValue();。
7.其完整代码如下:
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "key.h"
#include "lcd.h"
#include "sdram.h"
//1.¿ªÆôPA¿ÚʱÖÓºÍADC1ʱÖÓ
void HAL_ADC_MspDeInit(ADC_HandleTypeDef* hadc) //»Øµ÷º¯Êý
{
__HAL_RCC_GPIOA_CLK_ENABLE(); // ʹÄÜGPIOA
__HAL_RCC_ADC1_CLK_ENABLE(); //ʹÄÜADC1
GPIO_InitTypeDef GPIO_Initure; //¶¨Òå½á¹¹Ìå
GPIO_Initure.Mode=GPIO_MODE_ANALOG;
GPIO_Initure.Pin=GPIO_PIN_5;
GPIO_Initure.Pull=GPIO_NOPULL;
GPIO_Initure.Speed=GPIO_SPEED_FREQ_VERY_HIGH;
HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
//2.³õʼ»¯ADC1
ADC_HandleTypeDef adc_handler; //¶¨Òå½á¹¹Ìå
void MY_ADC_Init(void)
{
HAL_ADC_Init(&adc_handler);
//²ÎÊý³õʼ»¯
adc_handler.Instance=ADC1;
//InitΪ½á¹¹Ì壬¶ÔÆä³ÉÔ±±äÁ¿½øÐгõʼ»¯
adc_handler.Init.ClockPrescaler= ADC_CLOCK_SYNC_PCLK_DIV4 ;//ʱÖÓ·ÖƵϵÊý,F4²»Äܳ¬¹ý36MHz
adc_handler.Init.ContinuousConvMode= DISABLE;//Á¬Ðøת»»Ä£Ê½
adc_handler.Init.DataAlign= ADC_DATAALIGN_RIGHT ;//Êý¾Ý¶ÔÆë·½·¨£¬¹æÔò×é²ÉÓÃÓÒ¶ÔÆë
adc_handler.Init.DiscontinuousConvMode = DISABLE ;//²»Á¬Ðøת»»Ä£Ê½
adc_handler.Init.DMAContinuousRequests=DISABLE;
adc_handler.Init.EOCSelection=DISABLE;//ÊÇ·ñ¿ªÆôEOCÖжÏ
adc_handler.Init.ExternalTrigConv= ADC_SOFTWARE_START ;//Íⲿ´¥·¢·½Ê½ £¬´Ë´¦Ê¹ÓÃÈí¼þ´¥·¢·½Ê½
adc_handler.Init.ExternalTrigConvEdge= DISABLE ;//Íⲿ´¥·¢±ßÑØ
adc_handler.Init.NbrOfConversion= 1 ;//¹æÔòÐòÁÐת»»£¬Ö»ÐèÒª¶ÔPA5½øÐÐת»»
adc_handler.Init.NbrOfDiscConversion=0;
adc_handler.Init.Resolution= ADC_RESOLUTION_12B ;//·Ö±æÂÊ
adc_handler.Init.ScanConvMode= DISABLE;//ɨÃèģʽ£¬¶ÔÓÚ¶àͨµÀ¶øÑÔ£¬´Ë´¦Îªµ¥Í¨µÀ
}
//ÅäÖùæÔòͨµÀ£¬²¢»ñȡת»»½á¹û
u16 Get_Adc(u32 ch)
{
ADC_ChannelConfTypeDef channelConfig;//¶¨Òå½á¹¹Ìå
//½á¹¹Ìå±äÁ¿½øÐгõʼ»¯
channelConfig.Channel= ch;//ͨµÀ
channelConfig.Offset= 0; //Offset¶Ô×¢ÈëͨµÀ¶øÑÔ£¬´ËʵÑéΪ¹æÔòͨµÀ
channelConfig.Rank= 1; //ÐòÁкţ¬´ËʵÑéΪµ¥´Îת»»£¬ÉèÖÃΪ1
channelConfig.SamplingTime= ADC_SAMPLETIME_480CYCLES ; //ÉèÖòÉÑùʱ¼ä
HAL_ADC_ConfigChannel(&adc_handler,&channelConfig);
//¿ªÆôADC
HAL_ADC_Start(&adc_handler);
//µÈ´ýת»»
HAL_ADC_PollForConversion(&adc_handler,10);
//»ñÈ¡½á¹û
return HAL_ADC_GetValue(&adc_handler);
}
//ȡƽ¾ùÖµ
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);
}
}
8.提出问题。
a.HAL_XXX_MspDeInit函数的用法。
b.ADC的分频系数。
c.采样时间选哪个最好,为什么。