嵌入式学习-STC-PWM(脉宽调制)

记录每次学习的过程,总结学习的内容,希望能给到自己和别人帮助。

嵌入式学习-STC-PWM(脉宽调制)

PWM

PWM全称是脉宽调制(Pulse Width Modulation),是一种通过改变信号的脉冲宽度来控制电路输出的技术。控制高电平的占空比。PWM技术在工业自动化、电机控制、LED调光等领域广泛应用。
PWM是一种将数字信号转换为模拟信号的技术,它通过改变信号的占空比来控制输出的电平。在STC8H中,PWM输出的频率和占空比可以由程序控制,因此可以用来控制各种电机、灯光和其他设备的亮度、速度等参数。

STC8H 系列的单片机内部集成了8 通道 16 位高级PWM 定时器,分成两周期可不同的 PWM,分别命名为 PWMA 和PWMB ,可分别单独设置。
第一组 PWMA 可配置成4 组互补/对称/死区控制的PWM 或捕捉外部信号。
第二组 PWMB 可配置成4 路PWM 输出或捕捉外部信号。
两组 PWM 的时钟频率可分别独立设置。
(死区发生器:有一个错位,就能精确知道两个状态切换的时间点,一般用不上,设置为0就可以)

通过逻辑分析仪 可以看出,高电平占比不断减少。
在这里插入图片描述
需要关心的点:
高低电平使用引脚

PWM与引脚对应关系表

在这里插入图片描述
然后根据使用的PWM引脚所在选择PWM通道,选择需要初始化的内容。

初始化PWM

初始化PWMA

#define PERIOD (MAIN_Fosc / 1000)
PWMx_Duty dutyA;
void	PWM_config(void)
{
    PWMx_InitDefine		PWMx_InitStructure;
		
	// 配置PWM1
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyA.PWM1_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect	= ENO1P | ENO1N;	//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM1, &PWMx_InitStructure);			//初始化PWM
	// 配置PWM2
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyA.PWM2_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO2P | ENO2N;	//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM2, &PWMx_InitStructure);			//初始化PWM
	// 配置PWM3
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyA.PWM3_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO3P | ENO3N;	//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM3, &PWMx_InitStructure);	
	// 配置PWM4
    PWMx_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_MODE2
    PWMx_InitStructure.PWM_Duty    		= dutyA.PWM4_Duty;	//PWM占空比时间, 0~Period
    PWMx_InitStructure.PWM_EnoSelect    = ENO4P | ENO4N;	//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
    PWM_Configuration(PWM4, &PWMx_InitStructure);

	// 配置PWMA
    PWMx_InitStructure.PWM_Period   = PERIOD - 1;			//周期时间,   0~65535
    PWMx_InitStructure.PWM_DeadTime = 0;					//死区发生器设置, 0~255
    PWMx_InitStructure.PWM_MainOutEnable= ENABLE;			//主输出使能, ENABLE,DISABLE
    PWMx_InitStructure.PWM_CEN_Enable   = ENABLE;			//使能计数器, ENABLE,DISABLE
    PWM_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_P61
	PWM2_SW(PWM2_SW_P12_P13);			//PWM2_SW_P12_P13,PWM2_SW_P22_P23,PWM2_SW_P62_P63
	PWM3_SW(PWM3_SW_P14_P15);			//PWM3_SW_P14_P15,PWM3_SW_P24_P25,PWM3_SW_P64_P65
	PWM4_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);
}

初始化PWMB

#define PERIOD (MAIN_Fosc / 1000)
PWMx_Duty dutyB;
void	PWM_config(void)
{
	PWMx_InitDefine		PWMx_InitStructure;
	
	// 配置PWM5
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty   	 	= dutyB.PWM5_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO5P;			//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM5, &PWMx_InitStructure);			//初始化PWM,  PWMA,PWMB

	// 配置PWM6
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyB.PWM6_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO6P;			//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM6, &PWMx_InitStructure);			//初始化PWM,  PWMA,PWMB

	// 配置PWM7
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyB.PWM7_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO7P;			//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM7, &PWMx_InitStructure);			//初始化PWM,  PWMA,PWMB

	// 配置PWM8
	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		= dutyB.PWM8_Duty;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect    = ENO8P;			//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM8, &PWMx_InitStructure);			//初始化PWM,  PWMA,PWMB

	// 配置PWMB
	PWMx_InitStructure.PWM_Period   = PERIOD - 1;			//周期时间,   0~65535
	PWMx_InitStructure.PWM_DeadTime = 0;					//死区发生器设置, 0~255
	PWMx_InitStructure.PWM_MainOutEnable= ENABLE;			//主输出使能, ENABLE,DISABLE
	PWMx_InitStructure.PWM_CEN_Enable   = ENABLE;			//使能计数器, ENABLE,DISABLE
	PWM_Configuration(PWMB, &PWMx_InitStructure);			//初始化PWM通用寄存器,  PWMA,PWMB

	// 切换PWM通道
	PWM5_SW(PWM5_SW_P20);					//PWM5_SW_P20,PWM5_SW_P17,PWM5_SW_P00,PWM5_SW_P74
	PWM6_SW(PWM6_SW_P21);					//PWM6_SW_P21,PWM6_SW_P54,PWM6_SW_P01,PWM6_SW_P75
	PWM7_SW(PWM7_SW_P22);					//PWM7_SW_P22,PWM7_SW_P33,PWM7_SW_P02,PWM7_SW_P76
	PWM8_SW(PWM8_SW_P23);					//PWM8_SW_P23,PWM8_SW_P34,PWM8_SW_P03,PWM8_SW_P77

	// 初始化PWMB的中断
	NVIC_PWM_Init(PWMB,DISABLE,Priority_0);
}

