06 蓝桥杯单片机设计与开发_基础模块_PWM

一、前言

05 蓝桥杯单片机设计与开发_基础模块_AT24C02-CSDN博客,承接上文,本文将继续介绍剩余蓝桥杯涉及模块(PWM、串口通信、NE555以及超声波测距),为大家做出详细编程指导。

二、PWM

PWM 是脉宽调制(Pulse Width Modulation)的缩写。它是一种常用的调制技术,用于控制电子设备中的电源或信号。通过调整 PWM 信号的占空比,可以实现对输出信号的精确控制。

1、PWM原理剖析

本文将编写程序,实现:频率为 1000Hz ,占空比可通过按键调节。
将使用两个定时器,定时器 0 设置为 100us,用来控制占空比;定时器 1 设置为 2ms,用来检测按键及数码管显示等。

编程思路:定义单片机上P34引脚为pwm,如: sbit pwm = P3^4,初始 pwm = 1。假设要设置20%占空比,则可在定时器 0 中断服务函数中计数,若计数值超过 2 则设令 pwm = 0;若计数超过10则pwm继续置1。即可实现占空比为20%,频率为 1/(10*100us) = 1000Hz。

2、核心代码

// 定时器0中断服务函数
void timer0() interrupt 1
{
	static tt = 0;
	// pwm_plus可通过按键调节,pwm_plus = 2,则占空比20%;pwm_plus = 5,则占空比50%
	if(tt >= pwm_plus)
	{
		pwm = 0;
		door(0x80,0xff);   
	}
	else   // 初始状态为 1
	{
		pwm = 1;
		door(0x80,0x00);
	}
	
	tt++;
	// 奇数超过10复位,则周期为10*100us,频率为1000Hz。(可通过修改该值来改变PWM频率)
	if(tt >= 10)
		tt = 0;
}

3、整体代码

由于考虑初学者基础较为薄弱,因此将完整的代码贴出来,包含中断函数、矩阵键盘、数码管显示等,并且在关键处进行了注释,希望对大家有所帮助。

// 包含头文件
#include "STC15F2K60S2.h"

// 数据类型定义
#define u8 unsigned char
#define u16 unsigned int

// 8位数码管状态
u8 dspbuf[8] = {10,10,10,10,10,10,10,10};
u8 code tab[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf,0xc6};
u8 pwm_plus = 0,dspcom = 0;
bit key_flag = 0,led_flag = 0;
sbit pwm = P3^4;

// 定时器 0 初始化
void Timer0Init(void)		//100微秒@12.000MHz
{
	AUXR |= 0x80;		//定时器时钟1T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x50;		//设置定时初值
	TH0 = 0xFB;		//设置定时初值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	
	ET0 = 1;
	EA = 1;
}

// 定时器 1 初始化
void Timer1Init(void)		//2毫秒@12.000MHz
{
	AUXR |= 0x40;		//定时器时钟1T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x40;		//设置定时初值
	TH1 = 0xA2;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	ET1 = 1;
	EA = 1;
}

// 573锁存器封装成函数
void door(u8 choose,u8 input)
{
	P2 = (P2 & 0x1f) | choose;
	P0 = input;
	P2 &= 0x1f;	
}

// 关灯、蜂鸣器
void all_init()
{
 	door(0x80,0xff);
	door(0xa0,0xaf);
}

// 数码管显示函数
void display()
{
	door(0xe0,0xff);   // 消隐
	
	door(0xc0,0x01<<dspcom);
	door(0xe0,tab[dspbuf[dspcom++]]);
	
	if(dspcom >= 8)
		dspcom = 0;
}

// 矩阵键盘,接KBD
u8 keypress = 0,keyvalue = 0xff,keyread = 0;
u8 Read_key(void)		                              	//矩阵键盘,接KBD
{
    u8 key_m,cal;
    
    P3 = 0xf0;P42=1;P44=1;
  	P36=P42;P37=P44;			   //变量替换
    key_m = (P3 & 0xf0);

    if(key_m != 0xf0) 
        keypress++;
   else
        keypress = 0; 
    
    if(keypress == 3)
    {
		  keypress = 0;
	  	keyread = 1;
		  switch(key_m)
        {
            case 0x70:cal = 0;break;                
            case 0xb0:cal = 1;break;    
            case 0xd0:cal = 2;break;    
            case 0xe0:cal = 3;break;
        }
        
        P3 = 0x0f;P42=0;P44=0;
				P36=P42;P37=P44;			   //变量替换
        key_m = (P3 & 0x0f);
        
			switch(key_m)
					{
							case 0x0e:keyvalue = (4*cal+7);break;                
							case 0x0d:keyvalue = (4*cal+6);break;    
							case 0x0b:keyvalue = (4*cal+5);break;    
							case 0x07:keyvalue = (4*cal+4);break;
					}
    }

    P3 = 0x0f;P42=0;P44=0;
		P36=P42;P37=P44;			                //变量替换
    key_m = (P3&0x0f);
	
    if((keyread == 1) && (key_m == 0x0f))
    {
        keyread = 0;
        return keyvalue;	
    }
    
    return 0xff;  
}

//````````````````````````````````主函数````````````````````````````````````
void main()      
{
	u8 key_re,mode = 0,led_put = 0;
	// 初始化
	all_init();
	Timer0Init();
	Timer1Init();
	
	while(1)
	{
		// 实时显示当前设置的占空比
		dspbuf[6] = pwm_plus/10;
		dspbuf[7] = pwm_plus%10;
		
		if(key_flag)			
		{
			key_flag = 0;
			key_re = Read_key();
			
			if(key_re != 0xff)
			{
				switch(key_re)
				{
					// 按键调节占空比
					case 12:pwm_plus+=2;
					        if(pwm_plus > 10)
										pwm_plus = 0;
									break;
				}
			}
		}
	}
}

// 定时器 0 中断服务函数
void timer0() interrupt 1
{
	static tt = 0;
	// pwm_plus可通过按键调节,pwm_plus = 2,则占空比20%;pwm_plus = 5,则占空比50%
	if(tt >= pwm_plus)
	{
		pwm = 0;
		door(0x80,0xff);   
	}
	else   // 初始状态为 1
	{
		pwm = 1;
		door(0x80,0x00);
	}
	
	tt++;
	// 奇数超过10复位,则周期为10*100us,频率为1000Hz。(可通过修改该值来改变PWM频率)
	if(tt >= 10)
		tt = 0;
}

// 定时器 1 中断服务函数
void timer1() interrupt 3
{
	static u8  t_20ms = 0;   //MAX = 500 ms
	static int t_1s;
	
	display();

	t_20ms++;
	t_1s++;

	if(t_20ms >= 10)	//每20ms扫描一次按键
	{
		t_20ms = 0;
		key_flag = 1;
	}
	
	if(t_1s >= 500)
	{
		t_1s = 0;
		led_flag = 1;
	}
}

至此,本次 PWM 已介绍完毕。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_小猪沉塘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值