尝试移植标准库的fsmc驱动lcd到HAL驱动(完成)

看了好几遍官方的bsp显示器驱动  终于看懂为啥以前的驱动写个有问题。零知的芯片是F407,它的fsmc针脚定义跟f103是不一样的。错在了针脚的初始化上 。这个给出完整的arduino驱动。测试正常

新建一个generic 103工程,在pio.ini;里启动fsmc功能  .(最后一句)

 

main.c。这个修改了时钟。主频72、不修改也可以用  主频 48 。刷屏速度会慢

 

#include <Arduino.h>

#include "WB_LCD.h"

void SystemClock_Config(void)
{
    RCC_OscInitTypeDef RCC_OscInitStruct = {};
    RCC_ClkInitTypeDef RCC_ClkInitStruct = {};
    RCC_PeriphCLKInitTypeDef PeriphClkInit = {};

    /** Initializes the RCC Oscillators according to the specified parameters
     * in the RCC_OscInitTypeDef structure.
     */
    RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
    RCC_OscInitStruct.HSEState = RCC_HSE_ON;
    RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
    RCC_OscInitStruct.HSIState = RCC_HSI_ON;
    RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
    RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
    RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
    if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
    {
        Error_Handler();
    }
    /** Initializes the CPU, AHB and APB buses clocks
     */
    RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK | RCC_CLOCKTYPE_SYSCLK | RCC_CLOCKTYPE_PCLK1 | RCC_CLOCKTYPE_PCLK2;
    RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
    RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
    RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
    RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;

    if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
    {
        Error_Handler();
    }
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_ADC | RCC_PERIPHCLK_USB;
    PeriphClkInit.AdcClockSelection = RCC_ADCPCLK2_DIV6;
    PeriphClkInit.UsbClockSelection = RCC_USBCLKSOURCE_PLL_DIV1_5;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    {
        Error_Handler();
    }
}

void setup()
{
    SystemClock_Config(); //启动72M主频
    // put your setup code here, to run once:
    Serial.begin(57600);
    while (!Serial)
    {
        ; /* code */
    }

    Serial.println("初始化lcd屏");

    LCD_Init(); // 初始化lcd屏
    uint16_t lcd_id = DeviceCode;

    Serial.print("初始化完成, lcd id:0x");
    Serial.println(lcd_id, HEX);

    Serial.print("主频:");
    Serial.print(HAL_RCC_GetSysClockFreq());

    Display_Test();
}

void loop()
{
    // put your main code here, to run repeatedly:
    LCD_Clear(WHITE);
    HAL_Delay(20);
    LCD_Clear(BLACK);
    HAL_Delay(20);
    LCD_Clear(BLUE);
    HAL_Delay(20);
    LCD_Clear(RED);
    HAL_Delay(20);
    LCD_Clear(GREEN);
    HAL_Delay(20);
    LCD_Clear(MAGENTA);
    HAL_Delay(20);
    LCD_Clear(CYAN);
    HAL_Delay(20);
    LCD_Clear(YELLOW);
    HAL_Delay(20);
    LCD_Clear(GRAY);
    HAL_Delay(20);
    LCD_Clear(BROWN);
    HAL_Delay(20);
}
WB_LCD.h
  1. #ifndef __WB_LCD_H
    #define __WB_LCD_H
    #include <Arduino.h>
    #ifdef __cplusplus
    extern "C"
    {
    #endif
    
        typedef uint8_t u8;
        typedef uint16_t u16;
        typedef uint32_t u32;
    
    #include "stdio.h"
    #include "stdlib.h"
    
    #define LCD_RAM *(__IO uint16_t *)((uint32_t)0x6C000002) //地址寄存器
    #define LCD_REG *(__IO uint16_t *)((uint32_t)0x6C000000) //指令寄存器
    
    #define MAX_HZ_POSX 224
    #define MAX_HZ_POSY 304
    
    #define MAX_CHAR_POSX 232
    #define MAX_CHAR_POSY 304
    
    #define Horizontal 0x00
    #define Vertical 0x01
    
    /*Private define-------------------------*/
    #define POINT_COLOR WHITE
    #define BACK_COLOR BLACK
    
    /*--------16位颜色值---------------*/
    #define WHITE 0xFFFF
    #define BLACK 0x0000
    #define BLUE 0x001F
    #define RED 0xF800
    #define MAGENTA 0xF81F
    #define GREEN 0x07E0
    #define CYAN 0x7FFF
    #define YELLOW 0xFFE0
    #define BROWN 0XBC40 //棕色
    #define BRRED 0XFC07 //棕红色
    #define GRAY 0X8430  //灰色
    #define LGRAY 0XC618 //浅灰色
    
    /**
     * @brief  ili9325/ili9328 LCD Registers
     */
    #define LCD_REG_0 0x00
    #define LCD_REG_1 0x01
    #define LCD_REG_2 0x02
    #define LCD_REG_3 0x03
    #define LCD_REG_4 0x04
    #define LCD_REG_5 0x05
    #define LCD_REG_6 0x06
    #define LCD_REG_7 0x07
    #define LCD_REG_8 0x08
    #define LCD_REG_9 0x09
    #define LCD_REG_10 0x0A
    #define LCD_REG_12 0x0C
    #define LCD_REG_13 0x0D
    #define LCD_REG_14 0x0E
    #define LCD_REG_15 0x0F
    #define LCD_REG_16 0x10
    #define LCD_REG_17 0x11
    #define LCD_REG_18 0x12
    #define LCD_REG_19 0x13
    #define LCD_REG_20 0x14
    #define LCD_REG_21 0x15
    #define LCD_REG_22 0x16
    #define LCD_REG_23 0x17
    #define LCD_REG_24 0x18
    #define LCD_REG_25 0x19
    #define LCD_REG_26 0x1A
    #define LCD_REG_27 0x1B
    #define LCD_REG_28 0x1C
    #define LCD_REG_29 0x1D
    #define LCD_REG_30 0x1E
    #define LCD_REG_31 0x1F
    #define LCD_REG_32 0x20
    #define LCD_REG_33 0x21
    #define LCD_REG_34 0x22
    #define LCD_REG_36 0x24
    #define LCD_REG_37 0x25
    #define LCD_REG_40 0x28
    #define LCD_REG_41 0x29
    #define LCD_REG_43 0x2B
    #define LCD_REG_45 0x2D
    #define LCD_REG_48 0x30
    #define LCD_REG_49 0x31
    #define LCD_REG_50 0x32
    #define LCD_REG_51 0x33
    #define LCD_REG_52 0x34
    #define LCD_REG_53 0x35
    #define LCD_REG_54 0x36
    #define LCD_REG_55 0x37
    #define LCD_REG_56 0x38
    #define LCD_REG_57 0x39
    #define LCD_REG_58 0x3A
    #define LCD_REG_59 0x3B
    #define LCD_REG_60 0x3C
    #define LCD_REG_61 0x3D
    #define LCD_REG_62 0x3E
    #define LCD_REG_63 0x3F
    #define LCD_REG_64 0x40
    #define LCD_REG_65 0x41
    #define LCD_REG_66 0x42
    #define LCD_REG_67 0x43
    #define LCD_REG_68 0x44
    #define LCD_REG_69 0x45
    #define LCD_REG_70 0x46
    #define LCD_REG_71 0x47
    #define LCD_REG_72 0x48
    #define LCD_REG_73 0x49
    #define LCD_REG_74 0x4A
    #define LCD_REG_75 0x4B
    #define LCD_REG_76 0x4C
    #define LCD_REG_77 0x4D
    #define LCD_REG_78 0x4E
    #define LCD_REG_79 0x4F
    #define LCD_REG_80 0x50
    #define LCD_REG_81 0x51
    #define LCD_REG_82 0x52
    #define LCD_REG_83 0x53
    #define LCD_REG_96 0x60
    #define LCD_REG_97 0x61
    #define LCD_REG_106 0x6A
    #define LCD_REG_118 0x76
    #define LCD_REG_128 0x80
    #define LCD_REG_129 0x81
    #define LCD_REG_130 0x82
    #define LCD_REG_131 0x83
    #define LCD_REG_132 0x84
    #define LCD_REG_133 0x85
    #define LCD_REG_134 0x86
    #define LCD_REG_135 0x87
    #define LCD_REG_136 0x88
    #define LCD_REG_137 0x89
    #define LCD_REG_139 0x8B
    #define LCD_REG_140 0x8C
    #define LCD_REG_141 0x8D
    #define LCD_REG_143 0x8F
    #define LCD_REG_144 0x90
    #define LCD_REG_145 0x91
    #define LCD_REG_146 0x92
    #define LCD_REG_147 0x93
    #define LCD_REG_148 0x94
    #define LCD_REG_149 0x95
    #define LCD_REG_150 0x96
    #define LCD_REG_151 0x97
    #define LCD_REG_152 0x98
    #define LCD_REG_153 0x99
    #define LCD_REG_154 0x9A
    #define LCD_REG_157 0x9D
    #define LCD_REG_192 0xC0
    #define LCD_REG_193 0xC1
    #define LCD_REG_229 0xE5
    
        extern uint16_t DeviceCode;
    
        /*----------函数声明------------*/
        /* 刷屏 */
        void LCD_Clear(uint16_t Color);
        void LCD_Fill(uint8_t xsta, uint16_t ysta, uint8_t xend, uint16_t yend, uint16_t colour);
        void LCD_DrawLine(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend);
        void LCD_DrawHVLine(uint8_t xsta, uint16_t ysta, uint16_t Length, uint16_t Color, uint8_t Direction);
        void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r);
        void LCD_DrawRectangle(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend);
        void LCD_WindowMax(unsigned int x, unsigned int y, unsigned int x_end, unsigned int y_end);
        void LCD_ShowNum(u8 x, u8 y, u32 num, u8 len, u16 PenColor, u16 BackColor); //显示数字
        void LCD_DrawPicture(u16 StartX, u16 StartY, u16 Xend, u16 Yend, u8 *pic);  //显示图片 gImage取模 bmp格式
    
        void LCD_IOConfig(void);
        void LCD_Init(void);
        void LCD_DisplayStr(unsigned int x, unsigned int y, unsigned char *s, u16 PenColor, u16 BackColor);
        void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);
        void LCD_ShowLEDNum(uint16_t x, uint16_t y, uint16_t num, u16 PenColor, u16 BackColor);
        void Display_Test(void);
    
    #ifdef __cplusplus
    }
    #endif
    
    #endif

    WB_LCD.C

