历史上的今天
返回首页

历史上的今天

今天是:2024年12月27日(星期五)

正在发生

2021年12月27日 | STM8单片机ADC采样功能通过定时器触发

2021-12-27 来源:eefocus

  在使用STM8单片机的ADC功能时,读取ADC数据时一般有两种方式,一种是通常不断地读取采样标志位,来判断ADC采样是否结束,一种是通过中断的方式来通知系统采样是否结束。


  有时候采样ADC数据的时候,需要按照一定的时间间隔,定点的去采样数据。一般使用的方式就是通过定时器定时,然后在定时中断函数中再去读取ADC采样的数据。但是这种方式采样的时间是不固定的,比如进入定时器中断后,ADC采样刚结束,就可以直接使用当前采样到的数据。但是如果运气不好的话,进入定时中断后,ADC采样刚开始,那么此时就需要等到ADC采样结束后,才能使用数据。这样就好导致每次读取ADC数据时还会有随机的一段等到ADC数据的延时。


  通常查阅STM8单片机的手册发现,ADC采样可以通过定时器来触发。

在这里插入图片描述

  通过定时器来触发ADC采样时,定时器的定时时间是固定的,采样时间也是固定的,这样采样数据的间隔也就是固定的。这样通过定时器来触发ADC的采样时间,就能完全保证每次读取ADC采样数据的时间间隔都是一样的,从而避免了数据的误差。


  数据手册中对于开启ADC触发功能描述如下:

在这里插入图片描述

  对于如何通过代码来设置ADC触发,官方也没有详细的说明,在网上也没有找到相关例程。所以只能自己摸索,还好通过自己的一番摸索,成功的通过定时器的TRGO事件触发了ADC的启动。


  关于ADC相关寄存器的设置,基本就是上面说的6条。接下来需要设置的就是定时器的相关寄存器。

在这里插入图片描述

  关于定时器只需要设置CR2寄存器中的 MMS位就可以了。


  接下来就通过代码来实现。


#include "adc.h"

#include "main.h"

#include "led.h"


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

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

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


u16 adc_cnt = 0;

//AD通道引脚初始化

void ADC_GPIO_Init( void )

{

    PD_DDR &= ~( 1 << 2 );              //PD2 设置为输入     

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

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

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

}

//ch 为单片机的ADC 通道

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

void ADC_CH_Init( u8 ch )

{

    char l = 0;

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

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

    

    ADC_CR2 |= ( 1 << 6 );              //外部触发使能


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

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

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

    ADC_CSR |= ( 1 << 5 );              //EOCIE 使能转换结束中断  EOC中断使能

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

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

}


u16 value = 0;

//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

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

    adc_cnt++;

    LED = !LED;

}


  在ADC代码中,相比普通的ADC初始化方式,这里只需要增加一句对ADC_CR2寄存器的设置。


ADC_CR2 |= ( 1 << 6 ); //外部触发使能

在这里插入图片描述

  在ADC_CR2寄存器中 使能外部触发转换功能,设置外部触发事件为 内部定时器1 TRG事件。


  这里ADC使用的是单次触发模式,开启外部触发功能,开启ADC转换中断,当ADC转换完成之后,就会进入到ADC中断中,在中断中读取采样的数据,然后翻转LED的状态,通过示波器观察LED引脚电平的变化,就可以知道ADC中断进入的频率了。


  接下来编写定时器初始化代码。


unsigned long time_cnt = 0;

// 使用 定时器触发 ADC采样

void tim1_init( void )

{

    TIM1_ARRH = ( unsigned char )( 1000 >> 8 );         //定时1ms

    TIM1_ARRL = ( unsigned char )( 1000 );

    TIM1_PSCRH = ( unsigned char )( 0x0F >> 8 );        // 16M / (1+15) =1M

    TIM1_PSCRL = ( unsigned char )( 0x0F );

    TIM1_RCR = 0x00;                                    //重复计数器值

    TIM1_SR1 = ( ~0x01 );                        //清除更新中断标志


    TIM1_CR2 |= ( 2 << 4 );                             //使能信号,用于触发输出(TRGO)

    

    TIM1_CR1 |= 0x01;                                   //使能计数器

    TIM1_IER |= 0x01;                            //更新中断使能

}


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

