Ant_V1一期工程

简介 我做了个什么:我做的是一个带屏幕mp3(没有外放只有耳机接口),入这个坑的时候呢想的不是太多,我只是想要一个可以编程的mp3所以直接就收集材料开始制作了。坑是入了,所以这里呢有些东西我希望分享出来能够对大家有用。

概述:

         

         这个工程准确的时间是从2019 8初开始的,中间很多事耽搁,一方面是做这件事本身不太重视吧,感觉简单,可能只是做一个板子,但是硬件的事谁知道呢(就像我有同学说,昨天刚还好的代码今天就不行了),我遇见的大多数情况,其实是自己不用心所致,所以呢我希望把这些经验分享出来,如果对你有触动,想必也会减少你的损失。

         由于这里时间有限,有些工作做得不是很细致,像是原件的选用,某些驱动的移别人写的比较乱这里就也就直接拿来用了。另外呢由于每个人的习惯不同,代码的风格也会有较大的差异所以,整体的代码风格可能不是很一致,这里希望读者能够理解。

         首先看一下我初始时候的构想:

         大概的形式如下

image.png

其实这个和最终的实物的排版方式已经很接近了,除了没有加电源模块,lcd也最终放弃了横屏,由于驱动的管脚有限所以就没有选用需要驱动管脚较多的横屏LCD,而是选用SPILCD,这样省下了不少的管脚可以利用(最终貌似没有用到),mcu也放弃st32f103c8t664K flash)专用引脚数更多的身体stm32f103rgt61M flash),储存更大便于集成FAT,和更多的调试框架(直接用正点原子的usmart之类的)。

 

外置接口:

         Uart SWD 耳机口 microusb(或可以用于USB通信) microSD

集成的功能如下

image.png

外设最终没有集成FM和蓝牙,相信以后的工程会集成更多的功能。

         起初我的设想就是直接开源,可能大家对整个项目感兴趣很少,但是,pcb原理图,或者是驱动代码等总会对大家有帮助你的。

原件的选择

         由于这里还是在验证阶段,原件选用的原则就比较的随意了,不用考虑原理图,pcb布线事(最后发现这里是一个大坑),这里其实主要的选择是LCD的尺寸,以及解码芯片的选择,由于是市场上有很多的解码芯片,有的甚至直接插上内存卡都可以播放歌曲例如BY8001-SSOP24(淘宝有卖),但是这里希望能够编程,并且获得更多的功能,所以这些芯片是放弃的,另外屏幕的尺寸选择主要兼顾显示和性能,象stm32f1系列主频不是很高的,越大的屏幕刷新一次的时间就越长,这样对其他硬件的影响就比较大。最终选择如下:

image.png

image.png

(以上也算的打广告了了吧,关键是我没有网店啊)

LCD使用2寸屏(178*200)主要是2.4寸有点大,1.8又感觉很小折中之举吧。

解码芯片使用VS1053B:这个可以直接给音频数据然后直接播放直接减轻了mcu的压力。

 

关于flash我不知道很早的的时候买了两个W25Q128所以这直接就选用了(还是16脚的),虽然有点占地方但是驱动简单就直接上了。

 

管脚的分配

         这次的的管脚的分配是根据最小系统板的管脚进行配置的(之后发现真傻,只是方便了初期的验证),最小系统板的资源分配如下:

image.png

 

管脚分配如下:

image.png


验证板将会在电路模拟中展开。

电路的模拟

         初期只是为了验证驱动能力所以还是在stm32f103c8t6上做验证,可能你会问这么简单还要做验证?关键是我真的没有经验,不论是电源的选用还是管脚的驱动的问题,最终验证还是发现了一些管脚驱动能力的问题,所以在管脚分配的时候标记出来,防止画原理图的时候分配管脚出问题。下面是验证板的样子:

image.png

 

由于是手动焊接的样子确实有点挫,

 image.png

驱动实现

         这里就比较硬核了直接上代码吧!

         这里主要有三个外设是以前没有弄过的包括MicroSD W25Q128和按键(这里比较简单没有硬件的防抖处理)

 