使用流程

1.引入依赖和头文件 “STC8H_PWM.h”“NVIC.h”“Switch.h”
拷贝所需库文件
a. STC8H_PWM.cSTC8H_PWM.h
b. NVIC.cNVIC.h
c. Switch.h
2.扩展寄存器访问使能,EAXSFR(); /* 扩展寄存器访问使能 */EXASFR( ) 一定要在PWM_Config( )的前面
3.初始化PWMA/PWMB
4.调用库函数使用

PWM代码流程

1.引入依赖和头文件

#include	"STC8H_PWM.h"
#include	"NVIC.h"
#include	"Switch.h"

2.扩展寄存器访问使能

注意:EXASFR( ) 一定要在PWM_Config( )的前面
由于PWM的配置相关特殊功能寄存器位于扩展RAM区域,访问这些寄存器,需先将P_SW2的BIT7设置为1,才可正常读写。

EAXSFR();		/* 扩展寄存器访问使能 */

凡心所向,素履以往,生如逆旅,一苇以航。

3.初始化PWMA/PWMB

(具体可以往上看初始化PWM内容)
以下为配置注意点:
● 总配置中的 PWM_Period, 配置周期计数。#define PERIOD (MAIN_Fosc / 1000) 1000 表示1s执行1000次。此处为计数值。
● PWM1_Duty表示占空比,1个周期中高电平或者低电平出现的百分比,此处为百分比的计数值

其中
*配置PWM1/PWM2/PWM3/PWM4按照需要进行配置
*配置PWMA 是必须要的 总配置,参数一般不用修改
*切换PWM通道 是必须要的,选择实际使用的PWM1/PWM2/PWM3/PWM4
*初始化PWMA的中断 是必须要的,参数不用修改

4.调用库函数使用

函数声明在STC8H_PWM.h头文件中725,726行 有结构体和函数
duty.PWM4_Duty = d * PERIOD;
UpdatePwm(PWMA,&duty);

使用PWM控制马达

GPIO配置引脚
一定要用推挽输出,不然不够电流驱动马达
(使用P01引脚只是因为01引脚能用pwm功能,不是说马达必须是P01引脚,可以使用其他引脚)

    //电机需要推挽输出才可以
    P0_MODE_OUT_PP(GPIO_Pin_1);

基础功能:
给高电平就启动,低电平关闭

#define MOTOR P01
    GPIO_Config();
    MOTOR=1;
    delay_ms(250);
    delay_ms(250);
    delay_ms(250);
    delay_ms(250);
	MOTOR=0:

升级功能:
通过PWM控制马达

#include "Config.h"
#include "Delay.h"
#include "GPIO.h"
#include "STC8H_PWM.h"
#include "NVIC.h"
#include "Switch.h"

#define MOTOR P01

#define PREQ			1000

#define PERIOD (MAIN_Fosc / PREQ)

void GPIO_config(void) {
	GPIO_InitTypeDef	GPIO_InitStructure;		//结构定义
	GPIO_InitStructure.Pin  = GPIO_Pin_1;		//指定要初始化的IO,
	GPIO_InitStructure.Mode = GPIO_PullUp;	//指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
	GPIO_Inilize(GPIO_P0, &GPIO_InitStructure);//初始化
}
void	PWM_config(void)
{
	PWMx_InitDefine		PWMx_InitStructure;

	PWMx_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_MODE2
	PWMx_InitStructure.PWM_Duty    		=  0;	//PWM占空比时间, 0~Period
	PWMx_InitStructure.PWM_EnoSelect  = ENO6P;				//输出通道选择,	ENO1P,ENO1N,ENO2P,ENO2N,ENO3P,ENO3N,ENO4P,ENO4N / ENO5P,ENO6P,ENO7P,ENO8P
	PWM_Configuration(PWM6, &PWMx_InitStructure);			//初始化PWM,  PWMA,PWMB

	PWMx_InitStructure.PWM_Period   = PERIOD - 1;					//周期时间,   0~65535
	PWMx_InitStructure.PWM_DeadTime = 0;					//死区发生器设置, 0~255
	PWMx_InitStructure.PWM_MainOutEnable= ENABLE;			//主输出使能, ENABLE,DISABLE
	PWMx_InitStructure.PWM_CEN_Enable   = ENABLE;			//使能计数器, ENABLE,DISABLE
	PWM_Configuration(PWMB, &PWMx_InitStructure);			//初始化PWM通用寄存器,  PWMA,PWMB

	PWM6_SW(PWM6_SW_P01);					//PWM6_SW_P21,PWM6_SW_P54,PWM6_SW_P01,PWM6_SW_P75

	NVIC_PWM_Init(PWMB,DISABLE,Priority_0);
}

void main(){
	PWMx_Duty duty;
	u8 duty_percent = 0; // 0 - 100
	
	EAXSFR();
	
	GPIO_config();
	PWM_config();
	
	duty.PWM6_Duty = 0;
	UpdatePwm(PWM6, &duty);
	while(1){
		delay_ms(10);
		
		// 设置占空比
		duty.PWM6_Duty = PERIOD * duty_percent / 100;
		UpdatePwm(PWMB, &duty);
		
		// 修改占空比 0 -> 100
		duty_percent++;
		if(duty_percent > 100){
			duty_percent = 0;
		}
		
	}
}

在这里插入图片描述
![在这里插入图片描述](https://img-blog.csdnimg.cn/1ab2ab2b8ff94c9c8626d81c323104a3.png

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值