6.1、存储模块
存储模块使用的是P25Q32H,封装USON3*2,引脚定义如下所示。

讯享网
具体配置如下所示

该芯片的驱动程序和W25QXX系列基本一致,移植于之前的W25Q128驱动,主要内容几乎没变化。
#ifndef __SPI_FLASH__H #define __SPI_FLASH__H #include "spi.h" typedef enum {
SPI_FLASH_OK = 0, SPI_FLAHS_BUSY = 1, SPI_FLASH_TIMEOUT = 2, SPI_FLASH_ERR = 3, SPI_FLASH_UNKNOW }spi_flash_status_t; #define P25Q32H_Enable() HAL_GPIO_WritePin(F_CS_GPIO_Port, F_CS_Pin, GPIO_PIN_RESET) #define P25Q32H_Disable() HAL_GPIO_WritePin(F_CS_GPIO_Port, F_CS_Pin, GPIO_PIN_SET) #define PRINTF_DEBUG rt_kprintf #define P25Q32H_REMS 0x8515 #define P25Q32H_RDID 0x #define P25Q32H_FLASH_SIZE (P25Q32H_SECTOR_SIZE*64) //4MB #define P25Q32H_SECTOR_SIZE (P25Q32H_SUBSECTOR_SIZE*16) #define P25Q32H_SUBSECTOR_SIZE (4096) #define P25Q32H_PAGE_SIZE (256) #define P25Q32H_PAGE_ERASE 0X81 #define P25Q32H_SECTOR_ERASE 0X20 #define P25Q32H_BLOCK_32K_ERASE 0X52 #define P25Q32H_BLOCK_64K_ERASE 0XD8 #define P25Q32H_CHIP_ERASE 0X60 #define P25Q32H_READ_BYTE 0X03 #define P25Q32H_READ_QUICK_BYTE 0X0B #define P25Q32H_WRITE_PGAE_PROGRAM 0X02 #define P25Q32H_WRITE_ENABLE 0X06 #define P25Q32H_WRITE_DISABLE 0X04 #define P25Q32H_READ_STATU_REG 0X05 #define P25Q32H_READ_CONFIG_REG 0X35 #define P25Q32H_WRITE_STATU_RES 0X01 #define P25Q32H_WRITE_CONFIG_RES 0X11 #define P25Q32H_RESET_ENABLE 0X66 #define P25Q32H_RESET 0X99 #define P25Q32H_READ_DEV_ID 0X9F #define P25Q32H_READ_EMS_ID 0X90 #define P25Q32H_DEEP_POWER_DOWN 0XB9 #define P25Q32H_RELEASE_PWOER_DOWN 0XAB #define SR_WIP_BUSY_BIT (0X0001) #define SR_WEL_ENABLE_BIT (0X0002) #define SR_BLOCK1_4_ENABLE_BIT (0X007C) #define SR_SRP0_1_ENABLE_BIT (0X0180) #define SR_QUAD_SPI_ENABLE_BIT (0X0200) #define SR_SUS2_BIT (0X0400) #define SR_LB1_3_BIT (0X3800) #define SR_CMP_BIT (0X4000) #define SR_SUS1_BIT (0X8000) uint8_t BSP_P25Q30H_Init(void); void BSP_P25Q32H_Write(uint8_t* _p_buff,uint32_t _ui_addr,uint16_t _us_num); uint8_t BSP_P25Q32H_Read(uint8_t *_p_buff,uint32_t _uc_addr,uint32_t _uc_num); void BSP_P25Q32H_EraseSector(uint32_t _ui_addr); void BSP_P25Q32H_EarseChip(void); void BSP_P25Q32H_PowerDown(void) ; void BSP_P25Q32H_WAKEUP(void) ; void BSP_P25Q32H_TestProcess(void); #endif
讯享网
讯享网#include "spi_flash.h" #define DUMMY_BYTE 0xFF uint8_t SPI_FLASH_ReadWriteByte(uint8_t _uc_byte) {
uint8_t uc_read,uc_send=_uc_byte; if (HAL_SPI_TransmitReceive(&hspi2,&uc_send,&uc_read,1,100)!=HAL_OK) uc_read = 0X55; return uc_read; } uint32_t BSP_P25Q30H_ReadDevID(void) {
uint32_t ui_temp = 0; P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_READ_DEV_ID);//发送读取ID命令 ui_temp|=SPI_FLASH_ReadWriteByte(DUMMY_BYTE)<<16; ui_temp|=SPI_FLASH_ReadWriteByte(DUMMY_BYTE)<<8; ui_temp|=SPI_FLASH_ReadWriteByte(DUMMY_BYTE); P25Q32H_Disable(); return ui_temp; } uint32_t BSP_P25Q30H_ReadID(void) {
uint32_t ui_temp = 0; P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_READ_EMS_ID);//发送读取ID命令 SPI_FLASH_ReadWriteByte(0); SPI_FLASH_ReadWriteByte(0); SPI_FLASH_ReadWriteByte(0); ui_temp |= SPI_FLASH_ReadWriteByte(DUMMY_BYTE)<<8; ui_temp |= SPI_FLASH_ReadWriteByte(DUMMY_BYTE); P25Q32H_Disable(); return ui_temp; } uint32_t P25Q30H_ID = 0; uint8_t BSP_P25Q30H_Init(void) {
spi_flash_status_t res = SPI_FLASH_OK; P25Q30H_ID = BSP_P25Q30H_ReadID(); if(P25Q30H_ID != P25Q32H_REMS) {
res = SPI_FLASH_ERR; } P25Q30H_ID = BSP_P25Q30H_ReadDevID(); if(P25Q30H_ID != P25Q32H_RDID) {
res = SPI_FLASH_ERR; } else {
res = SPI_FLASH_OK; } return res; } /* BIT0: wip 1:正在操作 BIT1: WEL 1:写保护 BIT2-6: BP0_BP4 块保护 BIT7-8: SRP0_1 状态寄存器保护 BIT9: QE quad spi 使能位 BIT10: SUS2 program suspend 将会把该位置1(only read) BIT11-13:LB1-3 OTP区相关 BIT14: CMP BIT15: SUS1 erase_suspend 将会把该位置1(only read) */ uint16_t BSP_P25Q32H_ReadSR(void) {
uint16_t us_byte=0; P25Q32H_Enable(); //使能器件 SPI_FLASH_ReadWriteByte(P25Q32H_READ_STATU_REG); //发送读取状态寄存器命令 us_byte |= SPI_FLASH_ReadWriteByte(0Xff); //读取一个字节 P25Q32H_Disable(); //取消片选 return us_byte; } uint8_t BSP_P25Q32H_WaitBusy(void) {
return (BSP_P25Q32H_ReadSR()&0X01); } uint8_t BSP_P25Q32H_WriteSR(uint8_t _uc_reg) {
return 0; } uint8_t BSP_P25Q32H_WriteEnable(void) {
P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_WRITE_ENABLE); P25Q32H_Disable(); return 0; } uint8_t BSP_P25Q32H_WriteDisable(void) {
P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_WRITE_DISABLE); P25Q32H_Disable(); return 0; } void BSP_P25Q32H_EraseSector(uint32_t _ui_addr) {
//监视falsh擦除情况,测试用 // printf("fe:%x\r\n",Dst_Addr); _ui_addr*=P25Q32H_SUBSECTOR_SIZE; BSP_P25Q32H_WriteEnable(); //SET WEL BSP_P25Q32H_WaitBusy(); P25Q32H_Enable(); //使能器件 SPI_FLASH_ReadWriteByte(P25Q32H_SECTOR_ERASE); //发送扇区擦除指令 SPI_FLASH_ReadWriteByte((uint8_t)((_ui_addr)>>16)); //发送24bit地址 SPI_FLASH_ReadWriteByte((uint8_t)((_ui_addr)>>8)); SPI_FLASH_ReadWriteByte((uint8_t)_ui_addr); P25Q32H_Disable(); //取消片选 BSP_P25Q32H_WaitBusy(); //等待擦除完成 } uint8_t BSP_P25Q32H_Read(uint8_t *_p_buff,uint32_t _uc_addr,uint32_t _uc_num) {
uint16_t i = 0; spi_flash_status_t res = SPI_FLASH_OK; P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_READ_BYTE); SPI_FLASH_ReadWriteByte((uint8_t)(_uc_addr >> 16)); SPI_FLASH_ReadWriteByte((uint8_t)(_uc_addr >> 8)); SPI_FLASH_ReadWriteByte((uint8_t)(_uc_addr >> 0)); for(i=0;i<_uc_num;i++) {
_p_buff[i]=SPI_FLASH_ReadWriteByte(DUMMY_BYTE); //循环读数 } P25Q32H_Disable(); return res; } uint8_t BSP_P25Q32H_WritePage(uint8_t *_p_buff,uint32_t _uc_addr,uint32_t _uc_num) {
uint16_t i = 0; spi_flash_status_t res = SPI_FLASH_OK; BSP_P25Q32H_WriteEnable(); P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_WRITE_PGAE_PROGRAM); SPI_FLASH_ReadWriteByte((uint8_t)((_uc_addr&0XFF0000)>>16)); SPI_FLASH_ReadWriteByte((uint8_t)((_uc_addr&0X00FF00)>>8)); SPI_FLASH_ReadWriteByte((uint8_t)((_uc_addr&0X0000FF)>>0)); for(i=0;i<_uc_num;i++) {
SPI_FLASH_ReadWriteByte(_p_buff[i]); } P25Q32H_Disable(); BSP_P25Q32H_WaitBusy(); return res; } void BSP_P25Q32H_WriteNoCheck(uint8_t* _p_buff,uint32_t _ui_addr,uint16_t _us_num) {
uint16_t pageremain; pageremain = P25Q32H_PAGE_SIZE - _ui_addr % P25Q32H_PAGE_SIZE; if(_us_num<=pageremain) pageremain=_us_num; while(1) {
BSP_P25Q32H_WritePage(_p_buff,_ui_addr,pageremain); if(_us_num==pageremain)break; //写入结束了 else //NumByteToWrite>pageremain {
_p_buff+=pageremain; _ui_addr+=pageremain; _us_num-=pageremain; //减去已经写入了的字节数 if(_us_num > P25Q32H_PAGE_SIZE) pageremain = P25Q32H_PAGE_SIZE; //一次可以写入256个字节 else pageremain = _us_num; //不够256个字节了 } } } uint8_t BSP_P25Q32H_BUFFER[P25Q32H_SUBSECTOR_SIZE]; void BSP_P25Q32H_Write(uint8_t* _p_buff,uint32_t _ui_addr,uint16_t _us_num) {
uint32_t secpos; uint16_t secoff; uint16_t secremain; uint16_t i; uint8_t * p_buf; p_buf=BSP_P25Q32H_BUFFER; secpos = _ui_addr / P25Q32H_SUBSECTOR_SIZE;//扇区地址 secoff = _ui_addr % P25Q32H_SUBSECTOR_SIZE;//在扇区内的偏移 secremain = P25Q32H_SUBSECTOR_SIZE - secoff;//扇区剩余空间大小 if(_us_num<=secremain)secremain=_us_num;//不大于4096个字节 while(1) {
BSP_P25Q32H_Read(p_buf,secpos*P25Q32H_SUBSECTOR_SIZE,P25Q32H_SUBSECTOR_SIZE);//读出整个扇区的内容 for(i=0;i<secremain;i++)//校验数据 {
if(p_buf[secoff+i]!=0XFF)break;//需要擦除 } if(i<secremain)//需要擦除 {
BSP_P25Q32H_EraseSector(secpos); //擦除这个扇区 for(i=0;i<secremain;i++) //复制 {
p_buf[i+secoff]=_p_buff[i]; } BSP_P25Q32H_WriteNoCheck(p_buf,secpos*P25Q32H_SUBSECTOR_SIZE,P25Q32H_SUBSECTOR_SIZE);//写入整个扇区 }else BSP_P25Q32H_WriteNoCheck(_p_buff,_ui_addr,secremain);//写已经擦除了的,直接写入扇区剩余区间. if(_us_num==secremain)break;//写入结束了 else//写入未结束 {
secpos++;//扇区地址增1 secoff=0;//偏移位置为0 _p_buff+=secremain; //指针偏移 _ui_addr+=secremain; //写地址偏移 _us_num-=secremain; //字节数递减 if(_us_num>4096)secremain=4096;//下一个扇区还是写不完 else secremain=_us_num; //下一个扇区可以写完了 } }; } void BSP_P25Q32H_EarseChip(void) {
BSP_P25Q32H_WriteEnable(); //SET WEL BSP_P25Q32H_WaitBusy(); P25Q32H_Enable(); SPI_FLASH_ReadWriteByte(P25Q32H_CHIP_ERASE); //发送片擦除命令 P25Q32H_Disable(); BSP_P25Q32H_WaitBusy(); //等待芯片擦除结束 } //进入掉电模式 void BSP_P25Q32H_PowerDown(void) {
P25Q32H_Enable(); //使能器件 SPI_FLASH_ReadWriteByte(P25Q32H_DEEP_POWER_DOWN); //发送掉电命令 P25Q32H_Disable(); //取消片选 } //唤醒 void BSP_P25Q32H_WAKEUP(void) {
P25Q32H_Enable(); //使能器件 SPI_FLASH_ReadWriteByte(P25Q32H_RELEASE_PWOER_DOWN); // send W25X_PowerDown command 0xAB P25Q32H_Disable(); //取消片选 } void BSP_P25Q32H_TestProcess(void) {
// uint8_t res = SPI_FLASH_OK; // res = BSP_P25Q30H_Init(); // if(res == SPI_FLASH_OK) // {
// BSP_P25Q32H_Write(&w_buff[0],0,sizeof(w_buff)); //从倒数第100个地址处开始,写入SIZE长度的数据 // HAL_Delay(100); // BSP_P25Q32H_Read(&r_buff[0],0,100); // HAL_Delay(100); // } }
后续的存储线程只需要调用这里面的读写函数就可以了。比较简单,参考W25QXX系列驱动和本芯片datasheet即可。

6.2、按键模块

一共是7种触发按键的事件。其中,双击按键,长按时间都是通过修改文件内的宏定义修改时间的,但是
LONG_PRESS_HOLD这个事件的触发间隔确实写死的(一个button_ticks出发一次)。这不符合我的要求,于是将头文件内部宏定义修改为如下所示。
#define TICKS_INTERVAL 5 //ms //心跳间隔 #define DEBOUNCE_TICKS (20/TICKS_INTERVAL) //MAX 8次 40ms 滤波时间 #define SHORT_TICKS (200 /TICKS_INTERVAL) //双击的时间间隔 #define LONG_TICKS (500 /TICKS_INTERVAL) //长按的时间判断 #define LONG_HOLD_EVENT (200/TICKS_INTERVAL) //触发长按后,多长时间触发一次LONG_PRESS_HOLD事件
之后在
button_handler()函数添加如下内容。
到这对于
LONG_PRESS_HOLD事件的修改就做完了。
到这对于
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/121735.html