相信大家对正点原子推出的精英板不陌生吧,作为一款入门STM32的高性价比开发板,可以练习许多开发应用。本次分享就精英板V2驱动LCD彩屏外设展开话题。正点原子精英STM32开发板选择的是STM32F103ZET6作为MCU,该芯片是STM32F103里面配置非常强大的了,它拥有的资源包括:64KB SRAM、512KB FLASH、2个基本定时器、4个通用定时器、2个高级定时器、2个DMA控制器(共12个通道)、3个 SPI、2个IIC、5个串口、1个USB、1个CAN、3个12位ADC、1个12位DAC、1个SDIO接口、1个FSMC接口以及112个通用IO口。该芯片的配置十分强悍,并且还带外部总线(FSMC)可以用来外扩SRAM和连接LCD等,通过FSMC驱动LCD,可以显著提高LCD的刷屏速度,是STM32F1家族常用型号里面,最高配置的芯片了。
本次驱动的LCD屏并不是正点原子提供的,而是采用另外一个扩展板,通过GPIO去模拟SPI通讯,因此不占用精英板上的TFT_LCD固定硬件接口。这里不得不谈及这块扩展板,扩展板上的资源也很丰富,有集成多个传感器,包括温湿度传感器、三轴磁场传感器、加速度角速度传感器、环境光传感器,一个RGB彩灯、一块128*160分辨率的电阻式触摸屏,一个旋钮,一个双轴电位计摇杆。当然此次分享就触摸屏的显示驱动部分进行讲解。
本次采用JLink调试器与精英板相连接,扩展板上的触摸屏通过杜邦线与精英板相连接。两者之间的关联可通过下方的原理图可知。

