**本文使用环境:
电脑:WIN10 开发板:W80X (w806 w801 w800 air101 air 103) 平台:CDK 显示屏:openmv 1.8英寸SPI显示屏128X160(st7735r ,程序兼容st7735s) 显示屏资料:https://openmv.io/products/lcd-shield (128RMB,为什么会这么贵,搞不清楚)**
一、显示接口连接
1、显示屏接口: 典型的SPI接口 2、开发板接口 自己可以下去查看手册,这里不再赘述了,直接看SPI的IO口是哪些。80X带有硬件SPI,速度最快20MHZ,所以刷屏会有些慢。SPI接口如下程序:
void HAL_SPI_MspInit(SPI_HandleTypeDef* hspi)
{
__HAL_RCC_SPI_CLK_ENABLE();
__HAL_AFIO_REMAP_SPI_CS(GPIOB, GPIO_PIN_4);
__HAL_AFIO_REMAP_SPI_CLK(GPIOB, GPIO_PIN_2);
__HAL_AFIO_REMAP_SPI_MISO(GPIOB, GPIO_PIN_3);
__HAL_AFIO_REMAP_SPI_MOSI(GPIOB, GPIO_PIN_5);
注意:SPI端口中B3没有使用,因为LCD只需要数据传入,不需要数据传出,单片机作为M,LCD作为S。
除此之外LCD还需要额外的三个IO口控制,如下:复位、背光和数据控制切换端口,我这里分别采用的是B0 B1 B6 ,因为2、3、4、5已经作为SPI用了。
#define LCD_RES_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_RESET)
#define LCD_RES_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_0, GPIO_PIN_SET)
#define LCD_BLK_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_RESET)
#define LCD_BLK_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1, GPIO_PIN_SET)
#define LCD_DC_Clr() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET)
#define LCD_DC_Set() HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET)
端口对应表:
开发板引脚 | LCD引脚 |
---|
PB0 | RES | PB1 | BLK | PB2 | CLK | PB4 | CS | PB5 | MOSI | PB6 | DC | | |
二、 程序
这里需要特别说明的是:由于SPI_DMA无法调试成功,所以用的仅仅是硬件SPI,速度20MHZ所以初始化程序将DMA也初始化了,但是没有使用DMA。后期有大佬做出来DMA再更新, 如果是ST7735R可以直接使用程序,如果是ST7735S需要注释下列宏定义:
1、main.c:
#include <stdio.h>
#include "wm_hal.h"
#include "lcd_init.h"
#include "tft7735r.h"
void Error_Handler(void);
SPI_HandleTypeDef hspi;
DMA_HandleTypeDef hdma_spi_tx;
DMA_HandleTypeDef hdma_spi_rx;
static void SPI_Init(void);
static void DMA_Init(void);
#define data_len (10000)
uint8_t tx_data[data_len] = {0};
uint8_t rx_data[data_len] = {0};
int main(void)
{
SystemClock_Config(CPU_CLK_240M);
printf("enter main\r\n");
LCD_GPIO_Init();
DMA_Init();
SPI_Init();
__HAL_SPI_SET_CS_LOW(&hspi);
LCD_Init();
while(1)
{
uint32_t start = HAL_GetTick();
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
uint32_t end = HAL_GetTick();
printf("time %dms \r\n",end - start);
LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,BRED);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,GRED);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,GBLUE);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,MAGENTA);
HAL_Delay(1000);
LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
HAL_Delay(1000);
}
}
static void SPI_Init(void)
{
hspi.Instance = SPI;
hspi.Init.Mode = SPI_MODE_MASTER;
hspi.Init.CLKPolarity = SPI_POLARITY_LOW;
hspi.Init.CLKPhase = SPI_PHASE_1EDGE;
hspi.Init.NSS = SPI_NSS_SOFT;
hspi.Init.BaudRatePrescaler = SPI_BAUDRATEPRESCALER_2;
hspi.Init.FirstByte = SPI_LITTLEENDIAN;
if (HAL_SPI_Init(&hspi) != HAL_OK)
{
Error_Handler();
}
}
static void DMA_Init(void)
{
__HAL_RCC_DMA_CLK_ENABLE();
HAL_NVIC_SetPriority(DMA_Channel0_IRQn, 0);
HAL_NVIC_EnableIRQ(DMA_Channel0_IRQn);
HAL_NVIC_SetPriority(DMA_Channel1_IRQn, 0);
HAL_NVIC_EnableIRQ(DMA_Channel1_IRQn);
}
void HAL_SPI_TxCpltCallback(SPI_HandleTypeDef *hspi)
{
__HAL_SPI_SET_CS_HIGH(hspi);
printf("tx cplt\r\n");
}
void HAL_SPI_RxCpltCallback(SPI_HandleTypeDef *hspi)
{
__HAL_SPI_SET_CS_HIGH(hspi);
printf("rx cplt\r\n");
}
void Error_Handler(void)
{
while (1)
{
}
}
void assert_failed(uint8_t *file, uint32_t line)
{
printf("Wrong parameters value: file %s on line %d\r\n", file, line);
}
2、程序优化
LCD是参考的STM32的代码,在实际使用过程中发现,在传输数据的时候,单字节的传输时间较慢,如下所示:
void LCD_WR_DATA(uint16_t dat)
{
LCD_Writ_Bus(dat>>8);
LCD_Writ_Bus(dat);
}
这个函数是一个字节字节的传输,我的算下来一帧图像的时间是114ms,,较长,因为这里是一字节一字节的传输。由于W806的SPI传输中可以多字节发送,所以我做了如下修改:
void LCD_WR_DATA(uint16_t dat)
{
uint8_t data[2];
data[0] = dat>>8;
data[1] = dat;
HAL_SPI_Transmit(&hspi,(uint8_t *)data,2,100);
}
修改后的代码可以直接发生两个字节的数据,可以极大的节约时间,这点出乎我的意料。实际测下来,采用这种方式的发送时间是:69ms。114 到 69 这还是很有说服力的。
三、演示效果
1、图片展示
2、程序运行时间统计
通过串口助手打印显示,每一帧的时间大概是69ms左右:当然这个时间可以通过修改系统时钟频率变小一点,我大概测了一下是小了10个ms左右,意义不大就不在贴方法了。
3、视频展示
四、程序地址
https://github.com/xiansenzhao/WM_SDK_W806_7735r.git
|