MicroSDTF卡)的驱动代码:

MicroSD.h文件代码如下

 

#ifndef __SDIO_SDCARD_H

#define __SDIO_SDCARD_H

#include "sys.h"

 

char SD_Init(void);

char WriteSectorToMicroSD(long addr,char *buff);

char ReadSectorFromMicroSD(long sector,char *buffer);

 

#endif

 

 

MicroSD.c文件代码如下

#include "MicroSD.h"

#include "usart.h"    

#include "SPI.h"

//#include "sys.h"

/*

此处重新定义CS的脚

只需要使用一个CS引脚定义

PB0 CS

PA5 SCK

PA6 MISO

PA7 MOSI

SPI模式初始化完成以后就不需要crc校验了

 

计划如下:

已经完成初始化

1.需要get到一些东西例如是CID之类的信息

2.实现read write的方法

注意:一定要注意时序以及返回信息

*/

#define MicroSD_CS_SET GPIO_SetBits(GPIOB,GPIO_Pin_0)

#define MicroSD_CS_RESET GPIO_ResetBits(GPIOB,GPIO_Pin_0)

char MicroSDDataBuff[512]={0};//一个扇区的大小

char SentCommandToMicroSD(char cmd,int data,char crc)

{

         char result=0,times=0;

        

         MicroSD_CS_SET;//禁止SD卡片选 同步时钟

         SPI1_ReadWriteByte(0xff);  

         MicroSD_CS_RESET;//开始传输

         SPI1_ReadWriteByte(cmd);

         for(times=0;times<4;times++)   

         {   

      SPI1_ReadWriteByte((data>>24)&0xff);

                          data<<=8;

  }

  SPI1_ReadWriteByte(crc);

         SPI1_ReadWriteByte(0xff); //八个时钟

         times=0;

         do   

         {  //读取后8  

                  result = SPI1_ReadWriteByte(0xFF);  

                  times++;  

         }

         while((result==0xff)&&(times<200));

         return result;

}

//初始化化不是很稳定也就是说明传输数据可能不是很稳定

char SD_Init(void)

{

         char i,temp=0;

         //char CMD[] = {0x40,0x00,0x00,0x00,0x00,0x95};

         int retry=0;

         GPIO_InitTypeDef GPIO_InitStructure;

         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能

         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;

         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //PB0

         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

         GPIO_Init(GPIOB, &GPIO_InitStructure);//初始化GPIOB0

         GPIO_SetBits(GPIOB,GPIO_Pin_0);

         //初始化SPI1

         SPI1_Init();

         MicroSD_CS_SET;

         //发送至少74个时钟信号

         for (i=0;i<0x2f;i++){SPI1_ReadWriteByte(0xff);}

         //为了能够成功写入CMD0,在这里写200

         do 

         {  

                  temp=SentCommandToMicroSD(0x40,0,0x95);  

                  retry++;  

                  if(retry>800)

                  { //超过200  

                  //CMD0 Error!         return(INIT_CMD0_ERROR);

                          printf("Init MicroSD CMD0 Error!!!Back:%d\n\n",temp);

                          return 0;

                  }  

         }   

         while(temp!=0x01); //回应01h,停止写入

         printf("Reset MicroSD successfully!!!times:%d\n\n",retry);

         //发送CMD1SD

         retry=0;  

         do 

         {

                  //为了能成功写入CMD1,100  

                  temp=SentCommandToMicroSD(0x41,0,0xff);

                  retry++;  

                  if(retry>800)   

                  {

                          //超过100

                          printf("Init 1MicroSD CMD1 Error!!!Back:%d\n\n",temp);

                          return 0;

                  }

         }

         while(temp!=0x00);//回应00h停止写入   

         MicroSD_CS_SET;  //片选无效

         printf("Init MicroSD sent CMD1 successfully!!!times:%d\n\n",retry);

        

         //更换更快的SPI速率

         SPI1_SetSpeed(SPI_BaudRatePrescaler_4);

        

         return 0;

}

 

char WriteSectorToMicroSD(long addr,char *buff)

