STM32F4 (hal库)ADC+TIM1+DAC的配置

写在前面:感谢XXX大佬的指导,点击可查看他的博客

实现的功能:

用定时器TIM产生PWM波来控制ADC的采样频率,在ADC中断中将采样值直接通过DAC输出。本文主要展示ADC、TIM、DAC的配置(hal库)
主要的困难是通过定时器TIM触发ADC采样的配置比较复杂,定时器的配置还没太懂

ADC的配置

ADC_HandleTypeDef ADC1_Handler;//ADC句柄
ADC_ChannelConfTypeDef ADC1_ChanConf;

//初始化ADC
//ch: ADC_channels 
//通道值 0~16取值范围为:ADC_CHANNEL_0~ADC_CHANNEL_16
void MY_ADC_Init(void)
{ 
    ADC1_Handler.Instance=ADC1;
    ADC1_Handler.Init.ClockPrescaler=ADC_CLOCK_SYNC_PCLK_DIV4;   //4分频,ADCCLK=PCLK2/4=90/4=22.5MHZ ,不使用软件触发而使用外部触发时,ADC时钟不影响采样率
    ADC1_Handler.Init.Resolution=ADC_RESOLUTION_12B;             //12位模式
    ADC1_Handler.Init.DataAlign=ADC_DATAALIGN_RIGHT;             //右对齐
    ADC1_Handler.Init.ScanConvMode=DISABLE;                      //非扫描模式; 
    ADC1_Handler.Init.EOCSelection=ADC_EOC_SINGLE_CONV;          //DISABLE--关闭EOC中断
    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_EXTERNALTRIGCONV_T1_CC1;//外部触发方式;使用定时器TIM产生PWM来触发ADC采样,PWM波的频率就是这种模式下的采样频率
    ADC1_Handler.Init.ExternalTrigConvEdge=ADC_EXTERNALTRIGCONVEDGE_RISING;//外部边沿触发
//  ADC1_Handler.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;//使用软件触发
//  ADC1_Handler.Init.ExternalTrigConv = ADC_SOFTWARE_START;//软件触发
    ADC1_Handler.Init.DMAContinuousRequests=DISABLE;             //关闭DMA请求
    HAL_ADC_Init(&ADC1_Handler);                                 //初始化 
	    
    ADC1_ChanConf.Channel=ADC_CHANNEL_5;                                   //通道5
    ADC1_ChanConf.Rank=1;                                       //第1个序列,序列1
    ADC1_ChanConf.SamplingTime=ADC_SAMPLETIME_3CYCLES;        //采样时间;这个越小,单次采样(ADC转换)时间越短,但精度可能受影响
    ADC1_ChanConf.Offset=0;                 
    HAL_ADC_ConfigChannel(&ADC1_Handler,&ADC1_ChanConf);        //通道配置
		
	HAL_NVIC_SetPriority(ADC_IRQn,0,0);		//配置ADC中断的优先级
	HAL_NVIC_EnableIRQ(ADC_IRQn);          //开启ADC中断   
			
	HAL_ADC_Start_IT(&ADC1_Handler);	 //允许中断并启动常规通道的ADC转换
}

//ADC底层驱动,引脚配置,时钟使能
//此函数会被HAL_ADC_Init()调用
//hadc:ADC句柄
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_ADC1_CLK_ENABLE();            //使能ADC1时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
	
    GPIO_Initure.Pin=GPIO_PIN_5;            //PA5
    GPIO_Initure.Mode=GPIO_MODE_ANALOG;     //模拟
    GPIO_Initure.Pull=GPIO_NOPULL;          //不带上下拉
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}
//ADC中断服务函数
void ADC_IRQHandler(void)
{
	HAL_ADC_IRQHandler(&ADC1_Handler);
}
// ADC常规转换完全回调函数,就是ADC采一个值就进入这个函数一次
 void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
  	//将ADC采的值直接通过DAC输出
  	HAL_DAC_SetValue(&DAC1_Handler,DAC_CHANNEL_1,DAC_ALIGN_12B_R,HAL_ADC_GetValue(&ADC1_Handler));//12位右对齐数据格式设置DAC值
}

