如何測量72MHz以下的外部信號,STC32的144MHz的高速PWM
STC32G12K128-35MHz-LQFP64/48/32,TSSOP20
STC32G8K64-42MHz-LQFP48/32
STC8H1K08T-33I-TSSOP20/QFN20
的高速 144MHz ~ 196MHz 的PWM, 可以捕獲外部脈沖信號,可以工作在 144MHz 以上
理論上 STC32G系列可以測量 144MHz/2以下頻率的信號
已驗證了:
1, 內部 HIRC-12MHz
2, HIRC-12MHz / 10 = 1.2MHz低頻 給 STC32G12K128的CPU使用
3, HIRC-12MHz通過 PLL產生144MHz做PWM的時鐘源, PWMB組產生 28.8MHz信號源
4, PWMA組側量 28.8MHz的信號源正確 !
5, 等72MHz信號發生器來測試72MHz
jpg 3.15-001.png (295.03 KB, 下載次數: 60)
下載附件
2023-3-15 14:30 上傳
jpg 3.15-002.png (313.04 KB, 下載次數: 48)
下載附件
2023-3-15 14:30 上傳
jpg 3.15-003.png (186.49 KB, 下載次數: 60)
下載附件
2023-3-15 14:30 上傳
jpg 3.15-004.png (186.49 KB, 下載次數: 59)
下載附件
2023-3-15 14:31 上傳
STC32G系列單片機的高速PWM可以和CPU工作在不同頻率
STC32G12K128系列CPU最高工作頻率可達35MHz
STC32G8K64系列CPU最高工作頻率可達42MHz
上面兩個系列的高級PWM均可工作在144MHz
jpg 3.15-005.png (147.31 KB, 下載次數: 63)
下載附件
2023-3-15 14:32 上傳
范例說明:
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");
}
}
}
|