• (STM32)从零开始的RT-Thread之旅--SPI驱动ST7735(2)


    本篇使用的驱动来自ST官方提供:

    https://github.com/STMicroelectronics/stm32-st7735.git

    需要的可以直接git clone下来移植,核心代码无关芯片型号,可移植性很不错!本篇用的ST7735库比官方新添加了一些内容,是开发板卖家提供的,地址:

    WeActStudio

    第一篇中我们打通了SPI,读取到了芯片ID,这一篇只要完善几个接口函数就可以直接使用官方的驱动库了。至于要完善哪几个接口,需要看一下官方驱动库需要哪些函数。

    1.添加官方源代码

    可以参照我上图的结构把几个源文件添加进去,其中font.h可以在WeAct那个github上找到。

    添加完后记得把头文件路径也包含进去。

    2.官方库使用方法

    在添加完成后,新建lcd相关源文件,比如我的文件结构:

    修改 st7735.h 中一处地方:

    这个变量在st7735.c中被定义。 怎么使用库如下:

    其中ST7735Ctx是库里面定义好的,我们直接使用即可。但是还需要两个变量:

    st7735_pObj就是设备驱动实例,实际在屏幕上显示都是操作的它。关键是st7735_pIO这个变量,它负责提供底层接口。它里面包含的一些函数指针正是我们需要完成的。

    在上一章的基础上,使用了两套SPI使用方式,如果定义 USE_RTT_SPI ,就是用RTT驱动框架提供的SPI接口函数,如果把它注释掉,则直接使用HAL库的SPI函数,具体实现我会附在后面。

    实际我们使用的时候调用的函数是:

    比如要填充整个屏幕为黑色:

    附:

    mspi.c

    1. /*
    2. * Copyright (c) 2006-2021, RT-Thread Development Team
    3. *
    4. * SPDX-License-Identifier: Apache-2.0
    5. *
    6. * Change Logs:
    7. * Date Author Notes
    8. * 2022-11-14 cx the first version
    9. */
    10. #include
    11. #include
    12. #include
    13. #include
    14. #include
    15. #include "st7735_reg.h"
    16. #include "st7735.h"
    17. #define USE_RTT_SPI
    18. SPI_HandleTypeDef *spi_handle;
    19. #ifdef USE_RTT_SPI
    20. static struct rt_spi_device *spi_lcd;
    21. #define LCD_RD_HIGH rt_pin_write(SPI_RD_PIN_NUM, PIN_HIGH)
    22. #define LCD_RD_LOW rt_pin_write(SPI_RD_PIN_NUM, PIN_LOW)
    23. #else
    24. SPI_HandleTypeDef hspi4;
    25. #define SPI_Drv (&hspi4)
    26. #define LCD_CS_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_11,GPIO_PIN_SET)
    27. #define LCD_CS_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_11,GPIO_PIN_RESET)
    28. #define LCD_RD_HIGH HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_SET)
    29. #define LCD_RD_LOW HAL_GPIO_WritePin(GPIOE,GPIO_PIN_13,GPIO_PIN_RESET)
    30. #endif
    31. #ifdef USE_RTT_SPI
    32. int32_t mspi_send_reg(uint8_t reg,uint8_t *data,uint32_t len)
    33. {
    34. struct rt_spi_message msg;
    35. uint32_t remsg = RT_NULL;
    36. msg.send_buf = ®
    37. msg.recv_buf = RT_NULL;
    38. msg.length = 1;
    39. msg.cs_take = 1;
    40. msg.cs_release = 0;
    41. msg.next = RT_NULL;
    42. LCD_RD_LOW;
    43. remsg = (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    44. LCD_RD_HIGH;
    45. if(len > 0)
    46. {
    47. msg.send_buf = data;
    48. msg.recv_buf = RT_NULL;
    49. msg.length = len;
    50. msg.cs_take = 0;
    51. msg.cs_release = 1;
    52. msg.next = RT_NULL;
    53. remsg += (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    54. }
    55. if(remsg!=RT_NULL)
    56. return -1;
    57. else
    58. return 0;
    59. }
    60. int32_t mspi_read_reg(uint8_t reg,uint8_t *data)
    61. {
    62. struct rt_spi_message msg;
    63. uint32_t remsg = RT_NULL;
    64. uint8_t reg1 = reg;
    65. msg.send_buf = ®1;
    66. msg.recv_buf = RT_NULL;
    67. msg.length = 1;
    68. msg.cs_take = 1;
    69. msg.cs_release = 0;
    70. msg.next = RT_NULL;
    71. LCD_RD_LOW;
    72. remsg = (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    73. LCD_RD_HIGH;
    74. if(remsg == 0)
    75. {
    76. msg.send_buf = RT_NULL;
    77. msg.recv_buf = data;
    78. msg.length = 1;
    79. msg.cs_take = 0;
    80. msg.cs_release = 1;
    81. msg.next = RT_NULL;
    82. remsg += (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    83. }
    84. if(remsg!=RT_NULL)
    85. return -1;
    86. else
    87. return 0;
    88. }
    89. int32_t mspi_send_data(uint8_t *data,uint32_t len)
    90. {
    91. struct rt_spi_message msg;
    92. msg.send_buf = data;
    93. msg.recv_buf = RT_NULL;
    94. msg.length = len;
    95. msg.cs_take = 1;
    96. msg.cs_release = 1;
    97. msg.next = RT_NULL;
    98. return (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    99. }
    100. int32_t mspi_read_data(uint8_t *data,uint32_t len)
    101. {
    102. struct rt_spi_message msg;
    103. msg.send_buf = RT_NULL;
    104. msg.recv_buf = data;
    105. msg.length = len;
    106. msg.cs_take = 1;
    107. msg.cs_release = 1;
    108. msg.next = RT_NULL;
    109. return (uint32_t)rt_spi_transfer_message(spi_lcd,&msg);
    110. }
    111. #else
    112. int32_t mspi_send_reg(uint8_t reg,uint8_t *data,uint32_t len)
    113. {
    114. int32_t result;
    115. LCD_CS_LOW;
    116. LCD_RD_LOW;
    117. result = HAL_SPI_Transmit(SPI_Drv,®,1,100);
    118. LCD_RD_HIGH;
    119. if(len > 0)
    120. result += HAL_SPI_Transmit(SPI_Drv,data,len,500);
    121. LCD_CS_HIGH;
    122. if(result>0){
    123. result = -1;}
    124. else{
    125. result = 0;}
    126. return result;
    127. }
    128. int32_t mspi_read_reg(uint8_t reg,uint8_t *data)
    129. {
    130. int32_t result;
    131. LCD_CS_LOW;
    132. LCD_RD_LOW;
    133. result = HAL_SPI_Transmit(SPI_Drv,®,1,100);
    134. LCD_RD_HIGH;
    135. result += HAL_SPI_Receive(SPI_Drv,data,1,500);
    136. LCD_CS_HIGH;
    137. if(result>0){
    138. result = -1;}
    139. else{
    140. result = 0;}
    141. return result;
    142. }
    143. int32_t mspi_send_data(uint8_t *data,uint32_t len)
    144. {
    145. int32_t result;
    146. LCD_CS_LOW;
    147. //LCD_RD_HIGH;
    148. result =HAL_SPI_Transmit(SPI_Drv,data,len,100);
    149. LCD_CS_HIGH;
    150. if(result>0){
    151. result = -1;}
    152. else{
    153. result = 0;}
    154. return result;
    155. }
    156. int32_t mspi_read_data(uint8_t *data,uint32_t len)
    157. {
    158. int32_t result;
    159. LCD_CS_LOW;
    160. //LCD_RD_HIGH;
    161. result = HAL_SPI_Receive(SPI_Drv,data,len,500);
    162. LCD_CS_HIGH;
    163. if(result>0){
    164. result = -1;}
    165. else{
    166. result = 0;}
    167. return result;
    168. }
    169. #endif
    170. int32_t mspi_get_tick(void)
    171. {
    172. return HAL_GetTick();
    173. }
    174. void mspi_rw_gpio_init(void)
    175. {
    176. #ifdef USE_RTT_SPI
    177. rt_pin_mode(SPI_RD_PIN_NUM, PIN_MODE_OUTPUT);
    178. rt_pin_write(SPI_RD_PIN_NUM, PIN_HIGH);
    179. #else
    180. GPIO_InitTypeDef GPIO_InitStruct = {0};
    181. __HAL_RCC_GPIOE_CLK_ENABLE();
    182. HAL_GPIO_WritePin(GPIOE, GPIO_PIN_11|GPIO_PIN_13, GPIO_PIN_SET);
    183. GPIO_InitStruct.Pin = GPIO_PIN_11|GPIO_PIN_13;
    184. GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    185. GPIO_InitStruct.Pull = GPIO_NOPULL;
    186. GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_VERY_HIGH;
    187. HAL_GPIO_Init(GPIOE, &GPIO_InitStruct);
    188. #endif
    189. }
    190. void mspi_init(void)
    191. {
    192. mspi_rw_gpio_init();
    193. #ifdef USE_RTT_SPI
    194. struct rt_spi_configuration cfg;
    195. rt_hw_spi_device_attach("spi4", "spi40", GPIOE, GPIO_PIN_11);
    196. spi_lcd = (struct rt_spi_device *)rt_device_find("spi40");
    197. if(!spi_lcd)
    198. {
    199. rt_kprintf("spi40 can't find\n");
    200. }
    201. else
    202. {
    203. spi_lcd->bus->owner = spi_lcd;
    204. cfg.data_width = 8;
    205. cfg.mode = RT_SPI_MASTER | RT_SPI_3WIRE | RT_SPI_MODE_0 | RT_SPI_MSB;
    206. cfg.max_hz = 12.5 * 1000 * 1000;
    207. rt_spi_configure(spi_lcd, &cfg);
    208. }
    209. //也可以初始化使用框架提供的函数,发送接收使用HAL库函数,操作对象就是下面的 spi_handle
    210. // struct stm32_spi *spi_drv = rt_container_of(spi_lcd->bus, struct stm32_spi, spi_bus);
    211. // spi_handle = &spi_drv->handle;
    212. #else
    213. hspi4.Instance = SPI4;
    214. hspi4.Init.Mode = SPI_MODE_MASTER;
    215. hspi4.Init.Direction = SPI_DIRECTION_1LINE;
    216. hspi4.Init.DataSize = SPI_DATASIZE_8BIT;
    217. hspi4.Init.CLKPolarity = SPI_POLARITY_LOW;
    218. hspi4.Init.CLKPhase = SPI_PHASE_1EDGE;
    219. hspi4.Init.NSS = SPI_NSS_SOFT;
    220. hspi4.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_8;
    221. hspi4.Init.FirstBit = SPI_FIRSTBIT_MSB;
    222. hspi4.Init.TIMode = SPI_TIMODE_DISABLE;
    223. hspi4.Init.CRCCalculation = SPI_CRCCALCULATION_DISABLE;
    224. hspi4.Init.CRCPolynomial = 0x0;
    225. hspi4.Init.NSSPMode = SPI_NSS_PULSE_ENABLE;
    226. hspi4.Init.NSSPolarity = SPI_NSS_POLARITY_LOW;
    227. hspi4.Init.FifoThreshold = SPI_FIFO_THRESHOLD_01DATA;
    228. hspi4.Init.TxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    229. hspi4.Init.RxCRCInitializationPattern = SPI_CRC_INITIALIZATION_ALL_ZERO_PATTERN;
    230. hspi4.Init.MasterSSIdleness = SPI_MASTER_SS_IDLENESS_00CYCLE;
    231. hspi4.Init.MasterInterDataIdleness = SPI_MASTER_INTERDATA_IDLENESS_00CYCLE;
    232. hspi4.Init.MasterReceiverAutoSusp = SPI_MASTER_RX_AUTOSUSP_DISABLE;
    233. hspi4.Init.MasterKeepIOState = SPI_MASTER_KEEP_IO_STATE_DISABLE;
    234. hspi4.Init.IOSwap = SPI_IO_SWAP_DISABLE;
    235. if (HAL_SPI_Init(&hspi4) != HAL_OK)
    236. {
    237. rt_kprintf("ERROR\n");
    238. }
    239. #endif
    240. }

    mlcd.c

    1. /*
    2. * Copyright (c) 2006-2021, RT-Thread Development Team
    3. *
    4. * SPDX-License-Identifier: Apache-2.0
    5. *
    6. * Change Logs:
    7. * Date Author Notes
    8. * 2022-11-15 cx the first version
    9. */
    10. #include
    11. #include
    12. #include
    13. #define DBG_TAG "mlcd"
    14. #define DBG_LVL DBG_LOG
    15. #include
    16. #include "mpwm.h"
    17. #include "mspi.h"
    18. #include "st7735_reg.h"
    19. #include "st7735.h"
    20. #include "mlcd.h"
    21. #include "font.h"
    22. #include
    23. int32_t mlcd_st7735_init(void);
    24. ST7735_IO_t st7735_pIO = {
    25. mlcd_st7735_init,
    26. NULL,
    27. 0,
    28. mspi_send_reg,
    29. mspi_read_reg,
    30. mspi_send_data,
    31. mspi_read_data,
    32. mspi_get_tick
    33. };
    34. ST7735_Object_t st7735_pObj;
    35. int32_t mlcd_st7735_init(void)
    36. {
    37. int32_t result = ST7735_OK;
    38. mpwm_init();
    39. mspi_init();
    40. return result;
    41. }
    42. int mlcd_init(void)
    43. {
    44. uint32_t st7735_id;
    45. uint8_t text[50];
    46. #ifdef TFT96
    47. ST7735Ctx.Orientation = ST7735_ORIENTATION_LANDSCAPE_ROT180;
    48. ST7735Ctx.Panel = HannStar_Panel;
    49. ST7735Ctx.Type = ST7735_0_9_inch_screen;
    50. #elif TFT18
    51. ST7735Ctx.Orientation = ST7735_ORIENTATION_PORTRAIT;
    52. ST7735Ctx.Panel = BOE_Panel;
    53. ST7735Ctx.Type = ST7735_1_8_inch_screen;
    54. #else
    55. LOG_E("Unknown Screen");
    56. #endif
    57. ST7735_RegisterBusIO(&st7735_pObj,&st7735_pIO);
    58. ST7735_LCD_Driver.Init(&st7735_pObj,ST7735_FORMAT_RBG565,&ST7735Ctx);
    59. ST7735_LCD_Driver.ReadID(&st7735_pObj,&st7735_id);
    60. rt_kprintf("LCD ID:%08X\n",st7735_id);
    61. ST7735_LCD_Driver.FillRect(&st7735_pObj, 0, 0, ST7735Ctx.Width,ST7735Ctx.Height, BLACK);
    62. sprintf((char *)&text, "Something V1.0");
    63. LCD_ShowString(4, 4, ST7735Ctx.Width, 16, 16, text);
    64. return 0;
    65. }
    66. uint16_t POINT_COLOR=0xFFFF; //画笔颜色
    67. uint16_t BACK_COLOR=BLACK; //背景色
    68. //在指定位置显示一个字符
    69. //x,y:起始坐标
    70. //num:要显示的字符:" "--->"~"
    71. //size:字体大小 12/16
    72. //mode:叠加方式(1)还是非叠加方式(0)
    73. void LCD_ShowChar(uint16_t x,uint16_t y,uint8_t num,uint8_t size,uint8_t mode)
    74. {
    75. uint8_t temp,t1,t;
    76. uint16_t y0=y;
    77. uint16_t x0=x;
    78. uint16_t colortemp=POINT_COLOR;
    79. uint32_t h,w;
    80. uint16_t write[size][size==12?6:8];
    81. uint16_t count;
    82. ST7735_GetXSize(&st7735_pObj,&w);
    83. ST7735_GetYSize(&st7735_pObj,&h);
    84. //设置窗口
    85. num=num-' ';//得到偏移后的值
    86. count = 0;
    87. if(!mode) //非叠加方式
    88. {
    89. for(t=0;t
    90. {
    91. if(size==12)temp=asc2_1206[num][t]; //调用1206字体
    92. else temp=asc2_1608[num][t]; //调用1608字体
    93. for(t1=0;t1<8;t1++)
    94. {
    95. if(temp&0x80)
    96. POINT_COLOR=(colortemp&0xFF)<<8|colortemp>>8;
    97. else
    98. POINT_COLOR=(BACK_COLOR&0xFF)<<8|BACK_COLOR>>8;
    99. write[count][t/2]=POINT_COLOR;
    100. count ++;
    101. if(count >= size) count =0;
    102. temp<<=1;
    103. y++;
    104. if(y>=h){POINT_COLOR=colortemp;return;}//超区域了
    105. if((y-y0)==size)
    106. {
    107. y=y0;
    108. x++;
    109. if(x>=w){POINT_COLOR=colortemp;return;}//超区域了
    110. break;
    111. }
    112. }
    113. }
    114. }
    115. else//叠加方式
    116. {
    117. for(t=0;t
    118. {
    119. if(size==12)temp=asc2_1206[num][t]; //调用1206字体
    120. else temp=asc2_1608[num][t]; //调用1608字体
    121. for(t1=0;t1<8;t1++)
    122. {
    123. if(temp&0x80)
    124. write[count][t/2]=(POINT_COLOR&0xFF)<<8|POINT_COLOR>>8;
    125. count ++;
    126. if(count >= size) count =0;
    127. temp<<=1;
    128. y++;
    129. if(y>=h){POINT_COLOR=colortemp;return;}//超区域了
    130. if((y-y0)==size)
    131. {
    132. y=y0;
    133. x++;
    134. if(x>=w){POINT_COLOR=colortemp;return;}//超区域了
    135. break;
    136. }
    137. }
    138. }
    139. }
    140. ST7735_FillRGBRect(&st7735_pObj,x0,y0,(uint8_t *)&write,size==12?6:8,size);
    141. POINT_COLOR=colortemp;
    142. }
    143. //显示字符串
    144. //x,y:起点坐标
    145. //width,height:区域大小
    146. //size:字体大小
    147. //*p:字符串起始地址
    148. void LCD_ShowString(uint16_t x,uint16_t y,uint16_t width,uint16_t height,uint8_t size,uint8_t *p)
    149. {
    150. uint8_t x0=x;
    151. width+=x;
    152. height+=y;
    153. while((*p<='~')&&(*p>=' '))//判断是不是非法字符!
    154. {
    155. if(x>=width){x=x0;y+=size;}
    156. if(y>=height)break;//退出
    157. LCD_ShowChar(x,y,*p,size,0);
    158. x+=size/2;
    159. p++;
    160. }
    161. }

  • 相关阅读:
    系统架构设计师-第13章-层次式架构设计理论与实践-软考学习笔记
    题目 1074: 数字整除
    qml保姆级教程四:按钮组件
    高优先线程
    Laravel Routes Group-Prefix 使用变量问题
    AI模型精确解析果蝇行为,未来或可预测人类行为
    JaVers:自动化数据审计
    Java阻塞队列中的异类,SynchronousQueue底层实现原理剖析
    Java集合知识点
    android 解决AVC问题
  • 原文地址:https://blog.csdn.net/qwe5959798/article/details/127924308