1.adc.h文件
//ADC-------------------------------------------------------------------------//
#ifndef __EVAL_ADC_H
#define __EVAL_ADC_H
// Includes ------------------------------------------------------------------//
#include "stm32f10x.h"
#include "eval.h"
// Exported types ------------------------------------------------------------//
typedef struct
{
GPIO_TypeDef* io_gpio_port;
const uint16_t io_gpio_pin;
const uint32_t io_gpio_clk;
const uint8_t adc_channel;
const uint8_t adc_sample;
}ADC_CONFIG_STRUCT;
// Exported constants --------------------------------------------------------//
// Exported macro ------------------------------------------------------------//
// Exported define -----------------------------------------------------------//
#define ADC1_DR_Address ((uint32_t)0x4001244C)
//ADC_DR(ADC规则数据寄存器),偏移量=0x4c ADC1(0x40012400-0x400127ff)
//so ADC1_DR_Address=0x40012400+0x4c
#define ADC_USE_DMA 1//仅使用DMA方式,才能同时进行多路采样
#define ADC_USE_TIM 1//=1定时器触发扫描,=0为连续扫描
//ADC输入 PA0
#define ADCn 3
#define ADC_1 IO1 //信号1
#define ADC_2 IO2 //信号2
#define ADC_3 IO3 //信号3
#if PLATFORM_PKT
#define ADC_1_PIN GPIO_Pin_1
#define ADC_1_GPIO_PORT GPIOA
#define ADC_1_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_1_CHANNEL ADC_Channel_1
#define ADC_1_SAMPLE ADC_SampleTime_239Cycles5
#define ADC_2_PIN GPIO_Pin_0
#define ADC_2_GPIO_PORT GPIOA
#define ADC_2_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_2_CHANNEL ADC_Channel_0
#define ADC_2_SAMPLE ADC_SampleTime_239Cycles5
#define ADC_3_PIN GPIO_Pin_2
#define ADC_3_GPIO_PORT GPIOA
#define ADC_3_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_3_CHANNEL ADC_Channel_2
#define ADC_3_SAMPLE ADC_SampleTime_239Cycles5
#define ADC_4_PIN GPIO_Pin_3
#define ADC_4_GPIO_PORT GPIOA
#define ADC_4_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_4_CHANNEL ADC_Channel_3
#define ADC_4_SAMPLE ADC_SampleTime_239Cycles5
#define ADC_5_PIN GPIO_Pin_1
#define ADC_5_GPIO_PORT GPIOA
#define ADC_5_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_5_CHANNEL ADC_Channel_1
#define ADC_5_SAMPLE ADC_SampleTime_239Cycles5
#define ADC_6_PIN GPIO_Pin_1
#define ADC_6_GPIO_PORT GPIOA
#define ADC_6_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_6_CHANNEL ADC_Channel_1
#define ADC_6_SAMPLE ADC_SampleTime_239Cycles5//ADC_SampleTime_7Cycles5//
#else
#define ADC_1_PIN GPIO_Pin_0
#define ADC_1_GPIO_PORT GPIOA
#define ADC_1_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC_1_CHANNEL ADC_Channel_0
#define ADC_1_SAMPLE ADC_SampleTime_239Cycles5//ADC_SampleTime_7Cycles5//
#endif
//----------------------------------------------------------------------------//
/*
#define ADC16_PIN GPIO_Pin_0
#define ADC16_GPIO_PORT GPIOA
#define ADC16_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC16_CHANNEL ADC_Channel_16//通道16(内部温度)
#define ADC16_SAMPLE ADC_SampleTime_239Cycles5
#define ADC17_PIN GPIO_Pin_0
#define ADC17_GPIO_PORT GPIOA
#define ADC17_GPIO_CLK RCC_APB2Periph_GPIOA
#define ADC17_CHANNEL ADC_Channel_17//通道17(内部1.2v参照电压)
#define ADC17_SAMPLE ADC_SampleTime_239Cycles5
*/
// External variables --------------------------------------------------------//
extern volatile uint16_t ADC_Value[ADCn];
extern uint16_t ADC_ConvertedValue[ADCn];
// extern uint16_t ADC_ConvertedValue[3];
// extern volatile uint8_t adc_dma_simple_ok;
// Exported functions ------------------------------------------------------- //
void ADC_Configuration(void);
uint16_t Get_ADC_Converted_Values(uint8_t channel);
void ADC_Sample_Frequency_Set(u32 Frequency);
#endif
//----------------------------------------------------------------------------//
2.adc.c
/*
规则组采集多路电压时,使用DMA方式,且必须启用扫描模式,否则只能单路采样;
ADC时钟,必须<14MHz;
ADC的速度由2个参数决定,它是采样时间和转换时间之和:
TCONV = 采样时间 + 12.5个ADC时钟周期
采样时间共有8种选择:1.5、7.5、13.5、28.5、41.5、55.5、71.5和239.5;
若ADC的时钟频率=14MHz,则最高ADC的采样频率=14/(12.5+1.5)=1MHz;最低=14/(12.5+239.5)=55.56kHz
若ADC的时钟频率=12MHz,则最低ADC的采样频率=12/(12.5+239.5)=47.62kHz;
*/
// Includes ------------------------------------------------------------------//
#include "adc.h"
#include "ucos_ii.h"
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
#ifdef OS_uCOS_II_H
OS_EVENT* adc_dma_simple_ok;//信号量
#else
volatile uint8_t adc_dma_simple_ok = 0;
#endif
/* Extern variables ----------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
//----------------------------------------------------------------------------//
ADC_CONFIG_STRUCT adc_struct[ADCn] =
{
{ADC_1_GPIO_PORT, ADC_1_PIN, ADC_1_GPIO_CLK, ADC_1_CHANNEL, ADC_1_SAMPLE},
{ADC_1_GPIO_PORT, ADC_1_PIN, ADC_1_GPIO_CLK, ADC_Channel_Vrefint, ADC_1_SAMPLE},
{ADC_1_GPIO_PORT, ADC_1_PIN, ADC_1_GPIO_CLK, ADC_Channel_TempSensor, ADC_1_SAMPLE},
#if 0
{ADC_2_GPIO_PORT, ADC_2_PIN, ADC_2_GPIO_CLK, ADC_2_CHANNEL, ADC_2_SAMPLE},
{ADC_3_GPIO_PORT, ADC_3_PIN, ADC_3_GPIO_CLK, ADC_3_CHANNEL, ADC_3_SAMPLE},
{ADC_4_GPIO_PORT, ADC_4_PIN, ADC_4_GPIO_CLK, ADC_4_CHANNEL, ADC_4_SAMPLE},
{ADC_5_GPIO_PORT, ADC_5_PIN, ADC_5_GPIO_CLK, ADC_5_CHANNEL, ADC_5_SAMPLE},
{ADC_6_GPIO_PORT, ADC_6_PIN, ADC_6_GPIO_CLK, ADC_6_CHANNEL, ADC_6_SAMPLE},
#endif
};
uint16_t ADC_ConvertedValue[ADCn] =
{
0
};
//----------------------------------------------------------------------------//
void ADC_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
ADC_InitTypeDef ADC_InitStructure;
uint8_t i;
// Enable ADC1 clock
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1 | RCC_APB2Periph_AFIO, ENABLE);
//ADC管脚GPIO配置
for(i = 0; i < ADCn; i++)
{
RCC_APB2PeriphClockCmd(adc_struct[i].io_gpio_clk, ENABLE);
GPIO_InitStructure.GPIO_Pin = adc_struct[i].io_gpio_pin;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_Init(adc_struct[i].io_gpio_port, &GPIO_InitStructure);
}
//
#if ADC_USE_DMA
{
DMA_InitTypeDef DMA_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE); //Enable DMA1 clock
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = DMA1_Channel1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
DMA_DeInit(DMA1_Channel1);
DMA_InitStructure.DMA_PeripheralBaseAddr = ADC1_DR_Address; //指定外设基址
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) ADC_ConvertedValue; //指定内存基址
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC; //外设为源(外设->内存)
DMA_InitStructure.DMA_BufferSize = ADCn; //设置缓冲区大小
DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable; //外设地址固定(ADC结果)
DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable; //内存地址自增(存储)
DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_HalfWord; //外设传输单位:16bit
DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_HalfWord; //内存传输单位:16bit
DMA_InitStructure.DMA_Mode = DMA_Mode_Circular; //循环模式
DMA_InitStructure.DMA_Priority = DMA_Priority_High; //选择DMA优先级
DMA_InitStructure.DMA_M2M = DMA_M2M_Disable; //MA传输类型,不是内存到内存
DMA_Init(DMA1_Channel1, &DMA_InitStructure);
DMA_Cmd(DMA1_Channel1, ENABLE);
}
#endif
//内部温度对应16通道,无引脚,只需开启adc时钟即可.
//内部参考电压对应17通道,无引脚,只需开启时钟.
ADC_InitStructure.ADC_Mode = ADC_Mode_Independent; //ADC独立模式
ADC_InitStructure.ADC_ScanConvMode = DISABLE; //扫描模式
ADC_InitStructure.ADC_ContinuousConvMode = ENABLE; //连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_None;//不使用外部触发
ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //采集数据右对齐
ADC_InitStructure.ADC_NbrOfChannel = 1; //转换组的通道数目
#if ADC_USE_DMA
ADC_InitStructure.ADC_ScanConvMode = ENABLE; //必须启用扫描模式
ADC_InitStructure.ADC_NbrOfChannel = ADCn; //转换组的通道数目
#endif
#if ADC_USE_TIM//使用定时器触发
ADC_InitStructure.ADC_ContinuousConvMode = DISABLE; //不使用连续转换
ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T2_CC2;//定时器2触发
#endif
ADC_Init(ADC1, &ADC_InitStructure);
RCC_ADCCLKConfig(RCC_PCLK2_Div8);//配置ADC时钟,为PCLK2的6分频,即12MHz,时钟必须<14MHz;
ADC_TempSensorVrefintCmd(ENABLE);//使能温度传感器
#if ADC_USE_DMA
for(i = 0; i < ADCn; i++)
{
ADC_RegularChannelConfig(ADC1, adc_struct[i].adc_channel, i + 1, adc_struct[i].adc_sample);
}
DMA_ITConfig(DMA1_Channel1, DMA_IT_TC, ENABLE);
ADC_DMACmd(ADC1, ENABLE);
#else
ADC_RegularChannelConfig(ADC1, adc_struct[0].adc_channel, 1, adc_struct[0].adc_sample);
#endif
ADC_Cmd(ADC1, ENABLE);
//使能ADC1的复位校准寄存器
ADC_ResetCalibration(ADC1);
while(ADC_GetResetCalibrationStatus(ADC1));
//开始校准ADC1
ADC_StartCalibration(ADC1);
while(ADC_GetCalibrationStatus(ADC1));
#if ADC_USE_TIM
ADC_ExternalTrigConvCmd(ADC1, ENABLE);//使能ADC经外部触发启动转换功能
#endif
#if !ADC_USE_TIM
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动上面设置好的一个通道,进行转换
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待EOC置位
#endif
}
//----------------------------------------------------------------------------//
void ADC_Sample_Frequency_Set(u32 Frequency)
{
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
TIM_Cmd(TIM2, DISABLE); //先停止TIM2时钟
TIM_TimeBaseStructure.TIM_Period = 3599; //APR寄存器
TIM_TimeBaseStructure.TIM_Prescaler = 3999;//3;//(20,000 / Frequency - 1);//预分频值,用来调整频率,分频系数=1000khz/(prescaler+1)
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //时钟分频
TIM_TimeBaseStructure.TIM_RepetitionCounter = 0x00; //溢出指定(+1)次数后产生中断
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable;
TIM_OCInitStructure.TIM_Pulse = 1; //!!必须<=TIM_Period!!
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low;//
TIM_OC2Init(TIM2, &TIM_OCInitStructure);
TIM_Cmd(TIM2, ENABLE);
}
//----------------------------------------------------------------------------//
#if !ADC_USE_TIM
#define VOLTAGE_OVER_SAMPLING 0//过采样2^N次
uint16_t Get_ADC_Converted_Values(uint8_t channel)//提取通道电压
{
uint32_t adc_value = 0;
uint16_t i = 0;
//通道n,规则组序号1,。。。
ADC_RegularChannelConfig(ADC1, adc_struct[channel].adc_channel, 1, adc_struct[channel].adc_sample);
ADC_Cmd(ADC1, ENABLE); //使能ADC1
for(i = 0; i < (1<<VOLTAGE_OVER_SAMPLING); i++)
{
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动上面设置好的一个通道,进行转换
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待EOC置位
adc_value += ADC_GetConversionValue(ADC1); //把数据寄存器的值读走
}
return (adc_value>>VOLTAGE_OVER_SAMPLING);
}
#endif
//----------------------------------------------------------------------------//
uint16_t Get_ADC_Converted_Values0(uint8_t channel)//提取指定通道电压
{
ADC_RegularChannelConfig(ADC1, adc_struct[channel].adc_channel, 1, adc_struct[channel].adc_sample);
ADC_Cmd(ADC1, ENABLE);
#if !ADC_USE_DMA
ADC_SoftwareStartConvCmd(ADC1, ENABLE); //启动上面设置好的一个通道,进行转换
while(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) == RESET);//等待EOC置位
#endif
return ADC_GetConversionValue(ADC1); //把数据寄存器的值读走
}
//----------------------------------------------------------------------------//
void DMA1_Channel1_IRQHandler()
{
if(DMA_GetITStatus(DMA1_IT_TC1) != RESET)
{
#ifdef OS_uCOS_II_H
OSSemPost(adc_dma_simple_ok);
#else
adc_dma_simple_ok = 1;
#endif
DMA_ClearITPendingBit(DMA1_IT_TC1);
}
}
//----------------------------------------------------------------------------//
3.主程序中调用
extern OS_EVENT* adc_dma_simple_ok; //定义信号量
3.1.信号量初始化
adc_dma_simple_ok = OSSemCreate(0);
3.2.等待DMA中断,接收信号量
OSSemPend(adc_dma_simple_ok, 0, &err);
if(err == OS_NO_ERR)
{
//adc_dma_simple_ok = 0;
sprintf(tmp_str, "电压=%d,%d,%d,%drn", ADC_ConvertedValue[0],ADC_ConvertedValue[1],ADC_ConvertedValue[2],adc_tmp);
USB_Put_Str_PC((uint8_t *)tmp_str);
}