STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明

发布者:数据梦想最新更新时间:2022-06-09 来源: eefocus关键字:模数转换  ADC 手机看文章 扫描二维码
随时随地手机看文章

前面介绍了在Keil5和PlatformIO环境下使用FwLib_STC8, 接下来以STC8H系列为主, 结合demo中的演示用例介绍ADC(模数转换)


STC8G和STC8H的ADC模数转换

STC8G和STC8H的ADC部分在寄存器设置上基本上一致, 但是不同型号对应的通道编号, 通道数量和精度有区别


通道数量和精度

对应STC8G/STC8H的各个系列的通道数量和精度如下.

image.png

通道的选择使用寄存器ADC_CONTR的低4位, 对应STC8G/STC8H的各个系列, 这个寄存器的数值对应的通道如下

image.png

转换结果的对齐格式

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("rn");

        // 等待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("rn");

        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("rn");

        SYS_Delay(100);

    }

}


结束

以上就是STC8H使用FwLib_STC8封装库进行ADC转换的演示用例说明. 在实际使用中, 主动查询(polling)方式下的延时时间精度不高,

如果对采样的时间间隔精度有要求, 建议使用中断的形式.接:

关键字:模数转换  ADC 引用地址:STC8H开发(三): 基于FwLib_STC8的模数转换ADC介绍和演示用例说明

上一篇:STC8H开发(四): FwLib_STC8 封装库的介绍和注意事项
下一篇:STC8H开发(二): 在Linux VSCode中配置和使用FwLib_STC8封装库

推荐阅读最新更新时间:2024-11-13 01:29

STM32HAL库ADC实验(三)——中断查询法
(模式:连续模式 非扫描模式) 使能ADC全局中断 参考视频 【STM32】超简单的开发方法-基础篇(ADC模数转换) https://player.bilibili.com/player.html?aid=715022775 参考文章:https://blog.csdn.net/as480133937/article/details/99627062 设置定时 可以看我这篇文章 配置玩定时器之后 配置ADC 使能ADC中断 基本函数: • HAL_ADC_Start_IT(&hadcx);       //中断轮询模式开启ADC • HAL_ADC_Stop_IT() //中断轮询模式停
[单片机]
STM32HAL库<font color='red'>ADC</font>实验(三)——中断查询法
STM32H实现ADC采集
实现参考STM32F7实现ADC采集(软件触发+轮询) 注意,在CubeMX中,void SystemClock_Config(void)多了如下代码: RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0}; PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_ADC|RCC_PERIPHCLK_CKPER; PeriphClkInitStruct.CkperClockSelection = RCC_CLKPSOURCE_HSE; PeriphClkInitStruct.AdcClockSelection
[单片机]
STM32H实现<font color='red'>ADC</font>采集
STM32F103ZET6 — ADC
介绍 STM32F103ZET6 拥有12位ADC,是一种逐次逼近型模拟数字转换器。 12bits ADC 代表了 ADC 的转换精度。存在输入参考电压的情况下,ADC 将模拟信号经信号线输入,进行模拟信号的采样,再将采样后的数字信号存放于数据寄存器中,以供软件进行读取(CPU或者DMA方式),存储的数据是经过参考电压比较后,按照12bits 进行换算得到。 ADC输入范围:Vref- ≤ Vin ≤ Vref+ ADC 时钟 ADC 的输入时钟 ADCCLK 不能超过 14MHz(Datasheet规定)它是由PCLK2经分频产生。 转换模式 支持单次转换和连续转换,顾名思义,单次转换就仅仅只进行一次转换,然后就
[单片机]
STM32F103ZET6 — <font color='red'>ADC</font>
ADC 的布局小贴士
高速和高性能 ADC 对于布局是很敏感的,而优良的 PCB 布局对于实现正确的运作是不可或缺的。以下诸点是有助实现最优性能的布局小贴士: 1. 必须使用具有一个完整接地平面的印刷电路板。对于高分辨率或高速 A/D 转换器,建议不要采用绕接板。 2. 印刷电路板 (PCB) 的布局应确保数字信号线与模拟信号线尽可能地分开。特别地,应谨慎地避免沿着模拟信号线或在 ADC 的下方排布任何数字时钟或信号。 3. 利用接地来屏蔽模拟输入走线以最大限度地抑制来自其他走线的耦合。 4. 只要可能,应在模拟输入的周围采用一种对称布局以尽量减轻寄生元件的影响。信号源与 ADC 地之间的任何电位差都将表现为一个与输入信号相串联的误差电压。 5. 使走
[电源管理]
<font color='red'>ADC</font> 的布局小贴士
avr单片机精练的两路ADC代码+仿真图
电路原理图如下: #include iom16v.h #include macros.h #define uchar unsigned char #define uchar unsigned int const uchar SEG_CODE = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF}; uchar display = {0,0,0,10,0,0,0,10}; void delay(uint mS); void main() { uchar i; DDRA = 0xfc;
[单片机]
avr单片机精练的两路<font color='red'>ADC</font>代码+仿真图
STC8H开发(十): SPI驱动Nokia5110 LCD(PCD8544)
Nokia5110 LCD 有片很早以前买的Nokia5110 LCD一直在纸箱里吃灰. 可能是买其它配件时送的? 没有合适的用途一直扔在那里, 偶尔见到总会想什么时候有空给它点一下. 外观长这样. 其实市面上这种模块有几个不同的版本, 另一种版本是上下有两排排针, 方便不同的PCB布局, 功能是一样的. 单色LCD, 84x48像素, 带4颗蓝色LED灯珠作为背光. 显示芯片是Philips PCD8544. 因为是Nokia5110手机的显示屏, 所以一般都叫它Nokia5110 LCD. 在2014年大屏手机还没流行的年代, 这是个相当不错的显示输出设备, 相对于1602和2004LCD, 体积小分辨率高, 便宜
[单片机]
<font color='red'>STC8H</font>开发(十): SPI驱动Nokia5110 LCD(PCD8544)
STM32F0xx的ADC配置
STM32F0xx系列单片机基于ST官方标准库V1.5.0的ADC功能的配置 ADC.c文件 #include ADC.h uint32_t ADC1ConvertedValue = 0, ADC1ConvertedVoltage = 0; void ADC_GPIO_Configuration(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOA, ENABLE); //端口配置 // GPIO_StructInit(&GPIO_InitStructure); GPIO_InitSt
[单片机]
半导体制程日新月异 NSD成ADC选择新指标
近来,高速和超高速ADC及数字处理在各种场合中普及率的不断提高,让超取样(Oversampling)渐渐成为宽频和射频系统的一个实际可行的架构方法。半导体制程的缩小化,已促使速度的提升及成本的降低(费用、功耗、电路板面积等)达到相当大的改进,让系统设计人员得以使用具有平坦杂讯频谱密度(Noise Spectral Density, NSD )的宽频转换器,或是针对所需频带具有高动态范围的频带限制型Σ-Δ转换器,来探索各种不同的转换和处理途径。这些技术,改变了设计工程师对于信号处理所需考虑的方式,以及他们定义产品的方式。 NSD与其在关注频带上的分布,可提供深入的探究,以及转换器选择过程的参考指标。 如果要对运行速度差异很大
[半导体设计/制造]
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件
随便看看

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved