1.中断体系
1.1 NVIC的关键点
NVIC:Nest Vector Interrupt Controller,嵌套中断向量控制器,是用来管理中断嵌套的,核心任务在于其优先级的管理。NVIC给每个中断赋予先占优先级(抢占优先级)和次占优先级(响应优先级)。
CM3 内核支持256个中断,其中包含了16个内核中断和240个外部中断,并且具有256级的可编程中断设置。但STM32并没有使用CM3内核的全部东西,而是只用了它的一部分,STM32有76 个中断,包括16 个内核中断和60 个可屏蔽中断,具有16级可编程的中断优先级。而我们常用的就是这60个可屏蔽中断。
STM32将CM3内核的中断向量表进行了重新编排,将编号-3至6的中断向量定义为系统异常,编号为负的内核异常不能被设置优先级,从编号7开始为外部中断,这些中断优先级都是可以自行设置的。
(1)数据手册中相关部分浏览
(2)地址映射时0地址映射到Flash或SRAM
(3)中断向量表可以被人为重新映射,一般用来IAP中
(4)STM32采用一维的中断向量表
(5)中断优先级设置有点复杂,后面细说
1.2 起始代码中的ISR
(1)其实代码中定义了一个Vector数组
(2)WEAK声明的默认ISR
(3)用户根据需要提供自己真正有用的ISR
(4)中断要配置使能,ISR中要清挂起等,这一点和其他CPU一样
NVIC Nested vectoredinterrupt controller
嵌套向量中断控制器。
起始代码帮我们建立了中断向量表
EXTI(External interrupt/event controller)—外部中断/事件控制器
挂起寄存器保持着状态线的中断请求 挂起 标志位 从0 - 1 产生中断,没有屏蔽 ->事件处理 然后 变0;
EXTI控制器的主要特性如下:
● 每个中断/事件都有独立的触发和屏蔽
● 每个中断线都有专用的状态位
● 支持多达20个软件的中断/事件请求
● 检测脉冲宽度低于APB2时钟宽度的外部信号。(速度不能太快)参见数据手册中电气特性部分的相关参数。

