• 基于stm32F103的座面声控台灯


    1.基本内容:

            设计一个放置在桌面使用的台灯,使用220v交流电供电。具备显示屏能够实时显示日期(年、月、日和星期),时间(小时、分钟、秒)和温度(摄氏度);能够通过语音交互播报实时日期、时间或者温度;能够通过语音交互控制桌面台灯的开启与关闭(或者明暗程度)。设计符合安全规范,符合日常家居使用习惯,操作简便,符合人性化需求。

    2.演示视频

    桌面指针式时钟与语音台灯设计

    3.设计准备

            LD3320语音识别模块、SYN6288语音合成模块、DHT11温湿度传感器模块+SL-Link下载器、STM32F103VET6、杜邦线、ILI9341液晶屏(野火stm32f103可一起购买)。

    4.代码讲解

    syn6288.c

    1. #include "syn6288.h"
    2. #include "stdarg.h"
    3. xSYN6288_TypeDef xSYN6288; // 全局变量结构体
    4. static void delay_ms(uint32_t ms) // 简单的延时函数
    5. {
    6. uint32_t i = 0;
    7. ms = ms * 11993;
    8. for (; i < ms; i++);
    9. }
    10. //Music:选择背景音乐。0:无背景音乐,1~15:选择背景音乐
    11. // SYN6288_SendFrameInfo(0, "[v10][m1][t5]结算金额 为32.8元");
    12. // 参数: 0~15 : 背景音乐,0_无背景音乐,1~15_背景音乐可选
    13. // [V0~16]: 文本朗读音量,0_最小,16_最大
    14. // [m0~16]: 背景音乐音量,0_最小,16_最大
    15. // [t0~5]: 朗读语速,0_最慢,5_最快
    16. // 其它不常用功能请参考数据手册
    17. static void SYN6288_SendFrameInfo(uint8_t Music, uint8_t *HZdata)
    18. {
    19. /****************需要发送的文本**********************************/
    20. unsigned char Frame_Info[50];
    21. unsigned char HZ_Length;
    22. unsigned char ecc = 0; //定义校验字节
    23. unsigned int i = 0;
    24. HZ_Length = strlen((char *)HZdata); //需要发送文本的长度
    25. /*****************帧固定配置信息**************************************/
    26. Frame_Info[0] = 0xFD ; //构造帧头FD
    27. Frame_Info[1] = 0x00 ; //构造数据区长度的高字节
    28. Frame_Info[2] = HZ_Length + 3; //构造数据区长度的低字节
    29. Frame_Info[3] = 0x01 ; //构造命令字:合成播放命令
    30. Frame_Info[4] = 0x01 | Music << 4 ; //构造命令参数:背景音乐设定
    31. /*******************校验码计算***************************************/
    32. for (i = 0; i < 5; i++) //依次发送构造好的5个帧头字节
    33. ecc = ecc ^ (Frame_Info[i]); //对发送的字节进行异或校验
    34. for (i = 0; i < HZ_Length; i++) //依次发送待合成的文本数据
    35. ecc = ecc ^ (HZdata[i]); //对发送的字节进行异或校验
    36. /*******************发送帧信息***************************************/
    37. memcpy(&Frame_Info[5], HZdata, HZ_Length);
    38. Frame_Info[5 + HZ_Length] = ecc;
    39. if (xSYN6288.USARTx == USART1) USART1_SendData(Frame_Info, 5 + HZ_Length + 1);
    40. if (xSYN6288.USARTx == USART2) USART2_SendData(Frame_Info, 5 + HZ_Length + 1);
    41. if (xSYN6288.USARTx == USART3) USART3_SendData(Frame_Info, 5 + HZ_Length + 1);
    42. if (xSYN6288.USARTx == UART4) UART4_SendData(Frame_Info, 5 + HZ_Length + 1);
    43. if (xSYN6288.USARTx == UART5) UART5_SendData(Frame_Info, 5 + HZ_Length + 1);
    44. }
    45. /***********************************************************
    46. * 名 称: SYN6288_Set(uint8_t *Info_data)
    47. * 功 能: 主函数 程序入口
    48. * 入口参数: *Info_data:固定的配置信息变量
    49. * 出口参数:
    50. * 说 明:本函数用于配置,停止合成、暂停合成等设置 ,默认波特率9600bps。
    51. * 调用方法:通过调用已经定义的相关数组进行配置。
    52. **********************************************************/
    53. static void SYN6288_Set(uint8_t *Info_data)
    54. {
    55. uint8_t Com_Len;
    56. Com_Len = strlen((char *)Info_data);
    57. UART5_SendData(Info_data, Com_Len);
    58. }
    59. /******************************************************************************
    60. * 函 数: SYN6288_Say
    61. * 功 能: 输出合成语音
    62. * 参 数: 格式化参数,如printf参数般一样的用法
    63. * 返回值: 无
    64. * 示 例: SYN6288_Say("你好吗?");
    65. *******************************************************************************/
    66. void SYN6288_Say(char *fmt, ...)
    67. {
    68. static char str_1[200]; // 缓存区1,模块每次可转换200字节
    69. static char str_2[200]; // 缓存区2,模块每次可转换200字节
    70. va_list ap;
    71. va_start(ap, fmt);
    72. vsprintf(str_1, fmt, ap);
    73. va_end(ap);
    74. sprintf(str_2, "[d][V12][m15][t5]%s", str_1); // [d]恢复默认状态,[V12]朗读音量0~16,[m15]背景音量0~16,[t5]语速0~5
    75. SYN6288_SendFrameInfo(0, (uint8_t *)str_2); // 无背景音乐
    76. }
    77. /******************************************************************************
    78. * 函 数: SYN6288_Init
    79. * 功 能: 初始化所用串口, 模块默认通信波特率9600
    80. * 参 数: 串口-USARTx
    81. * 返回值: 无
    82. * 示 例: SYN6288_Init(USART1);
    83. *******************************************************************************/
    84. void SYN6288_Init(USART_TypeDef *USARTx)
    85. {
    86. uint16_t baudrate = 9600; // 默认波特率9600bps。
    87. delay_ms(200); // 上电后,稍作延时,等待模块进入稳定状态
    88. if (USARTx == USART1) USART1_Init(baudrate);
    89. if (USARTx == USART2) USART2_Init(baudrate);
    90. if (USARTx == USART3) USART3_Init(baudrate);
    91. #ifdef STM32F10X_HD
    92. if (USARTx == UART4) UART4_Init(baudrate);
    93. if (USARTx == UART5) UART5_Init(baudrate);
    94. #endif
    95. xSYN6288.FlagOkay = 0; // 初始化状态
    96. xSYN6288.USARTx = USARTx; // 记录所用串口端口
    97. }

    DHT11.c

    1. #include "DTH11.h"
    2. #include "bsp_systick.h"
    3. #include "stdio.h"
    4. static void DHT11_GPIO_Config ( void );
    5. static void DHT11_Mode_IPU ( void );
    6. static void DHT11_Mode_Out_PP ( void );
    7. static uint8_t DHT11_ReadByte ( void );
    8. /**
    9. * @brief DHT11 初始化函数
    10. * @param 无
    11. * @retval 无
    12. */
    13. void DHT11_Init ( void )
    14. {
    15. DHT11_GPIO_Config ();
    16. DHT11_Dout_1; // 拉高GPIOB10
    17. }
    18. /*
    19. * 函数名:DHT11_GPIO_Config
    20. * 描述 :配置DHT11用到的I/O口
    21. * 输入 :无
    22. * 输出 :无
    23. */
    24. static void DHT11_GPIO_Config ( void )
    25. {
    26. /*定义一个GPIO_InitTypeDef类型的结构体*/
    27. GPIO_InitTypeDef GPIO_InitStructure;
    28. /*开启DHT11_Dout_GPIO_PORT的外设时钟*/
    29. DHT11_Dout_SCK_APBxClock_FUN ( DHT11_Dout_GPIO_CLK, ENABLE );
    30. /*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
    31. GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
    32. /*设置引脚模式为通用推挽输出*/
    33. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    34. /*设置引脚速率为50MHz */
    35. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    36. /*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
    37. GPIO_Init ( DHT11_Dout_GPIO_PORT, &GPIO_InitStructure );
    38. }
    39. /*
    40. * 函数名:DHT11_Mode_IPU
    41. * 描述 :使DHT11-DATA引脚变为上拉输入模式
    42. * 输入 :无
    43. * 输出 :无
    44. */
    45. static void DHT11_Mode_IPU(void)
    46. {
    47. GPIO_InitTypeDef GPIO_InitStructure;
    48. /*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
    49. GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
    50. /*设置引脚模式为浮空输入模式*/
    51. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ;
    52. /*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
    53. GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
    54. }
    55. /*
    56. * 函数名:DHT11_Mode_Out_PP
    57. * 描述 :使DHT11-DATA引脚变为推挽输出模式
    58. * 输入 :无
    59. * 输出 :无
    60. */
    61. static void DHT11_Mode_Out_PP(void)
    62. {
    63. GPIO_InitTypeDef GPIO_InitStructure;
    64. /*选择要控制的DHT11_Dout_GPIO_PORT引脚*/
    65. GPIO_InitStructure.GPIO_Pin = DHT11_Dout_GPIO_PIN;
    66. /*设置引脚模式为通用推挽输出*/
    67. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    68. /*设置引脚速率为50MHz */
    69. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    70. /*调用库函数,初始化DHT11_Dout_GPIO_PORT*/
    71. GPIO_Init(DHT11_Dout_GPIO_PORT, &GPIO_InitStructure);
    72. }
    73. /*
    74. * 从DHT11读取一个字节,MSB先行
    75. */
    76. static uint8_t DHT11_ReadByte ( void )
    77. {
    78. uint8_t i, temp=0;
    79. for(i=0;i<8;i++)
    80. {
    81. /*每bit以50us低电平标置开始,轮询直到从机发出 的50us 低电平 结束*/
    82. while(DHT11_Dout_IN()==Bit_RESET);
    83. /*DHT11 以26~28us的高电平表示“0”,以70us高电平表示“1”,
    84. *通过检测 x us后的电平即可区别这两个状 ,x 即下面的延时
    85. */
    86. Systick_Delay_us(40); //延时x us 这个延时需要大于数据0持续的时间即可
    87. if(DHT11_Dout_IN()==Bit_SET)/* x us后仍为高电平表示数据“1” */
    88. {
    89. /* 等待数据1的高电平结束 */
    90. while(DHT11_Dout_IN()==Bit_SET);
    91. temp|=(uint8_t)(0x01<<(7-i)); //把第7-i位置1,MSB先行
    92. }
    93. else // x us后为低电平表示数据“0”
    94. {
    95. temp&=(uint8_t)~(0x01<<(7-i)); //把第7-i位置0,MSB先行
    96. }
    97. }
    98. return temp;
    99. }
    100. /*
    101. * 一次完整的数据传输为40bit,高位先出
    102. * 8bit 湿度整数 + 8bit 湿度小数 + 8bit 温度整数 + 8bit 温度小数 + 8bit 校验和
    103. */
    104. uint8_t DHT11_Read_TempAndHumidity(DHT11_Data_TypeDef *DHT11_Data)
    105. {
    106. /*输出模式*/
    107. DHT11_Mode_Out_PP();
    108. /*主机拉低*/
    109. DHT11_Dout_0;
    110. /*延时18ms*/
    111. Systick_Delay_ms(18);
    112. /*总线拉高 主机延时30us*/
    113. DHT11_Dout_1;
    114. Systick_Delay_us(30); //延时30us
    115. /*主机设为输入 判断从机响应信号*/
    116. DHT11_Mode_IPU();
    117. /*判断从机是否有低电平响应信号 如不响应则跳出,响应则向下运行*/
    118. if(DHT11_Dout_IN()==Bit_RESET)
    119. {
    120. /*轮询直到从机发出 的80us 低电平 响应信号结束*/
    121. while(DHT11_Dout_IN()==Bit_RESET);
    122. /*轮询直到从机发出的 80us 高电平 标置信号结束*/
    123. while(DHT11_Dout_IN()==Bit_SET);
    124. /*开始接收数据*/
    125. DHT11_Data->humi_int= DHT11_ReadByte();
    126. DHT11_Data->humi_deci= DHT11_ReadByte();
    127. DHT11_Data->temp_int= DHT11_ReadByte();
    128. DHT11_Data->temp_deci= DHT11_ReadByte();
    129. DHT11_Data->check_sum= DHT11_ReadByte();
    130. /*读取结束,引脚改为输出模式*/
    131. DHT11_Mode_Out_PP();
    132. /*主机拉高*/
    133. DHT11_Dout_1;
    134. /*检查读取的数据是否正确*/
    135. if(DHT11_Data->check_sum == DHT11_Data->humi_int + DHT11_Data->humi_deci + DHT11_Data->temp_int+ DHT11_Data->temp_deci)
    136. return SUCCESS;
    137. else
    138. return ERROR;
    139. }
    140. else
    141. return ERROR;
    142. }

    ili9341.c

    1. /**
    2. ******************************************************************************
    3. * @file bsp_ili9341_lcd.c
    4. * @version V1.0
    5. * @date 2013-xx-xx
    6. * @brief ili9341液晶屏驱动
    7. ******************************************************************************
    8. * @attention
    9. *
    10. * 实验平台:秉火 F103-指南者 STM32 开发板
    11. * 论坛 :http://www.firebbs.cn
    12. * 淘宝 :http://firestm32.taobao.com
    13. *
    14. ******************************************************************************
    15. */
    16. #include "./lcd/bsp_ili9341_lcd.h"
    17. #include "./font/fonts.h"
    18. #include
    19. //根据液晶扫描方向而变化的XY像素宽度
    20. //调用ILI9341_GramScan函数设置方向时会自动更改
    21. uint16_t LCD_X_LENGTH = ILI9341_LESS_PIXEL;
    22. uint16_t LCD_Y_LENGTH = ILI9341_MORE_PIXEL;
    23. //液晶屏扫描模式,本变量主要用于方便选择触摸屏的计算参数
    24. //参数可选值为0-7
    25. //调用ILI9341_GramScan函数设置方向时会自动更改
    26. //LCD刚初始化完成时会使用本默认值
    27. uint8_t LCD_SCAN_MODE = 6;
    28. /**
    29. * @brief 向ILI9341写入命令
    30. * @param usCmd :要写入的命令(表寄存器地址)
    31. * @retval 无
    32. */
    33. __inline void ILI9341_Write_Cmd ( uint16_t usCmd )
    34. {
    35. * ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_CMD ) = usCmd;
    36. }
    37. /**
    38. * @brief 向ILI9341写入数据
    39. * @param usData :要写入的数据
    40. * @retval 无
    41. */
    42. __inline void ILI9341_Write_Data ( uint16_t usData )
    43. {
    44. * ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) = usData;
    45. }
    46. /**
    47. * @brief 从ILI9341读取数据
    48. * @param 无
    49. * @retval 读取到的数据
    50. */
    51. __inline uint16_t ILI9341_Read_Data ( void )
    52. {
    53. return ( * ( __IO uint16_t * ) ( FSMC_Addr_ILI9341_DATA ) );
    54. }
    55. /**
    56. * @brief 用于 ILI9341 简单延时函数
    57. * @param nCount :延时计数值
    58. * @retval 无
    59. */
    60. static void ILI9341_Delay ( __IO uint32_t nCount )
    61. {
    62. for ( ; nCount != 0; nCount -- );
    63. }
    64. /**
    65. * @brief 初始化ILI9341的IO引脚
    66. * @param 无
    67. * @retval 无
    68. */
    69. static void ILI9341_GPIO_Config ( void )
    70. {
    71. GPIO_InitTypeDef GPIO_InitStructure;
    72. /* 使能FSMC对应相应管脚时钟*/
    73. RCC_APB2PeriphClockCmd (
    74. /*控制信号*/
    75. ILI9341_CS_CLK|ILI9341_DC_CLK|ILI9341_WR_CLK|
    76. ILI9341_RD_CLK |ILI9341_BK_CLK|ILI9341_RST_CLK|
    77. /*数据信号*/
    78. ILI9341_D0_CLK|ILI9341_D1_CLK| ILI9341_D2_CLK |
    79. ILI9341_D3_CLK | ILI9341_D4_CLK|ILI9341_D5_CLK|
    80. ILI9341_D6_CLK | ILI9341_D7_CLK|ILI9341_D8_CLK|
    81. ILI9341_D9_CLK | ILI9341_D10_CLK|ILI9341_D11_CLK|
    82. ILI9341_D12_CLK | ILI9341_D13_CLK|ILI9341_D14_CLK|
    83. ILI9341_D15_CLK , ENABLE );
    84. /* 配置FSMC相对应的数据线,FSMC-D0~D15 */
    85. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    86. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    87. GPIO_InitStructure.GPIO_Pin = ILI9341_D0_PIN;
    88. GPIO_Init ( ILI9341_D0_PORT, & GPIO_InitStructure );
    89. GPIO_InitStructure.GPIO_Pin = ILI9341_D1_PIN;
    90. GPIO_Init ( ILI9341_D1_PORT, & GPIO_InitStructure );
    91. GPIO_InitStructure.GPIO_Pin = ILI9341_D2_PIN;
    92. GPIO_Init ( ILI9341_D2_PORT, & GPIO_InitStructure );
    93. GPIO_InitStructure.GPIO_Pin = ILI9341_D3_PIN;
    94. GPIO_Init ( ILI9341_D3_PORT, & GPIO_InitStructure );
    95. GPIO_InitStructure.GPIO_Pin = ILI9341_D4_PIN;
    96. GPIO_Init ( ILI9341_D4_PORT, & GPIO_InitStructure );
    97. GPIO_InitStructure.GPIO_Pin = ILI9341_D5_PIN;
    98. GPIO_Init ( ILI9341_D5_PORT, & GPIO_InitStructure );
    99. GPIO_InitStructure.GPIO_Pin = ILI9341_D6_PIN;
    100. GPIO_Init ( ILI9341_D6_PORT, & GPIO_InitStructure );
    101. GPIO_InitStructure.GPIO_Pin = ILI9341_D7_PIN;
    102. GPIO_Init ( ILI9341_D7_PORT, & GPIO_InitStructure );
    103. GPIO_InitStructure.GPIO_Pin = ILI9341_D8_PIN;
    104. GPIO_Init ( ILI9341_D8_PORT, & GPIO_InitStructure );
    105. GPIO_InitStructure.GPIO_Pin = ILI9341_D9_PIN;
    106. GPIO_Init ( ILI9341_D9_PORT, & GPIO_InitStructure );
    107. GPIO_InitStructure.GPIO_Pin = ILI9341_D10_PIN;
    108. GPIO_Init ( ILI9341_D10_PORT, & GPIO_InitStructure );
    109. GPIO_InitStructure.GPIO_Pin = ILI9341_D11_PIN;
    110. GPIO_Init ( ILI9341_D11_PORT, & GPIO_InitStructure );
    111. GPIO_InitStructure.GPIO_Pin = ILI9341_D12_PIN;
    112. GPIO_Init ( ILI9341_D12_PORT, & GPIO_InitStructure );
    113. GPIO_InitStructure.GPIO_Pin = ILI9341_D13_PIN;
    114. GPIO_Init ( ILI9341_D13_PORT, & GPIO_InitStructure );
    115. GPIO_InitStructure.GPIO_Pin = ILI9341_D14_PIN;
    116. GPIO_Init ( ILI9341_D14_PORT, & GPIO_InitStructure );
    117. GPIO_InitStructure.GPIO_Pin = ILI9341_D15_PIN;
    118. GPIO_Init ( ILI9341_D15_PORT, & GPIO_InitStructure );
    119. /* 配置FSMC相对应的控制线
    120. * FSMC_NOE :LCD-RD
    121. * FSMC_NWE :LCD-WR
    122. * FSMC_NE1 :LCD-CS
    123. * FSMC_A16 :LCD-DC
    124. */
    125. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    126. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    127. GPIO_InitStructure.GPIO_Pin = ILI9341_RD_PIN;
    128. GPIO_Init (ILI9341_RD_PORT, & GPIO_InitStructure );
    129. GPIO_InitStructure.GPIO_Pin = ILI9341_WR_PIN;
    130. GPIO_Init (ILI9341_WR_PORT, & GPIO_InitStructure );
    131. GPIO_InitStructure.GPIO_Pin = ILI9341_CS_PIN;
    132. GPIO_Init ( ILI9341_CS_PORT, & GPIO_InitStructure );
    133. GPIO_InitStructure.GPIO_Pin = ILI9341_DC_PIN;
    134. GPIO_Init ( ILI9341_DC_PORT, & GPIO_InitStructure );
    135. /* 配置LCD复位RST控制管脚*/
    136. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    137. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    138. GPIO_InitStructure.GPIO_Pin = ILI9341_RST_PIN;
    139. GPIO_Init ( ILI9341_RST_PORT, & GPIO_InitStructure );
    140. /* 配置LCD背光控制管脚BK*/
    141. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
    142. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    143. GPIO_InitStructure.GPIO_Pin = ILI9341_BK_PIN;
    144. GPIO_Init ( ILI9341_BK_PORT, & GPIO_InitStructure );
    145. }
    146. /**
    147. * @brief LCD FSMC 模式配置
    148. * @param 无
    149. * @retval 无
    150. */
    151. static void ILI9341_FSMC_Config ( void )
    152. {
    153. FSMC_NORSRAMInitTypeDef FSMC_NORSRAMInitStructure;
    154. FSMC_NORSRAMTimingInitTypeDef readWriteTiming;
    155. /* 使能FSMC时钟*/
    156. RCC_AHBPeriphClockCmd ( RCC_AHBPeriph_FSMC, ENABLE );
    157. //地址建立时间(ADDSET)为1个HCLK 2/72M=28ns
    158. readWriteTiming.FSMC_AddressSetupTime = 0x01; //地址建立时间
    159. //数据保持时间(DATAST)+ 1个HCLK = 5/72M=70ns
    160. readWriteTiming.FSMC_DataSetupTime = 0x04; //数据建立时间
    161. //选择控制的模式
    162. //模式B,异步NOR FLASH模式,与ILI9341的8080时序匹配
    163. readWriteTiming.FSMC_AccessMode = FSMC_AccessMode_B;
    164. /*以下配置与模式B无关*/
    165. //地址保持时间(ADDHLD)模式A未用到
    166. readWriteTiming.FSMC_AddressHoldTime = 0x00; //地址保持时间
    167. //设置总线转换周期,仅用于复用模式的NOR操作
    168. readWriteTiming.FSMC_BusTurnAroundDuration = 0x00;
    169. //设置时钟分频,仅用于同步类型的存储器
    170. readWriteTiming.FSMC_CLKDivision = 0x00;
    171. //数据保持时间,仅用于同步型的NOR
    172. readWriteTiming.FSMC_DataLatency = 0x00;
    173. FSMC_NORSRAMInitStructure.FSMC_AsynchronousWait =FSMC_AsynchronousWait_Disable;
    174. FSMC_NORSRAMInitStructure.FSMC_Bank = FSMC_Bank1_NORSRAMx;
    175. FSMC_NORSRAMInitStructure.FSMC_DataAddressMux = FSMC_DataAddressMux_Disable;
    176. FSMC_NORSRAMInitStructure.FSMC_MemoryType = FSMC_MemoryType_NOR;
    177. FSMC_NORSRAMInitStructure.FSMC_MemoryDataWidth = FSMC_MemoryDataWidth_16b;
    178. FSMC_NORSRAMInitStructure.FSMC_BurstAccessMode = FSMC_BurstAccessMode_Disable;
    179. FSMC_NORSRAMInitStructure.FSMC_WaitSignalPolarity = FSMC_WaitSignalPolarity_Low;
    180. FSMC_NORSRAMInitStructure.FSMC_WrapMode = FSMC_WrapMode_Disable;
    181. FSMC_NORSRAMInitStructure.FSMC_WaitSignalActive = FSMC_WaitSignalActive_BeforeWaitState;
    182. FSMC_NORSRAMInitStructure.FSMC_WriteOperation = FSMC_WriteOperation_Enable;
    183. FSMC_NORSRAMInitStructure.FSMC_WaitSignal = FSMC_WaitSignal_Disable;
    184. FSMC_NORSRAMInitStructure.FSMC_ExtendedMode = FSMC_ExtendedMode_Disable;
    185. FSMC_NORSRAMInitStructure.FSMC_WriteBurst = FSMC_WriteBurst_Disable;
    186. FSMC_NORSRAMInitStructure.FSMC_ReadWriteTimingStruct = &readWriteTiming;
    187. FSMC_NORSRAMInitStructure.FSMC_WriteTimingStruct = &readWriteTiming;
    188. FSMC_NORSRAMInit ( & FSMC_NORSRAMInitStructure );
    189. /* 使能 FSMC_Bank1_NORSRAM4 */
    190. FSMC_NORSRAMCmd ( FSMC_Bank1_NORSRAMx, ENABLE );
    191. }
    192. /**
    193. * @brief 初始化ILI9341寄存器
    194. * @param 无
    195. * @retval 无
    196. */
    197. static void ILI9341_REG_Config ( void )
    198. {
    199. /* Power control B (CFh) */
    200. DEBUG_DELAY ();
    201. ILI9341_Write_Cmd ( 0xCF );
    202. ILI9341_Write_Data ( 0x00 );
    203. ILI9341_Write_Data ( 0x81 );
    204. ILI9341_Write_Data ( 0x30 );
    205. /* Power on sequence control (EDh) */
    206. DEBUG_DELAY ();
    207. ILI9341_Write_Cmd ( 0xED );
    208. ILI9341_Write_Data ( 0x64 );
    209. ILI9341_Write_Data ( 0x03 );
    210. ILI9341_Write_Data ( 0x12 );
    211. ILI9341_Write_Data ( 0x81 );
    212. /* Driver timing control A (E8h) */
    213. DEBUG_DELAY ();
    214. ILI9341_Write_Cmd ( 0xE8 );
    215. ILI9341_Write_Data ( 0x85 );
    216. ILI9341_Write_Data ( 0x10 );
    217. ILI9341_Write_Data ( 0x78 );
    218. /* Power control A (CBh) */
    219. DEBUG_DELAY ();
    220. ILI9341_Write_Cmd ( 0xCB );
    221. ILI9341_Write_Data ( 0x39 );
    222. ILI9341_Write_Data ( 0x2C );
    223. ILI9341_Write_Data ( 0x00 );
    224. ILI9341_Write_Data ( 0x34 );
    225. ILI9341_Write_Data ( 0x02 );
    226. /* Pump ratio control (F7h) */
    227. DEBUG_DELAY ();
    228. ILI9341_Write_Cmd ( 0xF7 );
    229. ILI9341_Write_Data ( 0x20 );
    230. /* Driver timing control B */
    231. DEBUG_DELAY ();
    232. ILI9341_Write_Cmd ( 0xEA );
    233. ILI9341_Write_Data ( 0x00 );
    234. ILI9341_Write_Data ( 0x00 );
    235. /* Frame Rate Control (In Normal Mode/Full Colors) (B1h) */
    236. DEBUG_DELAY ();
    237. ILI9341_Write_Cmd ( 0xB1 );
    238. ILI9341_Write_Data ( 0x00 );
    239. ILI9341_Write_Data ( 0x1B );
    240. /* Display Function Control (B6h) */
    241. DEBUG_DELAY ();
    242. ILI9341_Write_Cmd ( 0xB6 );
    243. ILI9341_Write_Data ( 0x0A );
    244. ILI9341_Write_Data ( 0xA2 );
    245. /* Power Control 1 (C0h) */
    246. DEBUG_DELAY ();
    247. ILI9341_Write_Cmd ( 0xC0 );
    248. ILI9341_Write_Data ( 0x35 );
    249. /* Power Control 2 (C1h) */
    250. DEBUG_DELAY ();
    251. ILI9341_Write_Cmd ( 0xC1 );
    252. ILI9341_Write_Data ( 0x11 );
    253. /* VCOM Control 1 (C5h) */
    254. ILI9341_Write_Cmd ( 0xC5 );
    255. ILI9341_Write_Data ( 0x45 );
    256. ILI9341_Write_Data ( 0x45 );
    257. /* VCOM Control 2 (C7h) */
    258. ILI9341_Write_Cmd ( 0xC7 );
    259. ILI9341_Write_Data ( 0xA2 );
    260. /* Enable 3G (F2h) */
    261. ILI9341_Write_Cmd ( 0xF2 );
    262. ILI9341_Write_Data ( 0x00 );
    263. /* Gamma Set (26h) */
    264. ILI9341_Write_Cmd ( 0x26 );
    265. ILI9341_Write_Data ( 0x01 );
    266. DEBUG_DELAY ();
    267. /* Positive Gamma Correction */
    268. ILI9341_Write_Cmd ( 0xE0 ); //Set Gamma
    269. ILI9341_Write_Data ( 0x0F );
    270. ILI9341_Write_Data ( 0x26 );
    271. ILI9341_Write_Data ( 0x24 );
    272. ILI9341_Write_Data ( 0x0B );
    273. ILI9341_Write_Data ( 0x0E );
    274. ILI9341_Write_Data ( 0x09 );
    275. ILI9341_Write_Data ( 0x54 );
    276. ILI9341_Write_Data ( 0xA8 );
    277. ILI9341_Write_Data ( 0x46 );
    278. ILI9341_Write_Data ( 0x0C );
    279. ILI9341_Write_Data ( 0x17 );
    280. ILI9341_Write_Data ( 0x09 );
    281. ILI9341_Write_Data ( 0x0F );
    282. ILI9341_Write_Data ( 0x07 );
    283. ILI9341_Write_Data ( 0x00 );
    284. /* Negative Gamma Correction (E1h) */
    285. ILI9341_Write_Cmd ( 0XE1 ); //Set Gamma
    286. ILI9341_Write_Data ( 0x00 );
    287. ILI9341_Write_Data ( 0x19 );
    288. ILI9341_Write_Data ( 0x1B );
    289. ILI9341_Write_Data ( 0x04 );
    290. ILI9341_Write_Data ( 0x10 );
    291. ILI9341_Write_Data ( 0x07 );
    292. ILI9341_Write_Data ( 0x2A );
    293. ILI9341_Write_Data ( 0x47 );
    294. ILI9341_Write_Data ( 0x39 );
    295. ILI9341_Write_Data ( 0x03 );
    296. ILI9341_Write_Data ( 0x06 );
    297. ILI9341_Write_Data ( 0x06 );
    298. ILI9341_Write_Data ( 0x30 );
    299. ILI9341_Write_Data ( 0x38 );
    300. ILI9341_Write_Data ( 0x0F );
    301. /* memory access control set */
    302. DEBUG_DELAY ();
    303. ILI9341_Write_Cmd ( 0x36 );
    304. ILI9341_Write_Data ( 0xC8 ); /*竖屏 左上角到 (起点)到右下角 (终点)扫描方式*/
    305. DEBUG_DELAY ();
    306. /* column address control set */
    307. ILI9341_Write_Cmd ( CMD_SetCoordinateX );
    308. ILI9341_Write_Data ( 0x00 );
    309. ILI9341_Write_Data ( 0x00 );
    310. ILI9341_Write_Data ( 0x00 );
    311. ILI9341_Write_Data ( 0xEF );
    312. /* page address control set */
    313. DEBUG_DELAY ();
    314. ILI9341_Write_Cmd ( CMD_SetCoordinateY );
    315. ILI9341_Write_Data ( 0x00 );
    316. ILI9341_Write_Data ( 0x00 );
    317. ILI9341_Write_Data ( 0x01 );
    318. ILI9341_Write_Data ( 0x3F );
    319. /* Pixel Format Set (3Ah) */
    320. DEBUG_DELAY ();
    321. ILI9341_Write_Cmd ( 0x3a );
    322. ILI9341_Write_Data ( 0x55 );
    323. /* Sleep Out (11h) */
    324. ILI9341_Write_Cmd ( 0x11 );
    325. ILI9341_Delay ( 0xAFFf<<2 );
    326. DEBUG_DELAY ();
    327. /* Display ON (29h) */
    328. ILI9341_Write_Cmd ( 0x29 );
    329. }
    330. /**
    331. * @brief ILI9341初始化函数,如果要用到lcd,一定要调用这个函数
    332. * @param 无
    333. * @retval 无
    334. */
    335. void ILI9341_Init ( void )
    336. {
    337. ILI9341_GPIO_Config ();
    338. ILI9341_FSMC_Config ();
    339. ILI9341_BackLed_Control ( ENABLE ); //点亮LCD背光灯
    340. ILI9341_Rst ();
    341. ILI9341_REG_Config ();
    342. //设置默认扫描方向,其中 6 模式为大部分液晶例程的默认显示方向
    343. ILI9341_GramScan(LCD_SCAN_MODE);
    344. }
    345. /**
    346. * @brief ILI9341背光LED控制
    347. * @param enumState :决定是否使能背光LED
    348. * 该参数为以下值之一:
    349. * @arg ENABLE :使能背光LED
    350. * @arg DISABLE :禁用背光LED
    351. * @retval 无
    352. */
    353. void ILI9341_BackLed_Control ( FunctionalState enumState )
    354. {
    355. if ( enumState )
    356. GPIO_ResetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );
    357. else
    358. GPIO_SetBits ( ILI9341_BK_PORT, ILI9341_BK_PIN );
    359. }
    360. /**
    361. * @brief ILI9341 软件复位
    362. * @param 无
    363. * @retval 无
    364. */
    365. void ILI9341_Rst ( void )
    366. {
    367. GPIO_ResetBits ( ILI9341_RST_PORT, ILI9341_RST_PIN ); //低电平复位
    368. ILI9341_Delay ( 0xAFF );
    369. GPIO_SetBits ( ILI9341_RST_PORT, ILI9341_RST_PIN );
    370. ILI9341_Delay ( 0xAFF );
    371. }
    372. /**
    373. * @brief 设置ILI9341的GRAM的扫描方向
    374. * @param ucOption :选择GRAM的扫描方向
    375. * @arg 0-7 :参数可选值为0-7这八个方向
    376. *
    377. * !!!其中0、3、5、6 模式适合从左至右显示文字,
    378. * 不推荐使用其它模式显示文字 其它模式显示文字会有镜像效果
    379. *
    380. * 其中0、2、4、6 模式的X方向像素为240,Y方向像素为320
    381. * 其中1、3、5、7 模式下X方向像素为320,Y方向像素为240
    382. *
    383. * 其中 6 模式为大部分液晶例程的默认显示方向
    384. * 其中 3 模式为摄像头例程使用的方向
    385. * 其中 0 模式为BMP图片显示例程使用的方向
    386. *
    387. * @retval 无
    388. * @note 坐标图例:A表示向上,V表示向下,<表示向左,>表示向右
    389. X表示X轴,Y表示Y轴
    390. ------------------------------------------------------------
    391. 模式0: . 模式1: . 模式2: . 模式3:
    392. A . A . A . A
    393. | . | . | . |
    394. Y . X . Y . X
    395. 0 . 1 . 2 . 3
    396. <--- X0 o . <----Y1 o . o 2X---> . o 3Y--->
    397. ------------------------------------------------------------
    398. 模式4: . 模式5: . 模式6: . 模式7:
    399. <--- X4 o . <--- Y5 o . o 6X---> . o 7Y--->
    400. 4 . 5 . 6 . 7
    401. Y . X . Y . X
    402. | . | . | . |
    403. V . V . V . V
    404. ---------------------------------------------------------
    405. LCD屏示例
    406. |-----------------|
    407. | 秉火Logo |
    408. | |
    409. | |
    410. | |
    411. | |
    412. | |
    413. | |
    414. | |
    415. | |
    416. |-----------------|
    417. 屏幕正面(宽240,高320)
    418. *******************************************************/
    419. void ILI9341_GramScan ( uint8_t ucOption )
    420. {
    421. //参数检查,只可输入0-7
    422. if(ucOption >7 )
    423. return;
    424. //根据模式更新LCD_SCAN_MODE的值,主要用于触摸屏选择计算参数
    425. LCD_SCAN_MODE = ucOption;
    426. //根据模式更新XY方向的像素宽度
    427. if(ucOption%2 == 0)
    428. {
    429. //0 2 4 6模式下X方向像素宽度为240,Y方向为320
    430. LCD_X_LENGTH = ILI9341_LESS_PIXEL;
    431. LCD_Y_LENGTH = ILI9341_MORE_PIXEL;
    432. }
    433. else
    434. {
    435. //1 3 5 7模式下X方向像素宽度为320,Y方向为240
    436. LCD_X_LENGTH = ILI9341_MORE_PIXEL;
    437. LCD_Y_LENGTH = ILI9341_LESS_PIXEL;
    438. }
    439. //0x36命令参数的高3位可用于设置GRAM扫描方向
    440. ILI9341_Write_Cmd ( 0x36 );
    441. ILI9341_Write_Data ( 0x08 |(ucOption<<5));//根据ucOption的值设置LCD参数,共0-7种模式
    442. ILI9341_Write_Cmd ( CMD_SetCoordinateX );
    443. ILI9341_Write_Data ( 0x00 ); /* x 起始坐标高8位 */
    444. ILI9341_Write_Data ( 0x00 ); /* x 起始坐标低8位 */
    445. ILI9341_Write_Data ( ((LCD_X_LENGTH-1)>>8)&0xFF ); /* x 结束坐标高8位 */
    446. ILI9341_Write_Data ( (LCD_X_LENGTH-1)&0xFF ); /* x 结束坐标低8位 */
    447. ILI9341_Write_Cmd ( CMD_SetCoordinateY );
    448. ILI9341_Write_Data ( 0x00 ); /* y 起始坐标高8位 */
    449. ILI9341_Write_Data ( 0x00 ); /* y 起始坐标低8位 */
    450. ILI9341_Write_Data ( ((LCD_Y_LENGTH-1)>>8)&0xFF ); /* y 结束坐标高8位 */
    451. ILI9341_Write_Data ( (LCD_Y_LENGTH-1)&0xFF ); /* y 结束坐标低8位 */
    452. /* write gram start */
    453. ILI9341_Write_Cmd ( CMD_SetPixel );
    454. }
    455. /**
    456. * @brief 在ILI9341显示器上开辟一个窗口
    457. * @param usX :在特定扫描方向下窗口的起点X坐标
    458. * @param usY :在特定扫描方向下窗口的起点Y坐标
    459. * @param usWidth :窗口的宽度
    460. * @param usHeight :窗口的高度
    461. * @retval 无
    462. */
    463. void ILI9341_OpenWindow ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
    464. {
    465. ILI9341_Write_Cmd ( CMD_SetCoordinateX ); /* 设置X坐标 */
    466. ILI9341_Write_Data ( usX >> 8 ); /* 先高8位,然后低8位 */
    467. ILI9341_Write_Data ( usX & 0xff ); /* 设置起始点和结束点*/
    468. ILI9341_Write_Data ( ( usX + usWidth - 1 ) >> 8 );
    469. ILI9341_Write_Data ( ( usX + usWidth - 1 ) & 0xff );
    470. ILI9341_Write_Cmd ( CMD_SetCoordinateY ); /* 设置Y坐标*/
    471. ILI9341_Write_Data ( usY >> 8 );
    472. ILI9341_Write_Data ( usY & 0xff );
    473. ILI9341_Write_Data ( ( usY + usHeight - 1 ) >> 8 );
    474. ILI9341_Write_Data ( ( usY + usHeight - 1) & 0xff );
    475. }
    476. /**
    477. * @brief 设定ILI9341的光标坐标
    478. * @param usX :在特定扫描方向下光标的X坐标
    479. * @param usY :在特定扫描方向下光标的Y坐标
    480. * @retval 无
    481. */
    482. static void ILI9341_SetCursor ( uint16_t usX, uint16_t usY )
    483. {
    484. ILI9341_OpenWindow ( usX, usY, 1, 1 );
    485. }
    486. /**
    487. * @brief 在ILI9341显示器上以某一颜色填充像素点
    488. * @param ulAmout_Point :要填充颜色的像素点的总数目
    489. * @param usColor :颜色
    490. * @retval 无
    491. */
    492. static __inline void ILI9341_FillColor ( uint32_t ulAmout_Point, uint16_t usColor )
    493. {
    494. uint32_t i = 0;
    495. /* memory write */
    496. ILI9341_Write_Cmd ( CMD_SetPixel );
    497. for ( i = 0; i < ulAmout_Point; i ++ )
    498. ILI9341_Write_Data ( usColor );
    499. }
    500. /**
    501. * @brief 对ILI9341显示器的某一窗口以某种颜色进行清屏
    502. * @param usX :在特定扫描方向下窗口的起点X坐标
    503. * @param usY :在特定扫描方向下窗口的起点Y坐标
    504. * @param usWidth :窗口的宽度
    505. * @param usHeight :窗口的高度
    506. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    507. * @retval 无
    508. */
    509. void ILI9341_Clear ( uint16_t usX, uint16_t usY, uint16_t usWidth, uint16_t usHeight )
    510. {
    511. ILI9341_OpenWindow ( usX, usY, usWidth, usHeight );
    512. ILI9341_FillColor ( usWidth * usHeight, CurrentBackColor );
    513. }
    514. /**
    515. * @brief 对ILI9341显示器的某一点以某种颜色进行填充
    516. * @param usX :在特定扫描方向下该点的X坐标
    517. * @param usY :在特定扫描方向下该点的Y坐标
    518. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    519. * @retval 无
    520. */
    521. void ILI9341_SetPointPixel ( uint16_t usX, uint16_t usY )
    522. {
    523. if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH ))
    524. {
    525. ILI9341_SetCursor ( usX, usY );
    526. ILI9341_FillColor ( 1, CYAN );
    527. }
    528. }
    529. /**
    530. * @brief 对ILI9341显示器的某一点以某种颜色进行填充
    531. * @param usX :在特定扫描方向下该点的X坐标
    532. * @param usY :在特定扫描方向下该点的Y坐标
    533. * @param fill:0和1选择填充前景色或背景色
    534. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    535. * @retval 无
    536. */
    537. void ILI9341_SetPointPixel_Fill ( uint16_t usX, uint16_t usY ,uint8_t fill)
    538. {
    539. if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH )&& fill)
    540. {
    541. ILI9341_SetCursor ( usX, usY );
    542. ILI9341_FillColor ( 1, CurrentTextColor );
    543. }
    544. else
    545. {
    546. ILI9341_SetCursor ( usX, usY );
    547. ILI9341_FillColor ( 1, CurrentBackColor );
    548. }
    549. }
    550. /**
    551. * @brief 对ILI9341显示器的某一点以某种颜色进行填充
    552. * @param usX :在特定扫描方向下该点的X坐标
    553. * @param usY :在特定扫描方向下该点的Y坐标
    554. * @param color:选择某种颜色进行填充
    555. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    556. * @retval 无
    557. */
    558. void ILI9341_SetPointPixel_Color ( uint16_t usX, uint16_t usY ,uint16_t color)
    559. {
    560. if ( ( usX < LCD_X_LENGTH ) && ( usY < LCD_Y_LENGTH ))
    561. {
    562. ILI9341_SetCursor ( usX, usY );
    563. ILI9341_FillColor ( 1, color );
    564. }
    565. }
    566. /**
    567. * @brief 读取ILI9341 GRAN 的一个像素数据
    568. * @param 无
    569. * @retval 像素数据
    570. */
    571. static uint16_t ILI9341_Read_PixelData ( void )
    572. {
    573. uint16_t usR=0, usG=0, usB=0 ;
    574. ILI9341_Write_Cmd ( 0x2E ); /* 读数据 */
    575. usR = ILI9341_Read_Data (); /*FIRST READ OUT DUMMY DATA*/
    576. usR = ILI9341_Read_Data (); /*READ OUT RED DATA */
    577. usB = ILI9341_Read_Data (); /*READ OUT BLUE DATA*/
    578. usG = ILI9341_Read_Data (); /*READ OUT GREEN DATA*/
    579. return ( ( ( usR >> 11 ) << 11 ) | ( ( usG >> 10 ) << 5 ) | ( usB >> 11 ) );
    580. }
    581. /**
    582. * @brief 获取 ILI9341 显示器上某一个坐标点的像素数据
    583. * @param usX :在特定扫描方向下该点的X坐标
    584. * @param usY :在特定扫描方向下该点的Y坐标
    585. * @retval 像素数据
    586. */
    587. uint16_t ILI9341_GetPointPixel ( uint16_t usX, uint16_t usY )
    588. {
    589. uint16_t usPixelData;
    590. ILI9341_SetCursor ( usX, usY );
    591. usPixelData = ILI9341_Read_PixelData ();
    592. return usPixelData;
    593. }
    594. /**
    595. * @brief 在 ILI9341 显示器上使用 Bresenham 算法画线段
    596. * @param usX1 :在特定扫描方向下线段的一个端点X坐标
    597. * @param usY1 :在特定扫描方向下线段的一个端点Y坐标
    598. * @param usX2 :在特定扫描方向下线段的另一个端点X坐标
    599. * @param usY2 :在特定扫描方向下线段的另一个端点Y坐标
    600. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    601. * @retval 无
    602. */
    603. void ILI9341_DrawLine ( uint16_t usX1, uint16_t usY1, uint16_t usX2, uint16_t usY2 )
    604. {
    605. uint16_t us;
    606. uint16_t usX_Current, usY_Current;
    607. int32_t lError_X = 0, lError_Y = 0, lDelta_X, lDelta_Y, lDistance;
    608. int32_t lIncrease_X, lIncrease_Y;
    609. lDelta_X = usX2 - usX1; //计算坐标增量
    610. lDelta_Y = usY2 - usY1;
    611. usX_Current = usX1;
    612. usY_Current = usY1;
    613. if ( lDelta_X > 0 )
    614. lIncrease_X = 1; //设置单步方向
    615. else if ( lDelta_X == 0 )
    616. lIncrease_X = 0;//垂直线
    617. else
    618. {
    619. lIncrease_X = -1;
    620. lDelta_X = - lDelta_X;
    621. }
    622. if ( lDelta_Y > 0 )
    623. lIncrease_Y = 1;
    624. else if ( lDelta_Y == 0 )
    625. lIncrease_Y = 0;//水平线
    626. else
    627. {
    628. lIncrease_Y = -1;
    629. lDelta_Y = - lDelta_Y;
    630. }
    631. if ( lDelta_X > lDelta_Y )
    632. lDistance = lDelta_X; //选取基本增量坐标轴
    633. else
    634. lDistance = lDelta_Y;
    635. for ( us = 0; us <= lDistance + 1; us ++ )//画线输出
    636. {
    637. ILI9341_SetPointPixel ( usX_Current, usY_Current );//画点
    638. lError_X += lDelta_X ;
    639. lError_Y += lDelta_Y ;
    640. if ( lError_X > lDistance )
    641. {
    642. lError_X -= lDistance;
    643. usX_Current += lIncrease_X;
    644. }
    645. if ( lError_Y > lDistance )
    646. {
    647. lError_Y -= lDistance;
    648. usY_Current += lIncrease_Y;
    649. }
    650. }
    651. }
    652. /*
    653. 函数功能:任意角度画直线
    654. 参 数:
    655. usX,usY:坐标
    656. usAngle :度数
    657. usRadius:半径
    658. usLength :线段的长度
    659. c :颜色值 0或者1
    660. 例如:ILI9341_DrawAngleLine(60,30,45,20,20,1);//角度画线
    661. */
    662. void ILI9341_DrawAngleLine( uint32_t usX, uint32_t usY, float usAngle, uint32_t usRadius, uint32_t usLength,uint16_t color)
    663. {
    664. int i;
    665. int x0,y0;
    666. double k=usAngle*(3.1415926535/180);
    667. for(i=usRadius;i
    668. {
    669. x0=cos(k)*i;
    670. y0=sin(k)*i;
    671. ILI9341_SetPointPixel_Color(usX+x0,usY+y0,color);
    672. }
    673. }
    674. /*
    675. 函数功能:任意角度画直线
    676. 参 数:
    677. usX,usY:坐标
    678. usRadius :度数
    679. usLength :线段的长度
    680. c :颜色值 0或者1
    681. 例如:OLED_DrawAngleLine(60,30,45,20,20,1);//角度画线
    682. */
    683. void ILI9341_DrawAngleLine2( uint32_t usX, uint32_t usY,float usAngle,uint32_t usRadius,uint32_t usLength,uint8_t fill)
    684. {
    685. uint32_t i;
    686. int x0,y0;
    687. double k=usAngle*(3.1415926535L/180);
    688. for(i=usRadius;i
    689. {
    690. x0=cos(k)*i;
    691. y0=sin(k)*i;
    692. ILI9341_SetPointPixel_Fill(usX+x0,usY+y0,fill);
    693. }
    694. }
    695. /**
    696. * @brief 在 ILI9341 显示器上画一个矩形
    697. * @param usX_Start :在特定扫描方向下矩形的起始点X坐标
    698. * @param usY_Start :在特定扫描方向下矩形的起始点Y坐标
    699. * @param usWidth:矩形的宽度(单位:像素)
    700. * @param usHeight:矩形的高度(单位:像素)
    701. * @param ucFilled :选择是否填充该矩形
    702. * 该参数为以下值之一:
    703. * @arg 0 :空心矩形
    704. * @arg 1 :实心矩形
    705. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    706. * @retval 无
    707. */
    708. void ILI9341_DrawRectangle ( uint16_t usX_Start, uint16_t usY_Start, uint16_t usWidth, uint16_t usHeight, uint8_t ucFilled )
    709. {
    710. if ( ucFilled )
    711. {
    712. ILI9341_OpenWindow ( usX_Start, usY_Start, usWidth, usHeight );
    713. ILI9341_FillColor ( usWidth * usHeight ,CurrentTextColor);
    714. }
    715. else
    716. {
    717. ILI9341_DrawLine ( usX_Start, usY_Start, usX_Start + usWidth - 1, usY_Start );
    718. ILI9341_DrawLine ( usX_Start, usY_Start + usHeight - 1, usX_Start + usWidth - 1, usY_Start + usHeight - 1 );
    719. ILI9341_DrawLine ( usX_Start, usY_Start, usX_Start, usY_Start + usHeight - 1 );
    720. ILI9341_DrawLine ( usX_Start + usWidth - 1, usY_Start, usX_Start + usWidth - 1, usY_Start + usHeight - 1 );
    721. }
    722. }
    723. /**
    724. * @brief 在 ILI9341 显示器上使用 Bresenham 算法画圆
    725. * @param usX_Center :在特定扫描方向下圆心的X坐标
    726. * @param usY_Center :在特定扫描方向下圆心的Y坐标
    727. * @param usRadius:圆的半径(单位:像素)
    728. * @param ucFilled :选择是否填充该圆
    729. * 该参数为以下值之一:
    730. * @arg 0 :空心圆
    731. * @arg 1 :实心圆
    732. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    733. * @retval 无
    734. */
    735. void ILI9341_DrawCircle ( uint16_t usX_Center, uint16_t usY_Center, uint16_t usRadius, uint8_t ucFilled )
    736. {
    737. int16_t sCurrentX, sCurrentY;
    738. int16_t sError;
    739. sCurrentX = 0; sCurrentY = usRadius;
    740. sError = 3 - ( usRadius << 1 ); //判断下个点位置的标志
    741. while ( sCurrentX <= sCurrentY )
    742. {
    743. int16_t sCountY;
    744. if ( ucFilled )
    745. for ( sCountY = sCurrentX; sCountY <= sCurrentY; sCountY ++ )
    746. {
    747. ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center + sCountY ); //1,研究对象
    748. ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center + sCountY ); //2
    749. ILI9341_SetPointPixel ( usX_Center - sCountY, usY_Center + sCurrentX ); //3
    750. ILI9341_SetPointPixel ( usX_Center - sCountY, usY_Center - sCurrentX ); //4
    751. ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center - sCountY ); //5
    752. ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center - sCountY ); //6
    753. ILI9341_SetPointPixel ( usX_Center + sCountY, usY_Center - sCurrentX ); //7
    754. ILI9341_SetPointPixel ( usX_Center + sCountY, usY_Center + sCurrentX ); //0
    755. }
    756. else
    757. {
    758. ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center + sCurrentY ); //1,研究对象
    759. ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center + sCurrentY ); //2
    760. ILI9341_SetPointPixel ( usX_Center - sCurrentY, usY_Center + sCurrentX ); //3
    761. ILI9341_SetPointPixel ( usX_Center - sCurrentY, usY_Center - sCurrentX ); //4
    762. ILI9341_SetPointPixel ( usX_Center - sCurrentX, usY_Center - sCurrentY ); //5
    763. ILI9341_SetPointPixel ( usX_Center + sCurrentX, usY_Center - sCurrentY ); //6
    764. ILI9341_SetPointPixel ( usX_Center + sCurrentY, usY_Center - sCurrentX ); //7
    765. ILI9341_SetPointPixel ( usX_Center + sCurrentY, usY_Center + sCurrentX ); //0
    766. }
    767. sCurrentX ++;
    768. if ( sError < 0 )
    769. sError += 4 * sCurrentX + 6;
    770. else
    771. {
    772. sError += 10 + 4 * ( sCurrentX - sCurrentY );
    773. sCurrentY --;
    774. }
    775. }
    776. }
    777. /**
    778. * @brief 在 ILI9341 显示器上显示一个英文字符
    779. * @param usX :在特定扫描方向下字符的起始X坐标
    780. * @param usY :在特定扫描方向下该点的起始Y坐标
    781. * @param cChar :要显示的英文字符
    782. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    783. * @retval 无
    784. */
    785. void ILI9341_DispChar_EN ( uint16_t usX, uint16_t usY, const char cChar )
    786. {
    787. uint8_t byteCount, bitCount,fontLength;
    788. uint16_t ucRelativePositon;
    789. uint8_t *Pfont;
    790. //对ascii码表偏移(字模表不包含ASCII表的前32个非图形符号)
    791. ucRelativePositon = cChar - ' ';
    792. //每个字模的字节数
    793. fontLength = (LCD_Currentfonts->Width*LCD_Currentfonts->Height)/8;
    794. //字模首地址
    795. /*ascii码表偏移值乘以每个字模的字节数,求出字模的偏移位置*/
    796. Pfont = (uint8_t *)&LCD_Currentfonts->table[ucRelativePositon * fontLength];
    797. //设置显示窗口
    798. ILI9341_OpenWindow ( usX, usY, LCD_Currentfonts->Width, LCD_Currentfonts->Height);
    799. ILI9341_Write_Cmd ( CMD_SetPixel );
    800. //按字节读取字模数据
    801. //由于前面直接设置了显示窗口,显示数据会自动换行
    802. for ( byteCount = 0; byteCount < fontLength; byteCount++ )
    803. {
    804. //一位一位处理要显示的颜色
    805. for ( bitCount = 0; bitCount < 8; bitCount++ )
    806. {
    807. if ( Pfont[byteCount] & (0x80>>bitCount) )
    808. ILI9341_Write_Data ( CurrentTextColor );
    809. else
    810. ILI9341_Write_Data ( CurrentBackColor );
    811. }
    812. }
    813. }
    814. /**
    815. * @brief 在 ILI9341 显示器上显示一个中文字符
    816. * @param usX :在特定扫描方向下字符的起始X坐标
    817. * @param usY :在特定扫描方向下字符的起始Y坐标
    818. * @param usChar :要显示的中文字符(国标码)
    819. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    820. * @retval 无
    821. */
    822. void ILI9341_DispChar_CH ( uint16_t usX, uint16_t usY, uint16_t usChar )
    823. {
    824. uint8_t rowCount, bitCount;
    825. uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];
    826. uint16_t usTemp;
    827. //设置显示窗口
    828. ILI9341_OpenWindow ( usX, usY, WIDTH_CH_CHAR, HEIGHT_CH_CHAR );
    829. ILI9341_Write_Cmd ( CMD_SetPixel );
    830. //取字模数据
    831. GetGBKCode ( ucBuffer, usChar );
    832. for ( rowCount = 0; rowCount < HEIGHT_CH_CHAR; rowCount++ )
    833. {
    834. /* 取出两个字节的数据,在lcd上即是一个汉字的一行 */
    835. usTemp = ucBuffer [ rowCount * 2 ];
    836. usTemp = ( usTemp << 8 );
    837. usTemp |= ucBuffer [ rowCount * 2 + 1 ];
    838. for ( bitCount = 0; bitCount < WIDTH_CH_CHAR; bitCount ++ )
    839. {
    840. if ( usTemp & ( 0x8000 >> bitCount ) ) //高位在前
    841. ILI9341_Write_Data ( CurrentTextColor );
    842. else
    843. ILI9341_Write_Data ( CurrentBackColor );
    844. }
    845. }
    846. }
    847. /**
    848. * @brief 在 ILI9341 显示器上显示英文字符串
    849. * @param line :在特定扫描方向下字符串的起始Y坐标
    850. * 本参数可使用宏LINE(0)、LINE(1)等方式指定文字坐标,
    851. * 宏LINE(x)会根据当前选择的字体来计算Y坐标值。
    852. * 显示中文且使用LINE宏时,需要把英文字体设置成Font8x16
    853. * @param pStr :要显示的英文字符串的首地址
    854. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    855. * @retval 无
    856. */
    857. void ILI9341_DispStringLine_EN ( uint16_t line, char * pStr )
    858. {
    859. uint16_t usX = 0;
    860. while ( * pStr != '\0' )
    861. {
    862. if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
    863. {
    864. usX = ILI9341_DispWindow_X_Star;
    865. line += LCD_Currentfonts->Height;
    866. }
    867. if ( ( line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
    868. {
    869. usX = ILI9341_DispWindow_X_Star;
    870. line = ILI9341_DispWindow_Y_Star;
    871. }
    872. ILI9341_DispChar_EN ( usX, line, * pStr);
    873. pStr ++;
    874. usX += LCD_Currentfonts->Width;
    875. }
    876. }
    877. /**
    878. * @brief 在 ILI9341 显示器上显示英文字符串
    879. * @param usX :在特定扫描方向下字符的起始X坐标
    880. * @param usY :在特定扫描方向下字符的起始Y坐标
    881. * @param pStr :要显示的英文字符串的首地址
    882. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    883. * @retval 无
    884. */
    885. void ILI9341_DispString_EN ( uint16_t usX ,uint16_t usY, char * pStr )
    886. {
    887. while ( * pStr != '\0' )
    888. {
    889. if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
    890. {
    891. usX = ILI9341_DispWindow_X_Star;
    892. usY += LCD_Currentfonts->Height;
    893. }
    894. if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
    895. {
    896. usX = ILI9341_DispWindow_X_Star;
    897. usY = ILI9341_DispWindow_Y_Star;
    898. }
    899. ILI9341_DispChar_EN ( usX, usY, * pStr);
    900. pStr ++;
    901. usX += LCD_Currentfonts->Width;
    902. }
    903. }
    904. /**
    905. * @brief 在 ILI9341 显示器上显示英文字符串(沿Y轴方向)
    906. * @param usX :在特定扫描方向下字符的起始X坐标
    907. * @param usY :在特定扫描方向下字符的起始Y坐标
    908. * @param pStr :要显示的英文字符串的首地址
    909. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    910. * @retval 无
    911. */
    912. void ILI9341_DispString_EN_YDir ( uint16_t usX,uint16_t usY , char * pStr )
    913. {
    914. while ( * pStr != '\0' )
    915. {
    916. if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) >LCD_Y_LENGTH )
    917. {
    918. usY = ILI9341_DispWindow_Y_Star;
    919. usX += LCD_Currentfonts->Width;
    920. }
    921. if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH)
    922. {
    923. usX = ILI9341_DispWindow_X_Star;
    924. usY = ILI9341_DispWindow_Y_Star;
    925. }
    926. ILI9341_DispChar_EN ( usX, usY, * pStr);
    927. pStr ++;
    928. usY += LCD_Currentfonts->Height;
    929. }
    930. }
    931. /**
    932. * @brief 在 ILI9341 显示器上显示中英文字符串
    933. * @param usX :在特定扫描方向下字符的起始X坐标
    934. * @param usY :在特定扫描方向下字符的起始Y坐标
    935. * @param pStr :要显示的字符串的首地址
    936. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    937. * @retval 无
    938. */
    939. void ILI9341_DispString_EN_CH ( uint16_t usX , uint16_t usY, char * pStr )
    940. {
    941. uint16_t usCh;
    942. while( * pStr != '\0' )
    943. {
    944. if ( * pStr <= 126 ) //英文字符
    945. {
    946. if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
    947. {
    948. usX = ILI9341_DispWindow_X_Star;
    949. usY += LCD_Currentfonts->Height;
    950. }
    951. if ( ( usY - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
    952. {
    953. usX = ILI9341_DispWindow_X_Star;
    954. usY = ILI9341_DispWindow_Y_Star;
    955. }
    956. ILI9341_DispChar_EN ( usX, usY, * pStr );
    957. usX += LCD_Currentfonts->Width;
    958. pStr ++;
    959. }
    960. else //汉字字符
    961. {
    962. if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH )
    963. {
    964. usX = ILI9341_DispWindow_X_Star;
    965. usY += HEIGHT_CH_CHAR;
    966. }
    967. if ( ( usY - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH )
    968. {
    969. usX = ILI9341_DispWindow_X_Star;
    970. usY = ILI9341_DispWindow_Y_Star;
    971. }
    972. usCh = * ( uint16_t * ) pStr;
    973. usCh = ( usCh << 8 ) + ( usCh >> 8 );
    974. ILI9341_DispChar_CH ( usX, usY, usCh );
    975. usX += WIDTH_CH_CHAR;
    976. pStr += 2; //一个汉字两个字节
    977. }
    978. }
    979. }
    980. /**
    981. * @brief 在 ILI9341 显示器上显示中英文字符串
    982. * @param line :在特定扫描方向下字符串的起始Y坐标
    983. * 本参数可使用宏LINE(0)、LINE(1)等方式指定文字坐标,
    984. * 宏LINE(x)会根据当前选择的字体来计算Y坐标值。
    985. * 显示中文且使用LINE宏时,需要把英文字体设置成Font8x16
    986. * @param pStr :要显示的字符串的首地址
    987. * @note 可使用LCD_SetBackColor、LCD_SetTextColor、LCD_SetColors函数设置颜色
    988. * @retval 无
    989. */
    990. void ILI9341_DispStringLine_EN_CH ( uint16_t line, char * pStr )
    991. {
    992. uint16_t usCh;
    993. uint16_t usX = 0;
    994. while( * pStr != '\0' )
    995. {
    996. if ( * pStr <= 126 ) //英文字符
    997. {
    998. if ( ( usX - ILI9341_DispWindow_X_Star + LCD_Currentfonts->Width ) > LCD_X_LENGTH )
    999. {
    1000. usX = ILI9341_DispWindow_X_Star;
    1001. line += LCD_Currentfonts->Height;
    1002. }
    1003. if ( ( line - ILI9341_DispWindow_Y_Star + LCD_Currentfonts->Height ) > LCD_Y_LENGTH )
    1004. {
    1005. usX = ILI9341_DispWindow_X_Star;
    1006. line = ILI9341_DispWindow_Y_Star;
    1007. }
    1008. ILI9341_DispChar_EN ( usX, line, * pStr );
    1009. usX += LCD_Currentfonts->Width;
    1010. pStr ++;
    1011. }
    1012. else //汉字字符
    1013. {
    1014. if ( ( usX - ILI9341_DispWindow_X_Star + WIDTH_CH_CHAR ) > LCD_X_LENGTH )
    1015. {
    1016. usX = ILI9341_DispWindow_X_Star;
    1017. line += HEIGHT_CH_CHAR;
    1018. }
    1019. if ( ( line - ILI9341_DispWindow_Y_Star + HEIGHT_CH_CHAR ) > LCD_Y_LENGTH )
    1020. {
    1021. usX = ILI9341_DispWindow_X_Star;
    1022. line = ILI9341_DispWindow_Y_Star;
    1023. }
    1024. usCh = * ( uint16_t * ) pStr;
    1025. usCh = ( usCh << 8 ) + ( usCh >> 8 );
    1026. ILI9341_DispChar_CH ( usX, line, usCh );
    1027. usX += WIDTH_CH_CHAR;
    1028. pStr += 2; //一个汉字两个字节
    1029. }
    1030. }
    1031. }
    1032. /**
    1033. * @brief 设置英文字体类型
    1034. * @param fonts: 指定要选择的字体
    1035. * 参数为以下值之一
    1036. * @arg:Font24x32;
    1037. * @arg:Font16x24;
    1038. * @arg:Font8x16;
    1039. * @retval None
    1040. */
    1041. void LCD_SetFont(sFONT *fonts)
    1042. {
    1043. LCD_Currentfonts = fonts;
    1044. }
    1045. /**
    1046. * @brief 获取当前字体类型
    1047. * @param None.
    1048. * @retval 返回当前字体类型
    1049. */
    1050. sFONT *LCD_GetFont(void)
    1051. {
    1052. return LCD_Currentfonts;
    1053. }
    1054. /**
    1055. * @brief 设置LCD的前景(字体)及背景颜色,RGB565
    1056. * @param TextColor: 指定前景(字体)颜色
    1057. * @param BackColor: 指定背景颜色
    1058. * @retval None
    1059. */
    1060. void LCD_SetColors(uint16_t TextColor, uint16_t BackColor)
    1061. {
    1062. CurrentTextColor = TextColor;
    1063. CurrentBackColor = BackColor;
    1064. }
    1065. /**
    1066. * @brief 获取LCD的前景(字体)及背景颜色,RGB565
    1067. * @param TextColor: 用来存储前景(字体)颜色的指针变量
    1068. * @param BackColor: 用来存储背景颜色的指针变量
    1069. * @retval None
    1070. */
    1071. void LCD_GetColors(uint16_t *TextColor, uint16_t *BackColor)
    1072. {
    1073. *TextColor = CurrentTextColor;
    1074. *BackColor = CurrentBackColor;
    1075. }
    1076. /**
    1077. * @brief 设置LCD的前景(字体)颜色,RGB565
    1078. * @param Color: 指定前景(字体)颜色
    1079. * @retval None
    1080. */
    1081. void LCD_SetTextColor(uint16_t Color)
    1082. {
    1083. CurrentTextColor = Color;
    1084. }
    1085. /**
    1086. * @brief 设置LCD的背景颜色,RGB565
    1087. * @param Color: 指定背景颜色
    1088. * @retval None
    1089. */
    1090. void LCD_SetBackColor(uint16_t Color)
    1091. {
    1092. CurrentBackColor = Color;
    1093. }
    1094. /**
    1095. * @brief 清除某行文字
    1096. * @param Line: 指定要删除的行
    1097. * 本参数可使用宏LINE(0)、LINE(1)等方式指定要删除的行,
    1098. * 宏LINE(x)会根据当前选择的字体来计算Y坐标值,并删除当前字体高度的第x行。
    1099. * @retval None
    1100. */
    1101. void LCD_ClearLine(uint16_t Line)
    1102. {
    1103. ILI9341_Clear(0,Line,LCD_X_LENGTH,((sFONT *)LCD_GetFont())->Height); /* 清屏,显示全黑 */
    1104. }
    1105. /***********************缩放字体****************************/
    1106. #define ZOOMMAXBUFF 16384
    1107. uint8_t zoomBuff[ZOOMMAXBUFF] = {0}; //用于缩放的缓存,最大支持到128*128
    1108. uint8_t zoomTempBuff[1024] = {0};
    1109. /**
    1110. * @brief 缩放字模,缩放后的字模由1个像素点由8个数据位来表示
    1111. 0x01表示笔迹,0x00表示空白区
    1112. * @param in_width :原始字符宽度
    1113. * @param in_heig :原始字符高度
    1114. * @param out_width :缩放后的字符宽度
    1115. * @param out_heig:缩放后的字符高度
    1116. * @param in_ptr :字库输入指针 注意:1pixel 1bit
    1117. * @param out_ptr :缩放后的字符输出指针 注意: 1pixel 8bit
    1118. * out_ptr实际上没有正常输出,改成了直接输出到全局指针zoomBuff中
    1119. * @param en_cn :0为英文,1为中文
    1120. * @retval 无
    1121. */
    1122. void ILI9341_zoomChar(uint16_t in_width, //原始字符宽度
    1123. uint16_t in_heig, //原始字符高度
    1124. uint16_t out_width, //缩放后的字符宽度
    1125. uint16_t out_heig, //缩放后的字符高度
    1126. uint8_t *in_ptr, //字库输入指针 注意:1pixel 1bit
    1127. uint8_t *out_ptr, //缩放后的字符输出指针 注意: 1pixel 8bit
    1128. uint8_t en_cn) //0为英文,1为中文
    1129. {
    1130. uint8_t *pts,*ots;
    1131. //根据源字模及目标字模大小,设定运算比例因子,左移16是为了把浮点运算转成定点运算
    1132. unsigned int xrIntFloat_16=(in_width<<16)/out_width+1;
    1133. unsigned int yrIntFloat_16=(in_heig<<16)/out_heig+1;
    1134. unsigned int srcy_16=0;
    1135. unsigned int y,x;
    1136. uint8_t *pSrcLine;
    1137. uint16_t byteCount,bitCount;
    1138. //检查参数是否合法
    1139. if(in_width >= 32) return; //字库不允许超过32像素
    1140. if(in_width * in_heig == 0) return;
    1141. if(in_width * in_heig >= 1024 ) return; //限制输入最大 32*32
    1142. if(out_width * out_heig == 0) return;
    1143. if(out_width * out_heig >= ZOOMMAXBUFF ) return; //限制最大缩放 128*128
    1144. pts = (uint8_t*)&zoomTempBuff;
    1145. //为方便运算,字库的数据由1 pixel/1bit 映射到1pixel/8bit
    1146. //0x01表示笔迹,0x00表示空白区
    1147. if(en_cn == 0x00)//英文
    1148. {
    1149. //英文和中文字库上下边界不对,可在此处调整。需要注意tempBuff防止溢出
    1150. for(byteCount=0;byteCount8;byteCount++)
    1151. {
    1152. for(bitCount=0;bitCount<8;bitCount++)
    1153. {
    1154. //把源字模数据由位映射到字节
    1155. //in_ptr里bitX为1,则pts里整个字节值为1
    1156. //in_ptr里bitX为0,则pts里整个字节值为0
    1157. *pts++ = (in_ptr[byteCount] & (0x80>>bitCount))?1:0;
    1158. }
    1159. }
    1160. }
    1161. else //中文
    1162. {
    1163. for(byteCount=0;byteCount8;byteCount++)
    1164. {
    1165. for(bitCount=0;bitCount<8;bitCount++)
    1166. {
    1167. //把源字模数据由位映射到字节
    1168. //in_ptr里bitX为1,则pts里整个字节值为1
    1169. //in_ptr里bitX为0,则pts里整个字节值为0
    1170. *pts++ = (in_ptr[byteCount] & (0x80>>bitCount))?1:0;
    1171. }
    1172. }
    1173. }
    1174. //zoom过程
    1175. pts = (uint8_t*)&zoomTempBuff; //映射后的源数据指针
    1176. ots = (uint8_t*)&zoomBuff; //输出数据的指针
    1177. for (y=0;y/*行遍历*/
    1178. {
    1179. unsigned int srcx_16=0;
    1180. pSrcLine=pts+in_width*(srcy_16>>16);
    1181. for (x=0;x/*行内像素遍历*/
    1182. {
    1183. ots[x]=pSrcLine[srcx_16>>16]; //把源字模数据复制到目标指针中
    1184. srcx_16+=xrIntFloat_16; //按比例偏移源像素点
    1185. }
    1186. srcy_16+=yrIntFloat_16; //按比例偏移源像素点
    1187. ots+=out_width;
    1188. }
    1189. /*!!!缩放后的字模数据直接存储到全局指针zoomBuff里了*/
    1190. out_ptr = (uint8_t*)&zoomBuff; //out_ptr没有正确传出,后面调用直接改成了全局变量指针!
    1191. /*实际中如果使用out_ptr不需要下面这一句!!!
    1192. 只是因为out_ptr没有使用,会导致warning。强迫症*/
    1193. out_ptr++;
    1194. }
    1195. /**
    1196. * @brief 利用缩放后的字模显示字符
    1197. * @param Xpos :字符显示位置x
    1198. * @param Ypos :字符显示位置y
    1199. * @param Font_width :字符宽度
    1200. * @param Font_Heig:字符高度
    1201. * @param c :要显示的字模数据
    1202. * @param DrawModel :是否反色显示
    1203. * @retval 无
    1204. */
    1205. void ILI9341_DrawChar_Ex(uint16_t usX, //字符显示位置x
    1206. uint16_t usY, //字符显示位置y
    1207. uint16_t Font_width, //字符宽度
    1208. uint16_t Font_Height, //字符高度
    1209. uint8_t *c, //字模数据
    1210. uint16_t DrawModel) //是否反色显示
    1211. {
    1212. uint32_t index = 0, counter = 0;
    1213. //设置显示窗口
    1214. ILI9341_OpenWindow ( usX, usY, Font_width, Font_Height);
    1215. ILI9341_Write_Cmd ( CMD_SetPixel );
    1216. //按字节读取字模数据
    1217. //由于前面直接设置了显示窗口,显示数据会自动换行
    1218. for ( index = 0; index < Font_Height; index++ )
    1219. {
    1220. //一位一位处理要显示的颜色
    1221. for ( counter = 0; counter < Font_width; counter++ )
    1222. {
    1223. //缩放后的字模数据,以一个字节表示一个像素位
    1224. //整个字节值为1表示该像素为笔迹
    1225. //整个字节值为0表示该像素为背景
    1226. if ( *c++ == DrawModel )
    1227. ILI9341_Write_Data ( CurrentBackColor );
    1228. else
    1229. ILI9341_Write_Data ( CurrentTextColor );
    1230. }
    1231. }
    1232. }
    1233. /**
    1234. * @brief 利用缩放后的字模显示字符串
    1235. * @param Xpos :字符显示位置x
    1236. * @param Ypos :字符显示位置y
    1237. * @param Font_width :字符宽度,英文字符在此基础上/2。注意为偶数
    1238. * @param Font_Heig:字符高度,注意为偶数
    1239. * @param c :要显示的字符串
    1240. * @param DrawModel :是否反色显示
    1241. * @retval 无
    1242. */
    1243. void ILI9341_DisplayStringEx(uint16_t x, //字符显示位置x
    1244. uint16_t y, //字符显示位置y
    1245. uint16_t Font_width, //要显示的字体宽度,英文字符在此基础上/2。注意为偶数
    1246. uint16_t Font_Height, //要显示的字体高度,注意为偶数
    1247. uint8_t *ptr, //显示的字符内容
    1248. uint16_t DrawModel) //是否反色显示
    1249. {
    1250. uint16_t Charwidth = Font_width; //默认为Font_width,英文宽度为中文宽度的一半
    1251. uint8_t *psr;
    1252. uint8_t Ascii; //英文
    1253. uint16_t usCh; //中文
    1254. uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];
    1255. while ( *ptr != '\0')
    1256. {
    1257. /****处理换行*****/
    1258. if ( ( x - ILI9341_DispWindow_X_Star + Charwidth ) > LCD_X_LENGTH )
    1259. {
    1260. x = ILI9341_DispWindow_X_Star;
    1261. y += Font_Height;
    1262. }
    1263. if ( ( y - ILI9341_DispWindow_Y_Star + Font_Height ) > LCD_Y_LENGTH )
    1264. {
    1265. x = ILI9341_DispWindow_X_Star;
    1266. y = ILI9341_DispWindow_Y_Star;
    1267. }
    1268. if(*ptr > 0x80) //如果是中文
    1269. {
    1270. Charwidth = Font_width;
    1271. usCh = * ( uint16_t * ) ptr;
    1272. usCh = ( usCh << 8 ) + ( usCh >> 8 );
    1273. GetGBKCode ( ucBuffer, usCh ); //取字模数据
    1274. //缩放字模数据,源字模为16*16
    1275. ILI9341_zoomChar(WIDTH_CH_CHAR,HEIGHT_CH_CHAR,Charwidth,Font_Height,(uint8_t *)&ucBuffer,psr,1);
    1276. //显示单个字符
    1277. ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);
    1278. x+=Charwidth;
    1279. ptr+=2;
    1280. }
    1281. else
    1282. {
    1283. Charwidth = Font_width / 2;
    1284. Ascii = *ptr - 32;
    1285. //使用16*24字体缩放字模数据
    1286. ILI9341_zoomChar(16,24,Charwidth,Font_Height,(uint8_t *)&Font16x24.table[Ascii * Font16x24.Height*Font16x24.Width/8],psr,0);
    1287. //显示单个字符
    1288. ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);
    1289. x+=Charwidth;
    1290. ptr++;
    1291. }
    1292. }
    1293. }
    1294. /**
    1295. * @brief 利用缩放后的字模显示字符串(沿Y轴方向)
    1296. * @param Xpos :字符显示位置x
    1297. * @param Ypos :字符显示位置y
    1298. * @param Font_width :字符宽度,英文字符在此基础上/2。注意为偶数
    1299. * @param Font_Heig:字符高度,注意为偶数
    1300. * @param c :要显示的字符串
    1301. * @param DrawModel :是否反色显示
    1302. * @retval 无
    1303. */
    1304. void ILI9341_DisplayStringEx_YDir(uint16_t x, //字符显示位置x
    1305. uint16_t y, //字符显示位置y
    1306. uint16_t Font_width, //要显示的字体宽度,英文字符在此基础上/2。注意为偶数
    1307. uint16_t Font_Height, //要显示的字体高度,注意为偶数
    1308. uint8_t *ptr, //显示的字符内容
    1309. uint16_t DrawModel) //是否反色显示
    1310. {
    1311. uint16_t Charwidth = Font_width; //默认为Font_width,英文宽度为中文宽度的一半
    1312. uint8_t *psr;
    1313. uint8_t Ascii; //英文
    1314. uint16_t usCh; //中文
    1315. uint8_t ucBuffer [ WIDTH_CH_CHAR*HEIGHT_CH_CHAR/8 ];
    1316. while ( *ptr != '\0')
    1317. {
    1318. //统一使用汉字的宽高来计算换行
    1319. if ( ( y - ILI9341_DispWindow_X_Star + Font_width ) > LCD_Y_LENGTH )
    1320. {
    1321. y = ILI9341_DispWindow_X_Star;
    1322. x += Font_width;
    1323. }
    1324. if ( ( x - ILI9341_DispWindow_Y_Star + Font_Height ) > LCD_X_LENGTH )
    1325. {
    1326. y = ILI9341_DispWindow_X_Star;
    1327. x = ILI9341_DispWindow_Y_Star;
    1328. }
    1329. if(*ptr > 0x80) //如果是中文
    1330. {
    1331. Charwidth = Font_width;
    1332. usCh = * ( uint16_t * ) ptr;
    1333. usCh = ( usCh << 8 ) + ( usCh >> 8 );
    1334. GetGBKCode ( ucBuffer, usCh ); //取字模数据
    1335. //缩放字模数据,源字模为16*16
    1336. ILI9341_zoomChar(WIDTH_CH_CHAR,HEIGHT_CH_CHAR,Charwidth,Font_Height,(uint8_t *)&ucBuffer,psr,1);
    1337. //显示单个字符
    1338. ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);
    1339. y+=Font_Height;
    1340. ptr+=2;
    1341. }
    1342. else
    1343. {
    1344. Charwidth = Font_width / 2;
    1345. Ascii = *ptr - 32;
    1346. //使用16*24字体缩放字模数据
    1347. ILI9341_zoomChar(16,24,Charwidth,Font_Height,(uint8_t *)&Font16x24.table[Ascii * Font16x24.Height*Font16x24.Width/8],psr,0);
    1348. //显示单个字符
    1349. ILI9341_DrawChar_Ex(x,y,Charwidth,Font_Height,(uint8_t*)&zoomBuff,DrawModel);
    1350. y+=Font_Height;
    1351. ptr++;
    1352. }
    1353. }
    1354. }
    1355. /*********************end of file*************************/

    LD3320.c/usart.c

    1. #include "bsp_usart.h"
    2. #include
    3. /**
    4. * @brief USART GPIO 配置,工作参数配置
    5. * @param 无
    6. * @retval 无
    7. */
    8. void USART_Config(void)
    9. {
    10. GPIO_InitTypeDef GPIO_InitStructure;
    11. USART_InitTypeDef USART_InitStructure;
    12. // 打开串口GPIO的时钟
    13. DEBUG_USART_GPIO_APBxClkCmd(DEBUG_USART_GPIO_CLK, ENABLE);
    14. // 打开串口外设的时钟
    15. DEBUG_USART_APBxClkCmd(DEBUG_USART_CLK, ENABLE);
    16. // 将USART Tx的GPIO配置为推挽复用模式
    17. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_TX_GPIO_PIN;
    18. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    19. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    20. GPIO_Init(DEBUG_USART_TX_GPIO_PORT, &GPIO_InitStructure);
    21. // 将USART Rx的GPIO配置为浮空输入模式
    22. GPIO_InitStructure.GPIO_Pin = DEBUG_USART_RX_GPIO_PIN;
    23. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    24. GPIO_Init(DEBUG_USART_RX_GPIO_PORT, &GPIO_InitStructure);
    25. // 配置串口的工作参数
    26. // 配置波特率
    27. USART_InitStructure.USART_BaudRate = DEBUG_USART_BAUDRATE;
    28. // 配置 针数据字长
    29. USART_InitStructure.USART_WordLength = USART_WordLength_8b;
    30. // 配置停止位
    31. USART_InitStructure.USART_StopBits = USART_StopBits_1;
    32. // 配置校验位
    33. USART_InitStructure.USART_Parity = USART_Parity_No ;
    34. // 配置硬件流控制
    35. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    36. // 配置工作模式,收发一起
    37. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
    38. // 完成串口的初始化配置
    39. USART_Init(DEBUG_USARTx, &USART_InitStructure);
    40. // 使能串口
    41. USART_Cmd(DEBUG_USARTx, ENABLE);
    42. }
    43. /**
    44. * @brief 配置嵌套向量中断控制器NVIC
    45. * @param 无
    46. * @retval 无
    47. */
    48. static void NVIC_USART3_Configuration(void)
    49. {
    50. NVIC_InitTypeDef NVIC_InitStructure;//使能中断接收
    51. /* 嵌套向量中断控制器组选择 */
    52. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    53. /* 配置USART为中断源 */
    54. NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
    55. /* 抢断优先级*/
    56. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    57. /* 子优先级 */
    58. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    59. /* 使能中断 */
    60. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    61. /* 初始化配置NVIC */
    62. NVIC_Init(&NVIC_InitStructure);
    63. }
    64. /*
    65. PB10 :TXD
    66. PB11 : RXD
    67. */
    68. //串口IO初始化函数
    69. void USART3_Init(uint32_t baudrate)
    70. {
    71. GPIO_InitTypeDef GPIO_InitStructure; //IO端口的初始化
    72. USART_InitTypeDef USART_InitStructure; //串口的初始化
    73. RCC_APB2PeriphClockCmd(Ld3320_USART_GPIO_CLK, ENABLE); //使能IO端口的时钟
    74. RCC_APB1PeriphClockCmd(Ld3320_USART_CLK, ENABLE); //使能串口的时钟
    75. //发送
    76. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    77. GPIO_InitStructure.GPIO_Pin = Ld3320_USART_TX_GPIO_PIN; //发送引脚
    78. GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
    79. GPIO_Init(GPIOB, &GPIO_InitStructure);
    80. //接收
    81. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    82. GPIO_InitStructure.GPIO_Pin = Ld3320_USART_RX_GPIO_PIN; //接收引脚
    83. GPIO_InitStructure.GPIO_Speed= GPIO_Speed_50MHz;
    84. GPIO_Init(GPIOB,&GPIO_InitStructure);
    85. USART_InitStructure.USART_BaudRate = baudrate; //设置传输的波特率
    86. USART_InitStructure.USART_WordLength = USART_WordLength_8b; //设置传输一帧数据的数据位
    87. USART_InitStructure.USART_StopBits = USART_StopBits_1; //一位停止位
    88. USART_InitStructure.USART_Parity = USART_Parity_No; //无奇偶校验位
    89. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //能使接收的发送
    90. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //无硬件流控制
    91. USART_Init(Ld3320_USARTx,&USART_InitStructure);
    92. NVIC_USART3_Configuration();
    93. USART_ITConfig(Ld3320_USARTx,USART_IT_RXNE,ENABLE); //使能串口中断
    94. USART_Cmd(Ld3320_USARTx,ENABLE); //使能串口2
    95. }
    96. /*
    97. 函数名:USART3串口发送函数
    98. 功能: 发送数据
    99. 入口参数:发送的字符
    100. */
    101. void USART3_SendString(u8 *str)
    102. {
    103. u8 index=0;
    104. do
    105. {
    106. USART_SendData(USART3,str[index]); //逐一的发送数组中的内容
    107. while(USART_GetFlagStatus(USART3,USART_FLAG_TXE) == RESET); //判断是否发送完 发完为高电平
    108. index++;
    109. }
    110. while(str[index] != 0); //检查字符串结束标志
    111. }
    112. xUSATR_TypeDef xUSART; // 声明为全局变量,方便记录信息、状态
    113. // USART-1 //
    114. /
    115. /******************************************************************************
    116. * 函 数: vUSART1_Init
    117. * 功 能: 初始化USART1的GPIO、通信参数配置、中断优先级
    118. * (8位数据、无校验、1个停止位)
    119. * 参 数: uint32_t baudrate 通信波特率
    120. * 返回值: 无
    121. ******************************************************************************/
    122. void USART1_Init(uint32_t baudrate)
    123. {
    124. GPIO_InitTypeDef GPIO_InitStructure;
    125. NVIC_InitTypeDef NVIC_InitStructure;
    126. USART_InitTypeDef USART_InitStructure;
    127. // 时钟使能
    128. RCC->APB2ENR |= RCC_APB2ENR_USART1EN; // 使能USART1时钟
    129. RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能GPIOA时钟
    130. // GPIO_TX引脚配置
    131. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
    132. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    133. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // TX引脚工作模式:复用推挽
    134. GPIO_Init(GPIOA, &GPIO_InitStructure);
    135. // GPIO_RX引脚配置
    136. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    137. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // RX引脚工作模式:上拉输入; 如果使用浮空输入,引脚空置时可能产生误输入; 当电路上为一主多从电路时,可以使用复用开漏模式
    138. GPIO_Init(GPIOA, &GPIO_InitStructure);
    139. // 中断配置
    140. NVIC_InitStructure .NVIC_IRQChannel = USART1_IRQn;
    141. NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ; // 抢占优先级
    142. NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2; // 子优先级
    143. NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
    144. NVIC_Init(&NVIC_InitStructure);
    145. //USART 初始化设置
    146. USART_DeInit(USART1);
    147. USART_InitStructure.USART_BaudRate = baudrate; // 串口波特率
    148. USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    149. USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位
    150. USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位
    151. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    152. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能收、发模式
    153. USART_Init(USART1, &USART_InitStructure); // 初始化串口
    154. USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
    155. USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); // 使能接受中断
    156. USART_ITConfig(USART1, USART_IT_IDLE, ENABLE); // 使能空闲中断
    157. USART_Cmd(USART1, ENABLE); // 使能串口, 开始工作
    158. USART1->SR = ~(0x00F0); // 清理中断
    159. xUSART.USART1InitFlag = 1; // 标记初始化标志
    160. xUSART.USART1ReceivedNum = 0; // 接收字节数清零
    161. printf("\r\r\r=========== 魔女开发板 STM32F103 外设初始报告 ===========\r");
    162. printf("USART1初始化配置 接收中断、空闲中断, 发送中断\r");
    163. }
    164. /******************************************************************************
    165. * 函 数: USART1_IRQHandler
    166. * 功 能: USART1的接收中断、空闲中断、发送中断
    167. * 参 数: 无
    168. * 返回值: 无
    169. *
    170. ******************************************************************************/
    171. static uint8_t U1TxBuffer[256] ; // 用于中断发送:环形缓冲区,256个字节
    172. static uint8_t U1TxCounter = 0 ; // 用于中断发送:标记已发送的字节数(环形)
    173. static uint8_t U1TxCount = 0 ; // 用于中断发送:标记将要发送的字节数(环形)
    174. void USART1_IRQHandler(void)
    175. {
    176. static uint16_t cnt = 0; // 接收字节数累计:每一帧数据已接收到的字节数
    177. static uint8_t RxTemp[U1_RX_BUF_SIZE]; // 接收数据缓存数组:每新接收1个字节,先顺序存放到这里,当一帧接收完(发生空闲中断), 再转存到全局变量:xUSART.USARTxReceivedBuffer[xx]中;
    178. // 接收中断
    179. if (USART1->SR & (1 << 5)) // 检查RXNE(读数据寄存器非空标志位); RXNE中断清理方法:读DR时自动清理;
    180. {
    181. if ((cnt >= U1_RX_BUF_SIZE))//||(xUSART.USART1ReceivedFlag==1// 判断1: 当前帧已接收到的数据量,已满(缓存区), 为避免溢出,本包后面接收到的数据直接舍弃.
    182. {
    183. // 判断2: 如果之前接收好的数据包还没处理,就放弃新数据,即,新数据帧不能覆盖旧数据帧,直至旧数据帧被处理.缺点:数据传输过快于处理速度时会掉包;好处:机制清晰,易于调试
    184. USART1->DR; // 读取数据寄存器的数据,但不保存.主要作用:读DR时自动清理接收中断标志;
    185. return;
    186. }
    187. RxTemp[cnt++] = USART1->DR ; // 把新收到的字节数据,顺序存放到RXTemp数组中;注意:读取DR时自动清零中断位;
    188. }
    189. // 空闲中断, 用于配合接收中断,以判断一帧数据的接收完成
    190. if (USART1->SR & (1 << 4)) // 检查IDLE(空闲中断标志位); IDLE中断标志清理方法:序列清零,USART1 ->SR; USART1 ->DR;
    191. {
    192. xUSART.USART1ReceivedNum = 0; // 把接收到的数据字节数清0
    193. memcpy(xUSART.USART1ReceivedBuffer, RxTemp, U1_RX_BUF_SIZE); // 把本帧接收到的数据,存放到全局变量xUSART.USARTxReceivedBuffer中, 等待处理; 注意:复制的是整个数组,包括0值,以方便字符串数据
    194. xUSART.USART1ReceivedNum = cnt; // 把接收到的字节数,存放到全局变量xUSART.USARTxReceivedCNT中;
    195. cnt = 0; // 接收字节数累计器,清零; 准备下一次的接收
    196. memset(RxTemp, 0, U1_RX_BUF_SIZE); // 接收数据缓存数组,清零; 准备下一次的接收
    197. USART1 ->SR;
    198. USART1 ->DR; // 清零IDLE中断标志位!! 序列清零,顺序不能错!!
    199. }
    200. // 发送中断
    201. if ((USART1->SR & 1 << 7) && (USART1->CR1 & 1 << 7)) // 检查TXE(发送数据寄存器空)、TXEIE(发送缓冲区空中断使能)
    202. {
    203. USART1->DR = U1TxBuffer[U1TxCounter++]; // 读取数据寄存器值;注意:读取DR时自动清零中断位;
    204. if (U1TxCounter == U1TxCount)
    205. USART1->CR1 &= ~(1 << 7); // 已发送完成,关闭发送缓冲区空置中断 TXEIE
    206. }
    207. }
    208. /******************************************************************************
    209. * 函 数: vUSART1_GetBuffer
    210. * 功 能: 获取UART所接收到的数据
    211. * 参 数: uint8_t* buffer 数据存放缓存地址
    212. * uint8_t* cnt 接收到的字节数
    213. * 返回值: 0_没有接收到新数据, 非0_所接收到新数据的字节数
    214. ******************************************************************************/
    215. uint8_t USART1_GetBuffer(uint8_t *buffer, uint8_t *cnt)
    216. {
    217. if (xUSART.USART1ReceivedNum > 0) // 判断是否有新数据
    218. {
    219. memcpy(buffer, xUSART.USART1ReceivedBuffer, xUSART.USART1ReceivedNum); // 把新数据复制到指定位置
    220. *cnt = xUSART.USART1ReceivedNum; // 把新数据的字节数,存放指定变量
    221. xUSART.USART1ReceivedNum = 0; // 接收标记置0
    222. return *cnt; // 返回所接收到新数据的字节数
    223. }
    224. return 0; // 返回0, 表示没有接收到新数据
    225. }
    226. /******************************************************************************
    227. * 函 数: vUSART1_SendData
    228. * 功 能: UART通过中断发送数据,适合各种数据类型
    229. * 【适合场景】本函数可发送各种数据,而不限于字符串,如int,char
    230. * 【不 适 合】注意环形缓冲区容量256字节,如果发送频率太高,注意波特率
    231. * 参 数: uint8_t* buffer 需发送数据的首地址
    232. * uint8_t cnt 发送的字节数 ,限于中断发送的缓存区大小,不能大于256个字节
    233. * 返回值:
    234. ******************************************************************************/
    235. void USART1_SendData(uint8_t *buf, uint8_t cnt)
    236. {
    237. for (uint8_t i = 0; i < cnt; i++)
    238. U1TxBuffer[U1TxCount++] = buf[i];
    239. if ((USART1->CR1 & 1 << 7) == 0) // 检查发送缓冲区空置中断(TXEIE)是否已打开
    240. USART1->CR1 |= 1 << 7;
    241. }
    242. /******************************************************************************
    243. * 函 数: vUSART1_SendString
    244. * 功 能: UART通过中断发送输出字符串,无需输入数据长度
    245. * 【适合场景】字符串,长度<=256字节
    246. * 【不 适 合】int,float等数据类型
    247. * 参 数: char* stringTemp 需发送数据的缓存首地址
    248. * 返回值: 元
    249. ******************************************************************************/
    250. void USART1_SendString(char *stringTemp)
    251. {
    252. u16 num = 0; // 字符串长度
    253. char *t = stringTemp ; // 用于配合计算发送的数量
    254. while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    255. USART1_SendData((u8 *)stringTemp, num); // 注意调用函数所需要的真实数据长度; 如果目标需要以0作结尾判断,需num+1:字符串以0结尾,即多发一个:0
    256. }
    257. /******************************************************************************
    258. * 函 数: vUSART1_SendStringForDMA
    259. * 功 能: UART通过DMA发送数据,省了占用中断的时间
    260. * 【适合场景】字符串,字节数非常多,
    261. * 【不 适 合】1:只适合发送字符串,不适合发送可能含0的数值类数据; 2-时间间隔要足够
    262. * 参 数: char strintTemp 要发送的字符串首地址
    263. * 返回值: 无
    264. ******************************************************************************/
    265. void USART1_SendStringForDMA(char *stringTemp)
    266. {
    267. static u8 Flag_DmaTxInit = 0; // 用于标记是否已配置DMA发送
    268. u32 num = 0; // 发送的数量,注意发送的单位不是必须8位的
    269. char *t = stringTemp ; // 用于配合计算发送的数量
    270. while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    271. while (DMA1_Channel4->CNDTR > 0); // 重要:如果DMA还在进行上次发送,就等待; 得进完成中断清标志,F4不用这么麻烦,发送完后EN自动清零
    272. if (Flag_DmaTxInit == 0) // 是否已进行过USAART_TX的DMA传输配置
    273. {
    274. Flag_DmaTxInit = 1; // 设置标记,下次调用本函数就不再进行配置了
    275. USART1 ->CR3 |= 1 << 7; // 使能DMA发送
    276. RCC->AHBENR |= 1 << 0; // 开启DMA1时钟 [0]DMA1 [1]DMA2
    277. DMA1_Channel4->CCR = 0; // 失能, 清0整个寄存器, DMA必须失能才能配置
    278. DMA1_Channel4->CNDTR = num; // 传输数据量
    279. DMA1_Channel4->CMAR = (u32)stringTemp; // 存储器地址
    280. DMA1_Channel4->CPAR = (u32)&USART1->DR; // 外设地址
    281. DMA1_Channel4->CCR |= 1 << 4; // 数据传输方向 0:从外设读 1:从存储器读
    282. DMA1_Channel4->CCR |= 0 << 5; // 循环模式 0:不循环 1:循环
    283. DMA1_Channel4->CCR |= 0 << 6; // 外设地址非增量模式
    284. DMA1_Channel4->CCR |= 1 << 7; // 存储器增量模式
    285. DMA1_Channel4->CCR |= 0 << 8; // 外设数据宽度为8位
    286. DMA1_Channel4->CCR |= 0 << 10; // 存储器数据宽度8位
    287. DMA1_Channel4->CCR |= 0 << 12; // 中等优先级
    288. DMA1_Channel4->CCR |= 0 << 14; // 非存储器到存储器模式
    289. }
    290. DMA1_Channel4->CCR &= ~((u32)(1 << 0)); // 失能,DMA必须失能才能配置
    291. DMA1_Channel4->CNDTR = num; // 传输数据量
    292. DMA1_Channel4->CMAR = (u32)stringTemp; // 存储器地址
    293. DMA1_Channel4->CCR |= 1 << 0; // 开启DMA传输
    294. }
    295. // USART-2 //
    296. /
    297. /******************************************************************************
    298. * 函 数: vUSART2_Init
    299. * 功 能: 初始化USART的GPIO、通信参数配置、中断优先级
    300. * (8位数据、无校验、1个停止位)
    301. * 参 数: uint32_t baudrate 通信波特率
    302. * 返回值: 无
    303. ******************************************************************************/
    304. void USART2_Init(uint32_t baudrate)
    305. {
    306. GPIO_InitTypeDef GPIO_InitStructure;
    307. NVIC_InitTypeDef NVIC_InitStructure;
    308. USART_InitTypeDef USART_InitStructure;
    309. // 时钟使能
    310. RCC->APB1ENR |= RCC_APB1ENR_USART2EN; // 使能USART2时钟
    311. RCC->APB2ENR |= RCC_APB2ENR_IOPAEN; // 使能GPIOA时钟
    312. // GPIO_TX引脚配置
    313. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    314. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    315. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // TX引脚工作模式:复用推挽
    316. GPIO_Init(GPIOA, &GPIO_InitStructure);
    317. // GPIO_RX引脚配置
    318. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
    319. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // RX引脚工作模式:上拉输入; 如果使用浮空输入,引脚空置时可能产生误输入; 当电路上为一主多从电路时,可以使用复用开漏模式
    320. GPIO_Init(GPIOA, &GPIO_InitStructure);
    321. // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    322. // 中断配置
    323. NVIC_InitStructure .NVIC_IRQChannel = USART2_IRQn;
    324. NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ; // 抢占优先级
    325. NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2; // 子优先级
    326. NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
    327. NVIC_Init(&NVIC_InitStructure);
    328. //USART 初始化设置
    329. //USART_DeInit(USART2);
    330. USART_InitStructure.USART_BaudRate = baudrate; // 串口波特率
    331. USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    332. USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位
    333. USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位
    334. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    335. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能收、发模式
    336. USART_Init(USART2, &USART_InitStructure); // 初始化串口
    337. USART_ITConfig(USART2, USART_IT_TXE, DISABLE);
    338. USART_ITConfig(USART2, USART_IT_RXNE, ENABLE); // 使能接受中断
    339. USART_ITConfig(USART2, USART_IT_IDLE, ENABLE); // 使能空闲中断
    340. USART_Cmd(USART2, ENABLE); // 使能串口, 开始工作
    341. USART2->SR = ~(0x00F0); // 清理中断
    342. xUSART.USART2InitFlag = 1; // 标记初始化标志
    343. xUSART.USART2ReceivedNum = 0; // 接收字节数清零
    344. printf("\rUSART2初始化配置 接收中断、空闲中断, 发送中断\r");
    345. }
    346. /******************************************************************************
    347. * 函 数: USART2_IRQHandler
    348. * 功 能: USART2的接收中断、空闲中断、发送中断
    349. * 参 数: 无
    350. * 返回值: 无
    351. ******************************************************************************/
    352. static uint8_t U2TxBuffer[256] ; // 用于中断发送:环形缓冲区,256个字节
    353. static uint8_t U2TxCounter = 0 ; // 用于中断发送:标记已发送的字节数(环形)
    354. static uint8_t U2TxCount = 0 ; // 用于中断发送:标记将要发送的字节数(环形)
    355. void USART2_IRQHandler(void)
    356. {
    357. static uint16_t cnt = 0; // 接收字节数累计:每一帧数据已接收到的字节数
    358. static uint8_t RxTemp[U2_RX_BUF_SIZE]; // 接收数据缓存数组:每新接收1个字节,先顺序存放到这里,当一帧接收完(发生空闲中断), 再转存到全局变量:xUSART.USARTxReceivedBuffer[xx]中;
    359. // 接收中断
    360. if (USART2->SR & (1 << 5)) // 检查RXNE(读数据寄存器非空标志位); RXNE中断清理方法:读DR时自动清理;
    361. {
    362. if ((cnt >= U2_RX_BUF_SIZE))//||xUSART.USART2ReceivedFlag==1 // 判断1: 当前帧已接收到的数据量,已满(缓存区), 为避免溢出,本包后面接收到的数据直接舍弃.
    363. {
    364. // 判断2: 如果之前接收好的数据包还没处理,就放弃新数据,即,新数据帧不能覆盖旧数据帧,直至旧数据帧被处理.缺点:数据传输过快于处理速度时会掉包;好处:机制清晰,易于调试
    365. USART2->DR; // 读取数据寄存器的数据,但不保存.主要作用:读DR时自动清理接收中断标志;
    366. return;
    367. }
    368. RxTemp[cnt++] = USART2->DR ; // 把新收到的字节数据,顺序存放到RXTemp数组中;注意:读取DR时自动清零中断位;
    369. }
    370. // 空闲中断, 用于配合接收中断,以判断一帧数据的接收完成
    371. if (USART2->SR & (1 << 4)) // 检查IDLE(空闲中断标志位); IDLE中断标志清理方法:序列清零,USART1 ->SR; USART1 ->DR;
    372. {
    373. xUSART.USART2ReceivedNum = 0; // 把接收到的数据字节数清0
    374. memcpy(xUSART.USART2ReceivedBuffer, RxTemp, U2_RX_BUF_SIZE); // 把本帧接收到的数据,存放到全局变量xUSART.USARTxReceivedBuffer中, 等待处理; 注意:复制的是整个数组,包括0值,以方便字符串数据
    375. xUSART.USART2ReceivedNum = cnt; // 把接收到的字节数,存放到全局变量xUSART.USARTxReceivedCNT中;
    376. cnt = 0; // 接收字节数累计器,清零; 准备下一次的接收
    377. memset(RxTemp, 0, U2_RX_BUF_SIZE); // 接收数据缓存数组,清零; 准备下一次的接收
    378. USART2 ->SR;
    379. USART2 ->DR; // 清零IDLE中断标志位!! 序列清零,顺序不能错!!
    380. }
    381. // 发送中断
    382. if ((USART2->SR & 1 << 7) && (USART2->CR1 & 1 << 7)) // 检查TXE(发送数据寄存器空)、TXEIE(发送缓冲区空中断使能)
    383. {
    384. USART2->DR = U2TxBuffer[U2TxCounter++]; // 读取数据寄存器值;注意:读取DR时自动清零中断位;
    385. if (U2TxCounter == U2TxCount)
    386. USART2->CR1 &= ~(1 << 7); // 已发送完成,关闭发送缓冲区空置中断 TXEIE
    387. }
    388. }
    389. /******************************************************************************
    390. * 函 数: vUSART2_GetBuffer
    391. * 功 能: 获取UART所接收到的数据
    392. * 参 数: uint8_t* buffer 数据存放缓存地址
    393. * uint8_t* cnt 接收到的字节数
    394. * 返回值: 0_没有接收到新数据, 非0_所接收到新数据的字节数
    395. ******************************************************************************/
    396. uint8_t USART2_GetBuffer(uint8_t *buffer, uint8_t *cnt)
    397. {
    398. if (xUSART.USART2ReceivedNum > 0) // 判断是否有新数据
    399. {
    400. memcpy(buffer, xUSART.USART2ReceivedBuffer, xUSART.USART2ReceivedNum); // 把新数据复制到指定位置
    401. *cnt = xUSART.USART2ReceivedNum; // 把新数据的字节数,存放指定变量
    402. xUSART.USART2ReceivedNum = 0; // 接收标记置0
    403. return *cnt; // 返回所接收到新数据的字节数
    404. }
    405. return 0; // 返回0, 表示没有接收到新数据
    406. }
    407. /******************************************************************************
    408. * 函 数: vUSART2_SendData
    409. * 功 能: UART通过中断发送数据,适合各种数据类型
    410. * 【适合场景】本函数可发送各种数据,而不限于字符串,如int,char
    411. * 【不 适 合】注意环形缓冲区容量256字节,如果发送频率太高,注意波特率
    412. * 参 数: uint8_t* buffer 需发送数据的首地址
    413. * uint8_t cnt 发送的字节数 ,限于中断发送的缓存区大小,不能大于256个字节
    414. * 返回值:
    415. ******************************************************************************/
    416. void USART2_SendData(uint8_t *buf, uint8_t cnt)
    417. {
    418. for (uint8_t i = 0; i < cnt; i++)
    419. U2TxBuffer[U2TxCount++] = buf[i];
    420. if ((USART2->CR1 & 1 << 7) == 0) // 检查发送缓冲区空置中断(TXEIE)是否已打开
    421. USART2->CR1 |= 1 << 7;
    422. }
    423. /******************************************************************************
    424. * 函 数: vUSART2_SendString
    425. * 功 能: UART通过中断发送输出字符串,无需输入数据长度
    426. * 【适合场景】字符串,长度<=256字节
    427. * 【不 适 合】int,float等数据类型
    428. * 参 数: char* stringTemp 需发送数据的缓存首地址
    429. * 返回值: 元
    430. ******************************************************************************/
    431. void USART2_SendString(char *stringTemp)
    432. {
    433. u16 num = 0; // 字符串长度
    434. char *t = stringTemp ; // 用于配合计算发送的数量
    435. while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    436. USART2_SendData((u8 *)stringTemp, num); // 注意调用函数所需要的真实数据长度; 如果目标需要以0作结尾判断,需num+1:字符串以0结尾,即多发一个:0
    437. }
    438. /******************************************************************************
    439. * 函 数: USART3_IRQHandler
    440. * 功 能: USART的接收中断、空闲中断、发送中断
    441. * 参 数: 无
    442. * 返回值: 无
    443. ******************************************************************************/
    444. static uint8_t U3TxBuffer[256] ; // 用于中断发送:环形缓冲区,256个字节
    445. static uint8_t U3TxCounter = 0 ; // 用于中断发送:标记已发送的字节数(环形)
    446. static uint8_t U3TxCount = 0 ; // 用于中断发送:标记将要发送的字节数(环形)
    447. void USART3_SendData(uint8_t *buf, uint8_t cnt)
    448. {
    449. for (uint8_t i = 0; i < cnt; i++)
    450. U3TxBuffer[U3TxCount++] = buf[i];
    451. if ((USART3->CR1 & 1 << 7) == 0) // 检查发送缓冲区空置中断(TXEIE)是否已打开
    452. USART3->CR1 |= 1 << 7;
    453. }
    454. /******************************************************************************
    455. * 函 数: vUSART3_SendString
    456. * 功 能: UART通过中断发送输出字符串,无需输入数据长度
    457. * 【适合场景】字符串,长度<=256字节
    458. * 【不 适 合】int,float等数据类型
    459. * 参 数: char* stringTemp 需发送数据的缓存首地址
    460. * 返回值: 元
    461. ******************************************************************************/
    462. //void USART3_SendString(char *stringTemp)
    463. //{
    464. // u16 num = 0; // 字符串长度
    465. // char *t = stringTemp ; // 用于配合计算发送的数量
    466. // while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    467. // USART3_SendData((u8 *)stringTemp, num); // 注意调用函数所需要的真实数据长度; 如果目标需要以0作结尾判断,需num+1:字符串以0结尾,即多发一个:0
    468. //}
    469. #ifdef STM32F10X_HD // STM32F103R,及以上,才有UART4和UART5
    470. // UART-4 //
    471. /
    472. /******************************************************************************
    473. * 函 数: vUART4_Init
    474. * 功 能: 初始化USART的GPIO、通信参数配置、中断优先级
    475. * (8位数据、无校验、1个停止位)
    476. * 参 数: uint32_t baudrate 通信波特率
    477. * 返回值: 无
    478. ******************************************************************************/
    479. void UART4_Init(uint32_t baudrate)
    480. {
    481. GPIO_InitTypeDef GPIO_InitStructure;
    482. NVIC_InitTypeDef NVIC_InitStructure;
    483. USART_InitTypeDef USART_InitStructure;
    484. // 时钟使能
    485. RCC->APB1ENR |= RCC_APB1ENR_UART4EN; // 使能UART4时钟
    486. RCC->APB2ENR |= RCC_APB2ENR_IOPCEN; // 使能GPIOC时钟
    487. // GPIO_TX引脚配置
    488. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    489. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    490. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // TX引脚工作模式:复用推挽 GPIO_Init(GPIOC, &GPIO_InitStructure);
    491. GPIO_Init(GPIOC, &GPIO_InitStructure);
    492. // GPIO_RX引脚配置
    493. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
    494. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // RX引脚工作模式:上拉输入; 如果使用浮空输入,引脚空置时可能产生误输入; 当电路上为一主多从电路时,可以使用复用开漏模式
    495. GPIO_Init(GPIOC, &GPIO_InitStructure);
    496. // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    497. // 中断配置
    498. NVIC_InitStructure .NVIC_IRQChannel = UART4_IRQn;
    499. NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ; // 抢占优先级
    500. NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2; // 子优先级
    501. NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
    502. NVIC_Init(&NVIC_InitStructure);
    503. //USART 初始化设置
    504. USART_DeInit(UART4);
    505. USART_InitStructure.USART_BaudRate = baudrate; // 串口波特率
    506. USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    507. USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位
    508. USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位
    509. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    510. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能收、发模式
    511. USART_Init(UART4, &USART_InitStructure); // 初始化串口
    512. USART_ITConfig(UART4, USART_IT_TXE, DISABLE);
    513. USART_ITConfig(UART4, USART_IT_RXNE, ENABLE); // 使能接受中断
    514. USART_ITConfig(UART4, USART_IT_IDLE, ENABLE); // 使能空闲中断
    515. USART_Cmd(UART4, ENABLE); // 使能串口, 开始工作
    516. UART4->SR = ~(0x00F0); // 清理中断
    517. xUSART.UART4InitFlag = 1; // 标记初始化标志
    518. xUSART.UART4ReceivedNum = 0; // 接收字节数清零
    519. printf("\rUART4 初始化配置 接收中断、空闲中断, 发送中断\r");
    520. }
    521. /******************************************************************************
    522. * 函 数: UART4_IRQHandler
    523. * 功 能: USART2的接收中断、空闲中断、发送中断
    524. * 参 数: 无
    525. * 返回值: 无
    526. ******************************************************************************/
    527. static uint8_t U4TxBuffer[256] ; // 用于中断发送:环形缓冲区,256个字节
    528. static uint8_t U4TxCounter = 0 ; // 用于中断发送:标记已发送的字节数(环形)
    529. static uint8_t U4TxCount = 0 ; // 用于中断发送:标记将要发送的字节数(环形)
    530. void UART4_IRQHandler(void)
    531. {
    532. static uint16_t cnt = 0; // 接收字节数累计:每一帧数据已接收到的字节数
    533. static uint8_t RxTemp[U4_RX_BUF_SIZE]; // 接收数据缓存数组:每新接收1个字节,先顺序存放到这里,当一帧接收完(发生空闲中断), 再转存到全局变量:xUSART.USARTxReceivedBuffer[xx]中;
    534. // 接收中断
    535. if (UART4->SR & (1 << 5)) // 检查RXNE(读数据寄存器非空标志位); RXNE中断清理方法:读DR时自动清理;
    536. {
    537. if ((cnt >= U4_RX_BUF_SIZE))//||xUSART.UART4ReceivedFlag==1 // 判断1: 当前帧已接收到的数据量,已满(缓存区), 为避免溢出,本包后面接收到的数据直接舍弃.
    538. {
    539. // 判断2: 如果之前接收好的数据包还没处理,就放弃新数据,即,新数据帧不能覆盖旧数据帧,直至旧数据帧被处理.缺点:数据传输过快于处理速度时会掉包;好处:机制清晰,易于调试
    540. UART4->DR; // 读取数据寄存器的数据,但不保存.主要作用:读DR时自动清理接收中断标志;
    541. return;
    542. }
    543. RxTemp[cnt++] = UART4->DR ; // 把新收到的字节数据,顺序存放到RXTemp数组中;注意:读取DR时自动清零中断位;
    544. }
    545. // 空闲中断, 用于配合接收中断,以判断一帧数据的接收完成
    546. if (UART4->SR & (1 << 4)) // 检查IDLE(空闲中断标志位); IDLE中断标志清理方法:序列清零,USART1 ->SR; USART1 ->DR;
    547. {
    548. xUSART.UART4ReceivedNum = 0; // 把接收到的数据字节数清0
    549. memcpy(xUSART.UART4ReceivedBuffer, RxTemp, U4_RX_BUF_SIZE); // 把本帧接收到的数据,存放到全局变量xUSART.USARTxReceivedBuffer中, 等待处理; 注意:复制的是整个数组,包括0值,以方便字符串数据
    550. xUSART.UART4ReceivedNum = cnt; // 把接收到的字节数,存放到全局变量xUSART.USARTxReceivedCNT中;
    551. cnt = 0; // 接收字节数累计器,清零; 准备下一次的接收
    552. memset(RxTemp, 0, U4_RX_BUF_SIZE); // 接收数据缓存数组,清零; 准备下一次的接收
    553. UART4 ->SR;
    554. UART4 ->DR; // 清零IDLE中断标志位!! 序列清零,顺序不能错!!
    555. }
    556. // 发送中断
    557. if ((UART4->SR & 1 << 7) && (UART4->CR1 & 1 << 7)) // 检查TXE(发送数据寄存器空)、TXEIE(发送缓冲区空中断使能)
    558. {
    559. UART4->DR = U4TxBuffer[U4TxCounter++]; // 读取数据寄存器值;注意:读取DR时自动清零中断位;
    560. if (U4TxCounter == U4TxCount)
    561. UART4->CR1 &= ~(1 << 7); // 已发送完成,关闭发送缓冲区空置中断 TXEIE
    562. }
    563. }
    564. /******************************************************************************
    565. * 函 数: vUART4_GetBuffer
    566. * 功 能: 获取UART所接收到的数据
    567. * 参 数: uint8_t* buffer 数据存放缓存地址
    568. * uint8_t* cnt 接收到的字节数
    569. * 返回值: 0_没有接收到新数据, 非0_所接收到新数据的字节数
    570. ******************************************************************************/
    571. uint8_t UART4_GetBuffer(uint8_t *buffer, uint8_t *cnt)
    572. {
    573. if (xUSART.UART4ReceivedNum > 0) // 判断是否有新数据
    574. {
    575. memcpy(buffer, xUSART.UART4ReceivedBuffer, xUSART.UART4ReceivedNum); // 把新数据复制到指定位置
    576. *cnt = xUSART.UART4ReceivedNum; // 把新数据的字节数,存放指定变量
    577. xUSART.UART4ReceivedNum = 0; // 接收标记置0
    578. return *cnt; // 返回所接收到新数据的字节数
    579. }
    580. return 0; // 返回0, 表示没有接收到新数据
    581. }
    582. /******************************************************************************
    583. * 函 数: vUART4_SendData
    584. * 功 能: UART通过中断发送数据,适合各种数据类型
    585. * 【适合场景】本函数可发送各种数据,而不限于字符串,如int,char
    586. * 【不 适 合】注意环形缓冲区容量256字节,如果发送频率太高,注意波特率
    587. * 参 数: uint8_t* buffer 需发送数据的首地址
    588. * uint8_t cnt 发送的字节数 ,限于中断发送的缓存区大小,不能大于256个字节
    589. * 返回值:
    590. ******************************************************************************/
    591. void UART4_SendData(uint8_t *buf, uint8_t cnt)
    592. {
    593. for (uint8_t i = 0; i < cnt; i++)
    594. U4TxBuffer[U4TxCount++] = buf[i];
    595. if ((UART4->CR1 & 1 << 7) == 0) // 检查发送缓冲区空置中断(TXEIE)是否已打开
    596. UART4->CR1 |= 1 << 7;
    597. }
    598. /******************************************************************************
    599. * 函 数: vUART4_SendString
    600. * 功 能: UART通过中断发送输出字符串,无需输入数据长度
    601. * 【适合场景】字符串,长度<=256字节
    602. * 【不 适 合】int,float等数据类型
    603. * 参 数: char* stringTemp 需发送数据的缓存首地址
    604. * 返回值: 元
    605. ******************************************************************************/
    606. void UART4_SendString(char *stringTemp)
    607. {
    608. u16 num = 0; // 字符串长度
    609. char *t = stringTemp ; // 用于配合计算发送的数量
    610. while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    611. UART4_SendData((u8 *)stringTemp, num); // 调用函数完成发送,num+1:字符串以0结尾,需多发一个:0
    612. }
    613. // UART-4 //
    614. /
    615. /******************************************************************************
    616. * 函 数: vUART5_Init
    617. * 功 能: 初始化USART的GPIO、通信参数配置、中断优先级
    618. * (8位数据、无校验、1个停止位)
    619. * 参 数: uint32_t baudrate 通信波特率
    620. * 返回值: 无
    621. ******************************************************************************/
    622. void UART5_Init(uint32_t baudrate)
    623. {
    624. GPIO_InitTypeDef GPIO_InitStructure;
    625. NVIC_InitTypeDef NVIC_InitStructure;
    626. USART_InitTypeDef USART_InitStructure;
    627. // 时钟使能
    628. RCC->APB1ENR |= RCC_APB1ENR_UART5EN; // 使能UART5时钟
    629. RCC->APB2ENR |= RCC_APB2ENR_IOPDEN | RCC_APB2ENR_IOPCEN; // 使能GPIO时钟
    630. // GPIO_TX引脚配置
    631. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
    632. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    633. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // TX引脚工作模式:复用推挽
    634. GPIO_Init(GPIOC, &GPIO_InitStructure);
    635. // GPIO_RX引脚配置
    636. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2;
    637. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; // RX引脚工作模式:上拉输入; 如果使用浮空输入,引脚空置时可能产生误输入; 当电路上为一主多从电路时,可以使用复用开漏模式
    638. GPIO_Init(GPIOD, &GPIO_InitStructure);
    639. // NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    640. // 中断配置
    641. NVIC_InitStructure .NVIC_IRQChannel = UART5_IRQn;
    642. NVIC_InitStructure .NVIC_IRQChannelPreemptionPriority = 2 ; // 抢占优先级
    643. NVIC_InitStructure .NVIC_IRQChannelSubPriority = 2; // 子优先级
    644. NVIC_InitStructure .NVIC_IRQChannelCmd = ENABLE; // IRQ通道使能
    645. NVIC_Init(&NVIC_InitStructure);
    646. //USART 初始化设置
    647. USART_DeInit(UART5);
    648. USART_InitStructure.USART_BaudRate = baudrate; // 串口波特率
    649. USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 字长为8位数据格式
    650. USART_InitStructure.USART_StopBits = USART_StopBits_1; // 一个停止位
    651. USART_InitStructure.USART_Parity = USART_Parity_No; // 无奇偶校验位
    652. USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // 使能收、发模式
    653. USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
    654. USART_Init(UART5, &USART_InitStructure); // 初始化串口
    655. USART_ITConfig(UART5, USART_IT_TXE, DISABLE);
    656. USART_ITConfig(UART5, USART_IT_RXNE, ENABLE); // 使能接受中断
    657. USART_ITConfig(UART5, USART_IT_IDLE, ENABLE); // 使能空闲中断
    658. USART_Cmd(UART5, ENABLE); // 使能串口, 开始工作
    659. UART5->SR = ~(0x00F0); // 清理中断
    660. xUSART.UART5InitFlag = 1; // 标记初始化标志
    661. xUSART.UART5ReceivedNum = 0; // 接收字节数清零
    662. printf("\rUART5 初始化配置 接收中断、空闲中断, 发送中断\r");
    663. }
    664. /******************************************************************************
    665. * 函 数: UART5_IRQHandler
    666. * 功 能: USART2的接收中断、空闲中断、发送中断
    667. * 参 数: 无
    668. * 返回值: 无
    669. ******************************************************************************/
    670. static uint8_t U5TxBuffer[256] ; // 用于中断发送:环形缓冲区,256个字节
    671. static uint8_t U5TxCounter = 0 ; // 用于中断发送:标记已发送的字节数(环形)
    672. static uint8_t U5TxCount = 0 ; // 用于中断发送:标记将要发送的字节数(环形)
    673. void UART5_IRQHandler(void)
    674. {
    675. static uint16_t cnt = 0; // 接收字节数累计:每一帧数据已接收到的字节数
    676. static uint8_t RxTemp[U5_RX_BUF_SIZE]; // 接收数据缓存数组:每新接收1个字节,先顺序存放到这里,当一帧接收完(发生空闲中断), 再转存到全局变量:xUSART.USARTxReceivedBuffer[xx]中;
    677. // 接收中断
    678. if (UART5->SR & (1 << 5)) // 检查RXNE(读数据寄存器非空标志位); RXNE中断清理方法:读DR时自动清理;
    679. {
    680. if ((cnt >= U5_RX_BUF_SIZE))//||xUSART.UART5ReceivedFlag==1 // 判断1: 当前帧已接收到的数据量,已满(缓存区), 为避免溢出,本包后面接收到的数据直接舍弃.
    681. {
    682. // 判断2: 如果之前接收好的数据包还没处理,就放弃新数据,即,新数据帧不能覆盖旧数据帧,直至旧数据帧被处理.缺点:数据传输过快于处理速度时会掉包;好处:机制清晰,易于调试
    683. UART5->DR; // 读取数据寄存器的数据,但不保存.主要作用:读DR时自动清理接收中断标志;
    684. return;
    685. }
    686. RxTemp[cnt++] = UART5->DR ; // 把新收到的字节数据,顺序存放到RXTemp数组中;注意:读取DR时自动清零中断位;
    687. }
    688. // 空闲中断, 用于配合接收中断,以判断一帧数据的接收完成
    689. if (UART5->SR & (1 << 4)) // 检查IDLE(空闲中断标志位); IDLE中断标志清理方法:序列清零,USART1 ->SR; USART1 ->DR;
    690. {
    691. xUSART.UART5ReceivedNum = 0; // 把接收到的数据字节数清0
    692. memcpy(xUSART.UART5ReceivedBuffer, RxTemp, U5_RX_BUF_SIZE); // 把本帧接收到的数据,存放到全局变量xUSART.USARTxReceivedBuffer中, 等待处理; 注意:复制的是整个数组,包括0值,以方便字符串数据
    693. xUSART.UART5ReceivedNum = cnt; // 把接收到的字节数,存放到全局变量xUSART.USARTxReceivedCNT中;
    694. cnt = 0; // 接收字节数累计器,清零; 准备下一次的接收
    695. memset(RxTemp, 0, U5_RX_BUF_SIZE); // 接收数据缓存数组,清零; 准备下一次的接收
    696. UART5 ->SR;
    697. UART5 ->DR; // 清零IDLE中断标志位!! 序列清零,顺序不能错!!
    698. }
    699. // 发送中断
    700. if ((UART5->SR & 1 << 7) && (UART5->CR1 & 1 << 7)) // 检查TXE(发送数据寄存器空)、TXEIE(发送缓冲区空中断使能)
    701. {
    702. UART5->DR = U5TxBuffer[U5TxCounter++]; // 读取数据寄存器值;注意:读取DR时自动清零中断位;
    703. if (U5TxCounter == U5TxCount)
    704. UART5->CR1 &= ~(1 << 7); // 已发送完成,关闭发送缓冲区空置中断 TXEIE
    705. }
    706. }
    707. /******************************************************************************
    708. * 函 数: vUART5_GetBuffer
    709. * 功 能: 获取UART所接收到的数据
    710. * 参 数: uint8_t* buffer 数据存放缓存地址
    711. * uint8_t* cnt 接收到的字节数
    712. * 返回值: 0_没有接收到新数据, 非0_所接收到新数据的字节数
    713. ******************************************************************************/
    714. uint8_t UART5_GetBuffer(uint8_t *buffer, uint8_t *cnt)
    715. {
    716. if (xUSART.UART5ReceivedNum > 0) // 判断是否有新数据
    717. {
    718. memcpy(buffer, xUSART.UART5ReceivedBuffer, xUSART.UART5ReceivedNum); // 把新数据复制到指定位置
    719. *cnt = xUSART.UART5ReceivedNum; // 把新数据的字节数,存放指定变量
    720. xUSART.UART5ReceivedNum = 0; // 接收标记置0
    721. return *cnt; // 返回所接收到新数据的字节数
    722. }
    723. return 0; // 返回0, 表示没有接收到新数据
    724. }
    725. /******************************************************************************
    726. * 函 数: vUART5_SendData
    727. * 功 能: UART通过中断发送数据,适合各种数据类型
    728. * 【适合场景】本函数可发送各种数据,而不限于字符串,如int,char
    729. * 【不 适 合】注意环形缓冲区容量256字节,如果发送频率太高,注意波特率
    730. * 参 数: uint8_t* buffer 需发送数据的首地址
    731. * uint8_t cnt 发送的字节数 ,限于中断发送的缓存区大小,不能大于256个字节
    732. * 返回值:
    733. ******************************************************************************/
    734. void UART5_SendData(uint8_t *buf, uint8_t cnt)
    735. {
    736. for (uint8_t i = 0; i < cnt; i++)
    737. U5TxBuffer[U5TxCount++] = buf[i];
    738. if ((UART5->CR1 & 1 << 7) == 0) // 检查发送缓冲区空置中断(TXEIE)是否已打开
    739. UART5->CR1 |= 1 << 7;
    740. }
    741. /******************************************************************************
    742. * 函 数: vUART5_SendString
    743. * 功 能: UART通过中断发送输出字符串,无需输入数据长度
    744. * 【适合场景】字符串,长度<=256字节
    745. * 【不 适 合】int,float等数据类型
    746. * 参 数: char* stringTemp 需发送数据的缓存首地址
    747. * 返回值: 元
    748. ******************************************************************************/
    749. void UART5_SendString(char *stringTemp)
    750. {
    751. u16 num = 0; // 字符串长度
    752. char *t = stringTemp ; // 用于配合计算发送的数量
    753. while (*t++ != 0) num++; // 计算要发送的数目,这步比较耗时,测试发现每多6个字节,增加1us,单位:8位
    754. UART5_SendData((u8 *)stringTemp, num); // 注意调用函数所需要的真实数据长度; 如果目标需要以0作结尾判断,需num+1:字符串以0结尾,即多发一个:0
    755. }
    756. #endif
    757. // printf //
    758. /******************************************************************************
    759. * 功 能: printf函数支持代码
    760. * 【特别注意】加入以下代码, 使用printf函数时, 不再需要选择use MicroLIB
    761. * 参 数:
    762. * 返回值:
    763. * 备 注: 最后修改_2020年07月15日
    764. ******************************************************************************/
    765. //加入以下代码,支持printf函数,而不需要选择use MicroLIB
    766. //#pragma import(__use_no_semihosting)
    767. //struct __FILE
    768. //{
    769. // int handle;
    770. //}; // 标准库需要的支持函数
    771. //FILE __stdout; // FILE 在stdio.h文件
    772. void _sys_exit(int x)
    773. {
    774. x = x; // 定义_sys_exit()以避免使用半主机模式
    775. }
    776. //重定向 c 库函数 printf 到串口,重定向后可使用 printf 函数
    777. int fputc(int ch, FILE *f)
    778. { /* 发送一个字节数据到串口 */
    779. USART_SendData(DEBUG_USARTx, (uint8_t) ch);
    780. /* 等待发送完毕 */
    781. while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_TXE) == RESET);
    782. return (ch);
    783. }
    784. ///重定向 c 库函数 scanf 到串口,重写向后可使用 scanf、getchar 等函数
    785. int fgetc(FILE *f)
    786. {
    787. /* 等待串口输入数据 */
    788. while (USART_GetFlagStatus(DEBUG_USARTx, USART_FLAG_RXNE) == RESET);
    789. return (int)USART_ReceiveData(DEBUG_USARTx);
    790. }
    791. ///*
    792. //函数名:USART3中断服务函数
    793. //功能: 接收数据
    794. //注意:接收数据长度可调:RXCOUNT
    795. //*/
    796. //void USART3_IRQHandler(void)
    797. //{
    798. // u8 temp;
    799. //
    800. // if(USART_GetITStatus(USART3, USART_IT_RXNE) != RESET)
    801. // {
    802. // USART_ClearITPendingBit(USART3,USART_IT_RXNE);
    803. // temp = USART_ReceiveData(USART3);
    804. // if(temp == '\n' || RXCOUNT == 20) //判断是否接收到一个完整字符
    805. // {
    806. // RXCOUNT = 0;
    807. // RXOVER =1; //接收数据完成标志位置1
    808. // USART_ITConfig(USART3,USART_IT_RXNE,DISABLE);//失能串口接收中断标志
    809. // }
    810. // else
    811. // {
    812. // RXBUF[RXCOUNT] = temp; //依次存放到数组中
    813. // RXCOUNT++; //字符长度变化
    814. // }
    815. // }
    816. //}

    main.c

    1. /**
    2. ******************************************************************************
    3. * @file main.c
    4. * @author fire
    5. * @version V1.0
    6. * @date 2013-xx-xx
    7. * @brief rtc 测试,显示时间格式为: xx:xx:xx
    8. ******************************************************************************
    9. * @attention
    10. *
    11. * 实验平台:野火 F103-指南者 STM32 开发板
    12. * 论坛 :http://www.firebbs.cn
    13. * 淘宝 :https://fire-stm32.taobao.com
    14. *
    15. ******************************************************************************
    16. */
    17. #include "stm32f10x.h"
    18. #include "./usart/bsp_usart.h"
    19. #include "./rtc/bsp_rtc.h"
    20. #include "./lcd/bsp_ili9341_lcd.h"
    21. #include "./key/bsp_key.h"
    22. #include "./DTH11/DTH11.h"
    23. #include "./Led/bsp_led.h"
    24. #include "./syn6288/syn6288.h"
    25. //变量声明
    26. u8 RXBUF[20]; //串口存储数组
    27. u8 RXOVER=0; //串口接收标志位
    28. u8 RXCOUNT=0; //串口计数变量
    29. u8 i; //清空数组变量
    30. //时间更新函数
    31. void Update_FrameShow (void);
    32. //表盘框架绘制
    33. void DrawFixed_Frame (void);
    34. void DrawExcel (void);
    35. void DrawCongratulate (void);
    36. void DrawTimeFrame (void);
    37. void DrawExternal_Environmentz (void);
    38. void DrawWish (void);
    39. //语音处理函数
    40. void USART_Deal (void);
    41. // N = 2^32/365/24/60/60 = 136 年
    42. /*时间结构体,默认时间2024-03-02 03:20:10*/
    43. struct rtc_time systmtime=
    44. {
    45. 10,20,3,1,2,2024,4
    46. };
    47. extern __IO uint32_t TimeDisplay ;
    48. //温度参数
    49. /**
    50. * @brief 主函数
    51. * @param 无
    52. * @retval 无
    53. */
    54. int main()
    55. {
    56. //可使用该宏设置是否使用液晶显示
    57. #ifdef USE_LCD_DISPLAY
    58. ILI9341_Init (); //LCD 初始化
    59. LCD_SetFont(&Font8x16);
    60. LCD_SetColors(CurrentTextColor,CurrentBackColor);
    61. ILI9341_Clear(0,0,LCD_X_LENGTH,LCD_Y_LENGTH); /* 清屏,显示全黑 */
    62. DrawFixed_Frame();//绘制固定物
    63. #endif
    64. //串口部分
    65. USART_Config();
    66. LED_Configuration();//LED配置
    67. SYN6288_Init(USART2); // 初始化; USART2-PA2
    68. USART3_Init(9600); //LD3320串口初始化
    69. Key_GPIO_Config();
    70. /* 配置RTC秒中断优先级 */
    71. RTC_NVIC_Config();
    72. RTC_CheckAndConfig(&systmtime);
    73. DHT11_Init(); //初始化温度传感器引脚
    74. SYN6288_Say("已开灯");//Syn6288测试
    75. //Temperuture_Get();
    76. while (1)
    77. {
    78. /* 每过1s 更新一次时间*/
    79. if (TimeDisplay == 1)
    80. {
    81. /* 当前时间 */
    82. Time_Display( RTC_GetCounter(),&systmtime);
    83. //Time_Display1( RTC_GetCounter(),Temperature_Get(),&systmtime); //当加入温度获取时,温度获取
    84. TimeDisplay = 0;
    85. }
    86. //按下按键,通过串口修改时间
    87. if( Key_Scan(KEY1_GPIO_PORT,KEY1_GPIO_PIN) == KEY_ON )
    88. {
    89. struct rtc_time set_time;
    90. /*使用串口接收设置的时间,输入数字时注意末尾要加回车*/
    91. Time_Regulate_Get(&set_time);
    92. /*用接收到的时间设置RTC*/
    93. Time_Adjust(&set_time);
    94. //向备份寄存器写入标志
    95. BKP_WriteBackupRegister(RTC_BKP_DRX, RTC_BKP_DATA);
    96. }
    97. USART_Deal();
    98. }
    99. }
    100. /**************************************表盘框架绘制*****************************************/
    101. /*
    102. 函数功能: 绘制所有固定物
    103. */
    104. void DrawFixed_Frame(void)
    105. {
    106. DrawExcel();
    107. DrawCongratulate();
    108. DrawTimeFrame();
    109. DrawExternal_Environmentz();
    110. DrawWish();
    111. }
    112. /*
    113. 函数功能: 绘制表格
    114. */
    115. void DrawExcel(void)
    116. {
    117. ILI9341_DrawRectangle ( 0, 0, 240, 320, 0);
    118. ILI9341_DrawLine(0,136,50,136);
    119. ILI9341_DrawLine(185,136,240,136);
    120. ILI9341_DrawLine(0,180,240,180);
    121. ILI9341_DrawLine(0,200,240,200);
    122. ILI9341_DrawLine(48,200,48,320);
    123. ILI9341_DrawLine(240-48,200,240-48,320);
    124. }
    125. /*
    126. 函数功能: 绘制时钟表盘框架
    127. */
    128. void DrawTimeFrame(void)
    129. {
    130. uint8_t i;
    131. ILI9341_DrawCircle(RoundCenter_X,RoundCenter_Y,RoundRadius,0);//画外圆
    132. ILI9341_DrawCircle(RoundCenter_X,RoundCenter_Y,RoundCenter,1); //画中心圆
    133. //画刻度
    134. for(i=0;i<60;i++)
    135. {
    136. if(i%5==0)
    137. {//绘制圆大间距
    138. ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,6*i,RoundRadius-6,RoundRadius,RoundInterval_Color);
    139. }
    140. else
    141. {//绘制圆小间距
    142. ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,6*i,RoundRadius-3,RoundRadius,RoundInterval_Color);
    143. }
    144. }
    145. //OLED_WriteGRAM(); //刷新数据到OLED屏幕
    146. }
    147. /*
    148. 函数功能: 绘制龙年大吉
    149. */
    150. void DrawCongratulate(void)
    151. {
    152. ILI9341_DisplayStringEx(10,10,32,32,(uint8_t *)"龙",0);
    153. ILI9341_DisplayStringEx(240-32-10,10,32,32,(uint8_t *)"年",0);
    154. ILI9341_DisplayStringEx(10,3*32,32,32,(uint8_t *)"大",0);
    155. ILI9341_DisplayStringEx(240-32-10,3*32,32,32,(uint8_t *)"吉",0);
    156. }
    157. /*
    158. 函数功能: 绘制外部环境
    159. */
    160. void DrawExternal_Environmentz(void)
    161. {
    162. ILI9341_DisplayStringEx(20,144,16,16,(uint8_t *)"天气:多云",0);//也可后续添加天气检测设备配置
    163. ILI9341_DisplayStringEx(120,144,16,16,(uint8_t *)"温度:",0);//其他添加可仿照温度配置
    164. ILI9341_DisplayStringEx(20,160,16,16,(uint8_t *)"位置:贵阳",0);//也可后续添加定位设备配置
    165. ILI9341_DisplayStringEx(120,160,16,16,(uint8_t *)"湿度:",0);//也可后续添加空气检测设备配置
    166. }
    167. /*
    168. 函数功能: 绘制祝愿
    169. */
    170. void DrawWish(void)
    171. {
    172. ILI9341_DisplayStringEx(12,210,24,24,(uint8_t *)"宜",0);
    173. ILI9341_DisplayStringEx(204,210,24,24,(uint8_t *)"忌",0);
    174. ILI9341_DisplayStringEx_YDir(8,240,16,16,(uint8_t *)"搞钱",0);
    175. ILI9341_DisplayStringEx_YDir(28,240,16,16,(uint8_t *)"毕业设计",0);
    176. ILI9341_DisplayStringEx_YDir(200,240,16,16,(uint8_t *)"晚睡晚起",0);
    177. ILI9341_DisplayStringEx_YDir(220,240,16,16,(uint8_t *)"打游戏",0);
    178. ILI9341_DisplayStringEx(52,210,24,24,(uint8_t *)"等待开发",0);
    179. }
    180. /**************************************表盘框架绘制结束*****************************************/
    181. /*
    182. 函数功能: 更新时间框架显示,在RTC中断里调用
    183. */
    184. void Update_FrameShow(void)
    185. {
    186. /*1. 绘制秒针、分针、时针*/
    187. //画秒针
    188. ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_sec*6-6-90,RoundCenter,RoundSecondHand,0);//清除之前的秒针
    189. ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_sec*6-90,RoundCenter,RoundSecondHand,RoundSecondHand_Color);
    190. //画分针
    191. ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_min*6-6-90,RoundCenter,RoundMiuiteHand,0);
    192. ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_min*6-90,RoundCenter,RoundMiuiteHand,RoundMiuiteHand_Color);
    193. //画时针
    194. ILI9341_DrawAngleLine2(RoundCenter_X,RoundCenter_Y,systmtime.tm_hour*30-30-90,RoundCenter,RoundHourHand,0);
    195. ILI9341_DrawAngleLine(RoundCenter_X,RoundCenter_Y,systmtime.tm_hour*30-90,RoundCenter,RoundHourHand,RoundHourHand_Color);
    196. }
    197. /***********************************END OF FILE*********************************/
    198. //串口处理函数
    199. void USART_Deal(void)
    200. {
    201. if(RXOVER)
    202. {
    203. RXOVER = 0; //清除接收标志位
    204. switch(RXBUF[0]-48)
    205. {
    206. case 1:GPIO_ResetBits(GPIOB,GPIO_Pin_0); //点亮小灯
    207. SYN6288_Say("已开灯");
    208. break;
    209. case 2:GPIO_SetBits(GPIOB,GPIO_Pin_0); //熄灭小灯
    210. SYN6288_Say("已关灯");
    211. break;
    212. default: break;
    213. }
    214. USART3_SendString(RXBUF); //发送给pc机上面打印显示
    215. for(i=0;i<20;i++) //将已接收数据的数组清空:共20个字符长度
    216. {
    217. RXBUF[i] = 0; //重置数据缓存区
    218. }
    219. USART_ITConfig(USART3,USART_IT_RXNE,ENABLE);//始能串口接收
    220. }
    221. }

    液晶显示指针式时钟核心代码在上文已经放出,本文核心代码如上,本人撰写代码也需要时间,如需要全部代码或者仅需语音部分代码请私信我,感谢大家理解。

  • 相关阅读:
    Linux命令系列之ls——原来最简单的ls这么复杂
    (免费分享)基于springboot,vue公司财务系统
    《洛谷深入浅出基础篇》——P3405 citis and state ——哈希表
    聊聊 Nacos
    网工内推 | 金融业,网络管理岗,CCIE优先,最高30k
    【python实战】朋友因股票亏了,很惨常愤恨不平,当天我就分析出原因:怎么做到的?(听说关注我的人会暴富)
    [计算机网络基础]物理层详解
    二手闲置物品交易数据快照
    Debezium系列之:基于wal2json_streaming插件实时处理postgresql数据库超大数据
    Python-ONNX 相关
  • 原文地址:https://blog.csdn.net/C_say_easy_to_me/article/details/136347860