当前位置:   article > 正文

设计分享 | STM32F103RCT6实现AD单通道转化(详细)_stm32f103 ad

stm32f103 ad

wechat:嵌入式工程师成长日记

https://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==&mid=2247484191&idx=1&sn=ceb08f232c86a8da9aa78e6c3fa97e6f&chksm=cf430647f8348f51eb17c199cef1478b6497df065f2024ab94d9e8531259fdfa6df7765ecda3&token=11263168&lang=zh_CN#rdhttps://mp.weixin.qq.com/s?__biz=Mzg4Mzc3NDUxOQ==&mid=2247484191&idx=1&sn=ceb08f232c86a8da9aa78e6c3fa97e6f&chksm=cf430647f8348f51eb17c199cef1478b6497df065f2024ab94d9e8531259fdfa6df7765ecda3&token=11263168&lang=zh_CN#rd

具体功能实现

打开开关后,OLED上显示模拟值(0-4095)和电压值(0-3.3),通过调节电位器,电压值和模拟值都在不断发生变化。与此同时模拟值和电压值是映射关系,一一对应。

STM32F103RCT6原理图

器件

STM32F103RCT6,OLED屏,若干杜邦线 ,电位器,小型螺丝刀(用来旋转电位器),面包板

电位器接线图:(以STM32F103C8T6为例)

前后展示图

刚启动时:

旋转电位器后

知识介绍

ADC介绍

ADC可以将引脚上连续变化的模拟电压转化为数字量,12位ADC是一种逐次逼近型模拟数字转换器,转换时间为1us。其多达18个通道,可测量16个外部和2个内部信号源。

各通道AD转换可以单次,连续,扫描或间断模式执行。最后的数据存储在16为数据寄存器中。

输入电压范围:0-3.3V

转换结果范围:0-4095

转换单元:规则组和注入组

ADC资源:ADC1,ADC2,10个外部输入通道

模拟看门狗

可以自动检测模拟电压范围,可以检测指定通道,当AD值高于设定的上阈值和下阈值时,会自动申请中断,然后交给用户进行处理(多次中断对于系统的程序有一定影响)

作用:对外设信号起监控作用。

比如在做信号处理的时候,对于一些快速的处理和保护,最常规的方法是直接在采集中断中比较设定的最大值和最小值

数据对齐

数据可以左对齐或者是右对齐。对于规则组通道,不需要减去偏移值,因此只有12位有效数据,但是数据寄存器是16位。(一般采用右对齐)

左移一次相当于乘以2

数据校准

ADC有个内置的自校准模式,校准可以大幅减少因内部电容器组的变化而造成的准精度误差,校准期间,每个电容器中都会计算一个误差修正码,用于消除随后的转化中每个电容器产生的误差

建议在每一次上电后都执行一次校准

启动校准前,ADC必须处于关电状态至少超过两个ADC时钟周期

外围电路设计

第一个是利用滑动变阻器,当滑动变阻器往下的时候,电压减小;往上滑时,电压增大。

第二个是利用传感器模块,可以等效为可变电阻,利用串联分压来反映电压变化情况

对应电位器接线图:电位器中间引脚接PA0,左右引脚分别接地和接正极

AD转化

转化步骤:采样,保持,量化,编码

总转化时间:TCONV = 采样时间+12.5个ADC周期

ADC周期是RCC六分频来的14Mhz

最快转化时间:当ADCCLK=14Mhz时,采样时间为1.5个ADC周期

TCONV = 1.5+12.5=14周期=1us

规则组的四种模式

①单次转换非扫描模式:

下图是ADC对通道2进行模数转换,一段时间转换完成后,结果会放在数据寄存器中,同时EOC标志位置1,最后在数据寄存器中读取结果。

(EOC:转换结束位,该位在通道组转换结束时设置,由软件清楚或由读取ADC_DR时清除。

其中0:转换未完成;1:转换完成)

②连续转换非扫描:

在一次转换后不会停止,而是立刻开始下一轮的转换,一直持续下去,直接从数据寄存器中读AD值

优点:开始转换时无需等待,因为一直在转换,无需手动转换。

③单次转换扫描:

