11回答

2收藏

STM32F0 #02进程帖(三)---STM32F051 ADC单通道数据采集(中断方...

STMCU STMCU 22443 人阅读 | 11 人回复 | 2012-11-15

本帖最后由 fengye5340 于 2012-11-15 15:10 编辑

STM32F0 #02进程帖(三)---STM32F051 ADC单通道数据采集(中断方式实现)
  按照正常的进度,应该是先把ADC方面的内容传上来的,后来因为采用DMA 中断方式-采集多通道数据时,出现了点小问题,一直没有解决好,后只有先放手去解决别的问题了。直到今天,终于解决了那个小问题,ADC数据采集方面的工作进度算是全部完成。
    由于本人以前采用LM系列ARM M3,对STM32不太熟悉,故利用此机会系统的实验了一下STM32的ADC模块。主要包括:
   A--软件查询方式实现的ADC采集(单路)。
   B--中断方式实现的ADC采集(单路)。
   C--DMA软件查询方式实现的ADC采集(单路)。
   D--DMA中断方式实现的ADC采集(多路)。
  实验只是简单的测试一下,并没有进行滤波或只简单的进行了平均,如果用在项目中的话,需要实现更复杂的滤波算法才行(目前流行的滤波算法也有十几种吧)。个人感觉,相比较其他的M3/MO,STM32最大的特色就在于其12位ADC,高精度,高速度。对ADC模块整个STM32F0来说,目前的学习也仅是一点皮毛,只有后续不断的努力,才能更好的应用它。
  下面上一个用ADC中断方式实现的采集进度图和部分代码。

【部分代码】
/*********************************Copyright (c)*********************************                                      
  *                              
fengye5340@163.com
                     
  ******************************************************************************
  * 文件名称:ADC_51R8T6.C
  * 描    述:ADC模块
  * 创 建 者: fengye5340
  * 创建日期: 2012-11-1     
  * 修 改 者:            
  * 修改日期: 2012-11-8   
  * 版    本: v1.0.1
  ******************************************************************************
  * attention
  *
  ******************************************************************************
  */
/*Includes --------------------------------------------------------------------*/
#include  "stm32f0xx.h"
#include  "stm32f0xx_it.h"
#include  "stm32f0xx_adc.h"
#include  "ADC_51R8T6.H"
#include  "UART_51R8T6.H"
#include  "TIMER_51R8T6.H"

/* 类型定义 typedef-----------------------------------------------------------*/
/* 预定义字符     ------------------------------------------------------------*/
/* 宏定义        -------------------------------------------------------------*/
/* 变量定义          ---------------------------------------------------------*/
extern unsigned int  Adc_val = 0;
extern float         Ad_Val =0;
extern float         Ad_Val_Averge[32]={0.0};

