STM32H743,基于LL库实现adc采样(ADC+DMA+TIM)

2023-05-16

买了一块正点原子的阿波罗H743开发板,最近在调试ADC采样,由于CubeMx生成的是HAL库格式的代码,HAL库使用时太占用资源了不喜欢,个人比较喜欢LL库,这个库和STD库有点像。因此用LL库来实现ADC的采样,给大家分享一下我基于LL库写的adc采样程序,测试可用的。

 

#define USE_DMA           1 /* 是否使用DMA */

/*
 * 函数名称: Samp_TIM_Init
 * 函数说明: TIM4初始化,此定时器用于采样触发(采样率1M)
 * 输入参数: 无
 * 返回参数: 无
 */
static void Samp_TIM_Init(void)
{
	LL_TIM_InitTypeDef LL_TIM_Struct={0};
	LL_APB1_GRP1_EnableClock(LL_APB1_GRP1_PERIPH_TIM4);
	
	LL_TIM_Struct.Prescaler=19;
	LL_TIM_Struct.Autoreload=9;
	LL_TIM_Struct.CounterMode=LL_TIM_COUNTERDIRECTION_UP;
	LL_TIM_Struct.ClockDivision=LL_TIM_CLOCKDIVISION_DIV1;
	LL_TIM_Init(TIM4, &LL_TIM_Struct);
	LL_TIM_EnableARRPreload(TIM4);
	LL_TIM_SetClockSource(TIM4, LL_TIM_CLOCKSOURCE_INTERNAL);
	LL_TIM_SetTriggerOutput(TIM4, LL_TIM_TRGO_UPDATE);
	LL_TIM_DisableCounter(TIM4);
}

/*
 * 函数名称: Samp_Adc_Init
 * 函数说明: 采样ADC初始化
 * 输入参数: buff_Addr, 采样数据缓存地址
 *           trans_Num, DMA一次传输大小
 * 返回参数: 无
 */
void Samp_Adc_Init(uint32_t buff_Addr, uint32_t trans_Num)
{
	uint32_t wait_loop_index;
	LL_GPIO_InitTypeDef LL_GPIO_Struct={0};
  LL_ADC_InitTypeDef ADC_InitStruct = {0};
  LL_ADC_REG_InitTypeDef ADC_REG_InitStruct = {0};
  LL_ADC_CommonInitTypeDef ADC_CommonInitStruct = {0};
#if USE_DMA
	  LL_DMA_InitTypeDef LL_DMA_Struct={0};	
#endif
	/* 使能相应时钟 */
	LL_AHB4_GRP1_EnableClock(LL_AHB4_GRP1_PERIPH_GPIOA);
	LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_ADC12);
	__HAL_RCC_ADC_CONFIG(RCC_ADCCLKSOURCE_CLKP);        /* 选择ADC的时钟源为per_ck */
#if USE_DMA
		LL_AHB1_GRP1_EnableClock(LL_AHB1_GRP1_PERIPH_DMA1);
#endif	
	/* 配置ADC通道 */
	LL_GPIO_Struct.Pin=LL_GPIO_PIN_0;
	LL_GPIO_Struct.Mode=LL_GPIO_MODE_ANALOG;
	LL_GPIO_Struct.Pull=LL_GPIO_PULL_NO;
	LL_GPIO_Init(GPIOA, &LL_GPIO_Struct);	
