STM8单片机通过PWM触发ADC同步采样

  在做数字开关电源开发过程中使用最多的就是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的波形计数模式只有向上、向下或者中心对称模式。在向上或者向下计数模式中,中断一般只会触发一次,在中心对称模式计数时,中断会被触发两次,而中断触发的位置刚好是电平信号的中点位置。

   通过自己的摸索终于将PWM触发ADC采样功能实现了,如果哪位朋友有更好的方法来实现,欢迎留言讨论。

  • 10
    点赞
  • 72
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
### 回答1: 通过TIM1产生6路PWM信号,并使用CCR4触发ADC1的注入通道进行采样。 首先,我们需要配置TIM1来产生PWM信号。在TIM1的配置中,我们需要设置计数方式为向上计数,使能自动重载寄存器(ARR),设置预分频器的分频系数,配置PWM输出模式和极性。同时,我们还需要设置6个PWM通道的比较输出模式和比较值(CCR)。 接下来,我们需要配置CCR4来触发ADC1的注入通道进行采样。我们需要设置注入通道的采样时间,采样间隔和注入通道的顺序。然后,我们需要配置ADC1的注入通道,并设置注入通道的采样时间和采样顺序。 在使用的时候,我们需要启动TIM1以开始产生PWM信号,并启动ADC1进行注入通道的采样。当CCR4触发时,ADC1将开始采样,并将采样结果存放在指定的寄存器中,可以通过读取这些寄存器来获取采样结果。 请注意,以上是大致的步骤,具体的配置和代码实现可能会因为不同的硬件平台和开发环境而有所区别。 ### 回答2: 使用TIM1产生6路PWM信号,可以通过将TIM1配置为PWM模式,并设置输出比较通道CCR1至CCR6的占空比来实现。首先,需要配置TIM1的时钟和重载值,以确定PWM信号的频率和周期。然后,通过设置CCR1至CCR6寄存器的值,来确定占空比的大小。 接下来,使用CCR4触发ADC1的注入通道采样。首先,需要将TIM1的CCR4通道配置为PWM输出模式,并设置触发ADC1的注入通道。然后,通过设置TIM1的CCR4寄存器的值,来确定ADC1的触发时机。 由于题目中没有提供具体的参数和配置要求,因此无法提供详细的代码实现。但是,上述步骤可以作为整体的框架来实现用TIM1产生6路PWM,并用CCR4触发ADC1的注入通道采样。具体的配置和代码实现,需要根据具体的硬件平台和需求进行调整和编写。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值