1.问题描述

最近在调试电机驱动,刚好写到电压采集这一部分,板子的主控是STM32F040K6T6.用到了ADC,使用非DMA方式。刚开始读取到的值全部是0,然后程序卡死,我在使用万用表测IO口电压后,排除了硬件问题。网上找了一堆资料,得到的解决方案有这么几种:

1.说是官方的库函数ADC_ChannelConfig()有问题,需要把“|”符号去掉的,代码如下,修改之后,依旧卡死

void ADC_ChannelConfig(ADC_TypeDef* ADCx, uint32_t ADC_Channel, uint32_t ADC_SampleTime)
{uint32_t tmpreg = 0;/* Check the parameters */assert_param(IS_ADC_ALL_PERIPH(ADCx));assert_param(IS_ADC_CHANNEL(ADC_Channel));assert_param(IS_ADC_SAMPLE_TIME(ADC_SampleTime));/* Configure the ADC Channel */ADCx->CHSELR |= (uint32_t)ADC_Channel;  //把这里的或运算符去掉/* Clear the Sampling time Selection bits */tmpreg &= ~ADC_SMPR1_SMPR;/* Set the ADC Sampling Time register */tmpreg |= (uint32_t)ADC_SampleTime;/* Configure the ADC Sample time register */ADCx->SMPR = tmpreg ;
}

2. 在配置中加入:ADC_InitStructure.ADC_ExternalTrigConv =ADC_ExternalTrigConv_T1_TRGO;这一句,代码如下,测试没用

  ADC_StructInit(&ADC_InitStructure);ADC_DeInit(ADC1); //复位并初始化ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b;           ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;    ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None;       ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_TRGO; //据说加入这句ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;                                                          ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;    

3.在while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_ADRDY));这一句后面加入标志位清除函数,如下,测试之后,对我没用

  while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_ADRDY));  //启动就绪标志ADC_ClearFlag(ADC1, ADC_FLAG_EOC); //!!!加入这一句

4.有博主在重新命名了GPIO 结构体的名字后解决问题,如下面的代码,我尝试了一下,也没有解决。

void  Adc_Init(void)
{   ADC_InitTypeDef ADC_InitStructure; //GPIO_InitTypeDef GPIO_InitStructure; //原来在其他地方多次使用GPIO_InitStructureGPIO_InitTypeDef GPIO_ADC;  //将GPIO_InitStructure改为GPIO_ADC
}

2.解决办法

我这里两种情况都出现了。卡死是首要问题,先解决卡死问题,上会卡死的代码:

//配置部分
void  Adc_Init(void)
{   ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_ADC;/*ADC以及GPIO时钟使能*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB,ENABLE);//GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE );    //使能ADC1通道时钟RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);   /*PA5 作为模拟通道输入引脚*/                  GPIO_ADC.GPIO_Pin = GPIO_Pin_5; //PA5GPIO_ADC.GPIO_Mode = GPIO_Mode_AN;       //模拟输入引脚//PIO_ADC.GPIO_Speed = GPIO_Speed_50MHz;GPIO_ADC.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉GPIO_Init(GPIOA, &GPIO_ADC);  /*ADC配置*/ADC_StructInit(&ADC_InitStructure);ADC_DeInit(ADC1); //复位并初始化ADC_InitStructure.ADC_Resolution = ADC_Resolution_12b; //12位分辨率            ADC_InitStructure.ADC_ContinuousConvMode = ENABLE;    //连续转换模式ADC_InitStructure.ADC_ExternalTrigConvEdge = ADC_ExternalTrigConvEdge_None; //外部触发无     //ADC_InitStructure.ADC_ExternalTrigConv = ADC_ExternalTrigConv_T1_TRGO; //???ADC_InitStructure.ADC_DataAlign = ADC_DataAlign_Right;   //右端对齐                                                       ADC_InitStructure.ADC_ScanDirection = ADC_ScanDirection_Upward;    //浏览模式ADC_Init(ADC1,&ADC_InitStructure); //初始化ADCADC_GetCalibrationFactor(ADC1); //校验ADC_Cmd(ADC1,ENABLE); //使能//ADC通道配置ADC_ChannelConfig(ADC1,ADC_Channel_5,ADC_SampleTime_55_5Cycles); //IN5/*程序卡在了这里*/while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_ADRDY));  //启动就绪标志ADC_ClearFlag(ADC1, ADC_FLAG_EOC);
}