#if USE_DMA
  /* DMA配置 */
  LL_DMA_Struct.PeriphRequest=LL_DMAMUX1_REQ_ADC1;
  LL_DMA_Struct.Direction=LL_DMA_DIRECTION_PERIPH_TO_MEMORY;
  LL_DMA_Struct.Mode=LL_DMA_MODE_CIRCULAR;
  LL_DMA_Struct.Priority=LL_DMA_PRIORITY_MEDIUM;
  LL_DMA_Struct.NbData=trans_Num;
  LL_DMA_Struct.PeriphOrM2MSrcAddress=(uint32_t)&ADC1->DR;
  LL_DMA_Struct.MemoryOrM2MDstAddress=(uint32_t)buff_Addr;
  LL_DMA_Struct.PeriphOrM2MSrcDataSize=LL_DMA_PDATAALIGN_HALFWORD;
  LL_DMA_Struct.MemoryOrM2MDstDataSize=LL_DMA_MDATAALIGN_HALFWORD;
  LL_DMA_Struct.PeriphOrM2MSrcIncMode=LL_DMA_PERIPH_NOINCREMENT;
  LL_DMA_Struct.MemoryOrM2MDstIncMode=LL_DMA_MEMORY_INCREMENT;
  LL_DMA_Init(DMA1, LL_DMA_STREAM_0, &LL_DMA_Struct);  
  /* 开启DMA传输完成中断 */
  LL_DMA_EnableIT_TC(DMA1, LL_DMA_STREAM_0);
	/* 配置中断优先级 */
  NVIC_SetPriority(DMA1_Stream0_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
  NVIC_EnableIRQ(DMA1_Stream0_IRQn);
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);
#endif
	/* ADC初始化 */
	/* 退出掉电模式 */
	LL_ADC_DisableDeepPowerDown(ADC1);
	/* 启动内部稳压器 */
	LL_ADC_EnableInternalRegulator(ADC1);
  /* 等待内部稳压器启动 */
  wait_loop_index = ((LL_ADC_DELAY_INTERNAL_REGUL_STAB_US * (SystemCoreClock / (100000 * 2))) / 10);
  while(wait_loop_index != 0)
  {
    wait_loop_index--;
  }  	
	/* 设置ADC分频系数 */
  ADC_CommonInitStruct.CommonClock = LL_ADC_CLOCK_ASYNC_DIV1;
  LL_ADC_CommonInit(__LL_ADC_COMMON_INSTANCE(ADC1), &ADC_CommonInitStruct);	
	/* BOOST 位控制 */
	LL_ADC_SetBoostMode(ADC1, LL_ADC_BOOST_MODE_50MHZ);
	/* 采样率设置 */
  ADC_InitStruct.Resolution = LL_ADC_RESOLUTION_12B;
  ADC_InitStruct.LeftBitShift=LL_ADC_LEFT_BIT_SHIFT_NONE;
  ADC_InitStruct.LowPowerMode = LL_ADC_LP_MODE_NONE;
  LL_ADC_Init(ADC1, &ADC_InitStruct);
	/* 启动校准 */
  LL_ADC_StartCalibration(ADC1, LL_ADC_CALIB_OFFSET, LL_ADC_SINGLE_ENDED);  
	/* 等待校准完成 */
	while(LL_ADC_IsCalibrationOnGoing(ADC1) != 0UL);		
	/* 规则采样参数配置 */
	ADC_REG_InitStruct.TriggerSource=LL_ADC_REG_TRIG_EXT_TIM4_TRGO;
	ADC_REG_InitStruct.DataTransferMode=LL_ADC_REG_DMA_TRANSFER_UNLIMITED;
	ADC_REG_InitStruct.ContinuousMode=LL_ADC_REG_CONV_SINGLE;
  ADC_REG_InitStruct.SequencerLength = LL_ADC_REG_SEQ_SCAN_DISABLE;
  ADC_REG_InitStruct.SequencerDiscont = LL_ADC_REG_SEQ_DISCONT_DISABLE;	
  ADC_REG_InitStruct.Overrun = LL_ADC_REG_OVR_DATA_OVERWRITTEN;
  LL_ADC_REG_Init(ADC1, &ADC_REG_InitStruct);
  LL_ADC_REG_SetTriggerEdge(ADC1, LL_ADC_REG_TRIG_EXT_RISING);
	/* 配置规则通道 */
  LL_ADC_REG_SetSequencerRanks(ADC1, LL_ADC_REG_RANK_1, LL_ADC_CHANNEL_16);
  LL_ADC_SetChannelSamplingTime(ADC1, LL_ADC_CHANNEL_16, LL_ADC_SAMPLINGTIME_8CYCLES_5);
  LL_ADC_SetChannelSingleDiff(ADC1, LL_ADC_CHANNEL_16, LL_ADC_SINGLE_ENDED);
	/* 通道预选设置,这个很关键 */
  ADC1->PCSEL |= (1UL << (__LL_ADC_CHANNEL_TO_DECIMAL_NB(LL_ADC_CHANNEL_16) & 0x1FUL));  	
#if USE_DMA
  LL_ADC_REG_SetDataTransferMode(ADC1, LL_ADC_REG_DMA_TRANSFER_UNLIMITED);
#else
  LL_ADC_REG_SetDataTransferMode(ADC1, LL_ADC_REG_DR_TRANSFER);
	LL_ADC_EnableIT_EOC(ADC1);
	NVIC_SetPriority(ADC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(), 0, 0));
	NVIC_EnableIRQ(ADC_IRQn);
