ADC采集实验

目录

实验要求:

实验器材:

实验思路:

实验步骤:

总结:

程序源码:


实验要求:

通过stm32ADC采集50hz交流电,并通过串口显示

实验器材:

芯片为stm32f103RC的野火stm32MINI系列

实验思路:

通过TIM(定时器)触发ADC进行数据采样,将采集到的数据经过DMA转化到指定数组中。在进行一次采样过后,遍历数组经行数据的读取,并确定最大值与最小值,通过最大值与最小的差求得峰峰值。通过数学运算进而得到有效值与峰值。

注意:发生器显示的电压为峰峰值,在没有连接外部电路时,单片机只能采集到0~3.3V,因此单片得到的数据电压乘二即为发生器显示的电压。

实验步骤:

1。编写ADC配置:

static void ADCx_Mode_Config(void)
{
	ADC_InitTypeDef ADC_InitStructure;

	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);	  //使能ADC1通道时钟

	//ADC1初始化
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; 			//独立ADC模式
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;  			//关闭扫描方式
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;			//关闭连续转换模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;   	//使用外部触发模式
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; 			//采集数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = 1; 			//要转换的通道数目
	ADC_Init(ADCx, &ADC_InitStructure);
	
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);				//配置ADC时钟,为PCLK2的6分频,即12Hz
	ADC_RegularChannelConfig(ADCx, ADC_Channel_6, 1, ADC_SampleTime_239Cycles5);		//配置ADC1通道6为239.5个采样周期 
	
	//使能ADC、DMA
	ADC_DMACmd(ADCx,ENABLE);
	ADC_Cmd(ADCx,ENABLE);
 
	ADC_ResetCalibration(ADCx);				//复位校准寄存器
	while(ADC_GetResetCalibrationStatus(ADCx));				//等待校准寄存器复位完成
 
	ADC_StartCalibration(ADCx);				//ADC校准
	while(ADC_GetCalibrationStatus(ADCx));				//等待校准完成
	
	ADC_ExternalTrigConvCmd(ADCx, ENABLE);		//设置外部触发模式使能
}

2.DMA配置:

/* DMA1配置 */
void DMAx_Mode_Config()
{
	DMA_InitTypeDef DMA_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

	RCC_AHBPeriphClockCmd(DMA_CLK,ENABLE);	  										//使能ADC1通道时钟
	
	//DMA1初始化
	DMA_DeInit(DMA_CHANNE);
	DMA_InitStructure.DMA_PeripheralBaseAddr = ( u32 ) ( & ( ADCx->DR ) );			//ADC1地址
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t)&ADC_ConvertedValue; 			//内存地址
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; 								//方向(从外设到内存)
	DMA_InitStructure.DMA_BufferSize =  (uint32_t)DMA_LEN; 							//传输内容的大小
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; 				//外设地址固定
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; 						//内存地址递增
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord ; 	//外设数据单位
	DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord ;   			//内存数据单位
	DMA_InitStructure.DMA_Mode = DMA_Mode_Circular  ; 								//DMA模式:循环传输
	DMA_InitStructure.DMA_Priority = DMA_Priority_High ; 							//优先级:高
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;   									//禁止内存到内存的传输
	DMA_Init(DMA_CHANNE, &DMA_InitStructure);  										//配置DMA1
	
	DMA_ITConfig(DMA_CHANNE,DMA_IT_TC, ENABLE);										//使能传输完成中断

	NVIC_InitStructure.NVIC_IRQChannel = DMA_IRQN;									//中断源设置
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;						//优先级抢占
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;								//子优先级
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;									//使能中断
	NVIC_Init(&NVIC_InitStructure);
	
	DMA_Cmd(DMA_CHANNE,ENABLE);
}

3.ADC_GPIO设置

//GPIO配置,PA6
void GPIO_Mode_Config()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_APB2PeriphClockCmd(GPIO_CLK, ENABLE);	  					//使能GPIOA时钟 

	//PA6 作为模拟通道输入引脚   
	GPIO_InitStructure.GPIO_Pin = GPIO_PIN;		
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIO_PORT, &GPIO_InitStructure);
}