这张图可以很直观的看出中断和事件的区别,当外部有信号输入时,如果通过了事件屏蔽寄存器,那么事件信号就进入脉冲触发器,引发一个脉冲信号,直接传递给相应的外设,用于触发,这就是一个纯硬件的过程,这个方式不需要CPU参与,但是这也有它的缺点,如功能比较单一,仅能提供信号,不能提供信息,也就是只能产生指定功能的事件。如果通过中断屏蔽寄存器,就被直接送到CPU中,产生中断,如进入上面的入口函数开始处理。从这就可看出,事件是单纯硬件触发执行的过程,与CPU本身设计支持有关,而中断中则可以软件实现各种功能,而低功耗模式和事件唤醒就是stm32支持的事件之一。
1.3 如何实际编程使用外部中断
(1)时钟设置并打开相应GPIO模块时钟
(2)将相应GPIO配置为浮空输入
(3)NVIC设置
(4)将外部中断线和配套的GPIO进行连接映射
(5)外部中断线使能触发
(6)准备好ISR,并在ISR处等待执行中断程序即可
typedef struct{uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.//终端号 This parameter can be a value of @ref IRQn_Type(For the complete STM32 Devices IRQ Channels list, pleaserefer to stm32f10x.h file) */uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel//抢占优先级 specified in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified//次优先级 in NVIC_IRQChannel. This parameter can be a valuebetween 0 and 15 as described in the table @ref NVIC_Priority_Table */FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel//是否开启 will be enabled or disabled.This parameter can be set either to ENABLE or DISABLE */} NVIC_InitTypeDef;
- 高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的;
- 抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断;
- 抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行;
- 如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;
数字小的优先级高
A B C D
抢占优先级 0 0 1 1
(相应)次优先级 0 1 0 1
先看抢占优先级
再看次优先级
人为设置抢占优先级和次级优先级
优先级组:4
选择合适的优先级组
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority 2^0 = 24 bits for subpriority */ 2^4 = 8#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority3 bits for subpriority */#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority2 bits for subpriority */#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority1 bits for subpriority */#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority0 bits for subpriority */
1.4 EXTI
typedef struct{uint32_t EXTI_Line; //中断线 /*!< Specifies the EXTI lines to be enabled or disabled.This parameter can be any combination of @ref EXTI_Lines */EXTIMode_TypeDef EXTI_Mode; //中断模式 /*!< Specifies the mode for the EXTI lines.This parameter can be a value of @ref EXTIMode_TypeDef */EXTITrigger_TypeDef EXTI_Trigger;// 触发模式/*!< Specifies the trigger signal active edge for the EXTI lines.This parameter can be a value of @ref EXTIMode_TypeDef */FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.This parameter can be set either to ENABLE or DISABLE */}EXTI_InitTypeDef;
Key1 ->PA0 配置为中断模式
key2 -> pC13
LED1->PG6
LED2->PG7
key1->LED1
PA0->PG6
因此选择EXTI0
代码如下:
#include "stm32f10x.h"void KEY_Init(void);void LED_Init(void);void My_EXTI_Init(void);int main(void){//起始代码 已经将时钟设置为72MHZLED_Init();KEY_Init();My_EXTI_Init();//当我们按下按键 会运行中断函数while(1){};}// key1->LED1// PA0 -> PG6void KEY_Init(void){GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量//GPIOA使能RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//配置第0个引脚为输入模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空GPIO_Init(GPIOA, &GPIO_InitStructure);}//初始化LED IOvoid LED_Init(void){GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOG, ENABLE);//配置第6个引脚为输出模式GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_Init(GPIOG,&GPIO_InitStructure);}void My_EXTI_Init(void){NVIC_InitTypeDef NVIC_InitStructure; //NVICEXTI_InitTypeDef EXTI_InitStructure; //EXTI结构体RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);GPIO_EXTILineConfig(GPIO_PortSourceGPIOA, GPIO_PinSource0); //选择A0管脚用作外部中断线路//抢占优先级 2个抢占优先级 8个次优先级NVIC_PriorityGroupConfig(NVIC_PriorityGroup_0);NVIC_InitStructure.NVIC_IRQChannel = EXTI0_IRQn;//EXTI0 NVIC 配置NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //抢占优先级NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; //子优先级NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能 中断使能NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器//EXTI配置EXTI_InitStructure.EXTI_Line = EXTI_Line0; //lin0 EXTI中断/事件线选择EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //下降沿触发EXTI_InitStructure.EXTI_LineCmd = ENABLE;EXTI_Init(&EXTI_InitStructure); //初始化中断}//stm32f10x_it.c//中断处理函数 在这里进行处理void EXTI0_IRQHandler(void){if(EXTI_GetITStatus(EXTI_Line0) != RESET){GPIO_WriteBit(GPIOG, GPIO_Pin_6, (BitAction)(1 - GPIO_ReadOutputDataBit(GPIOG, GPIO_Pin_6)));EXTI_ClearITPendingBit(EXTI_Line0);}}
2.FSMC
1.概念
- 基本概念
(1)flexible static memory controller 灵活的静态内存控制器
(2)内部外设(寄存器+IO口)
(3)功能目标:让STM32可以对接外部存储器(NorFlash、NandFlash、SRAM、PCCard···)
- SoC如何扩展外部存储器
(1)专用内部控制器一对一服务 SD
(2)FSMC一对多服务
- FSMC的优缺点
(1)优点:灵活适配,有限资源实现多种外部存储器的支持
(2)缺点:配置复杂,需要考虑接口时序的细节
2.FSMC操控LCD
- LCD的操作接口
(1)8080接口:控制接口WR(写时钟)+RD(读时钟)+RS(cmd/data)+DataPort8/16 CS片选
(2)接口本质:低层的时序+高层的类SRAM
(3)操作要求:只要按照8080接口时序,任何SoC任何方式都可以与LCD进行互操作
- STM32的FSMC初步学习
(1)支持Nor/PSRAM(接口类似SRAM)、Nand、PCCard等多种类型外存
(2)FSMC为其支持的各种各个外存都提供了地址映射空间
(3)4个块共1GB地址空间,每块256MB;每块又分为4个子存储块,每字块64MB 份子快是为了多接几个设备
(4)LCD的接口类似于NorFlash/SRAM,所以可以用第1块的4部分任何一部分
3.相关GPIO
(1)DB0-15,16数据位,因此FSMC控制器FSMC_A[24:0]内部地址 对应HADDR[25:1] 外部地址 通过内部地址来访问外部地址
最简单的是1-1对应,
8位:1个字节
16位:2个字节
对齐访问:
详细解释:
实质就是将FSMC_A的值,左移一位,然后放到HADDR中,也就是将其乘以2倍,这样FSMC_A和HADDR的值就对应了,只要传对应值就可以了
2^26 = 0X0400 0000 = 64MB,每个 BANK 有4*64MB = 256MB
64MB:FSMC_Bank1_NORSRAM1:0X6000 0000 ~ 0X63FF FFFF
64MB:FSMC_Bank1_NORSRAM2:0X6400 0000 ~ 0X67FF FFFF
64MB:FSMC_Bank1_NORSRAM3:0X6800 0000 ~ 0X6BFF FFFF
64MB:FSMC_Bank1_NORSRAM4:0X6C00 0000 ~ 0X6FFF FFFF
选择BANK1-BORSRAM4 连接 TFT,地址范围为0X6C00 0000 ~ 0X6FFF FFFF
YS-F1P开发板选择 FSMC_A0 接LCD的DC(寄存器/数据选择)脚
寄存器基地址 = 0X6C00 0000 命令总线地址
RAM基地址 = 0X6C00 0002 = 0X6C00 0000+(1<<(0+1)) 数据总线地址
如果电路设计时选择不同的地址线时,地址要重新计算
(2)GPD、GPE、GPF、GPG共4个端口和FSMC有关,但是GPF都是A线(地址)所以LCD用不到,用不到地址线
(3)NOE接RD 读,NWE接WR 写,A0接RS(0 寄存器 写配置数值/1 数据选择 写数据),NE4接CS
block1:60000000-6FFFFFFF
block1-子块1:60000000-63FFFFFF NE1
block1-子块2:64000000-67FFFFFF
block1-子块3:68000000-6BFFFFFF
block1-子块4:6C000000-6FFFFFFF NE4
RS接了FSMC地址线A0,只需要A0为0就是cmd,为1就是DATA
如何控制?
不能直接单独IO控制,通过写地址来完成。
6C00 0000 这个地址对应A0的地方(bit2)为0,所以直接写6C00 0000时就是写cmd 写命令
6C00 0002 这个地址对应A0的地方(bit2)为1,所以直接写6C00 0002就是写DATA 写数据
4.标准库
(1)只看NOR/SRAM部分,其余Nand、PCCard等不看
(2)重点就FSMC_NORSRAMInit一个函数,FSMC_NORSRAMInitTypeDef一个结构体
FSMC_NORSRAMCmd
总线操作:
RS接的可不是GPIO,是FSMC地址总线的一根.FSMC进行读写操作的时候会在地址总线根据要读写的地址输出电平的.
不是通过操作GPIO来操作RS,而是直接根据地址总线地址的不同来完成操作RS
#include "stm32f10x.h"#include "lcd_driver.h"#include "stdlib.h"uint16_t color;static void delay(void){uint32_t i,j;for(i=0;i<0x7FF;i++)for(j=0;j<0xFFF;j++);}int main(void){//初始化LCDBSP_LCD_Init();//开启背光LCD_BK_ON();//设置颜色为蓝色LCD_Clear(0, 0, LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGTH, BLUE);//随机颜色srand(0xffff);while(1){//随机颜色color = rand();//设置颜色LCD_Clear(0,0,LCD_DEFAULT_WIDTH, LCD_DEFAULT_HEIGTH, color);//延时delay();};return 0;}
#ifndef __LEC_DRIVER__H#define __LEC_DRIVER__H#include "stm32f10x.h"typedef enum{USB_FONT_16=16,USB_FONT_24=24,}USB_FONT_Typdef;#define IS_USB_FONT(FONT) (((FONT) == USB_FONT_16) || ((FONT) == USB_FONT_24))/******************************* ILI9488 显示屏的 FSMC 参数定义 ***************/#define FSMC_LCD_CMD ((uint32_t)0x6C000000) //FSMC_Bank1_NORSRAM1用于LCD命令操作的地址#define FSMC_LCD_DATA ((uint32_t)0x6C000002) //FSMC_Bank1_NORSRAM1用于LCD数据操作的地址#define LCD_WRITE_CMD(x) *(__IO uint16_t *)FSMC_LCD_CMD = x#define LCD_WRITE_DATA(x) *(__IO uint16_t *)FSMC_LCD_DATA = x#define LCD_READ_DATA() *(__IO uint16_t *)FSMC_LCD_DATA#define FSMC_LCD_BACKx FSMC_Bank1_NORSRAM4/************************* ILI9488 显示屏8080通讯引脚定义 *********************///片选CS#define FSMC_LCD_CS_APBxClock_FUN RCC_APB2PeriphClockCmd#define FSMC_LCD_CS_CLK RCC_APB2Periph_GPIOG#define FSMC_LCD_CS_PORT GPIOG#define FSMC_LCD_CS_PIN GPIO_Pin_12//DR->区分写命令还是写地址#define FSMC_LCD_DC_APBxClock_FUN RCC_APB2PeriphClockCmd#define FSMC_LCD_DC_CLK RCC_APB2Periph_GPIOF#define FSMC_LCD_DC_PORT GPIOF#define FSMC_LCD_DC_PIN GPIO_Pin_0//背光#define FSMC_LCD_BK_APBxClock_FUN RCC_APB2PeriphClockCmd#define FSMC_LCD_BK_CLK RCC_APB2Periph_GPIOF#define FSMC_LCD_BK_PORT GPIOF#define FSMC_LCD_BK_PIN GPIO_Pin_10#define LCD_BK_ON() GPIO_SetBits(FSMC_LCD_BK_PORT,FSMC_LCD_BK_PIN)#define LCD_BK_OFF() GPIO_ResetBits(FSMC_LCD_BK_PORT,FSMC_LCD_BK_PIN)/**************** 显示方向选择,可选(1,2,3,4)四个方向 *************************///#define LCD_DIRECTION 1 // 原点在屏幕左上角 X*Y=320*480#define LCD_DIRECTION 2 // 原点在屏幕右上角 X*Y=480*320//#define LCD_DIRECTION 3 // 原点在屏幕右下角 X*Y=320*480//#define LCD_DIRECTION 4 // 原点在屏幕左下角 X*Y=480*320/******** ILI934 显示屏全屏默认(扫描方向为1时)最大宽度和最大高度*************/#if (LCD_DIRECTION==1)||(LCD_DIRECTION==3)#define LCD_DEFAULT_WIDTH 320 // X轴长度#define LCD_DEFAULT_HEIGTH 480 // Y轴长度#else#define LCD_DEFAULT_WIDTH 480 // X轴长度#define LCD_DEFAULT_HEIGTH 320 // Y轴长度#endif/******************************* 定义 ILI9488 显示屏常用颜色 ********************************/#define BACKGROUND WHITE //默认背景颜色#define WHITE 0xFFFF //白色#define BLACK 0x0000 //黑色#define GREY 0xF7DE //灰色#define BLUE 0x001F //蓝色#define RED 0xF800 //红色#define MAGENTA 0xF81F //红紫色,洋红色#define GREEN 0x07E0 //绿色#define CYAN 0x7FFF //蓝绿色,青色#define YELLOW 0xFFE0 //黄色#define BRED 0xF81F#define GRED 0xFFE0#define GBLUE 0x07FFvoid LCD_SetDirection( uint8_t ucOption );void LCD_Clear(uint16_t usX,uint16_t usY,uint16_t usWidth,uint16_t usHeight,uint16_t usColor);void LCD_OpenWindow(uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight);uint32_t BSP_LCD_Init(void);static __inline void LCD_FillColor ( uint32_t ulAmout_Point, uint16_t usColor );#endif
#include "lcd_driver.h"// 保存当前检查到的液晶模块IDvolatile uint32_t lcd_id=0;//delay函数static void LCD_DELAY( __IO uint32_t nCount ){for ( ; nCount != 0; nCount -- );}//初始化使用的引脚static void LCD_GPIO_Config ( void ){GPIO_InitTypeDef GPIO_InitStructure;/* 使能复用IO时钟:复用为fsmc功能 */RCC_APB2PeriphClockCmd ( RCC_APB2Periph_AFIO, ENABLE );/* 使能FSMC对应相应管脚时钟 */RCC_APB2PeriphClockCmd ( RCC_APB2Periph_GPIOD | RCC_APB2Periph_GPIOE, ENABLE );FSMC_LCD_CS_APBxClock_FUN ( FSMC_LCD_CS_CLK, ENABLE ); // FSMC_LCD_CS_APBxClock_FUN = RCC_APB2PeriphClockCmdFSMC_LCD_DC_APBxClock_FUN ( FSMC_LCD_DC_CLK, ENABLE );FSMC_LCD_BK_APBxClock_FUN ( FSMC_LCD_BK_CLK, ENABLE );/* 配置FSMC相对应的数据线,FSMC-D0~D15: PD 14 15 0 1,PE 7 8 9 10 11 12 13 14 15,PD 8 9 10 */GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_8 | GPIO_Pin_9 |GPIO_Pin_10 | GPIO_Pin_14 | GPIO_Pin_15;GPIO_Init ( GPIOD, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = 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 );/* 配置FSMC相对应的控制线* PD4-FSMC_NOE :LCD-RD* PD5-FSMC_NWE :LCD-WR* PG12-FSMC_NE4 :LCD-CS* PF0-FSMC_A0 :LCD-DC*/GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_4;GPIO_Init (GPIOD, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5;GPIO_Init (GPIOD, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = FSMC_LCD_CS_PIN;GPIO_Init ( FSMC_LCD_CS_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = FSMC_LCD_DC_PIN;GPIO_Init ( FSMC_LCD_DC_PORT, & GPIO_InitStructure );/* 配置LCD背光控制管脚BK*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_10MHz;GPIO_InitStructure.GPIO_Pin = FSMC_LCD_BK_PIN;GPIO_Init ( FSMC_LCD_BK_PORT, & GPIO_InitStructure );/* 初始化时先不开背光 */GPIO_ResetBits(FSMC_LCD_BK_PORT,FSMC_LCD_BK_PIN);}//FSMC模式配置和时序static void LCD_FSMC_Config ( void ){FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;FSMC_NORSRAMTimingInitTypeDef fsmc_lcd;/* 使能FSMC时钟*/RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_FSMC, ENABLE );fsmc_lcd.FSMC_AddressSetupTime = 0x02; //地址建立时间fsmc_lcd.FSMC_AddressHoldTime = 0x00; //地址保持时间fsmc_lcd.FSMC_DataSetupTime = 0x05; //数据建立时间fsmc_lcd.FSMC_BusTurnAroundDuration = 0x00;fsmc_lcd.FSMC_CLKDivision = 0x00;fsmc_lcd.FSMC_DataLatency = 0x00;fsmc_lcd.FSMC_AccessMode = FSMC_AccessMode_B; //模式B比较适用于LCD//数据手册有相关介绍FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_LCD_BACKx;FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;//这里使用的是NOR来代替 其实和SARM都可以驱动FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;//地址和数据复用使能关闭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_Disable;FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = & fsmc_lcd;FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = & fsmc_lcd;FSMC_NORSRAMInit ( & FSMC_NORSRAMInitStructure );/* 使能 FSMC_Bank1_NORSRAM4 */FSMC_NORSRAMCmd ( FSMC_LCD_BACKx, ENABLE );}//初始化LCD寄存器//设置了像素点格式、屏幕扫描方式、横屏竖屏等配置,由厂家提供static void ILI9488_REG_Config ( void ){//************* Start Initial Sequence **********///* PGAMCTRL (Positive Gamma Control) (E0h) */LCD_WRITE_CMD(0xE0);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x07);LCD_WRITE_DATA(0x10);LCD_WRITE_DATA(0x09);LCD_WRITE_DATA(0x17);LCD_WRITE_DATA(0x0B);LCD_WRITE_DATA(0x41);LCD_WRITE_DATA(0x89);LCD_WRITE_DATA(0x4B);LCD_WRITE_DATA(0x0A);LCD_WRITE_DATA(0x0C);LCD_WRITE_DATA(0x0E);LCD_WRITE_DATA(0x18);LCD_WRITE_DATA(0x1B);LCD_WRITE_DATA(0x0F);/* NGAMCTRL (Negative Gamma Control) (E1h) */LCD_WRITE_CMD(0XE1);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x17);LCD_WRITE_DATA(0x1A);LCD_WRITE_DATA(0x04);LCD_WRITE_DATA(0x0E);LCD_WRITE_DATA(0x06);LCD_WRITE_DATA(0x2F);LCD_WRITE_DATA(0x45);LCD_WRITE_DATA(0x43);LCD_WRITE_DATA(0x02);LCD_WRITE_DATA(0x0A);LCD_WRITE_DATA(0x09);LCD_WRITE_DATA(0x32);LCD_WRITE_DATA(0x36);LCD_WRITE_DATA(0x0F);/* Adjust Control 3 (F7h) */LCD_WRITE_CMD(0XF7);LCD_WRITE_DATA(0xA9);LCD_WRITE_DATA(0x51);LCD_WRITE_DATA(0x2C);LCD_WRITE_DATA(0x82);/* DSI write DCS command, use loose packet RGB 666 *//* Power Control 1 (C0h) */LCD_WRITE_CMD(0xC0);LCD_WRITE_DATA(0x11);LCD_WRITE_DATA(0x09);/* Power Control 2 (C1h) */LCD_WRITE_CMD(0xC1);LCD_WRITE_DATA(0x41);/* VCOM Control (C5h) */LCD_WRITE_CMD(0XC5);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x0A);LCD_WRITE_DATA(0x80);/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */LCD_WRITE_CMD(0xB1);LCD_WRITE_DATA(0xB0);LCD_WRITE_DATA(0x11);/* Display Inversion Control (B4h) */LCD_WRITE_CMD(0xB4);LCD_WRITE_DATA(0x02);/* Display Function Control (B6h) */LCD_WRITE_CMD(0xB6);LCD_WRITE_DATA(0x02);LCD_WRITE_DATA(0x22);/* Entry Mode Set (B7h) */LCD_WRITE_CMD(0xB7);LCD_WRITE_DATA(0xc6);/* HS Lanes Control (BEh) */LCD_WRITE_CMD(0xBE);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x04);/* Set Image Function (E9h) */LCD_WRITE_CMD(0xE9);LCD_WRITE_DATA(0x00);/* 设置屏幕方向和尺寸 */LCD_SetDirection(LCD_DIRECTION);/* Interface Pixel Format (3Ah) */LCD_WRITE_CMD(0x3A);LCD_WRITE_DATA(0x55);/* 0x55 : 16 bits/pixel *//* Sleep Out (11h) */LCD_WRITE_CMD(0x11);LCD_DELAY(120*2000);/* Display On */LCD_WRITE_CMD(0x29);}void LCD_SetDirection( uint8_t ucOption ){/*** Memory Access Control (36h)* This command defines read/write scanning direction of the frame memory.** These 3 bits control the direction from the MPU to memory write/read.** Bit Symbol Name Description* D7 MY Row Address Order -- 以X轴镜像* D6 MX Column Address Order -- 以Y轴镜像* D5 MV Row/Column Exchange -- X轴与Y轴交换* D4 ML Vertical Refresh Order LCD vertical refresh direction control.** D3 BGR RGB-BGR Order Color selector switch control* (0 = RGB color filter panel, 1 = BGR color filter panel )* D2 MH Horizontal Refresh ORDER LCD horizontal refreshing direction control.* D1 X Reserved Reserved* D0 X Reserved Reserved*/switch ( ucOption ){case 1:// 左上角->右下角// (0,0) ___ x(320)// |// |// | y(480)LCD_WRITE_CMD(0x36);LCD_WRITE_DATA(0x08);LCD_WRITE_CMD(0x2A);LCD_WRITE_DATA(0x00); /* x start */LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01); /* x end */LCD_WRITE_DATA(0x3F);LCD_WRITE_CMD(0x2B);LCD_WRITE_DATA(0x00); /* y start */LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01); /* y end */LCD_WRITE_DATA(0xDF);break;case 2:// 右上角-> 左下角// y(320)___ (0,0)// |// |// |x(480)LCD_WRITE_CMD(0x36);LCD_WRITE_DATA(0x68);LCD_WRITE_CMD(0x2A);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0xDF);LCD_WRITE_CMD(0x2B);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0x3F);break;case 3:// 右下角->左上角// |y(480)// |// x(320) ___|(0,0)LCD_WRITE_CMD(0x36);LCD_WRITE_DATA(0xC8);LCD_WRITE_CMD(0x2A);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0x3F);LCD_WRITE_CMD(0x2B);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0x3F);break;case 4:// 左下角->右上角// |x(480)// |// |___ y(320)LCD_WRITE_CMD(0x36);LCD_WRITE_DATA(0xA8);LCD_WRITE_CMD(0x2A);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0xDF);LCD_WRITE_CMD(0x2B);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x00);LCD_WRITE_DATA(0x01);LCD_WRITE_DATA(0x3F);break;}/* 开始向GRAM写入数据 */LCD_WRITE_CMD (0x2C);}/*** 函数功能: 读取液晶模组ID* 输入参数: 无* 返 回 值: 液晶模组的ID* 说 明:这是通过读取04H寄存器获取得到液晶模组ID,该ID值有液晶厂家编程,不同液晶* 厂家的液晶模组得到的ID值可能不同。这也可以分辨不同型号的液晶模组。*/static uint32_t LCD_ReadID(void){uint16_t buf[4];LCD_WRITE_CMD(0x04);buf[0] = LCD_READ_DATA(); // 第一个读取数据无效buf[1] = LCD_READ_DATA()&0x00ff; // 只有低8位数据有效buf[2] = LCD_READ_DATA()&0x00ff; // 只有低8位数据有效buf[3] = LCD_READ_DATA()&0x00ff; // 只有低8位数据有效return (buf[1] << 16) + (buf[2] << 8) + buf[3];}/*** 函数功能: 液晶模组初始化* 输入参数: 无* 返 回 值: 无* 说 明:无*/uint32_t BSP_LCD_Init(void){LCD_GPIO_Config();LCD_FSMC_Config();lcd_id = LCD_ReadID();if(lcd_id == 0x548066 || lcd_id == 0x8066){ILI9488_REG_Config();}LCD_Clear(0,0,LCD_DEFAULT_WIDTH,LCD_DEFAULT_HEIGTH,BLACK);LCD_DELAY(2000);return lcd_id;}void LCD_Clear(uint16_t usX,uint16_t usY,uint16_t usWidth,uint16_t usHeight,uint16_t usColor){#if 0 /* 优化代码执行速度 */uint32_t i;uint32_t n,m;/* 在LCD显示器上开辟一个窗口 */LCD_OpenWindow(usX,usY,usWidth,usHeight);/* 开始向GRAM写入数据 */LCD_WRITE_CMD(0x2C);m = usWidth * usHeight; //320 * 480n = m / 8; // 320 * 480 / 8m = m - 8 * n; // 320 * 480 - 320 * 480for(i=0;i<n;i++){LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);LCD_WRITE_DATA(usColor);}for(i=0;i<m;i++){LCD_WRITE_DATA(usColor);}#else/* 在LCD显示器上开辟一个窗口 */LCD_OpenWindow(usX,usY,usWidth,usHeight);/* 在LCD显示器上以某一颜色填充像素点 */LCD_FillColor(usWidth*usHeight, usColor);#endif}//开窗函数//该函数的作用是在LCD显示器上开辟一个窗口,该函数的参数有四个,//从左到右的分别代表的含义为://在特定扫描方向下窗口的起点x坐标、//起点Y坐标、窗口的宽度、窗口的高度。通过查看ILI9488手册可以找到//Ox2A命令的含义是列地址控制命令,0x2B页(行)地址控制命令,两个命令都有//四个参数,对应起点终点、高和低8位。void LCD_OpenWindow(uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight){LCD_WRITE_CMD(0x2A); /* 设置X坐标 */LCD_WRITE_DATA(usX>>8); /* 设置起始点:先高8位 */LCD_WRITE_DATA(usX&0xff); /* 然后低8位 */LCD_WRITE_DATA((usX+usWidth-1)>>8); /* 设置结束点:先高8位 */LCD_WRITE_DATA((usX+usWidth-1)&0xff);/* 然后低8位 */LCD_WRITE_CMD(0x2B); /* 设置Y坐标*/LCD_WRITE_DATA(usY>>8); /* 设置起始点:先高8位 */LCD_WRITE_DATA(usY&0xff); /* 然后低8位 */LCD_WRITE_DATA((usY+usHeight-1)>>8); /* 设置结束点:先高8位 */LCD_WRITE_DATA((usY+usHeight-1)&0xff);/* 然后低8位 */}//以某色素填充点//主要使用Ox2C命令,//本命令用于表示开始写入像素显示数据,紧//跟着本命令后面的即为写入到GRAM的 RGB5:6:5的颜色数据,static __inline void LCD_FillColor ( uint32_t ulAmout_Point, uint16_t usColor ){uint32_t i = 0;/* 开始向GRAM写入数据 */LCD_WRITE_CMD ( 0x2C );for ( i = 0; i < ulAmout_Point; i ++ )LCD_WRITE_DATA ( usColor );}
