【蓝桥杯单片机笔记6】PWM脉宽调制信号

该博客介绍了如何使用单片机通过PWM脉宽调制信号控制LED灯的亮度,并实现独立按键S7控制亮度切换。同时,详细阐述了CT107D单片机实训平台上的呼吸流水灯功能,包括上电初始化状态、按键S4的点按控制LED灯的呼吸流水变化、按键S7显示当前LED位置和PWM占空比等。

内容来自小蜜蜂老师~

题目要求:

利用PWM脉宽信号实现独立按键S7控制对L1指示灯亮度变化的控制。

  1. PWM脉宽信号的频率为100HZ
  2. 系统上电后L1处于熄灭状态
  3. L1上电有四种亮度模式,分别是完全熄灭、10%亮度、50%亮度、90%亮度
  4. 按下S7按键,循环切换L1指示灯的四种亮度模式
#include "reg52.h"

sbit L1 = P0^0;
sbit S7 = P3^0;

void SelectHC573()/*74HC573锁存器*/
{
	P2 = (P2 & 0x1f) | 0x80;
}

//============定时相关的函数================
unsigned char count = 0;
unsigned char pwm_duty = 0;
void InitTimer0()
{
	TMOD = 0x01;
	TH0 = (65535 - 100) / 256;
	TL0 = (65535 - 100) % 256;
	
	ET0 = 1;
	EA = 1;
}


void ServiceTimer0() interrupt 1 /*定时器0的中端服务函数*/
{
	TH0 = (65535 - 100) / 256;
	TL0 = (65535 - 100) % 256; /*100微秒执行一次中断,单片机的时钟是100us,100ms=100us,所以要进行100次
	
	count++;
	if(count == pwm_duty)//在规定脉冲份额之下不亮
	{
		L1 = 1;
	}
	else if(count == 100)/*PWM频率为100HZ,即一个周期10ms;100*100微秒 = 10毫秒*/
	{
		L1 = 0;          //满100份不亮
		count = 0;
	}
}
//==========================================

//============按键相关的函数================
void Delay(unsigned int t)
{
	while(t--);
}

unsigned char stat = 0;
void ScanKeys()
{
	if(S7 == 0)
	{
		Delay(100);
		if(S7 == 0)
		{
			switch(stat)
			{
				case 0:L1 = 0;TR0 = 1;pwm_duty = 10;stat = 1;break;
				case 1:pwm_duty = 50;stat = 2;break;
				case 2:pwm_duty = 90;stat = 3;break;
                case 3:L1=1;TR0=0;stat = 0;break;
			}
			while(S7 == 0);
		}
	}
}
//============================================

//==================主函数====================
void main()
{
	SelectHC573();
	L1 = 1;
	InitTimer0();
	while(1)
	{
		ScanKeys();
	}
}

最好用定时器0产生PWM,以免被其他定时器打断

进阶

在CT107D单片机综合实训平台上,产生PWM脉宽调制信号控制8个LED灯进行呼吸流水变化,具体功能要求如下:

      [1] 上电开机运行时,关闭蜂鸣器和继电器,L4和L5点亮,其余LED灯熄灭。

      [2] 点按独立按键S4松开后,开始控制CT107D板上的L1-L8八个LED小灯进行每隔1秒的呼吸流水点亮,即:L1缓慢亮->L1缓慢灭->L2缓慢亮->L2缓慢灭....L8缓慢亮->L8缓慢灭->L1缓慢亮->L1缓慢灭....循环往复。

      [3] 再次点按独立按键S4松开后,控制CT107D板上的LED灯从当前灯开始逆向呼吸流水。即:比如当前的流水是L2缓慢灭->L3缓慢亮,按下S4按键松开后,L3缓慢灭->L2缓慢亮->L2缓慢灭->L1缓慢亮->L1缓慢灭->L8缓慢亮->L8缓慢灭....循环往复。

      [4] 每个LED灯,缓慢点亮0.5秒,缓慢熄灭0.5秒。

      [5] 按下独立按键S4时,当前LED灯暂停流水变化并保持现有亮度,直至按键松开后,亮度才开始变化。待当前的亮度变化完成后,才开始调整呼吸流水的方向。

      [6] 按下独立按键S7时,在数码管上显示当前LED灯的位置和PWM信号占空比,松开后,数码管熄灭。在最左边的1位数码管显示LED灯的位置,在最右边的2位数码管显示PWM信号的占空比。例如:当前点亮L6灯光,PWM信号的占空比为30%,在数码管最左边的1位显示“6”,在最右边的2位数码管显示“30”,其余的数码管熄灭。

      [7] 按下独立按键S7时,当前LED灯暂停流水变化并保持现有亮度,直至按键松开后,亮度才开始变化。

#include "regx52.h"
#include "absacc.h"
 
sbit S7 = P3^0;
sbit S4 = P3^3;
 
unsigned char pwm = 0;    //周期数      
unsigned char pwm_duty = 0;  //占空比            
unsigned char times = 0;     //0.5s变化   
unsigned char led_go = 0;    //LED pwm    
unsigned char stat_go = 0;     //LED流动状态 
unsigned char stat = 0;         
unsigned char key_puse = 0;     //键值记录
 
unsigned char code SMG_duanma[18]=
		{0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,
		 0x88,0x80,0xc6,0xc0,0x86,0x8e,0xbf,0x7f};
 
void DelaySMG(unsigned int t)
{
	while(t--);
}
 
void DisplaySMG_Bit(unsigned char pos, unsigned char value)
{
	XBYTE[0xE000] = 0xff;
	XBYTE[0xC000] = 0x01 << pos;
	XBYTE[0xE000] = value;
}
 //数码管数据显示
