基于STM8单片机的蜂鸣器和弦声音的设计

介绍如何使用STM8单片机通过PWM模式控制蜂鸣器发出和弦声音,包括电路连接、程序设计及定时中断实现。
AI助手已提取文章相关产品:
   1. 实验功能:本实验的功能是利用 STM8单片机控制蜂鸣器发出和弦声音。
   2. 电路原理:按键接PB2口,蜂鸣器接PD4口,当按下按键时STM8利用TIM2的PWM模式驱动蜂鸣器就发出“123”的和弦声音。
   3. 采用IAR FOR STM8开发环境,外部晶振16M。
   4. 程序代码如下:

/********************************************************************************

* 文件名称:STM8_Buzzer.c

* 开发环境:IAR FOR STM8 1.20

* 作者:        电子熊

*  http://www.dpjzj.com

********************************************************************************/
#include "iostm8s105s4.h"

#define uchar                              unsigned char
#define uint                                  unsigned int

uchar SysDeal_Flag = 0;
uchar Sys_Count = 0;
uchar SendData_Flag =0;
uchar K_Flag = 0;
#define Sys_Time                      99 //100*4us = 400us
#define Sys_Prescaler             6 //2^6 = 64

#define Key_In_Power             PB_IDR_IDR2
#define Key_Delay                    10
uchar Key_In = 0;
uchar Key_Value = 0;
uchar Key_Flag = 0;

#define BELL_PWM1           640 //320us
#define BELL_PWM2           564 //282us
#define BELL_PWM3           540 //270us
#define BELL_PWM4           460 //230us
#define BELL_PWM5           408 //204us
#define Buzzer_Stop()         (TIM2_CR1 = 0x00)
#define BELL_MODE2         0
uchar Buz_Time = 0;
uchar Buz_State = 0;
uchar Buz_Mode = 0;
uchar Buz_Start = 0;
const uint BUZ_PWMTAB[][11]= 
{
  {BELL_PWM3,BELL_PWM3, BELL_PWM4,BELL_PWM4, BELL_PWM5,BELL_PWM5, 0xff,0xff,0xff,0xff,0xff}
};
const uchar BUZ_TIMETAB[][11]=
{
  {8,10,6,10,6,20,0xff,0xff,0xff,0xff,0xff}
};


void Delay_ms( uint ms )

  uint i,j;
  for( j=0; j<MS; j++ )
  { 
    for( i=0; i<1000; i++ )
    {;} 
  }
}

void CLK_Init(void)
{
  CLK_ECKR=0x03;//外部时钟寄存器 外部时钟准备就绪,外部时钟开
  CLK_SWCR=0x02;//切换控制寄存器 使能切换机制
  CLK_SWR=0xB4;//主时钟切换寄存器 选择HSE为主时钟源*/

  while (!(CLK_SWCR & 0x08)); 
  CLK_CSSR=0x01;//时钟安全系统寄存器   
}

void SysClk_Init(void)

  asm("sim");
  TIM4_IER = 0x00; //禁止中断
  TIM4_EGR = 0x01; //允许产生更新事件
  TIM4_PSCR = Sys_Prescaler;
  TIM4_ARR = Sys_Time;
  TIM4_CNTR = Sys_Time;
                        //定时周期= 400us
  TIM4_CR1 = 0x01;
  TIM4_IER = 0x01;
  asm("rim");
}

#pragma vector = TIM4_OVR_UIF_vector
__interrupt void TIM4_OVR_UIF(void)

  TIM4_SR = 0x00;
  Sys_Count ++;
//---------------------------------------
  if( Sys_Count % 5 == 1 )  //2ms
  { 
    SysDeal_Flag = 1; 
  }
  else if(Sys_Count  == 5)
  {
    SendData_Flag =1;
  }
  else if(Sys_Count >= 15)
  {
    Sys_Count = 0;
  }
  else
  { 
    K_Flag = 1;       
  }  
}

void Buzzer_Init(void)

  PD_DDR |= 0x90;           // 配置PD4方向为输出
  PD_CR1 |= 0x90;           // 设置PD4推挽输出
  PD_CR2 &= 0x6f;
  //------------------------------------
  TIM2_PSCR = 3;            //8分频。f=16m/8=2m----0.5us
  TIM2_CCMR1 = 0x70;        // PWM 模式 2
  TIM2_CCER1 = 0x03;        // CC1配置为输出
}

