历史上的今天
今天是:2024年12月04日(星期三)
2019年12月04日 | 基于STM8的ADC读取---STM8-第四章
2019-12-04 来源:eefocus
1. 综诉
想学会如何在STM8上使用ADC这个功能,我们先得了解单片机中ADC究竟是什么。
ADC是模拟信号转成数值信号,单片机只能识别TTL电平,其实就是 1 或者 0 ,但是如果我们给它一个3.3V电压,单片机就无法识别,,若想使用单片机读取出来得时候,它必须将模拟量变成数字量。
2. 关于STM8S103手册的ADC简介

由官方的全英手册可知。
----------------------------------------------------------------------------------------------------------------------------------
STM8中ADC1和ADC2主要功能如下:
10位分辨率
单词和连续的转换模式
可编程的(转换频率的)预分频,fMASTER 可以被分频 2到18
可选择ADC专用外部中断(ADC_ETR)或者定时器触发信号(TRGO)来作为外部触发信号
模拟放大(对于具有VREF引角的型号)
转换结束时可产生中断
灵活的数据对齐方式
ADC输入电压范围:VSSA≤VIN≤VDDA
----------------------------------------------------------------------------------------------------------------------------------
ADC1具有以下拓展功能:
带缓冲的连续转换模式
单次和连续转换的扫描模式
具有上限和下限门槛的模拟看门狗
模拟看门狗时间发生可产生中断
----------------------------------------------------------------------------------------------------------------------------------
3. 例程
3.1 编译环境
我的编译环境是IAR,这款软件是现在STM8的主流平台,比较推荐。不过我打算等到STCubeMX更新出比较方便的版本后再去使用Keil5,因为我在用STM32的时候就是利用Keil5,的确很方便,你们也可以学着用一下。
3.2 主芯片
我的主芯片是STM8S系列中的103,其中STM8S的003、005、和103、105,配置一样(外设和CPU频率,FLASH),在代码相同的情况下均可进行烧写。
3.3 库文件的添加
我们的工程可以在IAR的例程中复制,操作过程:打开STM8S_StdPeriph_Lib(这是一个官方的库文件,下载IAR STM8包的时候就携带,里面有库文件和相对应的例程),将Libraries文件复制到你工程所在的文件下,并将有关于ADC的库文件添加到你的工程列表当中。添加完成后,有可能你会看到一些C文件会有红色的小点报错,这是因为你选的芯片上没有该功能,你需要将其删掉才能不报错。如图。

添加成功后,我们需要将头文件添加进来,头文件的路径存放在 Libraries->STM8S_StdPeriph_Driver->inc中,如图。