/**
 * @file    WB_LCD.c
 * @author  WB R&D Team - openmcu666   &Kyo
 * @version V1.0
 * @date    2016.05.04  20220909
 * @brief   LCD Driver on HAL
 * @description 红牛2.8/3.2/3.5寸LCD屏的驱动(支持的驱动IC为SSD1298、ili9325/ili9328、SSD2119)用于驱动液晶屏的软件库,基于硬件接口FSMC,使得读写速度非常高速,由此在LCD上进行绘画非常流畅,播放视频也能完全胜任。
 */
#include "WB_LCD.h"

#include "font.h"

#define Font_Size 16 // 默认字体为16*8
#define XY 1         //文字支持横竖屏切换,竖屏:1;横屏:0

uint16_t DeviceCode; //用于存取设备ID

SRAM_HandleTypeDef hsram3; // SRAM句柄(用于控制LCD)

/*********************************************************
** Function name:       void Delay_10ms (u32 nCount)
** Descriptions:        LCD延时函数 10MS
** input parameters:    nCount
** output parameters:   无
** Returned value:      无
*********************************************************/
void Delay_10ms(u32 nCount)
{
    HAL_Delay(nCount * 10);
}

/*********************************************************
** Function name:       void LCD_WR_REG(uint16_t LCD_Reg)
** Descriptions:        写寄存器
** input parameters:    LCD_Reg
** output parameters:   无
** Returned value:      无
*********************************************************/
void LCD_WR_REG(uint16_t LCD_Reg)
{
    LCD_REG = LCD_Reg; //往指令寄存器写指令
}

/*********************************************************
** Function name:       void LCD_WR_DATA(uint16_t LCD_Data)
** Descriptions:        写数据
** input parameters:    LCD_Data
** output parameters:   无
** Returned value:      无
*********************************************************/
void LCD_WR_DATA(uint16_t LCD_Data)
{
    LCD_RAM = LCD_Data; //往数据寄存器写数据
}

/*********************************************************************************
** Function name:     void LCD_WriteReg(uint16_t LCD_Reg ,uint16_t LCD_RegValue)
** Descriptions:      配置寄存器
** input parameters:  寄存器地址:LCD_Reg   数据:RegValue
** output parameters: 无
** Returned value:    无
**********************************************************************************/
void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue)
{
    LCD_WR_REG(LCD_Reg);       //写寄存器
    LCD_WR_DATA(LCD_RegValue); //写数据
}

/*********************************************************
** Function name:       void LCD_WriteRAM_Prepare(void)
** Descriptions:        开始写GRAM
** input parameters:    无
** output parameters:   无
** Returned value:      无
*********************************************************/
void LCD_WriteRAM_Prepare(void)
{
    LCD_WR_REG(0x22);
}

/*********************************************************
** Function name:       void LCD_WriteRAM(u16 RGB_Code)
** Descriptions:        LCD写GRAM
** input parameters:    颜色值
** output parameters:   无
** Returned value:      无
*********************************************************/
void LCD_WriteRAM(u16 RGB_Code)
{
    LCD_WR_DATA(RGB_Code); //写十六位GRAM
}

/*********************************************************
** Function name:       uint16_t Read_LCDReg(uint16_t LCD_Reg)
** Descriptions:        读寄存器
** input parameters:    LCD_Reg:寄存器
** output parameters:   无
** Returned value:      返回寄存器值
*********************************************************/
uint16_t Read_LCDReg(uint16_t LCD_Reg)
{
    uint16_t temp;

    LCD_REG = LCD_Reg;

    temp = LCD_RAM;

    return temp;
}