__interrupt void Timer1_Handle( void )          //1ms 定时中断

{

    TIM1_SR1 = ( ~0x01 );                        //清除更新中断标志

    time_cnt++;

}


  定时器的初始化代码,也比正常情况下初始化代码多了一行。


TIM1_CR2 |= ( 2 << 4 ); //使能信号,用于触发输出(TRGO)


  用来开启定时的的TRG功能。

在这里插入图片描述

  经过测试,这里定时器CR2寄存器中的值 只能设置为 010 或者 011,设置为其他值时,不能触发ADC采样。最开始测试的时候按照芯片资料上这个说明,MMS的值设置的是 001,ADC总是触发不了,还以为是方法的问题,最后才发现是MMS值设置的问题。


  ADC和定时器初始化代码设置完成之后,接下来在主函数中初始化这两个函数就行了,按照资料上说的,首先初始化完ADC之后,再初始化定时器。


void main( void )

{


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

    SysClkInit();

    delay_init( 16 );

    LED_GPIO_Init();

     ADC_GPIO_Init();

    ADC_CH_Init(3);

    tim1_init();

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

    while( 1 )

    {

       

    }

}

  接下来运行程序。

在这里插入图片描述

  分别在ADC中断中和定时器中断中用一个变量来统计中断执行的次数,通过变量变量观察窗口可以看到,ADC中断的次数比定时器中断的次数多了1次。这是因为ADC在初始化的时候,已经运行了一次。


  然后通过示波器观察LED口的电平。

在这里插入图片描述

  定时器的定时时间是1ms,LED的高低电平时间也是1ms,说明通过定时器触发ADC采样功能是正常运行的。


  为了减小系统进入中断的次数,可以将定时器的中断功能关闭掉。定时器中断功能关闭后,ADC的触发功能依然可以正常使用。

在这里插入图片描述

  这样只需要开启一个ADC中断,再加上定时器的TRG触发功能后,就可以实现ADC定时采样的功能了。

推荐阅读

史海拾趣

DIALIGHT公司的发展小趣事

DIALIGHT公司的故事始于1938年的纽约布鲁克林,当时该公司专注于为飞机生产仪表板灯。随着技术的不断进步和市场的变化,公司在1971年,即LED推出仅一年后,推出了他们的第一个LED产品。这一举措标志着DIALIGHT正式从传统的飞机仪表板灯制造转向LED照明技术的研发和应用。从此,DIALIGHT彻底改变了LED的用途,将其广泛应用于世界各地的交通控制、指示灯、结构塔和工业场所,为全球提供了优质的照明解决方案。

上海如韵(CONSONANCE)公司的发展小趣事

在发展过程中,如韵始终关注社会责任和可持续发展问题。公司积极参与社会公益活动,为弱势群体提供帮助和支持。同时,如韵注重环保和节能减排工作,在产品设计和生产过程中严格遵守相关环保法规和标准。

为了推动行业的可持续发展,如韵还积极参与行业交流和合作活动,与同行分享经验和资源。通过与产业链上下游企业的紧密合作和协同创新,如韵为推动电子行业的绿色发展和技术进步做出了积极贡献。

CTC Coils Ltd公司的发展小趣事

随着国内市场的逐渐饱和,CTC Coils Ltd公司开始将目光投向海外市场。公司首先在欧洲设立了销售分支机构,通过参加国际电子展会、与当地企业建立合作关系等方式,逐步打开了欧洲市场。随后,公司又进一步拓展到北美和亚洲其他地区,实现了业务的国际化布局。

DECON公司的发展小趣事

