基于stm32F103的座面聲控臺燈

1.基本內容:

????????設計一個放置在桌面使用的臺燈,使用220v交流電供電。具備顯示屏能夠實時顯示日期(年、月、日和星期),時間(小時、分鐘、秒)和溫度(攝氏度);能夠通過語音交互播報實時日期、時間或者溫度;能夠通過語音交互控制桌面臺燈的開啟與關閉(或者明暗程度)。設計符合安全規范,符合日常家居使用習慣,操作簡便,符合人性化需求。

2.演示視頻

桌面指針式時鐘與語音臺燈設計

3.設計準備

????????LD3320語音識別模塊、SYN6288語音合成模塊、DHT11溫濕度傳感器模塊+SL-Link下載器、STM32F103VET6、杜邦線、ILI9341液晶屏(野火stm32f103可一起購買)。

4.代碼講解

syn6288.c

#include "syn6288.h"
#include "stdarg.h"xSYN6288_TypeDef  xSYN6288;                // 全局變量結構體static void delay_ms(uint32_t ms)          // 簡單的延時函數
{uint32_t i = 0;ms = ms * 11993;                       for (; i < ms; i++);    
}//Music:選擇背景音樂。0:無背景音樂,1~15:選擇背景音樂
// SYN6288_SendFrameInfo(0, "[v10][m1][t5]結算金額 為32.8元");
// 參數: 0~15  :  背景音樂,0_無背景音樂,1~15_背景音樂可選
//       [V0~16]:  文本朗讀音量,0_最小,16_最大
//       [m0~16]:  背景音樂音量,0_最小,16_最大
//       [t0~5]:   朗讀語速,0_最慢,5_最快
//       其它不常用功能請參考數據手冊
static void SYN6288_SendFrameInfo(uint8_t Music, uint8_t *HZdata)
{/****************需要發送的文本**********************************/unsigned  char  Frame_Info[50];unsigned  char  HZ_Length;unsigned  char  ecc  = 0;             //定義校驗字節unsigned  int i = 0;HZ_Length = strlen((char *)HZdata);   //需要發送文本的長度/*****************幀固定配置信息**************************************/Frame_Info[0] = 0xFD ;                //構造幀頭FDFrame_Info[1] = 0x00 ;                //構造數據區長度的高字節Frame_Info[2] = HZ_Length + 3;        //構造數據區長度的低字節Frame_Info[3] = 0x01 ;                //構造命令字:合成播放命令Frame_Info[4] = 0x01 | Music << 4 ;   //構造命令參數:背景音樂設定/*******************校驗碼計算***************************************/for (i = 0; i < 5; i++)               //依次發送構造好的5個幀頭字節ecc = ecc ^ (Frame_Info[i]);      //對發送的字節進行異或校驗for (i = 0; i < HZ_Length; i++)       //依次發送待合成的文本數據ecc = ecc ^ (HZdata[i]);          //對發送的字節進行異或校驗/*******************發送幀信息***************************************/memcpy(&Frame_Info[5], HZdata, HZ_Length);Frame_Info[5 + HZ_Length] = ecc;if (xSYN6288.USARTx == USART1)   USART1_SendData(Frame_Info, 5 + HZ_Length + 1);if (xSYN6288.USARTx == USART2)   USART2_SendData(Frame_Info, 5 + HZ_Length + 1);if (xSYN6288.USARTx == USART3)   USART3_SendData(Frame_Info, 5 + HZ_Length + 1);if (xSYN6288.USARTx == UART4)    UART4_SendData(Frame_Info, 5 + HZ_Length + 1);if (xSYN6288.USARTx == UART5)    UART5_SendData(Frame_Info, 5 + HZ_Length + 1);
}/***********************************************************
* 名    稱: SYN6288_Set(uint8_t *Info_data)
* 功    能: 主函數 程序入口
* 入口參數: *Info_data:固定的配置信息變量
* 出口參數:
* 說    明:本函數用于配置,停止合成、暫停合成等設置 ,默認波特率9600bps。
* 調用方法:通過調用已經定義的相關數組進行配置。
**********************************************************/
static void SYN6288_Set(uint8_t *Info_data)
{uint8_t Com_Len;Com_Len = strlen((char *)Info_data);UART5_SendData(Info_data, Com_Len);
}/******************************************************************************* 函  數: SYN6288_Say* 功  能: 輸出合成語音* 參  數: 格式化參數,如printf參數般一樣的用法* 返回值: 無* 示  例: SYN6288_Say("你好嗎?");
*******************************************************************************/
void SYN6288_Say(char *fmt, ...)
{static char  str_1[200];   // 緩存區1,模塊每次可轉換200字節static char  str_2[200];   // 緩存區2,模塊每次可轉換200字節va_list ap;va_start(ap, fmt);vsprintf(str_1, fmt, ap);va_end(ap);sprintf(str_2, "[d][V12][m15][t5]%s", str_1);  // [d]恢復默認狀態,[V12]朗讀音量0~16,[m15]背景音量0~16,[t5]語速0~5SYN6288_SendFrameInfo(0, (uint8_t *)str_2); // 無背景音樂
}/******************************************************************************* 函  數: SYN6288_Init* 功  能: 初始化所用串口, 模塊默認通信波特率9600* 參  數: 串口-USARTx* 返回值: 無* 示  例: SYN6288_Init(USART1);
*******************************************************************************/
void SYN6288_Init(USART_TypeDef *USARTx)
{uint16_t baudrate = 9600;      // 默認波特率9600bps。delay_ms(200);                 // 上電后,稍作延時,等待模塊進入穩定狀態if (USARTx == USART1)    USART1_Init(baudrate);if (USARTx == USART2)    USART2_Init(baudrate);if (USARTx == USART3)    USART3_Init(baudrate);
#ifdef STM32F10X_HDif (USARTx == UART4)     UART4_Init(baudrate);if (USARTx == UART5)     UART5_Init(baudrate);
#endifxSYN6288.FlagOkay = 0;         // 初始化狀態xSYN6288.USARTx   = USARTx;    // 記錄所用串口端口
}

DHT11.c

