基于MSP430G2553官方开发板的音乐播放器

  • 实现目标
  • 硬件资源
    • 芯片资源使用情况
    • 外接硬件
  • 程序实现
    • 开发环境配置
    • 各部分硬件驱动
    • 主循环功能实现

实现目标

  1. 实现以蜂鸣器为播放设备,能够对简谱乐曲进行解码播放。
  2. 具有循环列表,可实时切换上下曲目,实时暂停和开始,实时通过齿轮电位器调节播放音量。
  3. 能够将歌曲列表等信息,通过串口向上位机传输并显示。

硬件资源

芯片资源使用情况

  • P1.3 P1.4 P1.5:使用了3个io作为按键输入
  • P1.7:一个ADC通道采集电位器的变化情况
  • P1.6:一个定时器a的PWM输出通道
  • P1.0:一个io输出接到led作为运行状态显示
  • P1.1 P1.2:串口1映射到printf()上,实现在上位机打印信息的功能

外接硬件

  1. 按键x3 (4.7k电阻x3,我的电路接的是按下为高电平,是为了失效实验板原来P1.3的按下为低电平的按键)
  2. 1k齿轮电位器x3 (510欧电阻x1,也可以选择其他的组合,原则上在降低最小电流的情况下尽量提高可测量的范围)
  3. 低电平触发的蜂鸣器模块x1 (无源蜂鸣器,淘宝两三块一个,不需要加放大电路直接可以用)

程序实现

本播放器的主体功能代码来自于RT-Thread的播放器教程,本身用于Kiel下的STM32单片机。由于原始程序需要OS提供的时间片轮转支持,对于移植时候的逻辑构建造成了很大障碍,所以在本工程之前没有将其移植到MSP上的类似案例。
RT-Thread教程请点这里

开发环境配置

一开始想使用CCS进行工程开发,可以很轻松的利用官方硬件驱动。但是由于未知的原因,CCS对存储简谱的数组疯狂报错,导致最终选择转移到IAR下完成了工程。
相较于CCS,IAR下新工程需要配置的内容更为简洁

首先在工程设置中将Device选成当前使用的芯片型号

然后将Debugger中的Driver选项从模拟改成硬件
此两步之后就完成了对于新建工程的配置,至于添加PATH的操作和其他开发工具基本一致。
注意:CCS下使用的头文件在IAR下容易报错,需要改换成"io430g2553.h"
如果需要使用中断,则还需#include “in430.h”

各部分硬件驱动

  • LED
#include "led.h"
#include "io430g2553.h"
#include <stdint.h>int led_init(void)
{/* 设定 LED 引脚为输出模式 */P1DIR = LED_PIN_R;P1OUT &= ~LED_PIN_R;return 0;
}int led_on(void)
{/* 调用 API 输出低电平 */P1OUT |= LED_PIN_R;return 0;
}int led_off(void)
{/* 调用 API 输出高电平 */P1OUT &= ~LED_PIN_R;return 0;
}int led_toggle(void)
{/* 调用 API 读出当前电平 然后输出相反电平 */P1OUT ^= LED_PIN_R;return 0;
}
  • PWM
