bsp_usart.h
#ifndef __BSP_USART_H__ #define __BSP_USART_H__ #include "stm32f10x.h" #include "stdio.h" // ----------------------- 串口1-USART1 // 使用哪個串口(串口1..5) #define DEBUG_USARTx USART1 // APB2串口的同步時鍾 #define DEBUG_USART_CLK RCC_APB2Periph_USART1 // APB2系統時鍾(因為串口USART1是掛載到APB2總線上的,所以要打開APB2總線的時鍾) #define DEBUG_USART_APBxClkCmd RCC_APB2PeriphClockCmd // 串口通信的波特率 #define DEBUG_USART_BAUDRATE 19200 // ----------------------- USART GPIO 引腳宏定義 // GPIO引腳 #define DEBUG_USART_GPIO_CLK (RCC_APB2Periph_GPIOA) // APB2系統時鍾(因為串口USART1是掛載到APB2總線上的,所以要打開APB2總線的時鍾) #define DEBUG_USART_GPIO_APBxClkCmd RCC_APB2PeriphClockCmd // GPIO引腳,發送接PA9,接收接PA10 #define DEBUG_USART_TX_GPIO_PORT GPIOA #define DEBUG_USART_TX_GPIO_PIN GPIO_Pin_9 #define DEBUG_USART_RX_GPIO_PORT GPIOA #define DEBUG_USART_RX_GPIO_PIN GPIO_Pin_10 #define DEBUG_USART_IRQ USART1_IRQn #define DEBUG_USART_IRQHandler USART1_IRQHandler /* 串口調試配置函數:配置串口的相關參數,使能串口 */ void DEBUG_USART_Config(void); /* 發送一個字節 */ void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch); /* 發送字符串 */ void Usart_SendString(USART_TypeDef* pUSARTx, char* str); #endif /* __BSP_USART_H__ */
bsp_usart.c
#include "./usart/bsp_usart.h" /* 串口中斷配置函數 */ static void NVIC_Configuration(void) { NVIC_InitTypeDef NVIC_InitStructure; /* 嵌套向量中斷控制器組選擇 */ NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); /* 配置USART為中斷源 */ NVIC_InitStructure.NVIC_IRQChannel = DEBUG_USART_IRQ; /* 搶斷優先級*/ NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; /* 子優先級 */ NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; /* 使能中斷 */ NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; /* 初始化配置NVIC */ NVIC_Init(&NVIC_InitStructure); } /* 串口調試配置函數:配置串口的相關參數,使能串口 */ void DEBUG_USART_Config(void) { /* 結構體變量聲明 */ GPIO_InitTypeDef GPIO_InitStructure; // GPIO USART_InitTypeDef USART_InitStructure; // USART /* ------------ 第一步:初始化GPIO */ // 打開串口GPIO的時鍾 DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE); // 將USART Tx的GPIO配置為推挽復用模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN; // 引腳 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // 模式 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; // 速率 GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure); // 初始化結構體 // 將USART Rx的GPIO配置為浮空輸入模式 GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure); /* ------------ 第二步:配置串口的初始化結構體 */ // 打開串口外設的時鍾 DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE); /* 配置串口的工作參數 */ // 波特率 USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE; // 針數據字長 USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 停止位 USART_InitStructure.USART_StopBits = USART_StopBits_1; // 校驗位 USART_InitStructure.USART_Parity = USART_Parity_No ; // 硬件流控制 USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // 工作模式,收發一起 USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 完成串口的初始化配置 USART_Init(DEBUG_USARTx, &USART_InitStructure); /* -------------------------------------------------------- */ // 串口中斷優先級配置 //NVIC_Configuration(); // 使能串口接收中斷 //USART_ITConfig(DEBUG_USARTx, USART_IT_RXNE, ENABLE); /* -------------------------------------------------------- */ /* ------------ 第三步:使能串口 */ USART_Cmd(DEBUG_USARTx, ENABLE); } /* 發送一個字節 */ void Usart_SendByte(USART_TypeDef* pUSARTx, uint8_t ch) { /* 發送一個字節數據到USART */ USART_SendData(pUSARTx, ch); /* 等待發送數據寄存器為空 */ while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE) == RESET); } /* 發送字符串 */ void Usart_SendString(USART_TypeDef* pUSARTx, char* str) { unsigned int k=0; do { Usart_SendByte(pUSARTx, *(str + k)); k++; } while(*(str + k)!='\0'); /* 等待發送完成 */ while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC) == RESET); } /* 重定向c庫函數printf到串口,重定向后可使用printf函數 */ int fputc(int ch, FILE *f) { /* 發送一個字節數據到串口 */ USART_SendData(DEBUG_USARTx, (uint8_t) ch); /* 等待發送完畢 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET); return (ch); } /* 重定向c庫函數scanf到串口,重寫向后可使用scanf、getchar等函數 */ int fgetc(FILE *f) { /* 等待串口輸入數據 */ while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET); return (int)USART_ReceiveData(DEBUG_USARTx); }
bsp_ili9341_lcd.h
#ifndef __BSP_ILI9341_LCD_H__ #define __BSP_ILI9341_LCD_H__ #include "stm32f10x.h" /* ------------------------------- 變量宏定義 ------------------------------ */ // CS(NSS)引腳 片選選普通GPIO即可 #define ILI9341_CS_CLK RCC_APB2Periph_GPIOC #define ILI9341_CS_PORT GPIOC #define ILI9341_CS_PIN GPIO_Pin_4 // RD引腳 片選選普通GPIO即可 #define ILI9341_RD_CLK RCC_APB2Periph_GPIOC #define ILI9341_RD_PORT GPIOC #define ILI9341_RD_PIN GPIO_Pin_5 // WE引腳 片選選普通GPIO即可 #define ILI9341_WE_CLK RCC_APB2Periph_GPIOC #define ILI9341_WE_PORT GPIOC #define ILI9341_WE_PIN GPIO_Pin_6 // DC引腳 片選選普通GPIO即可 #define ILI9341_DC_CLK RCC_APB2Periph_GPIOC #define ILI9341_DC_PORT GPIOC #define ILI9341_DC_PIN GPIO_Pin_7 // BK引腳 片選選普通GPIO即可 #define ILI9341_BK_CLK RCC_APB2Periph_GPIOD #define ILI9341_BK_PORT GPIOD #define ILI9341_BK_PIN GPIO_Pin_2 // D0-D15引腳 片選選普通GPIO即可(數據引腳) #define ILI9341_DATA_CLK RCC_APB2Periph_GPIOB #define ILI9341_DATA_PORT GPIOB #define ILI9341_DATA_PIN GPIO_Pin_All /* ------------------------------- 函數宏定義 ------------------------------ */ // BK:背光引腳的GPIO打開或關閉 #define LCD_BK_ON() GPIO_ResetBits(ILI9341_BK_PORT, ILI9341_BK_PIN) #define LCD_BK_OFF() GPIO_SetBits(ILI9341_BK_PORT, ILI9341_BK_PIN) // CS #define LCD_CS_HIGH() GPIO_SetBits(ILI9341_CS_PORT, ILI9341_CS_PIN) #define LCD_CS_LOW() GPIO_ResetBits(ILI9341_CS_PORT, ILI9341_CS_PIN) // RD #define LCD_RD_HIGH() GPIO_SetBits(ILI9341_RD_PORT, ILI9341_RD_PIN) #define LCD_RD_LOW() GPIO_ResetBits(ILI9341_RD_PORT, ILI9341_RD_PIN) // WE #define LCD_WE_HIGH() GPIO_SetBits(ILI9341_WE_PORT, ILI9341_WE_PIN) #define LCD_WE_LOW() GPIO_ResetBits(ILI9341_WE_PORT, ILI9341_WE_PIN) // DC #define LCD_DC_HIGH() GPIO_SetBits(ILI9341_DC_PORT, ILI9341_DC_PIN) #define LCD_DC_LOW() GPIO_ResetBits(ILI9341_DC_PORT, ILI9341_DC_PIN) // D0-D15 #define LCD_DATA_OUT(data) GPIO_Write(ILI9341_DATA_PORT, data) // ILI9341_DATA_PORT->ODR = data #define LCD_DATA_IN() GPIO_ReadInputData(ILI9341_DATA_PORT) /* ------------------------------- 函數 ------------------------------ */ /* ILI9341初始化 */ void ILI9341_GPIO_Init(void); /* 寫命令 */ void ILI9341_Write_Cmd(uint16_t cmd); /* 寫數據 */ void ILI9341_Write_Data(uint16_t data); /* 讀數據 */ uint16_t ILI9341_Read_Data(void); /* 讀取ID */ uint16_t ILI9341_Read_ID(void); #endif /* __BSP_ILI9341_LCD_H__ */
bsp_ili9341_lcd.c
/* 1.初始化跟液晶控制相關的引腳 初始化時要確認配置GPIOB使用的PB3/PB4引腳, 需要重定義才能用作普通GPIO 2.模擬8080時序 寫命令 寫數據 讀數據 3.通過讀取ILI9341的ID測試函數 4.初始化液晶屏及配置掃描方向 5.往LCD坐標x,y寫一個特定顏色像素點 */ #include "./lcd/bsp_ili9341_lcd.h" // 這里定義一個宏,目的是不用大幅度修改代碼,方便程序維護 #define ILI9341_DELAY() ILI9341_Delay(10) static void ILI9341_Delay(__IO uint32_t nCount) { for(; nCount!=0; nCount--); } /* ILI9341初始化 */ void ILI9341_GPIO_Init(void) { GPIO_InitTypeDef GPIO_InitStructure; /* 把PB3,PB4引腳用作普通GPIO 因為PB3和PB4引腳和JTAG功能引腳共用,所以要把JTAG功能禁用,讓PB3和PB4引腳可以使用 */ RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE); // 使能復用時鍾AFIO GPIO_PinRemapConfig(GPIO_Remap_SWJ_JTAGDisable,ENABLE); /* 使能引腳相關的時鍾 */ RCC_APB2PeriphClockCmd(ILI9341_CS_CLK| ILI9341_RD_CLK| ILI9341_WE_CLK| ILI9341_DC_CLK| ILI9341_BK_CLK| ILI9341_DATA_CLK, ENABLE); /* 默認全配置成輸出模式 */ GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; // CS GPIO_InitStructure.GPIO_Pin = ILI9341_CS_PIN; GPIO_Init(ILI9341_CS_PORT, &GPIO_InitStructure); // RD GPIO_InitStructure.GPIO_Pin = ILI9341_RD_PIN; GPIO_Init(ILI9341_RD_PORT, &GPIO_InitStructure); // WE GPIO_InitStructure.GPIO_Pin = ILI9341_WE_PIN; GPIO_Init(ILI9341_DC_PORT, &GPIO_InitStructure); // DC GPIO_InitStructure.GPIO_Pin = ILI9341_DC_PIN; GPIO_Init(ILI9341_WE_PORT, &GPIO_InitStructure); // BK GPIO_InitStructure.GPIO_Pin = ILI9341_BK_PIN; GPIO_Init(ILI9341_BK_PORT, &GPIO_InitStructure); // D0-D15 GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN; GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure); // 默認點亮背光 LCD_BK_ON(); } /* 寫命令:根據時序寫 */ void ILI9341_Write_Cmd(uint16_t cmd) { LCD_CS_LOW(); ILI9341_DELAY(); LCD_DC_LOW(); ILI9341_DELAY(); LCD_RD_HIGH(); ILI9341_DELAY(); LCD_DATA_OUT(cmd); ILI9341_DELAY(); LCD_WE_LOW(); ILI9341_DELAY(); LCD_WE_HIGH(); ILI9341_DELAY(); LCD_CS_HIGH(); } /* 寫數據:根據時序寫 */ void ILI9341_Write_Data(uint16_t data) { LCD_CS_LOW(); ILI9341_DELAY(); LCD_DC_HIGH(); /* 和寫命令的區別,這里DC為高電平 */ ILI9341_DELAY(); LCD_RD_HIGH(); ILI9341_DELAY(); LCD_DATA_OUT(data); ILI9341_DELAY(); LCD_WE_LOW(); ILI9341_DELAY(); LCD_WE_HIGH(); ILI9341_DELAY(); LCD_CS_HIGH(); } /* 讀數據:根據時序寫 */ uint16_t ILI9341_Read_Data() { uint16_t data = 0; // 切換data端口為輸入模式【因為輸出模式常用,輸入不常用,所以默認定義成輸出模式】 GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure); /* 根據時序寫 */ LCD_CS_LOW(); ILI9341_DELAY(); LCD_DC_HIGH(); ILI9341_DELAY(); LCD_WE_HIGH(); ILI9341_DELAY(); LCD_RD_LOW(); ILI9341_DELAY(); data = LCD_DATA_IN(); /* 讀取到的數據 */ ILI9341_DELAY(); LCD_RD_HIGH(); ILI9341_DELAY(); LCD_CS_HIGH(); /* 切換data端口為輸出模式,方便其他方法使用 */ GPIO_InitStructure.GPIO_Pin = ILI9341_DATA_PIN; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_Init(ILI9341_DATA_PORT, &GPIO_InitStructure); // 返回數據 return data; } /* 讀取ID */ uint16_t ILI9341_Read_ID() { uint16_t temp = 0 ; // 發送讀取ID的命令:0XD3 ILI9341_Write_Cmd(0xD3); // 讀取前面兩個用不到的字節 ILI9341_Read_Data(); ILI9341_Read_Data(); // 開始正式的讀取數據 temp = ILI9341_Read_Data(); // 將讀取到的數據向左移動8位,騰出位置 temp <<= 8; // 繼續讀取數據放到temp變量中 temp |= ILI9341_Read_Data(); // 返回讀取到的ID數據 return temp; }
main.c
#include "stm32f10x.h" #include "./usart/bsp_usart.h" #include "./led/bsp_led.h" #include "./lcd/bsp_ili9341_lcd.h" int main(void) { /* LED引腳初始化 */ //LED_GPIO_Config(); /* USART串口初始化 */ DEBUG_USART_Config(); printf("這是一個LCD實驗\r\n"); /* ILI9341初始化 */ ILI9341_GPIO_Init(); // 讀取ID printf("讀取到的ID = %x\r\n\r\n", ILI9341_Read_ID()); while(1); }
實驗結果:返回9341,是ILI9341的ID