当前位置: 首页 > article >正文

基于stm32的HAL库的adc采集实验

小实验1:ADC单通道采集实验

实验目的

使用 ADC1 采集通道 1 的电压值,通道 1 连接光敏电阻传感器。

adc功能代码模块

头文件

void adc_init(void);
uint32_t adc_get_result(uint32_t ch);

ADC_HandleTypeDef adc_handle = {0};

 初始化

void adc_init(void)
{
    adc_handle.Instance = ADC1;                       //通道选择
    adc_handle.Init.DataAlign   = ADC_DATAALIGN_RIGHT;//数据对齐方式右对齐
    adc_handle.Init.ScanConvMode = ADC_SCAN_DISABLE;  //是否需要扫描,连续转换
    adc_handle.Init.ContinuousConvMode =DISABLE;      //连续模式 触发一次就连续不停的转换
    adc_handle.Init.NbrOfConversion    =1;            //有几个需要转换
	adc_handle.Init.DiscontinuousConvMode = DISABLE;  //间断模式只有一个通道不需要间断
    adc_handle.Init.NbrOfDiscConversion   = 0;//触发方式
    adc_handle.Init.ExternalTrigConv   =ADC_SOFTWARE_STARTE;
    HAL_ADC_Init(&adc_handle);
    
    HAL_ADCEx_Calibration_Start(&adc_handle);//进行校准
}

底层代码配置NVIC、GPIO,CLOCK

void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
    if(hadc->Instance == ADC1)
{
    RCC_PeriphCLKInitTypeDef adc_clk_init={0};
    GPIO_InitTypeDef gpio_init_struct = {0};

    __HAL_RCC_ADC1_CLK_ENABLE();//adc时钟初始化
    __HAL_RCC_GPIO_CLK_ENABLE();//gpio时钟初始化

    gpio_init_struct.Pin  = GPIO_PIN_1;//只使用两个ADC有特供的
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;//模拟输入模式 adc dac,的特供
    HAL_GPIO_Init(GPIOA,&gpio_init_struct);

    adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;//时钟选择
    //72分频后不能超过14所以选择6分频  12M    
    adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;
    //通过指定参数初始化外设时钟
    HAL_RCCEx_PeriphCLKConfig(&adc_clk_init);
}
}

配置ADC通道 

void adc_channel_config(ADC_HandleTypeDef* hadc, uint32_t ch, uint32_t rank,uint32_t stime)
{
    //单通道采集,通道封装  操作的哪个adc,指定那个通道ch  通道放在那个规则组中rank 哪个位置, 采集时间多少
    ADC_ChannelConfTypeDef adc_ch_config = {0};

    adc_ch_config.Channel = ch;//指定通道
    adc_ch_config.Rank    = rank;
    adc_ch_config.SamPlingTime = stime;

    HAL_ADC_ConfigChannel(hadc,&adc_ch_config);

}
//根据流程图调用一个GetValue的函数,这里只是进行进一步的封装
uint32_t adc_get_result(uint32_t ch)
{
    //配置参数通道
    adc_channel_config(&adc_handle ch,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5);
    //开启adc
    HAL_ADC_Start(&adc_handle);
    //判断是否转换完成
    //获取DR寄存器中的值 等待时间
    HAL_ADC_PollForConversion(&adc_handle,10);
    
    return (uint16_t)HAL_ADC_GetValue(&adc_handle);
    //adc1占换的结果放在DR寄存器的低16位,这里强转为uint16_t就可以直接获取。DR寄存器的高16位存放 
    // 的转换结果
}

main初始化

#include "sys.h"
#include "delay.h"
#include "led.h"
#include "uart1.h"
#include "adc.h"

void main(void)
{
    HAL_Init();
    stm32_clock_init(RCC_PLL_MUL9);
    led_init();
    uart1_init(115200);
    
    adc_init();
    printf("helloworld!\r\n");

    while(1)
    {

    //一直答应adc的值
    printf("adc_result: %f\r\n", (float)adc_get_result(ADC_CHANNEL_1) / 4096 *3.3);
    delay_ms(500);
}

}

 

 

 

小实验2:ADC单通道采集实验+DMA读取

实验目的

使用 ADC1 采集通道 1 的电压值+DMA读取,通道 1 连接光敏电阻传感器

 

头文件

#include "sys.h"

void adc_dma_init(uint32_t *mar);//指定数据地址

ADC_HandleTypeDef adc_handle = {0};
DMA_HandleTypeDef dma_handle = {0};

初始化

void adc_config(void)
{
    adc_handle.Instance = ADC1;                          //通道选择
    adc_handle.Init.DataAlign      = ADC_DATAALIGN_RIGHT;//数据对齐
    adc_handle.Init.ScanConvMode   = ADC_SCAN_DISABLE;   //是否需要扫描,连续的转换
    adc_handle.Init.ContinuousConvMode=ENABLE;/*转换一次就将dma中的数字搬走,连续转化结婚,搬运这样就可以自动执行*/
    adc_handle.Init.NbrOfConversion = 1;     //有几个需要转换 单通道
    adc_handle.Init.DiscontinuousConvMode = DISABLE;//间断模式只有一个通道不需要间断
    adc_handle.Init.NbrOfDisConversion    = 0;//触发方式
    adc_handle.Init.ExternalTrigConv      = ADC_SOFTWARE_START;//中断触发方式,一般软件
    HAL_ADC_Init(&adc_handle);

    //进行校对
    HAL_ADCEx_Calibration_Start(&adc_handle);
}

底层代码配置NVIC、GPIO,CLOCK

