目录

前面介绍了在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介绍和演示用例说明的更多相关文章

  1. STM32 USB开发(三) 基于F105RBT6核心板开发的自定义HID收发(FS)

    硬件设计 该核心板的USB插口有两个,一个是用于USB Slave的,可以用来做HID设备,把模拟STM32模拟为U盘等:另一个是USB Host设备,可以对插上的U盘的数据进行读写. 图中J2是Mi ...

  2. ArcSDE SDK For Java二次开发介绍、演示样例

    在一个工作中,遇到了须要java后台来查询ArcGIS 中用到的Oracle数据库空间数据,因为对ArcGIS空间数据首次接触,仅仅知道Oracle能够使用ST_GEOMETRY字段存储,例如以下图 ...

  3. STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  4. STC8H开发(六): SPI驱动ADXL345三轴加速度检测模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  5. STC8H开发(七): I2C驱动MPU6050三轴加速度+三轴角速度检测模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  6. STC8H开发(五): SPI驱动nRF24L01无线模块

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  7. STC8H开发(八): NRF24L01无线传输音频(对讲机原型)

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  8. STC8H开发(九): STC8H8K64U模拟USB HID外设

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

  9. STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)

    目录 STC8H开发(一): 在Keil5中配置和使用FwLib_STC8封装库(图文详解) STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库(图文详解) ST ...

随机推荐

  1. Oracle命名规则

    1.长度不能超过三十个字符 2. 不要使用Oracle关键字 比如:id  name  table 3. 不能使用数字开头 包含:数字  字母  下划线 美元符号 4.  建议用 英文单词,不要去用中 ...

  2. 一文详解面试常考的TopK问题

    首发公众号:bigsai ,转载请附上本文链接 前言 hello,大家好,我是bigsai哥哥,好久不见,甚是想念哇! 今天给大家分享一个TOPK问题,不过我这里不考虑特别大分布式的解决方案,普通的一 ...

  3. UVA12412 师兄帮帮忙 A Typical Homework (a.k.a Shi Xiong Bang Bang Mang) 题解

    Content 自己去看题面去. Solution 算不上很繁琐的一道大模拟. 首先,既然是输出 \(0\) 才退出,那么在此之前程序应当会执行菜单 \(\Rightarrow\) 子操作 \(\Ri ...

  4. LuoguB2104 矩阵加法 题解

    Content 给定两个 \(n\times m\) 的矩阵 \(A,B\),求 \(C=A+B\). 数据范围:\(1\leqslant n,m\leqslant 100\). Solution 我 ...

  5. JS获取客户的IP地址

    这里使用的是第三方的获取方式,重要项目建议不要用,因为你不知道搜狐未来会不会倒闭,,, 搜狐IP地址查询接口(默认GBK):http://pv.sohu.com/cityjson 搜狐IP地址查询接口 ...

  6. JAVA从字符串中提取纯数字

    /** * 从字符串中提取纯数字 * @param str * @return */ public static String getNumeric(String str) { String regE ...

  7. 【LeetCode】851. Loud and Rich 解题报告(Python)

    [LeetCode]851. Loud and Rich 解题报告(Python) 标签(空格分隔): LeetCode 作者: 负雪明烛 id: fuxuemingzhu 个人博客: http:// ...

  8. 【LeetCode】331. Verify Preorder Serialization of a Binary Tree 解题报告(Python)

    [LeetCode]331. Verify Preorder Serialization of a Binary Tree 解题报告(Python) 标签: LeetCode 题目地址:https:/ ...

  9. 【LeetCode】450. Delete Node in a BST 解题报告 (Python&C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 迭代 日期 题目地址:https://leetcode ...

  10. POJ 3126:Prime Path(素数+BFS)

    The ministers of the cabinet were quite upset by the message from the Chief of Security stating that ...