基于MSP430F5529的MP3
2015年长江大学电子
竞赛
基于MSP430F5529的MP3设计
2015年5月6日
摘 要
本系统主要由MSP430F5529单片机和VS1003音频解码芯片组成,MCU通过SPI串行协议读取SD卡的音频文件,将音频文件发送给VS1003音频解码,解码后的音频信号经功率放大器放大后驱动电声转换器件发出声响,系统另外
配备有由键盘和LCD组成的人机交互功能,整个系统简洁、功能完善。
。
I
目 录
1系统
....................................................................................................................... 1
1.1主控的论证与选择 ............................................................................................... 1
1.2 音频解码的论证与选择 ....................................................................................... 1
1.3 控制系统的论证与选择 ......................................................... 错误~未定义书签。
2系统理论分析与计算 ..................................................................................................... 1
2.1 XXXX的分析 ..................................................................... 错误~未定义书签。
2.1.1 XXX ............................................................................ 错误~未定义书签。
2.1.2 XXX ............................................................................ 错误~未定义书签。
2.1.3 XXX ............................................................................ 错误~未定义书签。
2.2 XXXX的计算 ........................................................................ 错误~未定义书签。
2.2.1 XXX ............................................................................ 错误~未定义书签。
2.2.2 XXX ............................................................................ 错误~未定义书签。
2.2.3 XXX ............................................................................ 错误~未定义书签。
2.3 XXXX的计算 ........................................................................ 错误~未定义书签。
2.3.1 XXX ............................................................................ 错误~未定义书签。
2.3.2 XXX ............................................................................ 错误~未定义书签。
2.3.3 XXX ............................................................................ 错误~未定义书签。
3电路与程序设计 ............................................................................................................ 1
1电路的设计 .......................................................................................................... 1 3.
3.1.1系统总体框图............................................................................................. 1
3.1.2 SD卡子系统框图与电路原理图 .................................................................. 2
3.1.3音频放大子系统框图与电路原理图 ............................................................. 2
3.1.4电源........................................................................................................... 3
3.2程序的设计 .......................................................................................................... 3
3.2.1程序功能描述与设计思路 ........................................................................... 3
3.2.2程序
................................................................................................ 3 4测试方案与测试结果 ..................................................................................................... 3
4.1测试方案 ............................................................................................................. 3
4.2 测试条件与仪器 .................................................................... 错误~未定义书签。
4.3 测试结果及分析 .................................................................................................. 4
4.3.1测试结果(数据) ............................................................ 错误~未定义书签。
4.3.2测试分析与结论 ......................................................................................... 4 附录1:电路原理图 ......................................................................................................... 5 附录2:源程序 ................................................................................................................ 6
II
基于MSP430F5529的MP3
【熊平波组】
1系统方案
本系统主要由MSP430F5529模块、VS1003模块、SD卡模块、电源模块组成,下面分别论证这几个模块的选择。
1.1 主控芯片的论证与选择
方案一:51单片机。
51单片机出现年代较早,所以各种资料也非常的多,实现起来比较简单,达不到学习锻炼的目的,所以只以他作为一个参考。
方案二:STM32单片机
STM32单片机虽然是近几年推出的单片机,但它以强大的性能,低廉的价格很快的占领了市场,目前这方面的资料也是非常的多,并且个人对这一型号的处理器不是很了解,所以也放弃选用。
方案三:MSP430单片机
MSP430是TI公司现在主推的单片机型号,也是历年电子设计大赛所大量选用的处理器型号,它具有极低功耗,超强模拟外设。
综合以上三种方案,选择方案三。
1.2音频解码的论证与选择
方案一:AD+滤波器 。
由单片机直接将SD卡里面WAV格式的音频文件传送到AD转换器,进行音频输出,优点是操作简单,成本低,缺点是音质较差
方案二:VS1003音频解码芯片。
VS1003是由芬兰 VLSI 公司出品的一款单芯片的MP3/WMA音频解码芯片,其 拥有一个高性能低功耗的 DSP 处理器核VS_DSP,5K的指令 RAM,0.5K的数据 RAM,串行的控制和数据输入接口,4 个通用 IO 口,一个 UART 口,同时片内带有一个 可变采样率的 ADC、一个立体声 DAC 以及音频耳机放大器。性能优良,操作简单
综合以上二种方案,选择方案二。
2系统理论分析与计算
3电路与程序设计
3.1电路的设计
3.1.1系统总体框图
系统总体框图如图1所示
1
Nokia511液晶
VS1003 音频放大 MSP430F5529 SD卡
键盘+红外
图1 系统总体框图 3.1.2 SD卡子系统电路原理图
2、SD卡子系统电路
图2 SD卡子系统电路 3.1.3 音频放大子系统框图与电路原理图
2、音频放大子系统电路
2
图3 音频放大子系统电路
3.1.4电源
电源由变压部分、滤波部分、稳压部分组成。为整个系统提供5V或者12V电压,确保电路的正常稳定工作。这部分电路比较简单,都采用三端稳压管实现,故不作详述。
3.2程序的设计
3.2.1程序功能描述与设计思路
1、程序功能描述
根据题目要求软件部分主要实现键盘的设置和显示。
1)键盘实现功能:设置音量、对比度、选歌。
2)显示部分:歌曲、演唱者、频谱、码率、时长、音量。
2、程序设计思路
3.2.2程序流程图
1、主程序流程图
4测试方案与测试结果
4.1测试方案
1、硬件测试
2、软件仿真测试
3
3、硬件软件联调
4.3 测试结果及分析
4.3.2测试分析与结论
根据上述测试数据,XXXXXXXXXXXXXXXXXXXXXXXXXXXXX,由此可以得出以下结论:
1、
2、
3、
综上所述,本设计达到设计要求。
4
附录1:实物图
5
附录2:源程序
/*
* LCD5110.h
*
* Created on: 2014-11-22
* Author: xiongpb
*/
#ifndef LCD5110_H_
#define LCD5110_H_
#include
#define uchar unsigned char #define uint unsigned int
//延时宏定义
#define CPU_F ((double)4000000) #define delay_us(x) __delay_cycles((long)(CPU_F*(double)x/1000000.0))
#define delay_ms(x) __delay_cycles((long)(CPU_F*(double)x/1000.0))
//枚举 D/C模式选择
typedef enum //emum为枚举常量
{
DC_CMD = 0, //写命令
DC_DATA = 1 //写数据
} DCType;
#define LCD_CLK_L P2OUT &= ~BIT2 //低电平 #define LCD_CLK_H P2OUT |=BIT2 //高电平 //数据输入端口
#define LCD_DIN_L P7OUT &= ~BIT4 //低电平 #define LCD_DIN_H P7OUT |=BIT4 //高电平 //数据/命令选择
#define LCD_DC_L P8OUT &= ~BIT1 //低电平 #define LCD_DC_H P8OUT |=BIT1 //高电平
//芯片使能
#define LCD_CE_L P4OUT &= ~BIT3 //低电平 #define LCD_CE_H P4OUT |=BIT3 //高电平
6
//串行输入复位
#define LCD_RST_L P4OUT &= ~BIT0 //低电平
#define LCD_RST_H P4OUT |=BIT0 //高电平
void LCD_write_byte(unsigned char data, DCType dc);
void LCD5110_Init(void);
void LCD5110_SetContrast(unsigned char contrast);
void LCD5110_Clear(void);
void LCD_Set_XY(unsigned char X, unsigned char Y);
void LCD_WriteChar(unsigned char x,unsigned char y,unsigned char c); void LCD_WriteString(unsigned char X,unsigned char Y,char *s); void LCD_WriteNum(unsigned char X,unsigned char Y,unsigned int num); void LCD_Write_12X16Font(unsigned char x,unsigned char y,unsigned char *c); void LCD_DrawPicture(unsigned char X,unsigned char Y,unsigned char const
*map,
unsigned char Pix_x,unsigned char Pix_y); void LCD_Write_12X16FontS(unsigned char x,unsigned char y,unsigned char *c); void LCD_Write_12X16FontS_TB(unsigned char x,unsigned char y,unsigned char
*c);
#endif /* LCD5110_H_ */
/*
* Nokia5110.c
*
* Created on: 2014-10-26
* Author: xiongpb
*/
//------------------------------------------------------------------- // Nokia5510指令集
// D7 D6 D5 D4 D3 D2 D1 D0
// 0 0 1 0 0 PD V H
// | | |_______1->扩展指令集 0->基本指令集
// | |___________1->垂直寻址 0->水平寻址
// |_______________1->低功耗模式 0->正常模式
//------------------------------------------------------------------- // 显示模式
// D7 D6 D5 D4 D3 D2 D1 D0
// 0 0 0 0 1 D 0 E
// | |_______0 0 1 1
7
// |_______________0 1 0 1 // 白屏 正常 全显 反转
//-------------------------------------------------------------------
/******************************************************* 文件名 : Nokia5110Lcd.c
描述 : 诺基亚 5110 LCD 驱动源文件
作者 : xiongpb
编辑器 : CCS5.3
日期 : 2014-10-25
*******************************************************/ #include"LCD5110.h"
#include
#include"font.h"
/***********************************************************************
******************
* 函数名称:LCD5110_IO_Init()
* 函数功能:I0口初始化
* 入口参数:无
* 出口参数:无
* 说明:无
***************************************************************************
**************/
void LCD5110_IO_Init()
{
/* P6DIR |=BIT5;
P3DIR |=BIT4;
P3DIR |=BIT3;
P1DIR |=BIT6;
P6DIR |=BIT6;*/
P2DIR |=BIT2;
P7DIR |=BIT4;
P8DIR |=BIT1;
P4DIR |=BIT3;
P4DIR |=BIT0;
}
/***********************************************************************
******************
8
* 函数名称:LCD5110_Init(void)
* 函数功能:5110初始化
* 入口参数:无
* 出口参数:无
* 说明:无
***************************************************************************
**************/
void LCD5110_Init(void)
{
LCD5110_IO_Init(); //I0口初始化
LCD_RST_L; // 产生一个让LCD复位的低电平脉冲
delay_us(150);
LCD_RST_H;
LCD_CE_H;
delay_ms(1);
LCD_CE_L; //5110片选有效,允许输入数
//设置LCD
LCD_write_byte(0x21, DC_CMD); //使用扩展命令设置LCD模式
LCD_write_byte(0xC8, DC_CMD);//设置偏置电压
LCD_write_byte(0x06, DC_CMD); //温度校正
LCD_write_byte(0x13, DC_CMD); //1:48
LCD_write_byte(0x20, DC_CMD); //使用基本命令。并设置V=0,水平寻址
LCD5110_Clear(); //清屏
LCD_write_byte(0x0C, DC_CMD);//设定显示模式,正常显示
LCD5110_SetContrast(70); //对比度为68
LCD_CE_L; // 关闭LCD
}
/***********************************************************************
******************
* 函数名称:LCD5110_SetContrast(unsigned char contrast)
* 函数功能:设置LCD对比度
* 入口参数:contrast 对比度(范围: 0~127)
* 出口参数:无
* 说明:无
9
***************************************************************************
**************/
void LCD5110_SetContrast(unsigned char contrast)
{
LCD_write_byte(0x21, DC_CMD);
LCD_write_byte(0x80 | contrast, DC_CMD);
LCD_write_byte(0x20, DC_CMD);
}
/***********************************************************************
******************
* 函数名称:LCD_write_byte(unsigned char data, DCType dc)
* 函数功能:向LCD发送数据
* 入口参数:data:数据 dc:DC_CMD = 0//写命令 DC_DATA = 1 //写数据
* 出口参数:无
* 说明:无
***************************************************************************
**************/
void LCD_write_byte(unsigned char data, DCType dc)
{
unsigned char i;
LCD_CE_L; //5110片选有效,允许输入数据
if (dc==DC_CMD)
LCD_DC_L; //发送命令
else
LCD_DC_H; //发送数据
for(i=0;i<8;i++) //传送8bit数据
{
if(data&0x80)
LCD_DIN_H;
else
LCD_DIN_L;
LCD_CLK_L;
data = data << 1;
LCD_CLK_H;
}
LCD_CE_H; //禁止5110
}
/***********************************************************************
*******************
10
* 函数名:LCD_Set_XY
* 功能: 设置LCD坐标
* 参数: X:0-83 Y:0-5
* 返回值:无
* 备 注:
***********************************************************************
*******************/
void LCD_Set_XY(unsigned char X, unsigned char Y)
{
LCD_write_byte(0x40 | Y,DC_CMD);// column 列
LCD_write_byte(0x80 | X,DC_CMD);// row 行
}
/***********************************************************************
******************
* 函数名称:LCD5110_Clear(void)
* 函数功能: LCD清屏函数
* 入口参数:无
* 出口参数:无
* 说明:无
***************************************************************************
**************/
void LCD5110_Clear(void)
{
unsigned char t;
unsigned char k;
LCD_Set_XY(0, 0);//设置RAM起始地址
for(t=0;t<6;t++)
{
for(k=0;k<84;k++)
{
LCD_write_byte(0x00, DC_DATA);
}
}
}
/***********************************************************************
******************
* 函数名称:void LCD_WriteChar(unsigned char x,unsigned char y,unsigned char
c)
* 函数功能: LCD清屏函数
* 入口参数:无
11
* 出口参数:无
* 说明:无
***************************************************************************
**************/
void LCD_WriteChar(unsigned char x,unsigned char y,unsigned char c)
{
unsigned char i;
c -= 32; //数组的行号
LCD_Set_XY(x,y);
for(i=0; i<12; i++)
{
LCD_write_byte(font6x12[c][i], DC_DATA);
if(i==5)
{
y++;
LCD_Set_XY(x,y);
}
}
}
/*
**********************************************************
*函数名:LCD_WriteString
*功能: LCD写6X8的字符串
*参数:X , Y , S
*返回值:无
备 注:
**********************************************************
*/
void LCD_WriteString(unsigned char X,unsigned char Y,char *s)
{
while(*s)
{
LCD_WriteChar(X,Y,*s);
s++;
X += 6;
}
}
/*
***************************************************************
12
*函数名:LCD_WriteNum(unsigned int num) *功能:写入数字
*参数:num
*返回值:无
****************************************************************
*/
void LCD_WriteNum(unsigned char X,unsigned char Y,unsigned int num)
{
unsigned char str[8],i=0,len=0;
unsigned int temp;
temp = num;
while(temp)
{
temp /=10;
len++;
}
if(!num)
{
len++;
str[0]=0x30;
}
str[len] = 0;
while(num)
{
str[len-i-1] = num%10 + 0x30;
num /=10;
i++;
}
LCD_WriteString(X,Y,(char *)str); }
/*
**********************************************************
*函数名:LCD_Write_16X16Font
*功能: 写一个16X16的汉字
*参数:x , y , c[2] x:0-83 y:0-5 *返回值:无
*备 注:
**********************************************************
*/
void LCD_Write_12X16Font(unsigned char x,unsigned char y,unsigned char *c)
{
unsigned char i,k;
LCD_Set_XY(x-12,y);
13
for(k=0; k<5; k++) //K的值表示汉字库最多存放的字的数量(可改大)
{
if((font12x16[k].Index[0]==c[0])&&(font12x16[k].Index[1]==c[1]))
{
for(i=0; i<24; i++)
{
LCD_write_byte(font12x16[k].Msk[i], DC_DATA);
if(i==11)
{
y++;
LCD_Set_XY(x-12,y);
}
}
}
}
}
/*
********************************************************** *函数名:LCD_Write_16X16FontS
*功能: 写一串16X16的汉字
*参数:x , y , c[2] x:0-83 y:0-5
*返回值:无
*备 注:
********************************************************** */
void LCD_Write_12X16FontS(unsigned char x,unsigned char y,unsigned char *c)
{
while(*c) {LCD_Write_12X16Font((x=x+12), y, c); c += 2;} //一个汉字GB码
由2个字节组成
}
/*
********************************************************** *函数名:LCD_Write_16X16Font
*功能: 取反写一个16X16的汉字
*参数:x , y , c[2] x:0-83 y:0-5
*返回值:无
*备 注:
********************************************************** */
void LCD_Write_12X16Font_TB(unsigned char x,unsigned char y,unsigned char
*c)
{
14
unsigned char i,k;
LCD_Set_XY(x-12,y);
for(k=0; k<5; k++) //K的值表示汉字库最多存放的字的数量(可改大)
{
if((font12x16[k].Index[0]==c[0])&&(font12x16[k].Index[1]==c[1]))
{
for(i=0; i<24; i++)
{
LCD_write_byte(~font12x16[k].Msk[i], DC_DATA);
if(i==11)
{
y++;
LCD_Set_XY(x-12,y);
}
}
}
}
}
/*
**********************************************************
*函数名:LCD_Write_16X16FontS
*功能:取反写一串16X16的汉字
*参数:x , y , c[2] x:0-83 y:0-5 *返回值:无
*备 注:
**********************************************************
*/
void LCD_Write_12X16FontS_TB(unsigned char x,unsigned char y,unsigned char
*c)
{
while(*c) {LCD_Write_12X16Font_TB((x=x+12), y, c); c += 2;} //一个汉字GB
码由2个字节组成
}
/*
**********************************************************
*函数名:LCD_DrawPicture
*功能: 绘图
*参数: X、Y :位图绘制的起始X、Y坐标;
*map :位图点阵数据;
15
Pix_x :位图像素(长) <=84
Pix_y :位图像素(宽) <=48
*返回值:无
*备 注:
**********************************************************
*/
void LCD_DrawPicture(unsigned char X,unsigned char Y,unsigned char const
*map,
unsigned char Pix_x,unsigned char Pix_y)
{
unsigned int i,n;
unsigned char row;
//计算位图所占行数
if (Pix_y%8==0) //如果为位图所占行数为整数
row=Pix_y/8;
else
row=Pix_y/8+1; //如果为位图所占行数不是整数
LCD_Set_XY(X,Y);
for (n=0;n检测
函数
}
/***********************************************************************
*******************************
* 名 称:P1_IODect()
* 功 能:判断是否有键被按下,哪个键被按下,并调用相应IO的中断事
件处理函数
* 入口参数:无
* 出口参数:无
* 说 明:必须用最近两次扫描的结果,才知道按键是否被按下
* 范 例:无
***************************************************************************
***************************/
void P_IODect()
{
static unsigned char KEY_Now=0; //变量值出函数时需保留
unsigned char KEY_Past=0;
KEY_Past=KEY_Now;
Key_val=20;
P8OUT&= ~BIT2; //设定P8.1=1
P3OUT |= BIT7; //设定P2.3=0
if((P6IN&BIT4)==0) Key_val=11;
else if((P7IN&BIT0)==0) Key_val=12;
else if((P3IN&BIT6)==0) Key_val=13;
else if((P3IN&BIT5)==0) Key_val=14;
P8OUT |=BIT2; //设定P8.1=1
P3OUT&= ~BIT7; //设定P2.3=0
if((P7IN&BIT0)==0) Key_val=15;
else if((P3IN&BIT6)==0) Key_val=16;
else if((P3IN&BIT5)==0) Key_val=17;
//-----查询IO的输入寄存器-----
if((10
>8);
VS_WriteByte(vsdata&0xff);
VS_CS_H; /* 关闭片选 */
}
/***********************************************************************
**********
** 函数名称: INT16U VS_Read_Reg(INT8U addr). ** 功能描述: 从VS的功能寄存器中读取数据,一个字.
** 输入参数: INT8U addr 功能寄存器的地址.
** 输出参数: None.
** 返回参数: return temp读到的字,2字节.
***********************************************************************
***********/
unsigned int VS_Read_Reg( unsigned char addr) {
unsigned int temp=0;
// VS_DREQ=1;
while(!VS_DREQ); /* VS的DREQ为高电平时才接收数据 */
VS_CS_L; /* 打开片选 */
VS_WriteByte(VS_Read); /* 读出操作码(功能寄存器读操作) */
VS_WriteByte(addr); /* 写入寄存器地址 */
temp =VS_ReadByte(); /* 读高字节 */
temp<<=8;
temp|=VS_ReadByte(); /* 读取低字节,与高字节拼成一个字 */
VS_CS_H; /* 关闭片选 */
return temp;
}
/***********************************************************************
**********
** 函数名称: void VsSetVolume(INT8U volume) . ** 功能描述: 设置音量 1 - 48.
** 输入参数: INT8U volume 1 - 48 .
** 输出参数: None.
** 返回参数: None.
***********************************************************************
***********/
void VsSetVolume( unsigned char volume)
25
{
volume = volume * 0x03;
VS_Write_Reg(VS_VOL,((volume<<8)|volume)); }
/***********************************************************************
**********
** 函数名称: void VS_Init(void).
** 功能描述: VS1003软复位及初始化.
** 输入参数: None.
** 输出参数: None.
** 返回参数: None.
***********************************************************************
***********/
void VS_Init(void)
{
VS_IO_Init();
VS_RST_H;
VS_delay(100);
VS_RST_L;
VS_delay(100);
VS_RST_H; /* 硬件复位,VS_RST低电平有效 */
VS_delay(100);
VS_Write_Reg(VS_MODE ,0x0804); /* 软件复位,向0号寄存器写入0x0804 SM_SDINEW为1 SM_RESET为1 */
VS_Write_Reg(VS_CLOCKF,0x9800); /* 时钟设置,向3号寄存器写入0x9800 SC_MULT 为4 SC_ADD 为3 SC_FREQ为0 */
VS_Write_Reg(VS_VOL ,0x7070); /* 音量设置,左右声道均中等音量 */
VS_Write_Reg(0x02 ,0x7aaa);
VS_DCS_L; /* 打开数据片选 */
VS_WriteByte(0); /* 写入数据,这里写入4个0,是无关数据,用来启动数据传输 */
VS_WriteByte(0);
VS_WriteByte(0);
VS_WriteByte(0);
VS_DCS_H; /* 关闭数据片选 */
}
/***********************************************************************
**********
** 函数名称: void VS_Send_Dat32(INT8U *dat) . ** 功能描述: 向VS1003写入32个字节的音频数据.
26
** 输入参数: INT8U *dat 音频数据.
** 输出参数: None.
** 返回参数: None.
***********************************************************************
***********/
void VS_Send_Dat32( unsigned char *dat) {
unsigned char i=0;
// VS_DREQ=1;
VS_DCS_L; /* 打开数据片选,即开启SDI传输 */
while(!VS_DREQ); /* VS1003的DREQ为高才能写入数据 */
for(i=0;i<32;i++)
VS_WriteByte(*(dat+i)); /* 通过SPI向VS1003写入32个字节的音频数据
*/
VS_DCS_H; /* 打开数据片选,即开启SDI传输 */ }
/***********************************************************************
**********
** 函数名称: void VS_Flush_Buffer(void). ** 功能描述: 向VS1003写入2048个0,清空缓冲,为下一首mp3做准备. ** 输入参数: None.
** 输出参数: None.
** 返回参数: None.
***********************************************************************
***********/
void VS_Flush_Buffer(void)
{
unsigned char i,j=0;
VS_DCS_L; /* 打开数据片选,即开启SDI传输 */
for(i=0;i<64;i++)
{
// VS_DREQ=1;
while(!VS_DREQ); /* VS1003的DREQ为高才能写入数据 */
for(j=0;j<32;j++)
VS_WriteByte(0); /* 通过SPI向VS1003写入32个字节的0 */
}
VS_DCS_H; /* 关闭数据片选 */
}
/***********************************************************************
**********
27
** 函数名称: void VS_SinTest(INT8U x). ** 功能描述: 正弦测试函数,检查vs1003是否正常.
** 输入参数: INT8U x 正弦波频率.
** 输出参数: None.
** 返回参数: None.
***********************************************************************
***********/
void VS_SinTest(int x)
{
VS_Write_Reg(0x00,0x0820); /* 启动测试,向0号寄存器写入0x0820
SM_SDINEW为1 SM_TEST为1 */
// VS_DREQ=1;
while(!VS_DREQ); /* 等待DREQ变为高电平 */
VS_DCS_L; /* 打开数据片选 */
VS_WriteByte(0x53); /* 写入以下8个字节,进入正弦测试 */
VS_WriteByte(0xef);
VS_WriteByte(0x6e);
VS_WriteByte(x); /* 参数x用来调整正弦测试中正弦波的频率
*/
VS_WriteByte(0);
VS_WriteByte(0);
VS_WriteByte(0);
VS_WriteByte(0);
VS_delay(60000); /* 这里延时一段时间,可以听到“正弦音”
*/
VS_delay(60000);
VS_delay(60000);
VS_delay(60000);
VS_delay(60000);
VS_delay(60000);
VS_WriteByte(0x45); /* 写入以下8个字节,退出正弦测试 */
VS_WriteByte(0x78);
VS_WriteByte(0x69);
VS_WriteByte(0x74);
VS_WriteByte(0);
VS_WriteByte(0);
VS_WriteByte(0);
VS_WriteByte(0);
VS_DCS_H; /* 关闭数据片选 */ }
/*
28
* SPI.h
*
* Created on: 2015-4-12
* Author: xiongpb
*/
#ifndef SPI_H_
#define SPI_H_
#include
#define SOFT_SPI //条件编译,SOFT_SPI启用软件SPI代码 extern void SPI_CS_High(void); extern void SPI_CS_Low(void); extern void SPI_HighSpeed(void); extern void SPI_LowSpeed(void); extern void SPI_init(void); extern unsigned char SPI_TxFrame(unsigned char *pBuffer, unsigned int
size);
char *pBuffer, unsigned int size); extern unsigned char SPI_RxFrame(unsigned
#endif /* SPI_H_ */
/***********************************************************************
****//**
* @file HAL_SDCard.c
* @addtogroup HAL_SDCard
* @{
***************************************************************************
***/
#include "msp430.h"
#include "SPI.h"
// Pins from MSP430 connected to the SD Card
#define SPI_SIMO BIT1 #define SPI_SOMI BIT2 #define SPI_CLK BIT3 #define SD_CS BIT7
// Ports
#define SPI_SEL P4SEL #define SPI_DIR P4DIR
29
#define SPI_OUT P4OUT
#define SPI_REN P4REN
#define SD_CS_SEL P3SEL
#define SD_CS_OUT P3OUT
#define SD_CS_DIR P3DIR
/***************************************************************************//**
* @brief Initialize SD Card
* @param None
* @return None
******************************************************************************/
void SPI_init(void)
{
// Port initialization for SD Card operation
SPI_SEL |= SPI_CLK + SPI_SOMI + SPI_SIMO;
SPI_DIR |= SPI_CLK + SPI_SIMO;
SPI_REN |= SPI_SOMI; // Pull-Ups on SD Card SOMI
SPI_OUT |= SPI_SOMI; // Certain SD Card Brands need pull-ups
SD_CS_SEL &= ~SD_CS;
SD_CS_OUT |= SD_CS;
SD_CS_DIR |= SD_CS;
// Initialize USCI_B1 for SPI Master operation
UCB1CTL1 |= UCSWRST; // Put state machine in reset
UCB1CTL0 = UCCKPL + UCMSB + UCMST + UCMODE_0 + UCSYNC; // 3-pin, 8-bit SPI master
// Clock polarity select - The inactive state is high
// MSB first
UCB1CTL1 = UCSWRST + UCSSEL_2; // Use SMCLK, keep RESET
UCB1BR0 = 63; // Initial SPI clock must be <400kHz
UCB1BR1 = 0; // f_UCxCLK = 25MHz/63 = 397kHz
UCB1CTL1 &= ~UCSWRST; // Release USCI state machine
30
UCB1IFG &= ~UCRXIFG;
}
/***************************************************************************//**
* @brief Enable low fast SD Card SPI transfers. This function is typically
* called after the initial SD Card setup is done to maximize
* transfer speed.
* @param None
* @return None
******************************************************************************/
void SPI_LowSpeed(void)
{
UCB1CTL1 |= UCSWRST; // Put state machine in reset
UCB1BR0 =63; // f_UCxCLK = 25MHz/2 = 12.5MHz
UCB1BR1 = 0;
UCB1CTL1 &= ~UCSWRST; // Release USCI state machine
}
/***************************************************************************//**
* @brief Enable fast SD Card SPI transfers. This function is typically
* called after the initial SD Card setup is done to maximize
* transfer speed.
* @param None
* @return None
******************************************************************************/
void SPI_HighSpeed(void)
{
UCB1CTL1 |= UCSWRST; // Put state machine in reset
UCB1BR0 = 2; // f_UCxCLK = 25MHz/2 = 12.5MHz
UCB1BR1 = 0;
UCB1CTL1 &= ~UCSWRST; //
31
Release USCI state machine
}
/***************************************************************************//**
* @brief Read a frame of bytes via SPI
* @param pBuffer Place to store the received bytes
* @param size Indicator of how many bytes to receive
* @return None
******************************************************************************/
unsigned char SPI_RxFrame(unsigned char *pBuffer, unsigned int size)
{
uint16_t gie = __get_SR_register() & GIE; // Store current GIE state
__disable_interrupt(); // Make this operation atomic
UCB1IFG &= ~UCRXIFG; // Ensure RXIFG is clear
// Clock the actual data transfer and receive the bytes
while (size--){
while (!(UCB1IFG & UCTXIFG)) ; // Wait while not ready for TX
UCB1TXBUF = 0xff; // Write dummy byte
while (!(UCB1IFG & UCRXIFG)) ; // Wait for RX buffer (full)
*pBuffer++ = UCB1RXBUF;
}
__bis_SR_register(gie); // Restore original GIE state
return 0;
}
/***************************************************************************//**
* @brief Send a frame of bytes via SPI
* @param pBuffer Place that holds the bytes to send
32
* @param size Indicator of how many bytes to send
* @return None
******************************************************************************/
unsigned char SPI_TxFrame(unsigned char *pBuffer, unsigned int size)
{
uint16_t gie = __get_SR_register() & GIE; // Store current GIE state
__disable_interrupt(); // Make this operation atomic
// Clock the actual data transfer and send the bytes. Note that we
// intentionally not read out the receive buffer during frame transmission
// in order to optimize transfer speed, however we need to take care of the
// resulting overrun condition.
while (size--){
while (!(UCB1IFG & UCTXIFG)) ; // Wait while not ready for TX
UCB1TXBUF = *pBuffer++; // Write byte
}
while (UCB1STAT & UCBUSY) ; // Wait for all TX/RX to finish
UCB1RXBUF; // Dummy read to empty RX buffer
// and clear any overrun conditions
__bis_SR_register(gie); // Restore original GIE state
return 0;
}
/***************************************************************************//**
* @brief Set the SD Card's chip-select signal to high
* @param None
* @return None
******************************************************************************/
33
void SPI_CS_High(void)
{
SD_CS_OUT |= SD_CS;
}
/***********************************************************************
****//**
* @brief Set the SD Card's chip-select signal to low
* @param None
* @return None
***************************************************************************
***/
void SPI_CS_Low(void)
{
SD_CS_OUT &= ~SD_CS;
}
/***********************************************************************
****//**
* @}
***************************************************************************
***/
/*
* Soft_SPI.h
*
* Created on: 2015-4-12
* Author: xiongpb
*/
#ifndef SOFT_SPI_H_
#define SOFT_SPI_H_
#include "msp430.h"
//sbit SPI_SCL=P40; //SPI同步时钟 输出
#define SPI_SCK_H P4OUT|=BIT0
#define SPI_SCK_L P4OUT&=~BIT0
34
//sbit SPI_SI =P42; //SPI同步数据 输出
#define SPI_SI_H P3OUT|=BIT5
#define SPI_SI_L P3OUT&=~BIT5 //sbit SPI_SO =P1^6; //SPI同步数据 输入
#define SPI_SO_IN P1IN&BIT6
extern void SPI2_Init(void);
extern void SPI_WriteByte(unsigned char x);
extern unsigned char SPI_ReadByte();
#endif /* SOFT_SPI_H_ */
/*
* Soft_SPI.c
*
* Created on: 2015-4-12
* Author: xiongpb
*/
#include "Soft_SPI.h"
/***********************************************************************
************************************* * 名 称:SPI_Init
* 功 能:初始化SPI端口
* 入口参数:无
* 出口参数:无
* 说 明: 初始化SD卡为SPI模式
* 使用范例:SPI_Init();
***********************************************************************
*************************************/ void SPI2_Init(void)
{
P3DIR|=BIT5; //输出
P4DIR|=BIT0; //输出
P1DIR&=~BIT6; //输入
SPI_SCK_H;
}
/***********************************************************************
************************************* * 名 称:SPI_WriteByte
* 功 能:SPI发送1个字节
* 入口参数:x:待发送字节
35
* 出口参数:无
* 说 明: 无
* 使用范例:无
***********************************************************************
*************************************/ void SPI_WriteByte(unsigned char x) {
unsigned char i,data;
data=x;
for(i=0;i<8;i++)
{
SPI_SCK_L;
if(data&BIT7)
SPI_SI_H;
else
SPI_SI_L;
SPI_SCK_H;
data<<=1;
}
}
/***********************************************************************
************************************* * 名 称:SPI_ReadByte
* 功 能:SPI接收1个字节
* 入口参数:无
* 出口参数:x:待接收字节
* 说 明: 无
* 使用范例:无
***********************************************************************
*************************************/ unsigned char SPI_ReadByte() {
unsigned char i,data;
for(i=0;i<8;i++)
{
SPI_SCK_L;
if(SPI_SO_IN)
{
data<<=1;
data=data+BIT0;
}
else
36
data<<=1;
SPI_SCK_H;
}
return data;
}
/*
* SD_SPI.h
*
* Created on: 2015-4-12
* Author: xiongpb
*/
#ifndef SD_SPI_H_
#define SD_SPI_H_
extern unsigned char SD_Init(); extern unsigned char SD_Reset(); extern unsigned char SD_Read_Sector(unsigned long Addr ,unsigned char
*Ptr,unsigned int FirstNum,unsigned int Num);
extern unsigned char SD_Write_Sector(unsigned long Addr ,unsigned char
*Ptr,unsigned int FirstNum,unsigned int Num);
extern unsigned char SD_Set_SPI();
#endif /* SD_SPI_H_ */
/*
* SD_SPI.c
*
* Created on: 2015-4-12
* Author: xiongpb
*/
/*
* SD_SPI.c
*说明:该函数库为通用SD卡读写顶层库函数。
* 用户只需要更改“SD_HardWare.c”中的少量底层代码,即可移
植到任何处理器上。
* Created on: 2013-3-4
*
*/
#include"SD_HardWare.h"
37
#include "SD_SPI.h"
#include"SPI.h"
//-----SD 卡相关的命令宏定义-----
#define SD_WRITE_DELAY 100 // 先发74个以上的时
钟
#define SD_EMPTY_CLK 0xFF #define SD_EMPTY_DATA 0xFF #define SD_SPI_CRC 0xFF //SPI模式下CRC
无效,随便给
#define SD_CMD0_CRC 0x95 //复位命令CMD0
的CRC校验码
#define SD_CMD0 0+0x40 //复位命令 #define SD_CMD1 1+0x40 //SPI模式命令 #define SD_CMD17 17+0x40 //读扇区命令 #define SD_CMD24 24+0x40 //写扇区命令 #define SD_CMD41 41+0x40 //初始化扇区命令 #define SD_CMD55 55+0x40 //初始化扇区命令 //-----SD卡相关应答-----
#define SD_COMMAND_ACK 0x00 //命令应答 #define SD_RESET_ACK 0x01 //复位应答 #define SD_DATA_ACK 0xFE //数据应答 #define SD_WRITE_ACK 0x05 //写扇区应答 //----系统超时控制----
#define SD_TIMEOUT 100
#define TIMEOUT 200
/***********************************************************************
************************************* * 名 称:Write_Command_SD()
* 功 能:SD卡在SPI模式下,向SD卡中写入6个字节的命令 * 入口参数:CMD:指向存放六个字节命令的数组
* 出口参数:SD 卡应答值
* 说 明: 向SD卡中一次写入六个字节的命令
* 使用范例:Write_Command_SD(CMD); ***********************************************************************
*************************************/ unsigned char Write_Command_SD(unsigned char *CMD)
{
unsigned char tmp=0;
unsigned char i = 0;
SD_CS_High();
//-----先发8个空clock-----
SD_Write_Byte(0xFF);
SD_CS_Low();
38
//-----写入6个字节的命令字帧-----
SD_Write_Frame(CMD,6);
//-----空第一次,即忽略第一个返回值-----
SD_Read_Byte();
i = SD_TIMEOUT;
do
{
tmp = SD_Read_Byte();
i--;
} while((tmp==0xff)&&i);
return(tmp);
}
/***********************************************************************
*************************************
* 名 称:SD_Write_Sector
* 功 能:SD卡在SPI模式下,向SD卡中,在指定的位置写入指定个数的数据。
* 入口参数:Addr:物理扇区的地址
* *Ptr:指向待写数据的数据缓存
* FirstNum:写入该扇区的首个字节偏移地址
* Num:此次操作要写入的数据个数
(FirstNum+Num<512)
* 出口参数:0:写入失败
:写入成功 * 1
* 使用范例:SD_Write_Sector(83241,buffer,0,100); //向扇区83241中写入100个字节
***********************************************************************
*************************************/
unsigned char SD_Write_Sector(unsigned long Addr ,unsigned char *Ptr,unsigned
int FirstNum,unsigned int Num)
{
unsigned char temp=0;
unsigned int EndNum = 0;
unsigned int i=0;
unsigned char CMD[6]={0};
//-----发送命令-----
CMD[0]=SD_CMD24;
//-----将32位地址拆分------
Addr = Addr <<9; //sector = sector*512 将物理地址转换为逻辑地址;(注意一定需要此处的转换)
CMD[1]=((Addr&0xFF000000)>>24);
CMD[2]=((Addr&0x00FF0000)>>16);
CMD[3]=((Addr&0x0000FF00)>>8);
CMD[4]=Addr&0x000000FF;
39
//-----CRC校验,SPI模式下无效,可随便给-----
CMD[5]=SD_SPI_CRC;
//----等待SD卡应答----
i=TIMEOUT; //超时
门限值
do{
temp = Write_Command_SD(CMD);
i--;
}while((temp != SD_COMMAND_ACK)&&i); //超时判断
if (i==0) return(0); //超
时,返回失败代码
//----空发若干次CLK----
for(i=0;i>24);
CMD[2]=((Addr&0x00FF0000)>>16);
CMD[3]=((Addr&0x0000FF00)>>8);
CMD[4]=Addr&0x000000FF;
//-----CRC校验,SPI模式下无效,可随便给-----
CMD[5]=SD_SPI_CRC;
//----等待SD卡应答----
i=TIMEOUT; //超时门
限值
do{
temp = Write_Command_SD(CMD);
i--;
}while((temp!=SD_COMMAND_ACK)&&i); //超时判断
if (i==0)
{
SD_CS_High();
return(0); //超
时,返回失败代码
}
//----等待SD卡应答--------------
i=TIMEOUT; //超时门
限值
do{
temp = SD_Read_Byte();
i--;
}while(( temp !=SD_DATA_ACK)&&i); //超时判断
if (i==0)
{
SD_CS_High();
return(0); //超
时,返回失败代码
}
//-----读取指定字节-----
EndNum=FirstNum+Num;
for(i=0;i>24);
CMD[2]= ((0x00ffc000 & 0x00ff0000) >>16);
CMD[3]= ((0x00ffc000 & 0x0000ff00) >>8);
CMD[4]= 0x00ffc000 & 0x000000ff;
CMD[5]= SD_SPI_CRC;
i=TIMEOUT;
//超时门限值
do{
CMD[0] = SD_CMD55;
//CMD55命令
temp = Write_Command_SD(CMD); //先发送 CMD55
//-----判断是否为SD卡-----
if(temp == 0x01)
//如果有反应
{
// //-----如无需判断存储卡类型,直接执行线间代码-----
CMD[0] = SD_CMD41;
//CMD41命令
temp = Write_Command_SD(CMD); //发送CMD41进行激活
if(temp == 0x00)
{
SD_CS_High();
//CS片选禁能
}
// //---------------------------------------------------
}
//-----否则,为MMC卡-----
else
//如果发送CMD55无反应,改发送CMD1
{
CMD[0] = SD_CMD1;
//CMD1命令
CMD[5] = 0xFF;
temp = Write_Command_SD(CMD); //发送
45
CMD1进行激活
if(temp == 0x00)
{
SD_CS_High();
//CS片选禁能
}
}
i--;
}while((temp !=SD_COMMAND_ACK)&&i); //超时
判断
if(i==0)
return(0);
//超时,返回失败代码
else
return (1);
}
/*
* SD_HardWare.h
*
* Created on: 2015-4-12
* Author: xiongpb
*/
#ifndef SD_HARDWARE_H_
#define SD_HARDWARE_H_
extern void SD_Write_Byte(unsigned char Value);
extern void SD_Write_Frame(unsigned char *pBuffer,unsigned char size);
extern void SD_CS_High();
extern void SD_CS_Low();
extern unsigned char SD_Read_Byte(); extern void SD_Read_Frame(unsigned char *pBuffer, unsigned int size);
extern void SD_High_Speed(); extern void SD_Low_Speed();
#endif /* SD_HARDWARE_H_ */
46
/*
* SD_HardWare.c
*
* Created on: 2015-4-12
* Author: xiongpb
*/
/*
* SD_HardWare.c
*说明:此函数库文件为SD卡底层相关的读写和操作函数,也是与最底层G2的SPI唯一的衔接函数库。
* 若是需要在其他硬件微处理器上使用上层SD_SPI.c库函数,只需要更改此函数库中带有
* “此处,调用底层G2硬件接口函数”注释的4处底层SPI函数,和SD_High_Speed()、
* SD_Low_Speed()这两个函数即可完成移植。
* Created on: 2013-4-3
*
*/
#include"MSP430.h"
#include"SPI.h"
/***********************************************************************
*****
* 名 称:SD_High_Speed()
* 功 能:SD卡在SPI读取模式下,使能SPI的时钟为高速传输模式 * 入口参数:无
* 出口参数:无
* 说 明: 该函数可以更改当前SPI工作的速度。 一般在初始化完SD卡后 * 需要将SPI的速度提高,加快读写速度
* 使用范例:SD_High_Speed();
***********************************************************************
*****/
void SD_High_Speed()
{
SPI_HighSpeed();
}
/***********************************************************************
*****
* 名 称:SD_Low_Speed()
* 功 能:SD卡在SPI读取模式下,使能SPI的时钟为低速(300K左右) * 入口参数:无
* 出口参数:无
47
* 说 明: 由于在初始化完SD卡时,需要的速度很低,此函数更改当前 * SPI工作的速度。使其在300K左右
* 使用范例:SD_Low_Speed();
***********************************************************************
*****/
void SD_Low_Speed()
{
SPI_LowSpeed();
}
/***********************************************************************
*****
* 名 称:SD_CS_High()
* 功 能:SD卡在SPI读取模式下,控制使能CS管脚为高电平 * 入口参数:无
* 出口参数:无
* 说 明: 此处的CS管脚可以根据硬件的需要,任意指定管脚作CS均可。 * 使用范例:SD_CS_High();
***********************************************************************
*****/
void SD_CS_High()
{
//-----此处,调用底层G2硬件接口函数-----
SPI_CS_High();
}
/***********************************************************************
*****
* 名 称:SD_CS_Low()
* 功 能:SD卡在SPI读取模式下,控制使能CS管脚为低电平 * 入口参数:无
* 出口参数:无
* 说 明:: 此处的CS管脚可以根据硬件的需要,任意指定管脚作CS均可。 * 使用范例:SD_CS_Low();
***********************************************************************
*****/
void SD_CS_Low()
{
//-----此处,调用底层G2硬件接口函数-----
SPI_CS_Low();
}
/***********************************************************************
*****
* 名 称:SD_Write_Byte()
* 功 能:SPI模式下,向SD卡中写入一个字节数据
48
* 入口参数:value:当前要写入的数据
* 出口参数:无
* 说 明:使用该函数可以向SD卡中写入一个字节
* 使用范例:SD_Write_Byte();// 将value写入SD 卡中
***********************************************************************
*****/
void SD_Write_Byte(unsigned char value) {
unsigned char temp=0;
do{
//-----此处,调用底层G2硬件接口函数-----
temp=SPI_TxFrame(&value,1);
}while(temp==0);
}
/***********************************************************************
*****
* 名 称:SD_Write_Frame()
* 功 能:SPI模式下,向SD卡中写入size个字节数据
* 入口参数:pBuffer:当前要写入的数据头指针
* size:要写入的数据个数
* 出口参数:无
* 说 明:使用该函数可以向SD卡中写入size个字节
* 使用范例:无
***********************************************************************
*****/
void SD_Write_Frame(unsigned char *pBuffer,unsigned int size)
{
unsigned char temp=0;
do{
//-----此处,调用底层G2硬件接口函数-----
temp=SPI_TxFrame(pBuffer,size);
}while(temp==0);
}
/***********************************************************************
*****
* 名 称:SD_Read_Frame()
* 功 能:SPI模式下,从SD卡中读出size个字节数据
* 入口参数:pBuffer:存储的读SD数据的头指针
* size:计划要读取的数据个数
* 出口参数:无
* 说 明:使用该函数可以从SD卡中读出size个字节
* 使用范例:无
***********************************************************************
*****/
49
void SD_Read_Frame(unsigned char *pBuffer, unsigned int size)
{
unsigned char temp=0;
do{
//-----此处,调用底层G2硬件接口函数-----
temp=SPI_RxFrame(pBuffer,size);
}while(temp==0);
}
/***********************************************************************
*****
* 名 称:SD_Read_Byte()
* 功 能:SPI模式下,读取SD卡中的一个字节
* 入口参数:无
* 出口参数:value:当前读取出的数据
* 说 明:使用该函数可以读取SD卡中的一个字节
* 使用范例:tempt=SD_Read_Byte();// 读取一个字节,并赋给tempt变量 ***********************************************************************
*****/
unsigned char SD_Read_Byte() {
unsigned char value=0;
unsigned char temp=0;
do{
-----此处,调用底层G2硬件接口函数----- //
temp=SPI_RxFrame(&value,1);
}while(temp==0);
return value;
}
未完待续。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
50