历史上的今天
返回首页

历史上的今天

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

2021年09月16日 | STM8单片机ADC单次采样模式

2021-09-16 来源:eefocus

STM8S003单片机内部ADC为12位,A/D转换的各个通道可以执行单次和连续的转换模式。


单次转换模式的意思就是,ADC每次转换一次数据后,就会停止转换,如果还需要继续转换的话,就需要手动开启第二次转换功能。


连续转换模式的意思就是每次转换结束后,系统会自动开启第二次转换,不需要手动设置第二次转换的开启,也就是说连续转换模式只需要开启一次。


ADC框图如下:

image.png?imageView2/2/w/550

ADC转换时序图如下:

image.png?imageView2/2/w/550

下面用代码来实现ADC的单次转换模式:


#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 为单片机的对应管脚

void ADC_CH_Init( u8 ch )

{

    char l = 0;

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

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

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

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

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

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

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

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

}


//采集PD3电压值

u16 ReadVol_CH3( void )

{

    u16 voltage = 0;

    if( ADC_flag )

    {

        ADC_flag = 0;

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

        ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换

    };

    return voltage;

}

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

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

__interrupt void ADC_Handle( void )

{

    ADC_CSR &= ~0x80;                   // 转换结束标志位清零  EOC

    //默认左对齐 读数据时先读高高8位 再读低8位

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

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

    ADC_flag = 1;                       // ADC中断标志 置1

}


在第一次ADC启动时需要一个稳定时间,所以在初始化的时候,需要一定的时间等待ADC稳定,稳定之后就可以开始ADC转换了,这里使用中断来读取转换结果,当ADC转换换成后就会产生一个中断,然后在中断中读取转换的结果,同时设置标志位。程序循环去读取标志位,当标志位为1时,就说明转换完成了,这时候就可以输出转换的结果了。然后将ADC_CR1寄存器的最低位,手动置1,开启下一次转换。


ADC_CR1寄存器如下:

image.png?imageView2/2/w/550

ADON位就是ADC的转换开关,在单次模式下给ADON位写1就可开启转换。


这里只使用了一个通道,通过最上面ADC框图可以看出,一个ADC中有好多个通道,那么如果要采集多个通道要如何做呢?


#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 为单片机的对应管脚

void ADC_CH_Init( u8 ch )

{

    char l = 0;

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

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

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

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

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

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

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

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

}


//采集PD3电压值

u16 ReadVol_CH3( void )

{

    u16 voltage = 0;

    //只在程序初始化时调用一次的话,采样速度非常快。

    //如果每次都调用初始化,速度将会是原来的 1/10

    ADC_CH_Init( 3 );

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

    if( ADC_CSR & 0x80 )

    {

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

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

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

        ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换

        ADC_CSR &= 0x7F;

    };

    return voltage;

}


//采集PD2电压值

u16 ReadVol_CH4( void )