/**********************************************************************************
** Function name:       void LCD_Configuration(void)
** Descriptions:        LCD相关引脚配置,fsmc能用的针脚是固定的
** input parameters:      无
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_IOConfig(void)
{
    //      GPIO_InitTypeDef GPIO_InitStructure;

    //   RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE |
    //                          RCC_APB2Periph_GPIOF | RCC_APB2Periph_GPIOG |
    //                          RCC_APB2Periph_AFIO, ENABLE);

    //   /* Set PD.00(D2), PD.01(D3), PD.04(NOE), PD.05(NWE), PD.08(D13), PD.09(D14),
    //      PD.10(D15), PD.14(D0), PD.15(D1) as alternate
    //      function push pull */
    //   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_4 | GPIO_Pin_5 |
    //                                 GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 | GPIO_Pin_14 |
    //                                 GPIO_Pin_15;
    //   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    //   GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    //   GPIO_Init(GPIOD, &GPIO_InitStructure);

    //   /* Set PE.07(D4), PE.08(D5), PE.09(D6), PE.10(D7), PE.11(D8), PE.12(D9), PE.13(D10),
    //      PE.14(D11), PE.15(D12) as alternate function push pull */
    //   GPIO_InitStructure.GPIO_Pin =  GPIO_Pin_6 | GPIO_Pin_7 | GPIO_Pin_8 | GPIO_Pin_9 | GPIO_Pin_10 |
    //                                 GPIO_Pin_11 | GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14 |
    //                                 GPIO_Pin_15;
    //   GPIO_Init(GPIOE, &GPIO_InitStructure);

    //   GPIO_WriteBit(GPIOE, GPIO_Pin_6, Bit_SET);
    //   /* Set PF.00(A0 (RS)) as alternate function push pull */
    //   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
    //   GPIO_Init(GPIOF, &GPIO_InitStructure);

    //   /* Set PG.12(NE4 (LCD/CS)) as alternate function push pull - CE3(LCD /CS) */
    //   GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    //   GPIO_Init(GPIOG, &GPIO_InitStructure);
    GPIO_InitTypeDef GPIO_InitStructure;

    __HAL_RCC_FSMC_CLK_ENABLE(); //使能FSMC时钟
    __HAL_RCC_GPIOF_CLK_ENABLE();
    __HAL_RCC_GPIOE_CLK_ENABLE();
    __HAL_RCC_GPIOD_CLK_ENABLE();
    __HAL_RCC_GPIOG_CLK_ENABLE(); //使能GPIO时钟
    GPIO_InitStructure.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_4 | GPIO_PIN_5 |
                             GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 | GPIO_PIN_14 |
                             GPIO_PIN_15;
    GPIO_InitStructure.Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    HAL_GPIO_Init(GPIOD, &GPIO_InitStructure);

    /* Set PE.07(D4), PE.08(D5), PE.09(D6), PE.10(D7), PE.11(D8), PE.12(D9), PE.13(D10),
       PE.14(D11), PE.15(D12) as alternate function push pull */
    GPIO_InitStructure.Pin = GPIO_PIN_6 | GPIO_PIN_7 | GPIO_PIN_8 | GPIO_PIN_9 | GPIO_PIN_10 |
                             GPIO_PIN_11 | GPIO_PIN_12 | GPIO_PIN_13 | GPIO_PIN_14 |
                             GPIO_PIN_15;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOE, &GPIO_InitStructure);

    /* Set PF.00(A0 (RS)) as alternate function push pull 设置a0做RS*/
    GPIO_InitStructure.Pin = GPIO_PIN_0;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOF, &GPIO_InitStructure);

    /* Set PG.12(NE4 (LCD/CS)) as alternate function push pull - CE3(LCD /CS) */
    GPIO_InitStructure.Pin = GPIO_PIN_12;
    GPIO_InitStructure.Mode = GPIO_MODE_AF_PP;
    GPIO_InitStructure.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(GPIOG, &GPIO_InitStructure);
}

