历史上的今天
返回首页

历史上的今天

今天是:2024年09月16日(星期一)

2021年09月16日 | STM8单片机ADC带缓存的连续采样模式

2021-09-16 来源:eefocus

在上一篇文章中说了STM8的ADC连续采样模式,为了提高采样的精度和速率,STM8单片机还提供了带缓存的连续采样模式,也就是说ADC会连续采集8个数据,放在缓存中,读取数据时可以一次从缓存中读取8个数据,这样就可以通过8个数据数据计算平均值,使得采样的结果更加准确。


下面看一下官方文档中的对缓存模式的介绍。

image.png?imageView2/2/w/550

通过文档中可以看出,要开启缓存模式,只需要将ADC_CR3寄存器中的COUNT为DBUF设置为1,就可以开启缓存模式了。


当开启缓存模式后,采样的结果将不会存放在ADC_DR寄存器中,而是会将结果依次存放在ADC_DB0R寄存器到ADCDB7R寄存器,连续读取8次数据,存储在这8个寄存器中。读取数据的时候,依次从这8个寄存器中读取就行。


下面直接通过代码来实现带缓存功能的连续采样模式:


#include "adc.h"

#include "main.h"


u16  DATAH = 0;                          //ADC转换值高8位

u16  DATAL = 0;                          //ADC转换值低8位

_Bool ADC_flag = 0;                     //ADC转换成功标志


//AD通道引脚初始化

void ADC_GPIO_Init( void )

{

    PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      电流

    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入

}

/*

ch 为单片机ADC通道

通过置位ADC_CR1寄存器的ADON位来开启ADC。当第一次置位ADON时,ADC从低功耗模式唤醒。

为了启动转换必须第二次使用写指令来置位ADON位。

在转换结束时,ADC会保持在上电状态,用户只需要置位ADON位一次来启动下一次转换。

转换完成后,转换数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置位,如果EOCIE被置位将产生一个中断

ADC输入通道初始化入口参数表示通道选择

*/

void ADC_CH_Init( u8 ch )

{

    char l = 0;

    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换

    

    ADC_CR1 |= ( 1 << 1 );              //开启连续转换模式

    

    ADC_CSR  = ch;                      //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)

    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低

    ADC_TDRL = ( 1 << ch );             //禁止相应通道 施密特触发功能 1左移ch+1位

    ADC_CR1 |= 0x01;                    //使能ADC并开始转换


    //ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能

    ADC_CR3 |= ( 1 << 7 );              //数据缓存使能


    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us

    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换

}


u16 databuf[8] = {0};

//采集PD2电压值

u16 ReadVol_CH3( void )

{

    u16 voltage = 0;


    while( ( ADC_CSR & 0x80 ) == 0 );      //等待转换结束

    if( ADC_CSR & 0x80 )

    {

        ADC_CSR &= 0x7F;

        /*

        使能缓存模式后,数据会存储在 ADC_DB0R ---- ADC_DB7R 寄存器中

        如果使能了扫描模式那么这几个寄存器存储的就是对应通道的数据

        如果没有使能扫描模式,那么这几个通道就存储的是连续转换的结果

        这里没有使用扫描模式,所以缓存器中存储的都是当前通道连续读取的数据

        */

        DATAH = ADC_DB0RH;                    // 读出ADC结果的高8位

        DATAL = ADC_DB0RL;                    // 读出ADC结果的低8位

        voltage = ( DATAH << 2 ) + DATAL ;    //得到十位精度的数据  0--1024

        databuf[0] = voltage;


        DATAH = ADC_DB1RH;

        DATAL = ADC_DB1RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[1] = voltage;


        DATAH = ADC_DB2RH;

        DATAL = ADC_DB2RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[2] = voltage;


        DATAH = ADC_DB3RH;

        DATAL = ADC_DB3RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[3] = voltage;


        DATAH = ADC_DB4RH;

        DATAL = ADC_DB4RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[4] = voltage;


        DATAH = ADC_DB5RH;

        DATAL = ADC_DB5RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[5] = voltage;


        DATAH = ADC_DB6RH;

        DATAL = ADC_DB6RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[6] = voltage;


        DATAH = ADC_DB7RH;

        DATAL = ADC_DB7RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[7] = voltage;

    }


    return voltage;

}


在初始化中设置 ADC_CR1 |= ( 1 << 1 ); 也就是将ADC_CR1寄存器的第一位设置为1。

image.png?imageView2/2/w/550

也就是使能了连续转换模式。


然后设置ADC_CR3 |= ( 1 << 7 ); 也就是将ADC_CR3寄存器的第7位设置为1.

image.png?imageView2/2/w/550

