|
STC32G系列单片机的高速PWM可以和CPU工作在不同频率
STC32G12K128系列CPU最高工作频率可达35MHz
STC32G8K64系列CPU最高工作频率可达42MHz
上面两个系列的高级PWM均可工作在144MHz
系统时钟树配置如下:
范例说明:
1、时钟说明:由内部IRC产生12MHz的时钟提供给PLL当作PLL输入时钟,PLL锁频到144MHz输出作为高速PWM的时钟源,
同时144MHz的PLL输出时钟通过CLKDIV进行4或者5分频,产生36MHz或者28.8MHz的时钟提供给CPU当作系统工作频率
2、PWM高速输出说明:PWMA的CC1通道配置为输出模式,并从P2.0口输出频率为28.8MHz,占空比为40%的PWM型号
3、PWM高速捕获说明:PWMB的CC5和CC6通道配置为捕获输入模式,CC5口P2.0口捕获信号的周期值,CC6从P2.0口捕获信号的占空比
4、测试说明:最后通过查询方式得到周期值和占空比并从串口送到PC显示
- #include "stc32g.h"
- #include "stdio.h"
- #include "intrins.h"
- #define FOSC 12000000UL
- #define PLLCLK 144000000UL
- #define MCLKDIV 4 //144M/4=36M
- //#define MCLKDIV 5 //144M/5=28.8M
- #define MCLK PLLCLK
- #define SYSCLK MCLK/MCLKDIV
- #define BAUD (65536 - SYSCLK/4/115200)
- #define MCLK_HIRC 0
- #define MCLK_IRC32K 1
- #define MCLK_IRC48M 2
- #define MCLK_XOSC 3
- #define MCLK_X32K 4
- #define MCLK_PLL 5
- #define MCLK_PLLD2 6
- #define MCLK_SEL MCLK_PLL
- #define HSCK_MCLK 0
- #define HSCK_PLL 1
- #define HSCK_SEL HSCK_PLL
- #define PLL_96M 0
- #define PLL_144M 1
- #define PLL_SEL PLL_144M
- #define CKMS 0x80
- #define HSIOCK 0x40
- #define MCK2SEL_MSK 0x0c
- #define MCK2SEL_SEL1 0x00
- #define MCK2SEL_PLL 0x04
- #define MCK2SEL_PLLD2 0x08
- #define MCK2SEL_IRC48 0x0c
- #define MCKSEL_MSK 0x03
- #define MCKSEL_HIRC 0x00
- #define MCKSEL_XOSC 0x01
- #define MCKSEL_X32K 0x02
- #define MCKSEL_IRC32K 0x03
- #define ENCKM 0x80
- #define PCKI_MSK 0x60
- #define PCKI_D1 0x00
- #define PCKI_D2 0x20
- #define PCKI_D4 0x40
- #define PCKI_D8 0x60
- void delay()
- {
- int i;
-
- for (i=0; i<100; i++);
- }
- char ReadPWMA(char addr)
- {
- char dat;
-
- while (HSPWMA_ADR & 0x80); //等待前一个异步读写完成
- HSPWMA_ADR = addr | 0x80; //设置间接访问地址,只需要设置原XFR地址的低7位
- //HSPWMA_ADDR寄存器的最高位写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_ADDR寄存器的最高位写0,表示写数据
- }
- char ReadPWMB(char addr)
- {
- char dat;
-
- while (HSPWMB_ADR & 0x80); //等待前一个异步读写完成
- HSPWMB_ADR = addr | 0x80; //设置间接访问地址,只需要设置原XFR地址的低7位
- //HSPWMB_ADDR寄存器的最高位写1,表示读数据
- while (HSPWMB_ADR & 0x80); //等待当前异步读取完成
- dat = HSPWMB_DAT; //读取异步数据
-
- return dat;
- }
- void WritePWMB(char addr, char dat)
- {
- while (HSPWMB_ADR & 0x80); //等待前一个异步读写完成
- HSPWMB_DAT = dat; //准备需要写入的数据
- HSPWMB_ADR = addr & 0x7f; //设置间接访问地址,只需要设置原XFR地址的低7位
- //HSPWMB_ADDR寄存器的最高位写0,表示写数据
- }
- void main()
- {
- WTST = 0x00;
- P_SW2 = 0x80;
-
- P0M0 = 0x00; P0M1 = 0x00;
- P1M0 = 0x00; P1M1 = 0x00;
- P2M0 = 0x00; P2M1 = 0x00;
- P3M0 = 0x00; P3M1 = 0x00;
- P5M0 = 0x10; P5M1 = 0x00;
-
- SCON = 0x52;
- AUXR = 0x40;
- TMOD = 0x00;
- TL1 = BAUD;
- TH1 = BAUD >> 8;
- TR1 = 1;
-
- //选择PLL输出时钟
- #if (PLL_SEL == PLL_96M)
- CLKSEL &= ~CKMS; //选择PLL的96M作为PLL的输出时钟
- #elif (PLL_SEL == PLL_144M)
- CLKSEL |= CKMS; //选择PLL的144M作为PLL的输出时钟
- #else
- CLKSEL &= ~CKMS; //默认选择PLL的96M作为PLL的输出时钟
- #endif
-
- //选择PLL输入时钟分频,保证输入时钟为12M
- USBCLK &= ~PCKI_MSK;
- #if (FOSC == 12000000UL)
- USBCLK |= PCKI_D1; //PLL输入时钟1分频
- #elif (FOSC == 24000000UL)
- USBCLK |= PCKI_D2; //PLL输入时钟2分频
- #elif (FOSC == 48000000UL)
- USBCLK |= PCKI_D4; //PLL输入时钟4分频
- #elif (FOSC == 96000000UL)
- USBCLK |= PCKI_D8; //PLL输入时钟8分频
- #else
- USBCLK |= PCKI_D1; //默认PLL输入时钟1分频
- #endif
- //启动PLL
- USBCLK |= ENCKM; //使能PLL倍频
-
- delay(); //等待PLL锁频
-
- //选择主时钟源
- CLKDIV = MCLKDIV; //主时钟选择高速频率前,必须先设置分频系数,否则程序会当掉
-
- CLKSEL &= ~MCKSEL_MSK;
- CLKSEL &= ~MCK2SEL_MSK;
- #if (MCLK_SEL == MCLK_HIRC)
- CLKSEL |= MCKSEL_HIRC; //选择内部高速IRC作为主时钟
- CLKSEL |= MCK2SEL_SEL1; //选择MCKSEL选择的时钟作为主时钟
- #elif (MCLK_SEL == MCLK_IRC32K)
- CLKSEL |= MCKSEL_X32K; //选择外部32K作为主时钟
- CLKSEL |= MCK2SEL_SEL1; //选择MCKSEL选择的时钟作为主时钟
- #elif (MCLK_SEL == MCLK_IRC48M)
- CLKSEL |= MCKSEL_HIRC; //选择内部高速IRC作为主时钟
- CLKSEL |= MCK2SEL_IRC48; //选择内部48M的IRC作为主时钟
- #elif (MCLK_SEL == MCLK_XOSC)
- CLKSEL |= MCKSEL_XOSC; //选择外部高速晶振作为主时钟
- CLKSEL |= MCK2SEL_SEL1; //选择MCKSEL选择的时钟作为主时钟
- #elif (MCLK_SEL == MCLK_X32K)
- CLKSEL |= MCKSEL_IRC32K; //选择内部低速IRC作为主时钟
- CLKSEL |= MCK2SEL_SEL1; //选择MCKSEL选择的时钟作为主时钟
- #elif (MCLK_SEL == MCLK_PLL)
- CLKSEL |= MCKSEL_HIRC; //选择内部高速IRC作为主时钟
- CLKSEL |= MCK2SEL_PLL; //选择PLL输出时钟作为主时钟
- #elif (MCLK_SEL == MCLK_PLLD2)
- CLKSEL |= MCKSEL_HIRC; //选择内部高速IRC作为主时钟
- CLKSEL |= MCK2SEL_PLLD2; //选择PLL输出时钟2分频后的时钟作为主时钟
- #else
- CLKSEL |= MCKSEL_HIRC; //默认选择内部高速IRC作为主时钟
- CLKSEL |= MCK2SEL_SEL1; //默认选择MCKSEL选择的时钟作为主时钟
- #endif
- MCLKOCR = 0x04; //系统时钟4分频后输出到P5.4口
- //选择HSPWM/HSSPI时钟
- #if (HSCK_SEL == HSCK_MCLK)
- CLKSEL &= ~HSIOCK; //HSPWM/HSSPI选择主时钟为时钟源
- #elif (HSCK_SEL == HSCK_PLL)
- CLKSEL |= HSIOCK; //HSPWM/HSSPI选择PLL输出时钟为时钟源
- #else
- CLKSEL &= ~HSIOCK; //默认HSPWM/HSSPI选择主时钟为时钟源
- #endif
- HSCLKDIV = 0; //HSPWM/HSSPI时钟源不分频
-
- HSPWMA_CFG = 0x03; //使能PWMA相关寄存器异步访问功能
- HSPWMB_CFG = 0x03; //使能PWMB相关寄存器异步访问功能
-
- PWMA_PS = 0x01; //PWMA_CC1高速PWM输出到P2.0口
- //PWMB_CC5从P2.0口进行捕获
- //通过异步方式设置PWMA/PWMB的相关寄存器
- WritePWMA((char)&PWMA_CCER1, 0x00);
- WritePWMA((char)&PWMA_CCMR1, 0x00); //CC1为输出模式
- WritePWMA((char)&PWMA_CCMR1, 0x60); //OC1REF输出PWM1(CNT<CCR时输出有效电平1)
- WritePWMA((char)&PWMA_CCER1, 0x05); //使能CC1/CC1N上的输出功能
- WritePWMA((char)&PWMA_ENO, 0x03); //使能PWM信号输出到端口
- WritePWMA((char)&PWMA_BKR, 0x80); //使能主输出
- WritePWMA((char)&PWMA_CCR1H, 0x00); //设置输出PWM的占空比
- WritePWMA((char)&PWMA_CCR1L, 0x02);
- WritePWMA((char)&PWMA_ARRH, 0x00); //设置输出PWM的周期
- WritePWMA((char)&PWMA_ARRL, 0x04);
- WritePWMA((char)&PWMA_CR1, 0x01); //开始PWM计数
- WritePWMB((char)&PWMB_CCER1, 0x00);
- WritePWMB((char)&PWMB_CCMR1, 0x01); //CC5为输入模式,且映射到TI5FP5上
- WritePWMB((char)&PWMB_CCMR2, 0x02); //CC6为输入模式,且映射到TI6FP5上
- WritePWMB((char)&PWMB_CCER1, 0x31); //使能CC5上的捕获功能(上升沿捕获)
- WritePWMB((char)&PWMB_SMCR, 0x54); //上升沿复位模式
- WritePWMB((char)&PWMB_CR1, 0x01); //开始PWM计数
-
- while (1)
- {
- if (ReadPWMB((char)&PWMB_SR1) & 0x02) //等待捕获完成
- {
- WritePWMB((char)&PWMB_SR1, 0x00); //清除完成标志
-
- //读取捕获到的周期值
- printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR5H) & 0xff);
- printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR5L) & 0xff);
- printf(" ");
-
- //读取捕获到的占空比值
- printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR6H) & 0xff);
- printf("%02x", (unsigned int)ReadPWMB((char)&PWMB_CCR6L) & 0xff);
- printf("\n");
- }
- }
- }
复制代码
|
|