/**********************************************************************************
** Function name:       void FSMC_LCDInit(void)
** Descriptions:        FSMC时序配置
** input parameters:      无
** output parameters:   无
** Returned value:      无
************************************************************************************/
void FSMC_LCDInit(void)
{
    //     FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;           //定义一个NOR初始化结构体
    //     FSMC_NORSRAMTimingInitTypeDef  w,r;                                  //定义一个NOR时序初始化结构体

    //     RCC_AHBPeriphClockCmd(RCC_AHBPeriph_FSMC, ENABLE);                        //使能FSMC总线时钟

    //   w.FSMC_AddressSetupTime = 0x00;                                              //地址建立时间:0x1
    //   w.FSMC_AddressHoldTime = 0x00;                                              //地址保持时间:0x00
    //   w.FSMC_DataSetupTime = 0x01;                                                //数据建立时间:0x2
    //   w.FSMC_BusTurnAroundDuration = 0x00;
    //   w.FSMC_CLKDivision = 0x00;
    //   w.FSMC_DataLatency = 0x00;
    //   w.FSMC_AccessMode = FSMC_AccessMode_B;

    //     r.FSMC_AddressSetupTime = 0x00;                                               //地址建立时间:0x1
    //   r.FSMC_AddressHoldTime = 0x00;                                               //地址保持时间:0x00
    //   r.FSMC_DataSetupTime = 0x07;                                                 //数据建立时间:0x2
    //   r.FSMC_BusTurnAroundDuration = 0x00;
    //   r.FSMC_CLKDivision = 0x00;
    //   r.FSMC_DataLatency = 0x0f;
    //   r.FSMC_AccessMode = FSMC_AccessMode_B;

    //   FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAM4;           //扩展NOR BANK 的第1个子BANK
    //   FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;//不使用总线复用

    //   FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;//扩展类型为NOR FLASH
    //   FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//扩展总线宽度为16位

    //   FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;

    //   FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;

    //   FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
    //   FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
    //   FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
    //   FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
    //   FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Enable;
    //   FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    //   FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &r;
    //   FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &w;

    //   FSMC_NORSRAMInit(&FSMC_NORSRAMInitStructure);                             //根据指定参数初始化结构体

    //   FSMC_NORSRAMCmd(FSMC_Bank1_NORSRAM4, ENABLE);                             //使能FSMC_Bank1_NORSRAM4 内存

    FSMC_NORSRAM_TimingTypeDef Timing = {0};
    FSMC_NORSRAM_TimingTypeDef ExtTiming = {0};

    /* USER CODE BEGIN FSMC_Init 1 */

    /* USER CODE END FSMC_Init 1 */

    /** Perform the SRAM3 memory initialization sequence
     */
    hsram3.Instance = FSMC_NORSRAM_DEVICE;
    hsram3.Extended = FSMC_NORSRAM_EXTENDED_DEVICE;
    /* hsram3.Init */
    hsram3.Init.NSBank = FSMC_NORSRAM_BANK4;
    hsram3.Init.DataAddressMux = FSMC_DATA_ADDRESS_MUX_DISABLE;
    hsram3.Init.MemoryType = FSMC_MEMORY_TYPE_SRAM;
    hsram3.Init.MemoryDataWidth = FSMC_NORSRAM_MEM_BUS_WIDTH_16;
    hsram3.Init.BurstAccessMode = FSMC_BURST_ACCESS_MODE_DISABLE;
    hsram3.Init.WaitSignalPolarity = FSMC_WAIT_SIGNAL_POLARITY_LOW;
    hsram3.Init.WrapMode = FSMC_WRAP_MODE_DISABLE;
    hsram3.Init.WaitSignalActive = FSMC_WAIT_TIMING_BEFORE_WS;
    hsram3.Init.WriteOperation = FSMC_WRITE_OPERATION_ENABLE;
    hsram3.Init.WaitSignal = FSMC_WAIT_SIGNAL_DISABLE;
    hsram3.Init.ExtendedMode = FSMC_EXTENDED_MODE_ENABLE;
    hsram3.Init.AsynchronousWait = FSMC_ASYNCHRONOUS_WAIT_DISABLE;
    hsram3.Init.WriteBurst = FSMC_WRITE_BURST_DISABLE;
    /* Timing */
    Timing.AddressSetupTime = 1;
    Timing.AddressHoldTime = 1;
    Timing.DataSetupTime = 2; //这个参数至少得是2,其他参数都可以最小1
    Timing.BusTurnAroundDuration = 1;
    Timing.CLKDivision = 1;
    Timing.DataLatency = 1;
    Timing.AccessMode = FSMC_ACCESS_MODE_D;
    /* ExtTiming */
    ExtTiming.AddressSetupTime = 1;
    ExtTiming.AddressHoldTime = 1;
    ExtTiming.DataSetupTime = 2;
    ExtTiming.BusTurnAroundDuration = 1;
    ExtTiming.CLKDivision = 1;
    ExtTiming.DataLatency = 1;
    ExtTiming.AccessMode = FSMC_ACCESS_MODE_D;

    if (HAL_SRAM_Init(&hsram3, &Timing, &ExtTiming) != HAL_OK)
    {
        Error_Handler();
    }

    __HAL_AFIO_FSMCNADV_DISCONNECTED();
}
/**********************************************************************************
** Function name:       void LCD_Init(void)
** Descriptions:        LCD初始化
** input parameters:      无
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_Init(void)
{

    LCD_IOConfig();
    FSMC_LCDInit();
    Delay_10ms(5);                       // delay 50 ms
    Delay_10ms(5);                       // delay 50 ms
    DeviceCode = Read_LCDReg(LCD_REG_0); // 读驱动IC
    // DeviceCode = 0x9325; // 读驱动IC
    Delay_10ms(5); // delay 50 ms

    // DeviceCode=0x8999;
    if (DeviceCode == 0x8999) // 对应的驱动IC为SSD1298
    {
        /*-----   Start Initial Sequence ------*/
        LCD_WriteReg(0x00, 0x0001); /*Start internal OSC */
        LCD_WriteReg(0x01, 0x3B3F); /*Driver output control */
        LCD_WriteReg(0x02, 0x0600); /* set 1 line inversion    */
        /*-------- Power control setup --------*/
        LCD_WriteReg(0x0C, 0x0007); /* Adjust VCIX2 output voltage */
        LCD_WriteReg(0x0D, 0x0006); /* Set amplitude magnification of VLCD63 */
        LCD_WriteReg(0x0E, 0x3200); /* Set alternating amplitude of VCOM */
        LCD_WriteReg(0x1E, 0x00BB); /* Set VcomH voltage */
        LCD_WriteReg(0x03, 0x6A64); /* Step-up factor/cycle setting  */
        /*-------- RAM position control --------*/
        LCD_WriteReg(0x0F, 0x0000); /* Gate scan position start at G0 */
        LCD_WriteReg(0x44, 0xEF00); /* Horizontal RAM address position */
        LCD_WriteReg(0x45, 0x0000); /* Vertical RAM address start position*/
        LCD_WriteReg(0x46, 0x013F); /* Vertical RAM address end position */
        /* ------ Adjust the Gamma Curve -------*/
        LCD_WriteReg(0x30, 0x0000);
        LCD_WriteReg(0x31, 0x0706);
        LCD_WriteReg(0x32, 0x0206);
        LCD_WriteReg(0x33, 0x0300);
        LCD_WriteReg(0x34, 0x0002);
        LCD_WriteReg(0x35, 0x0000);
        LCD_WriteReg(0x36, 0x0707);
        LCD_WriteReg(0x37, 0x0200);
        LCD_WriteReg(0x3A, 0x0908);
        LCD_WriteReg(0x3B, 0x0F0D);
        /*--------- Special command -----------*/
        LCD_WriteReg(0x28, 0x0006); /* Enable test command    */
        LCD_WriteReg(0x2F, 0x12EB); /* RAM speed tuning     */
        LCD_WriteReg(0x26, 0x7000); /* Internal Bandgap strength */
        LCD_WriteReg(0x20, 0xB0E3); /* Internal Vcom strength */
        LCD_WriteReg(0x27, 0x0044); /* Internal Vcomh/VcomL timing */
        LCD_WriteReg(0x2E, 0x7E45); /* VCOM charge sharing time */
        /*--------- Turn On display ------------*/
        LCD_WriteReg(0x10, 0x0000); /* Sleep mode off */
        Delay_10ms(3);              /* Wait 30mS  */
        LCD_WriteReg(0x11, 0x6870); /* Entry mode setup. 262K type B, take care on the data bus with 16it only */
        LCD_WriteReg(0x07, 0x0033); /* Display ON    */
    }

    if (DeviceCode == 0x9325 || DeviceCode == 0x9328) // ILI9325
    {
        LCD_WriteReg(LCD_REG_0, 0x0001);  /* Start internal OSC. */
        LCD_WriteReg(LCD_REG_1, 0x0100);  /* Set SS and SM bit */
        LCD_WriteReg(LCD_REG_2, 0x0700);  /* Set 1 line inversion */
        LCD_WriteReg(LCD_REG_3, 0x1018);  /* Set GRAM write direction and BGR=1. */
        LCD_WriteReg(LCD_REG_4, 0x0000);  /* Resize register */
        LCD_WriteReg(LCD_REG_8, 0x0202);  /* Set the back porch and front porch */
        LCD_WriteReg(LCD_REG_9, 0x0000);  /* Set non-display area refresh cycle ISC[3:0] */
        LCD_WriteReg(LCD_REG_10, 0x0000); /* FMARK function */
        LCD_WriteReg(LCD_REG_12, 0x0000); /* RGB interface setting */
        LCD_WriteReg(LCD_REG_13, 0x0000); /* Frame marker Position */
        LCD_WriteReg(LCD_REG_15, 0x0000); /* RGB interface polarity */

        /* Power On sequence -----------------------------------------------------*/
        LCD_WriteReg(LCD_REG_16, 0x0000); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
        LCD_WriteReg(LCD_REG_17, 0x0000); /* DC1[2:0], DC0[2:0], VC[2:0] */
        LCD_WriteReg(LCD_REG_18, 0x0000); /* VREG1OUT voltage */
        LCD_WriteReg(LCD_REG_19, 0x0000); /* VDV[4:0] for VCOM amplitude */
        Delay_10ms(130);                  /* Dis-charge capacitor power voltage (200ms) */
        LCD_WriteReg(LCD_REG_16, 0x17B0); /* SAP, BT[3:0], AP, DSTB, SLP, STB */
        LCD_WriteReg(LCD_REG_17, 0x0137); /* DC1[2:0], DC0[2:0], VC[2:0] */
        Delay_10ms(50);                   /* Delay 50 ms */
        LCD_WriteReg(LCD_REG_18, 0x009c); /*0x0139 VREG1OUT voltage */
        Delay_10ms(50);                   /* Delay 50 ms */
        LCD_WriteReg(LCD_REG_19, 0x1900); /* 0x1d00VDV[4:0] for VCOM amplitude */
        LCD_WriteReg(LCD_REG_41, 0x0013); /* VCM[4:0] for VCOMH */
        Delay_10ms(50);                   /* Delay 50 ms */
        LCD_WriteReg(LCD_REG_32, 0x0000); /* GRAM horizontal Address */
        LCD_WriteReg(LCD_REG_33, 0x0000); /* GRAM Vertical Address */

        /* Adjust the Gamma Curve (ILI9325)---------------------------------------*/
        LCD_WriteReg(LCD_REG_48, 0x0007);
        LCD_WriteReg(LCD_REG_49, 0x0302);
        LCD_WriteReg(LCD_REG_50, 0x0105);
        LCD_WriteReg(LCD_REG_53, 0x0206);
        LCD_WriteReg(LCD_REG_54, 0x0808);
        LCD_WriteReg(LCD_REG_55, 0x0206);
        LCD_WriteReg(LCD_REG_56, 0x0504);
        LCD_WriteReg(LCD_REG_57, 0x0007);
        LCD_WriteReg(LCD_REG_60, 0x0105);
        LCD_WriteReg(LCD_REG_61, 0x0808);

        /* Set GRAM area ---------------------------------------------------------*/
        LCD_WriteReg(LCD_REG_80, 0x0000); /* Horizontal GRAM Start Address */
        LCD_WriteReg(LCD_REG_81, 0x00EF); /* Horizontal GRAM End Address */
        LCD_WriteReg(LCD_REG_82, 0x0000); /* Vertical GRAM Start Address */
        LCD_WriteReg(LCD_REG_83, 0x013F); /* Vertical GRAM End Address */

        LCD_WriteReg(LCD_REG_96, 0xA700);  /* Gate Scan Line(GS=1, scan direction is G320~G1) */
        LCD_WriteReg(LCD_REG_97, 0x0001);  /* NDL,VLE, REV */
        LCD_WriteReg(LCD_REG_106, 0x0000); /* set scrolling line */

        /* Partial Display Control -----------------------------------------------*/
        LCD_WriteReg(LCD_REG_128, 0x0000);
        LCD_WriteReg(LCD_REG_129, 0x0000);
        LCD_WriteReg(LCD_REG_130, 0x0000);
        LCD_WriteReg(LCD_REG_131, 0x0000);
        LCD_WriteReg(LCD_REG_132, 0x0000);
        LCD_WriteReg(LCD_REG_133, 0x0000);

        /* Panel Control ---------------------------------------------------------*/
        LCD_WriteReg(LCD_REG_144, 0x0010);
        LCD_WriteReg(LCD_REG_146, 0x0000);
        LCD_WriteReg(LCD_REG_147, 0x0003);
        LCD_WriteReg(LCD_REG_149, 0x0110);
        LCD_WriteReg(LCD_REG_151, 0x0000);
        LCD_WriteReg(LCD_REG_152, 0x0000);

        /* set GRAM write direction and BGR = 1 */
        /* I/D=00 (Horizontal : increment, Vertical : decrement) */
        /* AM=1 (address is updated in vertical writing direction) */
        // LCD_WriteReg(LCD_REG_3, 0x1018);  //横屏
        LCD_WriteReg(LCD_REG_3, 0x1030);
        LCD_WriteReg(LCD_REG_7, 0x0133); /* 262K color and display ON */
    }
    else if (DeviceCode == 0x9919) // SSD2119
    {
        LCD_WriteReg(0x28, 0x0006);
        LCD_WriteReg(0x00, 0x0001);
        LCD_WriteReg(0x10, 0x0000);
        LCD_WriteReg(0x01, 0x72ef); //
        LCD_WriteReg(0x02, 0x0600);
        LCD_WriteReg(0x03, 0x6a38);
        LCD_WriteReg(0x11, 0x6874); // 74
        //  RAM WRITE DATA MASK
        LCD_WriteReg(0x0f, 0x0000);
        //  RAM WRITE DATA MASK
        LCD_WriteReg(0x0b, 0x5308);
        LCD_WriteReg(0x0c, 0x0000); // 3
        LCD_WriteReg(0x0d, 0x000a);
        LCD_WriteReg(0x0e, 0x2e00); // 0030
        LCD_WriteReg(0x1e, 0x00be);
        LCD_WriteReg(0x25, 0x8000);
        LCD_WriteReg(0x26, 0x7800);
        LCD_WriteReg(0x27, 0x0078);
        LCD_WriteReg(0x4e, 0x0000);
        LCD_WriteReg(0x4f, 0x0000);
        LCD_WriteReg(0x12, 0x08d9);
        // -----------------Adjust the Gamma Curve----//
        LCD_WriteReg(0x30, 0x0000); // 0007
        LCD_WriteReg(0x31, 0x0104); // 0203
        LCD_WriteReg(0x32, 0x0100); // 0001
        LCD_WriteReg(0x33, 0x0305); // 0007
        LCD_WriteReg(0x34, 0x0505); // 0007
        LCD_WriteReg(0x35, 0x0305); // 0407
        LCD_WriteReg(0x36, 0x0707); // 0407
        LCD_WriteReg(0x37, 0x0300); // 0607
        LCD_WriteReg(0x3a, 0x1200); // 0106
        LCD_WriteReg(0x3b, 0x0800);
        LCD_WriteReg(0x07, 0x0033);
        // LCD_WriteReg(0x11,0x6040|0x30);
    }
    Delay_10ms(5); //延时50ms
    LCD_Clear(BLACK);
}

