[其他ST产品] STM32F429/GD32F450液晶RGBLCD驱动代码

[复制链接]
1691|4
 楼主| t60yz 发表于 2021-11-30 23:56 | 显示全部楼层 |阅读模式

使用这段代码还需要使用SDRAM模块

工程代码可以参考正点原子的例程

LCD.h

  1. #ifndef __LCD_H
  2. #define __LCD_H               
  3. #include "sys.h"         
  4. #include "stdlib.h"  
  5. #include "delay.h"

  6. //LCD重要参数集
  7. typedef struct  
  8. {                          
  9.         uint16_t width;                        //LCD 宽度
  10.         uint16_t height;                        //LCD 高度
  11.         uint16_t id;                                //LCD ID
  12.         uint8_t  dir;                        //横屏还是竖屏控制:0,竖屏;1,横屏。       
  13.         uint16_t        wramcmd;                //开始写gram指令
  14.         uint16_t setxcmd;                //设置x坐标指令
  15.         uint16_t setycmd;                //设置y坐标指令
  16. }_lcd_dev;           

  17. //LCD参数
  18. extern _lcd_dev lcddev;        //管理LCD重要参数
  19. //LCD的画笔颜色和背景色          
  20. #define DEFAULT_POINT_COLOR   YELLOW;   //默认画笔颜色
  21. #define DEFAULT_BACK_COLOR    BLACK;    //默认背景颜色
  22. extern uint32_t  PointColor;//画笔颜色,默认黄色   
  23. extern uint32_t  BackColor; //背景颜色,默认为黑色

  24. //                      
  25. //LCD地址结构体
  26. typedef struct
  27. {
  28.         vuint16_t LCD_REG;
  29.         vuint16_t LCD_RAM;
  30. } LCD_TypeDef;
  31. //使用NOR/SRAM的 Bank1.sector4,地址位HADDR[27,26]=11 A18作为数据命令区分线
  32. //注意设置时STM32内部会右移一位对其!                              
  33. #define LCD_BASE        ((uint32_t)(0x60000000 | 0x0007FFFE))
  34. #define LCD             ((LCD_TypeDef *) LCD_BASE)
  35. //
  36.          
  37. //扫描方向定义
  38. #define L2R_U2D  0                 //从左到右,从上到下
  39. #define L2R_D2U  1                 //从左到右,从下到上
  40. #define R2L_U2D  2                 //从右到左,从上到下
  41. #define R2L_D2U  3                 //从右到左,从下到上

  42. #define U2D_L2R  4                 //从上到下,从左到右
  43. #define U2D_R2L  5                 //从上到下,从右到左
  44. #define D2U_L2R  6                 //从下到上,从左到右
  45. #define D2U_R2L  7                //从下到上,从右到左         

  46. #define DFT_SCAN_DIR  L2R_U2D  //默认的扫描方向

  47. //颜色
  48. #define WHITE                  0x0000FFFF //白色
  49. #define BLACK                  0x00000000        //黑色
  50. #define BLUE                  0x0000001F //蓝色
  51. #define RED                    0x0000F800 //红色
  52. #define GREEN                  0x000007E0 //绿色
  53. #define YELLOW                 0x0000FFE0 //黄色
  54. #define BROWN                          0X0000BC40 //棕色
  55. #define BRRED                          0X0000FC07 //棕红色
  56. #define GRAY                           0X00008430 //灰色

  57. //左右屏
  58. #define LEFT      0
  59. #define RIGHT     1
  60.                                                                                                                                       
  61. void LCD_Init(void);                                                                                                                   //初始化
  62. void LCD_DisplayOn(void);                                                                                                        //开显示
  63. void LCD_DisplayOff(void);                                                                                                        //关显示
  64. void LCD_BlackLightOn(void);                                                                        //点亮背光
  65. void LCD_BlackLightOff(void);                                                                   //熄灭背光
  66. void LCD_Clear(uint32_t Color);                                                                                                         //清屏
  67. void LCD_DrawPoint(uint16_t x,uint16_t y);                                                                                        //画点
  68. void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color);                                                                //快速画点
  69. uint32_t  LCD_ReadPoint(uint16_t x,uint16_t y);                                                                                         //读点
  70. void LCD_Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r);                                                                         //画圆
  71. void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);                                                        //画线
  72. void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);                                                   //画矩形
  73. void LCD_DrawCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2);     //画矩形复选框
  74. void LCD_FillCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint32_t color); //填充复选框
  75. void LCD_DrawTriangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y);  //画三角形
  76. void LCD_DrawTriangleRE(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y);//画反向三角形
  77. void LCD_DrawHistogram(uint16_t x,uint16_t y,uint16_t w);                                  //画柱形图
  78. void LCD_FillHistogram(uint16_t x,uint16_t y,uint16_t w,uint16_t value,uint16_t range);              //填充柱形图
  79. void LCD_DrawHistogramLimit(uint16_t x,uint16_t y,uint16_t w,uint16_t limit,uint16_t range);         //画柱状图上限值线
  80. void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color);                                                   //填充单色
  81. void LCD_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color);                                //填充指定颜色
  82. void LCD_ShowChar(uint16_t x,uint16_t y,char num,uint8_t size,uint8_t mode);                                        //显示一个字符
  83. void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,volatile char *p);                //显示一个字符串,12/16字体
  84. void Show_Font(uint16_t x,uint16_t y,uint8_t size,const volatile char *p, uint8_t mode);                 //显示一个汉字
  85. void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t width,uint16_t heigth, const uint8_t *data,uint8_t mode);   //显示一个单色位图
  86. void LCD_ShowText(uint16_t x,uint16_t y,uint16_t width,uint16_t height,volatile char*str,uint8_t size,uint8_t mode); //显示文本(带汉字)
  87. char* FloatAsc2Right(float value, uint8_t dot);                                                                //把浮点数转换成字符串(右对齐)  
  88. char* FloatAsc2Left(float value, uint8_t dot);                                     //把浮点数转换成字符串(左对齐)
  89. void LCD_WriteReg(uint16_t LCD_Reg, uint16_t LCD_RegValue);
  90. uint16_t  LCD_ReadReg(uint16_t LCD_Reg);
  91. void LCD_WriteRAM_Prepare(void);
  92. void LCD_WriteRAM(uint16_t RGB_Code);
  93. void LCD_Display_Dir(uint8_t dir);                                                                //设置屏幕显示方向
  94. void LCD_Set_Window(uint16_t sx,uint16_t sy,uint16_t width,uint16_t height);        //设置窗口                                                                                                                                                                                                                                                       
  95. //LCD分辨率设置
  96. #define LCD_HOR_RESOLUTION                640                //LCD水平分辨率
  97. #define LCD_VER_RESOLUTION                480                //LCD垂直分辨率
  98. //LCD驱动参数设置
  99. #define LCD_HOR_PULSE_WIDTH                1                //水平脉宽
  100. #define LCD_HOR_BACK_PORCH                144                //水平后廊
  101. #define LCD_HOR_FRONT_PORCH                16                //水平前廊

  102. #define LCD_VER_PULSE_WIDTH                1                //垂直脉宽
  103. #define LCD_VER_BACK_PORCH                35                //垂直后廊
  104. #define LCD_VER_FRONT_PORCH                10                //垂直前廊
  105. //如下几个参数,自动计算
  106. #define LCD_HT        (LCD_HOR_RESOLUTION+LCD_HOR_BACK_PORCH+LCD_HOR_FRONT_PORCH)
  107. #define LCD_HPS        (LCD_HOR_BACK_PORCH)
  108. #define LCD_VT         (LCD_VER_RESOLUTION+LCD_VER_BACK_PORCH+LCD_VER_FRONT_PORCH)
  109. #define LCD_VPS (LCD_VER_BACK_PORCH)

  110. #endif  



 楼主| t60yz 发表于 2021-11-30 23:57 | 显示全部楼层