扫描模式用到序列列表,每个通道可以任意指定,并且可以重复。但是规则组单次只能传输一个通道的数据,所以为了防止数据被覆盖,需要用DMA对数据进行转运,当通道全部转换完成后,产生EOC信号。

④连续转换扫描:

和非连续扫描模式同理,但是一次转换完成后立刻开始下一轮转换

主函数代码(C语言)KEIL5实现

  1. //main.c
  2. #include "stm32f10x.h"
  3. #include "Delay.h"
  4. #include "OLED.h"
  5. #include "AD.h"
  6. uint16_t ADValue;
  7. float Voltage;
  8. int main(void)
  9. {
  10. OLED_Init();
  11. AD_Init();
  12. OLED_ShowString(1, 1, "ADValue:");
  13. OLED_ShowString(2, 1, "Volatge:0.00V");
  14. while (1)
  15. {
  16. ADValue = AD_GetValue();
  17. Voltage = (float)ADValue/4095 * 3.3;
  18. OLED_ShowNum(1,9,ADValue,4);
  19. OLED_ShowNum(2,9,Voltage,1);
  20. OLED_ShowNum(2,11,(unsigned int)(Voltage*100) % 100,2);
  21. Delay_ms(100);
  22. }
  23. }
  24. //AD.c
  25. #include "stm32f10x.h"
  26. void AD_Init(void)
  27. {
  28. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
  29. RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1,ENABLE);
  30. RCC_ADCCLKConfig(RCC_PCLK2_Div6);
  31. GPIO_InitTypeDef GPIO_InitStructure;
  32. GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AIN;
  33. GPIO_InitStructure.GPIO_Pin=GPIO_Pin_0;
  34. GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
  35. GPIO_Init(GPIOA,&GPIO_InitStructure);
  36. ADC_RegularChannelConfig(ADC1,ADC_Channel_0,1,ADC_SampleTime_55Cycles5);
  37. ADC_InitTypeDef ADC_InitStructure;
  38. ADC_InitStructure.ADC_DataAlign=ADC_DataAlign_Right;
  39. ADC_InitStructure.ADC_ContinuousConvMode=DISABLE;
  40. ADC_InitStructure.ADC_Mode=ADC_Mode_Independent;
  41. ADC_InitStructure.ADC_ExternalTrigConv=ADC_ExternalTrigConv_None;
  42. ADC_InitStructure.ADC_NbrOfChannel=1;
  43. ADC_InitStructure.ADC_ScanConvMode=DISABLE;
  44. ADC_Init(ADC1,&ADC_InitStructure);
  45. ADC_Cmd(ADC1,ENABLE);
  46. ADC_ResetCalibration(ADC1);
  47. while(ADC_GetResetCalibrationStatus(ADC1)==SET);
  48. ADC_StartCalibration(ADC1);
  49. while(ADC_GetCalibrationStatus(ADC1)==SET);
  50. }
  51. uint16_t AD_GetValue()
  52. {
  53. ADC_SoftwareStartConvCmd(ADC1,ENABLE);
  54. while(ADC_GetFlagStatus(ADC1,ADC_FLAG_EOC)==RESET);
  55. return ADC_GetConversionValue(ADC1);
  56. }

问题解答

Q:

为什么在配置ADCCLKConfig要选择六分频

A:

下图是RCC的时钟树,上面写着ADCCLK最大是14Mhz,其中stm32f10x系列的最大时钟频率是72Mhz,也就是最大只能是6分频,72/6=12Mhz,所以虽然始终书上说最大是14Mhz,但是最大可以达到的却只有12Mhz。

Q:

如何在上电时执行一次ADC校准?

A:

代码如下:

ADC_ResetCalibration(ADC1);

while(ADC_GetResetCalibrationStatus(ADC1)==SET);

ADC_StartCalibration(ADC1);

while(ADC_GetCalibrationStatus(ADC1)==SET);

首先进行复位校准,然后获取复位校准状态,然后ADC开始转化,最后获取ADC转化状态

wechat:嵌入式工程师成长日记

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/繁依Fanyi0/article/detail/877298
推荐阅读
相关标签
  

闽ICP备14008679号