STC32G144K246,高速PWM@240Mhz 运行测试
高速PWM@240MHz 运行测试, STC32G144K246:
程序使用CHIPID参数固定内部时钟为24Mhz,
且通过HPLL功能升频至480MHz
其中,给CPU的为120MHz分频时钟,
给PWM外设的为240MHz分频时钟
串口使用115200波特率,
内部带有异步写入PWMA@240MHz和异步读取示例
效果是P60~P67上输出一个互补且循环自增的占空比,
表现为LED灯从最暗到最亮然后再继续循环

实际测量程序输出为:
58Khz,PWMA无预分频,PWMA_ARR设置为4096,
所以58Khz*4096=237Mhz,与理论值240Mhz接近

以下为程序代码和编译通过的程序文件:
这个是与CPU同频的PWM输出示例:

STC32G144K246 输出PWM测试.zip (74.59 KB, 下载次数: 4)
这个是与CPU不同频率的PWM输出示例:

STC32G144K246 240MHz-HSPWM.zip (212.39 KB, 下载次数: 3)
程序内容:
#include "STC32G.H"#include "stdio.h"#include "stdarg.h"//本例程使用CHIPID内预置参数,设置HIRC为24MHz//使用HPLL1,提供60Mhz,80Mhz,120Mhz的设置例程#define Fosc_60Mhz 0 //系统时钟为60Mhz#define Fosc_80Mhz 1 //系统时钟为80Mhz#define Fosc_120Mhz 2//系统时钟为120Mhz#define Main_Fosc Fosc_120Mhz //设置系统时钟为120Mhzvoid CLK_Init(void); //设置系统时钟,由Main_Fosc定义设置void Timer0_Init(void); //定时器0初始化函数void Io_Init(void); //I/O口初始化函数,设置P32为开漏+打开内部上拉电阻模式void Uart1_Init(void); //串口初始化函数,500000bpsvoid Pwm_Init(void); //PWM初始化函数void UpdatePwm(void); //更新PWM占空比函数void UpdateHSPwm(void); //更新高速PWM占空比函数void WritePWMA(char addr, char dat); //异步方式写入PWM寄存器char ReadPWMA(char addr); //异步方式读出PWM寄存器void uart_send(int num);bit P32_OUT = 1; //用于确定输出电平char uart_buff[64] = {0};unsigned int PWM1_Duty = 100, PWM2_Duty = 500, PWM3_Duty = 2000, PWM4_Duty = 4000, Duty_All = 0;void Delay100ms(void) //@120MHz{unsigned long edata i;_nop_();_nop_();i = 2999998UL;while (i) i--;}unsigned int read_pwmh = 0, read_pwml = 0;void main(void){EAXFR = 1; //使能访问扩展RAM区特殊功能寄存器(XFR)CKCON &= ~0x07; //清空[2:0],设置外部数据总线等待时钟为0(最快),默认为7CLK_Init(); //设置HPLL时钟为指定频率Timer0_Init(); //初始化定时器0,50毫秒@120MHzUart1_Init(); //串口初始化函数,115200bpsPwm_Init(); //PWM初始化函数HSPWMA_CFG = 0x03; //使能 PWMA 相关寄存器异步访问功能HPLL2CR &= ~(3<<5); //清空高速外设时钟选择HPLL2CR |= (0<<5); //选择HPLL1/2Io_Init(); //初始化I/O口,设置P32等效为原准双向口模式(开漏模式+打开内部上拉电阻)EA = 1; //打开总中断while(1){//用户程序Duty_All = (Duty_All+150)&0xfff;//限制最大值4095PWM1_Duty = PWM2_Duty = PWM3_Duty = PWM4_Duty = Duty_All;//调整占空比//UpdatePwm();//更新占空比UpdateHSPwm();read_pwmh = (unsigned char)ReadPWMA((char)&PWMA_CCR1H);read_pwml = (unsigned char)ReadPWMA((char)&PWMA_CCR1L);uart_send(sprintf(uart_buff, "read_pwm_cnt:0x%x%x, duty:%u\r\n",read_pwmh, read_pwml, Duty_All));//串口回传当前占空比Delay100ms();}}bit uart_flag = 0;void send_dat(char c){uart_flag = 1;SBUF = c;while(uart_flag);}int data dat_len = 0;void uart_send(int num){for(dat_len = 0; dat_len<num; dat_len++){send_dat(uart_buff[dat_len]);}}void Uart1_Isr(void) interrupt 4{if (TI) //检测串口1发送中断{TI = 0; //清除串口1发送中断请求位uart_flag = 0;}if (RI) //检测串口1接收中断{RI = 0; //清除串口1接收中断请求位}}void Uart1_Init(void) //115200bps@120MHz{SCON = 0x50; //8位数据,可变波特率AUXR |= 0x40; //定时器时钟1T模式AUXR &= 0xFE; //串口1选择定时器1为波特率发生器TMOD &= 0x0F; //设置定时器模式TL1 = 0xFC; //设置定时初始值TH1 = 0xFE; //设置定时初始值ET1 = 0; //禁止定时器中断TR1 = 1; //定时器1开始计时ES = 1; //使能串口1中断}char data off_t0_cnt = 0;void Timer0_Isr(void) interrupt 1{if(P32_OUT == 1&&P32 == 0&&off_t0_cnt<100)off_t0_cnt++; //判断外部P32按键按下一定时间时,关闭定时器0if(off_t0_cnt>5)TR0 = 0;//注:仅在P32输出为1的时候,外部的按键按下才能被读到P32_OUT = ~P32_OUT;//每隔10ms亮/灭切换一次P32 = P32_OUT; //将输出电平给P32管脚}void Timer0_Init(void) //50毫秒@120MHz{TM0PS = 0x5B; //设置定时器时钟预分频 ( 注意:并非所有系列都有此寄存器,详情请查看数据手册 )AUXR |= 0x80; //定时器时钟1T模式TMOD &= 0xF0; //设置定时器模式TL0 = 0x3F; //设置定时初始值TH0 = 0x01; //设置定时初始值TF0 = 0; //清除TF0标志TR0 = 1; //定时器0开始计时ET0 = 1; //使能定时器0中断T0CLKO = 1; //使能P35输出定时器溢出时钟}void Io_Init(void){P3M0 = 0x26; P3M1 = 0xdd;P3PU = 0x05;P3SR = 0xdc;P3DR = 0xdc;P6M0 = 0xff; P6M1 = 0x00; //推挽输出,P6,PWMP6SR = 0x00; //转换速度和驱动电流最大,P6P6DR = 0x00;}void Delay10ms(void) //@120MHz{unsigned long edata i;_nop_();_nop_();i = 299998UL;while (i) i--;}void CLK_Init(void){#if Main_Fosc == Fosc_120MhzWTST = 4;CLKDIV = 2; //设置系统时钟=480MHz/2/2=120MHz,(因为CLKSEL选择时,已经将HPLL/2了)#elif Main_Fosc == Fosc_80MhzWTST = 3;CLKDIV = 3; //设置系统时钟=480MHz/2/3=80MHz#elif Main_Fosc == Fosc_60MhzWTST = 2;CLKDIV = 4; //设置系统时钟=480MHz/2/4=60MHz#endif//以下为超过60MHz时,系统时钟使用HPLL方式提供VRTRIM = CHIPID22; //载入27MHz频段的VRTRIM值IRTRIM = CHIPID12; //指定当前HIRC为24MHz,此时会覆盖掉ISP设置的时钟频率IRCBAND &= ~0x03; //清空频段选择IRCBAND |= 0x01; //选择27Mhz频段HPLLCR &= ~0x10; //选择HPLL输入时钟源为HIRCHPLLPDIV = 4; //24MHz/4=6MHz,需要保证输入HPLL的时钟在6MHz附近HPLLCR |= 0x0e; //HPLL=6MHz*80=480MHzHPLLCR |= 0x80; //使能HPLLDelay10ms();CLKSEL &= ~0x03; //BASE_CLK选择为HIRC,用以提供给HPLLCLKSEL &= ~0x0c; //清空主时钟源选择CLKSEL |= 1<<2; //设置主时钟源为内部 HPLL1 输出/2}#define PWM1_1 0x00 //P:P1.0 N:P1.1#define PWM1_2 0x01 //P:P2.0 N:P2.1#define PWM1_3 0x02 //P:P6.0 N:P6.1#define PWM2_1 0x00 //P:P1.2/P5.4 N:P1.3#define PWM2_2 0x04 //P:P2.2 N:P2.3#define PWM2_3 0x08 //P:P6.2 N:P6.3#define PWM3_1 0x00 //P:P1.4 N:P1.5#define PWM3_2 0x10 //P:P2.4 N:P2.5#define PWM3_3 0x20 //P:P6.4 N:P6.5#define PWM4_1 0x00 //P:P1.6 N:P1.7#define PWM4_2 0x40 //P:P2.6 N:P2.7#define PWM4_3 0x80 //P:P6.6 N:P6.7#define PWM4_4 0xC0 //P:P3.4 N:P3.3#define ENO1P 0x01#define ENO1N 0x02#define ENO2P 0x04#define ENO2N 0x08#define ENO3P 0x10#define ENO3N 0x20#define ENO4P 0x40#define ENO4N 0x80void Pwm_Init(void){PWMA_CCER1 = 0x00; //写 CCMRx 前必须先清零 CCxE 关闭通道PWMA_CCER2 = 0x00;PWMA_CCMR1 = 0x60; //通道模式配置PWMA_CCMR2 = 0x60;PWMA_CCMR3 = 0x60;PWMA_CCMR4 = 0x60;PWMA_CCER1 = 0x55; //配置通道输出使能和极性PWMA_CCER2 = 0x55;PWMA_ARRH = 0x0f; //设置周期时间PWMA_ARRL = 0xff;PWMA_DTR = 0x40; //设置死区时间PWMA_PSCRH = 0; //设置预分频器PWMA_PSCRL = 0; //设置预分频器PWMA_ENO = 0x00;PWMA_ENO |= ENO1P; //使能输出PWMA_ENO |= ENO1N; //使能输出PWMA_ENO |= ENO2P; //使能输出PWMA_ENO |= ENO2N; //使能输出PWMA_ENO |= ENO3P; //使能输出PWMA_ENO |= ENO3N; //使能输出PWMA_ENO |= ENO4P; //使能输出PWMA_ENO |= ENO4N; //使能输出PWMA_PS = 0x00; //高级 PWM 通道输出脚选择位PWMA_PS |= PWM1_3; //选择 PWM1_3 通道PWMA_PS |= PWM2_3; //选择 PWM2_3 通道PWMA_PS |= PWM3_3; //选择 PWM3_3 通道PWMA_PS |= PWM4_3; //选择 PWM4_3 通道UpdatePwm();PWMA_BKR = 0x80; //使能主输出PWMA_CR1 |= 0x01; //开始计时}void UpdatePwm(void){PWMA_CCR1H = (unsigned char)(PWM1_Duty >> 8); //设置占空比时间PWMA_CCR1L = (unsigned char)(PWM1_Duty);PWMA_CCR2H = (unsigned char)(PWM2_Duty >> 8); //设置占空比时间PWMA_CCR2L = (unsigned char)(PWM2_Duty);PWMA_CCR3H = (unsigned char)(PWM3_Duty >> 8); //设置占空比时间PWMA_CCR3L = (unsigned char)(PWM3_Duty);PWMA_CCR4H = (unsigned char)(PWM4_Duty >> 8); //设置占空比时间PWMA_CCR4L = (unsigned char)(PWM4_Duty);}void UpdateHSPwm(void){WritePWMA((char)&PWMA_CCR1H,(unsigned char)(PWM1_Duty >> 8));WritePWMA((char)&PWMA_CCR1L,(unsigned char)(PWM1_Duty));WritePWMA((char)&PWMA_CCR2H,(unsigned char)(PWM2_Duty >> 8));WritePWMA((char)&PWMA_CCR2L,(unsigned char)(PWM2_Duty));WritePWMA((char)&PWMA_CCR3H,(unsigned char)(PWM3_Duty >> 8));WritePWMA((char)&PWMA_CCR3L,(unsigned char)(PWM3_Duty));WritePWMA((char)&PWMA_CCR4H,(unsigned char)(PWM4_Duty >> 8));WritePWMA((char)&PWMA_CCR4L,(unsigned char)(PWM4_Duty));}char ReadPWMA(char addr){char dat;while (HSPWMA_ADR & 0x80);//等待前一个异步读写完成HSPWMA_ADR = addr | 0x80;//设置间接访问地址,只需要设置原 XFR 地址的低 7 位。HSPWMA_ADR 寄存器的最高位写 1,表示读数据while (HSPWMA_ADR & 0x80);//等待当前异步读取完成dat = HSPWMA_DAT;//读取异步数据return dat;}void WritePWMA(char addr, char dat){while (HSPWMA_ADR & 0x80);//等待前一个异步读写完成HSPWMA_DAT = dat;//准备需要写入的数据HSPWMA_ADR = addr & 0x7f;//设置间接访问地址,只需要设置原 XFR 地址的低 7 位。HSPWMA_ADR 寄存器的最高位写 0,表示写数据}
STC32G144K246,高速PWM@240Mhz 运行测试
https://www.stcaimcu.com/thread-20680-1-1.html
(出处: 国芯人工智能技术交流网站)
