STM32驱动无刷直流电机学习(5)--ADC电流采样

还是采用匠心科技的无刷电机套件,采样电路如下

STM32驱动无刷直流电机学习(5)--ADC电流采样_第1张图片

 对应的 adc 的 io 是 

#define __ADC_MODE__ 4
无刷电机学习板 采用 PA6 PA7 PC4 进行电机的电流采样

先上adc采样的程序

#include "includes.h"
#ifndef __ADC_MODE__ 
#define __ADC_MODE__ 0
#endif
#if(__ADC_MODE__==0)
#define TEST_NUM 4
#endif
#if(__ADC_MODE__==1 || __ADC_MODE__==2 )
#define TEST_NUM 1
#endif

#if( __ADC_MODE__==3)
#define TEST_NUM 2
#endif


//
/************************************************************************************
__ADC_MODE__ ==4
无刷电机学习板 采用 PA6 PA7 PC4 进行电机的电流采样
************************************************************************************/
#if( __ADC_MODE__==4)
#define TEST_NUM 3
#endif




void DMA4ADC_Configuration(void* bufaddr,INT8U bufsize)
{
	DMA_InitTypeDef DMA_InitStructure;
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);								//启动DMA时钟
	/* DMA channel1 configuration ----------------------------------------------*/
	//使能DMA
	DMA_DeInit(DMA1_Channel1);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (INT32U)&ADC1->DR; 
	DMA_InitStructure.DMA_MemoryBaseAddr = (INT32U)bufaddr;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = bufsize;
	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_InitStructure.DMA_Priority = DMA_Priority_High;
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMA1_Channel1, &DMA_InitStructure);
	/* Enable DMA channel1 */
	DMA_Cmd(DMA1_Channel1, ENABLE);
}

void ADC_IO_Set(void)
{
#if(__ADC_MODE__==0)
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3;					//Channel 8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOC, &GPIO_InitStructure);  
	ADC_DeInit(ADC1);																//将外设 ADC1 的全部寄存器重设为缺省值
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);												//设置时钟
#endif
#if(__ADC_MODE__==1)
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOC, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;										//Channel 8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOC, &GPIO_InitStructure);  
	ADC_DeInit(ADC1);																//将外设 ADC1 的全部寄存器重设为缺省值
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);												//设置时钟
#endif
#if(__ADC_MODE__==2)
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOB, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;										//Channel 8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOB, &GPIO_InitStructure);  
	ADC_DeInit(ADC1);																//将外设 ADC1 的全部寄存器重设为缺省值
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);												//设置时钟
#endif
#if(__ADC_MODE__==3)
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_GPIOA, ENABLE);
	GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_4;							//Channel 8
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
	GPIO_Init(GPIOA, &GPIO_InitStructure);	
	ADC_DeInit(ADC1);																//将外设 ADC1 的全部寄存器重设为缺省值
	RCC_ADCCLKConfig(RCC_PCLK2_Div8);												//设置时钟
#endif
#if(__ADC_MODE__==4)
	RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
	SetPinState(GPIOA,GPIO_Pin_6|GPIO_Pin_7,GPIO_Mode_AIN);
	SetPinState(GPIOC,GPIO_Pin_4,GPIO_Mode_AIN);
	ADC_DeInit(ADC1);																//将外设 ADC1 的全部寄存器重设为缺省值
	RCC_ADCCLKConfig(RCC_PCLK2_Div6);												//设置时钟
#endif
}


