STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
目录
- STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解)
- STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明
前面介绍了在Keil5和PlatformIO环境下使用FwLib_STC8, 接下来以STC8H系列为主, 结合demo中的演示用例介绍ADC(模数转换)
STC8G和STC8H的ADC模数转换
STC8G和STC8H的ADC部分在寄存器设置上基本上一致, 但是不同型号对应的通道编号, 通道数量和精度有区别
通道数量和精度
对应STC8G/STC8H的各个系列的通道数量和精度如下.
| 产品线 | ADC 分辨率 | ADC 通道数 |
|---|---|---|
| STC8H1K08 系列 | 10 位 | 9 通道 |
| STC8H1K28 系列 | 10 位 | 12 通道 |
| STC8H3K64S4 系列 | 12 位 | 12 通道 |
| STC8H3K64S2 系列 | 12 位 | 12 通道 |
| STC8H8K64U 系列 | 12 位 | 15 通道 |
| STC8H2K64T 系列 | 12 位 | 15 通道 |
| STC8H4K64TLR 系列 | 12 位 | 15 通道 |
| STC8H4K64TLCD 系列 | 12 位 | 15 通道 |
| STC8H4K64LCD 系列 | 12 位 | 15 通道 |
通道的选择使用寄存器ADC_CONTR的低4位, 对应STC8G/STC8H的各个系列, 这个寄存器的数值对应的通道如下
| STC8H1K28 | STC8H1K08 | STC8H3K64S4 STC8H3K64S2 |
STC8H8K64U STC8H2K64T STC8H4K64TLR |
STC8H4K64TLCD STC8H4K64LCD |
STC8G1K08A | STC8G1K08 STC8G1K08T |
STC8G2K64S4 STC8G2K64S2 |
|
|---|---|---|---|---|---|---|---|---|
| 0000 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 | P3.0/ADC0 | P1.0/ADC0 | P1.0/ADC0 |
| 0001 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 | P3.1/ADC1 | P1.1/ADC1 | P1.1/ADC1 |
| 0010 | P1.2/ADC2 | N/A | P1.2/ADC2 | P5.4/ADC2 | P5.4/ADC2 | P3.2/ADC2 | P1.2/ADC2 | P1.2/ADC2 |
| 0011 | P1.3/ADC3 | N/A | N/A | P1.3/ADC3 | P1.3/ADC3 | P3.3/ADC3 | P1.3/ADC3 | P1.3/ADC3 |
| 0100 | P1.4/ADC4 | N/A | N/A | P1.4/ADC4 | P1.4/ADC4 | P5.4/ADC4 | P1.4/ADC4 | P1.4/ADC4 |
| 0101 | P1.5/ADC5 | N/A | N/A | P1.5/ADC5 | P1.5/ADC5 | P5.5/ADC5 | P1.5/ADC5 | P1.5/ADC5 |
| 0110 | P1.6/ADC6 | N/A | P1.6/ADC6 | P1.6/ADC6 | P6.2/ADC6 | N/A | P1.6/ADC6 | P1.6/ADC6 |
| 0111 | P1.7/ADC7 | N/A | P1.7/ADC7 | P1.7/ADC7 | P6.3/ADC7 | N/A | P1.7/ADC7 | P1.7/ADC7 |
| 1000 | P0.0/ADC8 | P3.0/ADC8 | P0.0/ADC8 | P0.0/ADC8 | P0.0/ADC8 | N/A | P3.0/ADC8 | P0.0/ADC8 |
| 1001 | P0.1/ADC9 | P3.1/ADC9 | P0.1/ADC9 | P0.1/ADC9 | P0.1/ADC9 | N/A | P3.1/ADC9 | P0.1/ADC9 |
| 1010 | P0.2/ADC10 | P3.2/ADC10 | P0.2/ADC10 | P0.2/ADC10 | P0.2/ADC10 | N/A | P3.2/ADC10 | P0.2/ADC10 |
| 1011 | P0.3/ADC11 | P3.3/ADC11 | P0.3/ADC11 | P0.3/ADC11 | P0.3/ADC11 | N/A | P3.3/ADC11 | P0.3/ADC11 |
| 1100 | N/A | P3.4/ADC12 | P0.4/ADC12 | P0.4/ADC12 | P0.4/ADC12 | N/A | P3.4/ADC12 | P0.4/ADC12 |
| 1101 | N/A | P3.5/ADC13 | P0.5/ADC13 | P0.5/ADC13 | P0.5/ADC13 | N/A | P3.5/ADC13 | P0.5/ADC13 |
| 1110 | N/A | P3.6/ADC14 | P0.6/ADC14 | P0.6/ADC14 | P0.6/ADC14 | N/A | P3.6/ADC14 | P0.6/ADC14 |
| 1111 | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref | 1.19Vref |
转换结果的对齐格式
ADC采样的精度实际上是不能设置的, 采样都是用的当前型号的最大精度, 结果存储在[ADC_RES, ADC_RESL]这两个寄存器. 为方便不同场合使用不同精度的结果, 可以将结果设置为左对齐或右对齐.
- 当设置为左对齐时, 可以只取ADC_RES的值(8位), 忽略最后两位.
- 当设置位右对齐时, 根据实际的精度, 可以取ADC_RES的低4位(12位精度)或低2位(10位精度), 加上ADC_RESL得到最终结果.
转换的时间消耗
一个完整的 ADC 转换时间为 = Tsetup + Tduty + Thold + Tconvert
- Tsetup: 转换的通道切换时间, 可以设置为1个或2个ADC时钟周期
- Tduty: 转换的采样时间, 默认是最低的11个ADC时钟, 最高为32个ADC时钟周期
- Thold: 通道选择的保持时间, 可以选择1, 2, 3, 4个ADC时钟周期
- Tconvert: 转换时间是固定的, 10bit精度是10个ADC时钟, 12bit精度是12个ADC时钟
以上的时间单位都是ADC时钟周期, 每个ADC时钟周期占用系统时钟(SYSCLK)的数量是可以设置的, 使用ADCCFG寄存器的低三位, 可以设置为最低2个系统时钟周期到最高32个系统时钟周期
对于转换的最高频率, DS上写了全局限制
- 10 位 ADC 的速度不能高于 500KHz
- 12 位 ADC 的速度不能高于 800KHz
- 转换的采样时间不能小于 10,建议设置为 15
硬件连线
STC8G/STC8H的ADC硬件连线有两种: 带AVcc,AGrnd和不带AVcc,AGrnd
带 AVcc,AGrnd
高端型号STC8H3K64S2系列, 例如会带这两个pin脚, 分别对应的是转换目标的电压参考值和对地参考值. 对于普通使用, 这两个可以直接接到VCC和GND, 连线为
AGrnd -> GND
AVcc -> VCC
AVref -> VCC
Vcc -> VCC
Gnd -> GND
ADC1 -> 采样点
不带 AVcc,AGrnd
低端型号以及STC8G系列不带这两个pin, 只需要接AVref, 采样点与MCU共地连接, 连线为
AVref -> VCC
Vcc -> VCC
Gnd -> GND
ADC1 -> Test voltage
演示用例说明
以下演示用例, 基于 FwLib_STC8, 源代码位于 FwLib_STC8/demo/adc 目录, 可以自行下载或查看. 因为版本演变, 代码可能与仓库中的代码有出入, 以仓库中的最新版本为准.
关于如何运行演示用例, 可以参考前面介绍的Keil C51和VSCode PlatformIO的配置说明
使用ADC1进行8位ADC转换, 主动查询(polling)方式
下面的例子, 使用主动查询的方式每隔0.1秒对P1.1口进行ADC转换, 精度8位, 将结果输出至串口
main.c代码
#include "fw_hal.h"
void main(void)
{
uint8_t res;
// 调整系统频率, 如果使用STC-ISP设定频率, 需要将这行注释掉
SYS_SetClock();
// 用于结果输出
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// 将 ADC1(GPIO P1.1) 设为高阻输入
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
// 使用通道: ADC1
ADC_SetChannel(0x01);
// 设置ADC时钟 = SYSCLK / 2 / (1+1) = SYSCLK / 4
ADC_SetClockPrescaler(0x01);
// 设置结果左对齐, 只需要取值 ADC_RES
ADC_SetResultAlignmentLeft();
// 开启ADC电源
ADC_SetPowerState(HAL_State_ON);
while(1)
{
// 开始转换
ADC_Start();
// 等待两个系统时钟
NOP();
NOP();
// 检查转换结果标志位是否置位
while (!ADC_SamplingFinished());
// 清除结果标志位
ADC_ClearInterrupt();
// 读取结果
res = ADC_RES;
// 通过串口1输出
UART1_TxString("Result: ");
UART1_TxHex(res);
UART1_TxString("\r\n");
// 等待100ms后再次进行转换
SYS_Delay(100);
}
}
使用ADC1进行10位/12位ADC转换, 中断(interrupt)方式
下面的例子, 使用中断的方式对P1.1口进行ADC连续转换, 精度10位(或12位, MCU型号不同精度不同), 每隔0.1秒将结果输出至串口
#include "fw_hal.h"
// 16位变量用于记录转换结果
uint16_t res;
// 处理中断的方法, 使用宏定义保证Keil C51和SDCC的兼容性
INTERRUPT(ADC_Routine, EXTI_VectADC)
{
// 先清除中断位
ADC_ClearInterrupt();
// 结果低8位
res = ADC_RESL;
// 结果高8位
res |= (ADC_RES & 0x0F) << 8;
// 再次启动, 使得ADC连续转换,
ADC_Start();
}
void main(void)
{
// 设置系统频率
SYS_SetClock();
// 结果输出
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// 设置P11高阻输入模式
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
// 使用通道: ADC1
ADC_SetChannel(0x01);
// ADC时钟 = SYSCLK / 2 / (1+15) = SYSCLK / 32
ADC_SetClockPrescaler(0x0F);
// 右对齐, 方便转换为双字节的结果
ADC_SetResultAlignmentRight();
// 开启全局中断和ADC中断
EXTI_Global_SetIntState(HAL_State_ON);
EXTI_ADC_SetIntState(HAL_State_ON);
// 开启ADC电源
ADC_SetPowerState(HAL_State_ON);
// 开始ADC转换
ADC_Start();
while(1)
{
// 转换结果输出
UART1_TxString("Result: ");
UART1_TxHex(res >> 8);
UART1_TxHex(res & 0xFF);
UART1_TxString("\r\n");
SYS_Delay(100);
}
}
使用ADC1, ADC2双通道进行转换, 中断(interrupt)方式
下面介绍一个更实用的例子, 中断形式进行多通道ADC转换, 可以用于无线小车遥控, 双声道音频采样等
#include "fw_hal.h"
// 用于记录当前采样的通道编号
uint8_t pos;
// 记录各通道的采样结果
uint16_t res[2];
// 中断处理方法
INTERRUPT(ADC_Routine, EXTI_VectADC)
{
ADC_ClearInterrupt();
// 记录采样结果
res[pos] = ADC_RESL;
res[pos] |= (ADC_RES & 0x0F) << 8;
// 切换到下一个通道
pos = (pos+1) & 0x1;
if (pos == 0)
{
/**
* 在采样频率较高时, 加上这两句能提高精度. 其机制是切换到开漏模式清除采样口上的残留电压
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_InOut_OD);
GPIO_P1_SetMode(GPIO_Pin_1, GPIO_Mode_Input_HIP);
*/
ADC_SetChannel(0x01);
}
else
{
/**
* Uncomment these lines in high speed ADC
GPIO_P1_SetMode(GPIO_Pin_2, GPIO_Mode_InOut_OD);
GPIO_P1_SetMode(GPIO_Pin_2, GPIO_Mode_Input_HIP);
*/
ADC_SetChannel(0x02);
}
ADC_Start();
}
// 下面的代码和前面的基本上是一样的, 就不详细注释了
void main(void)
{
SYS_SetClock();
// For debug print
UART1_Config8bitUart(UART1_BaudSource_Timer2, HAL_State_ON, 115200);
// Channel: ADC1
ADC_SetChannel(0x01);
// ADC Clock = SYSCLK / 2 / (1+15) = SYSCLK / 32
ADC_SetClockPrescaler(0x0F);
// Right alignment, high 2-bit in ADC_RES, low 8-bit in ADC_RESL
ADC_SetResultAlignmentRight();
// Enable interrupts
EXTI_Global_SetIntState(HAL_State_ON);
EXTI_ADC_SetIntState(HAL_State_ON);
// Turn on ADC power
ADC_SetPowerState(HAL_State_ON);
// Set ADC1(P1.1), ADC2(P1.2) HIP
GPIO_P1_SetMode(GPIO_Pin_1|GPIO_Pin_2, GPIO_Mode_Input_HIP);
// Start ADC
ADC_Start();
while(1)
{
UART1_TxString("Result: ");
UART1_TxHex(res[0] >> 8);
UART1_TxHex(res[0] & 0xFF);
UART1_TxChar(' ');
UART1_TxHex(res[1] >> 8);
UART1_TxHex(res[1] & 0xFF);
UART1_TxString("\r\n");
SYS_Delay(100);
}
}
结束
以上就是STC8H使用FwLib_STC8封装库进行ADC转换的演示用例说明. 在实际使用中, 主动查询(polling)方式下的延时时间精度不高,
如果对采样的时间间隔精度有要求, 建议使用中断的形式.
STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明的更多相关文章
- STM32 USB开发(三) 基于F105RBT6核心板开发的自定义HID收发(FS)
硬件设计 该核心板的USB插口有两个,一个是用于USB Slave的,可以用来做HID设备,把模拟STM32模拟为U盘等:另一个是USB Host设备,可以对插上的U盘的数据进行读写. 图中J2是Mi ...
- ArcSDE SDK For Java二次开发介绍、演示样例
在一个工作中,遇到了须要java后台来查询ArcGIS 中用到的Oracle数据库空间数据,因为对ArcGIS空间数据首次接触,仅仅知道Oracle能够使用ST_GEOMETRY字段存储,例如以下图 ...
- STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(五): SPI驱动nRF24L01无线模块
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(八): NRF24L01无线传输音频(对讲机原型)
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(九): STC8H8K64U模拟USB HID外设
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
- STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)
目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...
随机推荐
- Python用xlrd读取Excel数据到list中再用xlwt把数据写入到新的Excel中
一.先用xlrd读取Excel数据到list列表中(存入列表中的数据如下图所示) import xlrd as xd #导入需要的包 import xlwt data =xd.open_workboo ...
- ABP VNext框架基础知识介绍(2)--微服务的网关
ABP VNext框架如果不考虑在微服务上的应用,也就是开发单体应用解决方案,虽然也是模块化开发,但其集成使用的难度会降低一个层级,不过ABP VNext和ABP框架一样,基础内容都会设计很多内容,如 ...
- mrctf2020_shellcode_revenge(可见符shellcode)!!!!
第一次碰到这种题目,需要用可见符shellcode来做 题目我就不放了,我认为网上大佬会比我说的更加详细 [原创]纯字母shellcode揭秘-软件逆向-看雪论坛-安全社区|安全招聘|bbs.pedi ...
- [BUUCTF]REVERSE——[GUET-CTF2019]re
[GUET-CTF2019]re 附件 步骤: 查壳儿,upx壳,64位程序 upx脱壳儿,然后扔进64位ida,通过检索字符串,找到有关flag的信息定位到关键函数 让我们输入flag,然后满足su ...
- Excel里的格式会自动变成日期或会计专用吗?(Excel技巧集团)
Excel里的格式会自动变成日期或会计专用? 正常情况下当然不会了,可是最近却有很多很多同学问这样的问题,并把这个问题列成了Excel2007和2010的一个Bug,可是小妖同学却从来没遇到过这样的问 ...
- 升级过log4j,却还没搞懂log4j漏洞的本质?
摘要:log4j远程代码漏洞问题被大范围曝光后已经有一段时间了,今天完整讲清JNDI和RMI以及该漏洞的深层原因. 本文分享自华为云社区<升级过log4j,却还没搞懂log4j漏洞的本质?为你完 ...
- 雨课堂自动切换PPT代码
浏览器运行js步骤 原仓库 Podium = {}; Podium.keydown = function(k) { var oEvent = document.createEvent('Keyboar ...
- Spring Boot去掉浏览器默认的叶子图标
在Spring Boot的配置文件application.properites中添加配置项,可以关闭默认的Favicon spring.mvc.favicon.enabled=false
- 【九度OJ】题目1144:Freckles 解题报告
[九度OJ]题目1144:Freckles 解题报告 标签(空格分隔): 九度OJ 原题地址:http://ac.jobdu.com/problem.php?pid=1144 题目描述: In an ...
- 1144 - Ray Gun
1144 - Ray Gun PDF (English) Statistics Forum Time Limit: 2 second(s) Memory Limit: 32 MB You are ...