代码的注释以及说明都标注出来了!
/*=====================通道1 IO======================*/
// PB0 通过调帽接电位器
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT1 GPIOB
#define RHEOSTAT_ADC_GPIO_PIN1 GPIO_Pin_0
#define RHEOSTAT_ADC_GPIO_CLK1 RCC_AHB1Periph_GPIOB
#define RHEOSTAT_ADC_CHANNEL1 ADC_Channel_8
/*=====================通道2 IO ======================*/
// PA6 悬空,可用杜邦线接3V3或者GND来实验
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT2 GPIOB
#define RHEOSTAT_ADC_GPIO_PIN2 GPIO_Pin_1
#define RHEOSTAT_ADC_GPIO_CLK2 RCC_AHB1Periph_GPIOB
#define RHEOSTAT_ADC_CHANNEL2 ADC_Channel_9
/*=====================注入通道 IO ======================*/
// PA6 悬空,可用杜邦线接3V3或者GND来实验
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT3 GPIOA
#define RHEOSTAT_ADC_GPIO_PIN3 GPIO_Pin_6
#define RHEOSTAT_ADC_GPIO_CLK3 RCC_AHB1Periph_GPIOA
#define RHEOSTAT_ADC_CHANNEL3 ADC_Channel_6
/*=====================注入通道 IO ======================*/
// PA1 悬空,可用杜邦线接3V3或者GND来实验
// ADC IO宏定义
#define RHEOSTAT_ADC_GPIO_PORT4 GPIOA
#define RHEOSTAT_ADC_GPIO_PIN4 GPIO_Pin_1
#define RHEOSTAT_ADC_GPIO_CLK4 RCC_AHB1Periph_GPIOA
#define RHEOSTAT_ADC_CHANNEL4 ADC_Channel_1
// ADC 序号宏定义
#define RHEOSTAT_ADC1 ADC1
#define RHEOSTAT_ADC1_CLK RCC_APB2Periph_ADC1
// PB1 通过调帽接光敏电阻
// ADC IO宏定义
#define RHEOSTAT_ADC2_GPIO_PORT1 GPIOA
#define RHEOSTAT_ADC2_GPIO_PIN1 GPIO_Pin_3
#define RHEOSTAT_ADC2_GPIO_CLK1 RCC_AHB1Periph_GPIOA
#define RHEOSTAT_ADC2_CHANNEL1 ADC_Channel_3
/*=====================ADC2 通道2 IO ======================*/
// PA1 悬空,可用杜邦线接3V3或者GND来实验
// ADC IO宏定义
#define RHEOSTAT_ADC2_GPIO_PORT2 GPIOA
#define RHEOSTAT_ADC2_GPIO_PIN2 GPIO_Pin_4
#define RHEOSTAT_ADC2_GPIO_CLK2 RCC_AHB1Periph_GPIOA
#define RHEOSTAT_ADC2_CHANNEL2 ADC_Channel_4
#define RHEOSTAT_ADC2 ADC2
#define RHEOSTAT_ADC2_CLK RCC_APB2Periph_ADC2
// ADC CDR寄存器宏定义,ADC转换后的数字值则存放在这里
#define RHEOSTAT_ADC_CDR_ADDR ((uint32_t)0x40012308)
// ADC DMA 通道宏定义,这里我们使用DMA传输
#define RHEOSTAT_ADC_DMA_CLK RCC_AHB1Periph_DMA2
#define RHEOSTAT_ADC_DMA_CHANNEL DMA_Channel_0
#define RHEOSTAT_ADC_DMA_STREAM DMA2_Stream0
// 这个N是为了滤波使用的
#define N 20
// ADC 中断宏定义
#define Rheostat_ADC_IRQ ADC_IRQn
#define Rheostat_ADC_INT_FUNCTION ADC_IRQHandler
void Rheostat_Init(void);
void ADC1_External_T1_CC4_Init(void); //这个是为了触发ADC注入采样
void VALUE_PRINTF(void); //用串口打印函数转换结果
void FILTER(void); //简单的平均值滤波
u16 GetVolt(u16 advalue);
#endif /* __BSP_ADC_H */
static void Rheostat_ADC_GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
// 使能 GPIO 时钟
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK1, ENABLE);
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK2, ENABLE);
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK3, ENABLE);
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_GPIO_CLK4, ENABLE);
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC2_GPIO_CLK1, ENABLE);
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC2_GPIO_CLK2, ENABLE);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC_GPIO_PORT1, &GPIO_InitStructure);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC_GPIO_PORT2, &GPIO_InitStructure);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC_GPIO_PORT3, &GPIO_InitStructure);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC_GPIO_PIN4;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC_GPIO_PORT4, &GPIO_InitStructure);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC2_GPIO_PIN1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC2_GPIO_PORT1, &GPIO_InitStructure);
// 配置 IO
GPIO_InitStructure.GPIO_Pin = RHEOSTAT_ADC2_GPIO_PIN2;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL ; //不上拉不下拉
GPIO_Init(RHEOSTAT_ADC2_GPIO_PORT2, &GPIO_InitStructure);
}
定义需要用到的变量:
__IO uint16_t ADC_ConvertedValue[4];
float ADC_ConvertedValueLocal[6];
vu16 AD_Value[20][4]; //AD采样值
vu16 After_filter[4]; //AD滤波后
static void Rheostat_ADC_Mode_Config(void)
{
DMA_InitTypeDef DMA_InitStructure
// ------------------DMA Init 结构体参数 初始化--------------------------
// ADC1使用DMA2,数据流0,通道0,这个是手册固定死的
// 开启DMA时钟
RCC_AHB1PeriphClockCmd(RHEOSTAT_ADC_DMA_CLK, ENABLE);
// 外设基址为:ADC 数据寄存器地址,
DMA_InitStructure.DMA_PeripheralBaseAddr = RHEOSTAT_ADC_CDR_ADDR;
// 存储器地址,实际上就是一个内部SRAM的变量
DMA_InitStructure.DMA_Memory0BaseAddr = (vu32)AD_Value;
// 数据传输方向为外设到存储器
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
/********************************************************
缓冲区大小为,指一次传输的数据量,下边这个80是4*20等于80,不是要进行平均值滤波嘛,
规则通道每个通道采集20个值,80采集完进中断。
Q:为什么规则采样和注入采样一个6个通道,而这里只有4*20 = 80个数据,而不是120个呢?
A:我个人理解:DMA存储的是规则通道的数据,注入组的数据有专门的数据寄存器进行存储。
*********************************************************/
DMA_InitStructure.DMA_BufferSize = 80;
// 外设寄存器只有一个,地址不用递增
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_PeripheralDataSize_HalfWord;
// 循环传输模式,循环模式开启,buffer写满后,自动回到初始地址开始传输
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular;
// DMA 传输通道优先级为高,当使用一个DMA通道时,优先级设置不影响
DMA_InitStructure.DMA_Priority = DMA_Priority_High;
// 禁止DMA FIFO ,使用直连模式
DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
// FIFO 大小,FIFO模式禁止时,这个不用配置
DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_HalfFull;
DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
// 选择 DMA 通道,通道存在于流中
DMA_InitStructure.DMA_Channel = RHEOSTAT_ADC_DMA_CHANNEL;
//初始化DMA流,流相当于一个大的管道,管道里面有很多通道
DMA_Init(RHEOSTAT_ADC_DMA_STREAM, &DMA_InitStructure);
//开启DMA中断
DMA_ITConfig(RHEOSTAT_ADC_DMA_STREAM,DMA_IT_TC,ENABLE);
// 使能DMA流
DMA_Cmd(RHEOSTAT_ADC_DMA_STREAM, ENABLE);
NVIC_InitTypeDef NVIC_InitStructure;
//-----------------------------中断初始化--------------------------
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1);
NVIC_InitStructure.NVIC_IRQChannel = DMA2_Stream0_IRQn;//外部中断 +
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;//抢占优先级1
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0x02;//子优先级1
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//使能外部中断通道
NVIC_Init(&NVIC_InitStructure);//配置
// 先定义这两个ADC结构体
ADC_InitTypeDef ADC_InitStructure;
ADC_CommonInitTypeDef ADC_CommonInitStructure;
// 开启ADC时钟
RCC_APB2PeriphClockCmd(RHEOSTAT_ADC1_CLK , ENABLE);
RCC_APB2PeriphClockCmd(RHEOSTAT_ADC2_CLK , ENABLE);
// -------------------ADC Common 结构体 参数 初始化------------------------
// ADC双通道规则-注入模式
ADC_CommonInitStructure.ADC_Mode = ADC_DualMode_RegSimult_InjecSimult;
// 时钟为fpclk x分频
ADC_CommonInitStructure.ADC_Prescaler = ADC_Prescaler_Div4;
// 禁止DMA直接访问模式
ADC_CommonInitStructure.ADC_DMAAccessMode = ADC_DMAAccessMode_1;
// 采样时间间隔
ADC_CommonInitStructure.ADC_TwoSamplingDelay = ADC_TwoSamplingDelay_5Cycles;
ADC_CommonInit(&ADC_CommonInitStructure);
// -------------------ADC Init 结构体 参数 初始化--------------------------
ADC_StructInit(&ADC_InitStructure);
// ADC 分辨率
ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;
// 扫描模式,多通道采集才需要
ADC_InitStructure.ADC_ScanConvMode = ENABLE;
// 连续转换
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;
//禁止外部边沿触发
ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;
//外部触发通道,本例子使用软件触发,此值随便赋值即可
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_CC1;
//数据右对齐
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;
/*********************************************************
转换通道2个,配置要求:ADC1和ADC2分别两路规则采样,软件触发。
这里我的理解是:
这里的通道数是主ADC(ADC1)的规则转换通道数,因为选择的是双ADC规则-注入模式,
所以从ADC(ADC2)的两个通道就不用往这里加上去。
************************************************************/
ADC_InitStructure.ADC_NbrOfConversion = 2;
//---------------------------------------------------------------------------
ADC_Init(RHEOSTAT_ADC1, &ADC_InitStructure);
// 配置 ADC1 通道转换顺序,采样时间为3个时钟周期
ADC_RegularChannelConfig(RHEOSTAT_ADC1, RHEOSTAT_ADC_CHANNEL1, 1, ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(RHEOSTAT_ADC1, RHEOSTAT_ADC_CHANNEL2, 2, ADC_SampleTime_3Cycles);
//---------------------------------------------------------------------------
ADC_Init(RHEOSTAT_ADC2, &ADC_InitStructure);
// 配置 ADC2 通道转换顺序,采样时间为3个时钟周期
ADC_RegularChannelConfig(RHEOSTAT_ADC2, RHEOSTAT_ADC2_CHANNEL1, 1, ADC_SampleTime_3Cycles);
ADC_RegularChannelConfig(RHEOSTAT_ADC2, RHEOSTAT_ADC2_CHANNEL2, 2, ADC_SampleTime_3Cycles);
//---------------------------------------------------------------------------
//配置注入采样的通道转换顺序,ADC1只使用一个注入通道
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC1,1);
ADC_InjectedChannelConfig(RHEOSTAT_ADC1,RHEOSTAT_ADC_CHANNEL3,1,ADC_SampleTime_112Cycles);
//配置注入采样的通道转换顺序,ADC2也只使用一个注入通道
ADC_InjectedSequencerLengthConfig(RHEOSTAT_ADC2,1);
ADC_InjectedChannelConfig(RHEOSTAT_ADC2,RHEOSTAT_ADC_CHANNEL4,1,ADC_SampleTime_112Cycles);
//配置注入采样的触发方式,TIM1-CH4的脉冲上升沿触发
ADC_ExternalTrigInjectedConvConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConv_T1_CC4);
ADC_ExternalTrigInjectedConvEdgeConfig(RHEOSTAT_ADC1,ADC_ExternalTrigInjecConvEdge_Rising);
//这个照理说不用配置,因为我ADC的模式选的是双通道-规则-注入模式,但是我没有去掉这两行语句进行实验,
ADC_ExternalTrigInjectedConvConfig(RHEOSTAT_ADC2,ADC_ExternalTrigInjecConv_T1_CC4);
ADC_ExternalTrigInjectedConvEdgeConfig(RHEOSTAT_ADC2,ADC_ExternalTrigInjecConvEdge_Rising);
// 使能DMA请求 after last transfer (multi-ADC mode)
ADC_MultiModeDMARequestAfterLastTransferCmd(ENABLE);
//ADC_DMARequestAfterLastTransferCmd(RHEOSTAT_ADC1,ENABLE);
// 使能ADC DMA
ADC_DMACmd(RHEOSTAT_ADC1, ENABLE);
ADC_DMACmd(RHEOSTAT_ADC2, ENABLE);
// 使能ADC
ADC_Cmd(RHEOSTAT_ADC1, ENABLE);
ADC_Cmd(RHEOSTAT_ADC2, ENABLE);
//开始adc转换,软件触发
ADC_SoftwareStartConv(RHEOSTAT_ADC1);
ADC_SoftwareStartConv(RHEOSTAT_ADC2);
}
void ADC1_External_T1_CC4_Init(void)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_TIM1, ENABLE);
/* Time Base configuration */
TIM_TimeBaseStructInit(&TIM_TimeBaseStructure);
TIM_TimeBaseStructure.TIM_Period = 99;
TIM_TimeBaseStructure.TIM_Prescaler = 1679;
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;
TIM_TimeBaseInit(TIM1, &TIM_TimeBaseStructure);
TIM_SelectOutputTrigger(TIM1,TIM_TRGOSource_Update); //选择TRGO触发源为计时器更新时间
/* TIM1 channel1 configuration in PWM mode */
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1;
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse =10;
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;
TIM_OC4Init(TIM1, &TIM_OCInitStructure);
// TIM_ITConfig(TIM1, TIM_IT_CC4, ENABLE); // CCR4的中断,这个通过设置CCR4的pulse来控制产生中断相当于PWM-ON的位置
TIM_CtrlPWMOutputs(TIM1, ENABLE);
TIM_Cmd(TIM1, ENABLE);
}
//主函数初始化Rheostat_Init()就可以
void Rheostat_Init(void)
{
Rheostat_ADC_GPIO_Config();
Rheostat_ADC_Mode_Config();
ADC1_External_T1_CC4_Init();
}
/*---------------------------------均值滤波-----------------------------*/
void FILTER(void)
{
int sum = 0;
u8 count,i;
for(i=0; i<4; i++)
{
for(count=0; count<N; count++)
{
sum += AD_Value[count][i];
}
After_filter[i] = sum / N;
// ADC_ConvertedValueLocal[i] =(float)(After_filter[i] *3.3/4096);
sum = 0;
}
}
extern __IO uint16_t ADC_ConvertedValue[4]; //开始全部初始化为0
extern float ADC_ConvertedValueLocal[7];
void DMA2_Stream0_IRQHandler(void)
{
if(DMA_GetITStatus(DMA2_Stream0,DMA_IT_TCIF0) != RESET)
{
// 读取ADC的转换值
FILTER();
}
DMA_ClearITPendingBit(DMA2_Stream0,DMA_IT_TCIF0);
}
static void Delay(__IO uint32_t nCount) //简单的延时函数
{
for(; nCount != 0; nCount--);
}
void VALUE_PRINTF(void)
{
__IO uint16_t ADC_InjectValue[2]={0}; //定义数组
/******************存放注入转换数据*****************************/
ADC_InjectValue[0] = ADC_GetInjectedConversionValue(RHEOSTAT_ADC1,ADC_InjectedChannel_1);
ADC_InjectValue[1] = ADC_GetInjectedConversionValue(RHEOSTAT_ADC2,ADC_InjectedChannel_1);
ADC_ConvertedValueLocal[0] =(float)(After_filter[0] *3.3/4096);
ADC_ConvertedValueLocal[1] =(float)(After_filter[1] *3.3/4096);
ADC_ConvertedValueLocal[2] =(float)(After_filter[2] *3.3/4096);
ADC_ConvertedValueLocal[3] =(float)(After_filter[3] *3.3/4096);
ADC_ConvertedValueLocal[4] =(float)((uint16_t)ADC_InjectValue[0]*3.3/4096);
ADC_ConvertedValueLocal[5] =(float)((uint16_t)ADC_InjectValue[1]*3.3/4096);
printf("\r\n The current PB0 value = %f V \r\n",ADC_ConvertedValueLocal[0]);
printf("\r\n The current PA3 value = %f V \r\n",ADC_ConvertedValueLocal[1]);
printf("\r\n The current PB1 value = %f V \r\n",ADC_ConvertedValueLocal[2]);
printf("\r\n The current PA4 value = %f V \r\n",ADC_ConvertedValueLocal[3]);
printf("\r\n The current PA6 value = %f V \r\n",ADC_ConvertedValueLocal[4]);
printf("\r\n The current PA1 value = %f V \r\n",ADC_ConvertedValueLocal[5]);
printf("\r\n\r\n");
Delay(0xffffff);
}
如有错误,还望大家不吝赐教!
未经同意,请勿转载!