4.定时器配置

/* TIM2配置 */
void TIMx_Mode_Config(u16 arr,u16 psc)												//arr为重加载值,psc为预分频系数
{
	TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
	TIM_OCInitTypeDef TIM_OCInitStructure;
	
	RCC_APB1PeriphClockCmd(TIM_CLK, ENABLE); 								//时钟使能

	//定时器TIM2初始化
	TIM_TimeBaseStructure.TIM_Period = arr; 								//设置在下一个更新事件装入活动的自动重装载寄存器周期的值
	TIM_TimeBaseStructure.TIM_Prescaler =psc; 								//设置用来作为TIMx时钟频率除数的预分频值
	TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; 				//设置时钟分割:TDTS = Tck_tim
	TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; 			//TIM向上计数模式
	TIM_TimeBaseInit(TIMx, &TIM_TimeBaseStructure);							//根据指定的参数初始化TIMx的时间基数单位
	
	TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;						//选择定时器模式:TIM脉冲宽度调制模式1
	TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;			//比较输出使能
	TIM_OCInitStructure.TIM_Pulse = TIM_PULSE;								//脉搏宽度
	TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;				//输出极性:TIM输出比较极性低
	TIM_OC2Init(TIMx, & TIM_OCInitStructure);								//初始化外设TIM2_CH2
	
	TIM_Cmd(TIMx, ENABLE); 													//使能TIMx
	TIM_CtrlPWMOutputs(TIMx, ENABLE);
}

5.DAM终端配置

void DMA1_Channel1_IRQHandler(void)
{
	
	uint8_t i;
	uint16_t max=0;
	uint16_t min=4096;
    if(DMA_GetITStatus(DMA1_IT_TC1)!=RESET)
	{
		ADC_Cmd(ADC1, DISABLE);    //不使能ADC

		for(i=0;i<FFT_LENGTH;i++)
		{

		   if(max<ADC_ConvertedValue[i])
			 {
				 max=ADC_ConvertedValue[i];
			 }
			 if(min>ADC_ConvertedValue[i])
			 {
				 min=ADC_ConvertedValue[i]; 
			 }
		}
		fengzhi=(float)(max-min)*(3.3/4096);
		printf("峰值为:%.2f\r\n",fengzhi);
		printf("有效值为:%.2f\r\n",(fengzhi/sqrt(2.0)));
		ADC_Cmd(ADC1, ENABLE);//使能ADC  
    }
    DMA_ClearITPendingBit(DMA1_IT_TC1);
}

6.其他相关函数的配置


/* 数据定义 */
__IO uint16_t ADC_ConvertedValue[ADC_LEN] = {0};							// 采集数据存放的数据
float fengzhi = 0;															//峰值的定义
//float youxiao = 0;														//有效值通过峰值除以sqr(2)得到,暂未使用变量
//float Rms = 0;

7。初始化

/* 初始化 */
void Adc_Init()
{
	TIMx_Mode_Config(100,71);		//(72000000/71+1)/(100+1)=10000HZ;
	ADCx_Mode_Config();
	DMAx_Mode_Config();
	GPIO_Mode_Config();
}

以上均写在ADC.c文件中


ADC.h 文件的编写

#ifndef	__BSP_ADC_H
#define	__BSP_ADC_H

#include "stm32f10x.h"
#include "stdio.h"
#include "math.h"

/* 通用定义 */
#define FFT_LENGTH	200

/* ADC相关引脚定义 */
#define	ADCx	ADC1
#define ADC_LEN	200
#define	ADC_CLK	RCC_APB2Periph_ADC1

/* ADC输入引脚定义 */
#define	GPIO_PORT	GPIOC
#define	GPIO_PIN	GPIO_Pin_1
#define GPIO_CLK	RCC_APB2Periph_GPIOC