void InitAdc(void* bufaddr,INT8U bufsize)
{
	ADC_InitTypeDef ADC_InitStructure;
	DMA4ADC_Configuration(bufaddr,bufsize);									//dma自动测试数据
	ADC_IO_Set();

	/* ADC1 configuration ------------------------------------------------------*/
	//ADC配置
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;						//ADC1和ADC2工作在独立模式
	ADC_InitStructure.ADC_ScanConvMode = ENABLE;							//了模数转换工作在扫描模式(多通道)还是单次(单通道)模式
#if(__ADC_MODE__==0 || __ADC_MODE__==1 || __ADC_MODE__==4)
	ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;						//了模数转换工作在扫描模式(多通道)还是单次(单通道)模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;		//转换由软件而不是外部触发启动
#endif
#if(__ADC_MODE__==2)
	ADC_InitStructure.ADC_ContinuousConvMode =DISABLE;						//了模数转换工作在扫描模式(多通道)还是单次(单通道)模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;	//配置TIM2_CC2为触发源	
#endif
#if(__ADC_MODE__==3)
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;						//了模数转换工作在扫描模式(多通道)还是单次(单通道)模式
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC3;	//配置TIM2_CC2为触发源	
#endif

	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;					//ADC数据右对齐
	ADC_InitStructure.ADC_NbrOfChannel = TEST_NUM;							//规定了顺序进行规则转换的ADC通道的数目。这个数目的取值范围是1到16
	ADC_Init(ADC1, &ADC_InitStructure);
	
	/* ADC1 regular channels configuration [规则模式通道配置]*/ 
#if(__ADC_MODE__==0)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_10 ,2, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_11 ,1, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_12, 3, ADC_SampleTime_55Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_13, 4, ADC_SampleTime_55Cycles5);
#endif

#if(__ADC_MODE__==1)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_13,1, ADC_SampleTime_239Cycles5);
#endif

#if(__ADC_MODE__==2)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5 );		
#endif


#if(__ADC_MODE__==3)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_0,1, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4,2, ADC_SampleTime_239Cycles5);
#endif

#if(__ADC_MODE__==4)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_6,1, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_7,2, ADC_SampleTime_239Cycles5);
	ADC_RegularChannelConfig(ADC1, ADC_Channel_14,3, ADC_SampleTime_239Cycles5);
#endif

	/* Enable ADC1 DMA [使能ADC1 DMA]*/
	ADC_DMACmd(ADC1, ENABLE);
	/* Enable ADC1 [使能ADC1]*/
	ADC_Cmd(ADC1, ENABLE);	
	/* Enable ADC1 reset calibaration register */	
	ADC_ResetCalibration(ADC1);
	/* Check the end of ADC1 reset calibration register */
	while(ADC_GetResetCalibrationStatus(ADC1));
	
	/* Start ADC1 calibaration */
	ADC_StartCalibration(ADC1);
	/* Check the end of ADC1 calibration */
	while(ADC_GetCalibrationStatus(ADC1));
	
	/* Start ADC1 Software Conversion */
	if(ADC_InitStructure.ADC_ExternalTrigConv == ADC_ExternalTrigConv_None)
		ADC_SoftwareStartConvCmd(ADC1, ENABLE);  
	else
		ADC_ExternalTrigConvCmd(ADC1, ENABLE);
}


/*单通道的ADC采集*/
void InitAdcOnce(void)
{ 	
	ADC_InitTypeDef ADC_InitStructure;
	ADC_IO_Set();
	ADC_InitStructure.ADC_Mode = ADC_Mode_Independent;					//工作模式:ADC1和ADC2独立工作模式  (还有其他什么模式?请看下面的附录图2)
	ADC_InitStructure.ADC_ScanConvMode = DISABLE;						//数模转换工作:扫描(多通道)模式=ENABLE、单次(单通道)模式=DISABLE
	ADC_InitStructure.ADC_ContinuousConvMode = DISABLE;					//数模转换工作:连续=ENABLE、单次=DISABLE
	ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;	//ADC转换由软件触发启动 (还有其他什么模式?请看下面的附录图3)
	ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;				//ADC数据右对齐   除了右就是左:ADC_DataAlign_Left
	ADC_InitStructure.ADC_NbrOfChannel = 1;								//顺序进行规则转换的ADC通道的数目   范围是1-16
	ADC_Init(ADC1, &ADC_InitStructure);									//根据ADC_InitStruct中指定的参数初始化外设ADC1的寄存器

	/*为啥要设置下面这一步?
	 细心的你可以发现上面初始化了一个引脚通道,初始化了一个ADC转换器,但ADC转换器并不知道你用的是哪个引脚吧?
	 这一步目的是:设置指定ADC的规则组通道(引脚),设置它们的转化顺序和采样时间
	 函数原型:void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, u8 ADC_Channel, u8 Rank, u8 ADC_SampleTime)
	 参数1 ADCx:x可以是1或者2来选择ADC外设ADC1或ADC2 
	 参数2 ADC_Channel:被设置的ADC通道  范围ADC_Channel_0~ADC_Channel_17
	 参数3 Rank:规则组采样顺序。取值范围1到16。
	 ADC_SampleTime:指定ADC通道的采样时间值  (取值范围?请看下面的附录图4)
	*/	
#if(__ADC_MODE__==2)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_9, 1, ADC_SampleTime_239Cycles5 );	  	
#endif	  		    
#if(__ADC_MODE__==3)
	ADC_RegularChannelConfig(ADC1, ADC_Channel_4, 1, ADC_SampleTime_239Cycles5 );		
#endif	  		    
	ADC_Cmd(ADC1, ENABLE);	//使能指定的ADC  注意:函数ADC_Cmd只能在其他ADC设置函数之后被调用

	/*下面4步按流程走,走完就行*/
	ADC_ResetCalibration(ADC1);	//重置指定的ADC的校准寄存器
	while(ADC_GetResetCalibrationStatus(ADC1)); //等待上一步操作完成
	ADC_StartCalibration(ADC1);	//开始指定ADC的校准状态	
	while(ADC_GetCalibrationStatus(ADC1));//等待上一步操作按成		

/*********************************************************************************************************************************
	//启动转换 获得转换的数值
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);		 //启动转换  
	while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC ));	//等待转换完成
	ADC_ConvertedValue=ADC_GetConversionValue(ADC1); 	//获取转换结果*ADC_ConvertedValue* 
**********************************************************************************************************************************/
 }	

