Arduino CH552 PWM的使用

发布于:2025-07-03 ⋅ 阅读:(21) ⋅ 点赞:(0)

Arduino CH552 PWM的使用


📑CH552 PWM简介

CH552 提供了 2 路 8 位 PWM,PWM 可以选择默认的输出极性为低电平或者高电平,可以动态修改PWM 的输出占空比,通过简单 RC 电阻电容进行积分低通滤波后,即可获得各种输出电压,相当于低速数模转换器 DAC。PWM1 输出占空比= PWM_DATA1 / 256,支持范围 0%到 99.6%。PWM2 输出占空比= PWM_DATA2 / 256,支持范围 0%到 99.6%。
实际应用中,建议允许 PWM 引脚输出并且设置 PWM 输出引脚为推挽输出模式。

📘PWM1 和 PWM2 相关寄存器

在这里插入图片描述

  • PWM2 数据寄存器(PWM_DATA2):
    在这里插入图片描述
  • PWM1 数据寄存器(PWM_DATA1):
    在这里插入图片描述
  • PWM 控制寄存器(PWM_CTRL):
    在这里插入图片描述
    • PWM 时钟分频设置寄存器(PWM_CK_SE):
      在这里插入图片描述
📝测试代码

开启PWM中断,需要在固件:C:\Users\Administrator\AppData\Local\Arduino15\packages\CH55xDuino\hardware\mcs51\0.0.23\cores\ch55xduino\main.c文件中,将PWM中断函数添加进去:void PWMInterrupt( void ) __interrupt(INT_NO_PWMX);

/*

  PWM_F = Fsys/256/分频系数
  PWM默认输出通道:
  PWM1:P15 
   PWM2: P34
   开启备用输出通道:PWM1PINAlter( )和PWM2PINAlter( )之后PWM输出引脚
   PWM1 使用 P3.0
   PWM2 使用 P3.1
   同时开启2个通道,PWM1通道输出会有杂波
*/
#include <Arduino.h>

#define  LED_BUILTIN  11
#define LED_PIN 17

volatile uint16_t count = 0;  // 中断计数器
const uint16_t target = 500;  // 500次中断(每次1ms)
static bool LED_FLAG = 0;
static bool LED2_FLAG = 0;

#define  PWM_INTERRUPT  1

#define SetPWMClk(CK_SE) (PWM_CK_SE = CK_SE)                                  //分频,默认时钟Fsys  0 ~ 255  

#define SetPWM1Dat(dat)  (PWM_DATA1 = dat)                                    //设置PWM输出占空比
#define SetPWM2Dat(dat)  (PWM_DATA2 = dat)

#define PWM1PINAlter( )  {PIN_FUNC |= bPWM1_PIN_X;}                           //PWM映射脚P30
#define PWM2PINAlter( )  {PIN_FUNC |= bPWM2_PIN_X;}                           //PWM映射脚P31

#define ForceClearPWMFIFO( ) {PWM_CTRL |= bPWM_CLR_ALL;}                      //强制清除PWM FIFO和COUNT
#define CancleClearPWMFIFO( ) {PWM_CTRL &= ~bPWM_CLR_ALL;}                    //取消清除PWM FIFO和COUNT

#define PWM1OutEnable()  (PWM_CTRL |= bPWM1_OUT_EN)                           //允许PWM1输出                           
#define PWM2OutEnable()  (PWM_CTRL |= bPWM2_OUT_EN)                           //允许PWM2输出  
#define DsiablePWM1Out() (PWM_CTRL &= ~bPWM1_OUT_EN)                          //关闭PWM1输出                           
#define DisablePWM2Out() (PWM_CTRL &= ~bPWM2_OUT_EN)                          //关闭PWM2输出  

#define PWM1OutPolarHighAct()(PWM_CTRL &= ~bPWM1_POLAR)                       //PWM1输出默认低,高有效                           
#define PWM2OutPolarHighAct()(PWM_CTRL &= ~bPWM2_POLAR)                       //PWM2输出默认低,高有效  
#define PWM1OutPolarLowAct() (PWM_CTRL |= bPWM1_POLAR)                        //PWM1输出默认高,低有效                         
#define PWM2OutPolarLowAct() (PWM_CTRL |= bPWM2_POLAR)                        //PWM2输出默认高,低有效 