void HAL_ADC_MspInit(ADC_HandleTypeDef *hadc)
{
    if(hadc->Instance == ADC1)
{

    RCC_PeriphCLKInitTypeDef adc_clk_init = {0};
    GPIO_InitTypeDef gpio_init_struct = {0};
    
    __HAL_RCC_ADC1_CLK_ENABLE();//adc时钟初始化
    __HAL_RCC_GPIOA_CLK_ENABLE();//gpio时钟初始化
    
    gpio_init_struct.Pin = GPIO_PIN_1;//只使用两个ADC有特供的
    gpio_init_struct.Mode = GPIO_MODE_ANALOG;//模拟输入模式,adc,dac,的特供
    HAL_GPIO_Init(GPIOA,&gpio_init_struct);

    adc_clk_init.PeriphClockSelection = RCC_PERIPHCLK_ADC;//时钟选择 
    adc_clk_init.AdcClockSelection = RCC_ADCPCLK2_DIV6;//72分频后不能超过14M所以选择6分频 12M

    HAL_RCCEx_periphCLKConfig(&adc_clk_init);
}
}

通道配置

void dma_config(void)
{
	__HAL_RCC_DMA1_CLK_ENABLE();
	//提供的表格只适用于外设,串口1的TX是通道5
	
	dma_handle.Instance = DMA1_Channel1;   //指令基地址
	dma_handle.Init.Direction = DMA_PERIPH_TO_MEMORY; //指定方向  外设到内存
		
	//内存相关配置 
	//数据对齐的方式  一般用8字节对齐
	//对其增长方式
	
	dma_handle.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;//adc的DR寄存器是16位的,半字是16位的
	dma_handle.Init.MemInc  = DMA_MINC_ENABLE;//指针往下偏移,如果不偏移每次转运的都是第一个字符,地址递增
	
	//外设相关配置 
	//外设对齐的方式  一般用8字节对齐
	//外设对齐增长方式
	
	dma_handle.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;;//外设地址不能递增,如果递增,数据传数过来地址就跑到其他地方了,每次发到TDR寄存器内,不能递增
	dma_handle.Init.PeriphInc = DMA_PINC_DISABLE;
	
	
		
	dma_handle.Init.Priority  = DMA_PRIORITY_MEDIUM;  //如果只哟一个通道在使用优先级无所谓
	dma_handle.Init.Mode      = DMA_CIRCULAR;//传输模式  内存到内存只支持普通的模式,不支持循环模式
	HAL_DMA_Init(&dma_handle);
	
	//链接_HAL_LINK_DMA 是一个宏函数, 参数 需要连接的通道句柄,句柄中对应的成员变量,DMA的句柄
	__HAL_LINKDMA(&adc_handle, DMA_Handle, dma_handle);//在函数中将句柄与dma建立关联 
	
}

单通道采集,通道封装  操作的哪个adc,指定那个通道ch  通道放在那个规则组中rank 哪个位置, 采集时间多少


//单通道采集,通道封装  操作的哪个adc,指定那个通道ch  通道放在那个规则组中rank 哪个位置, 采集时间多少
void adc_channel_config(ADC_HandleTypeDef* hadc, uint32_t ch,uint32_t rank,uint32_t stime)
{
	ADC_ChannelConfTypeDef adc_ch_config = {0};
	
	adc_ch_config.Channel = ch;//指定通道
	adc_ch_config.Rank    = rank;
	adc_ch_config.SamplingTime = stime;
	
	HAL_ADC_ConfigChannel(hadc,&adc_ch_config);
}

由于是adc_dma也要初始化


//由于是adc_dma也要初始化
void adc_dma_init(uint32_t *mar)//指定数据地址
{
	adc_config();
	
	//adc  通道填进去 (序列号,流水线的哪个位置) adc采样的时间
	adc_channel_config(&adc_handle,ADC_CHANNEL_1,ADC_REGULAR_RANK_1,ADC_SAMPLETIME_239CYCLES_5);
	dma_config();
	//触发adc转换,DMA传输数据
	HAL_ADC_Start_DMA(&adc_handle,mar,1);//只转运一个就可以
}


 


http://www.kler.cn/news/368360.html

相关文章:

  • 基于rk356x u-boot版本功能分析及编译相关(二)
  • VScode插件:前端每日一题
  • 深入理解跳出率:如何利用百度统计优化网站用户体验
  • 【随手笔记】远程升级之如何平衡下载包大小与速率?
  • 查找总价格为目标值的两个商品----双指针算法
  • 对角线遍历矩阵模板
  • 第18次CCF CSP认证真题解
  • 算法题总结(十九)——图论
  • Redis设计与实现 学习笔记 第十三章 客户端
  • Sora高端制造业WordPress外贸主题
  • 编程学习与心理健康:孩子会因学习编程而焦虑吗?
  • 远程:HTTP基本身份验证失败。提供的密码或令牌不正确,或者您的账户启用了两步验证,您必须使用个人访问令牌而不是密码。
  • BotScreen: Trust Everybody, but Cut the Aimbots Yourself
  • Django 5 增删改查 小练习
  • Python实现Android设备录屏功能及停止录屏功能
  • Linux: Shell编程入门
  • 详解Redis相关缓存问题
  • Java中的反射(2)——调用构造方法和获取继承关系
  • shodan搜索引擎——土豆片的网安之路
  • <项目代码>YOLOv8路面病害识别<目标检测>
  • python中使用pymobiledevice3与手机交互(一)获取udid
  • 【C++】函数的返回、重载以及匹配、函数指针
  • 线程池(重要)
  • 位运算算法及习题 ,丢弃的数字 , 两整数之和 ,只出现一次的数字II
  • Java 线程池:深入理解与高效应用
  • C语言 | Leetcode C语言题解之第515题在每个树行中找最大值