TIM配置

TIM_HandleTypeDef TIM1_Handler;      	//定时器句柄 
TIM_OC_InitTypeDef TIM1_CH1Handler;		//定时器1通道1句柄
//这个暂时不知道
TIM_MasterConfigTypeDef sMasterConfig;	

//TIM14 PWM部分初始化 
//arr:自动重装值。
//psc:时钟预分频数
//定时器溢出时间计算方法:Tout=((arr+1)*(psc+1))/Ft us.
//Ft=定时器工作频率,单位:Mhz  
void TIM1_PWM_Init(u16 arr,u16 psc)
{  
    TIM1_Handler.Instance=TIM1;          	//定时器1
    TIM1_Handler.Init.Prescaler=psc;       //定时器分频
    TIM1_Handler.Init.CounterMode=TIM_COUNTERMODE_UP;//向上计数模式
    TIM1_Handler.Init.Period=arr;          //自动重装载值
    TIM1_Handler.Init.ClockDivision=TIM_CLOCKDIVISION_DIV1;
    HAL_TIM_PWM_Init(&TIM1_Handler);       //初始化PWM
	
	//这个很重要,还没懂
   	sMasterConfig.MasterOutputTrigger = TIM_TRGO_UPDATE;// 主模式选择。选择具体模式发送到TRG0上。
   	sMasterConfig.MasterSlaveMode = TIM_MASTERSLAVEMODE_DISABLE;//主定时器的从模式使能与失能位
    
    TIM1_CH1Handler.OCMode=TIM_OCMODE_PWM1; //模式选择PWM1
    TIM1_CH1Handler.Pulse=arr/2;            //设置比较值,此值用来确定占空比,默认比较值为自动重装载值的一半,即占空比为50%
    TIM1_CH1Handler.OCPolarity=TIM_OCPOLARITY_LOW; //输出比较极性为低 
    HAL_TIM_PWM_ConfigChannel(&TIM1_Handler,&TIM1_CH1Handler,TIM_CHANNEL_1);//配置TIM1通道1
	
    HAL_TIM_PWM_Start(&TIM1_Handler,TIM_CHANNEL_1);//开启PWM通道1	
}

//定时器底层驱动,时钟使能,引脚配置
//此函数会被HAL_TIM_PWM_Init()调用
//htim:定时器句柄
void HAL_TIM_PWM_MspInit(TIM_HandleTypeDef *htim)
{
	GPIO_InitTypeDef GPIO_Initure;
	__HAL_RCC_TIM1_CLK_ENABLE();			//使能定时器1
	__HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
	
	GPIO_Initure.Pin=GPIO_PIN_8;           	//PA8 
	//配置完成后可在该引脚观察到PWM波,波的频率就是ADC的采样频率
	GPIO_Initure.Mode=GPIO_MODE_AF_PP;  	//复用推挽输出
	GPIO_Initure.Pull=GPIO_PULLUP;          //上拉
	GPIO_Initure.Speed=GPIO_SPEED_HIGH;     //高速
	GPIO_Initure.Alternate= GPIO_AF1_TIM1;	//PA8复用为TIM1_CH1
	HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}

TIM系统时钟频率

系统时钟设置(正点原子STM32F4例程的sys.c为例)

    RCC_OscInitStructure.OscillatorType=RCC_OSCILLATORTYPE_HSE;    //时钟源为HSE