/************************************************************************
** Function name:       void LCD_SetCursor(u16 Xpos, u16 Ypos)
** Descriptions:        设置光标位置
** input parameters:    x轴坐标:uint8_t Xpos ;  y轴坐标:uint16_t Ypos
** output parameters:   无
** Returned value:      无
**************************************************************************/
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
    if (DeviceCode == 0x8999 || DeviceCode == 0x9919)
    {
        LCD_WriteReg(0x4E, Xpos);
        LCD_WriteReg(0x4F, Ypos);
    }
    else
    {
        LCD_WriteReg(0x20, Xpos);
        LCD_WriteReg(0x21, Ypos);
    }
}

/***********************************************************
** Function name:       void LCD_Clear(uint16_t Color)
** Descriptions:        刷屏函数
** input parameters:    颜色值
** output parameters:   无
** Returned value:      无
************************************************************/
void LCD_Clear(uint16_t Color)
{
    uint32_t index = 0;
    LCD_SetCursor(0x00, 0x0000); //设置光标位置
    LCD_WriteRAM_Prepare();      //开始写入GRAM
    for (index = 0; index < 76800; index++)
    {
        LCD_WR_DATA(Color);
    }
}

/****************************************************************************
 * 名    称:u16 LCD_GetPoint(u16 x,u16 y)
 * 功    能:获取指定座标的颜色值
 * 入口参数:x      行座标
 *           y      列座标
 * 出口参数:当前座标颜色值
 * 说    明:
 * 调用方法:CurrentColor = LCD_GetPoint(10,10);
 * 备注:此函数有待验证,此处屏蔽
 ****************************************************************************/
// u16 LCD_GetPoint(u16 x,u16 y)
//{
//   LCD_SetCursor(x,y);
//   if(DeviceCode=0X8999)
//     return (LCD_ReadRAM());
//   else
//     return (LCD_BGRtoRGB(LCD_ReadRAM()));
// }

/***********************************************************************
** Function name:       void LCD_DrawPoint(uint16_t xsta, uint16_t ysta)
** Descriptions:        打点
** input parameters:    xsta X起始坐标 0~239;ysta    Y起始坐标 0~319
** output parameters:   无
** Returned value:      无
***********************************************************************/
void LCD_DrawPoint(uint16_t xsta, uint16_t ysta)
{
    LCD_SetCursor(xsta, ysta); //设置光标位置
    LCD_WR_REG(0x22);          //开始写入GRAM
    LCD_WR_DATA(POINT_COLOR);
}

/*************************************************************************************************************
** Function name:       void LCD_XYRAM(uint16_t xstart ,uint16_t ystart ,uint16_t xend ,uint16_t yend)
** Descriptions:        设置显存区域,用完以后要恢复起点(0,0)和终点(239,319)(ili9325/ili9328调用)
** input parameters:    xsta 起始X坐标
                            ysta 起始Y坐标
                            xend 结束X坐标
                            yend 结束Y坐标
** output parameters:   无
** Returned value:      无
**************************************************************************************************************/
void LCD_XYRAM(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend)
{
    LCD_WriteReg(0x0050, xsta);     // 设置横坐标GRAM起始地址
    LCD_WriteReg(0x0051, xend - 1); // 设置横坐标GRAM结束地址
    LCD_WriteReg(0x0052, ysta);     // 设置纵坐标GRAM起始地址
    LCD_WriteReg(0x0053, yend - 1); // 设置纵坐标GRAM结束地址
}

/*******************************************************************************************************
** Function name:       void LCD_WindowMax (unsigned int x,unsigned int y,unsigned int x_end,unsigned int y_end)
** Descriptions:        设置窗口最大化240*320
** input parameters:    xsta X起始坐标 0~239;ysta    Y起始坐标 0~319
** output parameters:   无
** Returned value:      无
******************************************************************************************************/
void LCD_WindowMax(unsigned int x, unsigned int y, unsigned int x_end, unsigned int y_end)
{
    if (DeviceCode == 0x8999 || DeviceCode == 0x9919)
    {
        LCD_WriteReg(0x44, x | ((x_end - 1) << 8));
        LCD_WriteReg(0x45, y);
        LCD_WriteReg(0x46, y_end - 1);
    }
    else
    {
        LCD_WriteReg(0x50, x);         //水平方向GRAM起始地址
        LCD_WriteReg(0x51, x + x_end); //水平方向GRAM结束地址
        LCD_WriteReg(0x52, y);         //垂直方向GRAM起始地址
        LCD_WriteReg(0x53, y + y_end); //垂直方向GRAM结束地址
                                       // LCD_SetCursor(x, y);                   //设置光标位置
    }
}

/*************************************************************************************************************
** Function name:       void LCD_Fill(uint8_t xsta, uint16_t ysta, uint8_t xend, uint16_t yend, uint16_t colour)
** Descriptions:        在指定矩形区域填充指定颜色,区域大小(xend-xsta)*(yend-ysta)
** input parameters:    xsta 起始X坐标
                            ysta 起始Y坐标
                            xend 结束X坐标
                            yend 结束Y坐标
                            color 待填充颜色
** output parameters:   无
** Returned value:      无
**************************************************************************************************************/
void LCD_Fill(uint8_t xsta, uint16_t ysta, uint8_t xend, uint16_t yend, uint16_t colour)
{
    u32 n;
    if (DeviceCode == 0x8999 || DeviceCode == 0x9919) // 对应的驱动IC为SSD1298
    {
        LCD_WindowMax(xsta, ysta, xend, yend); //设置窗口
    }
    else
    {
        LCD_XYRAM(xsta, ysta, xend, yend); // 设置GRAM坐标
    }
    LCD_SetCursor(xsta, ysta); //设置光标位置
    LCD_WriteRAM_Prepare();    //开始写入GRAM*6
    n = (u32)(yend - ysta + 1) * (xend - xsta + 1);
    while (n--)
    {
        LCD_WR_DATA(colour);
    } //显示所填充的颜色

    LCD_WindowMax(0, 0, 240, 320); //恢复窗口
}

