查看: 21445|回复: 11

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

[复制链接]
  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-11-15 15:09:25 | 显示全部楼层 |阅读模式
    分享到:
    本帖最后由 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);
             }
    }









    串口显示--2

    串口显示--2

    串口显示--1

    串口显示--1

    电路实物--2

    电路实物--2

    电路实物-1

    电路实物-1
    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2017-8-10 17:40
  • 签到天数: 641 天

    连续签到: 2 天

    [LV.9]以坛为家II

    发表于 2012-12-22 14:15:45 来自手机 | 显示全部楼层
    沙发啊!这强贴怎没人顶泥?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-12-22 14:25:19 | 显示全部楼层
    zndz410 发表于 2012-12-22 14:15
    沙发啊!这强贴怎没人顶泥?

    谢谢,
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-26 01:52
  • 签到天数: 120 天

    连续签到: 1 天

    [LV.7]常住居民III

    发表于 2012-12-23 10:59:49 | 显示全部楼层
    还没玩儿过F0的ADC,继续顶一个{:soso_e179:}
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2012-12-24 18:18:07 | 显示全部楼层
    Kite 发表于 2012-12-23 10:59
    还没玩儿过F0的ADC,继续顶一个

    F0的ADC精度很高,不错
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-1-7 11:53:24 | 显示全部楼层
    你这里的浮点运算怎么加进去的?可以支持?
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2013-1-7 14:45:21 | 显示全部楼层
    青风 发表于 2013-1-7 11:53
    你这里的浮点运算怎么加进去的?可以支持?

    青风大哥,这里直接加入了浮点,支持没问题的
    回复 支持 反对

    使用道具 举报

    该用户从未签到

    发表于 2013-1-7 21:59:29 | 显示全部楼层
    f0竟然支持浮点运算~~~~~~,不是吧
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2016-8-25 12:42
  • 签到天数: 692 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2013-1-8 09:50:59 | 显示全部楼层
    青风 发表于 2013-1-7 21:59
    f0竟然支持浮点运算~~~~~~,不是吧

    虽然没有使用外部参考,采集的数据精度还是不错的
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    2013-11-13 09:14
  • 签到天数: 19 天

    连续签到: 1 天

    [LV.4]偶尔看看III

    发表于 2013-8-27 22:58:21 | 显示全部楼层
    请教一下QQ哥,这个中断方式实现ADC单通道采集是否可以这样理解:ADC模块一开始就是被初始化函数给打开的,并且按照设定的频率连续不断的转换数据,每次转换完成后产生一个中断,在中断函数中将该数传出去。还是说另外一种理解:由某个中断(例如TIMER)来启动ADC,待ADC转换完之后,将数据传出去。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

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



    手机版|小黑屋|与非网

    GMT+8, 2024-11-25 03:52 , Processed in 0.197561 second(s), 34 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.