选择时钟源为HSE;HSE 是高速外部时钟,开发板接的是 8M 的晶振

    RCC_OscInitStructure.PLL.PLLM=pllm; //主PLL和音频PLL分频系数(PLL之前的分频),取值范围:2~63.
    RCC_OscInitStructure.PLL.PLLN=plln; //主PLL倍频系数(PLL倍频),取值范围:64~432.  
    RCC_OscInitStructure.PLL.PLLP=pllp; //系统时钟的主PLL分频系数(PLL之后的分频),取值范围:2,4,6,8.(仅限这4个值!)
    //下面这个暂时用不上
    RCC_OscInitStructure.PLL.PLLQ=pllq; //USB/SDIO/随机数产生器等的主PLL分频系数(PLL之后的分频),取值范围:2~15.

当pllm=8,plln=336,pllp=2
系统时钟频率SYSCLK=8 / pllm * plln / pllp=8 / 8 * 336 / 2 =168 MHz

    //选中PLL作为系统时钟源并且配置HCLK,PCLK1和PCLK2
    RCC_ClkInitStructure.ClockType=(RCC_CLOCKTYPE_SYSCLK|RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2);
    RCC_ClkInitStructure.SYSCLKSource=RCC_SYSCLKSOURCE_PLLCLK;//设置系统时钟时钟源为PLL
    RCC_ClkInitStructure.AHBCLKDivider=RCC_SYSCLK_DIV1;//AHB分频系数为1
    RCC_ClkInitStructure.APB1CLKDivider=RCC_HCLK_DIV4; //APB1分频系数为4
    RCC_ClkInitStructure.APB2CLKDivider=RCC_HCLK_DIV2; //APB2分频系数为2
    ret=HAL_RCC_ClockConfig(&RCC_ClkInitStructure,FLASH_LATENCY_5);//同时设置FLASH延时周期为5WS,也就是6个CPU周期。

HCLK = SYSCLK = 168 MHz ;
PCLK1 = SYSCLK / 4 = 42 MHz ; APB1分频系数为4
PCLK2 = SYSCLK / 2 = 86 MHz ; APB2分频系数为2

定时器TIM1由APB2的输出产生
当APB1和APB2的分频系数不为1时,时钟到定时器间会经过一个倍频器
即 定时器TIM1的工作频率:TIM1_CLK = PCLK2 * 2 = 168 MHz

可参考

http://www.elecfans.com/d/760770.html

DAC配置

DAC_HandleTypeDef DAC1_Handler;//DAC句柄

//初始化DAC
void DAC1_Init(void)
{
    DAC_ChannelConfTypeDef DACCH1_Config;
    
    DAC1_Handler.Instance=DAC;
    HAL_DAC_Init(&DAC1_Handler);                 //初始化DAC
    
    DACCH1_Config.DAC_Trigger=DAC_TRIGGER_NONE;             //不使用触发功能
    DACCH1_Config.DAC_OutputBuffer=DAC_OUTPUTBUFFER_DISABLE;//DAC1输出缓冲关闭
    HAL_DAC_ConfigChannel(&DAC1_Handler,&DACCH1_Config,DAC_CHANNEL_1);//DAC通道1配置
    
    HAL_DAC_Start(&DAC1_Handler,DAC_CHANNEL_1);  //开启DAC通道1
}

//DAC底层驱动,时钟配置,引脚 配置
//此函数会被HAL_DAC_Init()调用
//hdac:DAC句柄
void HAL_DAC_MspInit(DAC_HandleTypeDef* hdac)
{      
    GPIO_InitTypeDef GPIO_Initure;
    __HAL_RCC_DAC_CLK_ENABLE();             //使能DAC时钟
    __HAL_RCC_GPIOA_CLK_ENABLE();			//开启GPIOA时钟
	
    GPIO_Initure.Pin=GPIO_PIN_4;            //PA4
    GPIO_Initure.Mode=GPIO_MODE_ANALOG;     //模拟
    GPIO_Initure.Pull=GPIO_NOPULL;          //不带上下拉
    HAL_GPIO_Init(GPIOA,&GPIO_Initure);
}

你可能感兴趣的:(stm32,单片机,arm)