{    

   int tmp,retry;  

   unsigned int i;  

   addr = addr << 9; //addr = addr * 512

   //写命令24SD卡中去  

   retry=0;  

   do 

   {  //为了可靠写入,写100  

      tmp=SentCommandToMicroSD(0x58,addr,0xff);  

      retry++;  

      if(retry>800)   

      {   

                                   printf("Write CMD58 Error!!!\n\r");

        return 1; //send commamd Error!  

      }  

   }  

   while(tmp!=0);

          

   //在写之前先产生100个时钟信号  

   for (i=0;i<100;i++)  

   {  

      SPI1_ReadWriteByte(0xff);  

   }  

   //写入开始字节  

   SPI1_ReadWriteByte(0xfe);   

   

   //现在可以写入512个字节   

   for (i=0;i<512;i++)  

   {  

      SPI1_ReadWriteByte(*buff);

                          buff++;

   }

   //CRC-Byte   

   SPI1_ReadWriteByte(0xFF); //Dummy CRC  

   SPI1_ReadWriteByte(0xFF); //CRC Code

          

   tmp=SPI1_ReadWriteByte(0xff);   // read response  

   if((tmp & 0x1F)!=0x05) // 写入的512个字节是未被接受  

   {  

     MicroSD_CS_SET;

                   printf("Write data didn't accept by MicroSD\n\r");

     return 1; //Error!  

   }  

   //等到SD卡不忙为止  

          //因为数据被接受后,SD卡在向储存阵列中编程数据  

   while (SPI1_ReadWriteByte(0xff)!=0xff);

          

   //禁止SD 写入成功

   MicroSD_CS_SET;

   return 0;  

}

 

char ReadSectorFromMicroSD(long sector,char *buffer)  

{    

   int retry;  

   //命令16 

         int times=0;

  //unsigned char CMD[] = {0x51,0x00,0x00,0x00,0x00,0xFF};   

  unsigned char temp;  

  

   //地址变换   由逻辑块地址转为字节地址  

   sector = sector << 9; //sector = sector * 512

   //将命令16写入SD  

   retry=0;  

   do 

   {  //为了保证写入命令  一共写100  

      temp=SentCommandToMicroSD(0x51,sector,0xff);  

      retry++;  

      if(retry>800)   

      {  

                                   printf("Read sector from MicroSD is failed!!\n\r");

        return 1; //block write Error!  

      }  

   }  

   while(temp!=0);   

        

   //Read Start Byte form MMC/SD-Card (FEh/Start Byte)  

   //Now data is ready,you can read it out.  

  while (SPI1_ReadWriteByte(0xff) != 0xfe);

         for(times=0;times<512;times++)

         {

                  MicroSDDataBuff[times]=SPI1_ReadWriteByte(0xff);

         }

         //禁止SD 读出完成

   MicroSD_CS_SET;

         return 0;

}

 

下面是W25Q的驱动代码

由于是直接用正点原子的例程侵权删(仅供学习使用)

我就直接做了一下管脚与例程的管脚兼容

w25qxx.h内容如下

#ifndef __FLASH_H

#define __FLASH_H                             

#include "sys.h"

//////////////////////////////////////////////////////////////////////////////////      

//本程序只供学习使用,未经作者许可,不得用于其它任何用途

//ALIENTEK战舰STM32开发板

//W25Q64 代码      

//正点原子@ALIENTEK

//技术论坛:www.openedv.com

//修改日期:2012/9/9

//版本:V1.0

//版权所有,盗版必究。

//Copyright(C) 广州市星翼电子科技有限公司 2009-2019

//All rights reserved                                                                               

//////////////////////////////////////////////////////////////////////////////////

          

//W25X系列/Q系列芯片列表      

//W25Q80  ID  0XEF13

//W25Q16  ID  0XEF14

//W25Q32  ID  0XEF15

//W25Q64  ID  0XEF16      

//W25Q128 ID  0XEF17       

#define W25Q80   0XEF13  

#define W25Q16   0XEF14

#define W25Q32   0XEF15

#define W25Q64   0XEF16

#define W25Q128  0XEF17

