1.初始化IO口
初始化IO是最底层,我们就从最底层来看是如何一步一步把程序驱动起来的.
#ifndef BSP_LCD_H
#define BSP_LCD_H
#include "stm32f10x.h"
void bsp_spi_init(void);
void bsp_gpio_init(void);
u8 bsp_spi_write(u8 Byte);
#endif
#include "bsp_lcd.h"
/*******************************************************************
此文件主要是对屏幕外设所接的引脚做初始化
*******************************************************************/
/******************************定义屏幕的IO接口*********************
PB13 : SPI时钟
PB15 : MOSI
PD9 : 复位
PD11 : 数据命令选择引脚
PD13 : 背光,这里没用PWM控制,直接接了IO口
*******************************************************************/
/*******************************************************************
函数功能:
SPI初始化
参数:
返回值:
说明:
这里只用到了SPI的MOSI,所以MISO没进行初始化
*******************************************************************/
void bsp_spi_init(void)
{
SPI_InitTypeDef SPI_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
//配置SPI2管脚
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO|RCC_APB2Periph_GPIOB, ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13 | GPIO_Pin_15;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOB, &GPIO_InitStructure);
//SPI2配置选项
RCC_APB1PeriphClockCmd(RCC_APB1Periph_SPI2 ,ENABLE);
SPI_InitStructure.SPI_Direction = SPI_Direction_2Lines_FullDuplex;
SPI_InitStructure.SPI_Mode = SPI_Mode_Master;
SPI_InitStructure.SPI_DataSize = SPI_DataSize_8b;
SPI_InitStructure.SPI_CPOL = SPI_CPOL_High;
SPI_InitStructure.SPI_CPHA = SPI_CPHA_2Edge;
SPI_InitStructure.SPI_NSS = SPI_NSS_Soft;
SPI_InitStructure.SPI_BaudRatePrescaler = SPI_BaudRatePrescaler_2;
SPI_InitStructure.SPI_FirstBit = SPI_FirstBit_MSB;
SPI_InitStructure.SPI_CRCPolynomial = 7;
SPI_Init(SPI2, &SPI_InitStructure);
//使能SPI2
SPI_Cmd(SPI2, ENABLE);
}
/*******************************************************************
函数功能:
对lcd其他三个引脚初始化
参数:
返回值:
说明:
全部设为推完输出,
*******************************************************************/
void bsp_gpio_init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOD ,ENABLE); //使能GPIOB时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9| GPIO_Pin_11| GPIO_Pin_13;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOD, &GPIO_InitStructure);//初始化
GPIO_SetBits(GPIOD,GPIO_Pin_9| GPIO_Pin_11| GPIO_Pin_13);
}
/*******************************************************************
函数功能:
SPI写函数
参数:
Byte:写入一个字节
返回值:
返回读到的值,这里没有初始化SPI的MISO,忽视返回值
说明:
*******************************************************************/
u8 bsp_spi_write(u8 Byte)
{
while((SPI2->SR&SPI_I2S_FLAG_TXE)==RESET); //等待发送区空
SPI2->DR=Byte; //发送一个byte
while((SPI2->SR&SPI_I2S_FLAG_RXNE)==RESET);//等待接收完一个byte
return SPI2->DR; //返回收到的数据
}
2.初始化屏幕
初始化屏幕这一层向外暴露3个函数,一个初始化,一个画点,一个填充矩形区域.(在移植LVGL时需要调用填充矩形区域这个函数)
#ifndef DEV_LCD_H
#define DEV_LCD_H
#include "stm32f10x.h"
#include "bsp_lcd.h"
/***************************宏替换硬件操作函数********************************/
#define LCD_SPI_WRITE(data) bsp_spi_write(data)
#define LCD_WRITE_REG_CMD() GPIO_ResetBits(GPIOD, GPIO_Pin_11)
#define LCD_WRITE_DATA_CMD() GPIO_SetBits(GPIOD, GPIO_Pin_11)
#define LCD_RESET_CONTRL() GPIO_ResetBits(GPIOD, GPIO_Pin_9)
#define LCD_SET_CONTRL() GPIO_SetBits(GPIOD, GPIO_Pin_9)
/***************************************************************************/
/******************************寄存器地址 ********************************/
#define SET_X_CMD 0x2A
#define SET_Y_CMD 0x2B
#define WRITE_GRAM_CMD 0x2C
/***************************************************************************/
/***************************用宏定义一些重要的参数********************************/
//定义屏幕的大小
#define LCD_W 240
#define LCD_H 240
//画笔颜色
#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 GRAY0 0xEF7D
#define GRAY1 0x8410 //灰色1 00000 000000 00000
#define GRAY2 0x4208
#define DARKBLUE 0X01CF //深蓝色
#define LIGHTBLUE 0X7D7C //浅蓝色
#define GRAYBLUE 0X5458 //灰蓝色
#define LIGHTGREEN 0X841F //浅绿色
#define LIGHTGRAY 0XEF5B //浅灰色(PANNEL)
#define LGRAY 0XC618 //浅灰色(PANNEL),窗体背景色
#define LGRAYBLUE 0XA651 //浅灰蓝色(中间层颜色)
#define LBBLUE 0X2B12 //浅棕蓝色(选择条目的反色)
/***************************************************************************/
//LCD参数
typedef struct
{
u16 width; //LCD 宽度
u16 height; //LCD 高度
u8 dir; //横屏还是竖屏控制:0,竖屏;1,横屏。
u16 write_gram_cmd; //开始写gram指令
u16 set_x_cmd; //设置x坐标指令
u16 set_y_cmd; //设置y坐标指令
u8 x_offset;
u8 y_offset;
}lcd_dev_t;
void dev_lcd_init(void);
void LCD_DrawPoint(u16 x,u16 y, u16 color);
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color);
#endif
#include "dev_lcd.h"
/*******************************************************************
此文件主要对屏幕初始化
*******************************************************************/
lcd_dev_t lcd_dev; /*创建一个lcd设备*/
/*******************************************************************
函数功能:
延时
参数:
返回值:
说明:
*******************************************************************/
static void lcd_delay_ms(u32 i)
{
i = i * 4000;
while(i--);
}
/*******************************************************************
函数功能:
告诉ST7789要操作的寄存器的地址
参数:
返回值:
说明:
*******************************************************************/
void LCD_WR_REG(u8 data)
{
LCD_WRITE_REG_CMD();
LCD_SPI_WRITE(data);
}
/*******************************************************************
函数功能:
告诉ST7789写入的是数据
参数:
返回值:
说明:
*******************************************************************/
void LCD_WR_DATA(u8 data)
{
LCD_WRITE_DATA_CMD();
LCD_SPI_WRITE(data);
}
/*******************************************************************
函数功能:
LCD复位
参数:
返回值:
说明:
*******************************************************************/
void LCD_RESET(void)
{
LCD_RESET_CONTRL();
lcd_delay_ms(20);
LCD_SET_CONTRL();
lcd_delay_ms(20);
}
/*******************************************************************
函数功能:
向ST7789指定的寄存器中写入数据
参数:
返回值:
说明:
*******************************************************************/
void LCD_WriteReg(u8 LCD_Reg, u16 LCD_RegValue)
{
LCD_WR_REG(LCD_Reg);
LCD_SPI_WRITE(LCD_RegValue >> 8);
LCD_SPI_WRITE(LCD_RegValue);
}
/*******************************************************************
函数功能:
准备向gram中写入数据,也就是颜色信息
参数:
返回值:
说明:
*******************************************************************/
void LCD_Prepare_Write_GRAM(void)
{
LCD_WR_REG(lcd_dev.write_gram_cmd);
}
/*******************************************************************
函数功能:
写入一个16bit的数据
参数:
返回值:
说明:
*******************************************************************/
void Lcd_WriteData_16Bit(u16 Data)
{
LCD_WRITE_DATA_CMD();
LCD_SPI_WRITE(Data >> 8);
LCD_SPI_WRITE(Data);
}
/*******************************************************************
函数功能:
设置显示窗口大小
参数:
xStart,yStart,xEnd,yEnd:起始和结束的坐标
返回值:
说明:
*******************************************************************/
void LCD_SetWindows(u16 xStart, u16 yStart,u16 xEnd,u16 yEnd)
{
//设置起始点和结束点x轴的坐标
LCD_WR_REG(lcd_dev.set_x_cmd);
LCD_WR_DATA((xStart+lcd_dev.x_offset)>>8);
LCD_WR_DATA(xStart+lcd_dev.x_offset);
LCD_WR_DATA((xEnd+lcd_dev.x_offset)>>8);
LCD_WR_DATA(xEnd+lcd_dev.x_offset);
//设置起始点和结束点y轴的坐标
LCD_WR_REG(lcd_dev.set_y_cmd);
LCD_WR_DATA((yStart+lcd_dev.y_offset)>>8);
LCD_WR_DATA(yStart+lcd_dev.y_offset);
LCD_WR_DATA((yEnd+lcd_dev.y_offset)>>8);
LCD_WR_DATA(yEnd+lcd_dev.y_offset);
//开始写入GRAM
LCD_Prepare_Write_GRAM();
}
/*******************************************************************
函数功能:
设置光标位置
参数:
Xpos,Ypos:光标位置
返回值:
说明:
*******************************************************************/
void LCD_SetCursor(u16 Xpos, u16 Ypos)
{
LCD_SetWindows(Xpos,Ypos,Xpos,Ypos);
}
/*******************************************************************
函数功能:
LCD显示的方向
参数:
Xpos,Ypos:光标位置
返回值:
说明:
*******************************************************************/
void LCD_direction(u8 direction)
{
lcd_dev.set_x_cmd = SET_X_CMD;
lcd_dev.set_y_cmd = SET_Y_CMD;
lcd_dev.write_gram_cmd = WRITE_GRAM_CMD;
switch(direction){
case 0:
lcd_dev.width = LCD_W;
lcd_dev.height = LCD_H;
lcd_dev.x_offset = 0;
lcd_dev.y_offset = 0;
LCD_WriteReg(0x36, 0);//BGR==1,MY==0,MX==0,MV==0
break;
case 1:
lcd_dev.width = LCD_H;
lcd_dev.height = LCD_W;
lcd_dev.x_offset = 0;
lcd_dev.y_offset = 0;
LCD_WriteReg(0x36,(1<<6)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
case 2:
lcd_dev.width = LCD_W;
lcd_dev.height = LCD_H;
lcd_dev.x_offset=0;
lcd_dev.y_offset = 80;
LCD_WriteReg(0x36,(1<<6)|(1<<7));//BGR==1,MY==0,MX==0,MV==0
break;
case 3:
lcd_dev.width = LCD_H;
lcd_dev.height = LCD_W;
lcd_dev.x_offset = 80;
lcd_dev.y_offset = 0;
LCD_WriteReg(0x36,(1<<7)|(1<<5));//BGR==1,MY==1,MX==0,MV==1
break;
default:break;
}
}
/*******************************************************************
函数功能:
LCD初始化
参数:
返回值:
说明:
*******************************************************************/
void LCD_Clear(u16 Color)
{
unsigned int i,m;
LCD_SetWindows(0,0,lcd_dev.width-1,lcd_dev.height-1);
// LCD_WRITE_DATA_CMD();
for(i = 0; i < lcd_dev.height; i++)
{
for(m = 0; m < lcd_dev.width; m++)
{
// LCD_SPI_WRITE(Color >> 8);
// LCD_SPI_WRITE(Color);
Lcd_WriteData_16Bit(Color);
}
}
}
void dev_lcd_init(void)
{
LCD_RESET(); //LCD 复位
//************* ST7789初始化**********//
LCD_WR_REG(0x36);
LCD_WR_DATA(0x00);
LCD_WR_REG(0x3A);
LCD_WR_DATA(0x05);
LCD_WR_REG(0xB2);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x00);
LCD_WR_DATA(0x33);
LCD_WR_DATA(0x33);
LCD_WR_REG(0xB7);
LCD_WR_DATA(0x35);
LCD_WR_REG(0xBB);
LCD_WR_DATA(0x19);
LCD_WR_REG(0xC0);
LCD_WR_DATA(0x2C);
LCD_WR_REG(0xC2);
LCD_WR_DATA(0x01);
LCD_WR_REG(0xC3);
LCD_WR_DATA(0x12);
LCD_WR_REG(0xC4);
LCD_WR_DATA(0x20);
LCD_WR_REG(0xC6);
LCD_WR_DATA(0x0F);
LCD_WR_REG(0xD0);
LCD_WR_DATA(0xA4);
LCD_WR_DATA(0xA1);
LCD_WR_REG(0xE0);
LCD_WR_DATA(0xD0);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x13);
LCD_WR_DATA(0x2B);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x54);
LCD_WR_DATA(0x4C);
LCD_WR_DATA(0x18);
LCD_WR_DATA(0x0D);
LCD_WR_DATA(0x0B);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x23);
LCD_WR_REG(0xE1);
LCD_WR_DATA(0xD0);
LCD_WR_DATA(0x04);
LCD_WR_DATA(0x0C);
LCD_WR_DATA(0x11);
LCD_WR_DATA(0x13);
LCD_WR_DATA(0x2C);
LCD_WR_DATA(0x3F);
LCD_WR_DATA(0x44);
LCD_WR_DATA(0x51);
LCD_WR_DATA(0x2F);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x1F);
LCD_WR_DATA(0x20);
LCD_WR_DATA(0x23);
LCD_WR_REG(0x21);
LCD_WR_REG(0x11);
LCD_WR_REG(0x29);
LCD_direction(0);//设置LCD显示方向
LCD_Clear(WHITE);//清全屏白色
}
/*******************************************************************
函数功能:
画点
参数:
x,y坐标,color,点的颜色
返回值:
说明:
*******************************************************************/
void LCD_DrawPoint(u16 x, u16 y, u16 color)
{
LCD_SetCursor(x, y);//设置光标位置
Lcd_WriteData_16Bit(color);
}
/*******************************************************************
函数功能:
在屏幕矩形范围内填充颜色
参数:
返回值:
说明:注意sx,sy要比ex,ey小
*******************************************************************/
void LCD_Fill(u16 sx,u16 sy,u16 ex,u16 ey,u16 color)
{
u16 i,j;
u16 width=ex-sx+1; //得到填充的宽度
u16 height=ey-sy+1; //高度
LCD_SetWindows(sx,sy,ex,ey);//设置显示窗口
for(i=0;i<width;i++)
{
for(j=0;j<height;j++)
{
Lcd_WriteData_16Bit(color);
}
}
LCD_SetWindows(0,0,lcd_dev.width-1,lcd_dev.height-1);//恢复窗口设置为全屏
}
3.UI函数
这一层主要调用设备层的画点和填充矩形区域,来完成一些复杂的画图功能.
#ifndef MID_UI_H
#define MID_UI_H
#include "dev_lcd.h"
#define LCD_DRAW_POINT(x, y, color) LCD_DrawPoint(x, y, color)
#define LCD_FILL_COLOR(x, y, x1, y1, color) LCD_Fill(x, y, x1, y1, color)
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2);
#endif
#include"mid_ui.h"
void LCD_DrawLine(u16 x1, u16 y1, u16 x2, u16 y2)
{
u16 t;
int xerr=0,yerr=0,delta_x,delta_y,distance;
int incx,incy,uRow,uCol;
delta_x=x2-x1; //计算坐标增量
delta_y=y2-y1;
uRow=x1;
uCol=y1;
if(delta_x>0)incx=1; //设置单步方向
else if(delta_x==0)incx=0;//垂直线
else {incx=-1;delta_x=-delta_x;}
if(delta_y>0)incy=1;
else if(delta_y==0)incy=0;//水平线
else{incy=-1;delta_y=-delta_y;}
if( delta_x>delta_y)distance=delta_x; //选取基本增量坐标轴
else distance=delta_y;
for(t=0;t<=distance+1;t++ )//画线输出
{
LCD_DRAW_POINT(uRow,uCol, RED);//画点
xerr+=delta_x ;
yerr+=delta_y ;
if(xerr>distance)
{
xerr-=distance;
uRow+=incx;
}
if(yerr>distance)
{
yerr-=distance;
uCol+=incy;
}
}
}
4.调用函数实现画图
#include "stm32f10x.h"
#include "bsp_lcd.h"
#include "dev_lcd.h"
#include "mid_ui.h"
int main(void)
{
unsigned int i,m;
bsp_spi_init();
bsp_gpio_init();
dev_lcd_init();
LCD_Fill(20,20,80, 80, RED);
LCD_DrawLine(100, 20, 60, 200);
while(1)
{
}
}