/****************************************************************************************************
** Function name:       void LCD_DrawLine(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend)
** Descriptions:        画线
** input parameters:    xsta X起始坐标
                          ysta Y起始坐标
                            xend X终点坐标
                            yend Y终点坐标
** output parameters:   无
** Returned value:      无
****************************************************************************************************/
void LCD_DrawLine(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend)
{
    u16 x, y, t;
    if ((xsta == xend) && (ysta == yend))
        LCD_DrawPoint(xsta, ysta);
    else if (abs(yend - ysta) > abs(xend - xsta)) //斜率大于1
    {
        if (ysta > yend)
        {
            t = ysta;
            ysta = yend;
            yend = t;
            t = xsta;
            xsta = xend;
            xend = t;
        }
        for (y = ysta; y < yend; y++) //以y轴为基准
        {
            x = (u32)(y - ysta) * (xend - xsta) / (yend - ysta) + xsta;
            LCD_DrawPoint(x, y);
        }
    }
    else //斜率小于等于1
    {
        if (xsta > xend)
        {
            t = ysta;
            ysta = yend;
            yend = t;
            t = xsta;
            xsta = xend;
            xend = t;
        }
        for (x = xsta; x <= xend; x++) //以x轴为基准
        {
            y = (u32)(x - xsta) * (yend - ysta) / (xend - xsta) + ysta;
            LCD_DrawPoint(x, y);
        }
    }
}

/****************************************************************************************************
** Function name:       void LCD_DrawHVLine(uint8_t xsta, uint16_t ysta, uint16_t Length,uint16_t Color,uint8_t Direction)
** Descriptions:        绘制水平或垂直的线条
** input parameters:    xsta X起始坐标
                          ysta Y起始坐标
                            Length 线条长度
                            Color 线条颜色
                        Direction: Horizontal 水平; Vertical 垂直
** output parameters:   无
** Returned value:      无
****************************************************************************************************/
void LCD_DrawHVLine(uint8_t xsta, uint16_t ysta, uint16_t Length, uint16_t Color, uint8_t Direction)
{
    uint32_t i = 0;

    LCD_SetCursor(xsta, ysta);

    if (Direction == Horizontal)
    {
        // LCD_WindowMax(ysta,xsta,ysta+Length,xsta-1);
        LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
        for (i = 0; i < Length; i++)
        {
            LCD_WriteRAM(Color);
        }
    }
    else
    {
        for (i = 0; i < Length; i++)
        {

            LCD_WriteRAM_Prepare(); /* Prepare to write GRAM */
            LCD_WriteRAM(Color);
            xsta++;
            LCD_SetCursor(xsta, ysta);
        }
    }
}
/*****************************************************************************
** Function name:       void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r)
** Descriptions:        画圆
** input parameters:    x0 中心点横坐标
                          y0 中心点纵坐标
                            r  半径
** output parameters:   无
** Returned value:      无
******************************************************************************/
void LCD_DrawCircle(uint16_t x0, uint16_t y0, uint8_t r)
{
    int a, b;
    int di;
    a = 0;
    b = r;
    di = 3 - (r << 1); //判断下个点位置的标志
    while (a <= b)
    {
        LCD_DrawPoint(x0 - b, y0 - a); // 3
        LCD_DrawPoint(x0 + b, y0 - a); // 0
        LCD_DrawPoint(x0 - a, y0 + b); // 1
        LCD_DrawPoint(x0 - b, y0 - a); // 7
        LCD_DrawPoint(x0 - a, y0 - b); // 2
        LCD_DrawPoint(x0 + b, y0 + a); // 4
        LCD_DrawPoint(x0 + a, y0 - b); // 5
        LCD_DrawPoint(x0 + a, y0 + b); // 6
        LCD_DrawPoint(x0 - b, y0 + a);
        a++;

        /*使用Bresenham算法画圆*/
        if (di < 0)
            di += 4 * a + 6;
        else
        {
            di += 10 + 4 * (a - b);
            b--;
        }
        LCD_DrawPoint(x0 + a, y0 + b);
    }
}

/*****************************************************************************
** Function name:       void Draw_Circle(uint16_t x0, uint16_t y0, uint8_t r)
** Descriptions:        画矩形
** input parameters:    xsta X起始坐标
                          ysta Y起始坐标
                            xend X结束坐标
                            yend Y结束坐标
** output parameters:   无
** Returned value:      无
******************************************************************************/
void LCD_DrawRectangle(uint16_t xsta, uint16_t ysta, uint16_t xend, uint16_t yend)
{
    LCD_DrawLine(xsta, ysta, xend, ysta);
    LCD_DrawLine(xsta, ysta, xsta, yend);
    LCD_DrawLine(xsta, yend, xend, yend);
    LCD_DrawLine(xend, ysta, xend, yend);
}

void LCD_DrawPixel(uint16_t xsta, uint16_t ysta, uint16_t color)
{
    LCD_SetCursor(xsta, ysta); //设置光标位置                  */
    LCD_WriteRAM_Prepare();
    LCD_WR_DATA(color);
}
/***************************************************************************************************
** Function name:       void LCD_ShowChar(u8 x, u16 y, u8 num, u8 size, u16 PenColor, u16 BackColor)
** Descriptions:        显示一个字符
** input parameters:    x,y      起始坐标(x:0~234 y:0~308)
                            num       字符ASCII码值
                            size      字符大小,使用默认8*16
                            PenColor  字体颜色
                            BackColor 字体背景颜色
** output parameters:   无
** Returned value:      无
****************************************************************************************************/
void LCD_ShowChar(u8 x, u16 y, u8 num, u8 size, u16 PenColor, u16 BackColor)
{
    u8 temp;
    u8 pos, t;
    if (x > MAX_CHAR_POSX || y > MAX_CHAR_POSY)
        return;
    if (DeviceCode == 0x8999) //驱动IC为SSD1298
    {
        if (XY) //竖屏显示
        {
            LCD_WindowMax(x, y, x + size / 2, y + size); //设置窗口
            LCD_WriteReg(0x11, 0x6870);
            LCD_SetCursor(x, y);
        }
        else //横屏显示
        {
            LCD_WindowMax(x, y - size / 2, x + size, y); //设置窗口
            LCD_WriteReg(0x11, 0x6858);
            LCD_SetCursor(x, y - 1); //设置光标位置
        }
    }
    else if (DeviceCode == 0x9919) //驱动IC为SSD2119
    {
        if (XY) //竖屏显示
        {
            LCD_WindowMax(x, y, x + size / 2, y + size); //设置窗口
            LCD_WriteReg(0x01, 0x32EF);                  //输出控制寄存器01
            LCD_WriteReg(0x11, 0x6038);                  //设置GRAM自增方向
            LCD_SetCursor(y, x);
        }
        else //横屏显示
        {
            LCD_WindowMax(x, y, x + size, y + size / 2); //设置窗口
            LCD_SetCursor(y, x);                         //设置光标位置
        }
    }
    else if (DeviceCode == 0x9325 || DeviceCode == 0x9328)
    {
        if (XY)
        {
            LCD_WindowMax(x, y, (size / 2 - 1), size - 1); //设置窗口    驱动IC为ILI9325/9328
            LCD_WriteReg(LCD_REG_3, 0x1030);
            LCD_SetCursor(x, y); //设置光标位置
        }
        else
        {
            LCD_WindowMax(x, y + (size / 2), size - 1, (size / 2) - 1);
            LCD_WriteReg(LCD_REG_3, 0x1098); // 0x1068
            LCD_SetCursor(x, y);
        }
    }
    LCD_WriteRAM_Prepare(); //开始写入GRAM
    num = num - ' ';        //得到偏移后的值
    for (pos = 0; pos < size; pos++)
    {
        if (size == 12)
            temp = asc2_1206[num][pos]; //调用1206字体
        else
            temp = asc2_1608[num][pos]; //调用1608字体
        for (t = 0; t < size / 2; t++)
        {
            if (temp & 0x01) //从低位开始
            {
                LCD_WR_DATA(PenColor); //画字体颜色 一个点
            }
            else
                LCD_WR_DATA(BackColor); //画背景颜色 一个点
            temp >>= 1;
        }
    }
    LCD_WindowMax(0x0000, 0x0000, 240, 320); //恢复窗体大小
}
/**********************************************************************************
** Function name:       unsigned int mypow(unsigned int m,unsigned int n)
** Descriptions:        m的n次方 用于取出数值每一位
** input parameters:      m进制:unsigned int m
**                                            n次方:unsigned int n
** output parameters:   m^n
** Returned value:      无
************************************************************************************/
u32 mypow(u8 m, u8 n)
{
    u32 result = 1;
    while (n--)
        result *= m;
    return result;
}