3.4 代码编写
STM8SF003这款芯片能用的是5个AD采样通道,分别为为AIN2~AIN6。其一个通道AIN7,但在官方手册中我没找到有对其描述的,感兴趣的朋友可以去察看芯片的英文手册进行研究,也许会找到和我不一样的结果。
在ADC头文件中,将ADC1所有的ADC1_CHANNEL(ADC通道)都进行枚举,以方便调用。
1 /* Enum ----------------------------------------------------------------------*/
2
3 enum ADC1_CHANNEL
4 { //bit 8 7 6 5 4 3 2 1
5
6 ADC1_CHANNEL2 = 0x01, // 0 0 0 0 0 0 0 1
7 ADC1_CHANNEL3 = 0x02, // 0 0 0 0 0 0 1 0
8 ADC1_CHANNEL4 = 0x04, // 0 0 0 0 0 1 0 0
9 ADC1_CHANNEL5 = 0x08, // 0 0 0 0 1 0 0 0
10 ADC1_CHANNEL6 = 0x10 // 0 0 0 1 0 0 0 0
11
12 };
在ADC.C文件中,分为了多个函数,降低他们的耦合性,也方便理解。
首先是ADC中引角的初始化,将你所选通道的引角进行初始化,没有选到的就不进行初始化。
1 /*******************************************************************************
2 * Function Name : MX_ADC_GPIO_Init
3 * Description : ADC GPIO Init
4 * Input : ADC1_CHANNEL
5 * Output : None
6 * Return : None
7 ********************************************************************************/
8
9 void MX_ADC_GPIO_Init(uint8_t ADC1_CHANNEL)
10 {
11 switch(ADC1_CHANNEL)
12 {
13 case ADC1_CHANNEL2: GPIO_Init(ADC_Opt_GPIOC_Port,ADC_channe2_Pin,GPIO_MODE_IN_PU_NO_IT);break;
14 case ADC1_CHANNEL3: GPIO_Init(ADC_Opt_GPIOD_Port,ADC_channe3_Pin,GPIO_MODE_IN_PU_NO_IT);break;
15 case ADC1_CHANNEL4: GPIO_Init(ADC_Opt_GPIOD_Port,ADC_channe4_Pin,GPIO_MODE_IN_PU_NO_IT);break;
16 case ADC1_CHANNEL5: GPIO_Init(ADC_Opt_GPIOD_Port,ADC_channe5_Pin,GPIO_MODE_IN_PU_NO_IT);break;
17 case ADC1_CHANNEL6: GPIO_Init(ADC_Opt_GPIOD_Port,ADC_channe6_Pin,GPIO_MODE_IN_PU_NO_IT);break;
18 }
19
20 }
然后是ADC1的选择通道初始化:ADC连续读取,所选的通道,二分频,外部转换触发,外部触发器不开启,数据右对齐,施密特触发,不开启。(注意:STMS8003中的串口使用了PD5和PD6,与ADC1中通道5、通道6发生冲突,故不可使用。如需使用,请将串口的TXRX引角更改换为其它的引角。)
1 /*******************************************************************************
2 * Function Name : MX_ADC1_CHANNEL_Init
3 * Description : ADC CHANNEL Init
4 * Input : ADC1_CHANNEL
5 * Output : None
6 * Return : None
7 ********************************************************************************/
8
9 void MX_ADC1_CHANNEL_Init(uint8_t ADC1_CHANNEL)
10 {
11 switch(ADC1_CHANNEL)
12 {
13 case ADC1_CHANNEL2:
14 {
15 ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_2,
16 ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE,
17 ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL2, DISABLE);break;
18 }
19 case ADC1_CHANNEL3:
20 {
21 ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_3,
22 ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE,
23 ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL3, DISABLE);break;
24 }
25 case ADC1_CHANNEL4:
26 {
27 ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_4,
28 ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE,
29 ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL4, DISABLE);break;
30 }
31 case ADC1_CHANNEL5:
32 {
33 ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_5,
34 ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE,
35 ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL5, DISABLE);break;
36 }
37 case ADC1_CHANNEL6:
38 {
39 ADC1_Init(ADC1_CONVERSIONMODE_CONTINUOUS, ADC1_CHANNEL_6,
40 ADC1_PRESSEL_FCPU_D2, ADC1_EXTTRIG_TIM, DISABLE,
41 ADC1_ALIGN_RIGHT, ADC1_SCHMITTTRIG_CHANNEL6, DISABLE);break;
42 }
43 }
44 }
这里就是将所有的ADC初始化进行一个统一的一个归类。
1 /*******************************************************************************
2 * Function Name : MX_ADC1_Init
3 * Description : ADC Init
4 * Input : ADC1_CHANNEL
5 * Output : None
6 * Return : None
7 ********************************************************************************/
8 void MX_ADC1_Init(uint8_t ADC1_CHANNEL)
9 {
10 //初始化GPIO
11 MX_ADC_GPIO_Init(ADC1_CHANNEL);
12
13 //初始化ADC1所有寄存器
14 ADC1_DeInit();
15
16 //配置ADC1寄存器中的参数
17 MX_ADC1_CHANNEL_Init(ADC1_CHANNEL);
18
19 //使能ADC1
20 ADC1_Cmd(ENABLE);
21
22 //ADC1转换开始
23 ADC1_StartConversion();
24 }
最后就是数据获取,可以选择直接获取数据,也可以获取十次数据后取平均数。
注意:
ADC获取的值是AD值,需要将其进行代入公式中才能得到电压值。
Vin = (ADC * Vref) / 1024
VCC很明显可以使用万用表先测出来,1024是因为STM8S这款的AD是10位精度。
这里测试的VCC是3.35V,VCC另外一个意思就是单片机的供给电源。
1 /*******************************************************************************
2 * Function Name : MX_ADC1_Get_Data
3 * Description : get VCC data
4 * Input : None
5 * Output : None
6 * Return : fVCC
7 ********************************************************************************/
8 float MX_ADC1_Get_Data(void)
9 {
10 int iADC1_Value;
11 float fVCC;
12
13 //读取转换结果
14 iADC1_Value = ADC1_GetConversionValue();
15 fVCC = (iADC1_Value * 3.350)/1024;
16 return fVCC;
17
18 }
19
20
21 /*******************************************************************************
22 * Function Name : MX_ADC1_Get_Average_Data
23 * Description : Get VCC ten times average data.
24 * Input : None
25 * Output : None
26 * Return : fAverage_VCC
27 ********************************************************************************/
28 float MX_ADC1_Get_Average_Data(void)
29 {
30 int i;
31 float fAverage_VCC = 0.0;
32
33 for(i=0;i<10;i++)
34 {
35 fAverage_VCC += MX_ADC1_Get_Data();
36 }
37 fAverage_VCC /= 10;
38
39 return fAverage_VCC;
40
41 }
将上面需要用到的函数在主函数中调用打印即可。
4. 实验结果
调试仪器:可调式电源,可通过旋钮控制电压的输出大小。
当没有输出电压时,打印的值为0V.