extern u16 W25QXX_TYPE;                                       //定义W25QXX芯片型号               

 

#define    W25QXX_CS           PBout(12)               //W25QXX的片选信号

                                    

////////////////////////////////////////////////////////////////////////////

 

//指令表

#define W25X_WriteEnable           0x06

#define W25X_WriteDisable          0x04

#define W25X_ReadStatusReg               0x05

#define W25X_WriteStatusReg              0x01

#define W25X_ReadData                        0x03

#define W25X_FastReadData                 0x0B

#define W25X_FastReadDual                 0x3B

#define W25X_PageProgram                  0x02

#define W25X_BlockErase                      0xD8

#define W25X_SectorErase            0x20

#define W25X_ChipErase                        0xC7

#define W25X_PowerDown                    0xB9

#define W25X_ReleasePowerDown      0xAB

#define W25X_DeviceID                          0xAB

#define W25X_ManufactDeviceID        0x90

#define W25X_JedecDeviceID                0x9F

 

void W25QXX_Init(void);

u16  W25QXX_ReadID(void);                          //读取FLASH ID

u8     W25QXX_ReadSR(void);                       //读取状态寄存器

void W25QXX_Write_SR(u8 sr);                    //写状态寄存器

void W25QXX_Write_Enable(void);             //写使能

void W25QXX_Write_Disable(void);               //写保护

void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);

void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead);   //读取flash

void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite);//写入flash

void W25QXX_Erase_Chip(void);            //整片擦除

void W25QXX_Erase_Sector(u32 Dst_Addr);        //扇区擦除

void W25QXX_Wait_Busy(void);                //等待空闲

void W25QXX_PowerDown(void);                 //进入掉电模式

void W25QXX_WAKEUP(void);                                 //唤醒

#endif

 

w25qxx.c文件内容如下

#include "w25qxx.h"

#include "SPI.h"

#include "delay.h"

#include "usart.h"

//////////////////////////////////////////////////////////////////////////////////      

//本程序只供学习使用,未经作者许可,不得用于其它任何用途

//ALIENTEK精英STM32开发板

//W25Q64 代码      

//正点原子@ALIENTEK

//技术论坛:www.openedv.com

//修改日期:2012/9/9

//版本:V1.0

//版权所有,盗版必究。

//Copyright(C) 广州市星翼电子科技有限公司 2009-2019

//All rights reserved                                                                               

//////////////////////////////////////////////////////////////////////////////////

 

 

u16 W25QXX_TYPE=W25Q128;     //默认是W25Q128

 

//4Kbytes为一个Sector

//16个扇区为1Block

//W25Q128

//容量为16M字节,共有128Block,4096Sector

                                                                                                                   

//初始化SPI FLASHIO

void W25QXX_Init(void)

{      

  GPIO_InitTypeDef GPIO_InitStructure;

         RCC_APB2PeriphClockCmd(  RCC_APB2Periph_GPIOB, ENABLE );//PORTB时钟使能

 

         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;  // PB12 推挽

        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //推挽输出

         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

        GPIO_Init(GPIOB, &GPIO_InitStructure);

        GPIO_SetBits(GPIOB,GPIO_Pin_12);

 

   W25QXX_CS=1;                                   //SPI FLASH不选中

         //SPI2_Init();                 //初始化SPI

         SPI2_SetSpeed(SPI_BaudRatePrescaler_2);//设置为18M时钟,高速模式

         W25QXX_TYPE=W25QXX_ReadID();//读取FLASH ID.

         printf("your W25Q type:%d!!!\n\r",W25QXX_TYPE);  

 

 

//读取W25QXX的状态寄存器

//BIT7  6   5   4   3   2   1   0

//SPR   RV  TB BP2 BP1 BP0 WEL BUSY

//SPR:默认0,状态寄存器保护位,配合WP使用

//TB,BP2,BP1,BP0:FLASH区域写保护设置

//WEL:写使能锁定

//BUSY:忙标记位(1,;0,空闲)

//默认:0x00

u8 W25QXX_ReadSR(void)  

         u8 byte=0;  

         W25QXX_CS=0;                            //使能器件  

         SPI2_ReadWriteByte(W25X_ReadStatusReg); //发送读取状态寄存器命令   

         byte=SPI2_ReadWriteByte(0Xff);          //读取一个字节 

         W25QXX_CS=1;                            //取消片选    

         return byte;  

}

