之前了解了ADC的单独使用,由于AD的采样和处理对CPU的消耗较大,单独使用AD会对CPU 的很有要求
void Adc_Init(void)
{
ADC_InitTypeDef ADC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOC | RCC_APB2Periph_ADC1,ENABLE );//使能端口1的时钟和ADC1的时钟,因为ADC1的通道1在PA1上
RCC_ADCCLKConfig(RCC_PCLK2_Div6); //设置ADC分频因子6 72M/6=12M,ADC最大时间不能超过14M,也就是ADC的时钟频率为12MHz
//PAx 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PCx 作为模拟通道输入引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_5;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN; //模拟输入引脚
GPIO_Init(GPIOC, &GPIO_InitStructure);
ADC_DeInit(ADC1); //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //本次实验使用的是ADC1,并ADC1工作在独立模式ADC_CR1的位19:16,即这几位为0000
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //ADC_ScanConvMode 用来设置是否开启扫描模式,本实验开启扫面模式.ADC_CR1的位8
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;//ADC_ContinuousConvMode 用来设置是否开启连续转换模式 模数转换工作在连续转换模式,ADC_CR2的位1
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None; //转换由软件而不是外部触发启动 ADC_CR2的位19:17
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //ADC数据右对齐ADC_CR2的位11
ADC_InitStructure.ADC_NbrOfChannel = N; //顺序进行规则转换的ADC通道的数目ADC_SQR1位23:20
ADC_Init(ADC1, &ADC_InitStructure); //根据ADC_InitStruct中指定的参数初始化外设ADCx的寄存器
ADC_RegularChannelConfig(ADC1, ADC_Channel_3, 3, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道0;第1转换;采样时间为239.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_15, 2, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道1;第2转换;采样时间为239.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_5, 1, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道3;第3转换;采样时间为239.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_11, 4, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道0;第1转换;采样时间为239.5周期
ADC_RegularChannelConfig(ADC1, ADC_Channel_10, 5, ADC_SampleTime_55Cycles5 );//ADC1;ADC1通道1;第2转换;采样时间为239.5周期
ADC_DMACmd(ADC1, ENABLE); //使能ADC1的DMA传输,ADC_CR2位8
ADC_Cmd(ADC1, ENABLE); //使能的ADC1,ADC_CR2位0
ADC_ResetCalibration(ADC1); //使能复位校准,ADC_CR2位3
while(ADC_GetResetCalibrationStatus(ADC1)); //等待复位校准结束
ADC_StartCalibration(ADC1); //开启AD校准,ADC_CR2位2
while(ADC_GetCalibrationStatus(ADC1)); //等待校准结束
ADC_SoftwareStartConvCmd(ADC1, ENABLE);//软件启动AD转换
}
,下面上传一点AD的DMA方式的应用,有不对之处欢迎指正:
Adc_Init();//AD初始化函数
MYDMA_Config(DMA1_Channel1,(u32)&ADC1->DR,(u32)&AD_DATA,N);//DMA1通道1;外设为ADC1;存储器为AD_DATA;通道数为N个.
u8 DMA1_MEM_LEN;
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从外设模式->存储器/16位数据宽度/存储器增量模式
//DMA_CHx:DMA通道CHx //cpar:外设地址 //cmar:存储器地址//cndtr:数据传输量
void MYDMA_Config(DMA_Channel_TypeDef* DMA_CHx,u32 cpar,u32 cmar,u16 cndtr)
{
DMA_InitTypeDef DMA_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //使能DMA时钟
DMA_DeInit(DMA_CHx); //将DMA的通道1寄存器重设为缺省值
DMA1_MEM_LEN=cndtr;//通道数据长度
DMA_InitStructure.DMA_PeripheralBaseAddr = cpar; //DMA外设基地址
DMA_InitStructure.DMA_MemoryBaseAddr = cmar; //DMA内存基地址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //数据传输方向,从外设发送到内存 DMA_CCRX位4
DMA_InitStructure.DMA_BufferSize = cndtr; //DMA通道的DMA缓存的大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址寄存器不变
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址寄存器递增
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设数据宽度为16位
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存数据宽度为16位
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //工作在循环缓存模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //DMA通道 x拥有高优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //DMA通道x没有设置为内存到内存传输
DMA_Init(DMA_CHx, &DMA_InitStructure); //根据DMA_InitStruct中指定的参数初始化DMA的通道USART1_Tx_DMA_Channel所标识的寄存器
DMA_Cmd(DMA1_Channel1, ENABLE);//启动DMA通道
}
void TIM2_IRQHandler(void)
{
int i;
// if(START_FLAG == 0)
// {
// START_TIME++;
// if(START_TIME > 2000)
// {
// g_fangle0 -= 30;
// START_TIME = 0;
// START_FLAG = 1;
// }
// }
// if((Magnetic_L1+Magnetic_R2) < 20) g_fangle0 = 1918;
g_nspeedcontroltime++;
SpeedControlout();
g_nDirectionControlPeriod++;
DirectionControlOutput();
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if(g_nspeedcishu == 0)
{
/* Enable the TIM Counter */
TIM4->CNT = 0;
TIM4->CR1 |= TIM_CR1_CEN;
TIM5->CNT = 0;
TIM5->CR1 |= TIM_CR1_CEN;
}
g_nspeedcishu++;
if(g_nspeedcishu >= 100)
{
g_fspeedrightce = TIM4->CNT;
if(g_fspeedrightce > 32767) g_fspeedrightce = 65535 - g_fspeedrightce; //正转为0xffff-CNT,反转为CNT-0
g_fspeedleftce = TIM5->CNT;
if(g_fspeedleftce > 32767) g_fspeedleftce = 65535 - g_fspeedleftce; //正转为0xffff-CNT,反转为CNT-0
g_nspeedcishu = 0;
/* Disable the TIM Counter */
TIM4->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
TIM5->CR1 &= (uint16_t)(~((uint16_t)TIM_CR1_CEN));
}
/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
if(TimeCount == 1) //AD转换,采集陀螺仪+加速度+方向
{
for(i = 0; i < 20; i++)
{
ATDTUO[i] = AD_DATA[0];
ATDDIR[i] = AD_DATA[1];
ATDJIA[i] = AD_DATA[2];
ATDLEFT[i] = AD_DATA[3];
ATDRIGHT[i] = AD_DATA[4];
}
AVE();
Kalman_Filter(g_fanglespeed, g_fangle, 0.1, 0.003, 0.05, 0.0122, &Angle_Z, &Gyro_T2_t);
Kalman_Filter(g_fangle, g_fanglespeed,0.1, 0.003, 0.05, 0.0122, &Gyro_T2, &Angle_Z_t);
Kalman_Filter(g_fangle, g_fdirection, 0.1, 0.003, 0.05, 0.0122, &Gyro_T1, &Angle_Z2);
Kalman_Filter(g_fmagneticl, g_fmagneticl, 0.1, 0.003, 0.05, 0.0122, &Magnetic_L1, &Magnetic_R1);
Kalman_Filter(g_fmagneticl, g_fmagneticr, 0.1, 0.003, 0.05, 0.0122, &Magnetic_R2, &Magnetic_L2);
OutData[0] = Angle_Z;
OutData[1] = Gyro_T2;
OutData[2] = AD_DATA[2];
OutData[3] = AD_DATA[0];
// printf("Jiasudu=%d\n",AD_DATA[2]);
// printf("Tuoluoyi=%d\n",AD_DATA[0]);
// printf("Fangxiang=%d\n",AD_DATA[1]);
// printf("Zuodianci=%d\n",AD_DATA[3]);
// printf("Youdianci=%d\n",AD_DATA[4]);
}
else if(TimeCount == 2) //角度控制
{
AngleControl();
}
else if(TimeCount == 3) //方向控制
{
DirectionControl();
}
else if(TimeCount == 4) //速度控制
{
SpeedControl();
Motoroutput();
Motorspeedout();
Setmotorvoltage(g_fleftval,g_frightval);
TIM3_Mode_Config(PWMDTY01,PWMDTY23,PWMDTY45,PWMDTY67);
}
if(TimeCount >= 5)
{
TimeCount = 0;
}
TimeCount++;
TIM2->SR = 0;//清中断标志位
}