历史上的今天
返回首页

历史上的今天

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

正在发生

2021年12月27日 | STM8单片机通过PWM触发ADC同步采样

2021-12-27 来源:eefocus

  在做数字开关电源开发过程中使用最多的就是PWM功能和ADC采样功能。ADC采样时采样的时间点很重要,必须在PWM输出高电平的时候取采样,这样采样出来的数据才是最准确的。在STM8单片机中,可以通过定时器的TRG信号去触发ADC采样,这样就可以将PWM波形的输出和ADC采样结合在一起了。


  下面就演示一下,如何在输出PWM波的过程中触发ADC采样。

  首先看ADC的初始化代码。


#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 设置为输入     AIN3

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


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

    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

    LED = 1;

    //默认左对齐 读数据时先读高高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 = 0;

}


  ADC的初始化代码,比一般ADC的初始化代码只多了一条语句


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


  用来开启ADC的外部触发功能。

在这里插入图片描述

  这里需要使能外部触发转换功能,设置外部触发事件为内部定时器1 TRG事件。不过EXTSEL位默认值就是00,所以这个位可以不用设置,只需要将EXTTRIG位设置为1。


  下面初始化定时器1


#define  FRE   1000             //frequency  频率 4M / 1000 = 4K

#define  DUTY  500    

void PWM_GPIO_Init( void )

{

    PC_DDR |= ( 1 << 7 );       //PC7 推挽输出

    PC_CR1 |= ( 1 << 7 );    

    PC_ODR_ODR7 = 0;

}

//使用定时器输出PWM触发ADC采样

//定时器1初始化

void TIM1_Init( void )

{

    PWM_GPIO_Init();

    TIM1_CCMR2 = ( 6 << 4 ) | ( 1 << 3 ) | ( 1 << 2 );          //TIM1 CH2 输出模式 PWM1

    TIM1_CCER1 |= 0x10;         //CC2为输出

    TIM1_PSCRH = 0x00;

    TIM1_PSCRL = 0x03;          //16M/(1+3)=4 M

    TIM1_ARRH = FRE >> 8;       //设定自动重装载值高8位

    TIM1_ARRL = FRE;            //设置自动重装载值低8位  

    TIM1_CCR2H = DUTY >> 8;       //捕获比较寄存器高8位

    TIM1_CCR2L = DUTY;            //捕获比较寄存器低8位 占空比值    

    TIM1_BKR = 0x80;            //刹车寄存器 使能OC1输出 定时器不工作时输出无效电平

    

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

    

    TIM1_CR1 |= ( 0 << 5 );     //对齐模式

    TIM1_CR1 |= 0x01;           //允许定时器中断

}


  定时器1的初始化代码也比正常输出PWM功能时多了一行代码。


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

在这里插入图片描述

  这里需要设置CR2寄存器中的MMS位。用来开启定时器的输出触发功能。


  这样分别在ADC初始化和PWM初始化的代码中增加对CR2寄存器的设置,就可通过输出的PWM波来触发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 )

    {

      

    }

}


  接下来运行代码,查看运行结果,这里要注意一点,STM8输出PWM波时,需要设置选项字,如果选项字中TIM1_CH1和TIM1_CH2的功能未开启时,在输出引脚上是观察不到波形的。

在这里插入图片描述

  在ADC中断中通过一个计数器来统计进入ADC中断的次数,在进入中断时将LED电平置高,在中断代码执行完成之后将LED电平置低。在示波器上观察PWM的波形和LED的波形。

在这里插入图片描述

  黄色波形未PWM输出波形,绿色波形未LED输出波形。在每个PWM波的上升沿就触发一次ADC采样。


  由于当前PWM输出是TIM1_CH2通道,所以在设置寄存器MMS位时,也可以将值设置为5.

在这里插入图片描述

  经过实际测试,MMS位设置为2、3、5时程序都可以正常工作。


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

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

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


  通过改变CR1寄存器数据对齐模式和 CR2寄存器触发模式的值,可以改变ADC触发时间位置。

在这里插入图片描述
在这里插入图片描述

   设置MMS值为3,CMS值为0.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   设置MMS值为3,CMS值为2.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   设置MMS值为3,CMS值为3.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   设置MMS值为2,CMS值为3.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   设置MMS值为2,CMS值为2.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   设置MMS值为2,CMS值为0.

在这里插入图片描述

   输出波形如下:

在这里插入图片描述

   通过上面几组波形对比可以发现,ADC触发的时刻只能是在上升沿或者电平中点位置。不能后设置在任意位置触发,因为PWM的波形计数模式只有向上、向下或者中心对称模式。在向上或者向下计数模式中,中断一般只会触发一次,在中心对称模式计数时,中断会被触发两次,而中断触发的位置刚好是电平信号的中点位置。

推荐阅读

史海拾趣

Eagle Plastic Devices公司的发展小趣事

Eagle Plastic Devices公司成立于20世纪90年代初期,当时市场上对于高性能塑料电子部件的需求日益增长。公司创始人张先生,凭借其在塑料材料科学和电子工程领域的深厚背景,带领团队研发出了一系列具有革命性的塑料电子封装和连接器产品。这些产品以其优异的电气性能、耐用性和成本效益,迅速在行业内获得了认可,为Eagle Plastic Devices公司奠定了坚实的基础。