当可调式电源输出的电压值为3.3V,串口助手上打印的也是3.3V。


当可调式电源输出的电压值为24V,串口助手上打印的也是24V。
注意:请不要将24V电源直接通入单片机中,我是自己设置了一条电路进行测试的。ADC的最大输入电压是3.3V,为了安全起见,请不要超过该值。
注意:请不要将24V电源直接通入单片机中,我是自己设置了一条电路进行测试的。ADC的最大输入电压是3.3V,为了安全起见,请不要超过该值。
注意:请不要将24V电源直接通入单片机中,我是自己设置了一条电路进行测试的。ADC的最大输入电压是3.3V,为了安全起见,请不要超过该值。


5. 结尾
对STM8的ADC的说明和引用到这里结束,感谢各位看官的点击。
史海拾趣
|
有归属、没宗派,有尊重、没辈分,有针对、没争竞,有奉献、没名利 相互尊重、友好交流、扩大共识,倡导不同文化间增进了解、相互借鉴 电子工程师,结构工程师,软件工程师,硬件工程师,FPGA研发。另有数码产品,影音视听产品,手机,微型硬盘播放机,R ...… 查看全部问答> |
|
阿牛哥冒着七月的艳阳酷暑,晚上听完国际广播电台的新闻,西瓜荔枝,要看世界杯球赛了。晚上的这场要看,凌晨的那场要听。电视电脑收音机都需要,就是不能影响白天的工作。先说说世界杯比赛,不能在家里看,太影响家人.去哥们马六家看;啤酒不喝 ...… 查看全部问答> |
|
PC104设备在纯DOS下跑程序的问题,虚拟软驱引导的纯DOS和实际安装的DOS有区别不? 如题。 现在程序跑在虚拟软驱引导的纯DOS里面,2000里面用bc31写的程序在2000下跑很流畅,但是到DOS下却非常卡。 想在DOS里面再编译,链接模式选small能通过,但是程序一跑就死,选large能通过,一跑连画面都没有,选其他linker都不成功。何解? ...… 查看全部问答> |
|
wince 是否支持\"微软雅黑\"字体? 看到linux下显示的字体比较漂亮,font文件下看到msyh.ttf,也就是雅黑字体了,EVC下显示的字效果比较一般,要是wince支持msyh.ttf的话,应该怎样添加呢? … 查看全部问答> |
|
紧急求救!!用c开发手机或PDA需要看什么方面的书籍资料!!谢谢各位拉 本人用vc写过应用程序,用c写过mp3的程式,但是c++不太好,在vc里面基本用的都是c,现在想转做手机或pda方面,请教需要看哪些书啊?我看些资料,一般都是在用WinCE或在Linux下开发,哪个发展更好些?不知道这方面薪水待遇怎么样?敢请各位不啬赐教 ...… 查看全部问答> |
|
MSP430FG461X系列的20位地址指针在C语言中如何实现? 我把一个20位的地址0x10000,赋值给一个指针变量时,总是提示超出了0~0xFFFF的范围。 在汇编中这是可以做到的,因为MSP430X提供了MOVA等带A的指令,且工作寄存器都是20位的,可以用于20位的地址传输。就是不知道C语言中怎么实现。 不知是不是有 ...… 查看全部问答> |
|
问题1:一般在主函数中装定时器初值,有必要吗?我好像试了,不装也能正常运行。 问题2:如果在定时器1中关闭了定时器0,用TR0=1再次打开定时器0时,需要重新装定时器0的初值吗?还是TR0=1直接就进入定时器0的中断函数从头开始执行。我试过两次不 ...… 查看全部问答> |
|
一般不会这样做pcduino 可以连GY-86(MPU6050, HMC5883L, MS561101BA)ic吗? 一般不会这样做pcduino 可以连GY-86(MPU6050, HMC5883L, MS561101BA)ic吗?… 查看全部问答> |
|
使用C2000的SPI驱动ADS8332,过去曾成功过,是不同的PCB。然而再次搞它时,却问题多多。 现象:采样转换的通道,采样(转换)时,输入端悬空或稍大的旁路电阻(>10K,再小没试),就有有1V左右的电压。而未采样的通道,采样通道未采样时,没有这个 ...… 查看全部问答> |




