物联网项目分享 Stm32单片机的音乐播放器设计 - 物联网 嵌入式

2024-01-09


0 前言

???? 这两年开始毕业设计和毕业答辩的要求和难度不断提升,传统的毕设题目缺少创新和亮点,往往达不到毕业答辩的要求,这两年不断有学弟学妹告诉学长自己做的项目系统达不到老师的要求。

为了大家能够顺利以及最少的精力通过毕设,学长分享优质毕业设计项目,今天要分享的是

???? 基于Stm32单片机的音乐播放器设计与实现

????学长这里给一个题目综合评分(每项满分5分)

  • 难度系数:3分
  • 工作量:3分
  • 创新点:3分

1 简介

采用STM32实现的多功能音乐播放器。

2 主要器件

  • STM32F103RBT6主控芯片
  • VS1003解码芯片(解码MP3)
  • TEA5767立体收音机芯片
  • DS18B20数字温度温度传感器
  • RGB彩灯
  • EEPROM芯片
  • TPA152功率放大芯片
  • LM2576-3.3V电源芯片

3 实现效果

整体实物
在这里插入图片描述
系统主界面
在这里插入图片描述

音乐播放器功能部分展示
在这里插入图片描述
在这里插入图片描述

4 设计原理

硬件系统框图
在这里插入图片描述

MCU为整个系统的核心,控制着整个系统的运行,让MCU稳定的运行是非常必须的,下图(图2.2)为MCU的原理图,包括一个后备电源UPS1,一个主电源VCC3.3和一个模拟电源,模拟电源通过从VCC3.3加滤波电路得到。MCU外围的必须电路由滤波电容,下载电路(串口1)以及复位开关组成。同时,考虑到系统需要时钟功能,给时钟部分增加了后背电源电路,通过二极管连接到VBAT脚,给实时时钟供电。这里采用了双电源结构,即在电源有外部供电的时候,后备电池不给时钟供电,时钟的电源来自外部,只有当外部电源断开的时候,后备电源才给时钟供电,以保持时钟的计时,这样可以延长后备电池的使用时间。
同时,为了调试方便,下面电路还加了一个多余的按键和LED灯,方便在调试的时候使用。并且,考虑到某些模块对速度的要求,特意对MCU的IO口做了安排,这样虽然增加了布线难度,但是提高了执行速度,还是值得的。对多余IO口的安排,则是全部引出,方便以后扩展其他功能,比如:家电控制等。同时,对于STM32F103RBT6自带的USB接口,也已经引出,日后通过升级,可以实现USB控制的功能。
这里要注意一点:因为PT2314,TEA5767,FM24C16这三个器件都是使用IIC总线控制的,所以,把这三个器件挂在一个IIC总线上,节省了IO口。 MCU和DS18B20模块电路图如下:
在这里插入图片描述
软件模块化设计

  • 对于底层驱动软件子系统包括如下模块程序:LCD驱动模块、触摸屏驱动模块、SD卡驱动模块、VS1003驱动模块、PT2314驱动模块、FM24C16驱动模块、TEA5767驱动模块、温度传感器驱动模块、彩灯驱动模块、实时时钟驱动模块。
  • 对于应用软件子系统包括如下模块程序:JPEG/BMP解码模块、FAT文件系统管理模块、音乐播放模块、图片浏览模块、游戏模块、闹钟模块、时间模块、设置管理模块、电子书模块、收音机模块、彩灯控制模块。

LCD模块驱动程序设计

本系统用到的LCD是八位数据模式,驱动IC型号是FMT0371,该芯片为松下合资厂生产的一个LCD驱动IC。最高支持26万色的TFT LCD,有6位、8位、16位和18位数据模式,可以方便选择。本系统配套的LCD使用的是八位数据模式,65K色。