/*******************************************************************************
* 函数名称: ADC_GPIO_Init();
* 功能描述: ADC--GPIO输入引脚配置---在此可以设置16路外部输入通道
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void ADC_GPIO_Init(void)
{
     GPIO_InitTypeDef  GPIO_InitStructure;
     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOB, ENABLE);   
     GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_0 ;
     GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AN;
     //GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
     //GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz; // 做输入时不用设置速率
     GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_NOPULL;
     GPIO_Init(GPIOB, &GPIO_InitStructure);
}
/*******************************************************************************
* 函数名称:  ADC_Reset()
* 功能描述:  ADC模块初始化
* 输入参数:  void
* 返回参数:  无
********************************************************************************/
void ADC_Reset(void)
{   
     ADC_InitTypeDef  ADC_InitStructure;
   
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);  //使能ADC1通道时钟
     ADC_DeInit(ADC1);  //复位ADC1,将外设 ADC1 的全部寄存器重设为缺省值
     ADC_StructInit(&ADC_InitStructure);
     ADC_GPIO_Init(); //ADC-GPIO引脚初始化

     /* 配置 ADC1 连续采集模式-12位精度 */
     ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位精度
     ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;     // 连续转换模式
     ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //转换由软件而不是外部触发启动
     ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right; //数据右对齐
     ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward ; //后前:0--18通道
     ADC_Init(ADC1, &ADC_InitStructure);
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    #if TEMP_TEST
        ADC_ChannelConfig(ADC1, ADC_Channel_TempSensor, ADC_SampleTime_55_5Cycles);
      /* 配置ADC1 温度传感器239.5 周期(>2.2us)采样时间
      1--ADC_SampleTime_1_5Cycles                    
      2--ADC_SampleTime_7_5Cycles                    
      3--ADC_SampleTime_13_5Cycles                  
      4--ADC_SampleTime_28_5Cycles                 
      5--ADC_SampleTime_41_5Cycles               
      6--ADC_SampleTime_55_5Cycles                  
      7--ADC_SampleTime_71_5Cycles               
      8--ADC_SampleTime_239_5Cycles
      */
       ADC_TempSensorCmd(ENABLE); //使能内部温度传感器
   #endif
   #if VREF_TEST
       ADC_ChannelConfig(ADC1, ADC_Channel_Vrefint , ADC_SampleTime_55_5Cycles);
       ADC_VrefintCmd(ENABLE);
     #endif
     #if ADC_TEST
       ADC_ChannelConfig(ADC1, ADC_Channel_8 , ADC_SampleTime_55_5Cycles);
     #endif
   #if ADC_IPQ  
         ADC_ChannelConfig(ADC1, ADC_Channel_8 , ADC_SampleTime_239_5Cycles);
         ADC_ITConfig(ADC1, ADC_IT_EOC,ENABLE);//开启ADC转换结束中断。
     #endif
////////////////////////////////////////////////////////////////////////////////////////   
   
   
     ADC_GetCalibrationFactor(ADC1);        // 开始ADC校准
     ADC_Cmd(ADC1, ENABLE);                //  使能指定的ADC1
     
     while(!ADC_GetFlagStatus(ADC1, ADC_FLAG_ADEN));   /* 等待ADC准备好 */
  
     ADC_StartOfConversion(ADC1); //开始温度转换;
}  
/*******************************************************************************
* 函数名称:  Temperature_Test()
* 功能描述:  软件查询方式实现的内部温度传感器测试
* 输入参数:  void
* 返回参数:  无
********************************************************************************/
void Temperature_Test(void)
{
     unsigned int  Temperature = 0;
if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET)
    {
    Delay_Ms(1000);
     Temperature = ADC_GetConversionValue(ADC1);
     Temperature= (1.42 - Temperature*3.3/4096)*1000/4.35 + 25; //计算算法
     printf("The temperature = %d℃ \r\n", Temperature);
      
    }
   
}
/*******************************************************************************
* 函数名称:  Vref_Test()
* 功能描述:  内部参考电压采集测试---没有进行滤波算法处理
* 输入参数:  void
* 返回参数:  无
********************************************************************************/
void Vref_Test(void)
{
     unsigned int  Vref = 0;
    float  Vref_Value =0;
   if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET)
    {
     Delay_Ms(1000);
      Vref=ADC_GetConversionValue(ADC1);
      Vref_Value =(float)Vref/4096*3.3; //计算算法
      printf("The Voltage = %f V \r\n", Vref_Value);
      
    }
   
}
/*******************************************************************************
* 函数名称:  ADC_Test()
* 功能描述:  电压采集测试--没有进行滤波算法处理
* 输入参数:  void
* 返回参数:  无
********************************************************************************/
void ADC_Test(void)
{   
     unsigned int  Adc_value = 0;
     float        Ad_Value =0;
      if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET)
    {
     Delay_Ms(1000);
      Adc_value =ADC_GetConversionValue(ADC1);
      Ad_Value =(float)Adc_value/4096*3.3; //计算算法
      Ad_Value = (1.2*Ad_Value)/1.36;      //精度误差补偿  
      printf("The Voltage = %f V \r\n", Ad_Value);
      
    }

}


//主程序--数据处理部分
while (1)
   {     
      // 1--闪灯程序
         // Led_Test();
   
      
                      // 2--DS18B20模块
      
        // DS18B20_Test();
      
         //3-- ADC内部测温
         #if  TEMP_TEST
              Temperature_Test();
         #endif
         #if  VREF_TEST
            Vref_Test();
       #endif
           #if ADC_TEST
              ADC_Test();
           #endif  
           #if ADC_IPQ
              printf("当前电压是 %f V \r\n", sum);
           #endif  
   
   }