#include "io430g2553.h"#define DEADTIME 20                         //预设死区时间,以TA的clk为单位
/*******设定TA输出IO口,目前设定为MSP430G2553,20Pin封装无TA0.2********/
#define TA01_SET    P1SEL |= BIT6; P1DIR |= BIT6      //P1.6
#define TA02_SET    P3SEL |= BIT0; P3DIR |= BIT0      //P3.0
#define TA11_SET    P2SEL |= BIT2; P2DIR |= BIT2      //P2.2
#define TA12_SET    P2SEL |= BIT4; P2DIR |= BIT4      //P2.4
#define TA01_OFF    P1SEL&= ~BIT6                  //P1.6
#define TA02_OFF    P3SEL &= ~BIT0                         //P3.0
#define TA11_OFF    P2SEL &= ~BIT2                         //P2.2
#define TA12_OFF    P2SEL &= ~BIT4                         //P2.4char TA0_PWM_Init(char Clk,char Div,char Mode1,char Mode2)
{TA0CTL =0;                                                                        // 清除以前设置switch(Clk)                                                                        //为定时器TA选择时钟源{case 'A': case 'a':   TA0CTL|=TASSEL_1; break;               //ACLKcase 'S': case 's':   TA0CTL|=TASSEL_2; break;           //SMCLKcase 'E':                  TA0CTL|=TASSEL_0; break;           //外部输入(TACLK)case 'e':                    TA0CTL|=TASSEL_3; break;               //外部输入(TACLK取反)default :  return(0);                                                        //设置参数有误,返回0}switch(Div)                                                                         //为定时器TA选择分频系数{case 1:   TA0CTL|=ID_0; break;   //1case 2:   TA0CTL|=ID_1; break;   //2case 4:   TA0CTL|=ID_2; break;   //4case 8:   TA0CTL|=ID_3; break;   //8default :  return(0);                                                        //设置参数有误,返回0}switch(Mode1)                                                                   //为定时器选择计数模式{case 'F': case 'f':                                                                //普通PWMTA0CTL |=MC_1; break;                                           //主定时器为增计数case 'B':case 'b':TA0CTL |=MC_1; break;                                          //主定时器为增计数case 'D': case 'd':                                                               //死区PWMTA0CTL |=MC_3; break;                                           //主定时器为增减计数default : return(0);                                                         //其他情况都是设置参数有误,返回0}switch(Mode1)                                                                 //设置PWM通道1的输出模式。{case 'F':    case 'f':TA0CCTL1 = OUTMOD_7;TA01_SET;break;case 'B':  case 'b':TA0CCTL1 = OUTMOD_3;TA01_SET;break;case 'D': case'd':TA0CCTL1 = OUTMOD_6;TA01_SET;break;case '0':case 0:                                                             //如果设置为禁用TA01_OFF;                                                              //TA0.1恢复为普通IO口break;default :  return(0);                                                      //设置参数有误,返回0}switch(Mode2)                                                               //设置PWM通道2的输出模式。{case 'F':     case 'f':TA0CCTL2 = OUTMOD_7;TA02_SET;  break;case 'B':   case 'b':TA0CCTL2 = OUTMOD_3;TA02_SET;break;case 'D': case 'd':TA0CCTL2 = OUTMOD_2;TA02_SET;break;case '0':case 0:                                                        //如果设置为禁用TA02_OFF;                                                      //TA0.1恢复为普通IO口break;default :  return(0);                                              //设置参数有误,返回0}return(1);
}char TA0_PWM_SetPeriod(unsigned int Period)
{if (Period>65535)   return(0);TA0CCR0 = 12000/Period;return(1);
}char TA0_PWM_SetPermill(char Channel,unsigned int Duty)
{unsigned char Mod = 0;unsigned int DeadPermill=0;unsigned long int Percent=0;                           //防止乘法运算时溢出Percent=Duty;DeadPermill=((DEADTIME*1000)/TACCR0);     //将绝对死区时间换算成千分比死区时间switch (Channel)                                             //先判断出通道的工作模式{case 1:Mod = (TA0CCTL1& 0x00e0)>>5;        break;  //读取输出模式,OUTMOD0位于5-7位case 2:Mod = (TA0CCTL2 & 0x00e0)>>5;    break;  //读取输出模式,OUTMOD1位于5-7位default:   return(0);}switch(Mod)                                                      //根据模式设定TACCRx{case 2: case 6:          /**死区模式2,6时,需要判断修正死区时间,且同时设定TA0CCR1/2 的值*/{if((1000-2*Percent)<=DeadPermill)          //预留死区时间Percent=(1000-DeadPermill)/2;TA0CCR1=Percent*TA0CCR0/1000;TA0CCR2= TA0CCR0-TA0CCR1;break;}case 7:{if(Percent>1000)    Percent=1000;if(Channel==1) TA0CCR1=Percent* TA0CCR0/1000;if(Channel==2) TA0CCR2=Percent* TA0CCR0/1000;break;}case 3:        //占空比一律为正脉宽,所以需要 TA0CCR0减去占空比{if(Percent>1000)    Percent=1000;if(Channel==1) TA0CCR1= TA0CCR0-Percent*TA0CCR0/1000;if(Channel==2) TA0CCR2= TA0CCR0-Percent*TA0CCR0/1000;break;}default: return(0);}return (1);
}