也就是开启了ADC的数据缓存功能,当数据转换完成之后,ADC_CSR寄存器的EOC位会置1,此时如果程序判断到EOC位为1时,就可以去数据缓存寄存器读取数据了。也就是代码中ReadVol_CH3()函数实现的功能。

image.png?imageView2/2/w/550

这里是通过查询标志位的方法读取数据,也可以通过中断的方式读取数据。


通过中断方式读取代码如下:


#include "adc.h"

#include "main.h"


u16  DATAH = 0;                          //ADC转换值高8位

u16  DATAL = 0;                          //ADC转换值低8位

_Bool ADC_flag = 0;                     //ADC转换成功标志


//AD通道引脚初始化

void ADC_GPIO_Init( void )

{

    PD_DDR &= ~( 1 << 3 );              //PD3 设置为输入      电流

    PD_CR1 &= ~( 1 << 3 );              //PD3 设置为悬空输入

}

/*

ch 为单片机ADC通道

通过置位ADC_CR1寄存器的ADON位来开启ADC。当第一次置位ADON时,ADC从低功耗模式唤醒。

为了启动转换必须第二次使用写指令来置位ADON位。

在转换结束时,ADC会保持在上电状态,用户只需要置位ADON位一次来启动下一次转换。

转换完成后,转换数据存储在ADC_DR寄存器中,EOC(转换结束)标志被置位,如果EOCIE被置位将产生一个中断

ADC输入通道初始化入口参数表示通道选择

*/

void ADC_CH_Init( u8 ch )

{

    char l = 0;

    ADC_CR1  = 0x00;                    //fADC = fMASTER/2, 8Mhz  单次转换,禁止转换

    

    ADC_CR1 |= ( 1 << 1 );              //开启连续转换模式

    

    ADC_CSR  = ch;                      //控制状态寄存器 选择要 AD输入通道  如:PD2(AIN3)

    ADC_CR2  = 0x00;                    //默认左对齐 读数据时先读高在读低

    ADC_TDRL = ( 1 << ch );             //禁止相应通道 施密特触发功能 1左移ch+1位

    ADC_CR1 |= 0x01;                    //使能ADC并开始转换


    ADC_CSR |= 0x20;                    //EOCIE 使能转换结束中断  EOC中断使能

    ADC_CR3 |= ( 1 << 7 );              //数据缓存使能


    for( l = 0; l < 100; l++ );         //延时,保证ADC模块的上电完成 至少7us

    ADC_CR1 = ADC_CR1 | 0x01;           //再次将CR1寄存器的最低位置1 使能ADC 并开始转换

}


u16 databuf[8] = {0};

//采集PD2电压值

u16 ReadVol_CH3( void )

{

    u16 voltage = 0;


    if( ADC_flag )

    {

        ADC_flag = 0;

        /*

        使能缓存模式后,数据会存储在 ADC_DB0R ---- ADC_DB7R 寄存器中

        如果使能了扫描模式那么这几个寄存器存储的就是对应通道的数据

        如果没有使能扫描模式,那么这几个通道就存储的是连续转换的结果

        这里没有使用扫描模式,所以缓存器中存储的都是当前通道连续读取的数据

        */

        DATAH = ADC_DB0RH;                    // 读出ADC结果的高8位

        DATAL = ADC_DB0RL;                    // 读出ADC结果的低8位

        voltage = ( DATAH << 2 ) + DATAL ;    //得到十位精度的数据  0--1024

        databuf[0] = voltage;


        DATAH = ADC_DB1RH;

        DATAL = ADC_DB1RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[1] = voltage;


        DATAH = ADC_DB2RH;

        DATAL = ADC_DB2RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[2] = voltage;


        DATAH = ADC_DB3RH;

        DATAL = ADC_DB3RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[3] = voltage;


        DATAH = ADC_DB4RH;

        DATAL = ADC_DB4RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[4] = voltage;


        DATAH = ADC_DB5RH;

        DATAL = ADC_DB5RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[5] = voltage;


        DATAH = ADC_DB6RH;

        DATAL = ADC_DB6RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[6] = voltage;


        DATAH = ADC_DB7RH;

        DATAL = ADC_DB7RL;

        voltage = ( DATAH << 2 ) + DATAL ;

        databuf[7] = voltage;     

    }

    return voltage;

}



//AD中断服务函数 中断号22

#pragma vector = 24                     // IAR中的中断号,要在STVD中的中断号上加2

推荐阅读

史海拾趣

Frolyt Condensers & Elements GmbH公司的发展小趣事