根据该LCD的DATASHEET,每个像素点的GRAM实际上是一个18bit的数据寄存器。在16bit模式下与写入数据的对应关系如图3.1 所示:
在这里插入图片描述
从图中可以看出,RGB的有效位数分别为565,比如写入0XF800则显示纯红色,写入0X07E0则显示纯绿色,写入0X001F 则显示纯蓝色。在处理数据的时候要把像素值先变换为这样的结构,然后再写入LCD。LCD的显示状态都是由LCD的控制命令控制的,通过写入不同的控制命令和数据,就可以实现不同的现实功能和效果。分析DATASHEET得到几个重要的控制命令:

00H:这个命令用来控制内存操作模式,这里我们主要用它来改变LCD的扫描方向。
02H,03H:这两个命令用来分别设置X,Y方向的开始显示的点坐标。
04H,05H:这两个命令用来分别设置X,Y方向的结束显示的点坐标。
0EH,0FH:这两个命令用来写入和读取显存。
LCD驱动部分包括几个关键函数:LCD读写寄存器函数、LCD读写数据函数、LCD初始化函数和LCD画点函数。有了这几个基本函数,其他的画线、画面、甚至画图都比较容易了。LCD与MCU的连线包括D0~D7、CS、RS、RST、WR、RD、BL共14根线。
D0~D7:数据线
CS:LCD的片选线,低电平有效。
RS:LCD的地址/数据控制,高电平表示数据,低电平表示地址。
RST:复位线,低电平有效。
WR:写数据访问控制。
RD:读数据访问控制。
BL:LCD背光,高电平有效。

  1. LCD读写寄存器:对LCD寄存器的操作线设置RS为低,表示写入寄存器,然后拉低片选信号,给BL
    送入数据,然后通过一个WR的脉冲,就可以把数据写入到LCD了。最后释放RS,CS,完成此次操作。对LCD寄存器的读操作和写操作差不多,不同之处就是把WR脉冲改为RD脉冲。
  2. LCD读写数据:对于LCD数据的读写,和寄存器的读写差不多,只要把RS设置为高,就表示此次操作是对数据的读写,其他同寄存器的读写操作一样。
  3. LCD初始化:这部分是在前面两步成功的基础上才能进行的,LCD的初始化涉及到其内部很多寄存器的初始化。比较复杂,由void TFT_Init(void)函数实现,具体初始化过程请参考附件里面的代码。
  4. LCD画点:画点的实现,要先设置LCD开始显示和结束显示的范围,通过0X02H~0X04H这四个命令实现。之后写入0X0E命令,开始写入数据,就可以写入像素值(16bit)了,对于画点,我们只要写入一个像素点就可以了,这样就完成了在LCD上画一点。具体见附件里面的void TFT_DrawPoint(u8 x,u16 y)函数。

以上四个函数是LCD的主要函数,是最底层的。其他任何功能的函数都可以在这几个底层函数基础上实现。其他功能的LCD驱动函数均在tftlcd.c里面有定义和说明,具体见附件。

VS1003模块驱动程序设计
VS1003也是采用SPI模式,不过是挂在SPI1上面,这里主要介绍VS1003的初始化操作。在对MCU相关IO口正确配置之后就可以对VS1003模块进行初始化了。VS1003通过7根线与MCU通信: XRST、XDCS、XCS、DREQ、SCK、SO、SI。

  • XRST:VS1003复位线,低电平有效。
  • XDCS:数据片选信号,低电平有效。
  • XCS:命令片选信号,低电平有效。
  • DREQ:数据请求,输入总线。
  • SCK、SI、SO:SPI接口线。

VS1003与MCU的通讯都是通过SPI总线来完成的,在默认情况下,数据将在SCLK的上升沿有效(被读入VS1003),一次需要在SCLK的下降沿更新数据,并且字节发送以MSB在先。注意VS1003的最大写入和读出时钟分别是CLKI/4和CLKI/6(CLKI为VS1003内部时钟)。

