🎬 秋野醬:《個人主頁》
🔥 個人專欄:《Java專欄》《Python專欄》
??心若有所向往,何懼道阻且長
文章目錄
- PWM基礎概念
- STC8H芯片
- PWMA應用
- PWM配置詳解
- 占空比
PWM基礎概念
PWM全稱是脈寬調制(Pulse Width Modulation),是一種通過改變信號的脈沖寬度來控制電路輸出的技術。PWM技術在工業自動化、電機控制、LED調光等領域廣泛應用。
PWM是一種將數字信號轉換為模擬信號的技術,它通過改變信號的占空比來控制輸出的電平。在STC8H中,PWM輸出的頻率和占空比可以由程序控制,因此可以用來控制各種電機、燈光和其他設備的亮度、速度等參數。
STC8H芯片
STC8H 系列的單片機內部集成了8 通道 16 位高級PWM 定時器,分成兩周期可不同的 PWM,分別命名為 PWMA 和PWMB ,可分別單獨設置。
第一組 PWMA 可配置成4 組互補/對稱/死區控制的PWM 或捕捉外部信號。
第二組 PWMB 可配置成4 路PWM 輸出或捕捉外部信號。
兩組 PWM 的時鐘頻率可分別獨立設置。
PWM與引腳對應關系如下圖:
PWMA應用
控制引腳P2.7實現LED燈1的呼吸效果。
- 拷貝所需庫文件(其他必備庫請自行準備)
a. STC8H_PWM.cSTC8H_PWM.h
b. NVIC.cNVIC.h
c. Switch.h - 導入頭文件,初始化宏及全局變量
#include "Config.h"
#include "GPIO.h"
#include "Delay.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"#define LED_SW P45#define LED1 P27
#define LED2 P26
#define LED3 P15#define FREQ 1000#define PERIOD ((MAIN_Fosc / FREQ) - 1) // 周期PWMx_Duty dutyA;
配置GPIO
void GPIO_config(void) {GPIO_InitTypeDef GPIO_InitStructure; //結構定義// LED_SWGPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P4, &GPIO_InitStructure);//初始化// P2GPIO_InitStructure.Pin = GPIO_Pin_6 | GPIO_Pin_7; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的輸入或輸出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P2, &GPIO_InitStructure);//初始化
}
配置PWM
void PWM_config(void)
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM4PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE2; //模式, CCMRn_FREEZE,CCMRn_MATCH_VALID,CCMRn_MATCH_INVALID,CCMRn_ROLLOVER,CCMRn_FORCE_INVALID,CCMRn_FORCE_VALID,CCMRn_PWM_MODE1,CCMRn_PWM_MODE2PWMx_InitStructure.PWM_Duty = 0; //PWM占空比時間, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO4P | ENO4N; //輸出通道選擇, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM4, &PWMx_InitStructure);// 配置PWMAPWMx_InitStructure.PWM_Period = PERIOD; //周期時間, 0~65535PWMx_InitStructure.PWM_DeadTime = 0; //死區發生器設置, 0~255PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主輸出使能, ENABLE,DISABLEPWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能計數器, ENABLE,DISABLEPWM_Configuration(PWMA, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB// 切換PWM4選擇PWM4_SW_P26_P27PWM4_SW(PWM4_SW_P26_P27); //PWM4_SW_P16_P17,PWM4_SW_P26_P27,PWM4_SW_P66_P67,PWM4_SW_P34_P33// 初始化PWMA的中斷NVIC_PWM_Init(PWMA,DISABLE,Priority_0);
}
編寫Main函數
void main() {char direction = 1;u8 duty_percent = 0;// 0 -> 100EAXSFR(); /* 擴展寄存器訪問使能, 必寫! */GPIO_config();PWM_config();EA = 1;// 總開關LED_SW = 0;LED1 = 0; // P2.7 PWM4LED2 = 0;LED3 = 0;// 循環之前,設置一次pwm(可選)dutyA.PWM4_Duty = PERIOD * duty_percent / 100;UpdatePwm(PWM4, &dutyA);// 0 -> 100while(1) {duty_percent += direction;// 讓duty_percent一直在0-100來回往返if(duty_percent >= 100) {duty_percent = 100;direction = -1;} else if(duty_percent <= 0) {duty_percent = 0;direction = 1;}// 修改PWM4的dutydutyA.PWM4_Duty = PERIOD * duty_percent / 100;UpdatePwm(PWM4, &dutyA);delay_ms(10);}
}
PWM配置詳解
周期
系統主頻:1秒鐘計數多少次。
代碼中的PWM周期(PWM Period),指的是按N等份切分1秒鐘,每個等份的計數值。
例如上圖,我們按照8等份切分1秒鐘的總計數值MAIN_Fosc(主頻),每個PWM周期的計數值為:
PWM_Period = MAIN_Fosc / 8 = 24M / 8 = 3M = 3 000 000 單位為次。
即如果將這個3M作為Period參數,可以得到PWM方波每個周期的時長為:
1 / 8 = 0.125s
代碼中的配置:
#define PERIOD (MAIN_Fosc / FREQ) // 周期
PWMx_InitStructure.PWM_Period = PERIOD - 1;
配置的是周期中的計數值。
我們的理解策略:通常我們不關心計數值,關心的是1秒鐘執行多少次(即頻率Hz),也就是一秒鐘多少個周期。
因此在代碼MAIN_Fosc / 1000中的1000表示的是1秒鐘多少個周期(即頻率Hz)。
MAIN_Fosc / 1000表示的是每個周期的計數值。那為什么要-1呢?因為計數器是從0開始計數的。
占空比
在一個PWM的周期計數中,高電平的計數時長百分比。
模式
● 凍結: CCMRn_FREEZE
● 匹配時設置通道 n 的輸出為有效電平: CCMRn_MATCH_VALID
● 匹配時設置通道 n 的輸出為無效電平: CCMRn_MATCH_INVALID
● 翻轉: CCMRn_ROLLOVER
● 強制為無效電平: CCMRn_FORCE_INVALID
● 強制為有效電平: CCMRn_FORCE_VALID
● PWM 模式 1: CCMRn_PWM_MODE1
● PWM 模式 2: CCMRn_PWM_MODE2
常用的為PWM 模式 1PWM 模式 2
PWM 模式 1和PWM 模式 2是反向的,一個占空比越大越亮,一個是越小越亮。
使能PWM
PWMx_InitStructure.PWM_MainOutEnable= ENABLE; //主輸出使能, ENABLE,DISABLE
PWMx_InitStructure.PWM_CEN_Enable = ENABLE; //使能計數器, ENABLE,DISABLE
PWM_Configuration(PWMA, &PWMx_InitStructure); //初始化PWM通用寄存器, PWMA,PWMB
引腳配置
PWM4_SW(PWM4_SW_P26_P27);
使能配置成功后,pwm才能工作。
如果運行中pwm想停止掉,也可以通過配置使能來停止。
EAXSFR擴展寄存器
由于PWM的配置相關特殊功能寄存器位于擴展RAM區域,訪問這些寄存器,需先將P_SW2的BIT7設置為1,才可正常讀寫。
EAXSFR(); /* 擴展寄存器訪問使能 */