查看: 4020|回复: 3

[分享] 【中秋活动】LPC845+ST7735驱动小LCD送中秋祝福

[复制链接]
  • TA的每日心情

    2025-5-29 09:38
  • 签到天数: 632 天

    连续签到: 1 天

    [LV.9]以坛为家II

    94

    主题

    1639

    帖子

    2

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    4470

    热心会员

    最后登录
    2025-6-10
    发表于 2021-9-17 11:08:33 | 显示全部楼层 |阅读模式
    本帖最后由 胤幻1988 于 2021-9-17 12:35 编辑

    中秋转眼快到了!我在这里先祝大家中秋节快乐,阖家团圆!~
    废话不多说,上祝福:
    ZQ.jpeg
    本次测试板用LPC845自制版+一个仿ARDUINO ADRFRUIT的一个小的LCD shield 来实现。
    LCD驱动芯片ST7735,分辨率128*160 ,使用硬件SPI的方法来驱动LCD及SD卡。
    初始化代码使用TOOL工具生成:
    引脚配置:
    X0.png
    时钟配置:
    X3.png
    外设配置:
    SPI1
    X1.png
    USART0:
    X2.png
    导出文件,覆盖原MDK工程同名文件,下面就可以愉快的写程序了。
    X6.png
    给出代码:
    lcd_init.h
    1. #ifndef __LCD_INIT_H
    2. #define __LCD_INIT_H

    3. #include "sys.h"
    4. #include "fsl_gpio.h"
    5. #include "fsl_swm.h"
    6. #include "pin_mux.h"
    7. #include "delay.h"


    8. #define USE_HORIZONTAL 1  //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏


    9. #if USE_HORIZONTAL==0||USE_HORIZONTAL==1
    10. #define LCD_W 128
    11. #define LCD_H 160

    12. #else
    13. #define LCD_W 160
    14. #define LCD_H 128
    15. #endif


    16. /* Symbols to be used with GPIO driver */
    17. #define LCD_SCK_GPIO              BOARD_INITPINS_SPI1_SCK_GPIO                /*!<@brief GPIO peripheral base pointer */
    18. #define LCD_SCK_GPIO_PIN_MASK     BOARD_INITPINS_SPI1_SCK_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    19. #define LCD_SCK_PORT              BOARD_INITPINS_SPI1_SCK_PORT                   /*!<@brief PORT device index: 0 */
    20. #define LCD_SCK_PIN               BOARD_INITPINS_SPI1_SCK_PIN                    /*!<@brief PORT pin number */
    21. #define LCD_SCK_PIN_MASK          BOARD_INITPINS_SPI1_SCK_PIN_MASK       /*!<@brief PORT pin mask */
    22.                                                          /* @} */

    23. /*! @name PIO0_7 (number 45), SPI1_MISO
    24.   @{ */

    25. /* Symbols to be used with GPIO driver */
    26. #define LCD_MISO_GPIO             BOARD_INITPINS_SPI1_MISO_GPIO                 /*!<@brief GPIO peripheral base pointer */
    27. #define LCD_MISO_GPIO_PIN_MASK    BOARD_INITPINS_SPI1_MISO_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    28. #define LCD_MISO_PORT             BOARD_INITPINS_SPI1_MISO_PORT                   /*!<@brief PORT device index: 0 */
    29. #define LCD_MISO_PIN              BOARD_INITPINS_SPI1_MISO_PIN                    /*!<@brief PORT pin number */
    30. #define LCD_MISO_PIN_MASK         BOARD_INITPINS_SPI1_MISO_PIN_MASK      /*!<@brief PORT pin mask */
    31.                                                           /* @} */

    32. /*! @name PIO1_19 (number 44), SPI1_MOSI
    33.   @{ */

    34. /* Symbols to be used with GPIO driver */
    35. #define LCD_MOSI_GPIO             BOARD_INITPINS_SPI1_MOSI_GPIO                 /*!<@brief GPIO peripheral base pointer */
    36. #define LCD_MOSI_GPIO_PIN_MASK    BOARD_INITPINS_SPI1_MOSI_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    37. #define LCD_MOSI_PORT             BOARD_INITPINS_SPI1_MOSI_PORT                    /*!<@brief PORT device index: 1 */
    38. #define LCD_MOSI_PIN              BOARD_INITPINS_SPI1_MOSI_PIN                   /*!<@brief PORT pin number */
    39. #define LCD_MOSI_PIN_MASK         BOARD_INITPINS_SPI1_MOSI_PIN_MASK       /*!<@brief PORT pin mask */
    40.                                                            /* @} */

    41. /*! @name PIO1_18 (number 43), SPI1_SSEL0
    42.   @{ */

    43. /* Symbols to be used with GPIO driver */
    44. #define LCD_SSEL0_GPIO            BOARD_INITPINS_SPI1_SSEL0_GPIO                /*!<@brief GPIO peripheral base pointer */
    45. #define LCD_SSEL0_GPIO_PIN_MASK   BOARD_INITPINS_SPI1_SSEL0_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    46. #define LCD_SSEL0_PORT            BOARD_INITPINS_SPI1_SSEL0_PORT                    /*!<@brief PORT device index: 1 */
    47. #define LCD_SSEL0_PIN             BOARD_INITPINS_SPI1_SSEL0_PIN                   /*!<@brief PORT pin number */
    48. #define LCD_SSEL0_PIN_MASK        BOARD_INITPINS_SPI1_SSEL0_PIN_MASK       /*!<@brief PORT pin mask */
    49.                                                             /* @} */

    50. /*! @name PIO0_16 (number 19), TFT_DC
    51.   @{ */

    52. /* Symbols to be used with GPIO driver */
    53. #define LCD_DC_GPIO               BOARD_INITPINS_TFT_DC_GPIO                /*!<@brief GPIO peripheral base pointer */
    54. #define LCD_DC_GPIO_PIN_MASK      BOARD_INITPINS_TFT_DC_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    55. #define LCD_DC_PORT               BOARD_INITPINS_TFT_DC_PORT                    /*!<@brief PORT device index: 0 */
    56. #define LCD_DC_PIN                BOARD_INITPINS_TFT_DC_PIN                    /*!<@brief PORT pin number */
    57. #define LCD_DC_PIN_MASK           BOARD_INITPINS_TFT_DC_PIN_MASK       /*!<@brief PORT pin mask */
    58.                                                         /* @} */

    59. /*! @name PIO1_21 (number 59), SD_CS
    60.   @{ */

    61. /* Symbols to be used with GPIO driver */
    62. #define SD_CS_GPIO                BOARD_INITPINS_SD_CS_GPIO                  /*!<@brief GPIO peripheral base pointer */
    63. #define SD_CS_GPIO_PIN_MASK       BOARD_INITPINS_SD_CS_GPIO_PIN_MASK  /*!<@brief GPIO pin mask */
    64. #define SD_CS_PORT                BOARD_INITPINS_SD_CS_PORT                   /*!<@brief PORT device index: 1 */
    65. #define SD_CS_PIN                 BOARD_INITPINS_SD_CS_PIN                   /*!<@brief PORT pin number */
    66. #define SD_CS_PIN_MASK            BOARD_INITPINS_SD_CS_PIN_MASK      /*!<@brief PORT pin mask */
    67.                                                        /* @} */

    68. //-----------------LCD端口定义----------------

    69. #define LCD_SCLK_Clr() GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 0)//SCL=SCLK
    70. #define LCD_SCLK_Set() GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 1)

    71. #define LCD_MOSI_Clr() GPIO_PinWrite(LCD_MOSI_GPIO, LCD_MOSI_PORT, LCD_MOSI_PIN, 0)//SDA=MOSI
    72. #define LCD_MOSI_Set() GPIO_PinWrite(LCD_MOSI_GPIO, LCD_MOSI_PORT, LCD_MOSI_PIN, 1)

    73. #define LCD_RES_Clr()  delay_us(1)//GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 0)//RES
    74. #define LCD_RES_Set()  delay_us(1)//GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 1)

    75. #define LCD_DC_Clr()   GPIO_PinWrite(LCD_DC_GPIO, LCD_DC_PORT, LCD_DC_PIN, 0)//DC
    76. #define LCD_DC_Set()   GPIO_PinWrite(LCD_DC_GPIO, LCD_DC_PORT, LCD_DC_PIN, 1)
    77.                      
    78. #define LCD_CS_Clr()   GPIO_PinWrite(LCD_SSEL0_GPIO, LCD_SSEL0_PORT, LCD_SSEL0_PIN, 0)//CS
    79. #define LCD_CS_Set()   GPIO_PinWrite(LCD_SSEL0_GPIO, LCD_SSEL0_PORT, LCD_SSEL0_PIN, 1)

    80. #define LCD_BLK_Clr()  delay_us(1)//GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 0)//BLK
    81. #define LCD_BLK_Set()  delay_us(1)//GPIO_PinWrite(LCD_SCK_GPIO, LCD_SCK_PORT, LCD_SCK_PIN, 1)


    82. #define SD_CS_Clr()   GPIO_PinWrite(SD_CS_GPIO, SD_CS_PORT, SD_CS_PIN, 0)//CS
    83. #define SD_CS_Set()   GPIO_PinWrite(SD_CS_GPIO, SD_CS_PORT, SD_CS_PIN, 1)


    84. u8 spi1_write_read_byte(u8 writedata);

    85. void LCD_GPIO_Init(void);//初始化GPIO
    86. void LCD_Writ_Bus(u8 dat);//模拟SPI时序
    87. void LCD_WR_DATA8(u8 dat);//写入一个字节
    88. void LCD_WR_DATA(u16 dat);//写入两个字节
    89. void LCD_WR_REG(u8 dat);//写入一个指令
    90. void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2);//设置坐标函数
    91. void LCD_Init(void);//LCD初始化
    92. #endif


    复制代码


    lcd_init.c
    1. #include "lcd_init.h"
    2. #include "peripherals.h"
    3. #include "delay.h"




    4. u8 spi1_write_read_byte(u8 writedata)
    5. {
    6.   u8 readdata=0;
    7.   //等待发送成功
    8.   while ((SPI1->STAT & SPI_STAT_TXRDY_MASK) == 0U)
    9.   {
    10.    
    11.   }  
    12.   SPI1->TXDAT = ((uint32_t)writedata & 0x0000FFFFU);
    13.   
    14.   while ((SPI1->STAT & SPI_STAT_RXRDY_MASK) == 0U)
    15.   {
    16.   }
    17.   readdata = SPI1->RXDAT;
    18.   
    19.   return readdata;
    20. }


    21. void LCD_GPIO_Init(void)
    22. {
    23.   SD_CS_Set();
    24.   
    25.   LCD_DC_Set();
    26.   LCD_CS_Set();
    27.   delay_ms(500);
    28. }


    29. /******************************************************************************
    30.       函数说明:LCD串行数据写入函数
    31.       入口数据:dat  要写入的串行数据
    32.       返回值:  无
    33. ******************************************************************************/
    34. void LCD_Writ_Bus(u8 dat)
    35. {        
    36.         u8 i;
    37.         LCD_CS_Clr();
    38.   spi1_write_read_byte(dat);
    39.   LCD_CS_Set();        
    40. }


    41. /******************************************************************************
    42.       函数说明:LCD写入数据
    43.       入口数据:dat 写入的数据
    44.       返回值:  无
    45. ******************************************************************************/
    46. void LCD_WR_DATA8(u8 dat)
    47. {
    48.         LCD_Writ_Bus(dat);
    49. }


    50. /******************************************************************************
    51.       函数说明:LCD写入数据
    52.       入口数据:dat 写入的数据
    53.       返回值:  无
    54. ******************************************************************************/
    55. void LCD_WR_DATA(u16 dat)
    56. {
    57.         LCD_Writ_Bus(dat>>8);
    58.         LCD_Writ_Bus(dat);
    59. }


    60. /******************************************************************************
    61.       函数说明:LCD写入命令
    62.       入口数据:dat 写入的命令
    63.       返回值:  无
    64. ******************************************************************************/
    65. void LCD_WR_REG(u8 dat)
    66. {
    67.         LCD_DC_Clr();//写命令
    68.         LCD_Writ_Bus(dat);
    69.         LCD_DC_Set();//写数据
    70. }


    71. /******************************************************************************
    72.       函数说明:设置起始和结束地址
    73.       入口数据:x1,x2 设置列的起始和结束地址
    74.                 y1,y2 设置行的起始和结束地址
    75.       返回值:  无
    76. ******************************************************************************/
    77. void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
    78. {
    79.         if(USE_HORIZONTAL==0)
    80.         {
    81.                 LCD_WR_REG(0x2a);//列地址设置
    82.                 LCD_WR_DATA(x1+2);
    83.                 LCD_WR_DATA(x2+2);
    84.                 LCD_WR_REG(0x2b);//行地址设置
    85.                 LCD_WR_DATA(y1+1);
    86.                 LCD_WR_DATA(y2+1);
    87.                 LCD_WR_REG(0x2c);//储存器写
    88.         }
    89.         else if(USE_HORIZONTAL==1)
    90.         {
    91.                 LCD_WR_REG(0x2a);//列地址设置
    92.                 LCD_WR_DATA(x1+2);
    93.                 LCD_WR_DATA(x2+2);
    94.                 LCD_WR_REG(0x2b);//行地址设置
    95.                 LCD_WR_DATA(y1+1);
    96.                 LCD_WR_DATA(y2+1);
    97.                 LCD_WR_REG(0x2c);//储存器写
    98.         }
    99.         else if(USE_HORIZONTAL==2)
    100.         {
    101.                 LCD_WR_REG(0x2a);//列地址设置
    102.                 LCD_WR_DATA(x1+1);
    103.                 LCD_WR_DATA(x2+1);
    104.                 LCD_WR_REG(0x2b);//行地址设置
    105.                 LCD_WR_DATA(y1+2);
    106.                 LCD_WR_DATA(y2+2);
    107.                 LCD_WR_REG(0x2c);//储存器写
    108.         }
    109.         else
    110.         {
    111.                 LCD_WR_REG(0x2a);//列地址设置
    112.                 LCD_WR_DATA(x1+1);
    113.                 LCD_WR_DATA(x2+1);
    114.                 LCD_WR_REG(0x2b);//行地址设置
    115.                 LCD_WR_DATA(y1+2);
    116.                 LCD_WR_DATA(y2+2);
    117.                 LCD_WR_REG(0x2c);//储存器写
    118.         }
    119. }

    120. void LCD_Init(void)
    121. {
    122.         LCD_GPIO_Init();//初始化GPIO
    123.         
    124.         LCD_RES_Clr();//复位
    125.         delay_ms(100);
    126.         LCD_RES_Set();
    127.         delay_ms(100);
    128.         
    129.         LCD_BLK_Set();//打开背光
    130.   delay_ms(100);
    131.         
    132.         //************* Start Initial Sequence **********//
    133.         LCD_WR_REG(0x11); //Sleep out
    134.         delay_ms(120);              //Delay 120ms
    135.         //------------------------------------ST7735S Frame Rate-----------------------------------------//
    136.         LCD_WR_REG(0xB1);
    137.         LCD_WR_DATA8(0x05);
    138.         LCD_WR_DATA8(0x3C);
    139.         LCD_WR_DATA8(0x3C);
    140.         LCD_WR_REG(0xB2);
    141.         LCD_WR_DATA8(0x05);
    142.         LCD_WR_DATA8(0x3C);
    143.         LCD_WR_DATA8(0x3C);
    144.         LCD_WR_REG(0xB3);
    145.         LCD_WR_DATA8(0x05);
    146.         LCD_WR_DATA8(0x3C);
    147.         LCD_WR_DATA8(0x3C);
    148.         LCD_WR_DATA8(0x05);
    149.         LCD_WR_DATA8(0x3C);
    150.         LCD_WR_DATA8(0x3C);
    151.         //------------------------------------End ST7735S Frame Rate---------------------------------//
    152.         LCD_WR_REG(0xB4); //Dot inversion
    153.         LCD_WR_DATA8(0x03);
    154.         //------------------------------------ST7735S Power Sequence---------------------------------//
    155.         LCD_WR_REG(0xC0);
    156.         LCD_WR_DATA8(0x28);
    157.         LCD_WR_DATA8(0x08);
    158.         LCD_WR_DATA8(0x04);
    159.         LCD_WR_REG(0xC1);
    160.         LCD_WR_DATA8(0XC0);
    161.         LCD_WR_REG(0xC2);
    162.         LCD_WR_DATA8(0x0D);
    163.         LCD_WR_DATA8(0x00);
    164.         LCD_WR_REG(0xC3);
    165.         LCD_WR_DATA8(0x8D);
    166.         LCD_WR_DATA8(0x2A);
    167.         LCD_WR_REG(0xC4);
    168.         LCD_WR_DATA8(0x8D);
    169.         LCD_WR_DATA8(0xEE);
    170.         //---------------------------------End ST7735S Power Sequence-------------------------------------//
    171.         LCD_WR_REG(0xC5); //VCOM
    172.         LCD_WR_DATA8(0x1A);
    173.         LCD_WR_REG(0x36); //MX, MY, RGB mode
    174.         if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
    175.         else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
    176.         else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
    177.         else LCD_WR_DATA8(0xA0);
    178.         //------------------------------------ST7735S Gamma Sequence---------------------------------//
    179.         LCD_WR_REG(0xE0);
    180.         LCD_WR_DATA8(0x04);
    181.         LCD_WR_DATA8(0x22);
    182.         LCD_WR_DATA8(0x07);
    183.         LCD_WR_DATA8(0x0A);
    184.         LCD_WR_DATA8(0x2E);
    185.         LCD_WR_DATA8(0x30);
    186.         LCD_WR_DATA8(0x25);
    187.         LCD_WR_DATA8(0x2A);
    188.         LCD_WR_DATA8(0x28);
    189.         LCD_WR_DATA8(0x26);
    190.         LCD_WR_DATA8(0x2E);
    191.         LCD_WR_DATA8(0x3A);
    192.         LCD_WR_DATA8(0x00);
    193.         LCD_WR_DATA8(0x01);
    194.         LCD_WR_DATA8(0x03);
    195.         LCD_WR_DATA8(0x13);
    196.         LCD_WR_REG(0xE1);
    197.         LCD_WR_DATA8(0x04);
    198.         LCD_WR_DATA8(0x16);
    199.         LCD_WR_DATA8(0x06);
    200.         LCD_WR_DATA8(0x0D);
    201.         LCD_WR_DATA8(0x2D);
    202.         LCD_WR_DATA8(0x26);
    203.         LCD_WR_DATA8(0x23);
    204.         LCD_WR_DATA8(0x27);
    205.         LCD_WR_DATA8(0x27);
    206.         LCD_WR_DATA8(0x25);
    207.         LCD_WR_DATA8(0x2D);
    208.         LCD_WR_DATA8(0x3B);
    209.         LCD_WR_DATA8(0x00);
    210.         LCD_WR_DATA8(0x01);
    211.         LCD_WR_DATA8(0x04);
    212.         LCD_WR_DATA8(0x13);
    213.         //------------------------------------End ST7735S Gamma Sequence-----------------------------//
    214.         LCD_WR_REG(0x3A); //65k mode
    215.         LCD_WR_DATA8(0x05);
    216.         LCD_WR_REG(0x29); //Display on
    217. }

    复制代码

    lcd.h
    1. #ifndef __LCD_H
    2. #define __LCD_H               
    3. #include "sys.h"
    4. #include <math.h>
    5. #include <stdlib.h>


    6. void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color);//指定区域填充颜色
    7. void LCD_DrawPoint(u16 x,u16 y,u16 color);//在指定位置画一个点
    8. void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2,u16 color);//在指定位置画一条线
    9. void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color);//在指定位置画一个矩形
    10. void Draw_Circle(u16 x0,u16 y0,u8 r,u16 color);//在指定位置画一个圆

    11. void LCD_ShowChinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示汉字串
    12. void LCD_ShowChinese12x12(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个12x12汉字
    13. void LCD_ShowChinese16x16(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个16x16汉字
    14. void LCD_ShowChinese24x24(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个24x24汉字
    15. void LCD_ShowChinese32x32(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个32x32汉字

    16. void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode);//显示一个字符
    17. void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode);//显示字符串
    18. u32 mypow(u8 m,u8 n);//求幂
    19. void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc,u8 sizey);//显示整数变量
    20. void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey);//显示两位小数变量

    21. void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[]);//显示图片


    22. //画笔颜色
    23. #define WHITE                  0xFFFF
    24. #define BLACK                  0x0000         
    25. #define BLUE                    0x001F  
    26. #define BRED             0XF81F
    27. #define GRED                                0XFFE0
    28. #define GBLUE                               0X07FF
    29. #define RED                    0xF800
    30. #define MAGENTA                0xF81F
    31. #define GREEN                  0x07E0
    32. #define CYAN                   0x7FFF
    33. #define YELLOW                 0xFFE0
    34. #define BROWN                              0XBC40 //棕色
    35. #define BRRED                              0XFC07 //棕红色
    36. #define GRAY                               0X8430 //灰色
    37. #define DARKBLUE               0X01CF        //深蓝色
    38. #define LIGHTBLUE               0X7D7C        //浅蓝色  
    39. #define GRAYBLUE                0X5458 //灰蓝色
    40. #define LIGHTGREEN              0X841F //浅绿色
    41. #define LGRAY                              0XC618 //浅灰色(PANNEL),窗体背景色
    42. #define LGRAYBLUE        0XA651 //浅灰蓝色(中间层颜色)
    43. #define LBBLUE           0X2B12 //浅棕蓝色(选择条目的反色)

    44. #endif

    复制代码

    lcd.c
    1. #include "lcd.h"
    2. #include "lcd_init.h"
    3. #include "lcdfont.h"
    4. #include "delay.h"


    5. /******************************************************************************
    6.       函数说明:在指定区域填充颜色
    7.       入口数据:xsta,ysta   起始坐标
    8.                 xend,yend   终止坐标
    9.                                                                 color       要填充的颜色
    10.       返回值:  无
    11. ******************************************************************************/
    12. void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color)
    13. {         
    14.         u16 i,j;
    15.         LCD_Address_Set(xsta,ysta,xend-1,yend-1);//设置显示范围
    16.         for(i=ysta;i<yend;i++)
    17.         {                                                                                                                           
    18.                 for(j=xsta;j<xend;j++)
    19.                 {
    20.                         LCD_WR_DATA(color);
    21.                 }
    22.         }                                                      
    23. }

    24. /******************************************************************************
    25.       函数说明:在指定位置画点
    26.       入口数据:x,y 画点坐标
    27.                 color 点的颜色
    28.       返回值:  无
    29. ******************************************************************************/
    30. void LCD_DrawPoint(u16 x,u16 y,u16 color)
    31. {
    32.         LCD_Address_Set(x,y,x,y);//设置光标位置
    33.         LCD_WR_DATA(color);
    34. }


    35. /******************************************************************************
    36.       函数说明:画线
    37.       入口数据:x1,y1   起始坐标
    38.                 x2,y2   终止坐标
    39.                 color   线的颜色
    40.       返回值:  无
    41. ******************************************************************************/
    42. void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2,u16 color)
    43. {
    44.         u16 t;
    45.         int xerr=0,yerr=0,delta_x,delta_y,distance;
    46.         int incx,incy,uRow,uCol;
    47.         delta_x=x2-x1; //计算坐标增量
    48.         delta_y=y2-y1;
    49.         uRow=x1;//画线起点坐标
    50.         uCol=y1;
    51.         if(delta_x>0)incx=1; //设置单步方向
    52.         else if (delta_x==0)incx=0;//垂直线
    53.         else {incx=-1;delta_x=-delta_x;}
    54.         if(delta_y>0)incy=1;
    55.         else if (delta_y==0)incy=0;//水平线
    56.         else {incy=-1;delta_y=-delta_y;}
    57.         if(delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
    58.         else distance=delta_y;
    59.         for(t=0;t<distance+1;t++)
    60.         {
    61.                 LCD_DrawPoint(uRow,uCol,color);//画点
    62.                 xerr+=delta_x;
    63.                 yerr+=delta_y;
    64.                 if(xerr>distance)
    65.                 {
    66.                         xerr-=distance;
    67.                         uRow+=incx;
    68.                 }
    69.                 if(yerr>distance)
    70.                 {
    71.                         yerr-=distance;
    72.                         uCol+=incy;
    73.                 }
    74.         }
    75. }


    76. /******************************************************************************
    77.       函数说明:画矩形
    78.       入口数据:x1,y1   起始坐标
    79.                 x2,y2   终止坐标
    80.                 color   矩形的颜色
    81.       返回值:  无
    82. ******************************************************************************/
    83. void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color)
    84. {
    85.         LCD_DrawLine(x1,y1,x2,y1,color);
    86.         LCD_DrawLine(x1,y1,x1,y2,color);
    87.         LCD_DrawLine(x1,y2,x2,y2,color);
    88.         LCD_DrawLine(x2,y1,x2,y2,color);
    89. }


    90. /******************************************************************************
    91.       函数说明:画圆
    92.       入口数据:x0,y0   圆心坐标
    93.                 r       半径
    94.                 color   圆的颜色
    95.       返回值:  无
    96. ******************************************************************************/
    97. void Draw_Circle(u16 x0,u16 y0,u8 r,u16 color)
    98. {
    99.         int a,b;
    100.         a=0;b=r;         
    101.         while(a<=b)
    102.         {
    103.                 LCD_DrawPoint(x0-b,y0-a,color);             //3           
    104.                 LCD_DrawPoint(x0+b,y0-a,color);             //0           
    105.                 LCD_DrawPoint(x0-a,y0+b,color);             //1               
    106.                 LCD_DrawPoint(x0-a,y0-b,color);             //2            
    107.                 LCD_DrawPoint(x0+b,y0+a,color);             //4               
    108.                 LCD_DrawPoint(x0+a,y0-b,color);             //5
    109.                 LCD_DrawPoint(x0+a,y0+b,color);             //6
    110.                 LCD_DrawPoint(x0-b,y0+a,color);             //7
    111.                 a++;
    112.                 if((a*a+b*b)>(r*r))//判断要画的点是否过远
    113.                 {
    114.                         b--;
    115.                 }
    116.         }
    117. }

    118. /******************************************************************************
    119.       函数说明:显示汉字串
    120.       入口数据:x,y显示坐标
    121.                 *s 要显示的汉字串
    122.                 fc 字的颜色
    123.                 bc 字的背景色
    124.                 sizey 字号 可选 16 24 32
    125.                 mode:  0非叠加模式  1叠加模式
    126.       返回值:  无
    127. ******************************************************************************/
    128. void LCD_ShowChinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    129. {
    130.         while(*s!=0)
    131.         {
    132.                 if(sizey==12) LCD_ShowChinese12x12(x,y,s,fc,bc,sizey,mode);
    133.                 else if(sizey==16) LCD_ShowChinese16x16(x,y,s,fc,bc,sizey,mode);
    134.                 else if(sizey==24) LCD_ShowChinese24x24(x,y,s,fc,bc,sizey,mode);
    135.                 else if(sizey==32) LCD_ShowChinese32x32(x,y,s,fc,bc,sizey,mode);
    136.                 else return;
    137.                 s+=2;
    138.                 x+=sizey;
    139.         }
    140. }

    141. /******************************************************************************
    142.       函数说明:显示单个12x12汉字
    143.       入口数据:x,y显示坐标
    144.                 *s 要显示的汉字
    145.                 fc 字的颜色
    146.                 bc 字的背景色
    147.                 sizey 字号
    148.                 mode:  0非叠加模式  1叠加模式
    149.       返回值:  无
    150. ******************************************************************************/
    151. void LCD_ShowChinese12x12(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    152. {
    153.         u8 i,j,m=0;
    154.         u16 k;
    155.         u16 HZnum;//汉字数目
    156.         u16 TypefaceNum;//一个字符所占字节大小
    157.         u16 x0=x;
    158.         TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    159.                                  
    160.         HZnum=sizeof(tfont12)/sizeof(typFNT_GB12);        //统计汉字数目
    161.         for(k=0;k<HZnum;k++)
    162.         {
    163.                 if((tfont12[k].Index[0]==*(s))&&(tfont12[k].Index[1]==*(s+1)))
    164.                 {         
    165.                         LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
    166.                         for(i=0;i<TypefaceNum;i++)
    167.                         {
    168.                                 for(j=0;j<8;j++)
    169.                                 {        
    170.                                         if(!mode)//非叠加方式
    171.                                         {
    172.                                                 if(tfont12[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
    173.                                                 else LCD_WR_DATA(bc);
    174.                                                 m++;
    175.                                                 if(m%sizey==0)
    176.                                                 {
    177.                                                         m=0;
    178.                                                         break;
    179.                                                 }
    180.                                         }
    181.                                         else//叠加方式
    182.                                         {
    183.                                                 if(tfont12[k].Msk[i]&(0x01<<j))        LCD_DrawPoint(x,y,fc);//画一个点
    184.                                                 x++;
    185.                                                 if((x-x0)==sizey)
    186.                                                 {
    187.                                                         x=x0;
    188.                                                         y++;
    189.                                                         break;
    190.                                                 }
    191.                                         }
    192.                                 }
    193.                         }
    194.                 }                                          
    195.                 continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
    196.         }
    197. }

    198. /******************************************************************************
    199.       函数说明:显示单个16x16汉字
    200.       入口数据:x,y显示坐标
    201.                 *s 要显示的汉字
    202.                 fc 字的颜色
    203.                 bc 字的背景色
    204.                 sizey 字号
    205.                 mode:  0非叠加模式  1叠加模式
    206.       返回值:  无
    207. ******************************************************************************/
    208. void LCD_ShowChinese16x16(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    209. {
    210.         u8 i,j,m=0;
    211.         u16 k;
    212.         u16 HZnum;//汉字数目
    213.         u16 TypefaceNum;//一个字符所占字节大小
    214.         u16 x0=x;
    215.   TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    216.         HZnum=sizeof(tfont16)/sizeof(typFNT_GB16);        //统计汉字数目
    217.         for(k=0;k<HZnum;k++)
    218.         {
    219.                 if ((tfont16[k].Index[0]==*(s))&&(tfont16[k].Index[1]==*(s+1)))
    220.                 {         
    221.                         LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
    222.                         for(i=0;i<TypefaceNum;i++)
    223.                         {
    224.                                 for(j=0;j<8;j++)
    225.                                 {        
    226.                                         if(!mode)//非叠加方式
    227.                                         {
    228.                                                 if(tfont16[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
    229.                                                 else LCD_WR_DATA(bc);
    230.                                                 m++;
    231.                                                 if(m%sizey==0)
    232.                                                 {
    233.                                                         m=0;
    234.                                                         break;
    235.                                                 }
    236.                                         }
    237.                                         else//叠加方式
    238.                                         {
    239.                                                 if(tfont16[k].Msk[i]&(0x01<<j))        LCD_DrawPoint(x,y,fc);//画一个点
    240.                                                 x++;
    241.                                                 if((x-x0)==sizey)
    242.                                                 {
    243.                                                         x=x0;
    244.                                                         y++;
    245.                                                         break;
    246.                                                 }
    247.                                         }
    248.                                 }
    249.                         }
    250.                 }                                          
    251.                 continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
    252.         }
    253. }


    254. /******************************************************************************
    255.       函数说明:显示单个24x24汉字
    256.       入口数据:x,y显示坐标
    257.                 *s 要显示的汉字
    258.                 fc 字的颜色
    259.                 bc 字的背景色
    260.                 sizey 字号
    261.                 mode:  0非叠加模式  1叠加模式
    262.       返回值:  无
    263. ******************************************************************************/
    264. void LCD_ShowChinese24x24(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    265. {
    266.         u8 i,j,m=0;
    267.         u16 k;
    268.         u16 HZnum;//汉字数目
    269.         u16 TypefaceNum;//一个字符所占字节大小
    270.         u16 x0=x;
    271.         TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    272.         HZnum=sizeof(tfont24)/sizeof(typFNT_GB24);        //统计汉字数目
    273.         for(k=0;k<HZnum;k++)
    274.         {
    275.                 if ((tfont24[k].Index[0]==*(s))&&(tfont24[k].Index[1]==*(s+1)))
    276.                 {         
    277.                         LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
    278.                         for(i=0;i<TypefaceNum;i++)
    279.                         {
    280.                                 for(j=0;j<8;j++)
    281.                                 {        
    282.                                         if(!mode)//非叠加方式
    283.                                         {
    284.                                                 if(tfont24[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
    285.                                                 else LCD_WR_DATA(bc);
    286.                                                 m++;
    287.                                                 if(m%sizey==0)
    288.                                                 {
    289.                                                         m=0;
    290.                                                         break;
    291.                                                 }
    292.                                         }
    293.                                         else//叠加方式
    294.                                         {
    295.                                                 if(tfont24[k].Msk[i]&(0x01<<j))        LCD_DrawPoint(x,y,fc);//画一个点
    296.                                                 x++;
    297.                                                 if((x-x0)==sizey)
    298.                                                 {
    299.                                                         x=x0;
    300.                                                         y++;
    301.                                                         break;
    302.                                                 }
    303.                                         }
    304.                                 }
    305.                         }
    306.                 }                                          
    307.                 continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
    308.         }
    309. }

    310. /******************************************************************************
    311.       函数说明:显示单个32x32汉字
    312.       入口数据:x,y显示坐标
    313.                 *s 要显示的汉字
    314.                 fc 字的颜色
    315.                 bc 字的背景色
    316.                 sizey 字号
    317.                 mode:  0非叠加模式  1叠加模式
    318.       返回值:  无
    319. ******************************************************************************/
    320. void LCD_ShowChinese32x32(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode)
    321. {
    322.         u8 i,j,m=0;
    323.         u16 k;
    324.         u16 HZnum;//汉字数目
    325.         u16 TypefaceNum;//一个字符所占字节大小
    326.         u16 x0=x;
    327.         TypefaceNum=(sizey/8+((sizey%8)?1:0))*sizey;
    328.         HZnum=sizeof(tfont32)/sizeof(typFNT_GB32);        //统计汉字数目
    329.         for(k=0;k<HZnum;k++)
    330.         {
    331.                 if ((tfont32[k].Index[0]==*(s))&&(tfont32[k].Index[1]==*(s+1)))
    332.                 {         
    333.                         LCD_Address_Set(x,y,x+sizey-1,y+sizey-1);
    334.                         for(i=0;i<TypefaceNum;i++)
    335.                         {
    336.                                 for(j=0;j<8;j++)
    337.                                 {        
    338.                                         if(!mode)//非叠加方式
    339.                                         {
    340.                                                 if(tfont32[k].Msk[i]&(0x01<<j))LCD_WR_DATA(fc);
    341.                                                 else LCD_WR_DATA(bc);
    342.                                                 m++;
    343.                                                 if(m%sizey==0)
    344.                                                 {
    345.                                                         m=0;
    346.                                                         break;
    347.                                                 }
    348.                                         }
    349.                                         else//叠加方式
    350.                                         {
    351.                                                 if(tfont32[k].Msk[i]&(0x01<<j))        LCD_DrawPoint(x,y,fc);//画一个点
    352.                                                 x++;
    353.                                                 if((x-x0)==sizey)
    354.                                                 {
    355.                                                         x=x0;
    356.                                                         y++;
    357.                                                         break;
    358.                                                 }
    359.                                         }
    360.                                 }
    361.                         }
    362.                 }                                          
    363.                 continue;  //查找到对应点阵字库立即退出,防止多个汉字重复取模带来影响
    364.         }
    365. }


    366. /******************************************************************************
    367.       函数说明:显示单个字符
    368.       入口数据:x,y显示坐标
    369.                 num 要显示的字符
    370.                 fc 字的颜色
    371.                 bc 字的背景色
    372.                 sizey 字号
    373.                 mode:  0非叠加模式  1叠加模式
    374.       返回值:  无
    375. ******************************************************************************/
    376. void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode)
    377. {
    378.         u8 temp,sizex,t,m=0;
    379.         u16 i,TypefaceNum;//一个字符所占字节大小
    380.         u16 x0=x;
    381.         sizex=sizey/2;
    382.         TypefaceNum=(sizex/8+((sizex%8)?1:0))*sizey;
    383.         num=num-' ';    //得到偏移后的值
    384.         LCD_Address_Set(x,y,x+sizex-1,y+sizey-1);  //设置光标位置
    385.         for(i=0;i<TypefaceNum;i++)
    386.         {
    387.                 if(sizey==12)temp=ascii_1206[num][i];                       //调用6x12字体
    388.                 else if(sizey==16)temp=ascii_1608[num][i];                 //调用8x16字体
    389.                 else if(sizey==24)temp=ascii_2412[num][i];                 //调用12x24字体
    390.                 else if(sizey==32)temp=ascii_3216[num][i];                 //调用16x32字体
    391.                 else return;
    392.                 for(t=0;t<8;t++)
    393.                 {
    394.                         if(!mode)//非叠加模式
    395.                         {
    396.                                 if(temp&(0x01<<t))LCD_WR_DATA(fc);
    397.                                 else LCD_WR_DATA(bc);
    398.                                 m++;
    399.                                 if(m%sizex==0)
    400.                                 {
    401.                                         m=0;
    402.                                         break;
    403.                                 }
    404.                         }
    405.                         else//叠加模式
    406.                         {
    407.                                 if(temp&(0x01<<t))LCD_DrawPoint(x,y,fc);//画一个点
    408.                                 x++;
    409.                                 if((x-x0)==sizex)
    410.                                 {
    411.                                         x=x0;
    412.                                         y++;
    413.                                         break;
    414.                                 }
    415.                         }
    416.                 }
    417.         }                     
    418. }


    419. /******************************************************************************
    420.       函数说明:显示字符串
    421.       入口数据:x,y显示坐标
    422.                 *p 要显示的字符串
    423.                 fc 字的颜色
    424.                 bc 字的背景色
    425.                 sizey 字号
    426.                 mode:  0非叠加模式  1叠加模式
    427.       返回值:  无
    428. ******************************************************************************/
    429. void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode)
    430. {         
    431.         while(*p!='\0')
    432.         {      
    433.                 LCD_ShowChar(x,y,*p,fc,bc,sizey,mode);
    434.                 x+=sizey/2;
    435.                 p++;
    436.         }  
    437. }


    438. /******************************************************************************
    439.       函数说明:显示数字
    440.       入口数据:m底数,n指数
    441.       返回值:  无
    442. ******************************************************************************/
    443. u32 mypow(u8 m,u8 n)
    444. {
    445.         u32 result=1;         
    446.         while(n--)result*=m;
    447.         return result;
    448. }


    449. /******************************************************************************
    450.       函数说明:显示整数变量
    451.       入口数据:x,y显示坐标
    452.                 num 要显示整数变量
    453.                 len 要显示的位数
    454.                 fc 字的颜色
    455.                 bc 字的背景色
    456.                 sizey 字号
    457.       返回值:  无
    458. ******************************************************************************/
    459. void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc,u8 sizey)
    460. {                 
    461.         u8 t,temp;
    462.         u8 enshow=0;
    463.         u8 sizex=sizey/2;
    464.         for(t=0;t<len;t++)
    465.         {
    466.                 temp=(num/mypow(10,len-t-1))%10;
    467.                 if(enshow==0&&t<(len-1))
    468.                 {
    469.                         if(temp==0)
    470.                         {
    471.                                 LCD_ShowChar(x+t*sizex,y,' ',fc,bc,sizey,0);
    472.                                 continue;
    473.                         }else enshow=1;
    474.                           
    475.                 }
    476.                  LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
    477.         }
    478. }


    479. /******************************************************************************
    480.       函数说明:显示两位小数变量
    481.       入口数据:x,y显示坐标
    482.                 num 要显示小数变量
    483.                 len 要显示的位数
    484.                 fc 字的颜色
    485.                 bc 字的背景色
    486.                 sizey 字号
    487.       返回值:  无
    488. ******************************************************************************/
    489. void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey)
    490. {                 
    491.         u8 t,temp,sizex;
    492.         u16 num1;
    493.         sizex=sizey/2;
    494.         num1=num*100;
    495.         for(t=0;t<len;t++)
    496.         {
    497.                 temp=(num1/mypow(10,len-t-1))%10;
    498.                 if(t==(len-2))
    499.                 {
    500.                         LCD_ShowChar(x+(len-2)*sizex,y,'.',fc,bc,sizey,0);
    501.                         t++;
    502.                         len+=1;
    503.                 }
    504.                  LCD_ShowChar(x+t*sizex,y,temp+48,fc,bc,sizey,0);
    505.         }
    506. }


    507. /******************************************************************************
    508.       函数说明:显示图片
    509.       入口数据:x,y起点坐标
    510.                 length 图片长度
    511.                 width  图片宽度
    512.                 pic[]  图片数组   
    513.       返回值:  无
    514. ******************************************************************************/
    515. void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[])
    516. {
    517.         u16 i,j;
    518.         u32 k=0;
    519.         LCD_Address_Set(x,y,x+length-1,y+width-1);
    520.         for(i=0;i<length;i++)
    521.         {
    522.                 for(j=0;j<width;j++)
    523.                 {
    524.                         LCD_WR_DATA8(pic[k*2]);
    525.                         LCD_WR_DATA8(pic[k*2+1]);
    526.                         k++;
    527.                 }
    528.         }                        
    529. }


    复制代码

    sd.h
    1. #ifndef _SD_H__
    2. #define _SD_H__                 
    3. #include <stdio.h>
    4. #include "pin_mux.h"
    5. #include "clock_config.h"
    6. #include "lcd_init.h"


    7. #include "ff.h"
    8. #include "diskio.h"
    9. #include "fatfs_storage.h"
    10.                                                                               

    11. #define SD_TYPE_ERR     0X00
    12. #define SD_TYPE_MMC     0X01
    13. #define SD_TYPE_V1      0X02
    14. #define SD_TYPE_V2      0X04
    15. #define SD_TYPE_V2HC    0X06           
    16.    
    17. #define CMD0    0      
    18. #define CMD1    1
    19. #define CMD8    8      
    20. #define CMD9    9      
    21. #define CMD10   10      
    22. #define CMD12   12      
    23. #define CMD16   16      
    24. #define CMD17   17      
    25. #define CMD18   18      
    26. #define CMD23   23      
    27. #define CMD24   24      
    28. #define CMD25   25      
    29. #define CMD41   41      
    30. #define CMD55   55      
    31. #define CMD58   58      
    32. #define CMD59   59     

    33. #define MSD_DATA_OK                0x05
    34. #define MSD_DATA_CRC_ERROR         0x0B
    35. #define MSD_DATA_WRITE_ERROR       0x0D
    36. #define MSD_DATA_OTHER_ERROR       0xFF

    37. #define MSD_RESPONSE_NO_ERROR      0x00
    38. #define MSD_IN_IDLE_STATE          0x01
    39. #define MSD_ERASE_RESET            0x02
    40. #define MSD_ILLEGAL_COMMAND        0x04
    41. #define MSD_COM_CRC_ERROR          0x08
    42. #define MSD_ERASE_SEQUENCE_ERROR   0x10
    43. #define MSD_ADDRESS_ERROR          0x20
    44. #define MSD_PARAMETER_ERROR        0x40
    45. #define MSD_RESPONSE_FAILURE       0xFF


    46. #define  MAX_BMP_FILES  25



    47. #define __SD_CS_SET()          SD_CS_Set()
    48. #define __SD_CS_CLR()          SD_CS_Clr()


    49. #define __SD_WRITE_BYTE(__DATA)  spi1_write_read_byte(__DATA)




    50. extern uint8_t  SD_Type;


    51. void SD_port_init(void);
    52. uint8_t SD_SPI_ReadWriteByte(uint8_t data);
    53. void SD_SPI_SpeedLow(void);
    54. void SD_SPI_SpeedHigh(void);
    55. uint8_t SD_WaitReady(void);                                                            
    56. uint8_t SD_GetResponse(uint8_t Response);                                       
    57. uint8_t SD_Initialize(void);                                                        
    58. uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);               
    59. uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt);               
    60. uint32_t SD_GetSectorCount(void);                                          
    61. uint8_t SD_GetCID(uint8_t *cid_data);                     
    62. uint8_t SD_GetCSD(uint8_t *csd_data);                     

    63. #endif
    复制代码

    sd.c
    1. #include "sd.h"                           
    2. #include "peripherals.h"

    3.                                                                                       
    4. uint8_t  SD_Type=0;  //version of the sd card


    5. void SD_port_init(void)
    6. {
    7.         __SD_CS_SET();

    8. }

    9. //data: data to be written to sd card.
    10. //return: data read from sd card.
    11. uint8_t SD_SPI_ReadWriteByte(uint8_t data)
    12. {
    13.         return __SD_WRITE_BYTE(data);
    14. }         

    15. //set spi in low speed mode.
    16. void SD_SPI_SpeedLow(void)
    17. {
    18. //    SPI1->CR1&=0XFFC7;
    19. //        SPI1->CR1|=SPI_BaudRatePrescaler_256;
    20.         //SPI_Cmd(SPI1,ENABLE);
    21. }


    22. //set spi in high speed mode.
    23. void SD_SPI_SpeedHigh(void)
    24. {
    25. //    SPI1->CR1&=0XFFC7;
    26. //        SPI1->CR1|=SPI_BaudRatePrescaler_32;
    27.         //SPI_Cmd(SPI1,ENABLE);
    28. }


    29. //released spi bus
    30. void SD_DisSelect(void)
    31. {
    32.         __SD_CS_SET();
    33.          SD_SPI_ReadWriteByte(0xff);//providing extra 8 clocks  
    34. }

    35. //pick sd card and waiting until until it's ready
    36. //return: 0: succed 1: failure
    37. uint8_t SD_Select(void)
    38. {
    39.         __SD_CS_CLR();
    40.         if(SD_WaitReady()==0)return 0;
    41.         SD_DisSelect();
    42.         return 1;
    43. }

    44. //waiting for sd card until it's ready
    45. uint8_t SD_WaitReady(void)
    46. {
    47.         uint32_t t=0;
    48.         do
    49.         {
    50.                 if(SD_SPI_ReadWriteByte(0XFF)==0XFF)return 0;
    51.                 t++;                          
    52.         }while(t<0XFFFFFF);
    53.         return 1;
    54. }

    55. //waiting for response from sd card.
    56. //Response: expect from sd card.
    57. //return: succeed for 0, fail for other else
    58. //return: 0 for success, other for failure.   
    59. uint8_t SD_GetResponse(uint8_t Response)
    60. {
    61.         uint16_t Count=0xFFFF;                                                            
    62.         while ((SD_SPI_ReadWriteByte(0XFF)!=Response)&&Count)Count--;           
    63.         if (Count==0)return MSD_RESPONSE_FAILURE;  
    64.         else return MSD_RESPONSE_NO_ERROR;
    65. }

    66. //read a buffer from sd card.
    67. //*buf: pointer to a buffer.
    68. //len: length of the buffer.
    69. //return: 0 for success, other for failure.   
    70. uint8_t SD_RecvData(uint8_t*buf,uint16_t len)
    71. {                                    
    72.         if(SD_GetResponse(0xFE))return 1;//waiting for start command send back from sd card.
    73.     while(len--)//receiving data...
    74.     {
    75.         *buf=__SD_WRITE_BYTE(0xFF);
    76.         buf++;
    77.     }

    78.     //send 2 dummy write (dummy CRC)
    79.     SD_SPI_ReadWriteByte(0xFF);
    80.     SD_SPI_ReadWriteByte(0xFF);                                                                                                                     
    81.     return 0;
    82. }

    83. //write a buffer containing 512 bytes to sd card.
    84. //buf: data buffer
    85. //cmd: command
    86. //return: 0 for success, other for failure.   
    87. uint8_t SD_SendBlock(uint8_t*buf,uint8_t cmd)
    88. {        
    89.         uint16_t t;                           
    90.         if(SD_WaitReady())return 1;
    91.         SD_SPI_ReadWriteByte(cmd);
    92.         if(cmd!=0XFD)
    93.         {
    94.                 for(t=0;t<512;t++)__SD_WRITE_BYTE(buf[t]);
    95.             SD_SPI_ReadWriteByte(0xFF);//ignoring CRC
    96.             SD_SPI_ReadWriteByte(0xFF);
    97.                 t=SD_SPI_ReadWriteByte(0xFF);
    98.                 if((t&0x1F)!=0x05)return 2;                                                                                                              
    99.         }                                                                                                                                                                       
    100.     return 0;
    101. }


    102. //send a command to sd card
    103. //cmd??command
    104. //arg: parameter
    105. //crc: crc
    106. //return: response sent back from sd card.
    107. uint8_t SD_SendCmd(uint8_t cmd, uint32_t arg, uint8_t crc)
    108. {
    109.     uint8_t r1;        
    110.         uint8_t Retry=0;
    111.         SD_DisSelect();
    112.         if(SD_Select())return 0XFF;

    113.     SD_SPI_ReadWriteByte(cmd | 0x40);
    114.     SD_SPI_ReadWriteByte(arg >> 24);
    115.     SD_SPI_ReadWriteByte(arg >> 16);
    116.     SD_SPI_ReadWriteByte(arg >> 8);
    117.     SD_SPI_ReadWriteByte(arg);         
    118.     SD_SPI_ReadWriteByte(crc);
    119.         if(cmd==CMD12)SD_SPI_ReadWriteByte(0xff); //Skip a stuff byte when stop reading
    120.         Retry=0X1F;
    121.         do
    122.         {
    123.                 r1=SD_SPI_ReadWriteByte(0xFF);
    124.         }while((r1&0X80) && Retry--);         

    125.     return r1;
    126. }


    127. //obtain CID including manufacturer informationfrom sd card  
    128. //*cid_dat: pointer to the buffer storing CID, at least 16 bytes.
    129. //return: 0 no error  1 error
    130. uint8_t SD_GetCID(uint8_t *cid_data)
    131. {
    132.     uint8_t r1;           

    133.     r1=SD_SendCmd(CMD10,0,0x01);
    134.     if(r1==0x00)
    135.         {
    136.                 r1=SD_RecvData(cid_data,16);         
    137.     }
    138.         SD_DisSelect();
    139.         if(r1)return 1;
    140.         else return 0;
    141. }                                                                                                                                                                  

    142. //obtain CSD including storage and speed.
    143. //*csd_data : pointer to the buffer storing CSD, at least 16 bytes.
    144. //return: 0 no error  1 error
    145. uint8_t SD_GetCSD(uint8_t *csd_data)
    146. {
    147.     uint8_t r1;         
    148.     r1=SD_SendCmd(CMD9,0,0x01);//??CMD9??????CSD send CMD9 in order to get CSD
    149.     if(r1==0)
    150.         {
    151.             r1=SD_RecvData(csd_data, 16);
    152.     }
    153.         SD_DisSelect();
    154.         if(r1)return 1;
    155.         else return 0;
    156. }  

    157. //obtian the totals of sectors of sd card.
    158. //return: 0 error, other else for storage of sd card.
    159. //numbers of bytes of each sector must be 512, otherwise fail to initialization.  
    160. uint32_t SD_GetSectorCount(void)
    161. {
    162.     uint8_t csd[16];
    163.     uint32_t Capacity;  
    164.     uint8_t n;
    165.         uint16_t csize;                                             
    166.         
    167.     if(SD_GetCSD(csd)!=0) return 0;            
    168.     //calculation for SDHC below
    169.     if((csd[0]&0xC0)==0x40)         //V2.00
    170.     {        
    171.                 csize = csd[9] + ((uint16_t)csd[8] << 8) + 1;
    172.                 Capacity = (uint32_t)csize << 10;  //totals of sectors                    
    173.     }else//V1.XX
    174.     {        
    175.                 n = (csd[5] & 15) + ((csd[10] & 128) >> 7) + ((csd[9] & 3) << 1) + 2;
    176.                 csize = (csd[8] >> 6) + ((uint16_t)csd[7] << 2) + ((uint16_t)(csd[6] & 3) << 10) + 1;
    177.                 Capacity= (uint32_t)csize << (n - 9);
    178.     }
    179.     return Capacity;
    180. }

    181. //initialize sd card
    182. uint8_t SD_Initialize(void)
    183. {
    184.     uint8_t r1;      
    185.     uint16_t retry;  
    186.     uint8_t buf[4];  
    187.         uint16_t i;
    188.    
    189.     __SD_CS_SET();
    190.          SD_SPI_SpeedLow();        
    191.          for(i=0;i<10;i++)SD_SPI_ReadWriteByte(0XFF);
    192.         retry=20;
    193.         do
    194.         {
    195.                 r1=SD_SendCmd(CMD0,0,0x95);//enter to idle state
    196.         }while((r1!=0X01) && retry--);
    197.          SD_Type=0;
    198.    
    199.         if(r1==0X01)
    200.         {
    201.                 if(SD_SendCmd(CMD8,0x1AA,0x87)==1)//SD V2.0
    202.                 {
    203.                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);        //Get trailing return value of R7 resp
    204.                         if(buf[2]==0X01&&buf[3]==0XAA)//is it support of 2.7~3.6V
    205.                         {
    206.                                 retry=0XFFFE;
    207.                                 do
    208.                                 {
    209.                                         SD_SendCmd(CMD55,0,0X01);        
    210.                                         r1=SD_SendCmd(CMD41,0x40000000,0X01);
    211.                                 }while(r1&&retry--);
    212.                                 if(retry&&SD_SendCmd(CMD58,0,0X01)==0) //start to identify the SD2.0 version of sd card.
    213.                                 {
    214.                                         for(i=0;i<4;i++)buf[i]=SD_SPI_ReadWriteByte(0XFF);//get OCR
    215.                                         if(buf[0]&0x40)SD_Type=SD_TYPE_V2HC;    //check CCS
    216.                                         else SD_Type=SD_TYPE_V2;   
    217.                                 }
    218.                         }
    219.                 }else//SD V1.x/ MMC        V3
    220.                 {
    221.                         SD_SendCmd(CMD55,0,0X01);               
    222.                         r1=SD_SendCmd(CMD41,0,0X01);        
    223.                         if(r1<=1)
    224.                         {               
    225.                                 SD_Type=SD_TYPE_V1;
    226.                                 retry=0XFFFE;
    227.                                 do //exit idle state
    228.                                 {
    229.                                         SD_SendCmd(CMD55,0,0X01);        
    230.                                         r1=SD_SendCmd(CMD41,0,0X01);
    231.                                 }while(r1&&retry--);
    232.                         }else
    233.                         {
    234.                                 SD_Type=SD_TYPE_MMC;//MMC V3
    235.                                 retry=0XFFFE;
    236.                                 do
    237.                                 {                                                                                            
    238.                                         r1=SD_SendCmd(CMD1,0,0X01);
    239.                                 }while(r1&&retry--);  
    240.                         }
    241.                         if(retry==0||SD_SendCmd(CMD16,512,0X01)!=0)SD_Type=SD_TYPE_ERR;
    242.                 }
    243.         }
    244.         SD_DisSelect();
    245.         SD_SPI_SpeedHigh();
    246.         if(SD_Type)return 0;
    247.         else if(r1)return r1;            
    248.         return 0xaa;
    249. }


    250. //read SD card
    251. //buf: data buffer
    252. //sector: sector
    253. //cnt: totals of sectors]
    254. //return: 0 ok, other for failure
    255. uint8_t SD_ReadDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
    256. {
    257.         uint8_t r1;
    258.         if(SD_Type!=SD_TYPE_V2HC)sector <<= 9;
    259.         if(cnt==1)
    260.         {
    261.                 r1=SD_SendCmd(CMD17,sector,0X01);
    262.                 if(r1==0)
    263.                 {
    264.                         r1=SD_RecvData(buf,512);   
    265.                 }
    266.         }else
    267.         {
    268.                 r1=SD_SendCmd(CMD18,sector,0X01);
    269.                 do
    270.                 {
    271.                         r1=SD_RecvData(buf,512);
    272.                         buf+=512;  
    273.                 }while(--cnt && r1==0);         
    274.                 SD_SendCmd(CMD12,0,0X01);        
    275.         }   
    276.         SD_DisSelect();
    277.         return r1;//
    278. }


    279. //write sd card
    280. //buf: data buffer
    281. //sector: start sector
    282. //cnt: totals of sectors]
    283. //return: 0 ok, other for failure
    284. uint8_t SD_WriteDisk(uint8_t*buf,uint32_t sector,uint8_t cnt)
    285. {
    286.         uint8_t r1;
    287.         if(SD_Type!=SD_TYPE_V2HC)sector *= 512;
    288.         if(cnt==1)
    289.         {
    290.                 r1=SD_SendCmd(CMD24,sector,0X01);
    291.                 if(r1==0)
    292.                 {
    293.                         r1=SD_SendBlock(buf,0xFE);
    294.                 }
    295.         }else
    296.         {
    297.                 if(SD_Type!=SD_TYPE_MMC)
    298.                 {
    299.                         SD_SendCmd(CMD55,0,0X01);        
    300.                         SD_SendCmd(CMD23,cnt,0X01);        
    301.                 }
    302.                  r1=SD_SendCmd(CMD25,sector,0X01);
    303.                 if(r1==0)
    304.                 {
    305.                         do
    306.                         {
    307.                                 r1=SD_SendBlock(buf,0xFC);
    308.                                 buf+=512;  
    309.                         }while(--cnt && r1==0);
    310.                         r1=SD_SendBlock(0,0xFD);
    311.                 }
    312.         }   
    313.         SD_DisSelect();
    314.         return r1;
    315. }           

    复制代码
    其中还移植了FATFS系统,通过FATFS来软解BMP图片。FATFS具体移植就不多说了,BMP解码关键程序:
    1. #include "sys.h"
    2. #include <string.h>
    3. #include "sd.h"       
    4. #include "lcd.h"       
    5. #include "lcd_init.h"

    6. /** @addtogroup STM32_Nucleo_Demo
    7. * @{
    8. */

    9. /** @defgroup STORAGE
    10. * @brief This file includes the Storage (FatFs) driver for the STM32 Nucleo demo
    11. * @{
    12. */

    13. /** @defgroup STORAGE_Private_Types
    14. * @{
    15. */
    16. /**
    17. * @}
    18. */

    19. /** @defgroup STORAGE_Private_Defines
    20. * @{
    21. */
    22. /**
    23. * @}
    24. */

    25. /** @defgroup STORAGE_Private_Macros
    26. * @{
    27. */
    28. /**
    29. * @}
    30. */

    31. /** @defgroup STORAGE_Private_Variables
    32. * @{
    33. */

    34. uint8_t aBuffer[960];
    35. FILINFO MyFileInfo;
    36. DIR MyDirectory;
    37. FIL MyFile;
    38. UINT BytesWritten;
    39. UINT BytesRead;

    40. /**
    41. * @}
    42. */


    43. /** @defgroup STORAGE_Private_FunctionPrototypes
    44. * @{
    45. */
    46. /**
    47. * @}
    48. */

    49. /** @defgroup STORAGE_Private_Functions
    50. * @{
    51. */




    52. /**
    53. * @brief  Open a file and copy its content to a buffer
    54. * @param  DirName: the Directory name to open
    55. * @param  FileName: the file name to open
    56. * @param  BufferAddress: A pointer to a buffer to copy the file to
    57. * @param  FileLen: the File length
    58. * @retval err: Error status (0=> success, 1=> fail)
    59. */

    60. //#define LCD_W 128
    61. //#define LCD_H 160


    62. #define PIXEL(__M)  ((((__M) + 31 ) >> 5) << 2)
    63. uint32_t Storage_OpenReadFile(uint8_t Xpoz, uint16_t Ypoz,uint8_t pic_w, uint8_t pic_h,const char* BmpName)
    64. {
    65.     uint16_t i, j, k;
    66.    
    67.     uint32_t index = 0, size = 0, width = 0, height = 0;
    68.     uint32_t bmpaddress, bit_pixel = 0;
    69.     FIL file1;
    70.     uint16_t color = 0;
    71.   
    72.     uint16_t pic_h_t=0,pic_w_t=0; //实际位置为起点的长宽的终点位置   不能超过屏幕长宽最大值

    73.     f_open(&file1, BmpName, FA_READ);
    74.     f_read(&file1, aBuffer, 30, &BytesRead);

    75.     bmpaddress = (uint32_t)aBuffer;

    76.     /* Read bitmap size */
    77.     size = *(uint16_t *) (bmpaddress + 2);
    78.     size |= (*(uint16_t *) (bmpaddress + 4)) << 16;

    79.     /* Get bitmap data address offset */
    80.     index = *(uint16_t *) (bmpaddress + 10);
    81.     index |= (*(uint16_t *) (bmpaddress + 12)) << 16;

    82.     /* Read bitmap width */
    83.     width = *(uint16_t *) (bmpaddress + 18);
    84.     width |= (*(uint16_t *) (bmpaddress + 20)) << 16;

    85.     /* Read bitmap height */
    86.     height = *(uint16_t *) (bmpaddress + 22);
    87.     height |= (*(uint16_t *) (bmpaddress + 24)) << 16;

    88.     /* Read bit/pixel */
    89.     bit_pixel = *(uint16_t *) (bmpaddress + 28);  
    90.     f_close (&file1);

    91.     if (24 != bit_pixel) {
    92.         return 0;
    93.     }
    94.    
    95.     /* Synchronize f_read right in front of the image data */
    96.     f_open (&file1, (TCHAR const*)BmpName, FA_READ);  
    97.     f_read(&file1, aBuffer, index, &BytesRead);
    98.    
    99.     for (i = 0; i < pic_h; i ++) {
    100.         f_read(&file1, aBuffer, PIXEL(pic_w * bit_pixel) >> 1, (UINT *)&BytesRead);
    101.         f_read(&file1, aBuffer + (PIXEL(pic_w * bit_pixel) >> 1), PIXEL(pic_w * bit_pixel) >> 1, (UINT *)&BytesRead);
    102.         
    103.         //lcd_set_cursor(Xpoz + 0, Ypoz + i);
    104.         //LCD_Address_Set(Xpoz + 0, Ypoz + i,Xpoz + 0, Ypoz + i);
    105.         //计算绘图区域的实际终点
    106.         pic_h_t=Ypoz + i;     if(pic_h_t>=LCD_H) pic_h_t=LCD_H;
    107.         pic_w_t=Xpoz+pic_w;   if(pic_w_t>=LCD_W) pic_w_t=LCD_W;
    108.         LCD_Address_Set(Xpoz + 0, Ypoz + i,pic_w_t, pic_h_t);
    109.         //lcd_write_byte(0x22, LCD_CMD);
    110.         //LCD_WR_REG(0X22);
    111.         for (j = 0; j < pic_w; j ++) {
    112.             k = j * 3;
    113.             color = (uint16_t)(((aBuffer[k + 2] >> 3) << 11 ) | ((aBuffer[k + 1] >> 2) << 5) | (aBuffer[k] >> 3));
    114.             //lcd_draw_point(Xpoz + j, Ypoz + i, color);
    115.             LCD_WR_DATA(color);
    116.             
    117.         }
    118.     }
    119.    
    120.     f_close(&file1);
    121.    
    122.     return 1;
    123. }


    124. /**
    125. * @brief  Copy file BmpName1 to BmpName2
    126. * @param  BmpName1: the source file name
    127. * @param  BmpName2: the destination file name
    128. * @retval err: Error status (0=> success, 1=> fail)
    129. */
    130. uint32_t Storage_CopyFile(const char* BmpName1, const char* BmpName2)
    131. {
    132.   uint32_t index = 0;
    133.   FIL file1, file2;
    134.   
    135.   /* Open an Existent BMP file system */
    136.   f_open(&file1, BmpName1, FA_READ);
    137.   /* Create a new BMP file system */
    138.   f_open(&file2, BmpName2, FA_CREATE_ALWAYS | FA_WRITE);
    139.   
    140.   do
    141.   {
    142.     f_read(&file1, aBuffer, _MAX_SS, &BytesRead);
    143.     f_write(&file2, aBuffer, _MAX_SS, &BytesWritten);  
    144.     index+= _MAX_SS;
    145.    
    146.   } while(index < file1.fsize);
    147.   
    148.   f_close(&file1);
    149.   f_close(&file2);
    150.   
    151.   return 1;
    152. }

    153. /**
    154. * @brief  Opens a file and copies its content to a buffer.
    155. * @param  DirName: the Directory name to open
    156. * @param  FileName: the file name to open
    157. * @param  BufferAddress: A pointer to a buffer to copy the file to
    158. * @param  FileLen: File length
    159. * @retval err: Error status (0=> success, 1=> fail)
    160. */
    161. uint32_t Storage_CheckBitmapFile(const char* BmpName, uint32_t *FileLen)
    162. {
    163.     uint32_t err = 0;
    164.     if(f_open(&MyFile, BmpName, FA_READ) != FR_OK)
    165.     {
    166.         err = 2;
    167.     }
    168.    
    169.   return err;
    170. }

    171. /**
    172. * @brief  List up to 25 file on the root directory with extension .BMP
    173. * @param  DirName: Directory name
    174. * @param  Files: Buffer to contain read files
    175. * @retval The number of the found files
    176. */
    177. uint32_t Storage_GetDirectoryBitmapFiles(const char* DirName, char* Files[])
    178. {
    179.   uint32_t i = 0, j = 0;
    180.   FRESULT res;
    181.    
    182.   res = f_opendir(&MyDirectory, DirName);
    183.   
    184.   if(res == FR_OK)
    185.   {
    186.     i = strlen(DirName);
    187.     for (;;)
    188.     {
    189.       res = f_readdir(&MyDirectory, &MyFileInfo);
    190.       if(res != FR_OK || MyFileInfo.fname[0] == 0) break;
    191.       if(MyFileInfo.fname[0] == '.') continue;
    192.       
    193.       if(!(MyFileInfo.fattrib & AM_DIR))
    194.       {
    195.         do
    196.         {
    197.           i++;
    198.         }
    199.         while (MyFileInfo.fname[i] != 0x2E);
    200.         
    201.         
    202.         if(j < MAX_BMP_FILES)
    203.         {
    204.           if((MyFileInfo.fname[i + 1] == 'B') && (MyFileInfo.fname[i + 2] == 'M') && (MyFileInfo.fname[i + 3] == 'P'))
    205.           {
    206.             sprintf(Files[j], "%-11.11s", MyFileInfo.fname);
    207.             j++;
    208.           }
    209.         }
    210.         i = 0;
    211.       }
    212.     }
    213.   }
    214.    
    215.   return j;
    216. }

    217. /**
    218.   * @brief  Compares two buffers.
    219.   * @param  pBuffer1, pBuffer2: buffers to be compared
    220.   * @param  BufferLength: buffer's length
    221.   * @retval  0: pBuffer1 identical to pBuffer2
    222.   *          1: pBuffer1 differs from pBuffer2
    223.   */
    224. uint8_t Buffercmp(uint8_t* pBuffer1, uint8_t* pBuffer2, uint16_t BufferLength)
    225. {
    226.   uint8_t ret = 1;
    227.   while (BufferLength--)
    228.   {
    229.     if(*pBuffer1 != *pBuffer2)
    230.     {
    231.       ret = 0;
    232.     }
    233.    
    234.     pBuffer1++;
    235.     pBuffer2++;
    236.   }
    237.   
    238.   return ret;
    239. }
    复制代码


    下载,查看屏幕:
    A2.jpg
    AA[00_00_11--00_00_31].gif


    哎...今天够累的,签到来了~
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2025-7-11 08:53
  • 签到天数: 301 天

    连续签到: 2 天

    [LV.8]以坛为家I

    3877

    主题

    7482

    帖子

    0

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    39319
    最后登录
    2025-7-23
    发表于 2021-9-17 11:12:46 | 显示全部楼层
    NICE!!!
    qiandao qiandao
    回复

    使用道具 举报

  • TA的每日心情
    开心
    2025-6-10 23:03
  • 签到天数: 1502 天

    连续签到: 1 天

    [LV.Master]伴坛终老

    97

    主题

    4688

    帖子

    12

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    10080
    最后登录
    2025-7-2
    发表于 2021-9-17 14:40:32 | 显示全部楼层
    楼主 厉害呀!
    这小板子设计的,羡慕死我了
    该会员没有填写今日想说内容.
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    奋斗
    昨天 09:28
  • 签到天数: 2374 天

    连续签到: 83 天

    [LV.Master]伴坛终老

    84

    主题

    1万

    帖子

    3

    版主

    Rank: 7Rank: 7Rank: 7

    积分
    21996
    最后登录
    2025-7-23
    发表于 2021-9-17 14:49:28 | 显示全部楼层
    漂亮
    该会员没有填写今日想说内容.
    回复

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /3 下一条

    Archiver|手机版|小黑屋|恩智浦技术社区

    GMT+8, 2025-7-24 00:19 , Processed in 0.101767 second(s), 23 queries , MemCache On.

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.

    快速回复 返回顶部 返回列表