// 中断处理部分

extern unsigned int  Adc_val;
extern float         Ad_Val_Averge[32] ;
extern float         Ad_Val ;
extern float            sum ;
extern void Delay(unsigned int ucout);

/*******************************************************************************
* 函数名称: ADC1_COMP_IRQHandler()
* 功能描述: ADC1中断处理函数
* 输入参数: void
* 返回参数: 无
********************************************************************************/
void ADC1_COMP_IRQHandler(void)  
{   
   static unsigned char index;

    if(ADC_GetFlagStatus(ADC1, ADC_FLAG_EOC) != RESET)
    {   
   
      
     Delay(50000);
      Adc_val =ADC_GetConversionValue(ADC1);
      Ad_Val =(float)Adc_val/4096*3.3; //计算算法
      Ad_Val = (1.2*Ad_Val)/1.36;      //精度误差补偿 --采集内部电压误差大,需进一步修正
         Ad_Val_Averge[index++] = Ad_Val;
      if(index ==31)
     {
            unsigned char i;      
       sum =0;
       for(i = 0; i < 32; i++)
                sum += Ad_Val_Averge;
            sum = sum/32;                           //除以32求平均值     
            index = 0;
      
         }
         ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
         }
}









20121108171418968.jpg (81.34 KB, 下载次数: 58)

串口显示--2

串口显示--2

20121108171410281.jpg (81.67 KB, 下载次数: 66)

串口显示--1

串口显示--1

20121108226.jpg (169.92 KB, 下载次数: 80)

电路实物--2

电路实物--2

20121108227.jpg (202.18 KB, 下载次数: 94)

电路实物-1

电路实物-1
分享到:
回复

使用道具 举报

回答|共 11 个

倒序浏览

沙发

郎爱上羊

发表于 2012-12-22 14:15:45 来自手机 | 只看该作者

沙发啊!这强贴怎没人顶泥?
板凳

fengye5340-272571

发表于 2012-12-22 14:25:19 | 只看该作者

zndz410 发表于 2012-12-22 14:15
沙发啊!这强贴怎没人顶泥?

谢谢,
地板

陈克雄

发表于 2012-12-23 10:59:49 | 只看该作者

还没玩儿过F0的ADC,继续顶一个{:soso_e179:}
5#

fengye5340-272571

发表于 2012-12-24 18:18:07 | 只看该作者

Kite 发表于 2012-12-23 10:59
还没玩儿过F0的ADC,继续顶一个

F0的ADC精度很高,不错
6#

青风

发表于 2013-1-7 11:53:24 | 只看该作者

你这里的浮点运算怎么加进去的?可以支持?
我的淘宝店:http://qfv5.taobao.com/
7#

fengye5340-272571

发表于 2013-1-7 14:45:21 | 只看该作者

青风 发表于 2013-1-7 11:53
你这里的浮点运算怎么加进去的?可以支持?

青风大哥,这里直接加入了浮点,支持没问题的
8#

青风

发表于 2013-1-7 21:59:29 | 只看该作者

f0竟然支持浮点运算~~~~~~,不是吧
我的淘宝店:http://qfv5.taobao.com/
9#

fengye5340-272571

发表于 2013-1-8 09:50:59 | 只看该作者

青风 发表于 2013-1-7 21:59
f0竟然支持浮点运算~~~~~~,不是吧

虽然没有使用外部参考,采集的数据精度还是不错的
10#

树上那只猫

发表于 2013-8-27 22:58:21 | 只看该作者

请教一下QQ哥,这个中断方式实现ADC单通道采集是否可以这样理解:ADC模块一开始就是被初始化函数给打开的,并且按照设定的频率连续不断的转换数据,每次转换完成后产生一个中断,在中断函数中将该数传出去。还是说另外一种理解:由某个中断(例如TIMER)来启动ADC,待ADC转换完之后,将数据传出去。
您需要登录后才可以回帖 注册/登录

本版积分规则

关闭

站长推荐上一条 /3 下一条