#include "DTH11.h"
#include "bsp_systick.h"
#include "stdio.h"
static void                           DHT11_GPIO_Config                       ( void );
static void                           DHT11_Mode_IPU                          ( void );
static void                           DHT11_Mode_Out_PP                       ( void );
static uint8_t                        DHT11_ReadByte                          ( void );/*** @brief  DHT11 初始化函數* @param  無* @retval 無*/
void DHT11_Init ( void )
{DHT11_GPIO_Config ();DHT11_Dout_1;               // 拉高GPIOB10
}/*
* 函數名:DHT11_GPIO_Config
* 描述  :配置DHT11用到的I/O口
* 輸入  :無
* 輸出  :無
*/
static void DHT11_GPIO_Config ( void )
{               /*定義一個GPIO_InitTypeDef類型的結構體*/GPIO_InitTypeDef GPIO_InitStructure;/*開啟DHT11_Dout_GPIO_PORT的外設時鐘*/DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );       /*選擇要控制的DHT11_Dout_GPIO_PORT引腳*/                                                                                                                          GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;       /*設置引腳模式為通用推挽輸出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*設置引腳速率為50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*調用庫函數,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );                  }/*
* 函數名:DHT11_Mode_IPU
* 描述  :使DHT11-DATA引腳變為上拉輸入模式
* 輸入  :無
* 輸出  :無
*/
static void DHT11_Mode_IPU(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*選擇要控制的DHT11_Dout_GPIO_PORT引腳*/       GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;/*設置引腳模式為浮空輸入模式*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;/*調用庫函數,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);         }/*
* 函數名:DHT11_Mode_Out_PP
* 描述  :使DHT11-DATA引腳變為推挽輸出模式
* 輸入  :無
* 輸出  :無
*/
static void DHT11_Mode_Out_PP(void)
{GPIO_InitTypeDef GPIO_InitStructure;/*選擇要控制的DHT11_Dout_GPIO_PORT引腳*/                                                                                                                          GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;       /*設置引腳模式為通用推挽輸出*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;   /*設置引腳速率為50MHz */   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;/*調用庫函數,初始化DHT11_Dout_GPIO_PORT*/GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);                  }/*
* 從DHT11讀取一個字節,MSB先行
*/
static uint8_t DHT11_ReadByte ( void )
{uint8_t i, temp=0;for(i=0;i<8;i++)   {         /*每bit以50us低電平標置開始,輪詢直到從機發出 的50us 低電平 結束*/  while(DHT11_Dout_IN()==Bit_RESET);/*DHT11 以26~28us的高電平表示“0”,以70us高電平表示“1”,*通過檢測 x us后的電平即可區別這兩個狀 ,x 即下面的延時*/Systick_Delay_us(40); //延時x us 這個延時需要大于數據0持續的時間即可                     if(DHT11_Dout_IN()==Bit_SET)/* x us后仍為高電平表示數據“1” */{/* 等待數據1的高電平結束 */while(DHT11_Dout_IN()==Bit_SET);temp|=(uint8_t)(0x01<<(7-i));  //把第7-i位置1,MSB先行}else         // x us后為低電平表示數據“0”{                          temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行}}return temp;}/*
* 一次完整的數據傳輸為40bit,高位先出
* 8bit 濕度整數 + 8bit 濕度小數 + 8bit 溫度整數 + 8bit 溫度小數 + 8bit 校驗和
*/
uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
{  /*輸出模式*/DHT11_Mode_Out_PP();/*主機拉低*/DHT11_Dout_0;/*延時18ms*/Systick_Delay_ms(18);/*總線拉高 主機延時30us*/DHT11_Dout_1;Systick_Delay_us(30);   //延時30us/*主機設為輸入 判斷從機響應信號*/DHT11_Mode_IPU();/*判斷從機是否有低電平響應信號 如不響應則跳出,響應則向下運行*/   if(DHT11_Dout_IN()==Bit_RESET)     {/*輪詢直到從機發出 的80us 低電平 響應信號結束*/  while(DHT11_Dout_IN()==Bit_RESET);/*輪詢直到從機發出的 80us 高電平 標置信號結束*/while(DHT11_Dout_IN()==Bit_SET);/*開始接收數據*/   DHT11_Data->humi_int= DHT11_ReadByte();DHT11_Data->humi_deci= DHT11_ReadByte();DHT11_Data->temp_int= DHT11_ReadByte();DHT11_Data->temp_deci= DHT11_ReadByte();DHT11_Data->check_sum= DHT11_ReadByte();/*讀取結束,引腳改為輸出模式*/DHT11_Mode_Out_PP();/*主機拉高*/DHT11_Dout_1;/*檢查讀取的數據是否正確*/if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)return SUCCESS;elsereturn ERROR;}elsereturn ERROR;}

ili9341.c

/********************************************************************************* @file    bsp_ili9341_lcd.c* @version V1.0* @date    2013-xx-xx* @brief   ili9341液晶屏驅動******************************************************************************* @attention** 實驗平臺:秉火 F103-指南者 STM32 開發板 * 論壇    :http://www.firebbs.cn* 淘寶    :http://firestm32.taobao.com********************************************************************************/ #include "./lcd/bsp_ili9341_lcd.h"
#include "./font/fonts.h"	
#include <math.h>//根據液晶掃描方向而變化的XY像素寬度
//調用ILI9341_GramScan函數設置方向時會自動更改
uint16_t LCD_X_LENGTH = ILI9341_LESS_PIXEL;
uint16_t LCD_Y_LENGTH = ILI9341_MORE_PIXEL;//液晶屏掃描模式,本變量主要用于方便選擇觸摸屏的計算參數
//參數可選值為0-7
//調用ILI9341_GramScan函數設置方向時會自動更改
//LCD剛初始化完成時會使用本默認值
uint8_t LCD_SCAN_MODE = 6;/*** @brief  向ILI9341寫入命令* @param  usCmd :要寫入的命令(表寄存器地址)* @retval 無*/	
__inline void ILI9341_Write_Cmd ( uint16_t usCmd )
{* ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_CMD ) = usCmd;}/*** @brief  向ILI9341寫入數據* @param  usData :要寫入的數據* @retval 無*/	
__inline void ILI9341_Write_Data ( uint16_t usData )
{* ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) = usData;}/*** @brief  從ILI9341讀取數據* @param  無* @retval 讀取到的數據*/	
__inline uint16_t ILI9341_Read_Data ( void )
{return ( * ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) );}/*** @brief  用于 ILI9341 簡單延時函數* @param  nCount :延時計數值* @retval 無*/	
static void ILI9341_Delay ( __IO uint32_t nCount )
{for ( ; nCount != 0; nCount -- );}/*** @brief  初始化ILI9341的IO引腳* @param  無* @retval 無*/
static void ILI9341_GPIO_Config ( void )
{GPIO_InitTypeDef GPIO_InitStructure;/* 使能FSMC對應相應管腳時鐘*/RCC_APB2PeriphClockCmd ( 	/*控制信號*/ILI9341_CS_CLK|ILI9341_DC_CLK|ILI9341_WR_CLK|ILI9341_RD_CLK	|ILI9341_BK_CLK|ILI9341_RST_CLK|/*數據信號*/ILI9341_D0_CLK|ILI9341_D1_CLK|	ILI9341_D2_CLK | ILI9341_D3_CLK | ILI9341_D4_CLK|ILI9341_D5_CLK|ILI9341_D6_CLK | ILI9341_D7_CLK|ILI9341_D8_CLK|ILI9341_D9_CLK | ILI9341_D10_CLK|ILI9341_D11_CLK|ILI9341_D12_CLK | ILI9341_D13_CLK|ILI9341_D14_CLK|ILI9341_D15_CLK	, ENABLE );/* 配置FSMC相對應的數據線,FSMC-D0~D15 */	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = ILI9341_D0_PIN;GPIO_Init ( ILI9341_D0_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D1_PIN;GPIO_Init ( ILI9341_D1_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D2_PIN;GPIO_Init ( ILI9341_D2_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D3_PIN;GPIO_Init ( ILI9341_D3_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D4_PIN;GPIO_Init ( ILI9341_D4_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D5_PIN;GPIO_Init ( ILI9341_D5_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D6_PIN;GPIO_Init ( ILI9341_D6_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D7_PIN;GPIO_Init ( ILI9341_D7_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D8_PIN;GPIO_Init ( ILI9341_D8_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D9_PIN;GPIO_Init ( ILI9341_D9_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D10_PIN;GPIO_Init ( ILI9341_D10_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D11_PIN;GPIO_Init ( ILI9341_D11_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D12_PIN;GPIO_Init ( ILI9341_D12_PORT, & GPIO_InitStructure );	GPIO_InitStructure.GPIO_Pin = ILI9341_D13_PIN;GPIO_Init ( ILI9341_D13_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D14_PIN;GPIO_Init ( ILI9341_D14_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_D15_PIN;GPIO_Init ( ILI9341_D15_PORT, & GPIO_InitStructure );/* 配置FSMC相對應的控制線* FSMC_NOE   :LCD-RD* FSMC_NWE   :LCD-WR* FSMC_NE1   :LCD-CS* FSMC_A16  	:LCD-DC*/GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode =  GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin = ILI9341_RD_PIN; GPIO_Init (ILI9341_RD_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_WR_PIN; GPIO_Init (ILI9341_WR_PORT, & GPIO_InitStructure );GPIO_InitStructure.GPIO_Pin = ILI9341_CS_PIN; GPIO_Init ( ILI9341_CS_PORT, & GPIO_InitStructure );  GPIO_InitStructure.GPIO_Pin = ILI9341_DC_PIN; GPIO_Init ( ILI9341_DC_PORT, & GPIO_InitStructure );/* 配置LCD復位RST控制管腳*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = ILI9341_RST_PIN; GPIO_Init ( ILI9341_RST_PORT, & GPIO_InitStructure );/* 配置LCD背光控制管腳BK*/GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  GPIO_InitStructure.GPIO_Pin = ILI9341_BK_PIN; GPIO_Init ( ILI9341_BK_PORT, & GPIO_InitStructure );
}/*** @brief  LCD  FSMC 模式配置* @param  無* @retval 無*/
static void ILI9341_FSMC_Config ( void )
{FSMC_NORSRAMInitTypeDef  FSMC_NORSRAMInitStructure;FSMC_NORSRAMTimingInitTypeDef  readWriteTiming; 	/* 使能FSMC時鐘*/RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_FSMC, ENABLE );//地址建立時間(ADDSET)為1個HCLK 2/72M=28nsreadWriteTiming.FSMC_AddressSetupTime      = 0x01;	 //地址建立時間//數據保持時間(DATAST)+ 1個HCLK = 5/72M=70ns	readWriteTiming.FSMC_DataSetupTime         = 0x04;	 //數據建立時間//選擇控制的模式//模式B,異步NOR FLASH模式,與ILI9341的8080時序匹配readWriteTiming.FSMC_AccessMode            = FSMC_AccessMode_B;	/*以下配置與模式B無關*///地址保持時間(ADDHLD)模式A未用到readWriteTiming.FSMC_AddressHoldTime       = 0x00;	 //地址保持時間//設置總線轉換周期,僅用于復用模式的NOR操作readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;//設置時鐘分頻,僅用于同步類型的存儲器readWriteTiming.FSMC_CLKDivision           = 0x00;//數據保持時間,僅用于同步型的NOR	readWriteTiming.FSMC_DataLatency           = 0x00;	FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait		  =FSMC_AsynchronousWait_Disable;FSMC_NORSRAMInitStructure.FSMC_Bank                  = FSMC_Bank1_NORSRAMx;FSMC_NORSRAMInitStructure.FSMC_DataAddressMux        = FSMC_DataAddressMux_Disable;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 = &readWriteTiming;FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct     = &readWriteTiming;  FSMC_NORSRAMInit ( & FSMC_NORSRAMInitStructure ); /* 使能 FSMC_Bank1_NORSRAM4 */FSMC_NORSRAMCmd ( FSMC_Bank1_NORSRAMx, ENABLE );  }/*** @brief  初始化ILI9341寄存器* @param  無* @retval 無*/
static void ILI9341_REG_Config ( void )
{/*  Power control B (CFh)  */DEBUG_DELAY  ();ILI9341_Write_Cmd ( 0xCF  );ILI9341_Write_Data ( 0x00  );ILI9341_Write_Data ( 0x81  );ILI9341_Write_Data ( 0x30  );/*  Power on sequence control (EDh) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xED );ILI9341_Write_Data ( 0x64 );ILI9341_Write_Data ( 0x03 );ILI9341_Write_Data ( 0x12 );ILI9341_Write_Data ( 0x81 );/*  Driver timing control A (E8h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xE8 );ILI9341_Write_Data ( 0x85 );ILI9341_Write_Data ( 0x10 );ILI9341_Write_Data ( 0x78 );/*  Power control A (CBh) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xCB );ILI9341_Write_Data ( 0x39 );ILI9341_Write_Data ( 0x2C );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x34 );ILI9341_Write_Data ( 0x02 );/* Pump ratio control (F7h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xF7 );ILI9341_Write_Data ( 0x20 );/* Driver timing control B */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xEA );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );/* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xB1 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x1B );/*  Display Function Control (B6h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xB6 );ILI9341_Write_Data ( 0x0A );ILI9341_Write_Data ( 0xA2 );/* Power Control 1 (C0h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xC0 );ILI9341_Write_Data ( 0x35 );/* Power Control 2 (C1h) */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0xC1 );ILI9341_Write_Data ( 0x11 );/* VCOM Control 1 (C5h) */ILI9341_Write_Cmd ( 0xC5 );ILI9341_Write_Data ( 0x45 );ILI9341_Write_Data ( 0x45 );/*  VCOM Control 2 (C7h)  */ILI9341_Write_Cmd ( 0xC7 );ILI9341_Write_Data ( 0xA2 );/* Enable 3G (F2h) */ILI9341_Write_Cmd ( 0xF2 );ILI9341_Write_Data ( 0x00 );/* Gamma Set (26h) */ILI9341_Write_Cmd ( 0x26 );ILI9341_Write_Data ( 0x01 );DEBUG_DELAY ();/* Positive Gamma Correction */ILI9341_Write_Cmd ( 0xE0 ); //Set GammaILI9341_Write_Data ( 0x0F );ILI9341_Write_Data ( 0x26 );ILI9341_Write_Data ( 0x24 );ILI9341_Write_Data ( 0x0B );ILI9341_Write_Data ( 0x0E );ILI9341_Write_Data ( 0x09 );ILI9341_Write_Data ( 0x54 );ILI9341_Write_Data ( 0xA8 );ILI9341_Write_Data ( 0x46 );ILI9341_Write_Data ( 0x0C );ILI9341_Write_Data ( 0x17 );ILI9341_Write_Data ( 0x09 );ILI9341_Write_Data ( 0x0F );ILI9341_Write_Data ( 0x07 );ILI9341_Write_Data ( 0x00 );/* Negative Gamma Correction (E1h) */ILI9341_Write_Cmd ( 0XE1 ); //Set GammaILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x19 );ILI9341_Write_Data ( 0x1B );ILI9341_Write_Data ( 0x04 );ILI9341_Write_Data ( 0x10 );ILI9341_Write_Data ( 0x07 );ILI9341_Write_Data ( 0x2A );ILI9341_Write_Data ( 0x47 );ILI9341_Write_Data ( 0x39 );ILI9341_Write_Data ( 0x03 );ILI9341_Write_Data ( 0x06 );ILI9341_Write_Data ( 0x06 );ILI9341_Write_Data ( 0x30 );ILI9341_Write_Data ( 0x38 );ILI9341_Write_Data ( 0x0F );/* memory access control set */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0x36 ); 	ILI9341_Write_Data ( 0xC8 );    /*豎屏  左上角到 (起點)到右下角 (終點)掃描方式*/DEBUG_DELAY ();/* column address control set */ILI9341_Write_Cmd ( CMD_SetCoordinateX ); ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0xEF );/* page address control set */DEBUG_DELAY ();ILI9341_Write_Cmd ( CMD_SetCoordinateY ); ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x00 );ILI9341_Write_Data ( 0x01 );ILI9341_Write_Data ( 0x3F );/*  Pixel Format Set (3Ah)  */DEBUG_DELAY ();ILI9341_Write_Cmd ( 0x3a ); ILI9341_Write_Data ( 0x55 );/* Sleep Out (11h)  */ILI9341_Write_Cmd ( 0x11 );	ILI9341_Delay ( 0xAFFf<<2 );DEBUG_DELAY ();/* Display ON (29h) */ILI9341_Write_Cmd ( 0x29 ); }/*** @brief  ILI9341初始化函數,如果要用到lcd,一定要調用這個函數* @param  無* @retval 無*/
void ILI9341_Init ( void )
{ILI9341_GPIO_Config ();ILI9341_FSMC_Config ();ILI9341_BackLed_Control ( ENABLE );      //點亮LCD背光燈ILI9341_Rst ();ILI9341_REG_Config ();//設置默認掃描方向,其中 6 模式為大部分液晶例程的默認顯示方向  ILI9341_GramScan(LCD_SCAN_MODE);
}/*** @brief  ILI9341背光LED控制* @param  enumState :決定是否使能背光LED*   該參數為以下值之一:*     @arg ENABLE :使能背光LED*     @arg DISABLE :禁用背光LED* @retval 無*/
void ILI9341_BackLed_Control ( FunctionalState enumState )
{if ( enumState )GPIO_ResetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );	elseGPIO_SetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );}/*** @brief  ILI9341 軟件復位* @param  無* @retval 無*/
void ILI9341_Rst ( void )
{			GPIO_ResetBits ( ILI9341_RST_PORT, ILI9341_RST_PIN );	 //低電平復位ILI9341_Delay ( 0xAFF ); 					   GPIO_SetBits ( ILI9341_RST_PORT, ILI9341_RST_PIN );		 	 ILI9341_Delay ( 0xAFF ); 	}/*** @brief  設置ILI9341的GRAM的掃描方向 * @param  ucOption :選擇GRAM的掃描方向 *     @arg 0-7 :參數可選值為0-7這八個方向**	!!!其中0、3、5、6 模式適合從左至右顯示文字,*				不推薦使用其它模式顯示文字	其它模式顯示文字會有鏡像效果			*		*	其中0、2、4、6 模式的X方向像素為240,Y方向像素為320*	其中1、3、5、7 模式下X方向像素為320,Y方向像素為240**	其中 6 模式為大部分液晶例程的默認顯示方向*	其中 3 模式為攝像頭例程使用的方向*	其中 0 模式為BMP圖片顯示例程使用的方向** @retval 無* @note  坐標圖例:A表示向上,V表示向下,<表示向左,>表示向右X表示X軸,Y表示Y軸------------------------------------------------------------
模式0:				.		模式1:		.	模式2:			.	模式3:					A		.					A		.		A					.		A									|		.					|		.		|					.		|							Y		.					X		.		Y					.		X					0		.					1		.		2					.		3					<--- X0 o		.	<----Y1	o		.		o 2X--->  .		o 3Y--->	
------------------------------------------------------------	
模式4:				.	模式5:			.	模式6:			.	模式7:					<--- X4 o		.	<--- Y5 o		.		o 6X--->  .		o 7Y--->	4		.					5		.		6					.		7	Y		.					X		.		Y					.		X						|		.					|		.		|					.		|							V		.					V		.		V					.		V		
---------------------------------------------------------				LCD屏示例|-----------------||			秉火Logo		||									||									||									||									||									||									||									||									||-----------------|屏幕正面(寬240,高320)*******************************************************/
void ILI9341_GramScan ( uint8_t ucOption )
{	//參數檢查,只可輸入0-7if(ucOption >7 )return;//根據模式更新LCD_SCAN_MODE的值,主要用于觸摸屏選擇計算參數LCD_SCAN_MODE = ucOption;//根據模式更新XY方向的像素寬度if(ucOption%2 == 0)	{//0 2 4 6模式下X方向像素寬度為240,Y方向為320LCD_X_LENGTH = ILI9341_LESS_PIXEL;LCD_Y_LENGTH =	ILI9341_MORE_PIXEL;}else				{//1 3 5 7模式下X方向像素寬度為320,Y方向為240LCD_X_LENGTH = ILI9341_MORE_PIXEL;LCD_Y_LENGTH =	ILI9341_LESS_PIXEL; }//0x36命令參數的高3位可用于設置GRAM掃描方向	ILI9341_Write_Cmd ( 0x36 ); ILI9341_Write_Data ( 0x08 |(ucOption<<5));//根據ucOption的值設置LCD參數,共0-7種模式ILI9341_Write_Cmd ( CMD_SetCoordinateX ); ILI9341_Write_Data ( 0x00 );		/* x 起始坐標高8位 */ILI9341_Write_Data ( 0x00 );		/* x 起始坐標低8位 */ILI9341_Write_Data ( ((LCD_X_LENGTH-1)>>8)&0xFF ); /* x 結束坐標高8位 */	ILI9341_Write_Data ( (LCD_X_LENGTH-1)&0xFF );				/* x 結束坐標低8位 */ILI9341_Write_Cmd ( CMD_SetCoordinateY ); ILI9341_Write_Data ( 0x00 );		/* y 起始坐標高8位 */ILI9341_Write_Data ( 0x00 );		/* y 起始坐標低8位 */ILI9341_Write_Data ( ((LCD_Y_LENGTH-1)>>8)&0xFF );	/* y 結束坐標高8位 */	 ILI9341_Write_Data ( (LCD_Y_LENGTH-1)&0xFF );				/* y 結束坐標低8位 *//* write gram start */ILI9341_Write_Cmd ( CMD_SetPixel );	
}/*** @brief  在ILI9341顯示器上開辟一個窗口* @param  usX :在特定掃描方向下窗口的起點X坐標* @param  usY :在特定掃描方向下窗口的起點Y坐標* @param  usWidth :窗口的寬度* @param  usHeight :窗口的高度* @retval 無*/
void ILI9341_OpenWindow ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
{	ILI9341_Write_Cmd ( CMD_SetCoordinateX ); 				 /* 設置X坐標 */ILI9341_Write_Data ( usX >> 8  );	 /* 先高8位,然后低8位 */ILI9341_Write_Data ( usX & 0xff  );	 /* 設置起始點和結束點*/ILI9341_Write_Data ( ( usX + usWidth - 1 ) >> 8  );ILI9341_Write_Data ( ( usX + usWidth - 1 ) & 0xff  );ILI9341_Write_Cmd ( CMD_SetCoordinateY ); 			     /* 設置Y坐標*/ILI9341_Write_Data ( usY >> 8  );ILI9341_Write_Data ( usY & 0xff  );ILI9341_Write_Data ( ( usY + usHeight - 1 ) >> 8 );ILI9341_Write_Data ( ( usY + usHeight - 1) & 0xff );}/*** @brief  設定ILI9341的光標坐標* @param  usX :在特定掃描方向下光標的X坐標* @param  usY :在特定掃描方向下光標的Y坐標* @retval 無*/
static void ILI9341_SetCursor ( uint16_t usX, uint16_t usY )	
{ILI9341_OpenWindow ( usX, usY, 1, 1 );
}/*** @brief  在ILI9341顯示器上以某一顏色填充像素點* @param  ulAmout_Point :要填充顏色的像素點的總數目* @param  usColor :顏色* @retval 無*/
static __inline void ILI9341_FillColor ( uint32_t ulAmout_Point, uint16_t usColor )
{uint32_t i = 0;/* memory write */ILI9341_Write_Cmd ( CMD_SetPixel );	for ( i = 0; i < ulAmout_Point; i ++ )ILI9341_Write_Data ( usColor );}/*** @brief  對ILI9341顯示器的某一窗口以某種顏色進行清屏* @param  usX :在特定掃描方向下窗口的起點X坐標* @param  usY :在特定掃描方向下窗口的起點Y坐標* @param  usWidth :窗口的寬度* @param  usHeight :窗口的高度* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_Clear ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
{ILI9341_OpenWindow ( usX, usY, usWidth, usHeight );ILI9341_FillColor ( usWidth * usHeight, CurrentBackColor );		}/*** @brief  對ILI9341顯示器的某一點以某種顏色進行填充* @param  usX :在特定掃描方向下該點的X坐標* @param  usY :在特定掃描方向下該點的Y坐標* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_SetPointPixel ( uint16_t usX, uint16_t usY )	
{	if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH )){ILI9341_SetCursor ( usX, usY );ILI9341_FillColor ( 1, CYAN );}}/*** @brief  對ILI9341顯示器的某一點以某種顏色進行填充* @param  usX :在特定掃描方向下該點的X坐標* @param  usY :在特定掃描方向下該點的Y坐標* @param  fill:0和1選擇填充前景色或背景色* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_SetPointPixel_Fill ( uint16_t usX, uint16_t usY ,uint8_t fill)	
{	if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH )&& fill){ILI9341_SetCursor ( usX, usY );ILI9341_FillColor ( 1, CurrentTextColor );}else{ILI9341_SetCursor ( usX, usY );ILI9341_FillColor ( 1, CurrentBackColor );}}/*** @brief  對ILI9341顯示器的某一點以某種顏色進行填充* @param  usX :在特定掃描方向下該點的X坐標* @param  usY :在特定掃描方向下該點的Y坐標* @param  color:選擇某種顏色進行填充* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_SetPointPixel_Color ( uint16_t usX, uint16_t usY ,uint16_t color)	
{	if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH )){ILI9341_SetCursor ( usX, usY );ILI9341_FillColor ( 1, color );}}
/*** @brief  讀取ILI9341 GRAN 的一個像素數據* @param  無* @retval 像素數據*/
static uint16_t ILI9341_Read_PixelData ( void )	
{	uint16_t usR=0, usG=0, usB=0 ;ILI9341_Write_Cmd ( 0x2E );   /* 讀數據 */usR = ILI9341_Read_Data (); 	/*FIRST READ OUT DUMMY DATA*/usR = ILI9341_Read_Data ();  	/*READ OUT RED DATA  */usB = ILI9341_Read_Data ();  	/*READ OUT BLUE DATA*/usG = ILI9341_Read_Data ();  	/*READ OUT GREEN DATA*/	return ( ( ( usR >> 11 ) << 11 ) | ( ( usG >> 10 ) << 5 ) | ( usB >> 11 ) );}/*** @brief  獲取 ILI9341 顯示器上某一個坐標點的像素數據* @param  usX :在特定掃描方向下該點的X坐標* @param  usY :在特定掃描方向下該點的Y坐標* @retval 像素數據*/
uint16_t ILI9341_GetPointPixel ( uint16_t usX, uint16_t usY )
{ uint16_t usPixelData;ILI9341_SetCursor ( usX, usY );usPixelData = ILI9341_Read_PixelData ();return usPixelData;}/*** @brief  在 ILI9341 顯示器上使用 Bresenham 算法畫線段 * @param  usX1 :在特定掃描方向下線段的一個端點X坐標* @param  usY1 :在特定掃描方向下線段的一個端點Y坐標* @param  usX2 :在特定掃描方向下線段的另一個端點X坐標* @param  usY2 :在特定掃描方向下線段的另一個端點Y坐標* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DrawLine ( uint16_t usX1, uint16_t usY1, uint16_t usX2, uint16_t usY2 )
{uint16_t us; uint16_t usX_Current, usY_Current;int32_t lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance; int32_t lIncrease_X, lIncrease_Y; 	lDelta_X = usX2 - usX1; //計算坐標增量 lDelta_Y = usY2 - usY1; usX_Current = usX1; usY_Current = usY1; if ( lDelta_X > 0 ) lIncrease_X = 1; //設置單步方向 else if ( lDelta_X == 0 ) lIncrease_X = 0;//垂直線 else { lIncrease_X = -1;lDelta_X = - lDelta_X;} if ( lDelta_Y > 0 )lIncrease_Y = 1; else if ( lDelta_Y == 0 )lIncrease_Y = 0;//水平線 else {lIncrease_Y = -1;lDelta_Y = - lDelta_Y;} if (  lDelta_X > lDelta_Y )lDistance = lDelta_X; //選取基本增量坐標軸 else lDistance = lDelta_Y; for ( us = 0; us <= lDistance + 1; us ++ )//畫線輸出 {  ILI9341_SetPointPixel ( usX_Current, usY_Current );//畫點 lError_X += lDelta_X ; lError_Y += lDelta_Y ; if ( lError_X > lDistance ) { lError_X -= lDistance; usX_Current += lIncrease_X; }  if ( lError_Y > lDistance ) { lError_Y -= lDistance; usY_Current += lIncrease_Y; } }  }   /*
函數功能:任意角度畫直線 
參    數:usX,usY:坐標usAngle :度數usRadius:半徑usLength  :線段的長度c  :顏色值 0或者1
例如:ILI9341_DrawAngleLine(60,30,45,20,20,1);//角度畫線
*/
void 	ILI9341_DrawAngleLine( uint32_t usX, uint32_t usY, float usAngle, uint32_t usRadius, uint32_t usLength,uint16_t color)
{int i;int x0,y0;double k=usAngle*(3.1415926535/180);	for(i=usRadius;i<usLength;i++){x0=cos(k)*i;y0=sin(k)*i;ILI9341_SetPointPixel_Color(usX+x0,usY+y0,color);}
}/*
函數功能:任意角度畫直線 
參    數:usX,usY:坐標usRadius :度數usLength :線段的長度c  :顏色值 0或者1
例如:OLED_DrawAngleLine(60,30,45,20,20,1);//角度畫線
*/
void 	ILI9341_DrawAngleLine2( uint32_t usX, uint32_t usY,float usAngle,uint32_t usRadius,uint32_t usLength,uint8_t fill)
{uint32_t i;int x0,y0;double k=usAngle*(3.1415926535L/180);for(i=usRadius;i<usLength;i++){x0=cos(k)*i;y0=sin(k)*i;ILI9341_SetPointPixel_Fill(usX+x0,usY+y0,fill);}
}/*** @brief  在 ILI9341 顯示器上畫一個矩形* @param  usX_Start :在特定掃描方向下矩形的起始點X坐標* @param  usY_Start :在特定掃描方向下矩形的起始點Y坐標* @param  usWidth:矩形的寬度(單位:像素)* @param  usHeight:矩形的高度(單位:像素)* @param  ucFilled :選擇是否填充該矩形*   該參數為以下值之一:*     @arg 0 :空心矩形*     @arg 1 :實心矩形 * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DrawRectangle ( uint16_t usX_Start, uint16_t usY_Start, uint16_t usWidth, uint16_t usHeight, uint8_t ucFilled )
{if ( ucFilled ){ILI9341_OpenWindow ( usX_Start, usY_Start, usWidth, usHeight );ILI9341_FillColor ( usWidth * usHeight ,CurrentTextColor);	}else{ILI9341_DrawLine ( usX_Start, usY_Start, usX_Start + usWidth - 1, usY_Start );ILI9341_DrawLine ( usX_Start, usY_Start + usHeight - 1, usX_Start + usWidth - 1, usY_Start + usHeight - 1 );ILI9341_DrawLine ( usX_Start, usY_Start, usX_Start, usY_Start + usHeight - 1 );ILI9341_DrawLine ( usX_Start + usWidth - 1, usY_Start, usX_Start + usWidth - 1, usY_Start + usHeight - 1 );		}}/*** @brief  在 ILI9341 顯示器上使用 Bresenham 算法畫圓* @param  usX_Center :在特定掃描方向下圓心的X坐標* @param  usY_Center :在特定掃描方向下圓心的Y坐標* @param  usRadius:圓的半徑(單位:像素)* @param  ucFilled :選擇是否填充該圓*   該參數為以下值之一:*     @arg 0 :空心圓*     @arg 1 :實心圓* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DrawCircle ( uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint8_t ucFilled )
{int16_t sCurrentX, sCurrentY;int16_t sError;sCurrentX = 0; sCurrentY = usRadius;	  sError = 3 - ( usRadius << 1 );     //判斷下個點位置的標志while ( sCurrentX <= sCurrentY ){int16_t sCountY;if ( ucFilled ) 			for ( sCountY = sCurrentX; sCountY <= sCurrentY; sCountY ++ ) {                      ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center + sCountY );           //1,研究對象 ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center + sCountY );           //2       ILI9341_SetPointPixel ( usX_Center - sCountY,   usY_Center + sCurrentX );           //3ILI9341_SetPointPixel ( usX_Center - sCountY,   usY_Center - sCurrentX );           //4ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center - sCountY );           //5    ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center - sCountY );           //6ILI9341_SetPointPixel ( usX_Center + sCountY,   usY_Center - sCurrentX );           //7 	ILI9341_SetPointPixel ( usX_Center + sCountY,   usY_Center + sCurrentX );           //0				}else{          ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center + sCurrentY );             //1,研究對象ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center + sCurrentY );             //2      ILI9341_SetPointPixel ( usX_Center - sCurrentY, usY_Center + sCurrentX );             //3ILI9341_SetPointPixel ( usX_Center - sCurrentY, usY_Center - sCurrentX );             //4ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center - sCurrentY );             //5       ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center - sCurrentY );             //6ILI9341_SetPointPixel ( usX_Center + sCurrentY, usY_Center - sCurrentX );             //7 ILI9341_SetPointPixel ( usX_Center + sCurrentY, usY_Center + sCurrentX );             //0}			sCurrentX ++;if ( sError < 0 ) sError += 4 * sCurrentX + 6;	  else{sError += 10 + 4 * ( sCurrentX - sCurrentY );   sCurrentY --;} 	}}/*** @brief  在 ILI9341 顯示器上顯示一個英文字符* @param  usX :在特定掃描方向下字符的起始X坐標* @param  usY :在特定掃描方向下該點的起始Y坐標* @param  cChar :要顯示的英文字符* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispChar_EN ( uint16_t usX, uint16_t usY, const char cChar )
{uint8_t  byteCount, bitCount,fontLength;	uint16_t ucRelativePositon;uint8_t *Pfont;//對ascii碼表偏移(字模表不包含ASCII表的前32個非圖形符號)ucRelativePositon = cChar - ' ';//每個字模的字節數fontLength = (LCD_Currentfonts->Width*LCD_Currentfonts->Height)/8;//字模首地址/*ascii碼表偏移值乘以每個字模的字節數,求出字模的偏移位置*/Pfont = (uint8_t *)&LCD_Currentfonts->table[ucRelativePositon * fontLength];//設置顯示窗口ILI9341_OpenWindow ( usX, usY, LCD_Currentfonts->Width, LCD_Currentfonts->Height);ILI9341_Write_Cmd ( CMD_SetPixel );			//按字節讀取字模數據//由于前面直接設置了顯示窗口,顯示數據會自動換行for ( byteCount = 0; byteCount < fontLength; byteCount++ ){//一位一位處理要顯示的顏色for ( bitCount = 0; bitCount < 8; bitCount++ ){if ( Pfont[byteCount] & (0x80>>bitCount) )ILI9341_Write_Data ( CurrentTextColor );			elseILI9341_Write_Data ( CurrentBackColor );}	}	
}/*** @brief  在 ILI9341 顯示器上顯示一個中文字符* @param  usX :在特定掃描方向下字符的起始X坐標* @param  usY :在特定掃描方向下字符的起始Y坐標* @param  usChar :要顯示的中文字符(國標碼)* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/ 
void ILI9341_DispChar_CH ( uint16_t usX, uint16_t usY, uint16_t usChar )
{uint8_t rowCount, bitCount;uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];	uint16_t usTemp; 	//設置顯示窗口ILI9341_OpenWindow ( usX, usY, WIDTH_CH_CHAR, HEIGHT_CH_CHAR );ILI9341_Write_Cmd ( CMD_SetPixel );//取字模數據  GetGBKCode ( ucBuffer, usChar );	for ( rowCount = 0; rowCount < HEIGHT_CH_CHAR; rowCount++ ){/* 取出兩個字節的數據,在lcd上即是一個漢字的一行 */usTemp = ucBuffer [ rowCount * 2 ];usTemp = ( usTemp << 8 );usTemp |= ucBuffer [ rowCount * 2 + 1 ];for ( bitCount = 0; bitCount < WIDTH_CH_CHAR; bitCount ++ ){			if ( usTemp & ( 0x8000 >> bitCount ) )  //高位在前 ILI9341_Write_Data ( CurrentTextColor );				elseILI9341_Write_Data ( CurrentBackColor );			}		}}/*** @brief  在 ILI9341 顯示器上顯示英文字符串* @param  line :在特定掃描方向下字符串的起始Y坐標*   本參數可使用宏LINE(0)、LINE(1)等方式指定文字坐標,*   宏LINE(x)會根據當前選擇的字體來計算Y坐標值。*		顯示中文且使用LINE宏時,需要把英文字體設置成Font8x16* @param  pStr :要顯示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispStringLine_EN (  uint16_t line,  char * pStr )
{uint16_t usX = 0;while ( * pStr != '\0' ){if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;line += LCD_Currentfonts->Height;}if ( ( line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;line = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN ( usX, line, * pStr);pStr ++;usX += LCD_Currentfonts->Width;}}/*** @brief  在 ILI9341 顯示器上顯示英文字符串* @param  usX :在特定掃描方向下字符的起始X坐標* @param  usY :在特定掃描方向下字符的起始Y坐標* @param  pStr :要顯示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispString_EN ( 	uint16_t usX ,uint16_t usY,  char * pStr )
{while ( * pStr != '\0' ){if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY += LCD_Currentfonts->Height;}if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN ( usX, usY, * pStr);pStr ++;usX += LCD_Currentfonts->Width;}}/*** @brief  在 ILI9341 顯示器上顯示英文字符串(沿Y軸方向)* @param  usX :在特定掃描方向下字符的起始X坐標* @param  usY :在特定掃描方向下字符的起始Y坐標* @param  pStr :要顯示的英文字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispString_EN_YDir (	 uint16_t usX,uint16_t usY ,  char * pStr )
{	while ( * pStr != '\0' ){if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) >LCD_Y_LENGTH  ){usY = ILI9341_DispWindow_Y_Star;usX += LCD_Currentfonts->Width;}if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) >  LCD_X_LENGTH){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}ILI9341_DispChar_EN ( usX, usY, * pStr);pStr ++;usY += LCD_Currentfonts->Height;		}	
}/*** @brief  在 ILI9341 顯示器上顯示中英文字符串* @param  usX :在特定掃描方向下字符的起始X坐標* @param  usY :在特定掃描方向下字符的起始Y坐標* @param  pStr :要顯示的字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispString_EN_CH ( 	uint16_t usX , uint16_t usY, char * pStr )
{uint16_t usCh;while( * pStr != '\0' ){if ( * pStr <= 126 )	           	//英文字符{if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY += LCD_Currentfonts->Height;}if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}			ILI9341_DispChar_EN ( usX, usY, * pStr );usX +=  LCD_Currentfonts->Width;pStr ++;}else	                            //漢字字符{if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY += HEIGHT_CH_CHAR;}if ( ( usY - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;usY = ILI9341_DispWindow_Y_Star;}	usCh = * ( uint16_t * ) pStr;	usCh = ( usCh << 8 ) + ( usCh >> 8 );		ILI9341_DispChar_CH ( usX, usY, usCh );usX += WIDTH_CH_CHAR;pStr += 2;           //一個漢字兩個字節 }}	
} /*** @brief  在 ILI9341 顯示器上顯示中英文字符串* @param  line :在特定掃描方向下字符串的起始Y坐標*   本參數可使用宏LINE(0)、LINE(1)等方式指定文字坐標,*   宏LINE(x)會根據當前選擇的字體來計算Y坐標值。*		顯示中文且使用LINE宏時,需要把英文字體設置成Font8x16* @param  pStr :要顯示的字符串的首地址* @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函數設置顏色* @retval 無*/
void ILI9341_DispStringLine_EN_CH (  uint16_t line, char * pStr )
{uint16_t usCh;uint16_t usX = 0;while( * pStr != '\0' ){if ( * pStr <= 126 )	           	//英文字符{if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;line += LCD_Currentfonts->Height;}if ( ( line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;line = ILI9341_DispWindow_Y_Star;}			ILI9341_DispChar_EN ( usX, line, * pStr );usX +=  LCD_Currentfonts->Width;pStr ++;}else	                            //漢字字符{if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH ){usX = ILI9341_DispWindow_X_Star;line += HEIGHT_CH_CHAR;}if ( ( line - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH ){usX = ILI9341_DispWindow_X_Star;line = ILI9341_DispWindow_Y_Star;}	usCh = * ( uint16_t * ) pStr;	usCh = ( usCh << 8 ) + ( usCh >> 8 );		ILI9341_DispChar_CH ( usX, line, usCh );usX += WIDTH_CH_CHAR;pStr += 2;           //一個漢字兩個字節 }}	
} /*** @brief  設置英文字體類型* @param  fonts: 指定要選擇的字體*		參數為以下值之一* 	@arg:Font24x32;* 	@arg:Font16x24;* 	@arg:Font8x16;* @retval None*/
void LCD_SetFont(sFONT *fonts)
{LCD_Currentfonts = fonts;
}/*** @brief  獲取當前字體類型* @param  None.* @retval 返回當前字體類型*/
sFONT *LCD_GetFont(void)
{return LCD_Currentfonts;
}/*** @brief  設置LCD的前景(字體)及背景顏色,RGB565* @param  TextColor: 指定前景(字體)顏色* @param  BackColor: 指定背景顏色* @retval None*/
void LCD_SetColors(uint16_t TextColor, uint16_t BackColor) 
{CurrentTextColor = TextColor; CurrentBackColor = BackColor;
}/*** @brief  獲取LCD的前景(字體)及背景顏色,RGB565* @param  TextColor: 用來存儲前景(字體)顏色的指針變量* @param  BackColor: 用來存儲背景顏色的指針變量* @retval None*/
void LCD_GetColors(uint16_t *TextColor, uint16_t *BackColor)
{*TextColor = CurrentTextColor;*BackColor = CurrentBackColor;
}/*** @brief  設置LCD的前景(字體)顏色,RGB565* @param  Color: 指定前景(字體)顏色 * @retval None*/
void LCD_SetTextColor(uint16_t Color)
{CurrentTextColor = Color;
}/*** @brief  設置LCD的背景顏色,RGB565* @param  Color: 指定背景顏色 * @retval None*/
void LCD_SetBackColor(uint16_t Color)
{CurrentBackColor = Color;
}/*** @brief  清除某行文字* @param  Line: 指定要刪除的行*   本參數可使用宏LINE(0)、LINE(1)等方式指定要刪除的行,*   宏LINE(x)會根據當前選擇的字體來計算Y坐標值,并刪除當前字體高度的第x行。* @retval None*/
void LCD_ClearLine(uint16_t Line)
{ILI9341_Clear(0,Line,LCD_X_LENGTH,((sFONT *)LCD_GetFont())->Height);	/* 清屏,顯示全黑 */}/***********************縮放字體****************************/
#define ZOOMMAXBUFF 16384
uint8_t zoomBuff[ZOOMMAXBUFF] = {0};	//用于縮放的緩存,最大支持到128*128
uint8_t zoomTempBuff[1024] = {0};/*** @brief  縮放字模,縮放后的字模由1個像素點由8個數據位來表示0x01表示筆跡,0x00表示空白區* @param  in_width :原始字符寬度* @param  in_heig :原始字符高度* @param  out_width :縮放后的字符寬度* @param  out_heig:縮放后的字符高度* @param  in_ptr :字庫輸入指針	注意:1pixel 1bit* @param  out_ptr :縮放后的字符輸出指針 注意: 1pixel 8bit*		out_ptr實際上沒有正常輸出,改成了直接輸出到全局指針zoomBuff中* @param  en_cn :0為英文,1為中文* @retval 無*/
void ILI9341_zoomChar(uint16_t in_width,	//原始字符寬度uint16_t in_heig,		//原始字符高度uint16_t out_width,	//縮放后的字符寬度uint16_t out_heig,	//縮放后的字符高度uint8_t *in_ptr,	//字庫輸入指針	注意:1pixel 1bituint8_t *out_ptr, //縮放后的字符輸出指針 注意: 1pixel 8bituint8_t en_cn)		//0為英文,1為中文	
{uint8_t *pts,*ots;//根據源字模及目標字模大小,設定運算比例因子,左移16是為了把浮點運算轉成定點運算unsigned int xrIntFloat_16=(in_width<<16)/out_width+1; unsigned int yrIntFloat_16=(in_heig<<16)/out_heig+1;unsigned int srcy_16=0;unsigned int y,x;uint8_t *pSrcLine;uint16_t byteCount,bitCount;//檢查參數是否合法if(in_width >= 32) return;												//字庫不允許超過32像素if(in_width * in_heig == 0) return;	if(in_width * in_heig >= 1024 ) return; 					//限制輸入最大 32*32if(out_width * out_heig == 0) return;	if(out_width * out_heig >= ZOOMMAXBUFF ) return; //限制最大縮放 128*128pts = (uint8_t*)&zoomTempBuff;//為方便運算,字庫的數據由1 pixel/1bit 映射到1pixel/8bit//0x01表示筆跡,0x00表示空白區if(en_cn == 0x00)//英文{//英文和中文字庫上下邊界不對,可在此處調整。需要注意tempBuff防止溢出for(byteCount=0;byteCount<in_heig*in_width/8;byteCount++)	{for(bitCount=0;bitCount<8;bitCount++){						//把源字模數據由位映射到字節//in_ptr里bitX為1,則pts里整個字節值為1//in_ptr里bitX為0,則pts里整個字節值為0*pts++ = (in_ptr[byteCount] & (0x80>>bitCount))?1:0; }}				}else //中文{			for(byteCount=0;byteCount<in_heig*in_width/8;byteCount++)	{for(bitCount=0;bitCount<8;bitCount++){						//把源字模數據由位映射到字節//in_ptr里bitX為1,則pts里整個字節值為1//in_ptr里bitX為0,則pts里整個字節值為0*pts++ = (in_ptr[byteCount] & (0x80>>bitCount))?1:0; }}		}//zoom過程pts = (uint8_t*)&zoomTempBuff;	//映射后的源數據指針ots = (uint8_t*)&zoomBuff;	//輸出數據的指針for (y=0;y<out_heig;y++)	/*行遍歷*/{unsigned int srcx_16=0;pSrcLine=pts+in_width*(srcy_16>>16);				for (x=0;x<out_width;x++) /*行內像素遍歷*/{ots[x]=pSrcLine[srcx_16>>16]; //把源字模數據復制到目標指針中srcx_16+=xrIntFloat_16;			//按比例偏移源像素點}srcy_16+=yrIntFloat_16;				  //按比例偏移源像素點ots+=out_width;						}/*!!!縮放后的字模數據直接存儲到全局指針zoomBuff里了*/out_ptr = (uint8_t*)&zoomBuff;	//out_ptr沒有正確傳出,后面調用直接改成了全局變量指針!/*實際中如果使用out_ptr不需要下面這一句!!!只是因為out_ptr沒有使用,會導致warning。強迫癥*/out_ptr++; 
}			/*** @brief  利用縮放后的字模顯示字符* @param  Xpos :字符顯示位置x* @param  Ypos :字符顯示位置y* @param  Font_width :字符寬度* @param  Font_Heig:字符高度* @param  c :要顯示的字模數據* @param  DrawModel :是否反色顯示 * @retval 無*/
void ILI9341_DrawChar_Ex(uint16_t usX, //字符顯示位置xuint16_t usY, //字符顯示位置yuint16_t Font_width, //字符寬度uint16_t Font_Height,  //字符高度 uint8_t *c,						//字模數據uint16_t DrawModel)		//是否反色顯示
{uint32_t index = 0, counter = 0;//設置顯示窗口ILI9341_OpenWindow ( usX, usY, Font_width, Font_Height);ILI9341_Write_Cmd ( CMD_SetPixel );		//按字節讀取字模數據//由于前面直接設置了顯示窗口,顯示數據會自動換行for ( index = 0; index < Font_Height; index++ ){//一位一位處理要顯示的顏色for ( counter = 0; counter < Font_width; counter++ ){//縮放后的字模數據,以一個字節表示一個像素位//整個字節值為1表示該像素為筆跡//整個字節值為0表示該像素為背景if ( *c++ == DrawModel )ILI9341_Write_Data ( CurrentBackColor );			elseILI9341_Write_Data ( CurrentTextColor );}	}	
}/*** @brief  利用縮放后的字模顯示字符串* @param  Xpos :字符顯示位置x* @param  Ypos :字符顯示位置y* @param  Font_width :字符寬度,英文字符在此基礎上/2。注意為偶數* @param  Font_Heig:字符高度,注意為偶數* @param  c :要顯示的字符串* @param  DrawModel :是否反色顯示 * @retval 無*/
void ILI9341_DisplayStringEx(uint16_t x, 		//字符顯示位置xuint16_t y, 				//字符顯示位置yuint16_t Font_width,	//要顯示的字體寬度,英文字符在此基礎上/2。注意為偶數uint16_t Font_Height,	//要顯示的字體高度,注意為偶數uint8_t *ptr,					//顯示的字符內容uint16_t DrawModel)  //是否反色顯示{uint16_t Charwidth = Font_width; //默認為Font_width,英文寬度為中文寬度的一半uint8_t *psr;uint8_t Ascii;	//英文uint16_t usCh;  //中文uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];	while ( *ptr != '\0'){/****處理換行*****/if ( ( x - ILI9341_DispWindow_X_Star + Charwidth ) > LCD_X_LENGTH ){x = ILI9341_DispWindow_X_Star;y += Font_Height;}if ( ( y - ILI9341_DispWindow_Y_Star + Font_Height ) > LCD_Y_LENGTH ){x = ILI9341_DispWindow_X_Star;y = ILI9341_DispWindow_Y_Star;}	if(*ptr > 0x80) //如果是中文{			Charwidth = Font_width;usCh = * ( uint16_t * ) ptr;				usCh = ( usCh << 8 ) + ( usCh >> 8 );GetGBKCode ( ucBuffer, usCh );	//取字模數據//縮放字模數據,源字模為16*16ILI9341_zoomChar(WIDTH_CH_CHAR,HEIGHT_CH_CHAR,Charwidth,Font_Height,(uint8_t *)&ucBuffer,psr,1); //顯示單個字符ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);x+=Charwidth;ptr+=2;}else{Charwidth = Font_width / 2;Ascii = *ptr - 32;//使用16*24字體縮放字模數據ILI9341_zoomChar(16,24,Charwidth,Font_Height,(uint8_t *)&Font16x24.table[Ascii * Font16x24.Height*Font16x24.Width/8],psr,0);//顯示單個字符ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);x+=Charwidth;ptr++;}}
}/*** @brief  利用縮放后的字模顯示字符串(沿Y軸方向)* @param  Xpos :字符顯示位置x* @param  Ypos :字符顯示位置y* @param  Font_width :字符寬度,英文字符在此基礎上/2。注意為偶數* @param  Font_Heig:字符高度,注意為偶數* @param  c :要顯示的字符串* @param  DrawModel :是否反色顯示 * @retval 無*/
void ILI9341_DisplayStringEx_YDir(uint16_t x, 		//字符顯示位置xuint16_t y, 				//字符顯示位置yuint16_t Font_width,	//要顯示的字體寬度,英文字符在此基礎上/2。注意為偶數uint16_t Font_Height,	//要顯示的字體高度,注意為偶數uint8_t *ptr,					//顯示的字符內容uint16_t DrawModel)  //是否反色顯示
{uint16_t Charwidth = Font_width; //默認為Font_width,英文寬度為中文寬度的一半uint8_t *psr;uint8_t Ascii;	//英文uint16_t usCh;  //中文uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];	while ( *ptr != '\0'){			//統一使用漢字的寬高來計算換行if ( ( y - ILI9341_DispWindow_X_Star + Font_width ) > LCD_Y_LENGTH ){y = ILI9341_DispWindow_X_Star;x += Font_width;}if ( ( x - ILI9341_DispWindow_Y_Star + Font_Height ) > LCD_X_LENGTH ){y = ILI9341_DispWindow_X_Star;x = ILI9341_DispWindow_Y_Star;}	if(*ptr > 0x80) //如果是中文{			Charwidth = Font_width;usCh = * ( uint16_t * ) ptr;				usCh = ( usCh << 8 ) + ( usCh >> 8 );GetGBKCode ( ucBuffer, usCh );	//取字模數據//縮放字模數據,源字模為16*16ILI9341_zoomChar(WIDTH_CH_CHAR,HEIGHT_CH_CHAR,Charwidth,Font_Height,(uint8_t *)&ucBuffer,psr,1); //顯示單個字符ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);y+=Font_Height;ptr+=2;}else{Charwidth = Font_width / 2;Ascii = *ptr - 32;//使用16*24字體縮放字模數據ILI9341_zoomChar(16,24,Charwidth,Font_Height,(uint8_t *)&Font16x24.table[Ascii * Font16x24.Height*Font16x24.Width/8],psr,0);//顯示單個字符ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);y+=Font_Height;ptr++;}}
}/*********************end of file*************************/

LD3320.c/usart.c

#include "bsp_usart.h"
#include <string.h>/*** @brief  USART GPIO 配置,工作參數配置* @param  無* @retval 無*/
void USART_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;USART_InitTypeDef USART_InitStructure;// 打開串口GPIO的時鐘DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);// 打開串口外設的時鐘DEBUG_USART_APBxClkCmd(DEBUG_USART_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);// 配置串口的工作參數// 配置波特率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);// 使能串口USART_Cmd(DEBUG_USARTx, ENABLE);	    
}/*** @brief  配置嵌套向量中斷控制器NVIC* @param  無* @retval 無*/
static void NVIC_USART3_Configuration(void)
{NVIC_InitTypeDef NVIC_InitStructure;//使能中斷接收/* 嵌套向量中斷控制器組選擇 */NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);/* 配置USART為中斷源 */NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;/* 搶斷優先級*/NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;/* 子優先級 */NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;/* 使能中斷 */NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;/* 初始化配置NVIC */NVIC_Init(&NVIC_InitStructure);}/*
PB10   :TXD
PB11   : RXD
*///串口IO初始化函數
void USART3_Init(uint32_t baudrate)
{GPIO_InitTypeDef GPIO_InitStructure;         //IO端口的初始化USART_InitTypeDef USART_InitStructure;			 //串口的初始化       RCC_APB2PeriphClockCmd(Ld3320_USART_GPIO_CLK, ENABLE);  //使能IO端口的時鐘RCC_APB1PeriphClockCmd(Ld3320_USART_CLK, ENABLE); //使能串口的時鐘//發送GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;GPIO_InitStructure.GPIO_Pin  = Ld3320_USART_TX_GPIO_PIN;  //發送引腳GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB, &GPIO_InitStructure);//接收GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;GPIO_InitStructure.GPIO_Pin  = Ld3320_USART_RX_GPIO_PIN;  //接收引腳GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;GPIO_Init(GPIOB,&GPIO_InitStructure);USART_InitStructure.USART_BaudRate = 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_Mode = USART_Mode_Rx | USART_Mode_Tx;  //能使接收的發送USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;  //無硬件流控制USART_Init(Ld3320_USARTx,&USART_InitStructure);NVIC_USART3_Configuration();USART_ITConfig(Ld3320_USARTx,USART_IT_RXNE,ENABLE); //使能串口中斷USART_Cmd(Ld3320_USARTx,ENABLE);               //使能串口2}/*
函數名:USART3串口發送函數
功能:  發送數據
入口參數:發送的字符
*/
void USART3_SendString(u8 *str)
{u8 index=0;do{USART_SendData(USART3,str[index]);  //逐一的發送數組中的內容while(USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET);  //判斷是否發送完 發完為高電平index++;}while(str[index] != 0);   //檢查字符串結束標志
}xUSATR_TypeDef  xUSART;         // 聲明為全局變量,方便記錄信息、狀態//   USART-1   //
/
/******************************************************************************* 函  數: vUSART1_Init* 功  能: 初始化USART1的GPIO、通信參數配置、中斷優先級*          (8位數據、無校驗、1個停止位)* 參  數: uint32_t baudrate  通信波特率* 返回值: 無******************************************************************************/
void USART1_Init(uint32_t baudrate)
{GPIO_InitTypeDef  GPIO_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;USART_InitTypeDef USART_InitStructure;// 時鐘使能RCC->APB2ENR |= RCC_APB2ENR_USART1EN;                           // 使能USART1時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;                             // 使能GPIOA時鐘// GPIO_TX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_9;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                // TX引腳工作模式:復用推挽GPIO_Init(GPIOA, &GPIO_InitStructure);// GPIO_RX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;                  // RX引腳工作模式:上拉輸入; 如果使用浮空輸入,引腳空置時可能產生誤輸入; 當電路上為一主多從電路時,可以使用復用開漏模式GPIO_Init(GPIOA, &GPIO_InitStructure);// 中斷配置NVIC_InitStructure .NVIC_IRQChannel = USART1_IRQn;NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ;     // 搶占優先級NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2;             // 子優先級NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE;                // IRQ通道使能NVIC_Init(&NVIC_InitStructure);//USART 初始化設置USART_DeInit(USART1);USART_InitStructure.USART_BaudRate   = baudrate;                // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 字長為8位數據格式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(USART1, &USART_InitStructure);                       // 初始化串口USART_ITConfig(USART1, USART_IT_TXE, DISABLE);USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);                  // 使能接受中斷USART_ITConfig(USART1, USART_IT_IDLE, ENABLE);                  // 使能空閑中斷USART_Cmd(USART1, ENABLE);                                      // 使能串口, 開始工作USART1->SR = ~(0x00F0);                                         // 清理中斷xUSART.USART1InitFlag = 1;                                      // 標記初始化標志xUSART.USART1ReceivedNum = 0;                                   // 接收字節數清零printf("\r\r\r=========== 魔女開發板 STM32F103 外設初始報告 ===========\r");printf("USART1初始化配置      接收中斷、空閑中斷, 發送中斷\r");
}/******************************************************************************* 函  數: USART1_IRQHandler* 功  能: USART1的接收中斷、空閑中斷、發送中斷* 參  數: 無* 返回值: 無*
******************************************************************************/
static uint8_t U1TxBuffer[256] ;    // 用于中斷發送:環形緩沖區,256個字節
static uint8_t U1TxCounter = 0 ;    // 用于中斷發送:標記已發送的字節數(環形)
static uint8_t U1TxCount   = 0 ;    // 用于中斷發送:標記將要發送的字節數(環形)void USART1_IRQHandler(void)
{static uint16_t cnt = 0;                                         // 接收字節數累計:每一幀數據已接收到的字節數static uint8_t  RxTemp[U1_RX_BUF_SIZE];                          // 接收數據緩存數組:每新接收1個字節,先順序存放到這里,當一幀接收完(發生空閑中斷), 再轉存到全局變量:xUSART.USARTxReceivedBuffer[xx]中;// 接收中斷if (USART1->SR & (1 << 5))                                       // 檢查RXNE(讀數據寄存器非空標志位); RXNE中斷清理方法:讀DR時自動清理;{if ((cnt >= U1_RX_BUF_SIZE))//||(xUSART.USART1ReceivedFlag==1// 判斷1: 當前幀已接收到的數據量,已滿(緩存區), 為避免溢出,本包后面接收到的數據直接舍棄.{// 判斷2: 如果之前接收好的數據包還沒處理,就放棄新數據,即,新數據幀不能覆蓋舊數據幀,直至舊數據幀被處理.缺點:數據傳輸過快于處理速度時會掉包;好處:機制清晰,易于調試USART1->DR;                                              // 讀取數據寄存器的數據,但不保存.主要作用:讀DR時自動清理接收中斷標志;return;}RxTemp[cnt++] = USART1->DR ;                                 // 把新收到的字節數據,順序存放到RXTemp數組中;注意:讀取DR時自動清零中斷位;}// 空閑中斷, 用于配合接收中斷,以判斷一幀數據的接收完成if (USART1->SR & (1 << 4))                                       // 檢查IDLE(空閑中斷標志位); IDLE中斷標志清理方法:序列清零,USART1 ->SR;  USART1 ->DR;{xUSART.USART1ReceivedNum  = 0;                               // 把接收到的數據字節數清0memcpy(xUSART.USART1ReceivedBuffer, RxTemp, U1_RX_BUF_SIZE); // 把本幀接收到的數據,存放到全局變量xUSART.USARTxReceivedBuffer中, 等待處理; 注意:復制的是整個數組,包括0值,以方便字符串數據xUSART.USART1ReceivedNum  = cnt;                             // 把接收到的字節數,存放到全局變量xUSART.USARTxReceivedCNT中;cnt = 0;                                                     // 接收字節數累計器,清零; 準備下一次的接收memset(RxTemp, 0, U1_RX_BUF_SIZE);                           // 接收數據緩存數組,清零; 準備下一次的接收USART1 ->SR;USART1 ->DR;                                 // 清零IDLE中斷標志位!! 序列清零,順序不能錯!!}// 發送中斷if ((USART1->SR & 1 << 7) && (USART1->CR1 & 1 << 7))             // 檢查TXE(發送數據寄存器空)、TXEIE(發送緩沖區空中斷使能){USART1->DR = U1TxBuffer[U1TxCounter++];                      // 讀取數據寄存器值;注意:讀取DR時自動清零中斷位;if (U1TxCounter == U1TxCount)USART1->CR1 &= ~(1 << 7);                                // 已發送完成,關閉發送緩沖區空置中斷 TXEIE}
}/******************************************************************************* 函  數: vUSART1_GetBuffer* 功  能: 獲取UART所接收到的數據* 參  數: uint8_t* buffer   數據存放緩存地址*          uint8_t* cnt      接收到的字節數* 返回值: 0_沒有接收到新數據, 非0_所接收到新數據的字節數******************************************************************************/
uint8_t USART1_GetBuffer(uint8_t *buffer, uint8_t *cnt)
{if (xUSART.USART1ReceivedNum > 0)                                           // 判斷是否有新數據{memcpy(buffer, xUSART.USART1ReceivedBuffer, xUSART.USART1ReceivedNum);  // 把新數據復制到指定位置*cnt = xUSART.USART1ReceivedNum;                                        // 把新數據的字節數,存放指定變量xUSART.USART1ReceivedNum = 0;                                           // 接收標記置0return *cnt;                                                            // 返回所接收到新數據的字節數}return 0;                                                                   // 返回0, 表示沒有接收到新數據
}/******************************************************************************* 函  數: vUSART1_SendData* 功  能: UART通過中斷發送數據,適合各種數據類型*         【適合場景】本函數可發送各種數據,而不限于字符串,如int,char*         【不 適 合】注意環形緩沖區容量256字節,如果發送頻率太高,注意波特率* 參  數: uint8_t* buffer   需發送數據的首地址*          uint8_t  cnt      發送的字節數 ,限于中斷發送的緩存區大小,不能大于256個字節* 返回值:******************************************************************************/
void USART1_SendData(uint8_t *buf, uint8_t cnt)
{for (uint8_t i = 0; i < cnt; i++)U1TxBuffer[U1TxCount++] = buf[i];if ((USART1->CR1 & 1 << 7) == 0)       // 檢查發送緩沖區空置中斷(TXEIE)是否已打開USART1->CR1 |= 1 << 7;
}/******************************************************************************* 函  數: vUSART1_SendString* 功  能: UART通過中斷發送輸出字符串,無需輸入數據長度*         【適合場景】字符串,長度<=256字節*         【不 適 合】int,float等數據類型* 參  數: char* stringTemp   需發送數據的緩存首地址* 返回值: 元******************************************************************************/
void USART1_SendString(char *stringTemp)
{u16 num = 0;                                 // 字符串長度char *t = stringTemp ;                       // 用于配合計算發送的數量while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位USART1_SendData((u8 *)stringTemp, num);      // 注意調用函數所需要的真實數據長度; 如果目標需要以0作結尾判斷,需num+1:字符串以0結尾,即多發一個:0
}/******************************************************************************* 函  數: vUSART1_SendStringForDMA* 功  能: UART通過DMA發送數據,省了占用中斷的時間*         【適合場景】字符串,字節數非常多,*         【不 適 合】1:只適合發送字符串,不適合發送可能含0的數值類數據; 2-時間間隔要足夠* 參  數: char strintTemp  要發送的字符串首地址* 返回值: 無******************************************************************************/
void USART1_SendStringForDMA(char *stringTemp)
{static u8 Flag_DmaTxInit = 0;                // 用于標記是否已配置DMA發送u32   num = 0;                               // 發送的數量,注意發送的單位不是必須8位的char *t = stringTemp ;                       // 用于配合計算發送的數量while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位while (DMA1_Channel4->CNDTR > 0);            // 重要:如果DMA還在進行上次發送,就等待; 得進完成中斷清標志,F4不用這么麻煩,發送完后EN自動清零if (Flag_DmaTxInit == 0)                     // 是否已進行過USAART_TX的DMA傳輸配置{Flag_DmaTxInit  = 1;                     // 設置標記,下次調用本函數就不再進行配置了USART1 ->CR3   |= 1 << 7;                // 使能DMA發送RCC->AHBENR    |= 1 << 0;                // 開啟DMA1時鐘  [0]DMA1   [1]DMA2DMA1_Channel4->CCR   = 0;                // 失能, 清0整個寄存器, DMA必須失能才能配置DMA1_Channel4->CNDTR = num;              // 傳輸數據量DMA1_Channel4->CMAR  = (u32)stringTemp;  // 存儲器地址DMA1_Channel4->CPAR  = (u32)&USART1->DR; // 外設地址DMA1_Channel4->CCR |= 1 << 4;            // 數據傳輸方向   0:從外設讀   1:從存儲器讀DMA1_Channel4->CCR |= 0 << 5;            // 循環模式       0:不循環     1:循環DMA1_Channel4->CCR |= 0 << 6;            // 外設地址非增量模式DMA1_Channel4->CCR |= 1 << 7;            // 存儲器增量模式DMA1_Channel4->CCR |= 0 << 8;            // 外設數據寬度為8位DMA1_Channel4->CCR |= 0 << 10;           // 存儲器數據寬度8位DMA1_Channel4->CCR |= 0 << 12;           // 中等優先級DMA1_Channel4->CCR |= 0 << 14;           // 非存儲器到存儲器模式}DMA1_Channel4->CCR  &= ~((u32)(1 << 0));     // 失能,DMA必須失能才能配置DMA1_Channel4->CNDTR = num;                  // 傳輸數據量DMA1_Channel4->CMAR  = (u32)stringTemp;      // 存儲器地址DMA1_Channel4->CCR  |= 1 << 0;               // 開啟DMA傳輸
}//   USART-2   //
/
/******************************************************************************* 函  數: vUSART2_Init* 功  能: 初始化USART的GPIO、通信參數配置、中斷優先級*          (8位數據、無校驗、1個停止位)* 參  數: uint32_t baudrate  通信波特率* 返回值: 無******************************************************************************/
void USART2_Init(uint32_t baudrate)
{GPIO_InitTypeDef  GPIO_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;USART_InitTypeDef USART_InitStructure;// 時鐘使能RCC->APB1ENR |= RCC_APB1ENR_USART2EN;                           // 使能USART2時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;                             // 使能GPIOA時鐘// GPIO_TX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                // TX引腳工作模式:復用推挽GPIO_Init(GPIOA, &GPIO_InitStructure);// GPIO_RX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_3;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;                  // RX引腳工作模式:上拉輸入; 如果使用浮空輸入,引腳空置時可能產生誤輸入; 當電路上為一主多從電路時,可以使用復用開漏模式GPIO_Init(GPIOA, &GPIO_InitStructure);// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 中斷配置NVIC_InitStructure .NVIC_IRQChannel = USART2_IRQn;NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ;     // 搶占優先級NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2;             // 子優先級NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE;                // IRQ通道使能NVIC_Init(&NVIC_InitStructure);//USART 初始化設置//USART_DeInit(USART2);USART_InitStructure.USART_BaudRate   = baudrate;                // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 字長為8位數據格式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(USART2, &USART_InitStructure);                       // 初始化串口USART_ITConfig(USART2, USART_IT_TXE, DISABLE);USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);                  // 使能接受中斷USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);                  // 使能空閑中斷USART_Cmd(USART2, ENABLE);                                      // 使能串口, 開始工作USART2->SR = ~(0x00F0);                                         // 清理中斷xUSART.USART2InitFlag = 1;                                      // 標記初始化標志xUSART.USART2ReceivedNum = 0;                                   // 接收字節數清零printf("\rUSART2初始化配置      接收中斷、空閑中斷, 發送中斷\r");
}/******************************************************************************* 函  數: USART2_IRQHandler* 功  能: USART2的接收中斷、空閑中斷、發送中斷* 參  數: 無* 返回值: 無******************************************************************************/
static uint8_t U2TxBuffer[256] ;    // 用于中斷發送:環形緩沖區,256個字節
static uint8_t U2TxCounter = 0 ;    // 用于中斷發送:標記已發送的字節數(環形)
static uint8_t U2TxCount   = 0 ;    // 用于中斷發送:標記將要發送的字節數(環形)void USART2_IRQHandler(void)
{static uint16_t cnt = 0;                                         // 接收字節數累計:每一幀數據已接收到的字節數static uint8_t  RxTemp[U2_RX_BUF_SIZE];                          // 接收數據緩存數組:每新接收1個字節,先順序存放到這里,當一幀接收完(發生空閑中斷), 再轉存到全局變量:xUSART.USARTxReceivedBuffer[xx]中;// 接收中斷if (USART2->SR & (1 << 5))                                       // 檢查RXNE(讀數據寄存器非空標志位); RXNE中斷清理方法:讀DR時自動清理;{if ((cnt >= U2_RX_BUF_SIZE))//||xUSART.USART2ReceivedFlag==1 // 判斷1: 當前幀已接收到的數據量,已滿(緩存區), 為避免溢出,本包后面接收到的數據直接舍棄.{// 判斷2: 如果之前接收好的數據包還沒處理,就放棄新數據,即,新數據幀不能覆蓋舊數據幀,直至舊數據幀被處理.缺點:數據傳輸過快于處理速度時會掉包;好處:機制清晰,易于調試USART2->DR;                                              // 讀取數據寄存器的數據,但不保存.主要作用:讀DR時自動清理接收中斷標志;return;}RxTemp[cnt++] = USART2->DR ;                                 // 把新收到的字節數據,順序存放到RXTemp數組中;注意:讀取DR時自動清零中斷位;}// 空閑中斷, 用于配合接收中斷,以判斷一幀數據的接收完成if (USART2->SR & (1 << 4))                                       // 檢查IDLE(空閑中斷標志位); IDLE中斷標志清理方法:序列清零,USART1 ->SR;  USART1 ->DR;{xUSART.USART2ReceivedNum  = 0;                               // 把接收到的數據字節數清0memcpy(xUSART.USART2ReceivedBuffer, RxTemp, U2_RX_BUF_SIZE); // 把本幀接收到的數據,存放到全局變量xUSART.USARTxReceivedBuffer中, 等待處理; 注意:復制的是整個數組,包括0值,以方便字符串數據xUSART.USART2ReceivedNum  = cnt;                             // 把接收到的字節數,存放到全局變量xUSART.USARTxReceivedCNT中;cnt = 0;                                                     // 接收字節數累計器,清零; 準備下一次的接收memset(RxTemp, 0, U2_RX_BUF_SIZE);                           // 接收數據緩存數組,清零; 準備下一次的接收USART2 ->SR;USART2 ->DR;                                 // 清零IDLE中斷標志位!! 序列清零,順序不能錯!!}// 發送中斷if ((USART2->SR & 1 << 7) && (USART2->CR1 & 1 << 7))             // 檢查TXE(發送數據寄存器空)、TXEIE(發送緩沖區空中斷使能){USART2->DR = U2TxBuffer[U2TxCounter++];                      // 讀取數據寄存器值;注意:讀取DR時自動清零中斷位;if (U2TxCounter == U2TxCount)USART2->CR1 &= ~(1 << 7);                                // 已發送完成,關閉發送緩沖區空置中斷 TXEIE}
}/******************************************************************************* 函  數: vUSART2_GetBuffer* 功  能: 獲取UART所接收到的數據* 參  數: uint8_t* buffer   數據存放緩存地址*          uint8_t* cnt      接收到的字節數* 返回值: 0_沒有接收到新數據, 非0_所接收到新數據的字節數******************************************************************************/
uint8_t USART2_GetBuffer(uint8_t *buffer, uint8_t *cnt)
{if (xUSART.USART2ReceivedNum > 0)                                          // 判斷是否有新數據{memcpy(buffer, xUSART.USART2ReceivedBuffer, xUSART.USART2ReceivedNum); // 把新數據復制到指定位置*cnt = xUSART.USART2ReceivedNum;                                       // 把新數據的字節數,存放指定變量xUSART.USART2ReceivedNum = 0;                                          // 接收標記置0return *cnt;                                                           // 返回所接收到新數據的字節數}return 0;                                                                  // 返回0, 表示沒有接收到新數據
}/******************************************************************************* 函  數: vUSART2_SendData* 功  能: UART通過中斷發送數據,適合各種數據類型*         【適合場景】本函數可發送各種數據,而不限于字符串,如int,char*         【不 適 合】注意環形緩沖區容量256字節,如果發送頻率太高,注意波特率* 參  數: uint8_t* buffer   需發送數據的首地址*          uint8_t  cnt      發送的字節數 ,限于中斷發送的緩存區大小,不能大于256個字節* 返回值:******************************************************************************/
void USART2_SendData(uint8_t *buf, uint8_t cnt)
{for (uint8_t i = 0; i < cnt; i++)U2TxBuffer[U2TxCount++] = buf[i];if ((USART2->CR1 & 1 << 7) == 0)       // 檢查發送緩沖區空置中斷(TXEIE)是否已打開USART2->CR1 |= 1 << 7;
}/******************************************************************************* 函  數: vUSART2_SendString* 功  能: UART通過中斷發送輸出字符串,無需輸入數據長度*         【適合場景】字符串,長度<=256字節*         【不 適 合】int,float等數據類型* 參  數: char* stringTemp   需發送數據的緩存首地址* 返回值: 元******************************************************************************/
void USART2_SendString(char *stringTemp)
{u16 num = 0;                                 // 字符串長度char *t = stringTemp ;                       // 用于配合計算發送的數量while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位USART2_SendData((u8 *)stringTemp, num);      // 注意調用函數所需要的真實數據長度; 如果目標需要以0作結尾判斷,需num+1:字符串以0結尾,即多發一個:0
}/******************************************************************************* 函  數: USART3_IRQHandler* 功  能: USART的接收中斷、空閑中斷、發送中斷* 參  數: 無* 返回值: 無******************************************************************************/
static uint8_t U3TxBuffer[256] ;    // 用于中斷發送:環形緩沖區,256個字節
static uint8_t U3TxCounter = 0 ;    // 用于中斷發送:標記已發送的字節數(環形)
static uint8_t U3TxCount   = 0 ;    // 用于中斷發送:標記將要發送的字節數(環形)void USART3_SendData(uint8_t *buf, uint8_t cnt)
{for (uint8_t i = 0; i < cnt; i++)U3TxBuffer[U3TxCount++] = buf[i];if ((USART3->CR1 & 1 << 7) == 0)       // 檢查發送緩沖區空置中斷(TXEIE)是否已打開USART3->CR1 |= 1 << 7;
}/******************************************************************************* 函  數: vUSART3_SendString* 功  能: UART通過中斷發送輸出字符串,無需輸入數據長度*         【適合場景】字符串,長度<=256字節*         【不 適 合】int,float等數據類型* 參  數: char* stringTemp   需發送數據的緩存首地址* 返回值: 元******************************************************************************/
//void USART3_SendString(char *stringTemp)
//{
//    u16 num = 0;                                 // 字符串長度
//    char *t = stringTemp ;                       // 用于配合計算發送的數量
//    while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位
//    USART3_SendData((u8 *)stringTemp, num);      // 注意調用函數所需要的真實數據長度; 如果目標需要以0作結尾判斷,需num+1:字符串以0結尾,即多發一個:0
//}#ifdef STM32F10X_HD  // STM32F103R,及以上,才有UART4和UART5//   UART-4   //
/
/******************************************************************************* 函  數: vUART4_Init* 功  能: 初始化USART的GPIO、通信參數配置、中斷優先級*          (8位數據、無校驗、1個停止位)* 參  數: uint32_t baudrate  通信波特率* 返回值: 無******************************************************************************/
void UART4_Init(uint32_t baudrate)
{GPIO_InitTypeDef  GPIO_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;USART_InitTypeDef USART_InitStructure;// 時鐘使能RCC->APB1ENR |= RCC_APB1ENR_UART4EN;                            // 使能UART4時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPCEN;                             // 使能GPIOC時鐘// GPIO_TX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_10;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                // TX引腳工作模式:復用推挽    GPIO_Init(GPIOC, &GPIO_InitStructure);GPIO_Init(GPIOC, &GPIO_InitStructure);// GPIO_RX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;                  // RX引腳工作模式:上拉輸入; 如果使用浮空輸入,引腳空置時可能產生誤輸入; 當電路上為一主多從電路時,可以使用復用開漏模式GPIO_Init(GPIOC, &GPIO_InitStructure);// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 中斷配置NVIC_InitStructure .NVIC_IRQChannel = UART4_IRQn;NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ;     // 搶占優先級NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2;             // 子優先級NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE;                // IRQ通道使能NVIC_Init(&NVIC_InitStructure);//USART 初始化設置USART_DeInit(UART4);USART_InitStructure.USART_BaudRate   = baudrate;                // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 字長為8位數據格式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(UART4, &USART_InitStructure);                        // 初始化串口USART_ITConfig(UART4, USART_IT_TXE, DISABLE);USART_ITConfig(UART4, USART_IT_RXNE, ENABLE);                   // 使能接受中斷USART_ITConfig(UART4, USART_IT_IDLE, ENABLE);                   // 使能空閑中斷USART_Cmd(UART4, ENABLE);                                       // 使能串口, 開始工作UART4->SR = ~(0x00F0);                                          // 清理中斷xUSART.UART4InitFlag = 1;                                       // 標記初始化標志xUSART.UART4ReceivedNum = 0;                                    // 接收字節數清零printf("\rUART4 初始化配置      接收中斷、空閑中斷, 發送中斷\r");
}/******************************************************************************* 函  數: UART4_IRQHandler* 功  能: USART2的接收中斷、空閑中斷、發送中斷* 參  數: 無* 返回值: 無******************************************************************************/
static uint8_t U4TxBuffer[256] ;    // 用于中斷發送:環形緩沖區,256個字節
static uint8_t U4TxCounter = 0 ;    // 用于中斷發送:標記已發送的字節數(環形)
static uint8_t U4TxCount   = 0 ;    // 用于中斷發送:標記將要發送的字節數(環形)void UART4_IRQHandler(void)
{static uint16_t cnt = 0;                                        // 接收字節數累計:每一幀數據已接收到的字節數static uint8_t  RxTemp[U4_RX_BUF_SIZE];                         // 接收數據緩存數組:每新接收1個字節,先順序存放到這里,當一幀接收完(發生空閑中斷), 再轉存到全局變量:xUSART.USARTxReceivedBuffer[xx]中;// 接收中斷if (UART4->SR & (1 << 5))                                       // 檢查RXNE(讀數據寄存器非空標志位); RXNE中斷清理方法:讀DR時自動清理;{if ((cnt >= U4_RX_BUF_SIZE))//||xUSART.UART4ReceivedFlag==1 // 判斷1: 當前幀已接收到的數據量,已滿(緩存區), 為避免溢出,本包后面接收到的數據直接舍棄.{// 判斷2: 如果之前接收好的數據包還沒處理,就放棄新數據,即,新數據幀不能覆蓋舊數據幀,直至舊數據幀被處理.缺點:數據傳輸過快于處理速度時會掉包;好處:機制清晰,易于調試UART4->DR;                                              // 讀取數據寄存器的數據,但不保存.主要作用:讀DR時自動清理接收中斷標志;return;}RxTemp[cnt++] = UART4->DR ;                                 // 把新收到的字節數據,順序存放到RXTemp數組中;注意:讀取DR時自動清零中斷位;}// 空閑中斷, 用于配合接收中斷,以判斷一幀數據的接收完成if (UART4->SR & (1 << 4))                                       // 檢查IDLE(空閑中斷標志位); IDLE中斷標志清理方法:序列清零,USART1 ->SR;  USART1 ->DR;{xUSART.UART4ReceivedNum  = 0;                               // 把接收到的數據字節數清0memcpy(xUSART.UART4ReceivedBuffer, RxTemp, U4_RX_BUF_SIZE); // 把本幀接收到的數據,存放到全局變量xUSART.USARTxReceivedBuffer中, 等待處理; 注意:復制的是整個數組,包括0值,以方便字符串數據xUSART.UART4ReceivedNum  = cnt;                             // 把接收到的字節數,存放到全局變量xUSART.USARTxReceivedCNT中;cnt = 0;                                                    // 接收字節數累計器,清零; 準備下一次的接收memset(RxTemp, 0, U4_RX_BUF_SIZE);                          // 接收數據緩存數組,清零; 準備下一次的接收UART4 ->SR;UART4 ->DR;                                  // 清零IDLE中斷標志位!! 序列清零,順序不能錯!!}// 發送中斷if ((UART4->SR & 1 << 7) && (UART4->CR1 & 1 << 7))              // 檢查TXE(發送數據寄存器空)、TXEIE(發送緩沖區空中斷使能){UART4->DR = U4TxBuffer[U4TxCounter++];                      // 讀取數據寄存器值;注意:讀取DR時自動清零中斷位;if (U4TxCounter == U4TxCount)UART4->CR1 &= ~(1 << 7);                                // 已發送完成,關閉發送緩沖區空置中斷 TXEIE}
}/******************************************************************************* 函  數: vUART4_GetBuffer* 功  能: 獲取UART所接收到的數據* 參  數: uint8_t* buffer   數據存放緩存地址*          uint8_t* cnt      接收到的字節數* 返回值: 0_沒有接收到新數據, 非0_所接收到新數據的字節數******************************************************************************/
uint8_t UART4_GetBuffer(uint8_t *buffer, uint8_t *cnt)
{if (xUSART.UART4ReceivedNum > 0)                                         // 判斷是否有新數據{memcpy(buffer, xUSART.UART4ReceivedBuffer, xUSART.UART4ReceivedNum); // 把新數據復制到指定位置*cnt = xUSART.UART4ReceivedNum;                                      // 把新數據的字節數,存放指定變量xUSART.UART4ReceivedNum = 0;                                         // 接收標記置0return *cnt;                                                         // 返回所接收到新數據的字節數}return 0;                                                                // 返回0, 表示沒有接收到新數據
}/******************************************************************************* 函  數: vUART4_SendData* 功  能: UART通過中斷發送數據,適合各種數據類型*         【適合場景】本函數可發送各種數據,而不限于字符串,如int,char*         【不 適 合】注意環形緩沖區容量256字節,如果發送頻率太高,注意波特率* 參  數: uint8_t* buffer   需發送數據的首地址*          uint8_t  cnt      發送的字節數 ,限于中斷發送的緩存區大小,不能大于256個字節* 返回值:******************************************************************************/
void UART4_SendData(uint8_t *buf, uint8_t cnt)
{for (uint8_t i = 0; i < cnt; i++)U4TxBuffer[U4TxCount++] = buf[i];if ((UART4->CR1 & 1 << 7) == 0)       // 檢查發送緩沖區空置中斷(TXEIE)是否已打開UART4->CR1 |= 1 << 7;
}/******************************************************************************* 函  數: vUART4_SendString* 功  能: UART通過中斷發送輸出字符串,無需輸入數據長度*         【適合場景】字符串,長度<=256字節*         【不 適 合】int,float等數據類型* 參  數: char* stringTemp   需發送數據的緩存首地址* 返回值: 元******************************************************************************/
void UART4_SendString(char *stringTemp)
{u16 num = 0;                                 // 字符串長度char *t = stringTemp ;                       // 用于配合計算發送的數量while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位UART4_SendData((u8 *)stringTemp, num);       // 調用函數完成發送,num+1:字符串以0結尾,需多發一個:0
}//   UART-4   //
/
/******************************************************************************* 函  數: vUART5_Init* 功  能: 初始化USART的GPIO、通信參數配置、中斷優先級*          (8位數據、無校驗、1個停止位)* 參  數: uint32_t baudrate  通信波特率* 返回值: 無******************************************************************************/
void UART5_Init(uint32_t baudrate)
{GPIO_InitTypeDef  GPIO_InitStructure;NVIC_InitTypeDef  NVIC_InitStructure;USART_InitTypeDef USART_InitStructure;// 時鐘使能RCC->APB1ENR |= RCC_APB1ENR_UART5EN;                            // 使能UART5時鐘RCC->APB2ENR |= RCC_APB2ENR_IOPDEN | RCC_APB2ENR_IOPCEN;        // 使能GPIO時鐘// GPIO_TX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_12;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF_PP;                // TX引腳工作模式:復用推挽GPIO_Init(GPIOC, &GPIO_InitStructure);// GPIO_RX引腳配置GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_2;GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_IPU;                  // RX引腳工作模式:上拉輸入; 如果使用浮空輸入,引腳空置時可能產生誤輸入; 當電路上為一主多從電路時,可以使用復用開漏模式GPIO_Init(GPIOD, &GPIO_InitStructure);// NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);// 中斷配置NVIC_InitStructure .NVIC_IRQChannel = UART5_IRQn;NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ;     // 搶占優先級NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2;             // 子優先級NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE;                // IRQ通道使能NVIC_Init(&NVIC_InitStructure);//USART 初始化設置USART_DeInit(UART5);USART_InitStructure.USART_BaudRate   = baudrate;                // 串口波特率USART_InitStructure.USART_WordLength = USART_WordLength_8b;     // 字長為8位數據格式USART_InitStructure.USART_StopBits   = USART_StopBits_1;        // 一個停止位USART_InitStructure.USART_Parity     = USART_Parity_No;         // 無奇偶校驗位USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能收、發模式USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;USART_Init(UART5, &USART_InitStructure);                        // 初始化串口USART_ITConfig(UART5, USART_IT_TXE, DISABLE);USART_ITConfig(UART5, USART_IT_RXNE, ENABLE);                   // 使能接受中斷USART_ITConfig(UART5, USART_IT_IDLE, ENABLE);                   // 使能空閑中斷USART_Cmd(UART5, ENABLE);                                       // 使能串口, 開始工作UART5->SR = ~(0x00F0);                                          // 清理中斷xUSART.UART5InitFlag = 1;                                       // 標記初始化標志xUSART.UART5ReceivedNum = 0;                                    // 接收字節數清零printf("\rUART5 初始化配置      接收中斷、空閑中斷, 發送中斷\r");
}/******************************************************************************* 函  數: UART5_IRQHandler* 功  能: USART2的接收中斷、空閑中斷、發送中斷* 參  數: 無* 返回值: 無******************************************************************************/
static uint8_t U5TxBuffer[256] ;    // 用于中斷發送:環形緩沖區,256個字節
static uint8_t U5TxCounter = 0 ;    // 用于中斷發送:標記已發送的字節數(環形)
static uint8_t U5TxCount   = 0 ;    // 用于中斷發送:標記將要發送的字節數(環形)void UART5_IRQHandler(void)
{static uint16_t cnt = 0;                                        // 接收字節數累計:每一幀數據已接收到的字節數static uint8_t  RxTemp[U5_RX_BUF_SIZE];                         // 接收數據緩存數組:每新接收1個字節,先順序存放到這里,當一幀接收完(發生空閑中斷), 再轉存到全局變量:xUSART.USARTxReceivedBuffer[xx]中;// 接收中斷if (UART5->SR & (1 << 5))                                       // 檢查RXNE(讀數據寄存器非空標志位); RXNE中斷清理方法:讀DR時自動清理;{if ((cnt >= U5_RX_BUF_SIZE))//||xUSART.UART5ReceivedFlag==1 // 判斷1: 當前幀已接收到的數據量,已滿(緩存區), 為避免溢出,本包后面接收到的數據直接舍棄.{// 判斷2: 如果之前接收好的數據包還沒處理,就放棄新數據,即,新數據幀不能覆蓋舊數據幀,直至舊數據幀被處理.缺點:數據傳輸過快于處理速度時會掉包;好處:機制清晰,易于調試UART5->DR;                                              // 讀取數據寄存器的數據,但不保存.主要作用:讀DR時自動清理接收中斷標志;return;}RxTemp[cnt++] = UART5->DR ;                                 // 把新收到的字節數據,順序存放到RXTemp數組中;注意:讀取DR時自動清零中斷位;}// 空閑中斷, 用于配合接收中斷,以判斷一幀數據的接收完成if (UART5->SR & (1 << 4))                                       // 檢查IDLE(空閑中斷標志位); IDLE中斷標志清理方法:序列清零,USART1 ->SR;  USART1 ->DR;{xUSART.UART5ReceivedNum  = 0;                               // 把接收到的數據字節數清0memcpy(xUSART.UART5ReceivedBuffer, RxTemp, U5_RX_BUF_SIZE); // 把本幀接收到的數據,存放到全局變量xUSART.USARTxReceivedBuffer中, 等待處理; 注意:復制的是整個數組,包括0值,以方便字符串數據xUSART.UART5ReceivedNum  = cnt;                             // 把接收到的字節數,存放到全局變量xUSART.USARTxReceivedCNT中;cnt = 0;                                                    // 接收字節數累計器,清零; 準備下一次的接收memset(RxTemp, 0, U5_RX_BUF_SIZE);                          // 接收數據緩存數組,清零; 準備下一次的接收UART5 ->SR;UART5 ->DR;                                  // 清零IDLE中斷標志位!! 序列清零,順序不能錯!!}// 發送中斷if ((UART5->SR & 1 << 7) && (UART5->CR1 & 1 << 7))              // 檢查TXE(發送數據寄存器空)、TXEIE(發送緩沖區空中斷使能){UART5->DR = U5TxBuffer[U5TxCounter++];                      // 讀取數據寄存器值;注意:讀取DR時自動清零中斷位;if (U5TxCounter == U5TxCount)UART5->CR1 &= ~(1 << 7);                                // 已發送完成,關閉發送緩沖區空置中斷 TXEIE}
}/******************************************************************************* 函  數: vUART5_GetBuffer* 功  能: 獲取UART所接收到的數據* 參  數: uint8_t* buffer   數據存放緩存地址*          uint8_t* cnt      接收到的字節數* 返回值: 0_沒有接收到新數據, 非0_所接收到新數據的字節數******************************************************************************/
uint8_t UART5_GetBuffer(uint8_t *buffer, uint8_t *cnt)
{if (xUSART.UART5ReceivedNum > 0)                                         // 判斷是否有新數據{memcpy(buffer, xUSART.UART5ReceivedBuffer, xUSART.UART5ReceivedNum); // 把新數據復制到指定位置*cnt = xUSART.UART5ReceivedNum;                                      // 把新數據的字節數,存放指定變量xUSART.UART5ReceivedNum = 0;                                         // 接收標記置0return *cnt;                                                         // 返回所接收到新數據的字節數}return 0;                                                                // 返回0, 表示沒有接收到新數據
}/******************************************************************************* 函  數: vUART5_SendData* 功  能: UART通過中斷發送數據,適合各種數據類型*         【適合場景】本函數可發送各種數據,而不限于字符串,如int,char*         【不 適 合】注意環形緩沖區容量256字節,如果發送頻率太高,注意波特率* 參  數: uint8_t* buffer   需發送數據的首地址*          uint8_t  cnt      發送的字節數 ,限于中斷發送的緩存區大小,不能大于256個字節* 返回值:******************************************************************************/
void UART5_SendData(uint8_t *buf, uint8_t cnt)
{for (uint8_t i = 0; i < cnt; i++)U5TxBuffer[U5TxCount++] = buf[i];if ((UART5->CR1 & 1 << 7) == 0)       // 檢查發送緩沖區空置中斷(TXEIE)是否已打開UART5->CR1 |= 1 << 7;
}/******************************************************************************* 函  數: vUART5_SendString* 功  能: UART通過中斷發送輸出字符串,無需輸入數據長度*         【適合場景】字符串,長度<=256字節*         【不 適 合】int,float等數據類型* 參  數: char* stringTemp   需發送數據的緩存首地址* 返回值: 元******************************************************************************/
void UART5_SendString(char *stringTemp)
{u16 num = 0;                                 // 字符串長度char *t = stringTemp ;                       // 用于配合計算發送的數量while (*t++ != 0)  num++;                    // 計算要發送的數目,這步比較耗時,測試發現每多6個字節,增加1us,單位:8位UART5_SendData((u8 *)stringTemp, num);       // 注意調用函數所需要的真實數據長度; 如果目標需要以0作結尾判斷,需num+1:字符串以0結尾,即多發一個:0
}#endif//  printf   //
/******************************************************************************* 功  能: printf函數支持代碼*         【特別注意】加入以下代碼, 使用printf函數時, 不再需要選擇use MicroLIB* 參  數:* 返回值:* 備  注: 最后修改_2020年07月15日******************************************************************************/
//加入以下代碼,支持printf函數,而不需要選擇use MicroLIB
//#pragma import(__use_no_semihosting)
//struct __FILE
//{
//    int handle;
//};                     // 標準庫需要的支持函數
//FILE __stdout;         // FILE 在stdio.h文件
void _sys_exit(int x)
{x = x;             // 定義_sys_exit()以避免使用半主機模式
}//重定向 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);}///*
//函數名:USART3中斷服務函數
//功能:  接收數據
//注意:接收數據長度可調:RXCOUNT
//*/
//void USART3_IRQHandler(void)
//{
//	u8 temp;
//	
//  if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
//  {
//		USART_ClearITPendingBit(USART3,USART_IT_RXNE);
//		temp = USART_ReceiveData(USART3);
//		if(temp == '\n' || RXCOUNT == 20)   //判斷是否接收到一個完整字符
//		{
//			RXCOUNT = 0;
//			RXOVER =1;    //接收數據完成標志位置1
//			USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//失能串口接收中斷標志	
//		}
//		else
//		{
//			RXBUF[RXCOUNT] = temp;   //依次存放到數組中
//			RXCOUNT++;		           //字符長度變化
//		}
//	}
//}

main.c

/********************************************************************************* @file    main.c* @author  fire* @version V1.0* @date    2013-xx-xx* @brief   rtc 測試,顯示時間格式為: xx:xx:xx******************************************************************************* @attention** 實驗平臺:野火 F103-指南者 STM32 開發板 * 論壇    :http://www.firebbs.cn* 淘寶    :https://fire-stm32.taobao.com********************************************************************************/#include "stm32f10x.h"
#include "./usart/bsp_usart.h"
#include "./rtc/bsp_rtc.h"
#include "./lcd/bsp_ili9341_lcd.h"
#include "./key/bsp_key.h"  
#include "./DTH11/DTH11.h"
#include "./Led/bsp_led.h"
#include "./syn6288/syn6288.h"
//變量聲明
u8 RXBUF[20];       //串口存儲數組
u8 RXOVER=0;        //串口接收標志位
u8 RXCOUNT=0;       //串口計數變量  
u8 i;               //清空數組變量//時間更新函數
void 											Update_FrameShow										(void);//表盤框架繪制
void 											DrawFixed_Frame										(void);
void 											DrawExcel												(void);
void 											DrawCongratulate										(void);
void 											DrawTimeFrame											(void);
void 											DrawExternal_Environmentz							(void);
void 											DrawWish													(void);
//語音處理函數
void 											USART_Deal												(void);// N = 2^32/365/24/60/60 = 136 年/*時間結構體,默認時間2024-03-02 03:20:10*/
struct rtc_time systmtime=
{
10,20,3,1,2,2024,4
};extern __IO uint32_t TimeDisplay ;
//溫度參數/*** @brief  主函數* @param  無  * @retval 無*/
int main()
{		//可使用該宏設置是否使用液晶顯示
#ifdef  USE_LCD_DISPLAYILI9341_Init ();         //LCD 初始化LCD_SetFont(&Font8x16);LCD_SetColors(CurrentTextColor,CurrentBackColor);ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH);	/* 清屏,顯示全黑 */DrawFixed_Frame();//繪制固定物#endif//串口部分USART_Config();		LED_Configuration();//LED配置SYN6288_Init(USART2);                             // 初始化; USART2-PA2USART3_Init(9600);											//LD3320串口初始化Key_GPIO_Config();/* 配置RTC秒中斷優先級 */RTC_NVIC_Config();RTC_CheckAndConfig(&systmtime);DHT11_Init();  //初始化溫度傳感器引腳SYN6288_Say("已開燈");//Syn6288測試//Temperuture_Get();while (1){/* 每過1s 更新一次時間*/if (TimeDisplay == 1){/* 當前時間 */Time_Display( RTC_GetCounter(),&systmtime); //Time_Display1( RTC_GetCounter(),Temperature_Get(),&systmtime); //當加入溫度獲取時,溫度獲取TimeDisplay = 0;}//按下按鍵,通過串口修改時間if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON  ){struct rtc_time set_time;/*使用串口接收設置的時間,輸入數字時注意末尾要加回車*/Time_Regulate_Get(&set_time);/*用接收到的時間設置RTC*/Time_Adjust(&set_time);//向備份寄存器寫入標志BKP_WriteBackupRegister(RTC_BKP_DRX, RTC_BKP_DATA);} USART_Deal();}
}/**************************************表盤框架繪制*****************************************//*
函數功能: 繪制所有固定物
*/
void DrawFixed_Frame(void)
{
DrawExcel();
DrawCongratulate();
DrawTimeFrame();
DrawExternal_Environmentz();
DrawWish();
}/*
函數功能: 繪制表格
*/
void DrawExcel(void)
{
ILI9341_DrawRectangle ( 0, 0, 240, 320, 0);
ILI9341_DrawLine(0,136,50,136);
ILI9341_DrawLine(185,136,240,136);
ILI9341_DrawLine(0,180,240,180);
ILI9341_DrawLine(0,200,240,200);
ILI9341_DrawLine(48,200,48,320);
ILI9341_DrawLine(240-48,200,240-48,320);
}
/*
函數功能: 繪制時鐘表盤框架
*/
void DrawTimeFrame(void)
{uint8_t i;ILI9341_DrawCircle(RoundCenter_X,RoundCenter_Y,RoundRadius,0);//畫外圓ILI9341_DrawCircle(RoundCenter_X,RoundCenter_Y,RoundCenter,1); //畫中心圓//畫刻度for(i=0;i<60;i++){if(i%5==0){//繪制圓大間距ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,6*i,RoundRadius-6,RoundRadius,RoundInterval_Color);}else{//繪制圓小間距ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,6*i,RoundRadius-3,RoundRadius,RoundInterval_Color);}}//OLED_WriteGRAM();  //刷新數據到OLED屏幕
}
/*
函數功能: 繪制龍年大吉
*/
void DrawCongratulate(void)
{ILI9341_DisplayStringEx(10,10,32,32,(uint8_t *)"龍",0);ILI9341_DisplayStringEx(240-32-10,10,32,32,(uint8_t *)"年",0);ILI9341_DisplayStringEx(10,3*32,32,32,(uint8_t *)"大",0);ILI9341_DisplayStringEx(240-32-10,3*32,32,32,(uint8_t *)"吉",0);
}/*
函數功能: 繪制外部環境
*/
void DrawExternal_Environmentz(void)
{
ILI9341_DisplayStringEx(20,144,16,16,(uint8_t *)"天氣:多云",0);//也可后續添加天氣檢測設備配置
ILI9341_DisplayStringEx(120,144,16,16,(uint8_t *)"溫度:",0);//其他添加可仿照溫度配置
ILI9341_DisplayStringEx(20,160,16,16,(uint8_t *)"位置:貴陽",0);//也可后續添加定位設備配置
ILI9341_DisplayStringEx(120,160,16,16,(uint8_t *)"濕度:",0);//也可后續添加空氣檢測設備配置}
/*
函數功能: 繪制祝愿
*/
void DrawWish(void)
{
ILI9341_DisplayStringEx(12,210,24,24,(uint8_t *)"宜",0);
ILI9341_DisplayStringEx(204,210,24,24,(uint8_t *)"忌",0);ILI9341_DisplayStringEx_YDir(8,240,16,16,(uint8_t *)"搞錢",0);
ILI9341_DisplayStringEx_YDir(28,240,16,16,(uint8_t *)"畢業設計",0);
ILI9341_DisplayStringEx_YDir(200,240,16,16,(uint8_t *)"晚睡晚起",0);
ILI9341_DisplayStringEx_YDir(220,240,16,16,(uint8_t *)"打游戲",0);ILI9341_DisplayStringEx(52,210,24,24,(uint8_t *)"等待開發",0);
}/**************************************表盤框架繪制結束*****************************************/
/*
函數功能: 更新時間框架顯示,在RTC中斷里調用
*/
void Update_FrameShow(void)
{/*1. 繪制秒針、分針、時針*///畫秒針ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_sec*6-6-90,RoundCenter,RoundSecondHand,0);//清除之前的秒針ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_sec*6-90,RoundCenter,RoundSecondHand,RoundSecondHand_Color);//畫分針ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_min*6-6-90,RoundCenter,RoundMiuiteHand,0);ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_min*6-90,RoundCenter,RoundMiuiteHand,RoundMiuiteHand_Color);//畫時針	ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_hour*30-30-90,RoundCenter,RoundHourHand,0);ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_hour*30-90,RoundCenter,RoundHourHand,RoundHourHand_Color);}/***********************************END OF FILE*********************************///串口處理函數
void USART_Deal(void)
{if(RXOVER){RXOVER = 0;    //清除接收標志位switch(RXBUF[0]-48){case   1:GPIO_ResetBits(GPIOB,GPIO_Pin_0);   //點亮小燈SYN6288_Say("已開燈");break;case   2:GPIO_SetBits(GPIOB,GPIO_Pin_0); //熄滅小燈SYN6288_Say("已關燈");break;	default: break;			}USART3_SendString(RXBUF);    //發送給pc機上面打印顯示			for(i=0;i<20;i++)            //將已接收數據的數組清空:共20個字符長度{RXBUF[i] = 0;          	 //重置數據緩存區}USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//始能串口接收 }
}

液晶顯示指針式時鐘核心代碼在上文已經放出,本文核心代碼如上,本人撰寫代碼也需要時間,如需要全部代碼或者僅需語音部分代碼請私信我,感謝大家理解。

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/716364.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/716364.shtml
英文地址,請注明出處:http://en.pswp.cn/news/716364.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Python爬取天氣數據及可視化分析!(含源碼)

天氣預報我們每天都會關注&#xff0c;我們可以根據未來的天氣增減衣物、安排出行&#xff0c;每天的氣溫、風速風向、相對濕度、空氣質量等成為關注的焦點。本次使用python中requests和BeautifulSoup庫對中國天氣網當天和未來14天的數據進行爬取&#xff0c;保存為csv文件&…

帆軟下載PDF報錯java.lang.OutOfMemoryError: Java heap space

需求:前端選擇多條數據&#xff0c;點擊下載按鈕&#xff0c;下載帆軟報表的pdf格式。 &#xff08;目前用的是帆軟PDF下載接口&#xff0c;然后java轉成文件流&#xff0c;前端接到后端接口的文件流&#xff0c;使用axios下載blob,再創建下載鏈接&#xff0c;通過link標簽實現…

ArduinoTFTLCD應用

ArduinoTFTLCD應用 ArduinoTFTLCD應用硬件連接軟件導入庫顯示數字、字符顯示漢字方案1方案2 顯示圖片 總結 ArduinoTFTLCD應用 對于手工喜歡DIY的人來說&#xff0c;Arduino驅動的TFTLCD被很多人使用&#xff0c;此處就總結一下&#xff0c;使用的是VScode的PlatformIO插件驅動…

C# API異步方法和返回類型:提升應用程序性能和靈活性

摘要&#xff1a; 異步編程是現代應用程序開發中不可或缺的一部分。在C#中&#xff0c;異步方法允許我們在等待操作完成時繼續執行其他任務&#xff0c;從而提高應用程序的性能和響應性。本文將介紹C# API異步方法的基本概念、原理和實際應用&#xff0c;并詳細討論異步方法的返…

【機器學習】實驗5,AAAI 會議論文聚類分析

本次實驗以AAAI 2014會議論文數據為基礎&#xff0c;要求實現或調用無監督聚類算法&#xff0c;了解聚類方法。 任務介紹 每年國際上召開的大大小小學術會議不計其數&#xff0c;發表了非常多的論文。在計算機領域的一些大型學術會議上&#xff0c;一次就可以發表涉及各個方向…

RNA-Seq 筆記 [4]

***********************該筆記為初學者筆記&#xff0c;僅供個人參考謹慎搬運代碼****************************** samtools 排序壓縮和 featureCounts 生成基因計數表 SAM文件和BAM文件 1.SAM格式&#xff1a;是一種通用的比對格式&#xff0c;用來存儲reads到參考序列的比…

2024最新算法:鳑鲏魚優化算法(Bitterling Fish Optimization,BFO)求解23個基準函數(提供MATLAB代碼)

一、鳑鲏魚優化算法 鳑鲏魚優化算法&#xff08;Bitterling Fish Optimization&#xff0c;BFO&#xff09;由Lida Zareian 等人于2024年提出。鳑鲏魚在交配中&#xff0c;雄性和雌性物種相互接近&#xff0c;然后將精子和卵子釋放到水中&#xff0c;但這種方法有一個很大的缺…

BUUCTF---[極客大挑戰 2019]Upload1

1.題目描述 2.點開鏈接&#xff0c;需要上傳文件&#xff0c;要求是image&#xff0c;上傳文件后綴為jpg的一句話木馬&#xff0c;發現被檢測到了 3.換另一個木馬試試 GIF89a? <script language"php">eval($_REQUEST[1])</script> 發現可以上傳成功 4…

ctf_show筆記篇(web入門---文件包含)

目錄 文件包含 78-79&#xff1a;最基礎的文件包含&#xff0c;使用偽協議&#xff0c;大小寫繞過或者通配符繞過&#xff0c;再或者使用其他方法 ?編輯80-81&#xff1a;可采用日志文件繞過或者大小寫繞過&#xff08;81只能日志文件繞過&#xff09; ####80-86&#xff1…

『周年紀念』- 降生CSDN三周年的碎碎念

『周年紀念』- 降生CSDN三周年的碎碎念 緣起機緣迷茫厚積薄發 一轉眼又過來一年&#xff0c;自己也已經 大四即將畢業。 感覺這一年像是開了加速鍵&#xff0c;仿佛一瞬就又過去了。統計了一下發現自己在過去的這一年就發布了 2篇文章&#xff0c;2022年發布了 117篇&#x…

PDF 解析問題調研

說點真實的感受 &#xff1a;網上看啥組件都好&#xff0c;實際測&#xff0c;啥組件都不行。效果好的不開源收費&#xff0c;開源的效果不好。測試下來&#xff0c;發現把組件融合起來&#xff0c;還是能不花錢解決問題的&#xff0c;都是麻煩折騰一些。 這里分享了目前網上能…

Python中的反射

在Python中&#xff0c;反射&#xff08;Reflection&#xff09;是一種動態地訪問對象和調用其方法的能力&#xff0c;而不需要在編寫代碼時顯式地知道對象的類或屬性。這種機制使得代碼具有更高的靈活性和可擴展性。Python通過幾種內置函數提供了反射的功能&#xff0c;主要包…

機器學習中類別不平衡問題的解決方案

類別不平衡問題 解決方案簡單方法收集數據調整權重閾值移動 數據層面欠采樣過采樣采樣方法的優劣 算法層面代價敏感集成學習&#xff1a;EasyEnsemble 總結 類別不平衡&#xff08;class-imbalance&#xff09;就是指分類任務中不同類別的訓練樣例數目差別很大的情況 解決方案…

智能分析網關V4電瓶車檢測與煙火算法,全面提升小區消防安全水平

2024年2月23日&#xff0c;南京市某小區因電瓶車停放處起火引發火災事故&#xff0c;造成巨大人員傷亡和損失。根據國家消防救援局的統計&#xff0c;2023年全國共接報電動自行車火災2.1萬起。電瓶車火災事故頻發&#xff0c;這不得不引起我們的重視和思考&#xff0c;尤其是在…

阿里云A10推理qwen

硬件配置 vCPU&#xff1a;32核 內存&#xff1a;188 GiB 寬帶&#xff1a;5 Mbps GPU&#xff1a;NVIDIA A10 24Gcuda 安裝 wget https://developer.download.nvidia.com/compute/cuda/12.1.0/local_installers/cuda-repo-rhel7-12-1-local-12.1.0_530.30.02-1.x86_64.rpm s…

ZDH-大數據采集-支持KETTLE任務

目錄 項目源碼 預覽地址 支持KETTLE介紹 新增KETTLE任務 配置調度KETTLE 重要說明 感謝支持 項目源碼 zdh_web:GitHub - zhaoyachao/zdh_web: 大數據采集,抽取平臺 預覽地址 后臺管理-登陸 用戶名&#xff1a;zyc 密碼&#xff1a;123456 支持KETTLE介紹 當前平臺不…

lv20 QT進程線程編程

知識點&#xff1a;啟動進程 &#xff0c;線程 &#xff0c;線程同步互斥 1 啟動進程 應用場景&#xff1a;通常在qt中打開另一個程序 process模板 QString program “/bin/ls"; QStringList arguments; arguments << "-l" << “-a";QPro…

手撕Java集合之簡易版Deque(LinkedList)

在目前&#xff0c;許多互聯網公司的面試已經要求能手撕集合源碼&#xff0c;集合源碼本身算是源碼里比較簡單的一部分&#xff0c;但是要在面試極短的10來分鐘內快速寫出一個簡易版的源碼還是比較麻煩的&#xff0c;很容易出現各種小問題。所以在平時就要注重這方面的聯系。 以…

倉儲自動化新解:托盤四向穿梭車駛入智能工廠 智能倉儲與產線緊密結合

目前&#xff0c;由于對倉庫存儲量的要求越來越高&#xff0c;揀選、輸送以及出入庫頻率等要求也越來越高&#xff0c;對此&#xff0c;在物流倉儲領域&#xff0c;自動化與智能化控制技術得以快速發展&#xff0c;貨架穿梭車在自動庫領域的應用越來越廣泛。現階段&#xff0c;…

linux之進程理解(1)

目錄 1. 馮諾依曼體系結構 2. 操作系統(OS) 2.1 概念 2.2 設計OS的目的 2.3 定位 2.4 理解管理 3. 系統調用和庫函數概念 4. 補充 1. 馮諾依曼體系結構 我們常見的計算機&#xff0c;如筆記本。我們不常見的計算機&#xff0c;如服務器&#xff0c;大部分都遵守馮諾依曼體…