/*	DAM相关配置 */
#define	DMA_CLK		RCC_AHBPeriph_DMA1
#define DMA_CHANNE	DMA1_Channel1
#define	DMA_IRQN	DMA1_Channel1_IRQn;
#define DMA_LEN		200

/* TIM相关配置 */
#define TIMx		TIM2
#define	TIM_PULSE	50
#define	TIM_CLK		RCC_APB1Periph_TIM2

/* 函数定义 */
void Adc_Init(void);

#endif  /*__BSP__ADC_H*/

 主函数只需在main函数中加入 Adc.Init()  即可

总结:

本次实验囊括内容较多,通过本次实验加强了对ADC、DMA、TIM函数的认识,学习的内容也进一步扩大。注重章节的点点滴滴,脚踏实地的出发才能稳扎知识。

程序源码:

输入引脚要看代码,目前设置为PC1,即将发生器函数的红线接入PA6

文件集合访问 密码:74qn

注:本文代码借鉴于网络,本人只做CTRl+C与CTRl+V并对代码进行需求修改,侵删!

  • 3
    点赞
  • 36
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 要实现对交流信号的有效值和平均值的采集,可以利用STM32F103的定时器和ADC功能。 首先,通过STM32F103的定时器功能可以采集交流信号的波形。可以选择一个合适的定时器模式,设置定时器的时钟频率和预分频值,使得定时器的溢出周期与交流信号的周期相近。然后开启定时器中断,每次定时器溢出时触发中断函数。 在定时器中断函数中,可以通过ADC功能进行模拟信号的采样。配置ADC的通道和采样速率,选择合适的采样时间和转换模式。在中断函数中,通过调用ADC的转换函数进行信号的采样。 为了获取交流信号的有效值,可以利用公式:有效值=√(平均值^2 + 峰值^2 / 2),其中平均值可通过计算一段时间内采样值的平均值得到,峰值可通过观察采样值的最大值和最小值得到。可以设置一个采样时间窗口,在定时器中断函数中,将每次采集到的采样值保存起来,并记录采样值的最大值和最小值。 当采样时间窗口结束时,可以根据保存的采样值计算出平均值和峰值。然后再根据这两个值计算出交流信号的有效值。 最后,可以将有效值和平均值通过串口或者其他方式输出,以供后续处理或者显示。 总的来说,利用STM32F103的定时器和ADC功能,可以实现对交流信号的有效值和平均值的采集。通过适当的配置和计算,可以得到准确的结果。 ### 回答2: STM32F103是一款高性能的32位ARM Cortex-M3微控制器,具有很强的实时性能和丰富的外设接口。如果要采集交流信号的有效值和平均值,可以通过以下步骤实现: 1. 硬件连接:将交流信号作为输入引脚连接到STM32F103的某个GPIO引脚上。 2. 初始化ADC:使用STM32的内置模数转换器(ADC)来进行信号的采集。首先需要初始化ADC的相关参数,例如采样率、采样精度等。 3. 配置引脚:将需要采集的引脚配置为模拟输入模式,使其可以接收到ADC的输入信号。 4. 启动ADC转换:通过编程启动ADC转换过程,并设置为连续转换模式,以便持续地采集信号。 5. 采集数据:通过轮询模式或使用中断来获取ADC转换完成的标志位,并读取ADC数据寄存器的值,获取采样的电压值。 6. 数据处理:使用获取的采样数据,可以计算交流信号的有效值和平均值。 - 有效值:通过对样本数据进行平方和的累加操作,再除以采样点总数,最后取平方根来获得交流信号的有效值。 - 平均值:将所有样本数据进行相加操作,再除以采样点总数,即得到交流信号的平均值。 7. 输出结果:将计算得到的有效值和平均值进行输出,可以通过串口、LCD显示等方式进行结果的展示。 通过以上步骤,即可在STM32F103上成功采集交流信号的有效值和平均值。具体的实现需要根据具体的硬件和软件环境进行调整。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值