分析流程:初始化时钟(OK)->GPIO配置(OK)->ADC配置(OK)->ADC启动(?)->ADC转换(卡死) ,问题出在ADC启动之后,转换并未开始,通过打印调试(记住keil不支持F0系列的Debug),发现程序卡死在while(!ADC_GetFlagStatus(ADC1,ADC_FLAG_ADRDY));找到数据手册ADC配置一节,有几个细节引起了我的注意。

请看这句: 对 于 以 下 的 这 些 位 ADC_IER、ADC_CFGRi、ADC_SMPR、ADC_TR、ADC_CHSELR 和 ADC_CCR 寄存器,软件必须在 ADC 开启 (ADEN = 1) 且无转换期间 (ADSTART = 0) 的情况 下才能进行改写。我们来看下ADC_CHSELR这个寄存器,它是选择ADC通道的,他的意思是,我们只能在开启ADC后再选择通道,列个表说明一下这几个寄存器的名字。所以问题就出在这里:我们必须先配置,启动ADC,再操作这些寄存器,不然就会使ADC进入未知状态。

综上,第一个问题解决,正确代码思路如下:

Adc_Init();//配置并启动ADC
Get_Value();//转换
void  Adc_Init(void)
{   ADC_InitTypeDef ADC_InitStructure; GPIO_InitTypeDef GPIO_ADC;/*ADC以及GPIO时钟使能*/RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA|RCC_AHBPeriph_GPIOB,ENABLE);//GPIORCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE );    //使能ADC1通道时钟RCC_ADCCLKConfig(RCC_ADCCLK_PCLK_Div4);   //设置ADC分频因子6 72M/6=12,ADC最大时间不能超过14M/*PA4,5 作为模拟通道输入引脚*/                  GPIO_ADC.GPIO_Pin = GPIO_Pin_5|GPIO_Pin_4; //PA4与PA5GPIO_ADC.GPIO_Mode = GPIO_Mode_AN;     //模拟输入引脚GPIO_ADC.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉GPIO_Init(GPIOA, &GPIO_ADC);   /*PB0 作为模拟通道输入引脚*/                  GPIO_ADC.GPIO_Pin = GPIO_Pin_0; //PA4与PA5GPIO_ADC.GPIO_Mode = GPIO_Mode_AN;      //模拟输入引脚GPIO_ADC.GPIO_PuPd = GPIO_PuPd_NOPULL; //无上下拉GPIO_Init(GPIOB, &GPIO_ADC);  /*ADC配置*/ADC_StructInit(&ADC_InitStructure);ADC_DeInit(ADC1); //复位并初始化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;    //浏览模式ADC_Init(ADC1,&ADC_InitStructure); //初始化ADCADC_GetCalibrationFactor(ADC1); //校验ADC_VrefintCmd(ENABLE);ADC_Cmd(ADC1,ENABLE); //使能
}
float Get_Value(void)
{u32 Value= 0;u8 index;ADC_ChannelConfig(ADC1,ADC_Channel_5,ADC_SampleTime_55_5Cycles); //选择通道ADC_StartOfConversion(ADC1);        //启动转换,注意不是启动ADC,而是启动ADC转换for(index = 0;index<8;index++)  //均值滤波{while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC) == RESET);ADC_ClearFlag(ADC1, ADC_FLAG_EOC);Get_Value+=  ADC_GetConversionValue(ADC1);}Result_Voltage = Result_Voltage>>3; //求平均值return (float)((Get_Value/4096.00)*3.3);  //计算电压值
}

关于第二个问题,黑脸,忘记在4096后面加小数点了,4096是整型,我的的ADC为分子,就会得到小数,刚好运气不好,小数为0.34---,于是计算机取整,默认它就是0,后面的我就不用讲了。粗心害人呀。

 return (float)(((Result_Voltage/4096)*3.3*(39+2.2))/2.2);  //错误return (float)(((Result_Voltage/4096.00)*3.3*(39+2.2))/2.2);  //正确