/*******************************************************************************
* Function Name  : PWMInterruptEnable()
* Description    : PWM中断使能
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void  PWMInterruptEnable()
{
    PWM_CTRL |= bPWM_IF_END | bPWM_IE_END;                                      //清除PWM中断,使能PWM中断
    IE_PWMX = 1;  
}

void PWM_Init()
{
    P1_MOD_OC &= ~(bPWM1 | bPWM2);                         //设置PWM引脚为推挽输出
    P1_DIR_PU |= bPWM1 | bPWM2; 
    SetPWMClk(94);                                                              //PWM时钟配置 ,Fsys/256/94分频=24000,000/256/94=992Hz
    ForceClearPWMFIFO( );                                                      //强制清除PWM FIFO和COUNT
    CancleClearPWMFIFO( );                                                     //取消清除PWM FIFO和COUNT
    PWM1OutEnable( );                                                          //允许PWM1输出                           
    PWM2OutEnable( );                                                          //允许PWM2输出   

    PWM1OutPolarHighAct( );                                                    //PWM1输出默认低,高有效                                                   
    PWM2OutPolarLowAct( );                                                     //PWM2输出默认高,低有效 
#if PWM_INTERRUPT
    PWMInterruptEnable(); 
    EA = 1;
    SetPWM1Dat(64);                  //占空比25%
    SetPWM2Dat(0x7f); 
#else 
    SetPWM1Dat(0x10);                                                          //占空比0x10/256                                                         
    SetPWM2Dat(0x40); 
    while(1){
      if(PWM_CTRL&bPWM_IF_END){
        PWM_CTRL |= bPWM_IF_END;                                               //清除PWM中断        
        SetPWM1Dat(64);
        SetPWM2Dat(0x7f); 

 //   printf("PWM_CYC_END  %02X\n",(UINT16)PWM_CTRL);
     USBSerial_printf("PWM_CYC_END %02X\n",(uint16_t)PWM_CTRL);// wait for a second
     USBSerial_flush();//等待串口数据发送结束(串口数据发送必不可少)
     }
    }
#endif  
      

}

/*******************************************************************************
* Function Name  : PWMInterrupt(void)
* Description    : PWM中断服务程序   
*******************************************************************************/
void  PWMInterrupt( void )  __interrupt(INT_NO_PWMX)  __using(1)                     //PWM1&2中断服务程序,使用寄存器组1
{
    PWM_CTRL |= bPWM_IF_END;                                                  //清除PWM中断
    SetPWM1Dat(64);
 //   SetPWM2Dat(0x7f); 

 //   LED2_FLAG = !LED2_FLAG;
 //   digitalWrite(LED_PIN, LED_FLAG);  // 翻转LED

}

// 定时器2中断服务函数
void Timer2Interrupt(void) __interrupt(INT_NO_TMR2) __using(3) 
{

    if (TF2) {
        TF2 = 0;  // 清除定时器2溢出标志
        count++;
         if (count >= target) {
             count = 0;
         LED_FLAG = !LED_FLAG;
   // 执行500ms任务
  digitalWrite(LED_BUILTIN, LED_FLAG);  // 翻转LED
    }
    }

}

void Timer2_init()
{

  // 配置定时器2
 T2CON = 0x00;    // 清除T2CON,设置为16位自动重载模式
 T2MOD = 0x00;    // 时钟=Fsys(24MHz)
    
    // 计算定时器初值(24MHz时钟,1ms中断)
    uint16_t timerValue = 65536 - 1000;//1ms
    RCAP2L = timerValue & 0xFF;   // 低8位
    RCAP2H = (timerValue >> 8);   // 高8位
    
    // 装载初值
    TL2 = RCAP2L;
    TH2 = RCAP2H;

    // 使能定时器2中断
    ET2 = 1;  // 使能定时器2中断
    EA = 1;   // 使能全局中断

    // 启动定时器2
    TR2 = 1;
}

// the setup function runs once when you press reset or power the board
void setup() {
  // initialize digital pin LED_BUILTIN as an output.
  pinMode(LED_BUILTIN, OUTPUT);
  digitalWrite(LED_BUILTIN, LOW);
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);  // 初始化为低电平(LED熄灭)
  PWM_Init();
  Timer2_init();
}

// the loop function runs over and over again forever
void loop() {

  //   USBSerial_println("Hello World123!");
  // USBSerial_flush();
  // delay(1000);                       // wait for a second
      
  //   USBSerial_println("perseverance51");// wait for a second
  //   USBSerial_flush();//等待串口数据发送结束(串口数据发送必不可少)
}

  • 同时输出双路PWM输出,在PWM中断中重新装载计数值,PWM1输出波形中偶尔会出现杂波。只启用单路输出没有。两路PWM共用一个中断,只有PWM1有溢出标志位。

网站公告

今日签到

点亮在社区的每一天
去签到