TA1的驱动函数与TA0相同
TA0_PWM_SetPeriod()此函数中,TA0CCR0 = 12000/Period 的12k应该改为你所配置的低速外设时钟速度,才能获得正确的声音频率

  • BEEP
#include "beep.h"
#include <stdint.h>
#include "io430g2553.h"
#include "TA_PWM.h"int beep_init(void)
{      /* 初始化BEEP设备 */
//    BCSCTL1 = CALBC1_8MHZ;
//    DCOCTL = CALDCO_8MHZ;/* TA0CTL = TASSEL_1 + MC_1 + ID_0;        // //TA0设为增计数模式,时钟=ACLK   */return 0;
}int beep_on(void)
{   //使能蜂鸣器对应的 PWM 通道TA0_PWM_Init('A',1,'F',0);         return 0;
}int beep_off(void)
{//失能蜂鸣器对应的 PWM 通道TA0_PWM_Init('A',1,0,0);    //A 12kHz            return 0;
}int beep_set(uint16_t freq, uint8_t volume)
{//    uint32_t period, pulse;TA0_PWM_SetPeriod(freq);               /* 根据声音大小计算占空比 蜂鸣器低电平触发 *//*pulse = period - period / 100 * volume;*/TA0_PWM_SetPermill(7,1000-10*volume);  return 0;
}

实现了pwm驱动之后蜂鸣器只需要这几个接口就能正常使用

  • KEY
#include "io430g2553.h"
#include "in430.h"
#include <stdint.h>void key_init(void)
{P1REN |=BIT3;P1OUT &= ~BIT3;P1DIR &= ~BIT3;P1REN |=BIT4;P1OUT &= ~BIT4;P1DIR &= ~BIT4;P1REN |=BIT5;P1OUT &= ~BIT5;P1DIR &= ~BIT5;
}void scan_key(void)
{if(P1IN&BIT3){__delay_cycles(10000);NEXT_FLAG = 1;while(P1IN&BIT3);}if(P1IN&BIT4){__delay_cycles(10000);STOP_FLAG = 1;while(P1IN&BIT4);}if(P1IN&BIT5){__delay_cycles(10000);LAST_FLAG = 1;while(P1IN&BIT5);}
}

使用中断模式容易打断ADC模块的转换,所以采用了扫描模式来读取按键状态

  • ADC