【STM32F042】ADC卡死,ADC一直为0,ADC配置的坑相关推荐

  1. 如何利用单片机的ADC模块(或者独立的ADC芯片)得到接入ADC管脚上的实际电压值?

    这个问题,是第一次接触ADC时候,大家都会遇到的问题. 会读到什么值 单片机会读到什么值?需要看一个特性,就是几位的ADC,在手册上就会给出,例如,STM32的ADC是12位的.另外,还有8位,10位 ...

  2. STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及傻瓜式解析)

    STM32使用ADC+DMA进行多通道模拟量采集 (踩坑及通俗解析) ​ 利用STM32的片上外设可采集多个模拟量(如传感器数值),并在嵌入式程序中使用.如果只使用了一个通道,用时令ADC转换而后读取 ...

  3. 什么是电子计算机NXI并行线,并行ADC的原理是什么?流水线ADC与其它ADC有何区别?...

    为增进大家对ADC的认识和了解,本文将基于两方面对ADC予以介绍:1.什么是并行ADC,并行ADC的基本原理是什么?2.流水线ADC与其它ADC有何区别.如果你对ADC具有兴趣,本文无疑是您的福利.通 ...

  4. creo 3.0计算机配置,Creo 3.0 Parametric 配置选项文件使用说明

    最近安装了Creo Parametric 3.0 F000,其配置选项与Creo Parametric 2.0有部分更新,研究PTC Creo® 3.0 Parametric 配置选项configop ...

  5. android——记录从android studio2.3升级到android studio3.0版本遇到的坑

    今天手贱,升级到了AS3.0 ,结果遇到了坑.提示需要将gradle升级到3.5及以上版本.然后就开始动手升级.其中遇到了各种困难.首先,就是需要FQ下载.其次,就是配置后提示jcenter下的一个p ...

  6. Boost1.62.0 + VS2015 配置

    Boost1.62.0 + VS2015 配置 标签: 

  7. APACHE 2.2.8+TOMCAT6.0.14配置负载均衡

    作者: jiake0504  链接:http://jiake0504.javaeye.com/blog/265000  发表时间: 2008年11月10日 声明:本文系JavaEye网站发布的原创博客 ...

  8. python详细安装教程3.7.0-python 3.7.0 安装配置方法图文教程

    本文记录了python 3.7.0 安装配置方法,供大家参考,具体内容如下 S1登入Python官网下载网址 S2下载后缀为exe的可执行文件,并根据自己电脑/主机的系统选择32位还是64位. 双击选 ...

  9. windows+VS2017+opencv4.1.0环境配置

    网上有很多详细的教程,这里我这罗列一些需要注意的事项: windows+VS2017+opencv4.1.0 环境配置注意事项 1.添加系统环境变量 在添加系统环境变量的时候,至于是选vc14还是vc ...

最新文章

  1. MySQL主从的一致性校验及修复
  2. c#用webkit内核支持html5
  3. Java 实现单例模式的 9 种方法
  4. python 结束子线程并保证工作完成_python3中在线程中结束工作进程的方法
  5. 《C++标准程序库》笔记之二
  6. 15原型模式(Prototype)
  7. [PyTorch] 卷积函数 and 解卷积函数
  8. echart多个柱状图 设置y轴显示_Origin做多因子柱状图
  9. 黑客帝国动态特效代码
  10. 接口测试工具apipost关于post请求
  11. vue获取微信登陆权限_vue微信授权登录
  12. 用【花生壳】穿透内网主机运用dai搭建校园实现访问外网访问只有学校内网的教务系统
  13. 2022牛客寒假训练营1-K冒险公社
  14. [转帖]Photoshop鼻青脸肿效果的照片恶搞教程
  15. Python——文件读写
  16. 用计算机浮点数表示法计算,计算机组成原理第4章浮点数运算方法ppt课件
  17. 因补助低!名校博士生开展大规模学术罢工行动!多校濒临崩溃
  18. 录像机前面板指示灯显示详解
  19. arduino串口监视器显示nan_【Arduino】初识Arduino
  20. java 留言板源码,JSP留言板的JSP源码操作实施

热门文章

  1. 更新Windows11后无法使用Windows安全中心的解决方案
  2. STM32标准库下载教程
  3. HaaS600物联网开发板学习笔记(二)---轻应用方式让LED闪烁起来
  4. c/c++一百道小程序
  5. 扩展坞可以把手机投到显示器吗_手机 篇二:给电脑配的 Type-C拓展坞 没想到手机也能用...
  6. SharePoint Oauth和服务器到服务器(S2S)身份验证概述
  7. 比较探讨T-Sql(二)
  8. 太阳系外发现首颗适合地球生命居住星球(图)
  9. 公众号内容拓展学习笔记(2021.5.5)
  10. python模块名功能明和别名_Python周末练习