#endif
	/* 初始化采样定时器 */
	Samp_TIM_Init();
}

/*
 * 函数名称: Start_Sample
 * 函数说明: 开始采样
 * 输入参数: 无
 * 返回参数: 无
 */
void Start_Sample(void)
{
#if USE_DMA	
	LL_DMA_EnableStream(DMA1, LL_DMA_STREAM_0);
#endif
  LL_ADC_Enable(ADC1);
	while(LL_ADC_IsActiveFlag_ADRDY(ADC1) != SET);
	LL_ADC_REG_StartConversion(ADC1);
	LL_TIM_EnableCounter(TIM4);
}

/*
 * 函数名称: Stop_Sample
 * 函数说明: 停止采样
 * 输入参数: 无
 * 返回参数: 无
 */
void Stop_Sample(void)
{
	LL_TIM_DisableCounter(TIM4);
	LL_ADC_REG_StopConversion(ADC1);
	while(LL_ADC_REG_IsConversionOngoing(ADC1) != 0);
	LL_ADC_Disable(ADC1);
	LL_ADC_EnableDeepPowerDown(ADC1);
#if USE_DMA	
	LL_DMA_DisableStream(DMA1, LL_DMA_STREAM_0);
	LL_DMA_ClearFlag_TC0(DMA1);
#endif
}

#if USE_DMA
/*
 * 函数名称: DMA1_Stream0_IRQHandler
 * 函数说明: DMA1_Stream0中断服务函数
 * 输入参数: 无
 * 返回参数: 无
 */
void DMA1_Stream0_IRQHandler(void)
{
	if(LL_DMA_IsActiveFlag_TC0(DMA1) != RESET)
	{
		LL_DMA_ClearFlag_TC0(DMA1);
        /* 用于检测采样率是否准确的(1M采样率时,DMA传输1000个数据大概时间是1ms) */ 
		LL_GPIO_TogglePin(GPIOB, LL_GPIO_PIN_1);
	}
}

#else
/*
 * 函数名称: ADC_IRQHandler
 * 函数说明: ADC1的中断服务函数
 * 输入参数: 无
 * 返回参数: 无
 */
void ADC_IRQHandler(void)
{
	if(LL_ADC_IsActiveFlag_EOC(ADC1) != RESET)
	{
      LL_ADC_ClearFlag_EOC(ADC1);
      /* 不使用DMA时,在这里面获取采样值 */
	}
}

#endif

LL库的代码多简洁,希望官方能多完善下LL库。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

STM32H743,基于LL库实现adc采样(ADC+DMA+TIM) 的相关文章

