PY32F030 ADC的使用

PY32F030的ADC外设与STM32的ADC使用大同小异,差别不大。下面将介绍ADC 单通道 软件触发 规则组 DMA连续转化加均值滤波程序的编写流程。

1. ADC初始化函数ADC1_Init()

使用所有外设第一步都是开启与之相关的时钟,这里也不例外,首先复位ADC并开启其时钟。

选择ADC基地址,PY32F030只有一个12位ADC,所以这里我们选ADC1。然后设置ADC时钟,ADC时钟可选APB总线或者HSI时钟分频得到。设置转化分辨率,有6、8、10、12位可选。分辨率越高,转化精度越高,当然转化的时间也更长。数据对齐方式一般选择右对齐。扫描序列选择向上,即从通道0到通道11。然后将转化结束标志位作为结束/中断标志位,开启动态低功耗自动延迟,开启连续转换模式,关闭非连续转化模式。触发方式选择软件触发,禁用硬件触发检测。使能DMA,过载发生保留新数据,覆盖旧数据(当转化值没有及时取走时)。最后调用初始化函数HAL_ADC_Init()。

然后是ADC规则组和通道的初始化。选择需要用的通道,具体的通道映射要到数据手册查看,方便接下来的回调函数中初始化IO口。这里选这通道1,加入规则组序列,选择采样周期(采样周期加上12.5T就是采样所需的时间),最后配置使能规则组通道。

使用ADC前需要校准,不然可能出现较大误差。HAL_ADCEx_Calibration_Start(&adc1);

最后以DMA方式开启ADC转化。参数分别为ADC总控结构体、DMA传输的数组地址和传输的次数。

//ADC1的初始化函数
void ADC1_Init(void)
{
	
	__HAL_RCC_ADC_FORCE_RESET();
    __HAL_RCC_ADC_RELEASE_RESET();                                         /* 复位ADC */
    __HAL_RCC_ADC_CLK_ENABLE();                                            /* ADC时钟使能 */

	
    adc1.Instance = ADC1;
    adc1.Init.ClockPrescaler = ADC_CLOCK_SYNC_PCLK_DIV4;              /* 设置ADC时钟 */
    adc1.Init.Resolution = ADC_RESOLUTION_12B;                        /* 转换分辨率12bit */
    adc1.Init.DataAlign = ADC_DATAALIGN_RIGHT;                        /* 数据右对齐 */
    adc1.Init.ScanConvMode = ADC_SCAN_DIRECTION_FORWARD;              /* 扫描序列方向:向上 */
    adc1.Init.EOCSelection = ADC_EOC_SINGLE_CONV;                     /* 将转换结束标志作为结束/中断标志位 */
    adc1.Init.LowPowerAutoWait = ENABLE;                              /* 等待转换模式开启 */
    adc1.Init.ContinuousConvMode = ENABLE;                            /* 连续转换模式 */
    adc1.Init.DiscontinuousConvMode = DISABLE;                        /* 不使能非连续模式 */
    adc1.Init.ExternalTrigConv = ADC_SOFTWARE_START;                  /* 软件触发 */
    adc1.Init.ExternalTrigConvEdge = ADC_EXTERNALTRIGCONVEDGE_NONE;   /* 触发边沿无 */
    adc1.Init.DMAContinuousRequests = ENABLE;                         /* 使能DMA */
    adc1.Init.Overrun = ADC_OVR_DATA_OVERWRITTEN;                     /* 当过载发生时,覆盖上一个值 */
	HAL_ADC_Init(&adc1);                                  //配置ADC相关的寄存器
	
	adc1_in1.Channel = ADC_CHANNEL_1;                     //使用通道1
	adc1_in1.Rank = ADC_RANK_CHANNEL_NUMBER;              //加入规则组
	adc1_in1.SamplingTime = ADC_SAMPLETIME_41CYCLES_5;    //采样周期41.5个  41.5+12.5=54个
	HAL_ADC_ConfigChannel(&adc1,&adc1_in1);               //配置规则组通道
	
	HAL_ADCEx_Calibration_Start(&adc1);                   //自校准
	
	HAL_ADC_Start_DMA(&adc1, (uint32_t *)adc1_dma_buff, 10);                              //开启转换,DMA方式, 10次传输	
}

2. ADC回调函数HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)

在回调函数中配置IO口和DMA。

配置IO口,打开PA口时钟,配置为模拟输入。具体IO口可以看数据手册,得到PA1有ADC通道1的重映射。

然后是DMA的初始化。具体步骤可参考WS2812那一节,只要把传输方向和地址改下就行。还有就是HAL_SYSCFG_DMA_Req(0);         /* DMA1_MAP选择为ADC */。这个也是PY和ST的主要区别。

最后设置DMA中断优先级和使能DMA中断。