/*********************************************************************************************
** Function name:       void LCD_ShowNum(u8 x,u8 y,u32 num,u8 len, u16 PenColor, u16 BackColor)
** Descriptions:        显示数字(0~4294967295);
** input parameters:      x起始:     u8 x
                                            y起始:     u8 y
                                            数值:       num
                                            有效长度:  len
                        字体颜色:   PenColor
                        背景颜色:  BackColor
** output parameters:   无
** Returned value:      无
************************************************************************************************/
void LCD_ShowNum(u8 x, u8 y, u32 num, u8 len, u16 PenColor, u16 BackColor)
{
    u8 size = 16; // 这里使用默认的16*8
    u8 t, temp;
    u8 enshow = 0;
    for (t = 0; t < len; t++)
    {
        temp = (num / mypow(10, len - t - 1)) % 10;
        if (enshow == 0 && t < (len - 1))
        {
            if (temp == 0)
            {
                LCD_ShowChar(x + (size / 2) * t, y, ' ', size, PenColor, BackColor);
                LCD_ShowChar(x + (size / 2) * t, y, '0', size, PenColor, BackColor);
                continue;
            }
            else
                enshow = 1;
        }
        LCD_ShowChar(x + (size / 2) * t, y, temp + '0', size, PenColor, BackColor);
    }
}

/*********************************************************************************************
** Function name:       void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
** Descriptions:        显示字符(此函数不能单独调用)
** input parameters:      x,y      起始坐标
                          p         指向字符串起始地址
                            PenColor  字符颜色
                            BackColor 背景颜色
** output parameters:   无
** Returned value:      无
************************************************************************************************/
void LCD_ShowCharString(uint16_t x, uint16_t y, const uint8_t *p, uint16_t PenColor, uint16_t BackColor)
{
    uint8_t size = 16; //字符大小默认16*8

    if (x > MAX_CHAR_POSX)
    {
        x = 0;
        y += size;
    } //超出X轴字体最小单位,换行
    if (y > MAX_CHAR_POSY)
    {
        y = x = 0;
        LCD_Clear(WHITE);
    }                                                        //超出Y轴字体最小单位,回到原点,并且清屏
    LCD_ShowChar(x, 320 - y, *p, size, PenColor, BackColor); // 0表示非叠加方式
}

/**********************************************************************************
** Function name:       u16 findHzIndex(u8 *hz)
** Descriptions:        索引汉字存储的内存地址
** input parameters:      hz
** output parameters:   无
** Returned value:      无
************************************************************************************/
u16 findHzIndex(u8 *hz) // 在自定义汉字库在查找所要显示
                        // 的汉字的位置
{
    u16 i = 0;
    FNT_GB16 *ptGb16 = (FNT_GB16 *)GBHZ_16; // ptGb16指向GBHZ_16
    while (ptGb16[i].Index[0] > 0x80)
    {
        if ((*hz == ptGb16[i].Index[0]) && (*(hz + 1) == ptGb16[i].Index[1])) //汉字用两位来表示地址码
        {
            return i;
        }
        i++;
        if (i > (sizeof((FNT_GB16 *)GBHZ_16) / sizeof(FNT_GB16) - 1)) //搜索下标约束
        {
            break;
        }
    }
    return 0;
}

/************************************************************************************************
** Function name:       void WriteOneHz(u16 x0, u16 y0, u8 *pucMsk, u16 PenColor, u16 BackColor)
** Descriptions:        显示一个汉字(此函数不能单独作为汉字字符显示)
** input parameters:      x0,y0      起始坐标
                            *pucMsk    指向字符串地址
                            PenColor     字符颜色
                            BackColor  背景颜色
** output parameters:   无
** Returned value:      无
************************************************************************************************/
void WriteOneHz(u16 x0, u16 y0, u8 *pucMsk, u16 PenColor, u16 BackColor)
{
    u16 i, j;
    u16 mod[16]; //当前字模 16*16
    u16 *pusMsk; //当前字库地址
    u16 y;

    u16 size = 16; //汉字默认大小16*16

    pusMsk = (u16 *)pucMsk;

    for (i = 0; i < 16; i++) //保存当前汉字点阵式字模
    {
        mod[i] = *pusMsk;                                             //取得当前字模,半字对齐访问
        mod[i] = ((mod[i] & 0xff00) >> 8) | ((mod[i] & 0x00ff) << 8); //字模交换高低字节
        pusMsk = pusMsk + 1;
    }
    y = x0;
    if (DeviceCode == 0x8999) //驱动IC为SSD1298
    {
        if (XY) //竖屏显示
        {
            LCD_WindowMax(x0, y0, x0 + size, y0 + size); //设置窗口
            LCD_WriteReg(0x11, 0x6870);
            LCD_SetCursor(x0, y0);
        }
        else //横屏显示
        {
            LCD_WindowMax(x0, y0 - size, x0 + size, y0); //设置窗口
            LCD_WriteReg(0x11, 0x6858);                  //
            LCD_SetCursor(x0, y0 - 1);                   //设置光标位置
        }
    }
    else if (DeviceCode == 0x9919) //驱动IC为SSD2119
    {
        if (XY) //竖屏显示
        {

            LCD_WindowMax(x0, y0, x0 + size, y0 + size); //设置窗口
            LCD_WriteReg(0x01, 0x32EF);                  //输出控制寄存器01
            LCD_WriteReg(0x11, 0x6038);                  //设置GRAM自增方向
            LCD_SetCursor(y0, x0);
        }
        else //横屏显示
        {
            LCD_WindowMax(x0, y0, x0 + size, y0 + size);
            LCD_SetCursor(y0, x0); //设置光标位置
        }
    }

    else if (DeviceCode == 0x9325 || DeviceCode == 0x9328) //驱动IC为ILI9325/9328
    {
        LCD_WindowMax(x0, y0, (size - 1), size - 1);
        if (XY)
            LCD_WriteReg(LCD_REG_3, 0x1030);
        else
            LCD_WriteReg(LCD_REG_3, 0x1098);
        LCD_SetCursor(x0, y0);
    }

    LCD_WriteRAM_Prepare();  //开始写入GRAM
    for (i = 0; i < 16; i++) // 16行
    {
        for (j = 0; j < 16; j++) // 16列
        {
            if ((mod[i] << j) & 0x8000) //显示第i行 共16个点
            {
                LCD_WriteRAM(PenColor);
            }
            else
            {
                LCD_WriteRAM(BackColor); //用读方式跳过写空白点的像素
            }
        }
        y++;
    }
    LCD_WindowMax(0x0000, 0x0000, 240, 320); //恢复窗体大小
}