品质是企业的生命线,DECON公司深知这一点。因此,公司建立了完善的品质管理体系,从原材料采购到生产过程的每一个环节都进行严格的质量监控。公司引进了先进的生产设备和技术,优化了生产流程,提高了生产效率和产品质量。同时,公司还建立了完善的售后服务体系,为客户提供及时、高效的技术支持和解决方案。

Equinox公司的发展小趣事

1991年,在纽约的上西区,一个名叫Equinox的健身俱乐部悄然开业。它的创始人凭借对健身行业的热情和对高端市场的敏锐洞察,将Equinox定位为一家提供豪华健身体验的俱乐部。通过提供优质的设施、个性化的服务和丰富的课程,Equinox很快在上西区树立了良好的口碑。

广东爱晟电子(exsense)公司的发展小趣事

广东爱晟电子自成立以来,一直致力于NTC热敏电阻技术的研发和创新。在2010年代初,公司面临技术瓶颈,市场竞争激烈。然而,爱晟电子团队不畏艰难,通过深入研究,成功研发出具有更高精度和稳定性的NTC热敏电阻。这一技术突破迅速获得了市场的认可,公司销售额逐年攀升,奠定了在电子行业的领先地位。

问答坊 | AI 解惑

usb 主机在什么情况下会不停的给设备发送复位信号呢?请高手些指教哈!

我现在的设备端不停的收到复位信号,接着是超时,不知道是在什么情况下主机才会发复位信号?…

查看全部问答>

这样的报表用怎么做?

数量    厂家     数量     型号      数量                           n ...…

查看全部问答>

求解:wince6.0下电源管理,中父设备和子设备之间的关系?

求解:wince6.0下电源管理,中父设备和子设备之间的关系?…

查看全部问答>

wince 应用程序安装请教

魅族安装应用程序是这么做的。 四、发布应用程序 …

查看全部问答>

求购《Tornado/VxWorks入门与提高》

求购,《Tornado/VxWorks入门与提高》,哪里能买到呢? 网上的书店找了好多都是缺货,那位仁兄帮帮忙 谢谢 mryanzh@126.com…

查看全部问答>

EVC怎么控制菜单的checked属性?(基于对话框)

我用evc做了一个基于对话框的工程,我用代码来加上Menu,但我怎么控制菜单的checked属性呢? 我就是想实现选择一个菜单后有个小勾,就想windows里面的查看方式一样,比如列表,缩略图,小图标什么的,选择后有小勾的效果。 谁知道啊?…

查看全部问答>

STM32无法更新程序

本人购买了一块STM32F103ZET6评估板,配有KEIL3和ULINK下载器。后因需要防止程序被读出,想尝试下读保护功能,于是在程序中添加了使能读保护的代码。板子复位后正常运行,查询读保护状态位已置位,但无法更新程序。查阅资料得知使能读保护后 ...…

查看全部问答>

New head job opportunity for you

Here are some new job opportunities for you from EMC China,if it\'s fit for you .Plz touch me,thanks for your support! Christina(028)86701200 QQ:1106525264   Principal Software QA Engineer - USD/Chengdu Responsibilities ...…

查看全部问答>

如何利用FPGA做高阶FIR滤波器设计

小弟最近在做毕业设计,用到了高阶FIR滤波器,一头雾水,查找了一些资料后,了解了一种方法:利用分布式串并结合的算法可以实现。里面有用到FPGA的查找表和流水线,我对FPGA不怎么熟悉,不知道怎么调用这两个东西,或是自己设计?怎么设计?哪位大 ...…

查看全部问答>

28335采样瞬间电压跌落

用28335时,当板件正常工作时没有启动AD转换时信号是很好的,而一旦对信号进行AD采集时,信号就受到了干扰,在每个采样的瞬间 信号电压都有很大波动,如图中大的尖峰所示。采样频率10k,尖峰频率也是10k。请问,这个干扰是DSP造成的吗?是否是内部 ...…

查看全部问答>