void Display_Info(unsigned char pos, unsigned char duty)
{
	DisplaySMG_Bit(0, SMG_duanma[pos]);
	DelaySMG(500);
 
	DelaySMG(500);
	DisplaySMG_Bit(6, SMG_duanma[duty / 10]);
	DelaySMG(500);
	DisplaySMG_Bit(7, SMG_duanma[duty % 10]);	
	DelaySMG(500);
	
	DisplaySMG_Bit(0, 0xff);
	DisplaySMG_Bit(6, 0xff);
	DisplaySMG_Bit(7, 0xff);
}
 
void Init_Timer0()
{
	TMOD = 0x01;
	TH0 = (65535 - 1000) / 256;			
	TL0 = (65535 - 1000) % 256;
	
	ET0 = 1;
	EA = 1;
	TR0 = 1;
}
 
void Service_Timer0() interrupt 1
{
	TH0 = (65535 - 1000) / 256;
	TL0 = (65535 - 1000) % 256;
	
	if(stat_go == 0)      		//初始只有L4L5亮				
      {
        XBYTE[0x8000] = 0xe7;						
        return;
      } 
	
        pwm++;                
  
      if(pwm <= pwm_duty)   
      {
	XBYTE[0x8000] = ~(0x01 << stat);
      }
      else if(pwm <= 10)
      {
        XBYTE[0x8000] = 0xff;
      }
      else
      {
        XBYTE[0x8000] = ~(0x01 << stat);
    
        pwm = 0;
        if(key_puse == 0)     
        {
          times++;
        }
      }
}
 
void LED_Control()
{
  if(times == 5)          
  {
    times = 0;
    if(led_go == 0)       
    {
//增大占空比
      pwm_duty = pwm_duty + 1;
      if(pwm_duty == 11)//最大为一个周期10
      {
				pwm_duty = 10;
        led_go = 1;//状态翻转
      }
    }
    else if(led_go == 1)  
    {
//减小占空比
      pwm_duty = pwm_duty - 1;
      if(pwm_duty == 255)//减到最小值了
      {
		pwm_duty = 0;
        led_go = 0;//状态翻转
        
        if(stat_go == 1)  //从左到右    
        {
          stat++;
          if(stat == 8)
          {
            stat = 0;
          }
        }
        else if(stat_go == 2) //从右到左
        {
          stat--;
          if(stat == 255)
          {
            stat = 7;
          }
        }
      }
    }
  }
}
 
void Scan_Keys()
{
	if(S4 == 0)
	{
		DelaySMG(100);
		if(S4 == 0)
		{
			while(S4 == 0)
			{
				key_puse = 1;
			}
			key_puse = 0;
			
      stat_go++;            
      if(stat_go == 3)
      {
        stat_go = 1;
      }
		}
	}
	
	if(S7 == 0)
	{
		DelaySMG(100);
		if(S7 == 0)
		{
			while(S7 == 0)
			{
				key_puse = 1;
				Display_Info(stat + 1, pwm_duty * 10);
			}
			key_puse = 0;
		}
	}
}
 
void Init_System()
{
	XBYTE[0xA000] = 0xff;
	XBYTE[0xA000] = 0x00;
	XBYTE[0xE000] = 0xff;
	XBYTE[0xC000] = 0xff;
	
	Init_Timer0();
}
 
main()
{
	Init_System();
	while(1)
	{
		LED_Control();
		Scan_Keys();
	}
}

### 关于蓝桥杯嵌入式学习中PWM输出的相关资料 #### PWM模式概述 度调制(PWM)是一种通过调节信号的占空比来控制设备的技术。在STM32微控制器中,PWM可以通过定时器模块实现。具体来说,“度调制模式可以产生一个由TIMx_ARR寄存器确定频率、由TIMx_CCRx寄存器确定占空比的信号”[^2]。 #### 配置PWM的方法 为了生成PWM信号,通常需要配置以下几个关键寄存器: 1. **自动重装载寄存器 (ARR)** 此寄存器决定了PWM信号的周期长度。其计算公式如下: \[ f_{\text{PWM}} = \frac{\text{f}_{\text{CLK}}}{(\text{PSC} + 1)(\text{ARR} + 1)} \] 其中 \(f_{\text{CLK}}\) 是定时器时钟频率,\(PSC\) 是预分频值,\(ARR\) 是自动重装载值[^4]。 2. **捕获/比较寄存器 (CCR)** 这个寄存器用于设置PWM信号的占空比。如果要调整占空比为50%,可以直接将该寄存器设为ARR的一半,即 `TIM17->CCR1 = TIM17->ARR / 2`。 3. **预分频寄存器 (PSC)** PSC用于进一步降低计数器的工作频率,从而影响最终的PWM频率。 #### 修改PWM参数的例子 以下是一个简单的代码示例,展示如何动态修改PWM的频率和占空比: ```c // 初始化部分省略... // 修改占空比为50% TIM17->CCR1 = TIM17->ARR / 2; // 修改PWM频率为8kHz TIM17->ARR = 750 - 1; ``` 上述代码片段展示了如何通过直接操作寄存器的方式改变PWM波形特性。 #### BRR端口的应用 需要注意的是,在某些情况下可能需要用到BRR(Bit Reset Register),这是一个专门用来清零GPIO引脚状态的寄存器。“BRR端口位清除寄存器,清除单个位的输出值。只能用于置0。(只能写入并只能以字(16位)的形式操作)”[^3]。虽然它不直接影响PWM功能,但在调试过程中可能会被用到。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值