模拟小星星音乐播放
小星星
pwm_muisc_pro-----main.c
#include"exynos_4412.h"
#include"uart.h"
//pwm 模拟小星星播放
volatile unsigned int count = 0;//毫秒级变量
//延时 ms
void delay(unsigned short ms){
unsigned int tmp = count;//存放刚进入delay函数时 count 的数值
// while(count <= tmp+ms);//这种算法没有规避溢出问题
while(count-tmp < ms);//这种算法规避了溢出问题,不必纠结算法,用就完事了
}
//中断初始化
exit_init(){
//GIC 面向中断源
//开启总中断
ICDDCR = 1;
//配置端口中断使能
//中断模式: wdt中断 id 75
//75/32=2 75%32=11
ICDISER.ICDISER2 |= 1<<11;
//配置端口优先级 优先级设置为5
//75/4= 18 75%4=3 ---- [15:8]
ICDIPR.ICDIPR18 = (ICDIPR.ICDIPR18 & ~(0xff<<24)) | (5<<24);
//配置中断源送去哪个cpu处理 0x1表示直送cpu0
//寄存器分步格局 与ICDIPR 完全一样
ICDIPTR.ICDIPTR18 = (ICDIPTR.ICDIPTR18 & ~(0xff<<24)) | (0x1<<24);
//GIC 面向cpu
//cpu响应中断使能 =1 使能 =0 不使能
CPU0.ICCICR = 1;
//配置cpu过滤优先级
CPU0.ICCPMR = 255;
}
//中断响应,c语言入口函数,在汇编汇总调用,当irq异常触发时
void do_irq(){
//获取中断号
int id = CPU0.ICCIAR;
//根据中断id来处理对应的事件
switch(id){
case 75:
count++;
//先清除中断 源头的挂起 看门狗的中断
//写入任何值清除
WDT.WTCLRINT = 8;
//在清除GIC分配器层中断挂起 与ICDISER_CPU 结构一样 id:57
//置为1 清除
ICDICPR.ICDICPR2 |= 1<<11;
break;
}
//最后清除cpu中断挂起
//写入中断id清除对应中断挂起
CPU0.ICCEOIR = id;
}
//看门狗初始化
void dog_init(){
//预分频
WDT.WTCON = (WDT.WTCON &~(0xff<<8)) | (24<<8);
//固定分频
WDT.WTCON = (WDT.WTCON &~(0x3<<3)) | (0<<3);
//触发中断信号 [2] 时间到,是否触发中断信号 = 1 触发中断
WDT.WTCON |= 1<<2;
//重载寄存器
WDT.WTDAT = 250;
//计数寄存器
WDT.WTCNT =250;
//开启看门狗
WDT.WTCON |= 1<<5;
}
//pwm 初始化
void pwm_init(){
//配置GPD0_0 为pwm功能
GPD0.CON = (GPD0.CON & ~(0xf<<0)) | (2<<0);
//配置pwm控制器,五路固定分频 TCFG1 [3:0] = 0 这里设不固定分频
PWM.TCFG1 &= ~(0xf);
//频率 = 总线时钟 /固定分频/ (分频值+1) / 重载值 ;
//两路预分频 TCFG0 [7:0] = 99 100M/(99+1) = 1M
PWM.TCFG0 = (PWM.TCFG0 & ~(0xff<<0)) | (99<<0);
//重载值
PWM.TCNTB0 = 2000;
//比较寄存器 占空比 = 比较寄存器/重载值
PWM.TCMPB0 = 1000;
//配置总控
//不使能死区
PWM.TCON &= ~(1<<4);
//自动重装
PWM.TCON |= 1<<3;
//打开输出
PWM.TCON |= 1<<2;
//装载TCNTB0 TCMPB0
PWM.TCON |= 1<<1;
//关闭装载
PWM.TCON &= ~(1<<1);
}
//启动pwm
void pwm_start(){
//启动pwm
PWM.TCON |= 1;
}
//关闭pwm
void pwm_stop(){
//启动pwm
PWM.TCON &= ~1;
}
//改变音色
void chanage_pinlv(unsigned int hz){
if(hz == 0) //做 除数为0 校验
{
pwm_stop();
return ;
}
//重载值
PWM.TCNTB0 = 1000000/hz;
//比较寄存器 //占空比我们设为50%
PWM.TCMPB0 = 1000000/hz/2;
//装载TCNTB0 TCMPB0
PWM.TCON |= 1<<1;
//关闭装载
PWM.TCON &= ~(1<<1);
//打开pwm
pwm_start(); //因为我们在播放音律函数时 停止了pwm 所以每次改变音色 都要重新开启pwm
}
//定义音符频率
#define H1 1046
#define H2 1175
#define H3 1318
#define H4 1397
#define H5 1568
#define H6 1760
#define H7 1976
#define ST 0
//定义乐谱二维数组 n行两列
//这里解释为什么用const 因为数组的初始化需要memset内存复制完成,但是我们时arm逻辑变成,没有系统库
//使用const可以保证数组时常量,就不需要内存赋值操作了
//这里的 1 表示我们 一个音 要发 多久声响 在播放器中可以利用延时函数来配合完成 利用整体乘一个数来达到延时效果
const unsigned int little_star[][2] = {
{H1, 1},{H1, 1},{H5,1},{H5,1},
{H6, 1},{H6, 1},{H5,1},{ST,1},
{H4, 1},{H4, 1},{H3,1},{H3,1},
{H2, 1},{H2, 1},{H1,1},{ST,1},
{H5, 1},{H5, 1},{H4,1},{H4,1},
{H3, 1},{H3, 1},{H2,1},{ST,1},
{H5, 1},{H5, 1},{H4,1},{H4,1},
{H3, 1},{H3, 1},{H2,1},{ST,1},
{H1, 1},{H1, 1},{H5,1},{H5,1},
{H6, 1},{H6, 1},{H5,1},{ST,1},
{H4, 1},{H4, 1},{H3,1},{H3,1},
{H2, 1},{H2, 1},{H1,1},{ST,1},
{0,0}// 结束符号
};
//播放音律
void play(const unsigned int little_star[][2]){
unsigned int i=0;
for( ;little_star[i][1]!=0;i++ ){
chanage_pinlv(little_star[i][0]);
delay(little_star[i][1]*500);//发声200毫秒
pwm_stop();//停止
delay(20);//停止10毫秒
}
}
int main()
{
uart_init();
printf("music!!!\r\n");
//看门狗初始化
dog_init();
//中断初始化
exit_init();
//pwm初始化
pwm_init();
//开启pwm
pwm_start();
int i=0;
while(1){
play(little_star);
delay(2000);//所有音律播放完成总体停2秒
}
return 0;
}