• STC16f40k128——PWM


    前言

    PWM(全称Pulse Width Modulation,定频调宽度调制技术),是近年来发展的一种电力电子技术,广泛应用于开关电源,电能变换领域,以及电机驱动等众多领域。PWM本质上是高频率,但占空比可能变化的脉冲波

    产生专门产生PWM信号的集成芯片,也可以使用MCU或者DSP进行配置产生PWM。数字控制器生成PWM具有灵活方便的优点,因此广泛使用控制器产生期望的PWM进行控制。

    STC16F系列的单片机内部集成有PWMA,PWMB类高级PWM。PWMA有8个通道,PWMA1P,PWMA1N到PWMA4P,PWMA4N。

    每一个PWMxP和对应的PWMxN互为一组PWM。可以输出带死区互补对称PWM。而PWMB只有4个通道,分别是PWM5,PWM6,PWM7,PWM8.

    实际开发产品的过程中,基本上都有可能使用到互补对称的PWM波,并且STC16F系列的PWMA类的PWM通道完全够用。因此只需要掌握PWMA的配置方式以及使用方法即可。

    PWM产生原理

    TB(Time Base时基)模块

    在这里插入图片描述
    CK_PSC是主时钟,经预分频器分频后,作为16位计数器[PWM1_CNTRH:PWM1_CNTRL]的计数脉冲。
    这个计数器有3种计数模式,向上计数,向下计数或中央对齐模式。
    在这里插入图片描述
    在这里插入图片描述在这里插入图片描述
    当16位计数器溢出之后,会重新装载重装值进行下一次计数。(类似于定时器的自动重装载模式)

    重复计数寄存器PWM1_RCR用于设置多少次计数器溢出产生一次更新时间。
    在这里插入图片描述

    比较输出模块

    比较输出模块的主要功能是将TB模块中的定时器与一个16位的寄存器[CCRxH:CCRxL]中的值作比较。
    当PWMx_CNT<[CCRxH:CCRxL]以及PWMx_CNT>[CCRxH:CCRxL]时,PWM输出端口的极性。
    在这里插入图片描述
    一种PWM波形配置
    在这里插入图片描述

    代码配置

    综上所述,只需要对PWMx的TB模块和输出比较模块进行相应的配置即可输出对应的PWM波。但是由于STC16F系列的PWM输出端口很灵活,可以根据软件配置在不同的IO口输出PWM。
    在这里插入图片描述
    编写pwm.c文件

    #include "STC16f.h"
    #include "pwm.h"
    #include "led.h"
    
    int PWM1_Duty = 0.1 * TBPRD;
    int PWM2_Duty = 0.1 * TBPRD;
    int PWM3_Duty = 0.5 * TBPRD;
    int PWM4_Duty = 0.9 * TBPRD;  
    
    void Init_PWMA()
    {
    	P_SW2 |= 0x80; 
    
    	PWMA_CCER1 = 0x00; // PWMA的所有通道
    	PWMA_CCER2 = 0x00; // 
    	// 预分频设置
    	PWMA_PSCRH = (PreScale-1) >> 8;
    	PWMA_PSCRL = PreScale-1;
    	
    	// 写PWMA的动作
    	// PWM_CCMRx 寄存器用于配置PWMAx通道
    	PWMA_CCMR1 = 0x60; // upcount,CNT
    	PWMA_CCMR2 = 0x60;
        PWMA_CCMR3 = 0x60;
        PWMA_CCMR4 = 0x60;
    	// CCER1 configures PWM1/2, 使能和输出极性
    	// CCER2 configures PWM3/4, 使能和输出极性
    	PWMA_CCER1 = 0x55; 
    	PWMA_CCER2 = 0x55;
    	// 设置载波计数周期
    	PWMA_ARRH = (TBPRD - 1) >> 8;
    	PWMA_ARRL = TBPRD - 1;
    	// 使能输出
    	PWMA_ENO = 0x00;
        PWMA_ENO |= ENO1P; //使能输出
    //    PWMA_ENO |= ENO1N; //使能输出
        PWMA_ENO |= ENO2P; //使能输出
    //    PWMA_ENO |= ENO2N; //使能输出
    //    PWMA_ENO |= ENO3P; //使能输出
    //    PWMA_ENO |= ENO3N; //使能输出
    //    PWMA_ENO |= ENO4P; //使能输出
    //    PWMA_ENO |= ENO4N; //使能输出
    
    	PWMA_CCR1H = ((unsigned int)PWM1_Duty >> 8); //设置占空比时间
        PWMA_CCR1L = ((unsigned int)PWM1_Duty);
        PWMA_CCR2H = ((unsigned int)PWM2_Duty >> 8); //设置占空比时间
        PWMA_CCR2L = ((unsigned int)PWM2_Duty);
        PWMA_CCR3H = ((unsigned int)PWM3_Duty >> 8); //设置占空比时间
        PWMA_CCR3L = ((unsigned int)PWM3_Duty);
        PWMA_CCR4H = ((unsigned int)PWM4_Duty >> 8); //设置占空比时间
        PWMA_CCR4L = ((unsigned int)PWM4_Duty);
    //   选择输出脚位
    	PWMA_PS = 0x00;  //高级 PWM 通道输出脚选择位
        PWMA_PS |= PWM1_2; //选择 PWM1_2 通道
        PWMA_PS |= PWM2_2; //选择 PWM2_2 通道
        PWMA_PS |= PWM3_2; //选择 PWM3_2 通道
        PWMA_PS |= PWM4_2; //选择 PWM4_2 通道
    	
    
    	
    	// 设置死区
    	PWMA_DTR = 50; // 50*10e-6
    	
    	// 设置PWMA中断
    //	PWMA_IER |= 0x01; // 更新时中断
    //	PWMA_IER |= 1<<1; PWMA1 比较 捕获
    //	PWMA_IER |= 1<<2; PWMA1 比较 捕获
    //	PWMA_IER |= 1<<3; PWMA1 比较 捕获
    //	PWMA_IER |= 1<<4; PWMA1 比较 捕获
    	
    	PWMA_BKR |= 0x80; // 使能总输出
    	PWMA_CR1 |= 0x01; // 开始计数
    	
    	P_SW2 &= 0x7f;
    }
    void Forward()
    {
    	AIN1 = 0;
    	AIN2 = 1;
    	BIN1 = 0;
    	BIN2 = 1;
    }
    void Backward()
    {
    	AIN1=1;
    	AIN2=0;
    	BIN1=1;
    	BIN2=0;
    }
    void PWM1_Duty_Update(unsigned int cmp)
    {
    	P_SW2 |= 0x80;
    	if(cmp > 0.95 * TBPRD)
    		cmp = 0.95 * TBPRD;
    	else if(cmp < 0.05 * TBPRD)
    		cmp = 0.05 * TBPRD;
    	PWMA_CCR1H = ((unsigned int)cmp >> 8); //设置占空比时间
    	PWMA_CCR1L = ((unsigned int)cmp);
    	
    	P_SW2 &= 0x7f;
    }
    void PWM2_Duty_Update(unsigned int cmp)
    {	
    	P_SW2 |= 0x80;
    	if(cmp > 0.95 * TBPRD)
    		cmp = 0.95 * TBPRD;
    	else if(cmp < 0.05 * TBPRD)
    		cmp = 0.05 * TBPRD;
    	
    	PWMA_CCR2H = ((unsigned int)cmp >> 8); //设置占空比时间
    	PWMA_CCR2L = ((unsigned int)cmp);
    	
    	P_SW2 &= 0x7f;
    }
    void PWM3_Duty_Update(unsigned int cmp)
    {
    	P_SW2 |= 0x80;
    	if(cmp > 0.95 * TBPRD)
    		cmp = 0.95 * TBPRD;
    	else if(cmp < 0.05 * TBPRD)
    		cmp = 0.05 * TBPRD;
    	PWMA_CCR3H = ((unsigned int)cmp >> 8); //设置占空比时间
    	PWMA_CCR3L = ((unsigned int)cmp);
    	
    	P_SW2 &= 0x7f;
    }
    void PWM4_Duty_Update(unsigned int cmp)
    {	
    	P_SW2 |= 0x80;
    	if(cmp > 0.95 * TBPRD)
    		cmp = 0.95 * TBPRD;
    	else if(cmp < 0.05 * TBPRD)
    		cmp = 0.05 * TBPRD;
    	
    	PWMA_CCR4H = ((unsigned int)cmp >> 8); //设置占空比时间
    	PWMA_CCR4L = ((unsigned int)cmp);
    	
    	P_SW2 &= 0x7f;
    }
    void PWMA_Routine(void) interrupt 7
    {
    	static int i=0;
    	static int j=0;
    	i++;
    	if(i>=2000)
    	{
    		i=0;
    		j++;
    		if(j==500)
    		{
    			j=0;
    		}
    	}	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154

    编写pwm.h文件

    #ifndef _PWM_H_
    #define _PWM_H_
     
    #define AIN1 P05
    #define AIN2 P07
    #define BIN1 P03
    #define BIN2 P02
    
    #define PreScale 24 // 对主频进行的分频系数
    #define TBPRD  100// 时基模块的计数值,决定开关周期
    
    // PWMA各个通道的端口选择
    #define PWM1_0      0x00	//P:P1.0  N:P1.1
    #define PWM1_1      0x01	//P:P2.0  N:P2.1
    #define PWM1_2      0x02	//P:P6.0  N:P6.1
    
    #define PWM2_0      0x00	//P:P5.4  N:P1.3
    #define PWM2_1      0x04	//P:P2.2  N:P2.3
    #define PWM2_2      0x08	//P:P6.2  N:P6.3
    
    #define PWM3_0      0x00	//P:P1.4  N:P1.5
    #define PWM3_1      0x10	//P:P2.4  N:P2.5
    #define PWM3_2      0x20	//P:P6.4  N:P6.5
    
    #define PWM4_0      0x00	//P:P1.6  N:P1.7
    #define PWM4_1      0x40	//P:P2.6  N:P2.7
    #define PWM4_2      0x80	//P:P6.6  N:P6.7
    #define PWM4_3      0xC0	//P:P3.4  N:P3.3
    
    // PWM输出端口使能
    #define ENO1P       0x01
    #define ENO1N       0x02
    #define ENO2P       0x04
    #define ENO2N       0x08
    #define ENO3P       0x10
    #define ENO3N       0x20
    #define ENO4P       0x40
    #define ENO4N       0x80
    
    extern int PWM1_Duty;
    extern int PWM2_Duty;
    extern int PWM3_Duty;
    extern int PWM4_Duty;
    
    void InitPWMA(void);
    void Forward(void);
    void Backward(void);
    void PWM1_Duty_Update(unsigned int cmp);
    void PWM2_Duty_Update(unsigned int cmp);
    void PWM3_Duty_Update(unsigned int cmp);
    void PWM4_Duty_Update(unsigned int cmp);
    //void PWMA_Routine(void) interrupt 7
    
    #endif
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
  • 相关阅读:
    Spring Boot 邮件发送(五种类型的邮件)
    Java8新特性Stream流详解
    reactive和effect,依赖收集触发依赖
    java计算机毕业设计Web医学院校大学生就业信息管理系统源码+mysql数据库+系统+lw文档+部署1
    TensorFlow 的基本概念和使用场景
    git记录
    语义分割研究现状
    openai assistants(机器人助理)彩色图片转黑白
    Redis从入门到放弃(9):集群模式
    重学SpringBoot3-日志Logging
  • 原文地址:https://blog.csdn.net/xht2403267701/article/details/127649876