VS1003模块初始化步骤:

  • 硬复位,XRST =0;
  • 延时,XDCS、XCS、XRST置1;
  • 等待DREQ为高;
  • 软件复位:SPI_MODE=0X0804;
  • 等待DREQ为高(软件复位结束);
  • 设置VS1003的时钟:SCI_CLOCKF=0X9800,3倍频;
  • 设置VS1003的采样率:SPI_AUDATA=0XBB81,采样率48K,立体声;
  • 设置重音:SPI_BASS=0X0055;
  • 设置音量:SCI_VOL=0X2020;
  • 向VS1003发送四个字节无效数据,启动SPI发送;

VS1003的初始化在VS1003x.c里面,通过void Vs1003_Init(void)函数实现。

TEA5767模块驱动程序设计

TEA5767收音机模块支持IIC和三线模式,这里我们使用IIC来控制。TEA5767的器件地址是0XC0,在对TEA5767的读操作通过写入0XC1来执行。

TEA5767写操作:

  • 发送IIC起始信号
  • 发送器件地址0XC0
  • 等待应答
  • 发送一个字节,等待应答,再发送一个字节,等待应答,循环5次
  • 发送IIC停止信号

TEA5767的读操作与写操作基本相同,只是IIC开始之后写入0XC1,将发送一个字节改为接收一个字节就可以了。关于TEA5767的其他操作函数均在TEA5767.c里面

5 部分核心代码

#include "vs1003.h"	 

//VS1003的全功能函数
//支持SIN测试和RAM测试
//并加入了VS1003的频谱显示代码,不过说实话不咋地,还不如自己写的频谱分析,怀疑是不是真实的频谱变换?  
//正点原子@SCUT
//V1.1