//HAL_ADC_Init函数调用的回调函数(初始化底层IO和时钟)
void HAL_ADC_MspInit(ADC_HandleTypeDef* hadc)
{
	GPIO_InitTypeDef GPIO_InitType;
	
	if(hadc -> Instance == ADC1)
	{
		__HAL_RCC_GPIOA_CLK_ENABLE();
		__HAL_RCC_DMA_CLK_ENABLE();
		__HAL_RCC_SYSCFG_CLK_ENABLE();
		
		GPIO_InitType.Pin = GPIO_PIN_1;
        GPIO_InitType.Mode = GPIO_MODE_ANALOG;
		
        HAL_GPIO_Init(GPIOA, &GPIO_InitType);
		HAL_SYSCFG_DMA_Req(0);                                                 /* DMA1_MAP选择为ADC */
		
		adc1_dma.Instance = DMA1_Channel1;
		adc1_dma.Init.Direction = DMA_PERIPH_TO_MEMORY;                        //传输方向:外设->存储器
		adc1_dma.Init.PeriphInc = DMA_PINC_DISABLE;                            //外设地址是否自增    否
		adc1_dma.Init.MemInc = DMA_MINC_ENABLE;                                //存储器地址是否自增  是
		adc1_dma.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;           //外设数据宽度:半字(16位)
		adc1_dma.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;              //存储器数据宽度:半字(16位)
		adc1_dma.Init.Mode = DMA_CIRCULAR;                                     //循环模式
		adc1_dma.Init.Priority = DMA_PRIORITY_HIGH;                            //优先级 高
		
		__HAL_LINKDMA(hadc, DMA_Handle, adc1_dma);                             //链接
		
		HAL_DMA_Init(&adc1_dma);                                               //DMA初始化
		
		HAL_NVIC_SetPriority(DMA1_Channel1_IRQn,0,0);           //DMA1的中断优先级
		HAL_NVIC_EnableIRQ(DMA1_Channel1_IRQn);                 //开启DMA1中断		
		
		
		
//		HAL_NVIC_SetPriority(ADC_COMP_IRQn,0,0);           //ADC的中断优先级
//		HAL_NVIC_EnableIRQ(ADC_COMP_IRQn);                 //开启ADC中断
	}
		
} 

3. DMA通道1中断函数

DMA通道1中断函数中调用DMA中断函数。

DMA中断函数会调用完成中断回调函数并清除中断标志位。

//DMA通道1中断函数
void DMA1_Channel1_IRQHandler(void)
{
	HAL_DMA_IRQHandler(adc1.DMA_Handle);                   //DMA中断函数
}

4. ADC的DMA的完成中断回调函数

在完成中断回调函数中处理数据并打印到串口输出。将10次的ADC结果累加并取均值,减小误差。串口的配置就具体说了,有需要的参考下方代码,只需要重写重定向函数即可

//ADC的DMA的完成中断回调函数
void HAL_ADC_ConvCpltCallback(ADC_HandleTypeDef* hadc)
{
	uint32_t i,num;

	if(hadc ->Instance == ADC1){                                             //判断是不是ADC1进入
		num = 0;
		for(i=0; i<10; i++)
		{
			num +=adc1_dma_buff[i];
		}
		printf("ADC1_IN1:%f V\r\n", (num/10.0)*(3.3/4096.0));                //串口打印10次电压值
//		HAL_ADC_Start_IT(&adc1);                                             //再次开启转换, 中断方式
		
	}
}
/***************************************
 * 串口引脚定义:
 * USART1_TX---->PA2
 * USART1_RX---->PA3
****************************************/
#include "Usart1.h"

UART_HandleTypeDef USART1_Handle;//USART1句柄

//USART1参数配置
void USART1_Config(void)
{
  /*使能时钟*/
  __HAL_RCC_GPIOA_CLK_ENABLE();  //开启GPIOA模块时钟
  __HAL_RCC_USART1_CLK_ENABLE(); //开启USART1模块时钟

  /*配置GPIO参数*/
  GPIO_InitTypeDef GPIO_InitStruct;

  GPIO_InitStruct.Pin       = GPIO_PIN_2|GPIO_PIN_3;     //PA2|PA3
  GPIO_InitStruct.Mode      = GPIO_MODE_AF_PP;           //推免复用
  GPIO_InitStruct.Pull      = GPIO_PULLUP;               //上拉模式
  GPIO_InitStruct.Speed     = GPIO_SPEED_FREQ_VERY_HIGH; //超高速模式
  GPIO_InitStruct.Alternate = GPIO_AF1_USART1;           //连接到USART1

  HAL_GPIO_Init(GPIOA,&GPIO_InitStruct);//根据GPIO结构体初始化引脚
  /*配置USART1参数*/
  USART1_Handle.Instance        = USART1;              //串口基地址为USART1
  USART1_Handle.Init.BaudRate   = 115200;              //波特率设置为115200
  USART1_Handle.Init.WordLength = UART_WORDLENGTH_8B;  //数据位
  USART1_Handle.Init.StopBits   = UART_STOPBITS_1;     //停止位
  USART1_Handle.Init.Parity     = UART_PARITY_NONE;    //无校验
  USART1_Handle.Init.Mode       = UART_MODE_TX_RX;     //工作模式选择发送与接收
  USART1_Handle.Init.HwFlowCtl  = UART_HWCONTROL_NONE; //无硬件控制流
  
  HAL_UART_Init(&USART1_Handle);//根据结构体配置初始化USART1

  /* 使能NVIC */
  HAL_NVIC_SetPriority(USART1_IRQn, 1, 2);
  HAL_NVIC_EnableIRQ(USART1_IRQn);
}

//重定向printf
int fputc(int ch, FILE *f)
{
  HAL_UART_Transmit(&USART1_Handle, (uint8_t *)&ch, 1, 0xffff);//通过USART1发送数据
  return ch;
}


5. mai()


首先初始化HAL库,然后配置系统设置,初始化串口,最后初始化ADC即可。

int main(void)
{
//	uint8_t res;
	/***** 系统 *****/
	HAL_Init();//HAL库初始化
	System_Clock_Config_HSI();//使用外部部高速时钟--->24MHz
	/****** 用户 *****/
 	USART1_Config();//串口1参数配置
	printf("hello\r\n");//打印测试
	ADC1_Init();


	while(1)
	{

	}
}

  • 14
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值