随着全球对环保问题的日益重视,Frolyt Condensers & Elements GmbH积极响应号召,将环保理念融入产品设计和生产流程中。公司投入大量资金研发环保型电容器材料和生产工艺,成功推出了多款低能耗、无污染的电容器产品。这些产品不仅满足了市场对环保产品的需求,还帮助Frolyt树立了良好的企业形象,进一步提升了市场竞争力。

华润微(CRMICRO)公司的发展小趣事

尽管面临市场终端景气度低迷等挑战,华润微依然保持稳健的发展态势。公司积极应对市场变化,通过优化产品结构、加大研发投入等措施,不断提升自身竞争力。同时,华润微也看到了新能源业务等领域的巨大潜力,将其作为未来发展的重要方向。通过不断的技术创新和市场拓展,华润微有望在电子行业中实现更加辉煌的成就。

Diotec Electronics Corp公司的发展小趣事

面对全球化的市场趋势,Diotec开始实施全球化战略。公司加强与国际市场的联系,积极开拓海外市场。同时,Diotec还加强与全球合作伙伴的合作,共同推动电子行业的发展。展望未来,Diotec将继续坚持技术创新和品质至上的理念,致力于成为全球领先的电子元器件供应商。同时,公司还将关注新兴市场和技术趋势,为未来的发展做好充分准备。

ELMEC Technology Of America Inc公司的发展小趣事

在ELMEC Technology Of America Inc公司初创时期,创始人李明和他的团队面临着一个巨大的挑战:如何开发一款能在市场上脱颖而出的电子产品。经过无数次的实验和失败,他们最终成功研发了一款高效能、低功耗的半导体芯片。这款芯片的问世不仅为公司带来了第一笔可观的收入,也奠定了ELMEC在电子行业的技术领先地位。

Digilent公司的发展小趣事

在全球节能意识日益增强的背景下,DIALIGHT致力于推动绿色照明的发展。公司的LED产品具有高效节能、长寿命和环保等优点,有助于减少能源消耗和环境污染。此外,DIALIGHT还积极参与各种绿色照明项目,为推动可持续发展贡献自己的力量。

Caltron Devices Ltd公司的发展小趣事

在电子行业的早期阶段,Caltron Devices Ltd公司便以研发为核心,致力于开发具有竞争力的电子产品。公司投入大量资源,引进先进设备和技术,培养了一支专业的研发团队。通过不懈的努力,Caltron成功推出了一系列创新产品,不仅在国内市场取得了良好的业绩,还逐渐打开了国际市场的大门。

问答坊 | AI 解惑

智能传感器与现代汽车电子

一、汽车电子操控和安全系统谈起    近几年来我国汽车工业增长迅速,发展势头很猛。因此评论界出现了一些专家的预测:汽车工业有可能超过IT产业,成为中国国民经济最重要的支柱产业之一。其实,汽车工业的增长必将包含与汽车产业相 ...…

查看全部问答>

三菱功率模块可靠性文档

功率模块可靠性资料,免费提供给大家!…

查看全部问答>

步进电机Verilog语言控制程序

步进电机Verilog语言控制程序…

查看全部问答>

ugtroj

;ngk;guhhoh…

查看全部问答>

s3c2410_gpio_cfgpin,s3c2410_gpio_setpin这些函数在哪?

请问 s3c2410_gpio_cfgpin,s3c2410_gpio_setpin这些函数在哪? 驱动中应包含什么头文件? 网上看到的是用#include , 而我在源代码目录中没有这个文件夹? 这是怎么回事? 请问一般涉及到s3c2410_gpio_cfgpin,s3c2410_gpio_setpin这些函数,驱动中的 ...…

查看全部问答>

请教大家一下电阻单位

请大家帮我讲解下这些单位的区别 在贴片电阻上这些单位的区别 392R 392Ω 3.9K 这些单位都一样吗? 请问下大家 392R 392Ω 3.9K 都一样吗? 我搜了很久没有搜索到,身边也没有可以询问的人,请大家帮帮忙,谢谢先!…

查看全部问答>

lpc1768 can

急求lpc1768can通讯函数写完初始化后不知道怎么写了,,求帮助…

查看全部问答>

对建立时间和保持时间的疑问

最近这段时间调1602的时候发现的一个关于建立时间和保持时间的问题,至今仍未想明白,特来求教各位 。。 我不知道我理解的对不对,所以先从数电书上的解释说起, 其一,对于锁存器来说,锁存器是对电平敏感的存储单元电路,可以在特定输入脉冲电 ...…

查看全部问答>

wiki啥意思啊

这个问题我早就碰到但没问出来,就是我看TI资料里网址有wiki字样,资料还不错,请问wiki啥意思,怎么给我感觉象wifi 比如:http://processors.wiki.ti.com/index.php/Category:TMS570 里边就有wiki…

查看全部问答>