在硬件连线的基础上进行代码编写,这里我们采用GPIO模拟SPI通讯,屏的芯片是基于ST7735S的,因此我们在基础工程框架中增加驱动代码,部分参考代码如下:
lcd_init.h
#ifndef __LCD_INIT_H
#define __LCD_INIT_H
#include "stm32f1xx.h"
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/delay/delay.h"
#define USE_HORIZONTAL 1 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
#if USE_HORIZONTAL==0||USE_HORIZONTAL==1
#define LCD_W 128
#define LCD_H 160
#else
#define LCD_W 160
#define LCD_H 128
#endif
#define BOARD_LCD_GPIO GPIOA
#define BOARD_LCD_GPIO_SCLK_PIN GPIO_PIN_0
#define BOARD_LCD_GPIO_CS_PIN GPIO_PIN_1
#define BOARD_LCD_GPIO_MOSI_PIN GPIO_PIN_4
#define BOARD_LCD_GPIO_DC_PIN GPIO_PIN_5
#define BOARD_LCD_GPIO_RES_PIN GPIO_PIN_6
#define BOARD_LCD_BLK_GPIO GPIOA
#define BOARD_LCD_GPIO_BLK_PIN GPIO_PIN_7
//-----------------LCD端口定义----------------
#define LCD_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOA_CLK_ENABLE(); }while(0) /* PB口时钟使能 */
#define LCD_SCLK_Clr() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_SCLK_PIN,GPIO_PIN_RESET)//SCL SCLK
#define LCD_SCLK_Set() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_SCLK_PIN,GPIO_PIN_SET)
#define LCD_CS_Clr() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_CS_PIN,GPIO_PIN_RESET)//CS
#define LCD_CS_Set() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_CS_PIN,GPIO_PIN_SET)
#define LCD_MOSI_Clr() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_MOSI_PIN,GPIO_PIN_RESET)//SDA MOSI
#define LCD_MOSI_Set() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_MOSI_PIN,GPIO_PIN_SET)
#define LCD_DC_Clr() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_DC_PIN,GPIO_PIN_RESET)//DC
#define LCD_DC_Set() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_DC_PIN,GPIO_PIN_SET)
#define LCD_RES_Clr() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_RES_PIN,GPIO_PIN_RESET)//RES
#define LCD_RES_Set() HAL_GPIO_WritePin(BOARD_LCD_GPIO,BOARD_LCD_GPIO_RES_PIN,GPIO_PIN_SET)
#define LCD_BLK_Clr() HAL_GPIO_WritePin(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,GPIO_PIN_RESET)//BLK
#define LCD_BLK_Set() HAL_GPIO_WritePin(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,GPIO_PIN_SET)
void LCD_GPIO_Init(void);//初始化GPIO
void LCD_Writ_Bus(u8 dat);//模拟SPI时序
void LCD_WR_DATA8(u8 dat);//写入一个字节
void LCD_WR_DATA(u16 dat);//写入两个字节
void LCD_WR_REG(u8 dat);//写入一个指令
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2);//设置坐标函数
void LCD_Init(void);//LCD初始化
#endiflcd_init.c
#include "lcd_init.h"
#include "stm32f1xx.h"
/******************************************************************************
函数说明:LCD串行数据写入函数
入口数据:dat 要写入的串行数据
返回值: 无
******************************************************************************/
void LCD_Writ_Bus(u8 dat)
{
u8 i;
LCD_CS_Clr();
for(i=0;i<8;i++)
{
LCD_SCLK_Clr();
if(dat&0x80)
{
LCD_MOSI_Set();
}
else
{
LCD_MOSI_Clr();
}
LCD_SCLK_Set();
dat<<=1;
}
LCD_CS_Set();
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA8(u8 dat)
{
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入数据
入口数据:dat 写入的数据
返回值: 无
******************************************************************************/
void LCD_WR_DATA(u16 dat)
{
LCD_Writ_Bus(dat>>8);
LCD_Writ_Bus(dat);
}
/******************************************************************************
函数说明:LCD写入命令
入口数据:dat 写入的命令
返回值: 无
******************************************************************************/
void LCD_WR_REG(u8 dat)
{
LCD_DC_Clr();//写命令
LCD_Writ_Bus(dat);
LCD_DC_Set();//写数据
}
/******************************************************************************
函数说明:设置起始和结束地址
入口数据:x1,x2 设置列的起始和结束地址
y1,y2 设置行的起始和结束地址
返回值: 无
******************************************************************************/
void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2)
{
if(USE_HORIZONTAL==0)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+2);
LCD_WR_DATA(x2+2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+1);
LCD_WR_DATA(y2+1);
LCD_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==1)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+2);
LCD_WR_DATA(x2+2);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+1);
LCD_WR_DATA(y2+1);
LCD_WR_REG(0x2c);//储存器写
}
else if(USE_HORIZONTAL==2)
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+1);
LCD_WR_DATA(x2+1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+2);
LCD_WR_DATA(y2+2);
LCD_WR_REG(0x2c);//储存器写
}
else
{
LCD_WR_REG(0x2a);//列地址设置
LCD_WR_DATA(x1+1);
LCD_WR_DATA(x2+1);
LCD_WR_REG(0x2b);//行地址设置
LCD_WR_DATA(y1+2);
LCD_WR_DATA(y2+2);
LCD_WR_REG(0x2c);//储存器写
}
}
void LCD_Init(void)
{
LCD_GPIO_CLK_ENABLE();
GPIO_InitTypeDef gpio_init_struct;
gpio_init_struct.Pin = BOARD_LCD_GPIO_SCLK_PIN|BOARD_LCD_GPIO_CS_PIN|BOARD_LCD_GPIO_MOSI_PIN|\
BOARD_LCD_GPIO_DC_PIN|BOARD_LCD_GPIO_RES_PIN|BOARD_LCD_GPIO_BLK_PIN; /* LED0引脚 */
gpio_init_struct.Mode = GPIO_MODE_OUTPUT_PP; /* 推挽输出 */
gpio_init_struct.Pull = GPIO_PULLUP; /* 上拉 */
gpio_init_struct.Speed = GPIO_SPEED_FREQ_HIGH; /* 高速 */
HAL_GPIO_Init(BOARD_LCD_GPIO, &gpio_init_struct); /* 初始化LCD引脚 */
delay_ms(20);
LCD_RES_Clr();//复位
delay_ms(1);
LCD_RES_Set();
delay_ms(1);
LCD_BLK_Set();//打开背光
delay_ms(120);
LCD_WR_REG(0x11); //Sleep out
delay_ms(120);
LCD_WR_REG(0xB1);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB2);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB3);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x05);
LCD_WR_DATA8(0x3C);
LCD_WR_DATA8(0x3C);
LCD_WR_REG(0xB4); //Dot inversion
LCD_WR_DATA8(0x03);
LCD_WR_REG(0xC0);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x08);
LCD_WR_DATA8(0x04);
LCD_WR_REG(0xC1);
LCD_WR_DATA8(0XC0);
LCD_WR_REG(0xC2);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x00);
LCD_WR_REG(0xC3);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0x2A);
LCD_WR_REG(0xC4);
LCD_WR_DATA8(0x8D);
LCD_WR_DATA8(0xEE);
LCD_WR_REG(0xC5); //VCOM
LCD_WR_DATA8(0x1A);
LCD_WR_REG(0x36); //MX, MY, RGB mode
if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00);
else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0);
else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70);
else LCD_WR_DATA8(0xA0);
LCD_WR_REG(0xE0);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x22);
LCD_WR_DATA8(0x07);
LCD_WR_DATA8(0x0A);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x30);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2A);
LCD_WR_DATA8(0x28);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x2E);
LCD_WR_DATA8(0x3A);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x03);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0xE1);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x16);
LCD_WR_DATA8(0x06);
LCD_WR_DATA8(0x0D);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x26);
LCD_WR_DATA8(0x23);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x27);
LCD_WR_DATA8(0x25);
LCD_WR_DATA8(0x2D);
LCD_WR_DATA8(0x3B);
LCD_WR_DATA8(0x00);
LCD_WR_DATA8(0x01);
LCD_WR_DATA8(0x04);
LCD_WR_DATA8(0x13);
LCD_WR_REG(0x3A);
LCD_WR_DATA8(0x05);
LCD_WR_REG(0x29);
}lcd.h
#ifndef __LCD_H
#define __LCD_H
#include "stm32f1xx.h"
#include "lcd_init.h"
#define LCD_WIDTH 128
#define LCD_HEIGHT 160
typedef struct
{
unsigned int index;
unsigned int value[64];
}LCD_Plot_Data;
struct drv_lcd_coordinate
{
int8_t ymin;
int8_t ymax;
uint8_t x;
uint8_t y;
uint8_t xsize;
uint8_t ysize;
};
void LCD_Fill(u16 xsta,u16 ysta,u16 xend,u16 yend,u16 color);//指定区域填充颜色
void LCD_DrawPoint(u16 x,u16 y,u16 color);//在指定位置画一个点
void LCD_DrawLine(u16 x1,u16 y1,u16 x2,u16 y2,u16 color);//在指定位置画一条线
void LCD_DrawRectangle(u16 x1, u16 y1, u16 x2, u16 y2,u16 color);//在指定位置画一个矩形
void Draw_Circle(u16 x0,u16 y0,u8 r,u16 color);//在指定位置画一个圆
void LCD_ShowChinese(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示汉字串
void LCD_ShowChinese12x12(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个12x12汉字
void LCD_ShowChinese16x16(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个16x16汉字
void LCD_ShowChinese24x24(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个24x24汉字
void LCD_ShowChinese32x32(u16 x,u16 y,u8 *s,u16 fc,u16 bc,u8 sizey,u8 mode);//显示单个32x32汉字
void LCD_ShowChar(u16 x,u16 y,u8 num,u16 fc,u16 bc,u8 sizey,u8 mode);//显示一个字符
void LCD_ShowString(u16 x,u16 y,const u8 *p,u16 fc,u16 bc,u8 sizey,u8 mode);//显示字符串
void LCD_ShowIntNum(u16 x,u16 y,u16 num,u8 len,u16 fc,u16 bc,u8 sizey);//显示整数变量
void LCD_ShowFloatNum1(u16 x,u16 y,float num,u8 len,u16 fc,u16 bc,u8 sizey);//显示两位小数变量
void LCD_ShowPicture(u16 x,u16 y,u16 length,u16 width,const u8 pic[]);//显示图片
u32 mypow(u8 m,u8 n);//求幂
void Plot_Data_Add(LCD_Plot_Data *Plot_Data, u32 Data);//曲线绘制结构体
void LCD_Draw_Plot(LCD_Plot_Data *Plot_Data, u32 color);//曲线绘制函数
void drv_lcd_draw_line_with_color(u16 xbegin, u16 ybegin, u16 xend, u16 yend, u16 color);
void drv_lcd_draw_coordinate_with_color(struct drv_lcd_coordinate *coord, u8 x, u8 y, u8 xsize, u8 ysize, u16 color);
void drv_lcd_draw_coordinate(struct drv_lcd_coordinate *coord, u8 x, u8 y, u8 xsize, u8 ysize);
void drv_lcd_draw_coordinate_point_with_color(struct drv_lcd_coordinate *coord, int8_t *buf, u8 num, u16 color);
void drv_lcd_coordinate_create(struct drv_lcd_coordinate *coord, int8_t ymin, int8_t ymax);
//画笔颜色
#define WHITE 0xFFFF
#define BLACK 0x0000
#define BLUE 0x001F
#define BRED 0XF81F
#define GRED 0XFFE0
#define GBLUE 0X07FF
#define RED 0xF800
#define MAGENTA 0xF81F
#define GREEN 0x07E0
#define CYAN 0x7FFF
#define YELLOW 0xFFE0
#define BROWN 0XBC40 //棕色
#define BRRED 0XFC07 //棕红色
#define GRAY 0X8430 //灰色
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
#endifmain.c
#include "./SYSTEM/sys/sys.h"
#include "./SYSTEM/usart/usart.h"
#include "./SYSTEM/delay/delay.h"
#include "./BSP/LED/led.h"
#include "./BSP/LCD/lcd.h"
#include "./BSP/LCD/lcd_init.h"
int main(void)
{
static uint8_t num = 0;
HAL_Init(); /* 初始化HAL库 */
sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */
delay_init(72); /* 延时初始化 */
usart_init(115200); /* 串口初始化为115200 */
led_init(); /* 初始化LED */
LCD_Init(); /* 初始化LCD */
while (1)
{
switch (num)
{
case 0:
LCD_Fill(0,0,LCD_W,LCD_H,WHITE);
break;
case 1:
LCD_Fill(0,0,LCD_W,LCD_H,BLACK);
break;
case 2:
LCD_Fill(0,0,LCD_W,LCD_H,BLUE);
break;
case 3:
LCD_Fill(0,0,LCD_W,LCD_H,RED);
break;
case 4:
LCD_Fill(0,0,LCD_W,LCD_H,MAGENTA);
break;
case 5:
LCD_Fill(0,0,LCD_W,LCD_H,GREEN);
break;
case 6:
LCD_Fill(0,0,LCD_W,LCD_H,CYAN);
break;
case 7:
LCD_Fill(0,0,LCD_W,LCD_H,YELLOW);
break;
case 8:
LCD_Fill(0,0,LCD_W,LCD_H,BRRED);
break;
case 9:
LCD_Fill(0,0,LCD_W,LCD_H,GRAY);
break;
case 10:
LCD_Fill(0,0,LCD_W,LCD_H,LGRAY);
break;
case 11:
LCD_Fill(0,0,LCD_W,LCD_H,BROWN);
break;
}
LCD_ShowChinese(30,20,"0",RED,WHITE,16,0);
LCD_ShowChinese(46,20,"1",RED,WHITE,16,0);
LCD_ShowChinese(62,20,"2",RED,WHITE,16,0);
LCD_ShowChinese(78,20,"3",RED,WHITE,16,0);
LCD_ShowString(10, 50, (const u8 *)"STM32F103ZET6", RED, WHITE, 16, 0);
LCD_ShowString(10, 80, (const u8 *)"TFTLCD TEST", RED,WHITE, 16, 0);
LCD_ShowString(10, 110, (const u8 *)"EEPW.COM.CN", RED, WHITE, 16, 0);
num++;
if (num == 12)
num = 0;
LED0_TOGGLE(); /*红灯闪烁*/
delay_ms(500);
}
}精英板与扩展板及调试器实物连线如下:
扩展板上的触摸显示屏会依次循环刷出12种颜色的背景,展示如下图所示,具体移步优酷:https://v.youku.com/v_show/id_XNjM4MTQ4ODQ4OA==.html

我要赚赏金