void Buzzer_Pwm(uint timenum)

  TIM2_ARRH = (uchar)(timenum>>8);
  TIM2_ARRL = (uchar)(timenum);
  TIM2_CCR1H = (uchar)(timenum>>9);
  TIM2_CCR1L = (uchar)(timenum>>1);
  TIM2_CR1 = 0x01;          // 计数器使能,开始计数
}

void Bell_DealFun(void)

  static uchar index = 0;
  switch( Buz_State )
  { 
  case 0: 
         Buz_Time = 0; 
         Buzzer_Stop(); 
         index = 0;
         if( Buz_Start == 1 )
         { 
           Buz_State ++; 
           Buzzer_Pwm( BUZ_PWMTAB[Buz_Mode][index] );
         }
         break;
  case 1: 
         Buz_Time++;
         if( Buz_Time >= BUZ_TIMETAB[Buz_Mode][index] )
         { 
           Buz_Time = 0; 
           Buz_State = 2; 
           index ++;
           if( BUZ_TIMETAB[Buz_Mode][index] == 0xff )
           { 
             Buz_State = 0; 
             Buzzer_Stop(); 
             Buz_Start = 0; 
           }
             else
             { 
               Buzzer_Pwm( BUZ_PWMTAB[Buz_Mode][index] ); 
             }
         }
         break;
  case 2: 
         Buz_Time++;
         if( Buz_Time >= BUZ_TIMETAB[Buz_Mode][index] )
         { 
           Buz_Time = 0; 
           Buz_State = 1; 
           index ++;
           if( BUZ_TIMETAB[Buz_Mode][index] == 0xff )
           { 
             Buz_State = 0; 
             Buzzer_Stop();
             Buz_Start = 0;
           }
           else
           { 
             Buzzer_Pwm( BUZ_PWMTAB[Buz_Mode][index] );
           }
         }
         break;
  default: 
         Buz_State = 0; 
         Buz_Time = 0; 
         index = 0;
         break;
  }
}

void Buzzer_Start(uchar mode)

  if( Buz_Start == 0 )
  { 
    Buz_Mode = mode; 
    Buz_Start = 1; 
  }
}


void Get_Key(void)
{
  Key_In = 0;
  if(!Key_In_Power)
  {
    Key_In |= 0x01;
  }
}

uchar Scan_Key(void)

  static uchar Key_Task=0,Key_Count=0;
  switch( Key_Task )
  { 
  case 0: 
          if( Key_In != 0 )
          { 
            Key_Task = 1; 
            Key_Count = 0; 
          } 
       break;
  case 1: 
          Key_Count++;
          if( Key_Count >= Key_Delay )
          { 
            Key_Task = 2; 
            Key_Count = 0; 
          }
          break;
  case 2: 
          if( Key_In != 0 )
          { 
            Key_Task = 3; 
            Key_Count = 0; 
            Key_Value = Key_In; 
            return(1); 
          }
          else
          { 
            Key_Task = 0; 
          }
          break;
  case 3:
          if( Key_In == 0 )
          { 
            Key_Task = 0; 
            Key_Count = 0; 
          } 
          break;
  default: 
          Key_Task = 0; 
          Key_Count = 0; 
          break;
  }   
  return(0);
}

//端口设置

void Hard_Init(void)
{
  PB_DDR_DDR2 = 0;      // 配置PB端口的方向寄存器PB2输入
  PB_CR1_C12 = 1;            // 设置PB2带上拉输入
  PB_CR2_C22 = 0;            // 禁止外部中断
}

void Devices_Init(void)
{
  Delay_ms(200);
  CLK_Init(); 
  Hard_Init();
  SysClk_Init();
  Buzzer_Init();
}

//主程序

void main( void )
{
  Devices_Init();
  while(1)
  {
    if(SysDeal_Flag == 1)
    {
      Key_Flag = Scan_Key();
      if(Key_Flag >= 1)
      {
        Buzzer_Start( BELL_MODE2 );
      }
      SysDeal_Flag = 0;
    }
    if(SendData_Flag ==1)
    {
      SendData_Flag = 0;
      Bell_DealFun();
    }
    if(K_Flag == 1)
    {
      Get_Key();
      K_Flag = 0;
    }
  }
}

您可能感兴趣的与本文相关内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值