INT16U GetAdcValueAndStartNext(void)
{
	INT16U ret=ADC_GetConversionValue(ADC1);
	ADC_SoftwareStartConvCmd(ADC1, ENABLE);
	return ret;
}

在任务中 每个100MS 打印一下输出

代码如下

INT16U adcbuf[3];
void AdcTask(void *pdata)
{
	INT8U i;
	INT16U sum;
	SysTick_CounterCmd(SysTick_Counter_Enable);								//系统时钟开始计数	
/***************************************************
	DcMotorTim1Init(PWM_PAUSE,1000);
	//H输出低电平,全部禁止
	EnPortAFPP(GPIOA,8)=0;
	EnPortAFPP(GPIOA,9)=0;
	EnPortAFPP(GPIOA,10)=0;
	//L输出高电平 全部导通
	MOTORU=1;
	MOTORV=1;
	MOTORW=1;
*******************************************************/
	InitAdc(adcbuf, 3);
	do{
		OSTimeDly(OS_TICKS_PER_SEC/10);
		sum=0;
		for(i=0;i<3;i++)	
			sum+=adcbuf[i];
		printf("I:%d %d %d %d\r\n",adcbuf[0],adcbuf[1],adcbuf[2],sum);
	}while(1);
}

 在这段代码下 每个100ms 打印电流数据 发现  用手转动电机,检测数据基本稳定在 2048 的0V左右,

INT16U adcbuf[3];
void AdcTask(void *pdata)
{
	INT8U i;
	INT16U sum;
	SysTick_CounterCmd(SysTick_Counter_Enable);								//系统时钟开始计数	
	DcMotorTim1Init(PWM_PAUSE,1000);
	//H输出低电平,全部禁止
	EnPortAFPP(GPIOA,8)=0;
	EnPortAFPP(GPIOA,9)=0;
	EnPortAFPP(GPIOA,10)=0;
	//L输出高电平 全部导通
	MOTORU=1;
	MOTORV=1;
	MOTORW=1;

	InitAdc(adcbuf, 3);
	do{
		OSTimeDly(OS_TICKS_PER_SEC/10);
		sum=0;
		for(i=0;i<3;i++)	
			sum+=adcbuf[i];
		printf("I:%d %d %d %d\r\n",adcbuf[0],adcbuf[1],adcbuf[2],sum);
	}while(1);
}

解除代码的屏蔽,让电机形成发电回路,用手转动电机,可以感觉到阻力, adc输出也开始围绕2048 上下跳动,但sum数据基本稳定

 证明了 电机的确转为发电模式,可以用作 速度检测

  

你可能感兴趣的:(无刷直流电机,C,ucos2)