还是采用匠心科技的无刷电机套件,采样电路如下
对应的 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数据基本稳定
证明了 电机的确转为发电模式,可以用作 速度检测