//W25QXX状态寄存器

//只有SPR,TB,BP2,BP1,BP0(bit 7,5,4,3,2)可以写!!!

void W25QXX_Write_SR(u8 sr)  

{  

         W25QXX_CS=0;                            //使能器件  

         SPI2_ReadWriteByte(W25X_WriteStatusReg);//发送写取状态寄存器命令   

         SPI2_ReadWriteByte(sr);                //写入一个字节 

         W25QXX_CS=1;                            //取消片选                  

}  

//W25QXX写使能

//WEL置位  

void W25QXX_Write_Enable(void)  

{

         W25QXX_CS=0;                           //使能器件  

    SPI2_ReadWriteByte(W25X_WriteEnable);          //发送写使能 

         W25QXX_CS=1;                                  //取消片选             

}

//W25QXX写禁止

//WEL清零 

void W25QXX_Write_Disable(void)  

         W25QXX_CS=0;                            //使能器件  

    SPI2_ReadWriteByte(W25X_WriteDisable);  //发送写禁止指令   

         W25QXX_CS=1;                            //取消片选                  

}              

//读取芯片ID

//返回值如下:                                    

//0XEF13,表示芯片型号为W25Q80 

//0XEF14,表示芯片型号为W25Q16    

//0XEF15,表示芯片型号为W25Q32 

//0XEF16,表示芯片型号为W25Q64

//0XEF17,表示芯片型号为W25Q128           

u16 W25QXX_ReadID(void)

{

         u16 Temp = 0;  

         W25QXX_CS=0;                                    

         SPI2_ReadWriteByte(0x90);//发送读取ID命令    

         SPI2_ReadWriteByte(0x00);              

         SPI2_ReadWriteByte(0x00);              

         SPI2_ReadWriteByte(0x00);                                      

         Temp|=SPI2_ReadWriteByte(0xFF)<<8; 

         Temp|=SPI2_ReadWriteByte(0xFF);        

         W25QXX_CS=1;                                    

         return Temp;

}                

//读取SPI FLASH 

//在指定地址开始读取指定长度的数据

//pBuffer:数据存储区

//ReadAddr:开始读取的地址(24bit)

//NumByteToRead:要读取的字节数(最大65535)

void W25QXX_Read(u8* pBuffer,u32 ReadAddr,u16 NumByteToRead)  