LCD.c

  1. #include "lcd.h"
  2. #include "stdlib.h"
  3. #include "font.h"
  4. #include "usart.h"         
  5. #include "delay.h"         
  6. #include "ltdc.h"

  7. /** \addtogroup lcd_group 液晶显示模块 */

  8. /*@{*/

  9. //LCD的画笔颜色和背景色          
  10. uint32_t PointColor=DEFAULT_POINT_COLOR;         //画笔颜色
  11. uint32_t BackColor =DEFAULT_BACK_COLOR;   //背景色
  12. //管理LCD重要参数
  13. //默认为竖屏
  14. _lcd_dev lcddev;
  15. /**
  16. * \brief      函数功能:写寄存器函数
  17. *            
  18. * \param[in]  regval:寄存器值
  19. *            
  20. * \return   
  21. *            
  22. */         
  23. void LCD_WR_REG(vuint16_t regval)
  24. {   
  25.         regval=regval;                //使用-O2优化的时候,必须插入的延时
  26.         LCD->LCD_REG=regval;//写入要写的寄存器序号         
  27. }
  28. /**
  29. * \brief      函数功能:写LCD数据
  30. *            
  31. * \param[in]  data:要写入的值
  32. *            
  33. * \return   
  34. *            
  35. */
  36. void LCD_WR_DATA(vuint16_t data)
  37. {          
  38.         data=data;                        //使用-O2优化的时候,必须插入的延时
  39.         LCD->LCD_RAM=data;                 
  40. }
  41. /**
  42. * \brief      函数功能:读LCD数据
  43. *            
  44. * \param[in]  
  45. *            
  46. * \return     读到的值
  47. *            
  48. */
  49. uint16_t LCD_RD_DATA(void)
  50. {
  51.         vuint16_t ram;                        //防止被优化
  52.         ram=LCD->LCD_RAM;       
  53.         return ram;         
  54. }       
  55. /**
  56. * \brief      函数功能:写寄存器
  57. *            
  58. * \param[in]  LCD_Reg:寄存器地址
  59. *             LCD_RegValue:要写入的数据
  60. * \return   
  61. *            
  62. */
  63. void LCD_WriteReg(uint16_t LCD_Reg,uint16_t LCD_RegValue)
  64. {       
  65.         LCD->LCD_REG = LCD_Reg;                //写入要写的寄存器序号         
  66.         LCD->LCD_RAM = LCD_RegValue;//写入数据                             
  67. }          
  68. /**
  69. * \brief      函数功能:读寄存器
  70. *            
  71. * \param[in]  LCD_Reg:寄存器地址
  72. *            
  73. * \return   读到的数据
  74. *            
  75. */
  76. uint16_t LCD_ReadReg(uint16_t LCD_Reg)
  77. {                                                                                  
  78.         LCD_WR_REG(LCD_Reg);                //写入要读的寄存器序号
  79.         delay_us(5);                  
  80.         return LCD_RD_DATA();                //返回读到的值
  81. }   
  82. /**
  83. * \brief      函数功能:开始写GRAM
  84. *            
  85. * \param[in]  
  86. *            
  87. * \return   
  88. *            
  89. */
  90. void LCD_WriteRAM_Prepare(void)
  91. {
  92.         LCD->LCD_REG=lcddev.wramcmd;          
  93. }       
  94. /**
  95. * \brief      函数功能:LCD写GRAM
  96. *            
  97. * \param[in]  RGB_Code:颜色值
  98. *            
  99. * \return   
  100. *            
  101. */
  102. void LCD_WriteRAM(uint16_t RGB_Code)
  103. {                                                            
  104.         LCD->LCD_RAM = RGB_Code;//写十六位GRAM
  105. }
  106. /**
  107. * \brief      函数功能:当mdk -O1时间优化时需要设置
  108. *            
  109. * \param[in]  i:延时
  110. *            
  111. * \return   
  112. *            
  113. */
  114. void opt_delay(uint8_t i)
  115. {
  116.         while(i--);
  117. }
  118. /**
  119. * \brief      函数功能:读取个某点的颜色值
  120. *            
  121. * \param[in]  x,y:坐标
  122. *            
  123. * \return     此点的颜色
  124. *            
  125. */
  126. uint32_t LCD_ReadPoint(uint16_t x,uint16_t y)
  127. {
  128.         if(x>=lcddev.width||y>=lcddev.height)return 0;        //超过了范围,直接返回
  129.        
  130.         return LTDC_Read_Point(x,y);
  131. }       
  132. /**
  133. * \brief      函数功能:LCD开启显示
  134. *            
  135. * \param[in]  
  136. *            
  137. * \return   
  138. *            
  139. */
  140. void LCD_DisplayOn(void)
  141. {                                          
  142.         LTDC_Switch(1);//开启LCD
  143. }       
  144. /**
  145. * \brief      函数功能:LCD关闭显示
  146. *            
  147. * \param[in]  
  148. *            
  149. * \return   
  150. *            
  151. */
  152. void LCD_DisplayOff(void)
  153. {          
  154.         LTDC_Switch(0);//关闭LCD
  155. }
  156. /**
  157. * \brief      函数功能:点亮LCD背光
  158. *            
  159. * \param[in]  
  160. *            
  161. * \return   
  162. *            
  163. */
  164. void LCD_BlackLightOn(void)
  165. {
  166.         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_SET);
  167. }       
  168. /**
  169. * \brief      函数功能:熄灭LCD背光
  170. *            
  171. * \param[in]  
  172. *            
  173. * \return   
  174. *            
  175. */
  176. void LCD_BlackLightOff(void)
  177. {
  178.         HAL_GPIO_WritePin(GPIOB,GPIO_PIN_15,GPIO_PIN_RESET);
  179. }
  180. /**
  181. * \brief      函数功能:画点
  182. *            
  183. * \param[in]  x,y:坐标
  184. *             PointColor:此点的颜色
  185. * \return     
  186. *            
  187. */
  188. void LCD_DrawPoint(uint16_t x,uint16_t y)
  189. {
  190.                 LTDC_Draw_Point(x,y,PointColor);
  191. }
  192. /**
  193. * \brief      函数功能:快速画点
  194. *            
  195. * \param[in]  x,y:坐标
  196. *             color:颜色
  197. * \return   
  198. *            
  199. */
  200. void LCD_Fast_DrawPoint(uint16_t x,uint16_t y,uint32_t color)
  201. {          
  202.                 LTDC_Draw_Point(x,y,color);
  203.                 return;
  204. }         
  205. /**
  206. * \brief      函数功能:设置LCD显示方向
  207. *            
  208. * \param[in]  dir:0,竖屏;1,横屏
  209. *            
  210. * \return   
  211. *            
  212. */
  213. void LCD_Display_Dir(uint8_t dir)
  214. {
  215.                 LTDC_Display_Dir(dir);
  216.                 return;
  217. }         
  218. /**
  219. * \brief      函数功能:初始化lcd
  220. *
  221. * \param[in]  
  222. *            
  223. * \return   
  224. *            
  225. */      
  226. void LCD_Init(void)
  227. {           
  228.         LTDC_Init();                            //初始化LTDC
  229. }  
  230. /**
  231. * \brief      函数功能:清屏函数
  232. *            
  233. * \param[in]  color:要清屏的填充色
  234. *            
  235. * \return   
  236. *            
  237. */
  238. void LCD_Clear(uint32_t color)
  239. {
  240.         LTDC_Clear(color);
  241.         delay_ms(5);  //清屏以后不延时会导致LCD刷新次数多以后显示不全
  242. }  
  243. /**
  244. * \brief      函数功能:在指定区域内填充单个颜色
  245. *            
  246. * \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
  247. *             color:要填充的颜色
  248. * \return   
  249. *            
  250. */
  251. void LCD_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color)
  252. {         
  253.         LTDC_Fill(sx,sy,ex,ey,color);
  254.         delay_ms(5);  //填充以后不延时会导致LCD刷新次数多以后显示不全
  255. }  
  256. /**
  257. * \brief      函数功能:在指定区域内填充指定颜色块
  258. *            
  259. * \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
  260. *             color:要填充的颜色
  261. * \return   
  262. *            
  263. */
  264. void LCD_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color)
  265. {  
  266.                 LTDC_Color_Fill(sx,sy,ex,ey,color);
  267. }  
  268. /**
  269. * \brief      函数功能:画线
  270. *            
  271. * \param[in]  x1,y1:起点坐标
  272. *             x2,y2:终点坐标
  273. * \return   
  274. *            
  275. */
  276. void LCD_DrawLine(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  277. {
  278.         uint16_t t;
  279.         int xerr=0,yerr=0,delta_x,delta_y,distance;
  280.         int incx,incy,uRow,uCol;
  281.         delta_x=x2-x1; //计算坐标增量
  282.         delta_y=y2-y1;
  283.         uRow=x1;
  284.         uCol=y1;
  285.         if(delta_x>0)incx=1; //设置单步方向
  286.         else if(delta_x==0)incx=0;//垂直线
  287.         else {incx=-1;delta_x=-delta_x;}
  288.         if(delta_y>0)incy=1;
  289.         else if(delta_y==0)incy=0;//水平线
  290.         else{incy=-1;delta_y=-delta_y;}
  291.         if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
  292.         else distance=delta_y;
  293.         for(t=0;t<=distance+1;t++ )//画线输出
  294.         {  
  295.                 LCD_DrawPoint(uRow,uCol);//画点
  296.                 xerr+=delta_x ;
  297.                 yerr+=delta_y ;
  298.                 if(xerr>distance)
  299.                 {
  300.                         xerr-=distance;
  301.                         uRow+=incx;
  302.                 }
  303.                 if(yerr>distance)
  304.                 {
  305.                         yerr-=distance;
  306.                         uCol+=incy;
  307.                 }
  308.         }  
  309. }  
  310. /**
  311. * \brief      函数功能:画矩形
  312. *            
  313. * \param[in]  (x1,y1),(x2,y2):矩形的对角坐标
  314. *            
  315. * \return   
  316. *            
  317. */
  318. void LCD_DrawRectangle(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2)
  319. {
  320.         LCD_DrawLine(x1,y1,x2,y1);
  321.         LCD_DrawLine(x1,y1,x1,y2);
  322.         LCD_DrawLine(x1,y2,x2,y2);
  323.         LCD_DrawLine(x2,y1,x2,y2);
  324. }

  325. /**
  326. * \brief 函数功能 : 画矩形复选框
  327. *        
  328. * \param[in] (x1,y1),(x2,y2):复选框的对角坐标
  329. *
  330. * \return    无
  331. */
  332. void LCD_DrawCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2)
  333. {
  334.         LCD_DrawRectangle(x1,y1,x2,y2);
  335.         LCD_DrawRectangle(x1+1,y1+1,x2-1,y2-1);
  336. }

  337. /**
  338. * \brief 函数功能 : 填充矩形复选框
  339. *        
  340. * \param[in] (x1,y1),(x2,y2):复选框的对角坐标
  341. *
  342. * \return    无
  343. */
  344. void LCD_FillCheckBox(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint32_t color)
  345. {
  346.         LCD_Fill(x1+2,y1+2,x2-2,y2-2,color);       
  347.         PointColor = DEFAULT_POINT_COLOR;//恢复默认画笔颜色
  348. }
  349. /**
  350. * \brief 函数功能 : 画实心三角形
  351. *        
  352. * \param[in] (x1,y1),(x2,y2):填充区域
  353. *             x,y           :三角形坐标
  354. *
  355. * \return    无
  356. */
  357. void LCD_DrawTriangle(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y)
  358. {
  359.         LCD_Fill(x1,y1,x2,y2,BackColor);
  360.        
  361.         LCD_DrawLine(x,   y-10,x  , y+10);
  362.         LCD_DrawLine(x+1, y-9, x+1, y+9);
  363.         LCD_DrawLine(x+2, y-8, x+2, y+8);
  364.         LCD_DrawLine(x+3, y-7, x+3, y+7);
  365.         LCD_DrawLine(x+4, y-6, x+4, y+6);
  366.         LCD_DrawLine(x+5, y-5, x+5, y+5);
  367.         LCD_DrawLine(x+6, y-4, x+6, y+4);
  368.         LCD_DrawLine(x+7, y-3, x+7, y+3);
  369.         LCD_DrawLine(x+8, y-2, x+8, y+2);
  370.         LCD_DrawLine(x+9, y-1, x+9, y+1);
  371.         LCD_DrawLine(x+10,y  , x+10,y  );
  372. }
  373. /**
  374. * \brief 函数功能 : 画反向实心三角形
  375. *        
  376. * \param[in] (x1,y1),(x2,y2):填充区域
  377. *             x,y           :三角形坐标
  378. *
  379. * \return    无
  380. */
  381. void LCD_DrawTriangleRE(uint16_t x1,uint16_t y1,uint16_t x2,uint16_t y2,uint16_t x,uint16_t y)
  382. {
  383.         LCD_Fill(x1,y1,x2,y2,BackColor);
  384.        
  385.         LCD_DrawLine(x,   y-10,x  , y+10);
  386.         LCD_DrawLine(x-1, y-9, x-1, y+9);
  387.         LCD_DrawLine(x-2, y-8, x-2, y+8);
  388.         LCD_DrawLine(x-3, y-7, x-3, y+7);
  389.         LCD_DrawLine(x-4, y-6, x-4, y+6);
  390.         LCD_DrawLine(x-5, y-5, x-5, y+5);
  391.         LCD_DrawLine(x-6, y-4, x-6, y+4);
  392.         LCD_DrawLine(x-7, y-3, x-7, y+3);
  393.         LCD_DrawLine(x-8, y-2, x-8, y+2);
  394.         LCD_DrawLine(x-9, y-1, x-9, y+1);
  395.         LCD_DrawLine(x-10,y  , x-10,y  );
  396. }
  397. /**
  398. * \brief 函数功能 : 画柱状图
  399. *        这个柱状图高度为固定的280像素,8个刻度,刻度没有数值标识
  400. * \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
  401. *            w          柱状图宽度
  402. *
  403. * \return    无
  404. */
  405. void LCD_DrawHistogram(uint16_t x,uint16_t y,uint16_t w)
  406. {
  407.         LCD_DrawLine(x,y,x+w,y);
  408.         LCD_DrawLine(x,y,x,y+280);
  409.         LCD_DrawLine(x+w,y,x+w,y+280);
  410.         LCD_DrawLine(x,y+280,x+w,y+280);
  411.        
  412.         LCD_DrawLine(x-10,y,x-2,y);
  413.         LCD_DrawLine(x-6 ,y+35,x-2,y+35);
  414.         LCD_DrawLine(x-10,y+70,x-2,y+70);
  415.         LCD_DrawLine(x-6,y+105,x-2,y+105);
  416.         LCD_DrawLine(x-10,y+140,x-2,y+140);
  417.         LCD_DrawLine(x-6,y+175,x-2,y+175);
  418.         LCD_DrawLine(x-10,y+210,x-2,y+210);
  419.         LCD_DrawLine(x-6,y+245,x-2,y+245);
  420.         LCD_DrawLine(x-10,y+280,x-2,y+280);
  421.        
  422.         LCD_DrawLine(x-2,y,x-2,y+280);
  423. }

  424. /**
  425. * \brief 函数功能 : 填充柱状图
  426. *        这个柱状图高度为固定的280像素
  427. * \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
  428. *            w          柱状图宽度
  429. *            value      柱状图显示数值
  430. *            range      柱状图量程
  431. *
  432. * \return    无
  433. */
  434. void LCD_FillHistogram(uint16_t x,uint16_t y,uint16_t w,uint16_t value,uint16_t range)
  435. {
  436.         LCD_Fill(x+1,y+1,x+w-1,y-1+((range-value)*279)/range,BLACK);
  437.         LCD_Fill(x+1,y+((range-value)*279)/range,x+w-1,y+279,YELLOW);
  438. }

  439. /**
  440. * \brief 函数功能 : 画柱状图上限
  441. *        这个柱状图高度为固定的280像素
  442. * \param[in] x,y        柱状图坐标,这个坐标是柱状图矩形方框左上角的坐标
  443. *            w          柱状图宽度
  444. *            limit      柱状图上限值
  445. *            range      柱状图量程
  446. *
  447. * \return    无
  448. */
  449. void LCD_DrawHistogramLimit(uint16_t x,uint16_t y,uint16_t w,uint16_t limit,uint16_t range)
  450. {
  451.         LCD_Fill(x+w+2,y,x+w+2,y-1+((range-limit)*279)/range,RED);
  452.         LCD_Fill(x+w+2,y+((range-limit)*279)/range,x+w+2,y+279,BLACK);
  453. }
  454. /**
  455. * \brief      函数功能:在指定位置画一个指定大小的圆
  456. *            
  457. * \param[in]  (x,y):中心点
  458. *             r    :半径
  459. * \return   
  460. *            
  461. */
  462. void LCD_Draw_Circle(uint16_t x0,uint16_t y0,uint8_t r)
  463. {
  464.         int a,b;
  465.         int di;
  466.         a=0;b=r;          
  467.         di=3-(r<<1);             //判断下个点位置的标志
  468.         while(a<=b)
  469.         {
  470.                 LCD_DrawPoint(x0+a,y0-b);             //5
  471.                 LCD_DrawPoint(x0+b,y0-a);             //0           
  472.                 LCD_DrawPoint(x0+b,y0+a);             //4               
  473.                 LCD_DrawPoint(x0+a,y0+b);             //6
  474.                 LCD_DrawPoint(x0-a,y0+b);             //1      
  475.                 LCD_DrawPoint(x0-b,y0+a);            
  476.                 LCD_DrawPoint(x0-a,y0-b);             //2            
  477.                 LCD_DrawPoint(x0-b,y0-a);             //7                     
  478.                 a++;
  479.                 //使用Bresenham算法画圆     
  480.                 if(di<0)di +=4*a+6;          
  481.                 else
  482.                 {
  483.                         di+=10+4*(a-b);   
  484.                         b--;
  485.                 }                                                     
  486.         }
  487. }
  488. /**
  489. * \brief      函数功能:在指定位置显示一个字符
  490. *            
  491. * \param[in]  x,y:起始坐标
  492. *             num:要显示的字符:" "--->"~"
  493. *             size:字体大小 12/16/24/32
  494. *             mode:叠加方式(1)还是非叠加方式(0)
  495. * \return   
  496. *            
  497. */
  498. void LCD_ShowChar(uint16_t x,uint16_t y,char num,uint8_t size,uint8_t mode)
  499. {                                                            
  500.     uint8_t temp,t1,t;
  501.         uint16_t y0=y;
  502.         uint8_t csize=(size/8+((size%8)?1:0))*(size/2);                //得到字体一个字符对应点阵集所占的字节数       
  503.         num=num-' ';//得到偏移后的值(ASCII字库是从空格开始取模,所以-' '就是对应字符的字库)
  504.         for(t=0;t<csize;t++)
  505.         {   
  506.                 if(size==12)temp=asc2_1206[num][t];                  //调用1206字体
  507.                 else if(size==16)temp=asc2_1608[num][t];        //调用1608字体
  508.                 else if(size==24)temp=asc2_2412[num][t];        //调用2412字体
  509.                 else if(size==32)temp=asc2_3216[num][t];        //调用3216字体
  510.                 else return;                                                                //没有的字库
  511.                 for(t1=0;t1<8;t1++)
  512.                 {                            
  513.                         if(temp&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
  514.                         else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);
  515.                         temp<<=1;
  516.                         y++;
  517.                         if(y>=lcddev.height)return;                //超区域了
  518.                         if((y-y0)==size)
  519.                         {
  520.                                 y=y0;
  521.                                 x++;
  522.                                 if(x>=lcddev.width)return;        //超区域了
  523.                                 break;
  524.                         }
  525.                 }           
  526.         }                                            
  527. }   
  528. /**
  529. * \brief 浮点数转换至ASC2(右对齐)
  530. *        把浮点数值转化为ASC2码,小数点后最多2位,转换后数值长度为8,没有数值的部分是空格
  531. *        超过部分将被忽略,数值字符为ASCII字符。
  532. *        转换后的字符为右对齐
  533. *
  534. * \param[in]  value 需要转化的数值   转换数值0~99999
  535. * \param[in]  dot 小数点后位数       小数点最大为2
  536. * \return     转换后的字符串指针
  537. */
  538. char* FloatAsc2Right(float value, uint8_t dot)
  539. {
  540.     float temp_val, compensate;
  541.     uint16_t n, int_num, int_temp;
  542.     uint8_t i,j,k;
  543.     static char temp_char[9] = {0};
  544.         temp_char[8] = 0;  //字符串结尾,字符串输出函数需要检测字符串结尾,如果没有这个会导致字符串输出的时候多一位
  545.     i = 2 - dot;   //根据小数点数移位
  546.     compensate = 0.51;
  547.                
  548.     for(j = 0;j < 8;j++)  //初始化字符串数组,static变量如果不赋值就会保留原来的值
  549.     {
  550.                 temp_char[j] = ' ';
  551.         }
  552.        
  553.     for(k = 0; k < dot; k++)              //根据小数点位数加数值起到四舍五入的作用
  554.     {
  555.         compensate = compensate / 10;
  556.     }
  557.    
  558.     temp_val = value + compensate;       //由于浮点数运算问题需要加个数
  559.     int_num  = (uint16_t)temp_val;
  560.     int_temp = int_num;   

  561.         if(dot == 0)
  562.         {
  563.                 i++;
  564.         }
  565.        
  566.     n = 10000;
  567.         if(int_num == 0)
  568.         {
  569.                 i = i+4;
  570.         }else
  571.         {
  572.                 while(n > 0)
  573.                 {
  574.                         if(int_num >= n)
  575.                         {
  576.                                 temp_char[i] = (char)(int_temp / n) + 48;
  577.                                 int_temp = int_temp % n;                         
  578.                         }
  579.                         i += 1;               
  580.                         n /= 10;
  581.                 }
  582.         }

  583.     if(temp_val < 1)
  584.     {
  585.         temp_char[i] = 48;
  586.         i +=1;
  587.     }

  588.     int_temp = (uint16_t)((temp_val - int_num) * 10000);

  589.     if(dot > 0)
  590.     {
  591.         temp_char[i] = 46;
  592.         i += 1;
  593.         temp_char[i] = (char)(int_temp / 1000) + 48;
  594.         i += 1;
  595.     }

  596.     if(dot > 1)
  597.     {
  598.         int_temp = int_temp % 1000;
  599.         temp_char[i] = (char)(int_temp / 100) + 48;
  600.         i += 1;
  601.     }
  602.        
  603.         return temp_char;
  604. }

  605. /**
  606. * \brief 浮点数转换至ASC2(左对齐)
  607. *        把浮点数值转化为ASC2码,小数点后最多2位
  608. *        超过部分将被忽略,数值字符为ASCII字符。
  609. *        转换后的字符为右对齐
  610. *
  611. * \param[in]  value 需要转化的数值   转换数值0~99999
  612. * \param[in]  dot 小数点后位数       小数点最大为2
  613. * \return     转换后的字符串指针
  614. */
  615. char* FloatAsc2Left(float value, uint8_t dot)
  616. {
  617.     float temp_val, compensate;
  618.     uint16_t n, int_num, int_temp;
  619.     uint8_t i,j,k;
  620.     static char temp_char[8] = {0};
  621.         i = 0;
  622.     compensate = 0.51;
  623.                
  624.     for(j = 0;j < 8;j++)  //初始化字符串数组,static变量如果不赋值就会保留原来的值
  625.     {
  626.                 temp_char[j] = 0;
  627.         }
  628.        
  629.     for(k = 0; k < dot; k++)              //根据小数点位数加数值起到四舍五入的作用
  630.     {
  631.         compensate = compensate / 10;
  632.     }
  633.    
  634.     temp_val = value + compensate;       //由于浮点数运算问题需要加个数
  635.     int_num  = (uint16_t)temp_val;
  636.     int_temp = int_num;   

  637.     n = 10000;
  638.         while(n > 0)
  639.         {
  640.                 if(int_num >= n)
  641.                 {
  642.                         temp_char[i] = (char)(int_temp / n) + 48;
  643.                         int_temp = int_temp % n;        
  644.                         i += 1;
  645.                 }                                       
  646.                 n /= 10;
  647.         }

  648.     if(temp_val < 1)
  649.     {
  650.         temp_char[i] = 48;
  651.         i +=1;
  652.     }

  653.     int_temp = (uint16_t)((temp_val - int_num) * 10000);

  654.     if(dot > 0)
  655.     {
  656.         temp_char[i] = 46;
  657.         i += 1;
  658.         temp_char[i] = (char)(int_temp / 1000) + 48;
  659.         i += 1;
  660.     }

  661.     if(dot > 1)
  662.     {
  663.         int_temp = int_temp % 1000;
  664.         temp_char[i] = (char)(int_temp / 100) + 48;
  665.         i += 1;
  666.     }
  667.        
  668.         return temp_char;
  669. }
  670. /**
  671. * \brief      函数功能:显示字符串
  672. *            
  673. * \param[in]  x,y:起点坐标
  674. *             width,height:区域大小  
  675. *             size:字体大小
  676. *             *p:字符串起始地址       
  677. * \return   
  678. *            
  679. */  
  680. void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,volatile char *p)
  681. {         
  682.         uint8_t x0=x;
  683.         width+=x;
  684.         height+=y;
  685.     while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
  686.     {      
  687.         if(x>=width){x=x0;y+=size;}
  688.         if(y>=height)break;//退出
  689.         LCD_ShowChar(x,y,*p,size,0);
  690.         x+=size/2;
  691.         p++;
  692.     }  
  693. }
  694. /**
  695. * \brief      函数功能:显示一个指定大小的汉字
  696. *             显示24x24汉字,字体采用横向取模方式(即从左到右然后从上到下)
  697. * \param[in]  x,y :汉字的坐标
  698. *             size:字体大小
  699. *             mode:0,正常显示,1,叠加显示
  700. * \return   
  701. *            
  702. */                                                                  
  703. void LCD_ShowFont(uint16_t x,uint16_t y,uint8_t size,const volatile char *p,uint8_t mode)
  704. {
  705.         uint16_t i=0,j=0,k=0;
  706.         uint16_t num_font;
  707.         uint16_t x0=x;
  708.     if(size == 24)
  709.         {
  710.                 num_font = sizeof(GB24_Code) / sizeof(typFNT_GB24);  //计算字库中汉字个数               
  711.        
  712.                 for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找
  713.                 {
  714.                         if((*p==GB24_Code[i].Index[0]) && (*(p+1)==GB24_Code[i].Index[1]))//索引汉字成功
  715.                         {
  716.                                 for(j=0;j<MSKNUM24;j++)//写入数据
  717.                                 {
  718.                                         unsigned short word=GB24_Code[i].Msk[j];
  719.                                         for(k=0;k<8;k++)//循环8次移位
  720.                                         {
  721.                                                 if(word&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
  722.                                                 else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);                                    
  723.                                                 word<<=1;//往前移位
  724.                                                 x++;
  725.                                                 if((x-x0)==size)
  726.                                                 {
  727.                                                         x=x0;
  728.                                                         y++;
  729.                                                         break;
  730.                                                 }               
  731.                                         }
  732.                                 }
  733.                         }
  734.                 }
  735.         }else if(size == 32)
  736.         {
  737.                 num_font = sizeof(GB32_Code) / sizeof(typFNT_GB32);  //计算字库中汉字个数               
  738.        
  739.                 for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找
  740.                 {
  741.                         if((*p==GB32_Code[i].Index[0]) && (*(p+1)==GB32_Code[i].Index[1]))//索引汉字成功
  742.                         {
  743.                                 for(j=0;j<MSKNUM32;j++)//写入数据
  744.                                 {
  745.                                         unsigned short word=GB32_Code[i].Msk[j];
  746.                                         for(k=0;k<8;k++)//循环8次移位
  747.                                         {
  748.                                                 if(word&0x80)LCD_Fast_DrawPoint(x,y,PointColor);
  749.                                                 else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);                                    
  750.                                                 word<<=1;//往前移位
  751.                                                 x++;
  752.                                                 if((x-x0)==size)
  753.                                                 {
  754.                                                         x=x0;
  755.                                                         y++;
  756.                                                         break;
  757.                                                 }               
  758.                                         }
  759.                                 }
  760.                         }
  761.                 }
  762.         }else
  763.         {
  764.                 ; //字体大小不合法
  765.         }
  766. }
  767. /**
  768. * \brief      函数功能:显示一个单色位位图片
  769. *            
  770. * \param[in]  x,y :图片坐标
  771. *             width,heigth :显示区域
  772. *             data :图片数据
  773. *             mode:0,正常显示,1,叠加显示
  774. * \return   
  775. *            
  776. */
  777. void LCD_ShowPicture(uint16_t x,uint16_t y,uint16_t width,uint16_t heigth, const uint8_t *data,uint8_t mode)
  778. {
  779.         uint16_t i=0,j=0;
  780.         uint16_t num_font;
  781.         uint16_t x0=x;
  782.    
  783.         num_font = width * heigth / 8;  //计算图片字节数
  784.        
  785.         for(i=0;i<num_font;i++)//在所有的汉字结构体数组中查找,i最大为结构体数组成员的个数
  786.         {
  787.                 uint8_t word=data[i];
  788.                 for(j=0;j<8;j++)//循环8次移位
  789.                 {
  790.                         if(word&0x80)LCD_Fast_DrawPoint(x,y,WHITE);
  791.                         else if(mode==0)LCD_Fast_DrawPoint(x,y,BackColor);                                    
  792.                         word<<=1;//往前移位
  793.                         x++;
  794.                         if((x-x0)==width)
  795.                         {
  796.                                 x=x0;
  797.                                 y++;
  798.                                 break;
  799.                         }               
  800.                 }               
  801.         }
  802. }
  803. /**
  804. * \brief      函数功能:在指定位置开始显示一个字符串       
  805. *             支持自动换行
  806. * \param[in]  (x,y):起始坐标
  807. *             width,height:区域
  808. *             str  :字符串
  809. *             size :字体大小
  810. *             mode:0,非叠加方式;1,叠加方式
  811. * \return   
  812. *            
  813. */                                 
  814. void LCD_ShowText(uint16_t x,uint16_t y,uint16_t width,uint16_t height,volatile char*str,uint8_t size,uint8_t mode)
  815. {                                                                                                                                                                                                 
  816.     while(*str!=0)//数据未结束
  817.     {
  818.                 if((uint8_t)*str<0x81)//字符
  819.                 {      
  820.                                 LCD_ShowChar(x,y,*str,size,mode);//有效部分写入
  821.                                 str++;
  822.                         x+=size/2; //字符,为全字的一半
  823.                 }
  824.         else//中文
  825.         {                                                          
  826.                 LCD_ShowFont(x,y,size,str,mode); //显示这个汉字,空心显示
  827.                 str+=2;
  828.                 x+=size;//下一个汉字偏移            
  829.         }                                                 
  830.     }   
  831. }                                            

  832. /*@}*/
  833. LTDC.H

  834. ```c
  835. #ifndef _LCD_H
  836. #define _LCD_H
  837. #include "sys.h"

  838. //LCD LTDC重要参数集
  839. typedef struct  
  840. {                                                         
  841.         uint32_t pwidth;                        //LCD面板的宽度,固定参数,不随显示方向改变,如果为0,说明没有任何RGB屏接入
  842.         uint32_t pheight;                //LCD面板的高度,固定参数,不随显示方向改变
  843.         uint16_t hsw;                        //水平同步宽度
  844.         uint16_t vsw;                        //垂直同步宽度
  845.         uint16_t hbp;                        //水平后廊
  846.         uint16_t vbp;                        //垂直后廊
  847.         uint16_t hfp;                        //水平前廊
  848.         uint16_t vfp;                        //垂直前廊
  849.         uint8_t activelayer;                //当前层编号:0/1       
  850.         uint8_t dir;                                //0,竖屏;1,横屏;
  851.         uint16_t width;                        //LCD宽度
  852.         uint16_t height;                        //LCD高度
  853.         uint32_t pixsize;                //每个像素所占字节数
  854. }_ltdc_dev;

  855. extern _ltdc_dev lcdltdc;                            //管理LCD LTDC参数
  856. extern LTDC_HandleTypeDef LTDC_Handler;            //LTDC句柄
  857. extern DMA2D_HandleTypeDef DMA2D_Handler;   //DMA2D句柄

  858. #define LCD_PIXEL_FORMAT_ARGB8888       0X00   
  859. #define LCD_PIXEL_FORMAT_RGB888         0X01   
  860. #define LCD_PIXEL_FORMAT_RGB565         0X02      
  861. #define LCD_PIXEL_FORMAT_ARGB1555       0X03      
  862. #define LCD_PIXEL_FORMAT_ARGB4444       0X04     
  863. #define LCD_PIXEL_FORMAT_L8             0X05     
  864. #define LCD_PIXEL_FORMAT_AL44           0X06     
  865. #define LCD_PIXEL_FORMAT_AL88           0X07      

  866. ///
  867. //用户修改配置部分:

  868. //定义颜色像素格式,一般用RGB565
  869. #define LCD_PIXFORMAT                                LCD_PIXEL_FORMAT_RGB565       
  870. //定义默认背景层颜色
  871. #define LTDC_BACKLAYERCOLOR                        BLACK       
  872. //LCD帧缓冲区首地址,这里定义在SDRAM里面.
  873. #define LCD_FRAME_BUF_ADDR                        0XC0000000  

  874. void LTDC_Switch(uint8_t sw);                                        //LTDC开关
  875. void LTDC_Layer_Switch(uint8_t layerx,uint8_t sw);        //层开关
  876. void LTDC_Select_Layer(uint8_t layerx);                        //层选择
  877. void LTDC_Display_Dir(uint8_t dir);                                //显示方向控制
  878. void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color);//画点函数
  879. uint32_t LTDC_Read_Point(uint16_t x,uint16_t y);                        //读点函数
  880. void LTDC_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color);                        //矩形单色填充函数
  881. void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color);        //矩形彩色填充函数
  882. void LTDC_Clear(uint32_t color);                                        //清屏函数
  883. uint8_t LTDC_Clk_Set(uint32_t pllsain,uint32_t pllsair,uint32_t pllsaidivr);//LTDC时钟配置
  884. void LTDC_Layer_Window_Config(uint8_t layerx,uint16_t sx,uint16_t sy,uint16_t width,uint16_t height);//LTDC层窗口设置
  885. void LTDC_Layer_Parameter_Config(uint8_t layerx,uint32_t bufaddr,uint8_t pixformat,uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,uint32_t bkcolor);//LTDC基本参数设置
  886. uint16_t LTDC_PanelID_Read(void);                                //LCD ID读取函数
  887. void LTDC_Init(void);                                                //LTDC初始化函数
 楼主| t60yz 发表于 2021-11-30 23:58 | 显示全部楼层
LTDC.c

  1. #include "ltdc.h"
  2. #include "lcd.h"

  3. /** \addtogroup ltdc_group ltdc通讯模块 */

  4. /*@{*/

  5. LTDC_HandleTypeDef  LTDC_Handler;            //LTDC句柄
  6. DMA2D_HandleTypeDef DMA2D_Handler;             //DMA2D句柄

  7. //根据不同的颜色格式,定义帧缓存数组
  8. #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
  9.         uint32_t ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));        //定义最大屏分辨率时,LCD所需的帧缓存数组大小
  10. #else
  11.         uint16_t ltdc_lcd_framebuf[1280][800] __attribute__((at(LCD_FRAME_BUF_ADDR)));        //定义最大屏分辨率时,LCD所需的帧缓存数组大小
  12. #endif

  13. uint32_t *ltdc_framebuf[2];                                        //LTDC LCD帧缓存数组指针,必须指向对应大小的内存区域
  14. _ltdc_dev lcdltdc;                                                //管理LCD LTDC的重要参数
  15. /**
  16. * \brief      函数功能:打开LCD开关
  17. *
  18. * \param[in]  sw:1 打开,0,关闭
  19. * \return   
  20. *            
  21. */
  22. void LTDC_Switch(uint8_t sw)
  23. {
  24.         if(sw==1) __HAL_LTDC_ENABLE(&LTDC_Handler);
  25.         else if(sw==0)__HAL_LTDC_DISABLE(&LTDC_Handler);
  26. }
  27. /**
  28. * \brief      函数功能:开关指定层
  29. *
  30. * \param[in]  layerx:层号,0,第一层; 1,第二层
  31. *             sw:1 打开;0关闭
  32. * \return   
  33. *            
  34. */
  35. void LTDC_Layer_Switch(uint8_t layerx,uint8_t sw)
  36. {
  37.         if(sw==1) __HAL_LTDC_LAYER_ENABLE(&LTDC_Handler,layerx);
  38.         else if(sw==0) __HAL_LTDC_LAYER_DISABLE(&LTDC_Handler,layerx);
  39.         __HAL_LTDC_RELOAD_CONFIG(&LTDC_Handler);
  40. }
  41. /**
  42. * \brief      函数功能:选择层
  43. *
  44. * \param[in]  layerx:层号;0,第一层;1,第二层;
  45. * \return   
  46. *            
  47. */
  48. void LTDC_Select_Layer(uint8_t layerx)
  49. {
  50.         lcdltdc.activelayer=layerx;
  51. }
  52. /**
  53. * \brief      函数功能:设置LCD显示方向
  54. *
  55. * \param[in]  dir:0,竖屏;1,横屏
  56. * \return   
  57. *            
  58. */
  59. void LTDC_Display_Dir(uint8_t dir)
  60. {
  61.     lcdltdc.dir=dir;         //显示方向
  62.         if(dir==0)                        //竖屏
  63.         {
  64.                 lcdltdc.width=lcdltdc.pheight;
  65.                 lcdltdc.height=lcdltdc.pwidth;       
  66.         }else if(dir==1)        //横屏
  67.         {
  68.                 lcdltdc.width=lcdltdc.pwidth;
  69.                 lcdltdc.height=lcdltdc.pheight;
  70.         }
  71. }
  72. /**
  73. * \brief      函数功能:画点函数
  74. *
  75. * \param[in]  x,y:写入坐标
  76. *             color:颜色值
  77. * \return   
  78. *            
  79. */
  80. void LTDC_Draw_Point(uint16_t x,uint16_t y,uint32_t color)
  81. {
  82. #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
  83.         if(lcdltdc.dir)        //横屏
  84.         {
  85.         *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
  86.         }else                         //竖屏
  87.         {
  88.         *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y))=color;
  89.         }
  90. #else
  91.         if(lcdltdc.dir)        //横屏
  92.         {
  93.         *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x))=color;
  94.         }else                         //竖屏
  95.         {
  96.         *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y))=color;
  97.         }
  98. #endif
  99. }
  100. /**
  101. * \brief      函数功能:读点函数
  102. *
  103. * \param[in]  x,y:读取点的坐标
  104. *             返回值:颜色值
  105. * \return   
  106. *            
  107. */
  108. uint32_t LTDC_Read_Point(uint16_t x,uint16_t y)
  109. {
  110. #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
  111.         if(lcdltdc.dir)        //横屏
  112.         {
  113.                 return *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
  114.         }else                         //竖屏
  115.         {
  116.                 return *(uint32_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x)+y));
  117.         }
  118. #else
  119.         if(lcdltdc.dir)        //横屏
  120.         {
  121.                 return *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*y+x));
  122.         }else                         //竖屏
  123.         {
  124.                 return *(uint16_t*)((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*(lcdltdc.pheight-x-1)+y));
  125.         }
  126. #endif
  127. }
  128. /**
  129. * \brief      函数功能:LTDC填充矩形,DMA2D填充
  130. *             有时候需要频繁的调用填充函数,所以为了速度,填充函数采用寄存器版本
  131. * \param[in]  (sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
  132. *             color:要填充的颜色
  133. * \return   
  134. *            
  135. */
  136. void LTDC_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint32_t color)
  137. {
  138.         uint32_t psx,psy,pex,pey;        //以LCD面板为基准的坐标系,不随横竖屏变化而变化
  139.         uint32_t timeout=0;
  140.         uint16_t offline;
  141.         uint32_t addr;
  142.         //坐标系转换
  143.         if(lcdltdc.dir)        //横屏
  144.         {
  145.                 psx=sx;psy=sy;
  146.                 pex=ex;pey=ey;
  147.         }else                        //竖屏
  148.         {
  149.                 psx=sy;psy=lcdltdc.pheight-ex-1;
  150.                 pex=ey;pey=lcdltdc.pheight-sx-1;
  151.         }
  152.         offline=lcdltdc.pwidth-(pex-psx+1);
  153.         addr=((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
  154.         __HAL_RCC_DMA2D_CLK_ENABLE();        //使能DM2D时钟
  155.         DMA2D->CR&=~(DMA2D_CR_START);        //先停止DMA2D
  156.         DMA2D->CR=DMA2D_R2M;                        //寄存器到存储器模式
  157.         DMA2D->OPFCCR=LCD_PIXFORMAT;        //设置颜色格式
  158.         DMA2D->OOR=offline;                                //设置行偏移

  159.         DMA2D->OMAR=addr;                                //输出存储器地址
  160.         DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);        //设定行数寄存器
  161.         DMA2D->OCOLR=color;                                                //设定输出颜色寄存器
  162.         DMA2D->CR|=DMA2D_CR_START;                                //启动DMA2D
  163.         while((DMA2D->ISR&(DMA2D_FLAG_TC))==0)        //等待传输完成
  164.         {
  165.                 timeout++;
  166.                 if(timeout>0X1FFFFF)break;        //超时退出
  167.         }
  168.         DMA2D->IFCR|=DMA2D_FLAG_TC;                //清除传输完成标志                
  169. }
  170. /**
  171. * \brief      函数功能:在指定区域内填充指定颜色块,DMA2D填充       
  172. *             此函数仅支持uint16_t,RGB565格式的颜色数组填充.
  173. * \param[in]  sx,sy),(ex,ey):填充矩形对角坐标,区域大小为:(ex-sx+1)*(ey-sy+1)
  174. *                 注意:sx,ex,不能大于lcddev.width-1;sy,ey,不能大于lcddev.height-1!!!
  175. *             color:要填充的颜色数组首地址
  176. * \return   
  177. *            
  178. */
  179. void LTDC_Color_Fill(uint16_t sx,uint16_t sy,uint16_t ex,uint16_t ey,uint16_t *color)
  180. {
  181.         uint32_t psx,psy,pex,pey;        //以LCD面板为基准的坐标系,不随横竖屏变化而变化
  182.         uint32_t timeout=0;
  183.         uint16_t offline;
  184.         uint32_t addr;
  185.         //坐标系转换
  186.         if(lcdltdc.dir)        //横屏
  187.         {
  188.                 psx=sx;psy=sy;
  189.                 pex=ex;pey=ey;
  190.         }else                        //竖屏
  191.         {
  192.                 psx=sy;psy=lcdltdc.pheight-ex-1;
  193.                 pex=ey;pey=lcdltdc.pheight-sx-1;
  194.         }
  195.         offline=lcdltdc.pwidth-(pex-psx+1);
  196.         addr=((uint32_t)ltdc_framebuf[lcdltdc.activelayer]+lcdltdc.pixsize*(lcdltdc.pwidth*psy+psx));
  197.         __HAL_RCC_DMA2D_CLK_ENABLE();        //使能DM2D时钟
  198.         DMA2D->CR&=~(DMA2D_CR_START);        //先停止DMA2D
  199.         DMA2D->CR=DMA2D_M2M;                        //存储器到存储器模式
  200.         DMA2D->FGPFCCR=LCD_PIXFORMAT;        //设置颜色格式
  201.         DMA2D->FGOR=0;                                        //前景层行偏移为0
  202.         DMA2D->OOR=offline;                                //设置行偏移

  203.         DMA2D->FGMAR=(uint32_t)color;                //源地址
  204.         DMA2D->OMAR=addr;                                //输出存储器地址
  205.         DMA2D->NLR=(pey-psy+1)|((pex-psx+1)<<16);        //设定行数寄存器
  206.         DMA2D->CR|=DMA2D_CR_START;                                        //启动DMA2D
  207.         while((DMA2D->ISR&(DMA2D_FLAG_TC))==0)                //等待传输完成
  208.         {
  209.                 timeout++;
  210.                 if(timeout>0X1FFFFF)break;        //超时退出
  211.         }
  212.         DMA2D->IFCR|=DMA2D_FLAG_TC;                                //清除传输完成标志         
  213. }  
  214. /**
  215. * \brief      函数功能:LCD清屏
  216. *
  217. * \param[in]  color:颜色值
  218. * \return   
  219. *            
  220. */
  221. void LTDC_Clear(uint32_t color)
  222. {
  223.         LTDC_Fill(0,0,lcdltdc.width-1,lcdltdc.height-1,color);
  224. }
  225. /**
  226. * \brief      函数功能:LTDC时钟(Fdclk)设置函数
  227. *             Fvco=Fin*pllsain;
  228. *             Fdclk=Fvco/pllsair/2*2^pllsaidivr=Fin*pllsain/pllsair/2*2^pllsaidivr;
  229. *             假设:外部晶振为25M,pllm=25的时候,Fin=1Mhz.
  230. *             例如:要得到20M的LTDC时钟,则可以设置:pllsain=400,pllsair=5,pllsaidivr=RCC_PLLSAIDIVR_4
  231. *             Fdclk=1*400/5/4=400/20=20Mhz
  232. *
  233. * \param[in]  Fvco:VCO频率
  234. *             Fin:输入时钟频率一般为1Mhz(来自系统时钟PLLM分频后的时钟,见时钟树图)
  235. *             pllsain:SAI时钟倍频系数N,取值范围:50~432.  
  236. *             pllsair:SAI时钟的分频系数R,取值范围:2~7
  237. *             pllsaidivr:LCD时钟分频系数,取值范围:RCC_PLLSAIDIVR_2/4/8/16,对应分频2~16
  238. * \return     0,成功;1,失败。
  239. *            
  240. */
  241. uint8_t LTDC_Clk_Set(uint32_t pllsain,uint32_t pllsair,uint32_t pllsaidivr)
  242. {
  243.         RCC_PeriphCLKInitTypeDef PeriphClkIniture;
  244.        
  245.         //LTDC输出像素时钟,需要根据自己所使用的LCD数据手册来配置!
  246.     PeriphClkIniture.PeriphClockSelection=RCC_PERIPHCLK_LTDC;        //LTDC时钟        
  247.         PeriphClkIniture.PLLSAI.PLLSAIN=pllsain;   
  248.         PeriphClkIniture.PLLSAI.PLLSAIR=pllsair;  
  249.         PeriphClkIniture.PLLSAIDivR=pllsaidivr;
  250.         if(HAL_RCCEx_PeriphCLKConfig(&PeriphClkIniture)==HAL_OK)    //配置像素时钟
  251.     {
  252.         return 0;   //成功
  253.     }
  254.     else return 1;  //失败   
  255. }
  256. /**
  257. * \brief      函数功能:LTDC,层颜窗口设置,窗口以LCD面板坐标系为基准
  258. *             注意:此函数必须在LTDC_Layer_Parameter_Config之后再设置.
  259. * \param[in]  layerx:层值,0/1.
  260. *             sx,sy:起始坐标
  261. *             width,height:宽度和高度
  262. * \return   
  263. *            
  264. */
  265. void LTDC_Layer_Window_Config(uint8_t layerx,uint16_t sx,uint16_t sy,uint16_t width,uint16_t height)
  266. {
  267.     HAL_LTDC_SetWindowPosition(&LTDC_Handler,sx,sy,layerx);  //设置窗口的位置
  268.     HAL_LTDC_SetWindowSize(&LTDC_Handler,width,height,layerx);//设置窗口大小   
  269. }
  270. /**
  271. * \brief      函数功能:LTDC,基本参数设置.
  272. *             注意:此函数,必须在LTDC_Layer_Window_Config之前设置.
  273. * \param[in]  layerx:层值,0/1.
  274. *             bufaddr:层颜色帧缓存起始地址
  275. *             pixformat:颜色格式.0,ARGB8888;1,RGB888;2,RGB565;3,ARGB1555;4,ARGB4444;5,L8;6;AL44;7;AL88
  276. *             alpha:层颜色Alpha值,0,全透明;255,不透明
  277. *             alpha0:默认颜色Alpha值,0,全透明;255,不透明
  278. *             bfac1:混合系数1,4(100),恒定的Alpha;6(101),像素Alpha*恒定Alpha
  279. *             bfac2:混合系数2,5(101),恒定的Alpha;7(111),像素Alpha*恒定Alpha
  280. *             bkcolor:层默认颜色,32位,低24位有效,RGB888格式
  281. * \return   
  282. *            
  283. */
  284. void LTDC_Layer_Parameter_Config(uint8_t layerx,uint32_t bufaddr,uint8_t pixformat,uint8_t alpha,uint8_t alpha0,uint8_t bfac1,uint8_t bfac2,uint32_t bkcolor)
  285. {
  286.         LTDC_LayerCfgTypeDef pLayerCfg;
  287.        
  288.         pLayerCfg.WindowX0=0;                       //窗口起始X坐标
  289.         pLayerCfg.WindowY0=0;                       //窗口起始Y坐标
  290.         pLayerCfg.WindowX1=lcdltdc.pwidth;          //窗口终止X坐标
  291.         pLayerCfg.WindowY1=lcdltdc.pheight;         //窗口终止Y坐标
  292.         pLayerCfg.PixelFormat=pixformat;                    //像素格式
  293.         pLayerCfg.Alpha=alpha;                                        //Alpha值设置,0~255,255为完全不透明
  294.         pLayerCfg.Alpha0=alpha0;                                //默认Alpha值
  295.         pLayerCfg.BlendingFactor1=(uint32_t)bfac1<<8;    //设置层混合系数
  296.         pLayerCfg.BlendingFactor2=(uint32_t)bfac2<<8;        //设置层混合系数
  297.         pLayerCfg.FBStartAdress=bufaddr;                //设置层颜色帧缓存起始地址
  298.         pLayerCfg.ImageWidth=lcdltdc.pwidth;        //设置颜色帧缓冲区的宽度   
  299.         pLayerCfg.ImageHeight=lcdltdc.pheight;      //设置颜色帧缓冲区的高度
  300.         pLayerCfg.Backcolor.Red=(uint8_t)(bkcolor&0X00FF0000)>>16;   //背景颜色红色部分
  301.         pLayerCfg.Backcolor.Green=(uint8_t)(bkcolor&0X0000FF00)>>8;  //背景颜色绿色部分
  302.         pLayerCfg.Backcolor.Blue=(uint8_t)bkcolor&0X000000FF;        //背景颜色蓝色部分
  303.         HAL_LTDC_ConfigLayer(&LTDC_Handler,&pLayerCfg,layerx);   //设置所选中的层
  304. }  
  305. /**
  306. * \brief      函数功能:LCD初始化函数
  307. *            
  308. * \param[in]  
  309. *            
  310. * \return   
  311. *            
  312. */
  313. void LTDC_Init(void)
  314. {          
  315.         lcdltdc.pwidth=LCD_HOR_RESOLUTION;                            //面板宽度,单位:像素
  316.         lcdltdc.pheight=LCD_VER_RESOLUTION;                        //面板高度,单位:像素
  317.         lcdltdc.hsw=LCD_HOR_PULSE_WIDTH;                            //水平同步宽度
  318.         lcdltdc.vsw=LCD_VER_PULSE_WIDTH;                            //垂直同步宽度
  319.         lcdltdc.hbp=LCD_HOR_BACK_PORCH;                                    //水平后廊
  320.         lcdltdc.vbp=LCD_VER_BACK_PORCH;                                    //垂直后廊
  321.         lcdltdc.hfp=LCD_HOR_FRONT_PORCH;                            //水平前廊
  322.     lcdltdc.vfp=LCD_VER_FRONT_PORCH;                            //垂直前廊
  323.     LTDC_Clk_Set(400,4,RCC_PLLSAIDIVR_4);           //设置像素时钟 25Mhz
  324.                 //其他参数待定.

  325.         lcddev.width=lcdltdc.pwidth;
  326.         lcddev.height=lcdltdc.pheight;
  327.    
  328. #if LCD_PIXFORMAT==LCD_PIXFORMAT_ARGB8888||LCD_PIXFORMAT==LCD_PIXFORMAT_RGB888
  329.         ltdc_framebuf[0]=(uint32_t*)&ltdc_lcd_framebuf;
  330.         lcdltdc.pixsize=4;                                //每个像素占4个字节
  331. #else
  332.     lcdltdc.pixsize=2;                                //每个像素占2个字节
  333.         ltdc_framebuf[0]=(uint32_t*)&ltdc_lcd_framebuf;
  334. #endif        
  335.     //LTDC配置
  336.     LTDC_Handler.Instance=LTDC;
  337.     LTDC_Handler.Init.HSPolarity=LTDC_HSPOLARITY_AL;         //水平同步极性
  338.     LTDC_Handler.Init.VSPolarity=LTDC_VSPOLARITY_AL;         //垂直同步极性
  339.     LTDC_Handler.Init.DEPolarity=LTDC_DEPOLARITY_AL;         //数据使能极性
  340.     LTDC_Handler.Init.PCPolarity=LTDC_PCPOLARITY_IPC;           //像素时钟极性
  341.     LTDC_Handler.Init.HorizontalSync=lcdltdc.hsw-1;          //水平同步宽度
  342.     LTDC_Handler.Init.VerticalSync=lcdltdc.vsw-1;            //垂直同步宽度
  343.     LTDC_Handler.Init.AccumulatedHBP=lcdltdc.hsw+lcdltdc.hbp-1; //水平同步后沿宽度
  344.     LTDC_Handler.Init.AccumulatedVBP=lcdltdc.vsw+lcdltdc.vbp-1; //垂直同步后沿高度
  345.     LTDC_Handler.Init.AccumulatedActiveW=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth-1;//有效宽度
  346.     LTDC_Handler.Init.AccumulatedActiveH=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight-1;//有效高度
  347.     LTDC_Handler.Init.TotalWidth=lcdltdc.hsw+lcdltdc.hbp+lcdltdc.pwidth+lcdltdc.hfp-1;   //总宽度
  348.     LTDC_Handler.Init.TotalHeigh=lcdltdc.vsw+lcdltdc.vbp+lcdltdc.pheight+lcdltdc.vfp-1;  //总高度
  349.     LTDC_Handler.Init.Backcolor.Red=0XFF;           //屏幕背景层红色部分
  350.     LTDC_Handler.Init.Backcolor.Green=0XFF;         //屏幕背景层绿色部分
  351.     LTDC_Handler.Init.Backcolor.Blue=0XFF;          //屏幕背景色蓝色部分
  352.     HAL_LTDC_Init(&LTDC_Handler);
  353.        
  354.         //层配置
  355.         LTDC_Layer_Parameter_Config(0,(uint32_t)ltdc_framebuf[0],LCD_PIXFORMAT,255,0,6,7,0X000000);//层参数配置
  356.         LTDC_Layer_Window_Config(0,0,0,lcdltdc.pwidth,lcdltdc.pheight);        //层窗口配置,以LCD面板坐标系为基准,不要随便修改!
  357.        
  358.         LTDC_Display_Dir(1);                        //默认横屏
  359.         LTDC_Select_Layer(0);                         //选择第1层
  360.     LCD_BlackLightOn();                                 //点亮背光
  361.     LTDC_Clear(BLACK);                        //清屏
  362. }
  363. /**
  364. * \brief      函数功能:LTDC底层IO初始化和时钟使能
  365. *             此函数会被HAL_LTDC_Init()调用
  366. * \param[in]  hltdc:LTDC句柄
  367. * \return   
  368. *            
  369. */
  370. void HAL_LTDC_MspInit(LTDC_HandleTypeDef* hltdc)
  371. {
  372.     GPIO_InitTypeDef GPIO_Initure;
  373.    
  374.     __HAL_RCC_LTDC_CLK_ENABLE();                //使能LTDC时钟
  375.     __HAL_RCC_DMA2D_CLK_ENABLE();               //使能DMA2D时钟
  376.   //  __HAL_RCC_GPIOB_CLK_ENABLE();               //使能GPIOB时钟
  377.     __HAL_RCC_GPIOF_CLK_ENABLE();               //使能GPIOF时钟
  378.     __HAL_RCC_GPIOG_CLK_ENABLE();               //使能GPIOG时钟
  379.     __HAL_RCC_GPIOH_CLK_ENABLE();               //使能GPIOH时钟
  380.     __HAL_RCC_GPIOI_CLK_ENABLE();               //使能GPIOI时钟
  381.        
  382. /* 背光在硬件上连了,不用软件控制
  383.     //初始化PB15,背光引脚
  384.     GPIO_Initure.Pin=GPIO_PIN_15;               //PB15推挽输出,控制背光
  385.     GPIO_Initure.Mode=GPIO_MODE_OUTPUT_PP;      //推挽输出
  386.     GPIO_Initure.Pull=GPIO_PULLUP;              //上拉        
  387.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
  388.     HAL_GPIO_Init(GPIOB,&GPIO_Initure);
  389. */   
  390.     //初始化PF10
  391.     GPIO_Initure.Pin=GPIO_PIN_10;
  392.     GPIO_Initure.Mode=GPIO_MODE_AF_PP;          //复用
  393.     GPIO_Initure.Pull=GPIO_NOPULL;              
  394.     GPIO_Initure.Speed=GPIO_SPEED_HIGH;         //高速
  395.     GPIO_Initure.Alternate=GPIO_AF14_LTDC;      //复用为LTDC
  396.     HAL_GPIO_Init(GPIOF,&GPIO_Initure);
  397.   

  398.     //初始化PG6,7,11
  399.     GPIO_Initure.Pin=GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_11;
  400.     HAL_GPIO_Init(GPIOG,&GPIO_Initure);
  401.    
  402.     //初始化PH9,10,11,12,13,14,15
  403.     GPIO_Initure.Pin=GPIO_PIN_9|GPIO_PIN_10|GPIO_PIN_11|\
  404.                      GPIO_PIN_12|GPIO_PIN_13|GPIO_PIN_14|GPIO_PIN_15;
  405.     HAL_GPIO_Init(GPIOH,&GPIO_Initure);
  406.    
  407.     //初始化PI0,1,2,4,5,6,7,9,10
  408.     GPIO_Initure.Pin=GPIO_PIN_0|GPIO_PIN_1|GPIO_PIN_2|GPIO_PIN_4|GPIO_PIN_5|\
  409.                      GPIO_PIN_6|GPIO_PIN_7|GPIO_PIN_9|GPIO_PIN_10;
  410.     HAL_GPIO_Init(GPIOI,&GPIO_Initure);
  411. }
 楼主| t60yz 发表于 2021-11-30 23:59 | 显示全部楼层
完毕
~
linxi6414 发表于 2021-12-29 13:21 | 显示全部楼层
有没有外挂SDRAM?
您需要登录后才可以回帖 登录 | 注册

本版积分规则

189

主题

1191

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部