随机推荐

  • 自动化学科领域高质量科技期刊T1级期刊

    自动化学科领域高质量科技期刊T1级期刊 控制理论与控制工程方向 序号 期刊名称 T1 01 IEEE Transactions on Automatic Control T1 02 Automatica T1 03 SIAM Journal
  • UR机器人手眼标定

    一 UR机器人位姿表示 默认情况下UR机器人的基坐标系和TCP如下图所示 xff1a 注意这里的TCP位置和坐标系都是在默认TCP配置的情况下 xff0c 默认的TCP配置如下图所示 xff1a 如果用户想要自己设置TCP的位置和坐标系就可
  • 《自抗扰控制技术》——第一遍阅读

    目录 感想摘抄自认为有用的结论第一章 xff1a 剖析经典PID调节器第二章 xff1a 跟踪微分器第三章 xff1a 非光滑反馈的功能和效率第四章 xff1a 扩张状态观测器第五章 xff1a 自抗扰控制器第六章 xff1a 自抗扰控制器
  • ROS Melodic版本下Gazebo的更新与安装

    ROS Melodic自带的Gazebo版本过低 xff0c 建议升级 span class token comment 1 首先 xff0c 查看Gazebo版本 出现的是 gazebo9 及其相关插件 span dpkg l span
  • 《自抗扰控制技术》——第二遍(仿真)

    目录 感想复现书上的仿真图像第一章 xff1a 剖析经典PID调节器第二章 xff1a 跟踪微分器第三章 xff1a 非光滑反馈的功能和效率第四章 xff1a 扩张状态观测器第五章 xff1a 自抗扰控制器第六章 xff1a 自抗扰控制器的
  • 使用MYNT-EYE-D相机跑开源代码VINS_Fusion

    使用MYNT EYE D相机跑开源代码VINS Fusion 这两天刚买了一个小觅智能公司型号为D1000 IR 120 Color的深度相机 xff0c 探索了一下在VINS Fusions上的融合方法 xff0c 折腾了很久才成功 xf
  • 修改docker默认存储路径

    默认情况下 xff0c docker镜像的默认存储路径是 var lib docker xff0c 这相当于直接挂载系统目录下 xff0c 而一般在搭系统时 xff0c 这个区都不会太大 xff0c 所以如果长期使用docker开发应用 x
  • 制作自己的rgb-d数据集

    今天自己用机器人采了一波数据 尝试着用自己采集的RGB D数据来跑slam2的RGB D例程 下面来记录一下 该文章主要是参考这篇博客 xff1a https blog csdn net qq 16481211 article detail
  • ROS中的一些基本概念

    主节点 xff08 master xff09 xff1a 负责节点到节点的消息与通信 用roscore命令来运行主节点 节点只有在需要注册自己信息或向其他节点发送请求时才能访问主节点 节点 xff08 node xff09 xff1a 是指
  • ros实践(一):编写一个自己的功能包

    创建ROS功能包的命令如下 xff1a catkin create pkg 功能包名称 依赖功能包1 依赖功能包2 实践 cd catkin ws src catkin create pkg my first ros pkg std msg
  • 多传感器融合技术(一)

    传感器融合 xff0c 一般可以分为四种 xff1a Early fusion Fusing the raw data xff0c 一般称为前融合 xff08 或数据融合 xff09 xff0c 汇总所有传感器的数据 xff0c 得到一个s
  • 多传感器融合技术(序)

    一 xff0e 概述 多传感器融合 xff08 Multi sensor Fusion MSF xff09 是利用计算机技术 xff0c 将来自多传感器或多源的信息和数据以一定的准则进行自动分析和综合 xff0c 以完成所需的决策和估计而进
  • 如何使用手机端、ipad端来编写博客

    今天收到一位粉丝的提问 xff0c 为此我特意去试了一下 xff0c 相信大家都知道CSDN的移动APP是不能写博客的 xff0c 那么我就想到用网页去试试 xff0c 但是当我搜索CSDN网页进去以后 xff0c 如图 xff1a 解法是
  • 上位机串口数据检验方式(二)——奇偶校验

    奇偶校验这个概念在逻辑设计里面经常会用到 xff0c 但有的人对奇偶校验的理解很混乱 奇偶校验是对数据传输正确性的一种校验方法 在数据传输前附加一位奇校验位 xff0c 用来表示传输的数据中 34 1 34 的个数是奇数还是偶数 xff0c
  • coco2017 数据集获取

    span class token comment 下载命令 span span class token function wget span http images cocodataset org zips train2017 zip sp
  • c++/opencv利用相机位姿估计实现2D图像像素坐标到3D世界坐标的转换

    最近在做自动泊车项目中的车位线检测 xff0c 用到了将图像像素坐标转换为真实世界坐标的过程 xff0c 该过程可以通过世界坐标到图像像素坐标之间的关系进行求解 xff0c 在我的一篇博文中已经详细讲解了它们之间的数学关系 xff0c 不清
  • C语言回调函数的定义和写法

    C语言中的回调函数 xff08 Callback Function xff09 1 定义和使用场合 回调函数是指 使用者自己定义一个函数 xff0c 实现这个函数的程序内容 xff0c 然后把这个函数 xff08 入口地址 xff09 作为
  • MATLAB到底有多厉害

    前言 有人说 xff0c MATLAB除了不会生孩子 xff0c 什么都会 矩阵运算 数据可视化 GUI xff08 用户界面 xff09 设计 甚至是连接其他编程语言 xff0c MATLAB都能轻松实现 xff01 那么 xff0c M
  • 无人机的偏航角,滚动角,俯仰角解释

    1 偏航角 xff08 yaw xff09 简单的定义 xff1a 就是实际航向与计划航向之间的夹角 xff0c 如图所示 深刻的定义 xff1a 机轴 xff08 沿机头方向 xff09 水平投影与地轴的夹角 xff0c 如图所示 或者
  • STM32H743,基于LL库实现adc采样(ADC+DMA+TIM)

    买了一块正点原子的阿波罗H743开发板 xff0c 最近在调试ADC采样 xff0c 由于CubeMx生成的是HAL库格式的代码 xff0c HAL库使用时太占用资源了不喜欢 xff0c 个人比较喜欢LL库 xff0c 这个库和STD库有点