//VS1003设置参数
//0,henh.1,hfreq.2,lenh.3,lfreq 5,主音量
u8 vs1003ram[5]={0,0,0,0,250};
//保存VS1003的设置
//EEPROM地址:486~490 共五个
void Save_VS_Set(void)
{
	u8 t;
	for(t=0;t<5;t++)FM24C16_WriteOneByte(488+t,vs1003ram[t]);//vs1003ram保存 	 
}
//读取VS1003的设置
//EEPROM地址:486~490 共五个
void Read_VS_Set(void)
{
	u8 t;
	for(t=0;t<5;t++)vs1003ram[t]=FM24C16_ReadOneByte(488+t);//vs1003ram调用
}	 					 
//SPI1口读写一个字节
//TxData:要发送的字节
//返回值:读取到的字节
u8 SPI1_ReadWriteByte(u8 TxData)
{
	while((SPI1->SR&1<<1)==0);//等待发送区空				  
	SPI1->DR=TxData;	 	  //发送一个byte   
	while((SPI1->SR&1<<0)==0);//等待接收完一个byte  
	return SPI1->DR;          //返回收到的数据				    
} 
//设置SPI1的速度
//SpeedSet:1,高速;0,低速;
void SPI1_SetSpeed(u8 SpeedSet)
{
	SPI1->CR1&=0XFFC7;
	if(SpeedSet==1)//高速
	{
		SPI1->CR1|=6<<3;//Fsck=Fpclk/64=1.125Mhz	
	}else//低速
	{
		SPI1->CR1|=6<<3; //Fsck=Fpclk/128=562.5Khz
	}
	SPI1->CR1|=1<<6; //SPI设备使能	  
} 
//软复位VS1003
void Vs1003SoftReset(void)
{	 
	u8 retry; 				   
	while((GPIOC->IDR&MP3_DREQ)==0);//等待软件复位结束
	SPI1_ReadWriteByte(0X00);//启动传输
	retry=0;
	while(Vs1003_REG_Read(SPI_MODE)!=0x0804)// 软件复位,新模式  
	{
		Vs1003_CMD_Write(SPI_MODE,0x0804);// 软件复位,新模式
		delay_ms(2);//等待至少1.35ms 
		if(retry++>100)break; 
	}	 				  
	while ((GPIOC->IDR & MP3_DREQ) == 0);//等待软件复位结束	   

	retry=0;
	while(Vs1003_REG_Read(SPI_CLOCKF)!=0X9800)//设置vs1003的时钟,3倍频 ,1.5xADD 
	{
		Vs1003_CMD_Write(SPI_CLOCKF,0X9800);//设置vs1003的时钟,3倍频 ,1.5xADD
		if(retry++>100)break; 
	}		   
	retry=0;
	while(Vs1003_REG_Read(SPI_AUDATA)!=0XBB81)//设置vs1003的时钟,3倍频 ,1.5xADD 
	{
		Vs1003_CMD_Write(SPI_AUDATA,0XBB81);
		if(retry++>100)break; 
	}

	//Vs1003_CMD_Write(SPI_CLOCKF,0X9800); 	    
	//Vs1003_CMD_Write(SPI_AUDATA,0XBB81); //采样率48k,立体声	 
	set1003();//设置VS1003的音效				 
	ResetDecodeTime();//复位解码时间	    
    //向vs1003发送4个字节无效数据,用以启动SPI发送
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	SPI1_ReadWriteByte(0XFF);
	MP3_DCS_SET(1);//取消数据传输
	delay_ms(20);
} 
//硬复位MP3
void Mp3Reset(void)
{
	MP3_RST_SET(0);
	delay_ms(20);
	MP3_DCS_SET(1);//取消数据传输
	MP3_CCS_SET(1);//取消数据传输
	MP3_RST_SET(1);    
	while((GPIOC->IDR & MP3_DREQ)==0);	//等待DREQ为高
	delay_ms(20);				 
}
//正弦测试 
void VsSineTest(void)
{											    
	Mp3Reset();	 
	Vs1003_CMD_Write(0x0b,0X2020);	  //设置音量	 
 	Vs1003_CMD_Write(SPI_MODE,0x0820);//进入vs1003的测试模式	    
	while ((GPIOC->IDR & MP3_DREQ) == 0);     //等待DREQ为高
 	//向vs1003发送正弦测试命令:0x53 0xef 0x6e n 0x00 0x00 0x00 0x00
 	//其中n = 0x24, 设定vs1003所产生的正弦波的频率值,具体计算方法见vs1003的datasheet
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x53);
	SPI1_ReadWriteByte(0xef);
	SPI1_ReadWriteByte(0x6e);
	SPI1_ReadWriteByte(0x24);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1); 
    //退出正弦测试
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x45);
	SPI1_ReadWriteByte(0x78);
	SPI1_ReadWriteByte(0x69);
	SPI1_ReadWriteByte(0x74);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);		 

    //再次进入正弦测试并设置n值为0x44,即将正弦波的频率设置为另外的值
    MP3_DCS_SET(0);//选中数据传输      
	SPI1_ReadWriteByte(0x53);
	SPI1_ReadWriteByte(0xef);
	SPI1_ReadWriteByte(0x6e);
	SPI1_ReadWriteByte(0x44);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);
    //退出正弦测试
    MP3_DCS_SET(0);//选中数据传输
	SPI1_ReadWriteByte(0x45);
	SPI1_ReadWriteByte(0x78);
	SPI1_ReadWriteByte(0x69);
	SPI1_ReadWriteByte(0x74);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(100);
	MP3_DCS_SET(1);	 
}	 
//ram 测试 																				 
void VsRamTest(void)
{
	u16 regvalue ;	   
	Mp3Reset();     
 	Vs1003_CMD_Write(SPI_MODE,0x0820);// 进入vs1003的测试模式
	while ((GPIOC->IDR&MP3_DREQ)==0); // 等待DREQ为高
 	MP3_DCS_SET(0);	       			  // xDCS = 1,选择vs1003的数据接口
	SPI1_ReadWriteByte(0x4d);
	SPI1_ReadWriteByte(0xea);
	SPI1_ReadWriteByte(0x6d);
	SPI1_ReadWriteByte(0x54);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	SPI1_ReadWriteByte(0x00);
	delay_ms(50);  
	MP3_DCS_SET(1);
	regvalue=Vs1003_REG_Read(SPI_HDAT0); // 如果得到的值为0x807F,则表明完好。
	printf("regvalueH:%x\n",regvalue>>8);//输出结果 
	printf("regvalueL:%x\n",regvalue&0xff);//输出结果 
}     
//向VS1003写命令
//address:命令地址
//data:命令数据
void Vs1003_CMD_Write(u8 address,u16 data)
{  
    while((GPIOC->IDR&MP3_DREQ)==0);//等待空闲
	SPI1_SetSpeed(0);//低速 
	 
	MP3_DCS_SET(1); //MP3_DATA_CS=1;
	MP3_CCS_SET(0); //MP3_CMD_CS=0; 
	
	SPI1_ReadWriteByte(VS_WRITE_COMMAND);//发送VS1003的写命令
	SPI1_ReadWriteByte(address); //地址
	SPI1_ReadWriteByte(data>>8); //发送高八位
	SPI1_ReadWriteByte(data);	 //第八位
	MP3_CCS_SET(1);          //MP3_CMD_CS=1; 
	SPI1_SetSpeed(1);//高速
} 
//向VS1003写数据
void Vs1003_DATA_Write(u8 data)
{
	MP3_DCS_SET(0);   //MP3_DATA_CS=0;
	SPI1_ReadWriteByte(data);
	MP3_DCS_SET(1);   //MP3_DATA_CS=1;
	MP3_CCS_SET(1);   //MP3_CMD_CS=1; 
}         
//读VS1003的寄存器           
//读VS1003
//注意不要用倍速读取,会出错
u16 Vs1003_REG_Read(u8 address)
{ 
	u16 temp=0; 
    while((GPIOC->IDR&MP3_DREQ)==0);//非等待空闲状态 
	SPI1_SetSpeed(0);//低速 
	MP3_DCS_SET(1);       //MP3_DATA_CS=1;
	MP3_CCS_SET(0);       //MP3_CMD_CS=0;
	SPI1_ReadWriteByte(VS_READ_COMMAND);//发送VS1003的读命令
	SPI1_ReadWriteByte(address);        //地址
	temp=SPI1_ReadWriteByte(0xff);		//读取高字节
	temp=temp<<8;
	temp+=SPI1_ReadWriteByte(0xff); 	//读取低字节
	MP3_CCS_SET(1);      //MP3_CMD_CS=1; 
	SPI1_SetSpeed(1);//高速
    return temp; 
}  
//FOR WAV HEAD0 :0X7761 HEAD1:0X7665    
//FOR MIDI HEAD0 :other info HEAD1:0X4D54
//FOR WMA HEAD0 :data speed HEAD1:0X574D
//FOR MP3 HEAD0 :data speed HEAD1:ID
//比特率预定值
const u16 bitrate[2][16]=
{ 
{0,8,16,24,32,40,48,56,64,80,96,112,128,144,160,0}, 
{0,32,40,48,56,64,80,96,112,128,160,192,224,256,320,0}
};
//返回Kbps的大小
//得到mp3&wma的波特率
u16 GetHeadInfo(void)
{
	unsigned int HEAD0;
	unsigned int HEAD1;            
    HEAD0=Vs1003_REG_Read(SPI_HDAT0); 
    HEAD1=Vs1003_REG_Read(SPI_HDAT1);
    switch(HEAD1)
    {        
        case 0x7665:return 0;//WAV格式
        case 0X4D54:return 1;//MIDI格式 
        case 0X574D://WMA格式
        {
            HEAD1=HEAD0*2/25;
            if((HEAD1%10)>5)return HEAD1/10+1;
            else return HEAD1/10;
        }
        default://MP3格式
        {
            HEAD1>>=3;
            HEAD1=HEAD1&0x03; 
            if(HEAD1==3)HEAD1=1;
            else HEAD1=0;
            return bitrate[HEAD1][HEAD0>>12];
        }
    } 
}  
//重设解码时间                          
void ResetDecodeTime(void)
{
	Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);
	Vs1003_CMD_Write(SPI_DECODE_TIME,0x0000);//操作两次
}
//得到mp3的播放时间n sec
u16 GetDecodeTime(void)
{ 
    return Vs1003_REG_Read(SPI_DECODE_TIME);   
} 
//加载频谱分析的代码到VS1003
void LoadPatch(void)
{
	u16 i;
	for (i=0;i<943;i++)Vs1003_CMD_Write(atab[i],dtab[i]); 
	delay_ms(10);
}
//得到频谱数据
void GetSpec(u8 *p)
{
	u8 byteIndex=0;
	u8 temp;
	Vs1003_CMD_Write(SPI_WRAMADDR,0x1804);                                                                                             
	for (byteIndex=0;byteIndex<14;byteIndex++) 
	{                                                                               
		temp=Vs1003_REG_Read(SPI_WRAM)&0x63;//取小于100的数    
		*p++=temp;
	} 
}
void SPI1_RST(void)
{
	RCC->APB2RSTR|=1<<12;//复位SPI1
	delay_ms(10); 	
	RCC->APB2RSTR&=~(1<<12);//结束复位SPI1
	delay_ms(10); 
	SPI1->CR1|=0<<10;//全双工模式	
	SPI1->CR1|=1<<9; //软件nss管理
	SPI1->CR1|=1<<8;  

	SPI1->CR1|=1<<2; //SPI主机
	SPI1->CR1|=0<<11;//8bit数据格式	
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1  
	SPI1->CR1|=6<<3; //Fsck=Fpclk/128 =562.5khz
	SPI1->CR1|=0<<7; //MSBfirst 
	
	SPI1->CR1|=1<<6; //SPI设备使能
}	  
//设定vs1003播放的音量和高低音 
void set1003(void)
{
    u8 t;
    u16 bass=0; //暂存音调寄存器值
    u16 volt=0; //暂存音量值
    u8 vset=0;  //暂存音量值 	 
    vset=255-vs1003ram[4];//取反一下,得到最大值,表示最大的表示 
    volt=vset;
    volt<<=8;
    volt+=vset;//得到音量设置后大小
     //0,henh.1,hfreq.2,lenh.3,lfreq        
    for(t=0;t<4;t++)
    {
        bass<<=4;
        bass+=vs1003ram[t]; 
    }     
	Vs1003_CMD_Write(SPI_BASS,bass);//BASS   
    Vs1003_CMD_Write(SPI_VOL,volt); //设音量 
}    

