历史上的今天
今天是:2024年10月27日(星期日)
2021年10月27日 | stm32专题二十四:ADC独立模式单通道采集
2021-10-27 来源:eefocus
ADC独立单通道采集
使用的是野火stm32f103vet6指南者开发板,硬件连接图如下:

实验一:独立单通道中断读取ADC值
编程要点:
初始化ADC用到的GPIO;
初始化ADC初始化结构体;
配置ADC时钟,配置通道的转换顺序和采样时间;
使能ADC转换完成中断,配置中断优先级;
使能ADC,准备开始转换;
校准ADC;
软件触发ADC,真正开始转换;
编写中断服务函数,读取ADC转换数据;
编写main函数,把转换的数据打印出来;
代码如下:
bsp_adc.c
#include "bsp_adc.h"
static void ADCx_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 打开 ADC IO端口时钟
ADC_GPIO_APBxClock_FUN(ADC_GPIO_CLK, ENABLE);
// 配置 ADC IO 引脚模式
// 必须为模拟输入
GPIO_InitStructure.GPIO_Pin = ADC_PIN;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
// 初始化 ADC IO
GPIO_Init(ADC_PORT, &GPIO_InitStructure);
}
static void ADCx_Mode_Config(void)
{
ADC_InitTypeDef ADC_InitStruct;
// 打开ADC的时钟
ADC_APBxClock_FUN(ADC_CLK, ENABLE);
ADC_InitStruct.ADC_Mode = ADC_Mode_Independent; // 独立模式
ADC_InitStruct.ADC_ScanConvMode = DISABLE; // 不使用扫描模式
ADC_InitStruct.ADC_ContinuousConvMode = ENABLE; // 连续转换
/* 不使用外部触发 */
ADC_InitStruct.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;
ADC_InitStruct.ADC_DataAlign = ADC_DataAlign_Right;
ADC_InitStruct.ADC_NbrOfChannel = 1;
ADC_Init(ADC_x, &ADC_InitStruct);
RCC_ADCCLKConfig(RCC_PCLK2_Div8); // 配置ADC时钟为8分频 ADCCLK = 9M
ADC_RegularChannelConfig(ADC_x, ADC_CHANNEL, 1, ADC_SampleTime_55Cycles5);
ADC_ITConfig(ADC_x, ADC_IT_EOC, ENABLE); // 配置ADC转换完成中断
ADC_Cmd(ADC_x, ENABLE); // 使能ADC
ADC_ResetCalibration(ADC_x); // 初始化ADC 校准寄存器
while(ADC_GetResetCalibrationStatus(ADC_x)); // 等待校准寄存器初始化完成
ADC_StartCalibration(ADC_x); // ADC开始校准
while(ADC_GetCalibrationStatus(ADC_x)); // 等待校准完成
ADC_SoftwareStartConvCmd(ADC_x, ENABLE); // 使用软件触发
}
static void ADC_NVIC_Config(void)
{
NVIC_InitTypeDef NVIC_InitStructure;
// 优先级分组
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
// 配置中断优先级
NVIC_InitStructure.NVIC_IRQChannel = ADC_IRQ;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**
* @brief ADC初始化
* @param 无
* @retval 无
*/
void ADCx_Init(void)
{
ADCx_GPIO_Config();
ADCx_Mode_Config();
ADC_NVIC_Config();
}
bsp_adc.h
#ifndef __BSP_ADC_H
#define __BSP_ADC_H
#include "stm32f10x.h"
// ADC GPIO宏定义
#define ADC_GPIO_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_GPIO_CLK RCC_APB2Periph_GPIOC
#define ADC_PORT GPIOC
#define ADC_PIN GPIO_Pin_1
// ADC 编号选择
// 可以是 ADC1/2,如果使用ADC3,中断相关的要改成ADC3的
#define ADC_APBxClock_FUN RCC_APB2PeriphClockCmd
#define ADC_x ADC2
#define ADC_CLK RCC_APB2Periph_ADC2
// ADC 通道宏定义(PC1对应通道11)
#define ADC_CHANNEL ADC_Channel_11
// ADC 中断相关宏定义
#define ADC_IRQ ADC1_2_IRQn
#define ADC_IRQHandler ADC1_2_IRQHandler
void ADCx_Init(void);
#endif /* __BSP_ADC_H */
中断服务函数中,当转换完成后,把转换值不断刷新到全局变量中:
void ADC_IRQHandler(void)
{
if (ADC_GetITStatus(ADC_x, ADC_IT_EOC) == SET)
{
ADC_ConvertedValue = ADC_GetConversionValue(ADC_x);
}
ADC_ClearITPendingBit(ADC_x, ADC_IT_EOC); // 清中断标志位,防止一直在中断里
}
最后在主函数中进行测试:
#include "stm32f10x.h"
#include "bsp_led.h"
#include "bsp_usart.h"
#include "bsp_adc.h"
#include __IO uint16_t ADC_ConvertedValue; // 局部变量,用于保存转换计算后的电压值 float ADC_ConvertedValueLocal; void Delay(__IO uint32_t nCount) { for(; nCount != 0; nCount--); } int main(void) { LED_GPIO_Config(); USART_config(); ADCx_Init(); printf("这是一个ADC独立单通道读取实验tn"); while (1) { ADC_ConvertedValueLocal =(float) ADC_ConvertedValue / 4096 * 3.3; printf("The current AD value = %#X tn", ADC_ConvertedValue); printf("The current voltage = %f V tn", ADC_ConvertedValueLocal); printf("n"); LED_B_TOGGLE; Delay(0x2fffee); } } 实验现象如下: 实验二:独立单通道DMA读取 当要传输大量的数据时,一般都是采用DMA。ADC + DMA本身的配置非常简单,就只需要注意,只能使用ADC1或ADC3,而ADC2无DMA传输功能。 这里主要看一下ADC + DMA配置: /** * @brief ADC - DMA配置 * @note 注意,ADC - DMA只能使用ADC1 或 ADC3,ADC2无DMA功能 */ static void ADCx_DMA_Config(void) { DMA_InitTypeDef DMA_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); DMA_DeInit(ADC_DMA_CHANNEL); DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t)(&(ADC_x->DR)); DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; DMA_InitStructure.DMA_BufferSize = 1; DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Disable; DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; DMA_InitStructure.DMA_Priority = DMA_Priority_High; DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; DMA_Init(ADC_DMA_CHANNEL, &DMA_InitStructure); DMA_Cmd(ADC_DMA_CHANNEL , ENABLE); } 然后在ADC配置函数中进行调用,再使能ADC + DMA: /* ADC - DMA设置要在使能ADC完成 */ ADCx_DMA_Config(); // 配置ADC - DMA ADC_DMACmd(ADC_x, ENABLE); // 使能 ADC DMA 请求 然后在main.c中进行测试,结果如下:
史海拾趣
|
为什么单片机开发板国内外有明显差异? 文章内容: 初学者遍寻国内各地开发板,已经形成了基本概念 偶然查阅国外网站 发现至少外观形式有明显差异-- 1.-国外使用“面包板 ...… 查看全部问答> |
|
4200-PIV[1]包在4200-SCS[2]主机更高编号的插槽中增加了2个卡,如图2所示。此外,脉冲IV的互连也显示在图2和3中。 图2. PIV的连接图 图3. 4200-SCP2侧视图。4200-SCP2[3]连接的适配器细节显示了示波器通道输入的BNC到SMA ...… 查看全部问答> |
|
小弟想把keil mdk下的LPC1114工程移植到IAR for ARM下,目前来说已经成了一个半成品,在keil下工程调试时可以在IDE中复位MCU,然后从头开始运行。但这个功能在IAR下不知道为何就是无法正常使用,如果点击回到程序开头那个按钮,程序依然不会回去到m ...… 查看全部问答> |




