MCU:STM32F429ZIT6开发环境:STM32CubeMX+MDK5
(资料图)
外购了一个SPI接口的SD Card模块,想要实现SD卡存储数据的功能。
首先需要打开STM32CubeMX工具。输入开发板MCU对应型号,找到开发板对应封装的MCU型号,双击打开(图中第三)。
此时,双击完后会关闭此界面,然后打开一个新界面。
然后,我们开始基本配置。
现在我们选择一个LED作为系统LED,该步骤可以忽略,只是本人喜欢这样子。以硬件原理图的LD3为例子。
基本配置除了时钟树外,基本上已经配置好了。
现在配置时钟树
基本配置已经配置完,现在开始配置实验使用的内容。
配置USART1,重定向printf函数作为串口输出。
然后配置SPI1,作为驱动SD Card读写的接口。
然后配置文件系统,可以让文件的使用更方便。
现在配置按键,触发中断处理一些事情。
配置完成,完善工程,生成工程。
到此,STM32CubeMX工具的使用结束!可以发现在桌面已经生成了SDCard_rw工程。
使用MDK5打开SDCard_rw工程打开。点击魔法棒,勾选微库。选择对应的下载器,勾选下载完复位允许。USB线一端接开发板USB_Device,一端接PC。
现在可以开始实验了
在usart.c中重定向printf函数,并在usart.h中声明。
1 //重定向c库函数printf到串口DEBUG_USART,重定向后可使用printf函数2 int fputc(int ch, FILE *f)3 {4 HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 1000); 5 return (ch);6 }
在sdcard_write工程下创建UserCode文件夹,编写drive_spisd.c和drive_spisd.h。
然后在MDK5这里的SDCard_rw工程添加一个新文件夹UserCode,装入drive_spisd.c。并在魔法棒这里加入头文件路径。
drive_spisd.c如下
1 /* Includes ------------------------------------------------------------------*/ 2 #include "drive_spisd.h" 3 /* Private includes ----------------------------------------------------------*/ 4 #include "spi.h" 5 #include "ff.h" 6 #include "usart.h" 7 /* Private typedef -----------------------------------------------------------*/ 8 9 /* Private define ------------------------------------------------------------*/ 10 11 /* Private macro -------------------------------------------------------------*/ 12 13 /* Private variables ---------------------------------------------------------*/ 14 uint8_t test; 15 uint8_t SD_TYPE = 0x00; 16 MSD_CARDINFO SD0_CardInfo; 17 char SD_FileName[] = "hello.txt"; 18 /* Private function prototypes -----------------------------------------------*/ 19 static int SD_SendCMD(uint8_t cmd, uint32_t arg, uint8_t crc); 20 static uint8_t SD_ReceiveData(uint8_t *data, uint16_t len); 21 static uint8_t SD_SendBlock(uint8_t*buf, uint8_t cmd); 22 /* Private user code ---------------------------------------------------------*/ 23 24 /** 25 * @brief SPI_CS片选 26 * @note None 27 * @retval None 28 */ 29 void SPISD_CS(uint8_t p) 30 { 31 HAL_GPIO_WritePin(SPI1_CS_GPIO_Port, SPI1_CS_Pin, (p==0)?GPIO_PIN_SET:GPIO_PIN_RESET); 32 } 33 34 /** 35 * @brief 发送命令(CMD0~CMD63),发完释放 36 * @note 命令格式:0+传输标志(1-命令、0-响应)+CONTENT(6+32)+7CRC+1 37 * @retval None 38 */ 39 static int SD_SendCMD(uint8_t cmd, uint32_t arg, uint8_t crc) 40 { 41 uint8_t r1,retry; 42 43 SPISD_CS(0); //取消片选 44 HAL_Delay(20); 45 SPISD_CS(1); //选通 46 47 //SD卡的SPI通信协议规定,每个命令操作之前都需要发送至少8个时钟周期 48 do 49 { 50 retry = SPI_ReadWrite(0xFF); 51 }while(retry != 0xFF); 52 53 SPI_ReadWrite(cmd | 0x40); 54 SPI_ReadWrite(arg >> 24); 55 SPI_ReadWrite(arg >> 16); 56 SPI_ReadWrite(arg >> 8); 57 SPI_ReadWrite(arg); 58 SPI_ReadWrite(crc); 59 60 if(cmd == CMD12) 61 SPI_ReadWrite(0xFF); 62 do 63 { 64 r1 = SPI_ReadWrite(0xFF); 65 }while(r1 & 0x80); 66 67 return r1; 68 } 69 70 //SD卡初始化 71 uint8_t SD_Init(void) 72 { 73 uint8_t r1,i; 74 uint8_t buff[6] = {0}; 75 uint16_t retry; 76 77 SPI_SetSpeed(SPI_BAUDRATEPRESCALER_256); 78 SPISD_CS(0); 79 for(retry=0;retry<10;retry++) 80 SPI_ReadWrite(0xFF); 81 82 //SD卡进入IDLE状态 83 do 84 { 85 r1 = SD_SendCMD(CMD0 ,0, 0x95); 86 }while(r1 != 0x01); 87 88 //查看SD卡的类型 89 SD_TYPE = 0; 90 r1 = SD_SendCMD(CMD8, 0x1AA, 0x87); 91 if(r1 == 0x01) 92 { 93 for(i=0;i<4;i++) 94 buff[i] = SPI_ReadWrite(0xFF); //Get trailing return value of R7 resp 95 if( buff[2]==0X01 && buff[3]==0XAA ) //卡是否支持2.7~3.6V 96 { 97 retry = 0XFFFE; 98 do 99 { 100 SD_SendCMD(CMD55, 0, 0X01); //发送CMD55101 r1 = SD_SendCMD(CMD41, 0x40000000, 0X01); //发送CMD41102 }while(r1&&retry--);103 104 if(retry && SD_SendCMD(CMD58, 0, 0X01) == 0) //鉴别SD2.0卡版本开始105 {106 for(i=0;i<4;i++)107 buff[i] = SPI_ReadWrite(0XFF); //得到OCR值108 SD_TYPE = (buff[0]&0x40) ? V2HC:V2; 109 }110 }else111 {112 SD_SendCMD(CMD55, 0, 0X01); //发送CMD55113 r1 = SD_SendCMD(CMD41, 0, 0X01); //发送CMD41114 if(r1<=1)115 { 116 SD_TYPE = V1;117 retry = 0XFFFE;118 do //等待退出IDLE模式119 {120 SD_SendCMD(CMD55, 0, 0X01); //发送CMD55121 r1 = SD_SendCMD(CMD41, 0, 0X01); //发送CMD41122 }while(r1&&retry--);123 }else //MMC卡不支持CMD55+CMD41识别124 {125 SD_TYPE = MMC; //MMC V3126 retry = 0XFFFE;127 do //等待退出IDLE模式128 { 129 r1 = SD_SendCMD(CMD1, 0, 0X01); //发送CMD1130 }while(r1&&retry--); 131 }132 if( retry==0 || SD_SendCMD(CMD16, 512, 0X01)!=0 )133 SD_TYPE = ERR; //错误的卡134 }135 }136 SPISD_CS(0);137 SPI_SetSpeed(SPI_BAUDRATEPRESCALER_4);138 139 return SD_TYPE?0:1;140 }141 142 void FileSystem_Init(void)143 {144 FATFS *fs;145 DWORD fre_clust, AvailableSize, UserSize; 146 uint8_t res;147 uint8_t *work;148 uint16_t TotalSpace;149 150 res = SD_Init(); 151 if(res == 1)152 printf("SD卡初始化失败! \r\n"); 153 154 res = f_mount(&USERFatFS, USERPath, 1); //挂载155 if(res == FR_NO_FILESYSTEM) //没有文件系统,格式化156 {157 printf("没有文件系统! \r\n"); 158 159 work = malloc(_MIN_SS);160 res = f_mkfs(USERPath, FM_FAT, 0, work, _MIN_SS); //格式化sd卡161 free(work);162 163 if(res == FR_OK)164 { 165 res = f_mount(NULL, USERPath, 1); //格式化后先取消挂载166 res = f_mount(&USERFatFS, USERPath, 1); //重新挂载 167 if(res == FR_OK)168 {169 printf("SD卡已经成功挂载,可以进进行文件写入测试! \r\n");170 } 171 }172 else173 {174 printf("格式化失败! \r\n"); 175 }176 }else if(res == FR_OK)177 {178 printf("挂载成功! \r\n"); 179 }else180 {181 printf("挂载失败! (%d)\r\n", res);182 } 183 184 res = f_getfree(USERPath, &fre_clust, &fs); /* 根目录 */185 if ( res == FR_OK ) 186 {187 TotalSpace = (uint16_t)(((fs->n_fatent - 2) * fs->csize ) / 2 /1024);188 AvailableSize = (uint16_t)((fre_clust * fs->csize) / 2 /1024);189 UserSize = TotalSpace - AvailableSize; 190 /* Print free space in unit of MB (assuming 512 bytes/sector) */191 printf("\r\n%d MB total drive space.\r\n%ld MB available.\r\n%ld MB used.\r\n",TotalSpace, AvailableSize, UserSize);192 }193 else 194 {195 printf("Get SDCard Capacity Failed (%d)\r\n", res);196 } 197 // f_mount(NULL, USERPath, 1); //取消挂载198 } 199 200 /**201 * @brief 读取指定长度数据202 * @note None203 * @retval None204 */205 static uint8_t SD_ReceiveData(uint8_t *data, uint16_t len)206 {207 uint8_t r1;208 209 SPISD_CS(1); 210 do211 { 212 r1 = SPI_ReadWrite(0xFF); 213 HAL_Delay(100);214 }while(r1 != 0xFE); 215 216 while(len--)217 {218 *data = SPI_ReadWrite(0xFF);219 data++;220 }221 SPI_ReadWrite(0xFF);222 SPI_ReadWrite(0xFF); 223 224 return 0;225 }226 227 /**228 * @brief 向SD卡写入一个数据包(512字节)的内容229 * @note None230 * @retval None231 */232 static uint8_t SD_SendBlock(uint8_t*buf, uint8_t cmd)233 { 234 uint8_t r1; 235 uint16_t t; 236 237 do{238 r1 = SPI_ReadWrite(0xFF);239 }while(r1!=0xFF);240 241 SPI_ReadWrite(cmd);242 if(cmd != 0XFD) //不是结束指令243 {244 for(t=0; t<512; t++)245 SPI_ReadWrite(buf[t]); //提高速度,减少函数传参时间246 SPI_ReadWrite(0xFF); //忽略crc247 SPI_ReadWrite(0xFF);248 t = SPI_ReadWrite(0xFF); //接收响应249 if( (t&0x1F) != 0x05 )250 return 2; //响应错误 251 }252 253 return 0; //写入成功254 }255 256 /**257 * @brief CSD,卡的操作条件信息,128bit258 * @note None259 * @retval None260 */261 uint8_t SD_GetCSD(uint8_t *csd_data)262 {263 uint8_t r1; 264 265 r1 = SD_SendCMD(CMD9, 0, 0x01); //读取CSD寄存器266 if(r1 == 0x00)267 r1 = SD_ReceiveData(csd_data, 16); //接收16个字节的数据 268 SPISD_CS(0); //取消片选269 270 return r1?1:0;271 }272 273 /**274 * @brief CID,卡识别号,128bit275 * @note None276 * @retval None277 */278 uint8_t SD_GetCID(uint8_t *cid_data)279 {280 uint8_t r1;281 282 r1 = SD_SendCMD(CMD10, 0, 0x01); //读取CID寄存器283 if(r1==0x00)284 r1 = SD_ReceiveData(cid_data, 16); //接收16个字节的数据 285 SPISD_CS(0); //取消片选286 287 return r1?1:0;288 }289 290 //获取SD卡的总扇区数291 uint32_t SD_GetSectorCount(void)292 {293 uint8_t n;294 uint8_t csd[16];295 uint16_t csize;296 uint32_t Capacity; 297 298 if(SD_GetCSD(csd) != 0) //取CSD信息,如果期间出错,返回0299 return 0; 300 301 if( (csd[0]&0xC0) == 0x40 ) //如果为SDHC卡,按照下面方式计算。V2.00的卡302 { 303 csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;304 Capacity = (uint32_t)csize << 10; //得到扇区数 305 }else //V1.xx的卡306 { 307 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;308 csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;309 Capacity = (uint32_t)csize << (n - 9); //得到扇区数 310 }311 312 return Capacity;313 }314 315 int MSD0_GetCardInfo(PMSD_CARDINFO SD0_CardInfo)316 {317 uint8_t r1;318 uint8_t CSD_Tab[16], CID_Tab[16];319 320 /* Send CMD9, Read CSD */321 r1 = SD_SendCMD(CMD9, 0, 0xFF);322 if(r1 != 0x00)323 return r1;324 if(SD_ReceiveData(CSD_Tab, 16))325 return 1;326 327 /* Send CMD10, Read CID */328 r1 = SD_SendCMD(CMD10, 0, 0xFF);329 if(r1 != 0x00)330 return r1; 331 if(SD_ReceiveData(CID_Tab, 16))332 return 2;333 334 /* Byte 0 */335 SD0_CardInfo->CSD.CSDStruct = (CSD_Tab[0] & 0xC0) >> 6;336 SD0_CardInfo->CSD.SysSpecVersion = (CSD_Tab[0] & 0x3C) >> 2;337 SD0_CardInfo->CSD.Reserved1 = CSD_Tab[0] & 0x03;338 /* Byte 1 */339 SD0_CardInfo->CSD.TAAC = CSD_Tab[1] ;340 /* Byte 2 */341 SD0_CardInfo->CSD.NSAC = CSD_Tab[2];342 /* Byte 3 */343 SD0_CardInfo->CSD.MaxBusClkFrec = CSD_Tab[3];344 /* Byte 4 */345 SD0_CardInfo->CSD.CardComdClasses = CSD_Tab[4] << 4;346 /* Byte 5 */347 SD0_CardInfo->CSD.CardComdClasses |= (CSD_Tab[5] & 0xF0) >> 4;348 SD0_CardInfo->CSD.RdBlockLen = CSD_Tab[5] & 0x0F;349 /* Byte 6 */350 SD0_CardInfo->CSD.PartBlockRead = (CSD_Tab[6] & 0x80) >> 7;351 SD0_CardInfo->CSD.WrBlockMisalign = (CSD_Tab[6] & 0x40) >> 6;352 SD0_CardInfo->CSD.RdBlockMisalign = (CSD_Tab[6] & 0x20) >> 5;353 SD0_CardInfo->CSD.DSRImpl = (CSD_Tab[6] & 0x10) >> 4;354 SD0_CardInfo->CSD.Reserved2 = 0; /* Reserved */355 SD0_CardInfo->CSD.DeviceSize = (CSD_Tab[6] & 0x03) << 10;356 /* Byte 7 */357 SD0_CardInfo->CSD.DeviceSize |= (CSD_Tab[7]) << 2;358 /* Byte 8 */359 SD0_CardInfo->CSD.DeviceSize |= (CSD_Tab[8] & 0xC0) >> 6;360 SD0_CardInfo->CSD.MaxRdCurrentVDDMin = (CSD_Tab[8] & 0x38) >> 3;361 SD0_CardInfo->CSD.MaxRdCurrentVDDMax = (CSD_Tab[8] & 0x07);362 /* Byte 9 */363 SD0_CardInfo->CSD.MaxWrCurrentVDDMin = (CSD_Tab[9] & 0xE0) >> 5;364 SD0_CardInfo->CSD.MaxWrCurrentVDDMax = (CSD_Tab[9] & 0x1C) >> 2;365 SD0_CardInfo->CSD.DeviceSizeMul = (CSD_Tab[9] & 0x03) << 1;366 /* Byte 10 */367 SD0_CardInfo->CSD.DeviceSizeMul |= (CSD_Tab[10] & 0x80) >> 7;368 SD0_CardInfo->CSD.EraseGrSize = (CSD_Tab[10] & 0x7C) >> 2;369 SD0_CardInfo->CSD.EraseGrMul = (CSD_Tab[10] & 0x03) << 3;370 /* Byte 11 */371 SD0_CardInfo->CSD.EraseGrMul |= (CSD_Tab[11] & 0xE0) >> 5;372 SD0_CardInfo->CSD.WrProtectGrSize = (CSD_Tab[11] & 0x1F);373 /* Byte 12 */374 SD0_CardInfo->CSD.WrProtectGrEnable = (CSD_Tab[12] & 0x80) >> 7;375 SD0_CardInfo->CSD.ManDeflECC = (CSD_Tab[12] & 0x60) >> 5;376 SD0_CardInfo->CSD.WrSpeedFact = (CSD_Tab[12] & 0x1C) >> 2;377 SD0_CardInfo->CSD.MaxWrBlockLen = (CSD_Tab[12] & 0x03) << 2;378 /* Byte 13 */379 SD0_CardInfo->CSD.MaxWrBlockLen |= (CSD_Tab[13] & 0xc0) >> 6;380 SD0_CardInfo->CSD.WriteBlockPaPartial = (CSD_Tab[13] & 0x20) >> 5;381 SD0_CardInfo->CSD.Reserved3 = 0;382 SD0_CardInfo->CSD.ContentProtectAppli = (CSD_Tab[13] & 0x01);383 /* Byte 14 */384 SD0_CardInfo->CSD.FileFormatGrouop = (CSD_Tab[14] & 0x80) >> 7;385 SD0_CardInfo->CSD.CopyFlag = (CSD_Tab[14] & 0x40) >> 6;386 SD0_CardInfo->CSD.PermWrProtect = (CSD_Tab[14] & 0x20) >> 5;387 SD0_CardInfo->CSD.TempWrProtect = (CSD_Tab[14] & 0x10) >> 4;388 SD0_CardInfo->CSD.FileFormat = (CSD_Tab[14] & 0x0C) >> 2;389 SD0_CardInfo->CSD.ECC = (CSD_Tab[14] & 0x03);390 /* Byte 15 */391 SD0_CardInfo->CSD.CSD_CRC = (CSD_Tab[15] & 0xFE) >> 1;392 SD0_CardInfo->CSD.Reserved4 = 1;393 394 if(SD0_CardInfo->CardType == V2HC)395 {396 /* Byte 7 */397 SD0_CardInfo->CSD.DeviceSize = (uint16_t)(CSD_Tab[8]) *256;398 /* Byte 8 */399 SD0_CardInfo->CSD.DeviceSize += CSD_Tab[9] ;400 }401 402 SD0_CardInfo->Capacity = SD0_CardInfo->CSD.DeviceSize * MSD_BLOCKSIZE * 1024;403 SD0_CardInfo->BlockSize = MSD_BLOCKSIZE;404 405 /* Byte 0 */406 SD0_CardInfo->CID.ManufacturerID = CID_Tab[0];407 /* Byte 1 */408 SD0_CardInfo->CID.OEM_AppliID = CID_Tab[1] << 8;409 /* Byte 2 */410 SD0_CardInfo->CID.OEM_AppliID |= CID_Tab[2];411 /* Byte 3 */412 SD0_CardInfo->CID.ProdName1 = CID_Tab[3] << 24;413 /* Byte 4 */414 SD0_CardInfo->CID.ProdName1 |= CID_Tab[4] << 16;415 /* Byte 5 */416 SD0_CardInfo->CID.ProdName1 |= CID_Tab[5] << 8;417 /* Byte 6 */418 SD0_CardInfo->CID.ProdName1 |= CID_Tab[6];419 /* Byte 7 */420 SD0_CardInfo->CID.ProdName2 = CID_Tab[7];421 /* Byte 8 */422 SD0_CardInfo->CID.ProdRev = CID_Tab[8];423 /* Byte 9 */424 SD0_CardInfo->CID.ProdSN = CID_Tab[9] << 24;425 /* Byte 10 */426 SD0_CardInfo->CID.ProdSN |= CID_Tab[10] << 16;427 /* Byte 11 */428 SD0_CardInfo->CID.ProdSN |= CID_Tab[11] << 8;429 /* Byte 12 */430 SD0_CardInfo->CID.ProdSN |= CID_Tab[12];431 /* Byte 13 */432 SD0_CardInfo->CID.Reserved1 |= (CID_Tab[13] & 0xF0) >> 4;433 /* Byte 14 */434 SD0_CardInfo->CID.ManufactDate = (CID_Tab[13] & 0x0F) << 8;435 /* Byte 15 */436 SD0_CardInfo->CID.ManufactDate |= CID_Tab[14];437 /* Byte 16 */438 SD0_CardInfo->CID.CID_CRC = (CID_Tab[15] & 0xFE) >> 1;439 SD0_CardInfo->CID.Reserved2 = 1;440 441 return 0; 442 }443 444 445 //写SD卡446 //buf:数据缓存区447 //sector:起始扇区448 //cnt:扇区数449 //返回值:0,ok;其他,失败.450 uint8_t SD_WriteDisk(uint8_t *buf, uint32_t sector, uint8_t cnt)451 {452 uint8_t r1;453 454 if(SD_TYPE != V2HC)455 sector *= 512; //转换为字节地址456 if(cnt == 1)457 {458 r1 = SD_SendCMD(CMD24, sector, 0x01); //读命令459 if(r1 == 0) //指令发送成功460 r1=SD_SendBlock(buf, 0xFE); //写512个字节 461 }else462 {463 if(SD_TYPE != MMC)464 {465 SD_SendCMD(CMD55, 0, 0x01); 466 SD_SendCMD(CMD23, cnt, 0x01); //发送指令 467 }468 r1 = SD_SendCMD(CMD25, sector, 0x01); //连续读命令469 if(r1 == 0)470 {471 do472 {473 r1 = SD_SendBlock(buf,0xFC); //接收512个字节 474 buf += 512; 475 }while(--cnt && r1==0);476 r1 = SD_SendBlock(0,0xFD); //接收512个字节 477 }478 } 479 SPISD_CS(0); //取消片选480 481 return r1;482 } 483 484 //读SD卡485 //buf:数据缓存区486 //sector:扇区487 //cnt:扇区数488 //返回值:0,ok;其他,失败.489 uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)490 {491 uint8_t r1;492 493 if(SD_TYPE != V2HC)494 sector <<= 9; //转换为字节地址495 if(cnt == 1)496 {497 r1 = SD_SendCMD(CMD17, sector, 0x01); //读命令498 if(r1 == 0) 499 r1 = SD_ReceiveData(buf, 512); //接收512个字节 500 }else501 {502 r1 = SD_SendCMD(CMD18, sector, 0x01); //连续读命令503 do504 {505 r1 = SD_ReceiveData(buf, 512); //接收512个字节 506 buf += 512; 507 }while(--cnt && r1==0); 508 SD_SendCMD(CMD12, 0, 0x01); //发送停止命令509 } 510 SPISD_CS(0); //取消片选511 512 return r1;513 }514 515 uint8_t SPI_ReadWrite(uint8_t Txdata)516 {517 uint8_t Rxdata; 518 HAL_SPI_TransmitReceive(&hspi1, &Txdata, &Rxdata, 1, 100);519 return Rxdata;520 }521 522 //SPI1波特率设置523 void SPI_SetSpeed(uint8_t speed)524 {525 hspi1.Init.BaudRatePrescaler = speed;526 if (HAL_SPI_Init(&hspi1) != HAL_OK)527 {528 Error_Handler();529 }530 }531 ///////////////////////////END//////////////////////////////////////
drive_spisd.h如下
1 /* Define to prevent recursive inclusion -------------------------------------*/ 2 #ifndef __DRIVE_SPISD_H 3 #define __DRIVE_SPISD_H 4 5 #ifdef __cplusplus 6 extern "C" { 7 #endif 8 9 /* Includes ------------------------------------------------------------------*/ 10 #include "main.h" 11 /* Private includes ----------------------------------------------------------*/ 12 #include "fatfs.h" 13 /* Exported types ------------------------------------------------------------*/ 14 enum _CD_HOLD 15 { 16 HOLD = 0, 17 RELEASE = 1, 18 }; 19 20 typedef struct /* Card Specific Data */ 21 { 22 uint8_t CSDStruct; /* CSD structure */ 23 uint8_t SysSpecVersion; /* System specification version */ 24 uint8_t Reserved1; /* Reserved */ 25 uint8_t TAAC; /* Data read access-time 1 */ 26 uint8_t NSAC; /* Data read access-time 2 in CLK cycles */ 27 uint8_t MaxBusClkFrec; /* Max. bus clock frequency */ 28 uint16_t CardComdClasses; /* Card command classes */ 29 uint8_t RdBlockLen; /* Max. read data block length */ 30 uint8_t PartBlockRead; /* Partial blocks for read allowed */ 31 uint8_t WrBlockMisalign; /* Write block misalignment */ 32 uint8_t RdBlockMisalign; /* Read block misalignment */ 33 uint8_t DSRImpl; /* DSR implemented */ 34 uint8_t Reserved2; /* Reserved */ 35 uint32_t DeviceSize; /* Device Size */ 36 uint8_t MaxRdCurrentVDDMin; /* Max. read current @ VDD min */ 37 uint8_t MaxRdCurrentVDDMax; /* Max. read current @ VDD max */ 38 uint8_t MaxWrCurrentVDDMin; /* Max. write current @ VDD min */ 39 uint8_t MaxWrCurrentVDDMax; /* Max. write current @ VDD max */ 40 uint8_t DeviceSizeMul; /* Device size multiplier */ 41 uint8_t EraseGrSize; /* Erase group size */ 42 uint8_t EraseGrMul; /* Erase group size multiplier */ 43 uint8_t WrProtectGrSize; /* Write protect group size */ 44 uint8_t WrProtectGrEnable; /* Write protect group enable */ 45 uint8_t ManDeflECC; /* Manufacturer default ECC */ 46 uint8_t WrSpeedFact; /* Write speed factor */ 47 uint8_t MaxWrBlockLen; /* Max. write data block length */ 48 uint8_t WriteBlockPaPartial; /* Partial blocks for write allowed */ 49 uint8_t Reserved3; /* Reserded */ 50 uint8_t ContentProtectAppli; /* Content protection application */ 51 uint8_t FileFormatGrouop; /* File format group */ 52 uint8_t CopyFlag; /* Copy flag (OTP) */ 53 uint8_t PermWrProtect; /* Permanent write protection */ 54 uint8_t TempWrProtect; /* Temporary write protection */ 55 uint8_t FileFormat; /* File Format */ 56 uint8_t ECC; /* ECC code */ 57 uint8_t CSD_CRC; /* CSD CRC */ 58 uint8_t Reserved4; /* always 1*/ 59 }MSD_CSD; 60 61 typedef struct /*Card Identification Data*/ 62 { 63 uint8_t ManufacturerID; /* ManufacturerID */ 64 uint16_t OEM_AppliID; /* OEM/Application ID */ 65 uint32_t ProdName1; /* Product Name part1 */ 66 uint8_t ProdName2; /* Product Name part2*/ 67 uint8_t ProdRev; /* Product Revision */ 68 uint32_t ProdSN; /* Product Serial Number */ 69 uint8_t Reserved1; /* Reserved1 */ 70 uint16_t ManufactDate; /* Manufacturing Date */ 71 uint8_t CID_CRC; /* CID CRC */ 72 uint8_t Reserved2; /* always 1 */ 73 }MSD_CID; 74 75 typedef struct 76 { 77 MSD_CSD CSD; 78 MSD_CID CID; 79 uint32_t Capacity; /* Card Capacity */ 80 uint32_t BlockSize; /* Card Block Size */ 81 uint16_t RCA; 82 uint8_t CardType; 83 uint32_t SpaceTotal; /* Total space size in file system */ 84 uint32_t SpaceFree; /* Free space size in file system */ 85 }MSD_CARDINFO, *PMSD_CARDINFO; 86 87 extern MSD_CARDINFO SD0_CardInfo; 88 /* Exported constants --------------------------------------------------------*/ 89 90 /* Exported macro ------------------------------------------------------------*/ 91 //SD卡类型 92 #define ERR 0x00 93 #define MMC 0x01 94 #define V1 0x02 95 #define V2 0x04 96 #define V2HC 0x06 97 98 #define DUMMY_BYTE 0xFF 99 #define MSD_BLOCKSIZE 512100 101 /*102 CMD定义103 bc:发送到所有卡,不返回响应104 bcr:发送到所有卡,同时接收所有卡的响应105 ac:发送到选定卡,无数据传输106 adtc:发送到选定卡,有数据传输107 */108 #define CMD0 0 //bc,卡复位到IDLE状态109 #define CMD1 1 110 #define CMD8 8 //bcr,读SD卡接口条件,包含主机支持的电压信息,并询问卡是否支持111 #define CMD9 9 //ac,读CSD数据112 #define CMD10 10 //ac,读CID数据113 #define CMD12 12 //ac,停止数据传输114 #define CMD16 16 //ac,设置块长度(对于SDHC卡块命令长度固定为512字节) 应返回0x00115 #define CMD17 17 //adtc,读单个块116 #define CMD18 18 //adtc,读多个块。连续读块,直到被CMD12中断。117 #define CMD23 23 //设置多sector写入前预先擦除N个block118 #define CMD24 24 //adtc,写单个块119 #define CMD25 25 //adtc,写多个块。连续写块,直到被CMD12中断。120 #define CMD41 41 //应返回0x00121 #define CMD55 55 //ac,指定下个命令为特定应用命令(ACMD),不是标准命令,应返回0x01122 #define CMD58 58 //读OCR信息123 #define CMD59 59 //使能/禁止CRC,应返回0x00124 125 //数据写入回应字意义126 #define MSD_DATA_OK 0x05127 #define MSD_DATA_CRC_ERROR 0x0B128 #define MSD_DATA_WRITE_ERROR 0x0D129 #define MSD_DATA_OTHER_ERROR 0xFF130 131 //SD卡回应标记字132 #define MSD_RESPONSE_NO_ERROR 0x00133 #define MSD_IN_IDLE_STATE 0x01134 #define MSD_ERASE_RESET 0x02135 #define MSD_ILLEGAL_COMMAND 0x04136 #define MSD_COM_CRC_ERROR 0x08137 #define MSD_ERASE_SEQUENCE_ERROR 0x10138 #define MSD_ADDRESS_ERROR 0x20139 #define MSD_PARAMETER_ERROR 0x40140 #define MSD_RESPONSE_FAILURE 0xFF141 142 /* Exported functions prototypes ---------------------------------------------*/143 void SPISD_CS(uint8_t p);144 uint8_t SD_Init(void);145 void WritetoSD(BYTE write_buff[],uint8_t bufSize);146 void FileSystem_Init(void);147 uint32_t SD_GetSectorCount(void);148 uint8_t SD_GetCID(uint8_t *cid_data);149 uint8_t SD_GetCSD(uint8_t *csd_data);150 int MSD0_GetCardInfo(PMSD_CARDINFO SD0_CardInfo);151 uint8_t SD_ReadDisk(uint8_t*buf, uint32_t sector, uint8_t cnt);152 uint8_t SD_WriteDisk(uint8_t*buf, uint32_t sector, uint8_t cnt);153 void SPI_SetSpeed(uint8_t speed);154 uint8_t SPI_ReadWrite(uint8_t Txdata);155 156 /* Private defines -----------------------------------------------------------*/157 extern uint8_t SD_TYPE;158 #ifdef __cplusplus159 }160 #endif161 162 #endif /* __DRIVE_SPISD_H */163 164 /************************ (C) COPYRIGHT STMicroelectronics *****END OF FILE****/
然后在文件系统文件夹里修改内容。
user_diskio.c如下
1 /* USER CODE BEGIN Header */ 2 /** 3 ****************************************************************************** 4 * @file user_diskio.c 5 * @brief This file includes a diskio driver skeleton to be completed by the user. 6 ****************************************************************************** 7 * @attention 8 * 9 * Copyright (c) 2023 STMicroelectronics. 10 * All rights reserved. 11 * 12 * This software is licensed under terms that can be found in the LICENSE file 13 * in the root directory of this software component. 14 * If no LICENSE file comes with this software, it is provided AS-IS. 15 * 16 ****************************************************************************** 17 */ 18 /* USER CODE END Header */ 19 20 #ifdef USE_OBSOLETE_USER_CODE_SECTION_0 21 /* 22 * Warning: the user section 0 is no more in use (starting from CubeMx version 4.16.0) 23 * To be suppressed in the future. 24 * Kept to ensure backward compatibility with previous CubeMx versions when 25 * migrating projects. 26 * User code previously added there should be copied in the new user sections before 27 * the section contents can be deleted. 28 */ 29 /* USER CODE BEGIN 0 */ 30 /* USER CODE END 0 */ 31 #endif 32 33 /* USER CODE BEGIN DECL */ 34 35 /* Includes ------------------------------------------------------------------*/ 36 #include37 #include "ff_gen_drv.h" 38 39 /* Private typedef -----------------------------------------------------------*/ 40 #include "drive_spisd.h" 41 /* Private define ------------------------------------------------------------*/ 42 43 /* Private variables ---------------------------------------------------------*/ 44 /* Disk status */ 45 static volatile DSTATUS Stat = STA_NOINIT; 46 47 /* USER CODE END DECL */ 48 49 /* Private function prototypes -----------------------------------------------*/ 50 DSTATUS USER_initialize (BYTE pdrv); 51 DSTATUS USER_status (BYTE pdrv); 52 DRESULT USER_read (BYTE pdrv, BYTE *buff, DWORD sector, UINT count); 53 #if _USE_WRITE == 1 54 DRESULT USER_write (BYTE pdrv, const BYTE *buff, DWORD sector, UINT count); 55 #endif /* _USE_WRITE == 1 */ 56 #if _USE_IOCTL == 1 57 DRESULT USER_ioctl (BYTE pdrv, BYTE cmd, void *buff); 58 #endif /* _USE_IOCTL == 1 */ 59 60 Diskio_drvTypeDef USER_Driver = 61 { 62 USER_initialize, 63 USER_status, 64 USER_read, 65 #if _USE_WRITE 66 USER_write, 67 #endif /* _USE_WRITE == 1 */ 68 #if _USE_IOCTL == 1 69 USER_ioctl, 70 #endif /* _USE_IOCTL == 1 */ 71 }; 72 73 /* Private functions ---------------------------------------------------------*/ 74 75 /** 76 * @brief Initializes a Drive 77 * @param pdrv: Physical drive number (0..) 78 * @retval DSTATUS: Operation status 79 */ 80 DSTATUS USER_initialize ( 81 BYTE pdrv /* Physical drive nmuber to identify the drive */ 82 ) 83 { 84 /* USER CODE BEGIN INIT */ 85 uint8_t res; 86 res = SD_Init(); 87 if(res) //STM32 SPI的bug,在sd卡操作失败的时候如果不执行下面的语句,可能导致SPI读写异常 88 { 89 SPI_SetSpeed(SPI_BAUDRATEPRESCALER_256); 90 SPI_ReadWrite(0xff); //提供额外的8个时钟 91 SPI_SetSpeed(SPI_BAUDRATEPRESCALER_4); 92 } 93 if(res) 94 return STA_NOINIT; 95 else 96 return RES_OK; 97 /* USER CODE END INIT */ 98 } 99 100 /**101 * @brief Gets Disk Status102 * @param pdrv: Physical drive number (0..)103 * @retval DSTATUS: Operation status104 */105 DSTATUS USER_status (106 BYTE pdrv /* Physical drive number to identify the drive */107 )108 {109 /* USER CODE BEGIN STATUS */110 switch (pdrv)111 {112 case 0 :113 return RES_OK;114 case 1 :115 return RES_OK;116 case 2 :117 return RES_OK;118 default:119 return STA_NOINIT;120 }121 /* USER CODE END STATUS */122 }123 124 /**125 * @brief Reads Sector(s)126 * @param pdrv: Physical drive number (0..)127 * @param *buff: Data buffer to store read data128 * @param sector: Sector address (LBA)129 * @param count: Number of sectors to read (1..128)130 * @retval DRESULT: Operation result131 */132 DRESULT USER_read (133 BYTE pdrv, /* Physical drive nmuber to identify the drive */134 BYTE *buff, /* Data buffer to store read data */135 DWORD sector, /* Sector address in LBA */136 UINT count /* Number of sectors to read */137 )138 {139 /* USER CODE BEGIN READ */140 uint8_t res;141 if( !count )142 { 143 return RES_PARERR; /* count不能等于0,否则返回参数错误 */144 }145 switch (pdrv)146 {147 case 0:148 res = SD_ReadDisk(buff,sector,count); 149 if(res == 0)150 return RES_OK;151 else152 return RES_ERROR; 153 default:154 return RES_ERROR;155 }156 /* USER CODE END READ */157 }158 159 /**160 * @brief Writes Sector(s)161 * @param pdrv: Physical drive number (0..)162 * @param *buff: Data to be written163 * @param sector: Sector address (LBA)164 * @param count: Number of sectors to write (1..128)165 * @retval DRESULT: Operation result166 */167 #if _USE_WRITE == 1168 DRESULT USER_write (169 BYTE pdrv, /* Physical drive nmuber to identify the drive */170 const BYTE *buff, /* Data to be written */171 DWORD sector, /* Sector address in LBA */172 UINT count /* Number of sectors to write */173 )174 {175 /* USER CODE BEGIN WRITE */176 /* USER CODE HERE */177 uint8_t res;178 if( !count )179 return RES_PARERR; /* count不能等于0,否则返回参数错误 */180 switch (pdrv)181 {182 case 0:183 res=SD_WriteDisk((uint8_t *)buff,sector,count);184 if(res == 0)185 return RES_OK;186 else187 return RES_ERROR; 188 default:189 return RES_ERROR;190 }191 /* USER CODE END WRITE */192 }193 #endif /* _USE_WRITE == 1 */194 195 /**196 * @brief I/O control operation197 * @param pdrv: Physical drive number (0..)198 * @param cmd: Control code199 * @param *buff: Buffer to send/receive control data200 * @retval DRESULT: Operation result201 */202 #if _USE_IOCTL == 1203 DRESULT USER_ioctl (204 BYTE pdrv, /* Physical drive nmuber (0..) */205 BYTE cmd, /* Control code */206 void *buff /* Buffer to send/receive control data */207 )208 {209 /* USER CODE BEGIN IOCTL */210 DRESULT res;211 switch(cmd)212 {213 case CTRL_SYNC:214 SPISD_CS(1);215 do{216 HAL_Delay(20);217 }while(SPI_ReadWrite(0xFF)!=0xFF);218 res=RES_OK;219 SPISD_CS(0);220 break; 221 case GET_SECTOR_SIZE:222 *(WORD*)buff = 512;223 res = RES_OK;224 break; 225 case GET_BLOCK_SIZE:226 *(WORD*)buff = 8;227 res = RES_OK;228 break; 229 case GET_SECTOR_COUNT:230 *(DWORD*)buff = SD_GetSectorCount();231 res = RES_OK;232 break;233 default:234 res = RES_PARERR;235 break;236 }237 return res;238 /* USER CODE END IOCTL */239 }240 #endif /* _USE_IOCTL == 1 */
main.c
1 /* USER CODE BEGIN Header */ 2 /** 3 ****************************************************************************** 4 * @file : main.c 5 * @brief : Main program body 6 ****************************************************************************** 7 * @attention 8 * 9 * Copyright (c) 2023 STMicroelectronics. 10 * All rights reserved. 11 * 12 * This software is licensed under terms that can be found in the LICENSE file 13 * in the root directory of this software component. 14 * If no LICENSE file comes with this software, it is provided AS-IS. 15 * 16 ****************************************************************************** 17 */ 18 /* USER CODE END Header */ 19 /* Includes ------------------------------------------------------------------*/ 20 #include "main.h" 21 #include "fatfs.h" 22 #include "spi.h" 23 #include "usart.h" 24 #include "gpio.h" 25 26 /* Private includes ----------------------------------------------------------*/ 27 /* USER CODE BEGIN Includes */ 28 #include "drive_spisd.h" 29 /* USER CODE END Includes */ 30 31 /* Private typedef -----------------------------------------------------------*/ 32 /* USER CODE BEGIN PTD */ 33 34 /* USER CODE END PTD */ 35 36 /* Private define ------------------------------------------------------------*/ 37 /* USER CODE BEGIN PD */ 38 /* USER CODE END PD */ 39 40 /* Private macro -------------------------------------------------------------*/ 41 /* USER CODE BEGIN PM */ 42 43 /* USER CODE END PM */ 44 45 /* Private variables ---------------------------------------------------------*/ 46 47 /* USER CODE BEGIN PV */ 48 uint8_t status = 0; 49 uint8_t writeBuf[] = "demo program forever no bug!!!\r\n"; 50 /* USER CODE END PV */ 51 52 /* Private function prototypes -----------------------------------------------*/ 53 void SystemClock_Config(void); 54 /* USER CODE BEGIN PFP */ 55 56 /* USER CODE END PFP */ 57 58 /* Private user code ---------------------------------------------------------*/ 59 /* USER CODE BEGIN 0 */ 60 61 /* USER CODE END 0 */ 62 63 /** 64 * @brief The application entry point. 65 * @retval int 66 */ 67 int main(void) 68 { 69 /* USER CODE BEGIN 1 */ 70 UINT Bw; 71 FIL file; 72 uint16_t cb_task = 0; 73 uint8_t res1 = 0, res2 = 0; 74 /* USER CODE END 1 */ 75 76 /* MCU Configuration--------------------------------------------------------*/ 77 78 /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ 79 HAL_Init(); 80 81 /* USER CODE BEGIN Init */ 82 83 /* USER CODE END Init */ 84 85 /* Configure the system clock */ 86 SystemClock_Config(); 87 88 /* USER CODE BEGIN SysInit */ 89 90 /* USER CODE END SysInit */ 91 92 /* Initialize all configured peripherals */ 93 MX_GPIO_Init(); 94 MX_SPI1_Init(); 95 MX_USART1_UART_Init(); 96 MX_FATFS_Init(); 97 /* USER CODE BEGIN 2 */ 98 FileSystem_Init(); //初始化文件系统 99 100 status = 1;101 res1 = f_open(&file, "sdRW1.txt", FA_OPEN_ALWAYS | FA_WRITE);102 if((res1 & FR_DENIED) == FR_DENIED)103 printf("卡存储已满,写入失败! \r\n");104 /* USER CODE END 2 */105 106 /* Infinite loop */107 /* USER CODE BEGIN WHILE */108 while (1)109 {110 /* USER CODE END WHILE */111 112 /* USER CODE BEGIN 3 */113 if(status == 1)114 {115 if(res1 == FR_OK)116 {117 f_lseek(&file, f_size(&file)); //确保写入不会覆盖之前的数据118 res2 = f_write(&file, writeBuf, sizeof(writeBuf), &Bw); //写数据到SD卡 119 if(res2 != FR_OK)120 {121 printf("文件写入失败! \r\n");122 HAL_GPIO_WritePin(User_led_GPIO_Port, User_led_Pin, GPIO_PIN_RESET);123 }else124 {125 HAL_GPIO_WritePin(User_led_GPIO_Port, User_led_Pin, GPIO_PIN_SET);126 } 127 }128 else129 {130 printf("打开文件失败! %d\r\n",res1);131 } 132 if(++cb_task%4096==0)133 f_sync(&file); 134 }else if(status == 2)135 {136 f_close(&file);137 f_mount(NULL, USERPath, 1); //取消挂载138 HAL_GPIO_WritePin(User_led_GPIO_Port, User_led_Pin, GPIO_PIN_RESET);139 status = 0;140 }141 HAL_Delay(10);142 }143 /* USER CODE END 3 */144 }145 146 /**147 * @brief System Clock Configuration148 * @retval None149 */150 void SystemClock_Config(void)151 {152 RCC_OscInitTypeDef RCC_OscInitStruct = {0};153 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};154 155 /** Configure the main internal regulator output voltage156 */157 __HAL_RCC_PWR_CLK_ENABLE();158 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);159 /** Initializes the RCC Oscillators according to the specified parameters160 * in the RCC_OscInitTypeDef structure.161 */162 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;163 RCC_OscInitStruct.HSEState = RCC_HSE_ON;164 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;165 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;166 RCC_OscInitStruct.PLL.PLLM = 4;167 RCC_OscInitStruct.PLL.PLLN = 168;168 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;169 RCC_OscInitStruct.PLL.PLLQ = 4;170 if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)171 {172 Error_Handler();173 }174 /** Initializes the CPU, AHB and APB buses clocks175 */176 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK177 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;178 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;179 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;180 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;181 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;182 183 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)184 {185 Error_Handler();186 }187 }188 189 /* USER CODE BEGIN 4 */190 void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)191 {192 if(GPIO_Pin == User_Key_Pin)193 {194 status = 2;195 }196 }197 /* USER CODE END 4 */198 199 /**200 * @brief This function is executed in case of error occurrence.201 * @retval None202 */203 void Error_Handler(void)204 {205 /* USER CODE BEGIN Error_Handler_Debug */206 /* User can add his own implementation to report the HAL error return state */207 __disable_irq();208 while (1)209 {210 }211 /* USER CODE END Error_Handler_Debug */212 }213 214 #ifdef USE_FULL_ASSERT215 /**216 * @brief Reports the name of the source file and the source line number217 * where the assert_param error has occurred.218 * @param file: pointer to the source file name219 * @param line: assert_param error line source number220 * @retval None221 */222 void assert_failed(uint8_t *file, uint32_t line)223 {224 /* USER CODE BEGIN 6 */225 /* User can add his own implementation to report the file name and line number,226 ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */227 /* USER CODE END 6 */228 }229 #endif /* USE_FULL_ASSERT */
实测是可以的,但是写速度并没有网上说的1M/s那么快,也有可能是我引线的问题。
标签:
上一篇 : 可以融资融券的股票是不是都可以买跌?(可以融资融券的股票一共有那些)_焦点热议
下一篇 : 最后一页
最新推荐
MCU:STM32F429ZIT6开发环境:STM32CubeMX+MDK5外购了一个SPI接口的SDC
来为大家解答以上的问题。可以融资融券的股票是不是都可以买跌?,可以
每经AI快讯,有投资者在投资者互动平台提问:你好,想咨询贵司:1 目前
任天堂确认《皮克敏4(Pikmin4)》将于7月21日发售,全区支持简体中文
紫金矿业与哈萨克投资国有公司达成矿产开发协议 【紫金矿业与哈萨
同时提到,网易的营运利润增长已经连续七个季度超过游戏收入的增长,预
想必现在有很多小伙伴对于刺挠是什么意思网络用语,是哪里的方言方面的
1、丹阳属于江苏的哪个市2、丹阳是一个县级市,隶属于江苏省镇江市。3
中国基金报记者天心6月5日,A股市场表现分化,上证指数上涨0 07%,深证
音频解说1、余治平编著的《董子春秋义法辞考论》是一部从义、法、辞三
1、不论是初中还是高中。2、十四中都要强过五中的!。本文就为大家分享
科技!体验无人驾驶汽车采摘汉南甜玉米六月,汉南甜玉米进入成熟期,
台湾极限运动超铁协会理事长陈品杰接受中评社访问表示,大陆对台湾开了
七天无理由退货是为了保护消费者合法权益,但有人却利用这一规定占卖家
募集资金总额预计不超过35亿元。
1、PS中有一下几种有代表性的方法:使用选区工具中的【羽化】先按照边
1、这个是真的很厉害。2、我前几天买了逆天辅助。3、通宵玩。本文为大
重磅消息!记者从中福彩中心获悉,为回馈广大购彩者对中国福利彩票的关
iOS17发布之后,惯例苹果会给出支持更新升级的设备以及不支持的设备,
近日V社公布了本周Steam游戏销量周榜,CAPCOM旗下经典格斗游戏系列《街
初夏的沈阳医学院,绿草如茵,繁花盛开。在波光粼粼的博学湖畔的草地上
在国外市场上,白酒饮用口感和茅台酒存在的口感风格是有所不同的,茅台
2023年6月6日,罗普特发生1笔大宗交易,总成交23万股,成交金额338 79
商业连锁板块震荡走强,截至发稿,小商品城、第一医药等涨超8%,国药一
当身边不少人都否定你的付出,你心中肯定也是百感交集的,鞠婧祎自然也
据了解,高考期间,考生或家长只要看到贴有“爱心送考”车标并系有“绿
天气转好气温回升明夜至后天白天有雷阵雨今明天气今天上午雨止转阴,下
最新数据显示,我国工业互联网覆盖45大类经济行业,连接设备逾8000万台
周二早盘,美元指数保持在104 00附近的防御态势,此前一周开盘波动较大
摩托车强制报废的车辆补贴根据摩托车登记年限而定。提前一年报废的补贴
1、我想这个不是几句话就能说明白的。2、看你这么着急,给你一些建议和
铁路12306手机客户端5日起提供学生优惠资质在线核验服务记者从中国铁路
全省前四月新增税费缓减76 07亿元,主流媒体,山西门户。山西新闻网是经
华声在线6月4日讯(全媒体记者彭可心通讯员彭维刘雯)6月3日10时许,一
1、没有区别,腾讯新闻布局新闻类早,有自己团队。2、头条都是拿来主义
————————陶罐主体陶罐是在静物画中经常出现的一个种类,是能够
6月4日,在山东省委反腐败协调小组国际追逃追赃工作办公室统筹协调下,
断舍离,是一生的必修课。人到了晚年,就要过低配生活,道理很容易被接
1、LOLs6低优先级队列怎么解除?LOL低优先级队列是什么意思?LOLs6低优
由邱礼涛执导,郭富城、古天乐、刘青云领衔主演的动作犯罪电影《扫毒3
word斜线表头输入文字,word斜线表头怎么输入文字这个很多人还不知道,
哪吒汽车旗下产品有一个共同点,售价都相对亲民。这一次,哪吒S继续延
花上千元在珠宝店买的“阿玛尼”手表竟是假的9名消费者要求“退一赔三
记者从市统计局获悉,从近日出炉的规上工业企业生产经营景气状况季度调
智通财经APP讯,亿胜生物科技(01061)发布公告,于2023年6月5日,该公司
人民网北京6月5日电(记者杨曦)国务院新闻办公室今日举行国务院政策例行
信用卡逾期太多会连累家人吗如果您的信用卡逾期太多,可能会对您的
中新网6月5日电综合外媒报道,俄罗斯国防部发言人伊戈尔·科纳申科夫称
南京炭青化学品有限公司TDI报价平稳,上海货执行16500元 吨。供方积极
一年一度的高考即将开始考生面对考试北京市疾控中心提醒考生、家长及学
知识分享 为什么无线路由器连不上
环球要闻:初中化学教学工作总结及教学反思(初中化学教学工作总结)
全球时讯:日本"无菜单"寿司风靡中国:高端套餐人均2000元!
全球快讯:金融租赁业2022年总资产规模同比增加5.6% “新规”促行业加速回归租赁本源
日经225股指期货 (OSE) (M3) 当日内交易策略: 在 31750.00 之上 目标价位为 32190.00(20230605) 每日热议
“不满”量化继续“独大”,这批“深度研究型”基金经理要“上场对抗“
新乡市气象台发布大雾橙色预警【Ⅱ级/严重】【2023-06-05】_当前速读
每日报道:大余县气象台发布雷电黄色预警信号【III级/较重】【2023-06-04】
世界百事通!荒僻的拼音和解释是什么(荒僻的拼音 荒僻的造句简介介绍)
前沿资讯!我市举办环境日公益宣传活动 做生态文明建设的践行者
全球播报:微信莫名其妙被拉进群然后无限邀请朋友(微信莫名其妙被下线了)
三连胜!2023世界女排联赛中国女排3:1战胜荷兰队-环球播报
黄渤王一博主演电影《热烈》担任第25届上影节闭幕片-环球关注
【原】看了《后浪》才知道,端午节必备的艾草,原来一个夏天都这么有用! 全球新视野
Copyright © 2015-2022 世界律师网版权所有 备案号:琼ICP备2022009675号-1 联系邮箱:435 227 67@qq.com