//初始化VS1003的IO口	 
void Vs1003_Init(void)
{
	RCC->APB2ENR|=1<<2;       //PORTA时钟使能  
	RCC->APB2ENR|=1<<12;      //SPI1时钟使能	 
	
	//存储器映射,不用理    
	#ifdef  VECT_TAB_RAM  									   
	  NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0); 
	#else   							 
	  NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);   
	#endif  
			    
	GPIOA->CRL&=0X000FFFFF;//PA5.6.7复用输出
	GPIOA->CRL|=0XBBB00000; 	 
	GPIOA->ODR|=0X00E0;//PA5.6.7上拉  
	
	SPI1->CR1|=0<<10;//全双工模式	
	SPI1->CR1|=1<<9; //软件nss管理
	SPI1->CR1|=1<<8;  

	SPI1->CR1|=1<<2; //SPI主机
	SPI1->CR1|=0<<11;//8bit数据格式	
	SPI1->CR1|=1<<1; //空闲模式下SCK为1 CPOL=1
	SPI1->CR1|=1<<0; //数据采样从第二个时间边沿开始,CPHA=1  
	SPI1->CR1|=6<<3; //Fsck=Fpclk/128 =562.5khz
	SPI1->CR1|=0<<7; //MSBfirst 
	
	SPI1->CR1|=1<<6; //SPI设备使能
	//以上初始化VS1003的SPI连接口,SPI1口	
	//所以上拉之前,必须使能时钟.才能实现真正的上拉输出
	RCC->APB2ENR|=1<<2;    //PA时钟使能
	RCC->APB2ENR|=1<<4;    //PC时钟使能
	RCC->APB2ENR|=1<<0;    //开启辅助时钟
	AFIO->MAPR=0X04000000;//关闭JTAG,只有关闭JTAG,才能使用PA14 

	GPIOA->CRH&=0XF0FFFFF0;//PA.8/14推挽输出
	GPIOA->CRH|=0X03000003; 
	GPIOA->ODR|=0X4100;    //上拉

	GPIOC->CRH&=0XFFFFFF00;
  	GPIOC->CRH|=0X00000083;//PC.8输出 ,PC9输入
	GPIOC->ODR|=1<<8;      //PC.8上拉   
	GPIOC->ODR|=1<<9; 	   //PC.9上拉	  

}