/**********************************************************************************
** Function name:       void LCD_ShowHzString(u16 x0, u16 y0, u8 *pcStr, u16 PenColor, u16 BackColor)
** Descriptions:        显示汉字字符串(不能单独调用)
** input parameters:      x0,y0    起始坐标
                            pcStr     指向字符串地址
                            PenColor  字体颜色
                            BackColor 字体背景
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_ShowHzString(u16 x0, u16 y0, u8 *pcStr, u16 PenColor, u16 BackColor)
{

    u16 usIndex;
    u8 size = 16;
    FNT_GB16 *ptGb16 = 0;
    ptGb16 = (FNT_GB16 *)GBHZ_16;

    if (x0 > MAX_HZ_POSX)
    {
        x0 = 0;
        y0 += size;
    } //超出X轴字体最小单位,换行
      // if(y0>MAX_HZ_POSY){y0=x0=0;LCD_Clear(WHITE);}        //超出Y轴字体最小单位,回到原点,并且清屏

    usIndex = findHzIndex(pcStr);
    WriteOneHz(x0, y0, (u8 *)&(ptGb16[usIndex].Msk[0]), PenColor, BackColor); //显示一个汉字
}

/**********************************************************************************
** Function name:       void LCD_DisplayStr(unsigned int x, unsigned int y, unsigned char *s,u16 PenColor, u16 BackColor)
** Descriptions:        显示字符串(可以和汉字混合显示,支持横竖屏切换)
** input parameters:      x,y    起始坐标
                            *s     指向字符串地址
                            PenColor  字体颜色
                            BackColor 字体背景
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_DisplayStr(unsigned int x, unsigned int y, unsigned char *s, u16 PenColor, u16 BackColor)
{
    if (XY == 0)
    {
        u16 change = 0;
        change = x;
        x = y;
        y = change;
    }
    while (*s)
    {
        if (*s > 0x80) //显示汉字
        {
            if (XY)
            {
                LCD_ShowHzString(x, y, s, PenColor, BackColor);
                x += 16;
            }
            else
            {
                switch (DeviceCode)
                {
                case 0x8999:
                    LCD_ShowHzString(x, 319 - y, s, PenColor, BackColor);
                    break;
                case 0x9919:
                    LCD_ShowHzString(x, y, s, PenColor, BackColor);
                    break;
                default:
                    LCD_ShowHzString(x, 303 - y, s, PenColor, BackColor); // 319-16
                    break;
                }
                y += 16;
            }
            s += 2;
        }
        else //非汉字
        {
            if (XY) //竖屏显示
            {
                LCD_ShowChar(x, y, *s++, 16, PenColor, BackColor);
                x += Font_Size / 2;
                if (x >= 232)
                {
                    x = 0;
                    y += Font_Size;
                    if (y >= 304)
                        y = 0;
                }
            }
            else //横屏显示
            {
                switch (DeviceCode)
                {
                case 0x8999:
                    LCD_ShowChar(x, 319 - y, *s++, 16, PenColor, BackColor);
                    break;
                case 0x9919:
                    LCD_ShowChar(x, y, *s++, 16, PenColor, BackColor);
                    break;
                default:
                    LCD_ShowChar(x, 303 - y, *s++, 16, PenColor, BackColor); // 319-16
                    break;
                }
                y += Font_Size / 2;
                if (y >= 312)
                {
                    y = 0;
                    x += Font_Size;
                    if (x >= 224)
                        y = 0;
                }
            }
        }
    }
}

/**********************************************************************************
** Function name:       u16 LCD_RGBtoBGR(u16 Color)
** Descriptions:        RRRRRGGGGGGBBBBB 改为 BBBBBGGGGGGRRRRR 格式
** input parameters:      Color      RGB 颜色值
** output parameters:   BGR 颜色值
** Returned value:      无
************************************************************************************/
u16 LCD_RGBtoBGR(u16 Color)
{
    u16 r, g, b, bgr;

    b = (Color >> 0) & 0x1f;  //提取B
    g = (Color >> 5) & 0x3f;  //中间六位
    r = (Color >> 11) & 0x1f; //提取R

    bgr = (b << 11) + (g << 5) + (r << 0);

    return (bgr);
}

/**********************************************************************************
** Function name:       void LCD_DrawPicture(u16 StartX,u16 StartY,u16 Xend,u16 Yend,u8 *pic)
** Descriptions:        图片取模格式为水平扫描,16位颜色模式
** input parameters:      StartX     行起始座标
                        StartY     列起始座标
                        EndX       行结束座标
                        EndY       列结束座标
                        pic        图片头指针
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_DrawPicture(u16 StartX, u16 StartY, u16 Xend, u16 Yend, u8 *pic)
{
    static u16 i = 0, j = 0;
    u16 *bitmap = (u16 *)pic;
    if (DeviceCode == 0x8999 || DeviceCode == 0x9919)
    {
        LCD_WindowMax(StartX, StartY, Xend, Yend); //设置图片显示窗口大小
    }
    else
    {
        LCD_XYRAM(StartX, StartY, Xend, Yend); // 设置GRAM坐标
    }

    LCD_SetCursor(StartX, StartY);
    LCD_WriteRAM_Prepare();
    for (j = 0; j < Yend - StartY; j++)
    {
        for (i = 0; i < Xend - StartX; i++)
            LCD_WriteRAM(*bitmap++);
    }

    LCD_WindowMax(0, 0, 240, 320); //恢复窗口
}

/**********************************************************************************
** Function name:      void LCD_ShowLEDNum(uint16_t x,uint16_t y,uint16_t num,u16 PenColor, u16 BackColor)
** Descriptions:        显示数字数码管字体(暂只支持ili9325/ili9328的竖屏显示)
** input parameters:      x     行起始座标
                        y     列起始座标
                        num   要显示的数字
                        PenColor     字体颜色
                        BackColor    背景颜色
** output parameters:   无
** Returned value:      无
************************************************************************************/
void LCD_ShowLEDNum(uint16_t x, uint16_t y, uint16_t num, u16 PenColor, u16 BackColor)
{
    uint8_t temp;
    uint8_t pos, i, j;
    LCD_SetCursor(x, y);
    LCD_XYRAM(x, y, x + 24, y + 48); // 设置GRAM坐标
    LCD_WriteRAM_Prepare();          //指向RAM寄存器,准备写数据到RAM
    num = num * 9;
    for (j = 0; j < 9; j++)
    {
        for (pos = 0; pos < 16; pos++)
        {
            temp = led_ma[num][pos];
            for (i = 0; i < 8; i++)
            {
                if (temp & 0x80)
                    LCD_WR_DATA(PenColor);
                else
                    LCD_WR_DATA(BackColor);
                temp <<= 1;
            }
        }
        num++;
    }
}

/**********************************************************************************
** Function name:      void Display_Test(void)
** Descriptions:        显示测试
** input parameters:      无
** output parameters:   无
** Returned value:      无
************************************************************************************/
void Display_Test(void)
{
    u16 i = 0, Offset = 0;
    u16 color_tab[10] = {WHITE, BLUE, RED, GREEN, MAGENTA, YELLOW, CYAN, BROWN, LGRAY, GRAY};
    for (i = 0; i < 10; i++)
    {
        LCD_ShowLEDNum(Offset, 0, i, color_tab[i], BLACK);
        Offset += 24;
    }
    Offset = 0;
    for (i = 10; i > 0; i--)
    {
        LCD_ShowLEDNum(Offset, 50, i - 1, color_tab[i - 1], BLACK);
        Offset += 24;
    }
    LCD_DisplayStr(96, 120, "SZWB-RedBull", RED, BLACK);
    LCD_DisplayStr(110, 180, "梦想", RED, BLACK);
    LCD_DisplayStr(100, 150, "LCD-Test", RED, BLACK);
    LCD_DisplayStr(50, 210, "旺宝电子-红牛开发板", RED, BLACK);
    HAL_Delay(3000);
}

 

 工程结构

 

 这样就可以在arduino中使用fsmc驱动的16位屏幕了   刷屏速度相当块

posted @ 2022-09-11 13:41  kyo413  阅读(362)  评论(0编辑  收藏  举报