8g-pwm
```c
/*
标题:无源蜂鸣器播放音乐-两只老虎
主频:35MHz
用于:51单片机学习机-学电
资料:https://rationmcu.com
*/
#include "stc8g.h"
#include "intrins.h"
/* 寄存器定义 */
#define PWM5C (*(unsigned int volatile xdata *)0xFCA0)
#define PWM53T1 (*(unsigned int volatile xdata *)0xFCC8)
#define PWM53T2 (*(unsigned int volatile xdata *)0xFCCA)
/* 定义音调 低音 中音 高音
音符频率对应的PWM5C值
低中高每种7个 一共是21个 */
unsigned int tone[21]={
0x20A0, 0x1D13, 0x19E7, 0x187E, 0x15CE, 0x136D, 0x1141, // 低音1234567
0x1058, 0x0E90, 0x0CF8, 0x0C3F, 0x0AE7, 0x09B7, 0x08A7, // 中音1234567
0x082A, 0x0746, 0x067B, 0x061E, 0x0574, 0x04DB, 0x0454 // 高音1234567
};
/* 两只老虎 乐谱音符 */
unsigned char music[32]={
7,8,9,7, 7,8,9,7, 9,10,11, 9,10,11,
11,12,11,10,9,7, 11,12,11,10,9,7, 7,4,7, 7,4,7
};
/* 两只老虎 每个音符的时长
本来是1/4 1/8 1/16
这里都乘以16 得出以下值 */
unsigned char time[32]={
4,4,4,4, 4,4,4,4, 4,4,8, 4,4,8,
3,1,3,1,4,4, 3,1,3,1,4,4, 4,4,8, 4,4,8
};
/* 固定延时1毫秒 */
void Delay1ms() //@35MHz
{
unsigned char i, j;
_nop_();
_nop_();
i = 15;
j = 90;
do
{
while (--j);
} while (--i);
}
/* n毫秒延时函数 参数给几 就延时几毫秒 */
void delay_ms(unsigned int ms)
{
while(ms--)
{
Delay1ms();
}
}
/* 固定延时1微秒 */
void Delay1us() //@35MHz
{
unsigned char i;
_nop_();
_nop_();
i = 9;
while (--i);
}
/* n微秒延时函数 参数给几 就延时几微秒 */
void delay_us(unsigned int us)
{
while(us--)
{
Delay1us();
}
}
/* 蜂鸣器初始化 */
void beep_init()
{
P_SW2 |= 0X80; // 允许访问XFR
PWMSET |= (1<<5);// 使能PWM5模块
PWM5CKS = 0X0F; // 设置为系统时钟的16分频
PWM5C = tone[0];
PWM53T1 = PWM5C/2; // 遇到T1输出低电平
PWM53T2 = 0; // 遇到T2输出高电平
PWM53CR = 0XC0; // 把引脚设置为PWM输出口 初始电平是高电平 并关闭所有触发点中断
}
//P20-P21 P22-P23四个PWM
//10kHz
//
void PWM2_init()
{
PWMSET |= (1<<2);// 使能PWM5模块
P_SW2 |= 0X80; // 允许访问XFR
PWM2CKS = 0X0B; // 设置为系统时钟的12分频
PWM2C=(unsigned int)(921600/10000);//根据频率算得周期
PWM20CR = 0XC0; // 把引脚设置为PWM输出口 初始电平是1电平 并关闭所有触发点中断
PWM21CR = 0XC0; // 把引脚设置为PWM输出口 初始电平是1电平 并关闭所有触发点中断
PWM22CR = 0XC0; // 把引脚设置为PWM输出口 初始电平是1电平 并关闭所有触发点中断
PWM23CR = 0XC0; // 把引脚设置为PWM输出口 初始电平是1电平 并关闭所有触发点中断
// PWM20T1 = PWM2C/2; // 遇到T1输出低电平
// PWM20T2 = 0; // 遇到T2输出高电平
// PWM21T1 = PWM2C/2; // 遇到T1输出低电平
// PWM21T2 = 0; // 遇到T2输出高电平
// PWM22T1 = PWM2C/2; // 遇到T1输出低电平
// PWM22T2 = 0; // 遇到T2输出高电平
//
// PWM23T1 = PWM2C/2; // 遇到T1输出低电平
// PWM23T2 = 0; // 遇到T2输出高电平
}
//******************************************
void HPWM2_Set(int PWMchannel, unsigned int f,float zkb)
{
unsigned int CycleTime;
P_SW2 |= 0X80; // 允许访问XFR
//根据频率,计算周期=频率的倒数,设置计数周期
//921600=11.0592Mhz/12=11059200/12,兆,等于10的6次方。
//用到强制类型转换,将计算的小数强制转换为无符号整型,
//因为计数器只能是整数,而且是0-32767之间。
// CycleTime=(unsigned int)(921600/f);//根据频率算得周期
// PWM2C=CycleTime; //设置PWM周期,放到对应的寄存器中。
// CycleTime=(unsigned int)(921600/f);//根据频率算得周期
CycleTime=100;
PWM2C=100; //设置PWM周期,放到对应的寄存器中。
//看设置的那个通道的占空比;
switch(PWMchannel)
{
case 0: //P20通道,PWM0的占空比,翻转点设置;
PWM20T1 =zkb*CycleTime; //N*zkb=Nt1
PWM20T2 = 0;//当计数到CYCLE的时候,会归0
break;
case 1: //P21通道,PWM1的占空比,翻转点设置;
PWM21T1 =zkb*CycleTime; //
PWM21T2 = 0;//当计数到CYCLE的时候,会归0
break;
case 2: //P22通道,PWM2的占空比,翻转点设置;
PWM22T1 =zkb*CycleTime; //
PWM22T2 =0; //当计数到CYCLE的时候,会归0
break;
case 3:
PWM23T1 =zkb*CycleTime;
PWM23T2 = 0;//当计数到CYCLE的时候,会归0
break;
default:break;//
}
P_SW2=0x00;//关闭设置开关
PWMCFG23 |= 0X01;//开启PWM2,,
// 开启PWM5,, PWMCFG23 |= 0X10; ,, PWMCFG45 &= ~0X10; // 关闭PWM5
}
/* 主函数 */
void main()
{
/* 定义局部变量 */
unsigned int i=0,j=0; // 定义两个16位变量
/* 系统初始化 */
P5M0 = 0X00; //设置P5.0~P5.7为双向口模式
P5M1 = 0X00;
/* 系统初始化 */
P2M0 = 0X00; //设置P5.0~P5.7为双向口模式
P2M1 = 0X00;
// PWMSET |= (1<<2);// 使能PWM5模块
// P_SW2 |= 0X80; // 允许访问XFR
// PWM2CKS = 0X0B; // 设置为系统时钟的12分频
// PWM2C=94;//根据频率算得周期
// PWM20T1 =47; //N*zkb=Nt1
// PWM20T2 = 0;//当计数到CYCLE的时候,会归0
// PWM20CR = 0X80;
// P_SW2 = 0X00; // 允许访问XFR
// PWMCFG23 = 0X01; // 开启PWM5
// while(1);
//
//beep_init(); // 蜂鸣器初始化
PWM2_init();
HPWM2_Set(0, 2000,0.5);
while(1)
{
HPWM2_Set(0,2000,0.5);
HPWM2_Set(1,1000,0.4);
HPWM2_Set(2,1000,0.3);
HPWM2_Set(3,1000,0.2);
delay_ms(500);
HPWM2_Set(0,2000,0);
HPWM2_Set(1,1000,0);
HPWM2_Set(2,1000,0);
HPWM2_Set(3,1000,0);
delay_ms(500);
HPWM2_Set(0,2000,0.2);
HPWM2_Set(1,1000,0.3);
HPWM2_Set(2,1000,0.4);
HPWM2_Set(3,1000,0.5);
delay_ms(500);
HPWM2_Set(0,2000,0);
HPWM2_Set(1,1000,0);
HPWM2_Set(2,1000,0);
HPWM2_Set(3,1000,0);
delay_ms(500);
// for(i=0;i<32;i++) // 两只老虎 共32个音符
// {
// /* 输出音符 */
// PWM5C = tone[music[i]];//改变周期
// PWM53T1 = tone[music[i]]/2;//占空比为50%
// PWMCFG45 |= 0X10; // 开启PWM5
// /* 输出音符对应的时长 */
// delay_ms(time[i]*50);
// /* 模仿钢琴 输出音符尾音 */
// for(j=tone[music[i]]/2;j<tone[music[i]];j++)
// {
// PWM53T1 = j;
// delay_us(((unsigned long)time[i]*25000)/tone[music[i]]);
// }
// /* 结束本次音符 */
// PWMCFG45 &= ~0X10; // 关闭PWM5
// }
// delay_ms(1000);
}
}