#include "io430g2553.h"
#include "in430.h"
#include <stdint.h>float ADC_value=0;
float valum;
int volume_a;void change_volume(void)
{__delay_cycles(1000);              // Wait for ADC Ref to settleADC10CTL0 |= ENC + ADC10SC;          // Sampling and conversion start__bis_SR_register(CPUOFF + GIE);   // Low Power Mode 0 with interrupts enabledADC_value = ADC10MEM;valum =((ADC_value-333.0)*100)/688.0; // Assigns the value held in ADC10MEM to the integer called ADC_valuevolume_a=100-valum;if(volume_a >= 90)volume_a = 90;else if(volume_a <= 1)volume_a = 1;}void adc_init(void)
{ BCSCTL2 &= ~(DIVS_3);            // SMCLK = DCO = 1MHzP1SEL |= BIT7;                  // ADC input pin P1.7ADC10CTL1 = INCH_7 + ADC10DIV_3 ;         // Channel 3, ADC10CLK/3ADC10CTL0 = SREF_0 + ADC10SHT_3 + ADC10ON + ADC10IE;  // Vcc & Vss as reference, Sample and hold for 64 Clock cycles, ADC on, ADC interrupt enableADC10AE0 |= BIT7;                        // ADC input enable P1.3__enable_interrupt();          // Enable interrupts.
}// ADC10 interrupt service routine
#pragma vector=ADC10_VECTOR
__interrupt void ADC10_ISR (void)
{__bic_SR_register_on_exit(CPUOFF);        // Return to active mode }
}

建议直接放在main.c之中减少出错的概率
UART由于映射之后出现了printf()不能每次都成功输出正确信息的情况,最后就移除了这个功能。

主循环功能实现

int main( void )
{// Stop watchdog timer to prevent time out resetWDTCTL = WDTPW + WDTHOLD;clock_init();key_init();player_init();adc_init();while(1){//更改play对象状态change_volume();scan_key();change_player();play_loop(&player);}return 0;
}void play_loop(void *parameter)
{player_t player = (player_t)parameter;uint8_t buffer[PLAYER_BUFFER_SIZE], size;if (player->status == PLAYER_RUNNING){size = player->song_time_all - player->song_time_pass;if (size > PLAYER_BUFFER_SIZE) size = PLAYER_BUFFER_SIZE;size = player->decode->read(player->song_sheet[player->song_current - 1], player->song_time_pass, buffer, size);if (size > 0){player->audio->write(buffer, size);player->song_time_pass += size;}/* 如果播放时间到了,切换到下一首 */if (player->song_time_pass >= player->song_time_all){player_next(player);player_show(player);}}else{/* 暂停播放时关闭音频设备*/player->audio->close();/* 等待播放的信号量 */while(player->status != PLAYER_RUNNING){scan_key();change_player();}/* 开始播放时打开音频设备*/player->audio->open();}
}void change_player(void)
{uint8_t volume;if(LAST_FLAG){LAST_FLAG = 0;player_control(&player, PLAYER_CMD_LAST, 0);}else if(NEXT_FLAG){NEXT_FLAG = 0;player_control(&player, PLAYER_CMD_NEXT, 0);}else if(STOP_FLAG){STOP_FLAG = 0;if (player.status == PLAYER_RUNNING){player_control(&player, PLAYER_CMD_STOP, 0);}else{player_control(&player, PLAYER_CMD_PLAY, 0);}}player_control(&player, PLAYER_CMD_GET_VOL, &volume);if (volume_a != volume){volume = volume_a;player_control(&player, PLAYER_CMD_SET_VOL, &volume);}
}

最为主要的部分函数实现如上所示
此工程为嵌入式大作业所做,可以很容易的移植为其他单片机平台使用,很值得一看。
完整工程文件点此获取

基于MSP430G2553官方开发板的音乐播放器相关推荐

  1. 基于Arduino Uno开发板制作音乐播放器

    基于Arduino Uno开发板制作音乐播放器 本文将基于Arduino开发板实现一个音乐播放器. 利用Arduino Uno读取sd卡模块中内存卡的音乐,传输信号到扬声器进行播放. 一.项目软硬件简 ...

  2. 基于Android系统开发的简易音乐播放器

    大概做了一周左右,一个简易版本的音乐播放器.主要有三个界面,先上图: 一个主界面:主要负责1加载外部存储的音乐文件信息到应用内置数据库中2转到音乐文件列表界面 一个音乐文件列表界面:主要1负责展示音乐 ...

  3. 基于H5+js开发一款音乐播放器

    前言:当下音乐播放器不胜其数,为了更好的掌握一些东西,我们来自己制作一个音乐播放器. 文章目录: 一.开发环境: 二.页面视图: 1.主文件入口(首页): 2.音乐播放界面: 三.功能实现 (1).i ...

  4. 搬砖之路----MusicPlayer 一个基于Vlc(2.0+)开发的android音乐播放器--浅析在android开发过程中播放器选择之路!

    前言 MusicPlayer 是一款基于vlc播放器开发的一个音乐播放器,你也可以理解为在此核心上的搬砖之路,核心的内容并不是我写的,因此在正式写blog之前,感谢那些vlc核心的开发人员让我用到这么 ...

  5. 基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVAvue开发一个简单音乐播放器计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目 ...

  6. java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署

    java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署 java计算机毕业设计vue开发一个简单音乐播放器源码+mysql数据库+系统+lw文档+部署 本源码技 ...

  7. java计算机毕业设计vue开发一个简单音乐播放器MyBatis+系统+LW文档+源码+调试部署

    java计算机毕业设计vue开发一个简单音乐播放器MyBatis+系统+LW文档+源码+调试部署 java计算机毕业设计vue开发一个简单音乐播放器MyBatis+系统+LW文档+源码+调试部署 本源 ...

  8. 计算机毕业设计Javavue开发一个简单音乐播放器(源码+系统+mysql数据库+lw文档)

    计算机毕业设计Javavue开发一个简单音乐播放器(源码+系统+mysql数据库+lw文档) 计算机毕业设计Javavue开发一个简单音乐播放器(源码+系统+mysql数据库+lw文档) 本源码技术栈 ...

  9. JAVA毕业设计vue开发一个简单音乐播放器计算机源码+lw文档+系统+调试部署+数据库

    JAVA毕业设计vue开发一个简单音乐播放器计算机源码+lw文档+系统+调试部署+数据库 JAVA毕业设计vue开发一个简单音乐播放器计算机源码+lw文档+系统+调试部署+数据库 本源码技术栈: 项目 ...

最新文章

  1. C#.NET 大型通用信息化系统集成快速开发平台 4.1 版本 - 角色成员功能的改进支持公司加入到角色...
  2. 2021技术人新展望
  3. 超震撼!你没见过的24张震撼照片
  4. 7-1 作业调度算法--先来先服务 (30 分)(思路+详解+vector+map+map做法)Come Baby!!!!!!!!!!!
  5. turtle fillcolor_使Python中的turtle模块画图两只小羊
  6. js json过滤_如何在浏览器不崩溃的情况下过滤 200 万行数据?
  7. 安阳师范学院计算机与信息工程学院吴琴霞,基于甲骨文字形动态描述库的甲骨文输入方法...
  8. 特斯拉地图数据服务以后由百度地图提供
  9. c语言用栈输出迷宫所有路径,如何在迷宫中使用到栈
  10. DataGridView的DataGridViewComboBoxColumn列点击后触发其他方法
  11. 0514JS函数练习
  12. 【产品必备软件合集】
  13. HeadFirstJava 11异常处理
  14. html微博分享功能,js页面文字选中后分享到新浪微博实现
  15. linux操作系统启动盘,轻松制作Linux操作系统启动盘的四种通行方法
  16. wps如何对比两列数据找出不同
  17. 苹果手机html吊起拍照,一张好照片不是只按快门 iPhone手机拍照指南
  18. 细说 AppbarLayout,如何理解可折叠 Toolbar 的定制
  19. 毕业设计:新闻大数据搜索系统 (完整代码运行)
  20. Visual Studio/AnkhSVN在VS中出现SVN代码冲突的解决方法

热门文章

  1. python 魔法函数
  2. 2020知到python答案_参考答案2020知到APPPython程序设计
  3. Lr预设(手机+电脑):时尚Ins人像旅行风光电影大师Lightroom调色滤镜预设
  4. 基于Java的实时聊天系统设计与实现
  5. 联通、电信、移动 手机电子书制作工具
  6. 怎么将html导入trados,关于Trados的组成和界面
  7. 用pycharm创建第一个django项目
  8. 检查是否需要挂起计算机重新启动。挂起重新启动会导致安装程序失败
  9. 格式怎样把ppt转换成word文档
  10. 华为会议电脑版_华为云会议电脑版下载