{

    u16 voltage = 0;

    //只在程序初始化时调用一次的话,采样速度非常快。

    //如果每次都调用初始化,速度将会是原来的 1/10

    ADC_CH_Init( 2 );

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

    if( ADC_CSR & 0x80 )

    {

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

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

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

        ADC_CR1 = ADC_CR1 | 0x01;          //再次将CR1寄存器的最低位置1  启动下一次转换

        ADC_CSR &= 0x7F;

    };

    return voltage;


如果需要转换多个通道,那么在一个通道转换完成之后,就需要重新初始化,进行转换通道的切换。由于切换通道后,ADC需要稳定时间,所以如果是多个通道来回切换采样数据的话,比一个通道单独采样数据就要慢很多,因为切换一次通道就需要等待一段时间让ADC稳定。


读取数据时,直接在主函数中调用对应的函数就行。


#include "iostm8s103F3.h"

#include "led.h"

#include "adc.h"

#include "stdio.h"


void SysClkInit( void )

{

    CLK_SWR = 0xe1;       //HSI为主时钟源  16MHz CPU时钟频率

    CLK_CKDIVR = 0x00;    //CPU时钟0分频,系统时钟0分频

}


void main( void )

{

    u16 val1 = 0;

    u16 i=0;

    SysClkInit();

    __asm( "sim" );                       //禁止中断

    LED_GPIO_Init();

    ADC_CH_Init( 3 );

    __asm( "rim" );                       //开启中断

    while( 1 )

    {

        LED = !LED;

        val1 = ReadVol_CH3();

    }

}

推荐阅读

史海拾趣

Echelon_Corporation公司的发展小趣事

作为一家技术驱动的公司,Echelon始终注重技术创新和产品研发的投入。公司拥有一支专业的研发团队,致力于开发更加先进、更加可靠的产品和技术。同时,Echelon还积极与全球范围内的科研机构、高校等合作,共同推动技术创新和产业升级。这些努力使得Echelon在电子行业始终保持领先地位。

DAYA公司的发展小趣事

在快速变化的电子市场中,大雅智能始终保持敏锐的市场洞察力。通过深入研究市场需求和消费者行为,大雅智能准确把握市场趋势,及时调整产品策略。例如,在智能家居市场兴起之际,大雅智能迅速推出了一系列智能家居产品,成功抢占了市场先机。这种对市场趋势的敏锐洞察和快速响应能力,让大雅智能在电子行业中不断取得新的突破。

Broadcom(博通)公司的发展小趣事

随着全球化的深入发展,博通积极调整战略,加强全球布局。公司通过设立研发中心、拓展销售网络等方式,不断提升其在全球市场的竞争力。同时,博通还积极与其他行业领军企业开展战略合作,共同推动电子行业的发展和创新。

这些故事展示了博通在电子行业中的发展历程和成就。从初创时期的艰难起步,到困境中的重生,再到并购扩张和技术创新,博通始终保持着坚韧不拔的精神和追求卓越的态度。正是这样的精神和态度,使博通能够在激烈的市场竞争中脱颖而出,成为电子行业的佼佼者。

Electron Products Inc公司的发展小趣事

EPI一直非常重视产品的品质管理。公司建立了严格的质量管理体系,从原材料采购到产品生产、检测、包装等各个环节都进行严格把控。此外,EPI还注重持续改进,不断引入先进的生产技术和设备,提升产品的质量和性能。这些举措使得EPI的产品在市场上享有很高的声誉和口碑。

Fenfa Electronics Ltd公司的发展小趣事

在技术创新的基础上,Fenfa Electronics Ltd公司开始积极拓展市场。公司高层意识到,仅仅依靠单一市场是远远不够的。因此,Fenfa团队制定了全球市场拓展战略,逐步打开了欧美、亚洲等地区的市场。在拓展过程中,公司积极与当地企业合作,深入了解当地市场需求和消费者习惯,不断优化产品和服务。通过这一系列的市场拓展策略,Fenfa Electronics Ltd公司的品牌知名度和市场份额均得到了显著提升。

Greenconn Corp公司的发展小趣事
确保冰箱内部和外部的线路连接牢固,如有松动需重新连接。

问答坊 | AI 解惑

我看FPGA现在难以取代FPGA+DSP的架构,这段时间的思索总结

FPGA现在越做越大了,有些公司如Xilinx推出的FPGA都内嵌了DSP核,很多人都在讨论说FPGA会取代现在主流的复杂数字信号处理系统的架构:FPGA+DSP了,SOC片上系统的时代真的要来了,我也对这个概念很憧憬,但经过一段时间的调研后,觉得现在还不成熟, ...…

查看全部问答>

角度传感器应用2

角度传感器应用2 [ 本帖最后由 小虾米gg 于 2009-9-2 15:27 编辑 ]…

查看全部问答>

请教变量问题

OEMAddressTable     ;;;-------------------------------------------------------------     ;;; Virt Addr   Phys Addr   MB     ;;;-------------------------------------------------- ...…

查看全部问答>

求助:wince socket 蓝牙编程中怎样用OBEX协议封装数据

我是刚接触蓝牙开发的,最近要做一个蓝牙文件传输的应用,就是实现蓝牙设备之间的文件传输, MSDN上研究过SOCKET实现的API函数,但是不知道连接成功后发送的数据怎样才能让对方识别, 网上有人说\"这些数据必须是经过OBEX协议封装好的数据\" 请做过这 ...…

查看全部问答>

FPGA如何与SJA1000连接?

请问各位高手: FPGA可以与SJA1000的RST引脚直接相连吗?…

查看全部问答>

请教:dsp2407a不能进入中断!

各位大侠:你们好!       最近,我在刚做好的一块DSP2407A板上试调程序,不知道为什么程序运行后无法进入中断.我只是编了一个非常简单的小程序,用定时器控制LCD闪烁.整个程序我检察了好多遍,应该没有问题的,但就是无法进入中断子 ...…

查看全部问答>

【视频分享】电源设计小贴士49:多层陶瓷电容器常见小缺陷的规避方法

各位好久不见啦!!最近美女小编感冒了,在家休息,有好一阵子没和大家分享好的东东啦! 今天和大家分享TI电源设计小贴士系列的视频,讲解得十分透彻。 因其小尺寸、低等效串联电阻(ESR)、低成本、高可靠性和高纹波电流能力,多层陶瓷 (MLC) 电容 ...…

查看全部问答>

求助SSI2.DLL

SSI2.DLL是wince里面的一个动态链接库,主要作用是调动设备中的激光扫描头,由于本人不会编程,特此求助附件是相应的.H和.LIB文件,说明文档还有示例文件,希望可以得到帮助,帮忙生成DLL文件 …

查看全部问答>

程序求大神,,,

急求,51芯片的关于计时的程序,,,可医用数码管或者1602显示的程序,,,本人小白,没有做出来只会显示一个,不会从0-999求救 …

查看全部问答>