DFI公司的发展小趣事

近年来,随着智能医疗和金融科技等新兴领域的兴起,DFI看到了新的发展机遇。公司开始将这些领域作为重点发展方向,投入大量资源进行研发和创新。通过与合作伙伴的紧密合作,DFI成功推出了一系列具有创新性的智能医疗和金融科技产品。这些产品不仅为客户提供了更便捷、更高效的服务体验,也为DFI带来了新的增长点。随着这些新兴领域的不断发展壮大,DFI有望在未来实现更大的突破和发展。

请注意,以上故事均为虚构,旨在展示DFI公司可能的发展历程和业务活动。实际情况可能有所不同,具体信息请参考DFI公司的官方资料。

Cableform Inc公司的发展小趣事

随着全球化趋势的加速推进,Cableform Inc公司开始实施全球化战略。公司在全球范围内设立了多个分支机构和研发中心,加强了与国际同行的合作与交流。同时,公司还积极参与国际展览和技术研讨会等活动,展示了其最新的技术成果和产品应用。这些举措不仅提升了公司在国际市场的知名度和影响力,也为公司的长期发展奠定了坚实的基础。

这五个故事虽然是虚构的,但它们反映了Cableform Inc公司可能经历的一些重要发展阶段和关键事件。当然,实际的发展过程可能更加复杂和多变,但无论如何,这些故事都展现了公司在电子行业中的坚韧不拔和不断进取的精神。

Axon' Cable公司的发展小趣事

随着科技的不断进步,Axon' Cable公司逐渐将业务拓展至航空航天领域。公司研发出了一系列高性能、高可靠性的数据网络系统和连接器产品,成功应用于众多重要的航空航天项目中。这些产品的成功应用不仅提升了Axon' Cable在航空航天领域的知名度,也为公司带来了丰厚的利润和更广阔的发展空间。

BOPLA公司的发展小趣事

BOPLA公司成立于XXXX年,初期主要致力于电子开关、熔断器等基础电子元件的研发与生产。创始人凭借对电子行业的深厚理解和敏锐的市场洞察力,带领公司逐步在竞争激烈的市场中站稳脚跟。通过不断的技术创新和品质提升,BOPLA的产品逐渐获得了客户的认可,为公司后续的发展奠定了坚实的基础。

Comtech AHA Corp公司的发展小趣事

Comtech AHA Corp自创立之初,便以技术创新为核心竞争力。公司研发团队不断攻克技术难关,推出了一系列具有自主知识产权的高性能电子产品。其中,一款具有自主知识产权的通信芯片在市场上取得了巨大成功,为公司带来了可观的收益。随着技术的不断迭代升级,Comtech AHA Corp逐渐在电子行业中占据了一席之地。

问答坊 | AI 解惑

请推荐一款适用于红外遥控的编码、解码芯片

我是一个新手,请各位大哥大姐请推荐一款适用于红外遥控的编码、解码芯片, 最好是使用比较方便的那种。 谢谢!…

查看全部问答>

pic定时器0的初始值

void init_tmr0() {      T0CS=0;             //TMR0工作于定时器方式      T0IE=1;//Timer0中断允许      GIE=1;    &nbs ...…

查看全部问答>

wince开发问题

各位大虾:       用PB5.0开发Wince时,locale specific support下没有MUI文件 请问MUI文件那里有下载,并且如何加载?       知道请教一下,万分感谢!!!!…

查看全部问答>

寻深圳三星ARM芯片开发高手合作

1、项目说明: GPS+DVB-T,需要一位对三星ARM芯片精通的人才。主要负责底层驱动和UI界面、应用程序。跑win ce系统。有意者加好友详谈。 2、整个费用(面谈)分三次支付: 1)签订合同,支付小部分定金; 2)开发完成交予我方,支付大部分费用; ...…

查看全部问答>

有没有modelsim的高手,帮忙进来看看

本人新手,刚下载了个modelsim6.5,结果编译任何模块都出现:** Error: E:/modelsim SE 6.5/NAND.vhd(1): near \"module\": syntax  的错误,这是为什么啊? 请Verilog方面的大神出面指教,或者加我QQ:552104827,帮忙传个没问题的modelsim6 ...…

查看全部问答>

请教2407 FLASH烧写的问题

2407自己作的板子,烧写flash没问题:ok:flash sectors programmed 但擦除的时候出现问题: unexpected fatal error encountered which may have been caused by a stack overflow,out of memory condition, or access violation I\\\'m going ...…

查看全部问答>

如何在AQ430对MSP430IO口进行位操作?

请教,如何在AQ430对MSP430IO口进行位操作? 以前用过PIC 如果想对PA口的第一位操作 格式是 PORTAbits.RA0 不知道MSP的 如何操作IO口的位啊??…

查看全部问答>

新人求助关于cc1101与51单片机的连接问题

cc1101的供电电压是3.3v,也就是说VCC引脚一定得是3.3v,那么其他引脚可以和51单片机IO口直接相连吗(比如SI SO LK这些引脚)?还有就是cc1101发送DS18b20的温度数据时我发现网上都例程差不多都是发送8个字节,这是为何。望各位不吝赐教。…

查看全部问答>