6 最后

???? 项目分享与指导: https://gitee.com/sinonfin/sharing

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

物联网项目分享 Stm32单片机的音乐播放器设计 - 物联网 嵌入式 的相关文章

  • 如何处理不稳定的自动化测试?

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 abluecolor 在解决这个问题之前 请停止编写更多测试 因为这将花费你较高的测试维护成本 你需要尽快行动起来对不稳定的原因进行深入研究 找到不稳定
  • HarmonyOS鸿蒙开发指南:容器组建 tabs开发指导

    目录 创建Tabs 设置Tabs方向 设置样式 显示页签索引 场景示例 创建Tabs 在pages index目录下的hml文件中创建一个Tabs组件 div class container div

随机推荐

  • 阿里巴巴大神发布的Java零基础笔记,实战教程多到手软,跪了

    前言 现值金九银十之际 是面试高峰季 很多学校开始校招 也是跳槽转行的最佳时机 根据数据显示 程序员是金九银十里最热门的行业 也是需求量最大的行业 但是程序员是个门槛低 但金字塔顶峰比较高的行业 意味着你的付出要比别人多才能拔尖 我们都知道
  • 987页的Java面试宝典,看完才发现,应届生求职也没那么难

    前言 现在已经九月底 金九银十也已经过去了一大半 很明显今年的面试季明显不如往年火热 对于求职者来说 也更难了一些 马上迎来国庆节 假期一过 十月份又过去了三分之一 综合来看今年确实不是面试的最佳时期 不过趁今年所剩的时间来好好准备 明年的
  • 基于Java ssm美容院管理系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • 鸿蒙Ability开发-Stage模型下Ability的创建和使用

    创建Ability和Page页面 创建两个Ability EntryAbility DetailsAbility 其中EntryAbility是由工程默认创建的 这里我们只讲如何创建DetailsAbility 使用DevEco Studi
  • 基于Java ssm教资考前指导系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • Airtest常用API介绍

    2024软件测试面试刷题 这个小程序 永久刷题 靠它快速找到工作了 刷题APP的天花板 今天就继续给大家介绍一下Airtest框架常用的核心API用法 这也是熟悉使用Airtest框架的必备手册之一 一 官方文档 官方文档 https ai
  • 各大厂急招鸿蒙开发员,争抢鸿蒙工程师

    去年9月 余承东宣布鸿蒙原生应用全面启动 华为开始了全面抛弃安卓的进程 多家互联网公司也发布了鸿蒙OS的App开发工程师的岗位 开启了抢人大战 有的企业开出了近百万的年薪招聘鸿蒙OS工程师 而华为甚至为鸿蒙OS资深架构师开出了100万 16
  • 2024年一套超详细Java面试精华资料,让进大厂少走弯路

    在座的诸位有没有是自学Java的 有的话评论区给我扣个1看看 但凡自学过的同学都知道有多难 虽说现在互联网非常发达 不明白的上网一搜就有很多资料 不过大多质量不高 而且非常碎片化 实在很难梳理成一个可持续成长的体系 所以有了这篇文章 我结合
  • 基于Java ssm考研助手系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • OpenHarmony基于HDF简单驱动开发实例

    背景 OpenHarmony 3 0 LTS qemu small system demo liteos a qemu 添加配置 device qemu arm virt liteos a hdf config device info de
  • 蜜罐技术是指什么?

    特殊设计的安全措施 蜜罐技术 是一种特殊设计的安全措施 其主要目的是为了吸引并诱骗潜在的 网络攻击者 这种技术涉及布置诱饵主机 网络服务和信息 旨在引诱攻击者在不知情的情况下对其发起攻击 一旦攻击发生 蜜罐便能够捕获和分析攻击者的行为 从而
  • Python采集猎聘网站招聘数据内容,看看现在职位风向

    嗨喽 大家好呀 这里是爱看美女的茜茜呐 环境使用 Python 3 10 Pycharm 模块使用 第三方模块 需安装 requests gt pip install requests pandas gt pip install panda
  • 2024 年最新版 Java 面试题及答案整理(纯干货,超详细)

    程序员一步入中年 不知不觉便会被铺天盖地的 危机感 上身 曾经的那个少年已经不在 时间就是这样公平 就算你能发明 Java 语言 随着时间的推移 你注定还是要成为慢慢变蔫的茄子 缓缓变黑的葡萄 看着春招就要来临的消息 吓得我周末赶紧拿出了面
  • 基于ssm面向品牌会员的在线商城的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • 工程管理系统功能设计与实践:实现高效、透明的工程管理

    在现代化的工程项目管理中 一套功能全面 操作便捷的系统至关重要 本文将介绍一个基于Spring Cloud和Spring Boot技术的Java版工程项目管理系统 结合Vue和ElementUI实现前后端分离 该系统涵盖了项目管理 合同管理
  • Java面试资料合集(24年目前最全整理面试跳槽必备)

    有了他们闭着眼睛也能找到工作 这段时间不是正好到了金三银四的季节了嘛 我司前段时间在整体环境不是很景气的大前提下也是招到了很多的开发小伙伴 听到开发组的组长说这批进来的一些新人还算是很优秀的 本来我心里的小算盘是 这样后面再给他们提一些需求
  • 事件委托Tab栏切换

  • 基于Java ssm健身国际俱乐部系统的设计与实现

    一 技术介绍 Java语言 SSM框架 SpringBoot框架 JSP页面 Mysql数据库 IDEA Eclipse开发 有需要的同学 源代码和配套文档领取 加文章最下方的名片哦 二 资料介绍 完整源代码 前后端源代码 SQL脚本 配套
  • 史上最全的中高级Java工程师面试题汇总有哪些?

    你有面试机会了吗 近期 肯定有很多小伙伴 投出去的简历HR基本上都是已读不回 甚至都没有任何回复 或者平台默认筛选 你的简历HR根本就看不到 即使有些小伙伴简历通过 收到面试邀请了 结果被通知不用面试了 还有些小伙伴 有面试机会了 甚至已经
  • 物联网项目分享 Stm32单片机的音乐播放器设计 - 物联网 嵌入式

    文章目录 0 前言 1 简介 2 主要器件 3 实现效果 4 设计原理 5 部分核心代码 6 最后 0 前言 这两年开始毕业设计和毕业答辩的要求和难度不断提升 传统的毕设题目缺少创新和亮点 往往达不到毕业答辩的要求 这两年不断有学弟学妹告诉