PWM常用库函数(STC8系列)
STC8系列PWM操作常用库函数
STC8系列单片机通过增强型PWM模块提供灵活的脉冲宽度调制功能。以下是核心库函数及其使用说明:
1. PWM初始化函数
普通版:
/*** @brief 初始化PWM通道* @param ch: PWM通道号 (0-7)* @param freq: PWM频率 (单位: Hz)* @param duty: 初始占空比 (0.0-1.0)*/
void PWM_Init(uint8_t ch, uint32_t freq, float duty);
功能:配置PWM时钟源、分频系数和周期寄存器。频率范围参考公式:
fPWM=fsys(PWMAPS+1)×(PWMAARR+1)f_{PWM} = \frac{f_{sys}}{(PWMA_PS + 1) \times (PWMA_ARR + 1)}fPWM=(PWMAPS+1)×(PWMAARR+1)fsys
函数版:
#define PERIOD (MAIN_Fosc / 1000)
PWMx_Duty dutyA;
void PWM_config(void)
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM1PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, 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 = dutyA.PWM1_Duty; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO1P | ENO1N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM1, &PWMx_InitStructure); //初始化PWM// 配置PWM2PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, 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 = dutyA.PWM2_Duty; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO2P | ENO2N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM2, &PWMx_InitStructure); //初始化PWM// 配置PWM3PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, 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 = dutyA.PWM3_Duty; //PWM占空比时间, 0~PeriodPWMx_InitStructure.PWM_EnoSelect = ENO3P | ENO3N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM3, &PWMx_InitStructure); // 配置PWM4PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式, 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 = dutyA.PWM4_Duty; //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 - 1; //周期时间, 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// 切换PWM通道PWM1_SW(PWM1_SW_P10_P11); //PWM1_SW_P10_P11,PWM1_SW_P20_P21,PWM1_SW_P60_P61PWM2_SW(PWM2_SW_P12_P13); //PWM2_SW_P12_P13,PWM2_SW_P22_P23,PWM2_SW_P62_P63PWM3_SW(PWM3_SW_P14_P15); //PWM3_SW_P14_P15,PWM3_SW_P24_P25,PWM3_SW_P64_P65PWM4_SW(PWM4_SW_P16_P17); //PWM4_SW_P16_P17,PWM4_SW_P26_P27,PWM4_SW_P66_P67,PWM4_SW_P34_P33// 初始化PWMA的中断NVIC_PWM_Init(PWMA,DISABLE,Priority_0);
}
实现原理:通过修改捕获比较寄存器值:
CCR=duty×(ARR+1)CCR = duty \times (ARR + 1)CCR=duty×(ARR+1)
2. 扩展寄存器访问使能
EAXSFR(); /* 扩展寄存器访问使能 */
//写在main函数中
3. 频率更新函数
/*** @brief 动态更新PWM频率* @param ch: PWM通道号* @param freq: 新频率值 (单位: Hz)*/
void PWM_SetFreq(uint8_t ch, uint32_t freq);
注意:修改频率时会保持当前占空比不变。
4. PWM输出控制
// 开启PWM输出
void PWM_Enable(uint8_t ch);// 关闭PWM输出
void PWM_Disable(uint8_t ch);
使用示例
使用了库函数封装的一些数据
#include "GPIO.h" //依赖的库函数
#include"Delay.h"
#include "UART.h"
#include "NVIC.h"
#include "Switch.h"
#include "STC8H_PWM.h"// 1000就是频率 周期 1s/1000 ===> 1ms
#define PERIOD (MAIN_Fosc / 1000) // 周期
#define LED_SW P45
#define LED1 P27
#define LED2 P26
#define LED3 P15
#define LED4 P14
#define LED5 P23
#define LED6 P22
#define LED7 P21
#define LED8 P20void GPIO_config(void) {GPIO_InitTypeDef GPIO_InitStructure; //结构定义GPIO_InitStructure.Pin = GPIO_Pin_0 |GPIO_Pin_1; //指定要初始化的IO,GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PPGPIO_Inilize(GPIO_P3, &GPIO_InitStructure);//初始化P4_MODE_IO_PU(GPIO_Pin_5);P2_MODE_IO_PU(GPIO_Pin_7);P2_MODE_IO_PU(GPIO_Pin_6);P1_MODE_IO_PU(GPIO_Pin_5);P1_MODE_IO_PU(GPIO_Pin_4);P2_MODE_IO_PU(GPIO_Pin_3);P2_MODE_IO_PU(GPIO_Pin_2);P2_MODE_IO_PU(GPIO_Pin_1);P2_MODE_IO_PU(GPIO_Pin_0);LED_SW = 0 ; }
void UART_config(void) {// >>> 记得添加 NVIC.c, UART.c, UART_Isr.c <<<COMx_InitDefine COMx_InitStructure; //结构定义COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTxCOMx_InitStructure.UART_BRT_Use = BRT_Timer1; //选择波特率发生器, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLECOMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLEUART_Configuration(UART1, &COMx_InitStructure); //初始化串口1 UART1,UART2,UART3,UART4NVIC_UART1_Init(ENABLE,Priority_1); //中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3UART1_SW(UART1_SW_P30_P31); // 引脚选择, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17,UART1_SW_P43_P44
}// PWM配置
void PWM_config()
{PWMx_InitDefine PWMx_InitStructure;// 配置PWM4 // =========================== 模式 需要先用1 PWMx_InitStructure.PWM_Mode = CCMRn_PWM_MODE1; //模式// =========================== PWM高电平占空比时间, 0~PeriodPWMx_InitStructure.PWM_Duty = (0.0/100.0) * PERIOD; // =========================== 只用ENO4NPWMx_InitStructure.PWM_EnoSelect = ENO4P|ENO4N; //输出通道选择, ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8PPWM_Configuration(PWM4, &PWMx_InitStructure);// 配置PWMA// =========================== 周期 - 1PWMx_InitStructure.PWM_Period = PERIOD - 1; //周期时间, 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);
}
void PWM4_Updata_duty(char value){PWMx_Duty duty;duty.PWM4_Duty =(value /100.0)*PERIOD;UpdatePwm(PWM4,&duty);}void main() {char value = 50 ;u8 i ;EAXSFR ();EA = 1;GPIO_config();UART_config();PWM_config();PWM4_Updata_duty(value);while (1){ //超时计数if(--COM1.RX_TimeOut == 0) {if(COM1.RX_Cnt > 0) {// 这里处理收到的数据,做具体的逻辑,可以调用自己的on_uart1_recvfor(i=0; i<COM1.RX_Cnt; i++) {// RX1_Buffer[i]存的是接收的每个字节,写出用 TX1_write2buff}if (RX1_Buffer[0] == 0x01){value+=5;if (value >100)value = 100;}else if (RX1_Buffer[0] == 0x02){value-=5;if (value <0)value = 0;}PWM4_Updata_duty(value);printf("value = %d\n",(int)value);}COM1.RX_Cnt = 0;}
}// 不要处理的太快
delay_ms(10);}