利用彩屏显示图片需要先完成彩屏的驱动程序,然后在驱动程序的基础上再编写应用程序。
彩屏的驱动程序如果写好的话,就可以一直使用了,精力主要集中在应用程序的编写就可以了,但是移植的话,要移植驱动程序。其实移植也只是改变那些很底层的靠近处理器的那部分代码。
因为STM32F103C8的片上只有64K的FLASH,所以不能存储太多的图片数据,也就不能显示太大的图片。
一下的程序注释的比较详细,看懂了基本上就可以用了。
彩屏驱动程序的头文件lcd.h如下:
#define uchar unsigned char
#define uint unsigned int
#define Bus_16 //16位数据模式,如果使用8位模式,请注释此语句,如果使用16位模式,请打开此句
#define LCD_DataPortH P1 //高8位数据口,8位模式下只使用高8位
#define LCD_DataPortL P0 //低8位数据口 ,8位模式下低8位可以不接线
#define LCD_WR GPIO_Pin_2 //WR 引脚定义 P2^5
#define LCD_RS GPIO_Pin_1 //RS 引脚定义 P2^6
#define LCD_CS GPIO_Pin_0 //CS 引脚定义 P2^7
#define LCD_RST GPIO_Pin_11 //RST 引脚定义 P3^3
#define LCD_RD GPIO_Pin_8 //RD 引脚定义 P3^2
#define LCD_SIZE_X 240
#define LCD_SIZE_Y 320
extern uint colors[];
extern void pic_play(uint xStart, uint xEnd, uint yStart, uint yEnd); //显示图片函数
void delayms(int count) ;
//void LCD_Writ_Bus(char VH,char VL);
void LCD_Init(void);
void LCD_Writ_Bus( uint VH, uint VL);
void LCD_Write_COM(char VH,char VL);
void LCD_Write_DATA(char VH,char VL);
void Pant(char VH,char VL);
void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2);
驱动程序lcd.c文件如下:
#include "stm32f10x_lib.h"
#include "Lcd.h"
//存储图片数据的头文件
//#include "picture.h"
#include "picture_sara.h"
#include "xiaoqian.h"
#include "yang.h"
#define LCD_rest(x) x ? GPIO_SetBits(GPIOA, LCD_RST): GPIO_ResetBits(GPIOA, LCD_RST) //自己定义位操作函数
#define LCD_rd(x) x ? GPIO_SetBits(GPIOA, LCD_RD) : GPIO_ResetBits(GPIOA, LCD_RD)
#define LCD_rs(x) x ? GPIO_SetBits(GPIOB, LCD_RS) : GPIO_ResetBits(GPIOB, LCD_RS)
#define LCD_wr(x) x ? GPIO_SetBits(GPIOB, LCD_WR) : GPIO_ResetBits(GPIOB, LCD_WR)
#define LCD_cs(x) x ? GPIO_SetBits(GPIOB, LCD_CS) : GPIO_ResetBits(GPIOB, LCD_CS)
uint colors[]=
{
0xf800,0x07e0,0x001f,0xffe0,0x0000,0x07ff,0xf81f,0xffff //颜色数据
};
void LCD_Init(void) //初始化LCD
{
LCD_rest(1);
delayms(5);
LCD_rest(0);
delayms(5);
LCD_rest(1);
delayms(5);
LCD_cs(0); //打开片选使能
//
LCD_Write_COM(0x00,0xE5); LCD_Write_DATA(0x78,0xF0); // set SRAM internal timing
LCD_Write_COM(0x00,0x01); LCD_Write_DATA(0x01,0x00); // set SS and SM bit
LCD_Write_COM(0x00,0x02); LCD_Write_DATA(0x07,0x00); // set 1 line inversion
LCD_Write_COM(0x00,0x03); LCD_Write_DATA(0x10,0x30); // set GRAM write direction and BGR=1.
LCD_Write_COM(0x00,0x04); LCD_Write_DATA(0x00,0x00); // Resize register
LCD_Write_COM(0x00,0x08); LCD_Write_DATA(0x02,0x07); // set the back porch and front porch
LCD_Write_COM(0x00,0x09); LCD_Write_DATA(0x00,0x00); // set non-display area refresh cycle ISC[3:0]
LCD_Write_COM(0x00,0x0A); LCD_Write_DATA(0x00,0x00); // FMARK function
LCD_Write_COM(0x00,0x0C); LCD_Write_DATA(0x00,0x00); // RGB interface setting
LCD_Write_COM(0x00,0x0D); LCD_Write_DATA(0x00,0x00); // Frame marker Position
LCD_Write_COM(0x00,0x0F); LCD_Write_DATA(0x00,0x00); // RGB interface polarity
//
LCD_Write_COM(0x00,0x10); LCD_Write_DATA(0x00,0x00); // SAP, BT[3:0], AP, DSTB, SLP, STB
LCD_Write_COM(0x00,0x11); LCD_Write_DATA(0x00,0x07); // DC1[2:0], DC0[2:0], VC[2:0]
LCD_Write_COM(0x00,0x12); LCD_Write_DATA(0x00,0x00); // VREG1OUT voltage
LCD_Write_COM(0x00,0x13); LCD_Write_DATA(0x00,0x00); // VDV[4:0] for VCOM amplitude
LCD_Write_COM(0x00,0x07); LCD_Write_DATA(0x00,0x01);
delayms(50); // Dis-charge capacitor power voltage
LCD_Write_COM(0x00,0x10); LCD_Write_DATA(0x10,0x90); // 1490//SAP, BT[3:0], AP, DSTB, SLP, STB
LCD_Write_COM(0x00,0x11); LCD_Write_DATA(0x02,0x27); // DC1[2:0], DC0[2:0], VC[2:0]
delayms(50); // Delay 50ms
LCD_Write_COM(0x00,0x12); LCD_Write_DATA(0x00,0x1F); //001C// Internal reference voltage= Vci;
delayms(50); // Delay 50ms
LCD_Write_COM(0x00,0x13); LCD_Write_DATA(0x15,0x00); //0x1000//1400 Set VDV[4:0] for VCOM amplitude 1A00
LCD_Write_COM(0x00,0x29); LCD_Write_DATA(0x00,0x27); //0x0012 //001a Set VCM[5:0] for VCOMH //0x0025 0034
LCD_Write_COM(0x00,0x2B); LCD_Write_DATA(0x00,0x0D); // Set Frame Rate 000C
delayms(50); // Delay 50ms
LCD_Write_COM(0x00,0x20); LCD_Write_DATA(0x00,0x00); // GRAM horizontal Address
LCD_Write_COM(0x00,0x21); LCD_Write_DATA(0x00,0x00); // GRAM Vertical Address
// ----------- Adjust the Gamma Curve ----------//
LCD_Write_COM(0x00,0x30); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x31); LCD_Write_DATA(0x07,0x07);
LCD_Write_COM(0x00,0x32); LCD_Write_DATA(0x03,0x07);
LCD_Write_COM(0x00,0x35); LCD_Write_DATA(0x02,0x00);
LCD_Write_COM(0x00,0x36); LCD_Write_DATA(0x00,0x08);//0207
LCD_Write_COM(0x00,0x37); LCD_Write_DATA(0x00,0x04);//0306
LCD_Write_COM(0x00,0x38); LCD_Write_DATA(0x00,0x00);//0102
LCD_Write_COM(0x00,0x39); LCD_Write_DATA(0x07,0x07);//0707
LCD_Write_COM(0x00,0x3C); LCD_Write_DATA(0x00,0x02);//0702
LCD_Write_COM(0x00,0x3D); LCD_Write_DATA(0x1D,0x04);//1604
//------------------ Set GRAM area ---------------//
LCD_Write_COM(0x00,0x50); LCD_Write_DATA(0x00,0x00); // Horizontal GRAM Start Address
LCD_Write_COM(0x00,0x51); LCD_Write_DATA(0x00,0xEF); // Horizontal GRAM End Address
LCD_Write_COM(0x00,0x52); LCD_Write_DATA(0x00,0x00); // Vertical GRAM Start Address
LCD_Write_COM(0x00,0x53); LCD_Write_DATA(0x01,0x3F); // Vertical GRAM Start Address
LCD_Write_COM(0x00,0x60); LCD_Write_DATA(0xA7,0x00); // Gate Scan Line
LCD_Write_COM(0x00,0x61); LCD_Write_DATA(0x00,0x01); // NDL,VLE, REV
LCD_Write_COM(0x00,0x6A); LCD_Write_DATA(0x00,0x00); // set scrolling line
//-------------- Partial Display Control ---------//
LCD_Write_COM(0x00,0x80); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x81); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x82); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x83); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x84); LCD_Write_DATA(0x00,0x00);
LCD_Write_COM(0x00,0x85); LCD_Write_DATA(0x00,0x00);
//-------------- Panel Control -------------------//
LCD_Write_COM(0x00,0x90); LCD_Write_DATA(0x00,0x10);
LCD_Write_COM(0x00,0x92); LCD_Write_DATA(0x06,0x00);
LCD_Write_COM(0x00,0x07); LCD_Write_DATA(0x01,0x33); // 262K color and display ON
LCD_cs(1); //关闭片选使能
}
void delayms(int count) //
{
int i,j;
for(i=0;i<count;i++)
for(j=0;j<100;j++);
}
#ifdef Bus_16 //条件编译-16位数据模式
void LCD_Writ_Bus(uint VH , uint VL) //并行数据写入函数
{
//LCD_DataPortH=VH; //高位P1口
//屏蔽高8位 将数据送到PA0-PA7
GPIOA->BSRR = VH & 0x00ff;
GPIOA->BRR = (~VH) & 0x00ff;
//GPIO_SetBits(GPIOA, VH & 0x00ff);
//GPIO_ResetBits(GPIOA, (~ VH & 0x00ff));
//LCD_DataPortL=VL; //低位P0口
//屏蔽低8位 将数据送到PB8-PB15
GPIOB->BSRR = (VL)<<8 & 0xff00;
GPIOB->BRR = ((~VL)<<8) & 0xff00;
LCD_wr(0);
LCD_wr(1);
}
#else //条件编译-8位数据模式
void LCD_Writ_Bus(char VH,char VL) //并行数据写入函数
{
//LCD_DataPortH=VH; //八位模式都用P0口送数据
//LCD_wr(0);
//LCD_wr(1);
//LCD_DataPortH=VL; //八位模式都用P0口送数据
//LCD_wr(0);
//LCD_wr(1);
}
#endif
void LCD_Write_COM(char VH,char VL) //发送命令
{
LCD_rs(0);
LCD_Writ_Bus(VH,VL);
}
void LCD_Write_DATA(char VH,char VL) //发送数据
{
LCD_rs(1);
LCD_Writ_Bus(VH,VL);
}
void Pant(char VH,char VL) //涂满全屏函数
{
int i,j;
LCD_cs(0); //打开片选使能
Address_set(0,0,239,319);
for(i=0;i<320;i++)
{
for (j=0;j<240;j++)
{
LCD_Write_DATA(VH,VL);
}
}
LCD_cs(1); //关闭片选使能
}
void Address_set(unsigned int x1,unsigned int y1,unsigned int x2,unsigned int y2) //设置地址范围函数
{
LCD_Write_COM(0x00,0x20);LCD_Write_DATA(x1>>8,x1); //设置X坐标位置
LCD_Write_COM(0x00,0x21);LCD_Write_DATA(y1>>8,y1); //设置Y坐标位置
LCD_Write_COM(0x00,0x50);LCD_Write_DATA(x1>>8,x1); //开始X
LCD_Write_COM(0x00,0x52);LCD_Write_DATA(y1>>8,y1); //开始Y
LCD_Write_COM(0x00,0x51);LCD_Write_DATA(x2>>8,x2); //结束X
LCD_Write_COM(0x00,0x53);LCD_Write_DATA(y2>>8,y2); //结束Y
LCD_Write_COM(0x00,0x22);
}
void pic_play(uint Start_X, uint End_X,uint Start_Y,uint End_Y)
{
uint m;
//LCD_CS = 0;
GPIO_ResetBits(GPIOB,LCD_CS); //打开片选
Address_set(Start_X,Start_Y,End_X,End_Y) ; //指定图片显示的范围
// LCD_RS = 1;
GPIO_SetBits(GPIOB, LCD_RS); //关闭片选
//循环把图片的所有数据依次写入
Address_set(0,0,141,79); //用彩屏显示图片时,一定要注意图片长宽比例,如果长宽比例不对的话,显示的图片就会变形
//例如本幅图片取模软件输出的长宽为(177,100),所以在这里图片的显示范围必须设为(0,0,176,99),即x范围为0~176,y的范围为
//0~99.这样图片才能正常显示,否则图片就会变形。
for(m=0;m<22728/2;m++) //这里的35400这个数字指定显示图片的范围,因为该图的数据总共只有35400个,所以这里指定
//整幅图都显示出来。如果这个数比35400小,则只显示该图的一部分。
{
LCD_Write_DATA(gImage_sara[m*2+1],gImage_sara[m*2]);
}
Address_set(0,90,65,189); //一定要注意保持比例
for(m=0;m<13200/2;m++)
{
LCD_Write_DATA(gImage_xiaoqian[m*2+1],gImage_xiaoqian[m*2]);
}
Address_set(75,90,137,189); //一定要注意保持比例
for(m=0;m<12600/2;m++)
{
LCD_Write_DATA(gImage_yang[m*2+1],gImage_yang[m*2]);
}
//LCD_CS = 1;
GPIO_SetBits(GPIOB, LCD_CS); //关闭片选
}
主程序main.c
在主程序中完成对系统的初始化配置,利用彩屏的驱动程序完成图片的显示等功能,程序如下:
#include "stm32f10x_lib.h"
#include "lcd.h"
GPIO_InitTypeDef GPIO_InitStructure; //定义GPIO初始化的结构体变量
ErrorStatus HSEStartUpStatus; //定义错误状态变量,为枚举类型
void RCC_Configuration(void);
void NVIC_Configuration(void);
void Delay(vu32 nCount);
int main(void)
{
#ifdef DEBUG
debug(); //在线调试使用
#endif
RCC_Configuration(); //系统时钟配置函数
NVIC_Configuration(); //NVIC配置函数
//启动GPIO模块时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
//把调试设置普通IO口 禁止SWJ
GPIO_PinRemapConfig(GPIO_Remap_SWJ_Disable,ENABLE);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All; //所有GPIO为同一类型端口
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //输出的最大频率为50HZ
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化GPIOA端口
GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化GPIOB端口
GPIO_Write(GPIOA,0xffff); //将GPIOA 16个端口全部置为高电平
GPIO_Write(GPIOB,0xffff); //将GPIOB 16个端口全部置为高电平
LCD_Init(); //初始化LCD
//LCD_clear(6); //清屏为紫色
Pant(colors[6]>>8,colors[6]); //把全屏涂满紫色
pic_play(0,173,0,173); //显示图片
//pic_play(7,61,8,74); //显示图片
// pic_play(68,122,8,74);
// pic_play(7,61,82,148);
// pic_play(68,122,82,148);
while(1);
}
void RCC_Configuration(void)
{
//复位RCC外部设备寄存器到默认值
RCC_DeInit();
//打开外部高速晶振
RCC_HSEConfig(RCC_HSE_ON);
//等待外部高速时钟准备好
HSEStartUpStatus = RCC_WaitForHSEStartUp();
if(HSEStartUpStatus == SUCCESS) //外部高速时钟已经准别好
{
//开启FLASH的预取功能
FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);
//FLASH延迟2个周期
FLASH_SetLatency(FLASH_Latency_2);
//配置AHB(HCLK)时钟=SYSCLK
RCC_HCLKConfig(RCC_SYSCLK_Div1);
//配置APB2(PCLK2)钟=AHB时钟
RCC_PCLK2Config(RCC_HCLK_Div1);
//配置APB1(PCLK1)钟=AHB 1/2时钟
RCC_PCLK1Config(RCC_HCLK_Div2);
//配置PLL时钟 == 外部高速晶体时钟*9 PLLCLK = 8MHz * 9 = 72 MHz
RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);
//使能PLL时钟
RCC_PLLCmd(ENABLE);
//等待PLL时钟就绪
while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)
{
}
//配置系统时钟 = PLL时钟
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);
//检查PLL时钟是否作为系统时钟
while(RCC_GetSYSCLKSource() != 0x08)
{
}
}
}
void NVIC_Configuration(void)
{
#ifdef VECT_TAB_RAM
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
}
void Delay(vu32 nCount)
{
for(; nCount != 0; nCount--);
}
#ifdef DEBUG
void assert_failed(u8* file, u32 line)
{
while (1)
{
}
}
#endif