{

        u16 i;                                                                                       

         W25QXX_CS=0;                                 //使能器件  

    SPI2_ReadWriteByte(W25X_ReadData);             //发送读取命令  

    SPI2_ReadWriteByte((u8)((ReadAddr)>>16));     //发送24bit地址   

    SPI2_ReadWriteByte((u8)((ReadAddr)>>8));  

    SPI2_ReadWriteByte((u8)ReadAddr);  

    for(i=0;i<NumByteToRead;i++)

         {

        pBuffer[i]=SPI2_ReadWriteByte(0XFF);     //循环读数 

    }

         W25QXX_CS=1;                                                 

//SPI在一页(0~65535)内写入少于256个字节的数据

//在指定地址开始写入最大256字节的数据

//pBuffer:数据存储区

//WriteAddr:开始写入的地址(24bit)

//NumByteToWrite:要写入的字节数(最大256),该数不应该超过该页的剩余字节数!!!       

void W25QXX_Write_Page(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)

{

        u16 i; 

    W25QXX_Write_Enable();                           //SET WEL

         W25QXX_CS=0;                                 //使能器件  

    SPI2_ReadWriteByte(W25X_PageProgram);          //发送写页命令  

    SPI2_ReadWriteByte((u8)((WriteAddr)>>16));     //发送24bit地址   

    SPI2_ReadWriteByte((u8)((WriteAddr)>>8));  

    SPI2_ReadWriteByte((u8)WriteAddr);  

    for(i=0;i<NumByteToWrite;i++)SPI2_ReadWriteByte(pBuffer[i]);//循环写数 

         W25QXX_CS=1;                                 //取消片选

         W25QXX_Wait_Busy();                                                    //等待写入结束

}

//无检验写SPI FLASH

//必须确保所写的地址范围内的数据全部为0XFF,否则在非0XFF处写入的数据将失败!

//具有自动换页功能

//在指定地址开始写入指定长度的数据,但是要确保地址不越界!

//pBuffer:数据存储区

//WriteAddr:开始写入的地址(24bit)

//NumByteToWrite:要写入的字节数(最大65535)

//CHECK OK

void W25QXX_Write_NoCheck(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)  

{                                         

         u16 pageremain;      

         pageremain=256-WriteAddr%256; //单页剩余的字节数                       

         if(NumByteToWrite<=pageremain)pageremain=NumByteToWrite;//不大于256个字节

         while(1)

         {         

                  W25QXX_Write_Page(pBuffer,WriteAddr,pageremain);

                  if(NumByteToWrite==pageremain)break;//写入结束了

                 else //NumByteToWrite>pageremain

                  {

                          pBuffer+=pageremain;

                          WriteAddr+=pageremain;      

 

                          NumByteToWrite-=pageremain;                       //减去已经写入了的字节数

                          if(NumByteToWrite>256)pageremain=256; //一次可以写入256个字节

                          else pageremain=NumByteToWrite;      //不够256个字节了

                  }

         };          

}

//SPI FLASH 

//在指定地址开始写入指定长度的数据

//该函数带擦除操作!

//pBuffer:数据存储区

//WriteAddr:开始写入的地址(24bit)                                              

//NumByteToWrite:要写入的字节数(最大65535)  

u8 W25QXX_BUFFER[4096];           

void W25QXX_Write(u8* pBuffer,u32 WriteAddr,u16 NumByteToWrite)  

{

         u32 secpos;

         u16 secoff;

         u16 secremain;         

        u16 i;   

         u8 * W25QXX_BUF;         

     W25QXX_BUF=W25QXX_BUFFER;            

        secpos=WriteAddr/4096;//扇区地址 

         secoff=WriteAddr%4096;//在扇区内的偏移

         secremain=4096-secoff;//扇区剩余空间大小  

        //printf("ad:%X,nb:%X\r\n",WriteAddr,NumByteToWrite);//测试用

        if(NumByteToWrite<=secremain)secremain=NumByteToWrite;//不大于4096个字节

         while(1)

         {      

                  W25QXX_Read(W25QXX_BUF,secpos*4096,4096);//读出整个扇区的内容

                  for(i=0;i<secremain;i++)//校验数据

                  {

                          if(W25QXX_BUF[secoff+i]!=0XFF)break;//需要擦除           

                  }

                  if(i<secremain)//需要擦除

                  {

                          W25QXX_Erase_Sector(secpos);            //擦除这个扇区

                          for(i=0;i<secremain;i++)                       //复制

                          {

                                   W25QXX_BUF[i+secoff]=pBuffer[i];      

                          }

                          W25QXX_Write_NoCheck(W25QXX_BUF,secpos*4096,4096);//写入整个扇区  

 

                  }else W25QXX_Write_NoCheck(pBuffer,WriteAddr,secremain);//写已经擦除了的,直接写入扇区剩余区间.                                   

                  if(NumByteToWrite==secremain)break;//写入结束了

                  else//写入未结束

                  {

                          secpos++;//扇区地址增1

                          secoff=0;//偏移位置为0      

 

                       pBuffer+=secremain;                             //指针偏移

                          WriteAddr+=secremain;                           //写地址偏移           

                       NumByteToWrite-=secremain;                        //字节数递减

                          if(NumByteToWrite>4096)secremain=4096;//下一个扇区还是写不完

                          else secremain=NumByteToWrite;                 //下一个扇区可以写完了

                  }        

         };       

}

//擦除整个芯片              

//等待时间超长...

void W25QXX_Erase_Chip(void)  

{                                  

    W25QXX_Write_Enable();                            //SET WEL

    W25QXX_Wait_Busy();  

      W25QXX_CS=0;                                 //使能器件  

    SPI2_ReadWriteByte(W25X_ChipErase);              //发送片擦除命令 

         W25QXX_CS=1;                                 //取消片选             

         W25QXX_Wait_Busy();                                                //等待芯片擦除结束

}  

//擦除一个扇区

//Dst_Addr:扇区地址 根据实际容量设置

//擦除一个山区的最少时间:150ms

void W25QXX_Erase_Sector(u32 Dst_Addr)  

         //监视falsh擦除情况,测试用  

        printf("fe:%x\r\n",Dst_Addr);          

        Dst_Addr*=4096;

    W25QXX_Write_Enable();                           //SET WEL       

    W25QXX_Wait_Busy();  

      W25QXX_CS=0;                                 //使能器件  

    SPI2_ReadWriteByte(W25X_SectorErase);             //发送扇区擦除指令

    SPI2_ReadWriteByte((u8)((Dst_Addr)>>16));      //发送24bit地址   

    SPI2_ReadWriteByte((u8)((Dst_Addr)>>8));  

    SPI2_ReadWriteByte((u8)Dst_Addr); 

         W25QXX_CS=1;                                 //取消片选             

    W25QXX_Wait_Busy();                                                //等待擦除完成

//等待空闲

void W25QXX_Wait_Busy(void)  

{  

         while((W25QXX_ReadSR()&0x01)==0x01);                  // 等待BUSY位清空

//进入掉电模式

void W25QXX_PowerDown(void)  

{

      W25QXX_CS=0;                                          //使能器件  

    SPI2_ReadWriteByte(W25X_PowerDown);        //发送掉电命令 

         W25QXX_CS=1;                                 //取消片选             

    delay_us(3);                               //等待TPD 

}  

//唤醒

void W25QXX_WAKEUP(void)  

      W25QXX_CS=0;                                 //使能器件  

    SPI2_ReadWriteByte(W25X_ReleasePowerDown);     //  send W25X_PowerDown command 0xAB   

         W25QXX_CS=1;                                 //取消片选             

    delay_us(3);                              //等待TRES1

}  

 

 

Key按键的扫描程序如下:

Key.h文件

 

#ifndef             __KEY_H

#define             __KEY_H

#include "sys.h"

#define Key_WakeUp     0

#define Key_Back            1

#define Key_OK               2

#define Key_Menu          3

void KeyInit(void);

char GetKeyCilk(void);

 

#endif

 

Key.c文件

#include "Key.h"

void KeyInit(void)

{

         GPIO_InitTypeDef GPIO_InitStructure;

         RCC_APB2PeriphClockCmd(  RCC_APB2Periph_GPIOA, ENABLE );//PORTB时钟使能

         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2| GPIO_Pin_3;

         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;  //PB13/14/15复用推挽输出

         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

         GPIO_Init(GPIOA, &GPIO_InitStructure);

         GPIO_SetBits(GPIOA,GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3);//上拉

}

char GetKeyCilk()

{

         char keyValue=-1;

         if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_0)==0)

         {

                  keyValue=Key_WakeUp;

         }else if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_1)==0)

         {

                  keyValue=Key_Back;

         }else if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_2)==0)

         {

                  keyValue=Key_OK;

         }else if(GPIO_ReadInputDataBit(GPIOA,GPIO_Pin_3)==0)

         {

                  keyValue=Key_Menu;

         }

         return keyValue;

 

}

这里的代码可能不够全,有SPI UART 硬件延时Delay的实现这里由于篇幅是没有列出来的。或者你可以直接上github上直接clone我的工程

https://github.com/mrikelatefly/OpensourceMp3.git

Head文件夹下有相关代码。

 

总结:以上就是第一期工程的内容了,包含了管脚驱动,相关外设硬件的验证,这里换stm32f103rgt6也是由于这个验证发现的许多的问题,stm32f103c8t6是不够用的,而且后面也是有其他的打算所以直接在第二期工程创建原理图以及PCB的时候直接用的stm32f103rgt6


文章评论

Top