STM32单片机串行方式控制st7920 128*64屏显示字符,附件里面有2个程序,全部都是经过测试ok的
单片机源程序如下:
- /**********************************************************
- * @ File name -> lcd12864.c
- * @ Version -> V1.1.2
- * @ Date -> 11-30-13
- * @ Brief -> LCD12864驱动函数
- * 适用于ST7920驱动芯片
- V1.1
- * @ Revise -> A、修正操作命令宏定义。
- * @ -> B、增加串口、并口转换宏定义,增加对高速度MCU控制通讯频率延时函数
- * @ -> C、显示字符串函数增加显示长度选择,即显示多少个ASCII可显示字符,汉字x2即可
- * @ -> D、去掉显示数组函数,合并在字符串显示里
- V1.1.1
- * @ Revise -> 增加字符串显示函数,可以从要显示的数组中任意位置显示一定长度字符串
- V1.1.2
- * @ Revise -> A、增加对低速晶振系统的MCU通讯频率是否使用的宏定义
- * @ -> B、增加在检测液晶忙超时退出,预防死循环
- **********************************************************/
- #include "lcd12864.h"
- /**********************************************************
- 自定义显示字符
- **********************************************************/
- #define CGRAM_Value 64 //写入CGRAM数量
- u8 code CGROM_Code[] = {
- //天线图形
- 0xff,0xff,0x80,0x01,0xbf,0xfd,0xdf,0xfb,0xec,0x37,0xf6,0x6f,0xfb,0xdf,0xfd,0xbf,
- 0xfe,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe,0x7f,0xfe,0x7f,0xff,0xff,
- //摄氏图形
- // 0x00,0x00,0x00,0x00,0x00,0x00,0x1c,0x70,0x14,0xd8,0x1d,0x88,0x01,0x80,0x01,0x80,
- // 0x01,0x80,0x01,0x80,0x01,0x88,0x00,0xc8,0x00,0x70,0x00,0x00,0x00,0x00,0x00,0x00,
- //蓝牙图形
- 0x07,0xe0,0x0e,0x70,0x1e,0xb8,0x3e,0xdc,0x36,0xec,0x3a,0xdc,0x3c,0xbc,0x3e,0x7c,
- 0x3e,0x7c,0x3c,0xbc,0x3a,0xdc,0x36,0xec,0x3e,0xdc,0x1e,0xb8,0x0e,0x70,0x07,0xe0,
- //CD图形
- 0xff,0xff,0xff,0xff,0xff,0xff,0xe3,0x07,0xc9,0xb3,0x9d,0xb9,0x9f,0xb9,0x9f,0xb9,
- 0x9f,0xb9,0x9f,0xb9,0x9d,0xb9,0xc9,0xb3,0xe3,0x07,0xff,0xff,0xff,0xff,0xff,0xff,
- //右指向手型
- 0x00,0x00,0x1e,0x00,0x12,0x00,0x73,0xfc,0x52,0x02,0x52,0x1c,0x53,0xe0,0x52,0x10,
- 0x53,0xe0,0x52,0x10,0x53,0xe0,0x52,0x10,0x73,0xe0,0x12,0x00,0x1e,0x00,0x00,0x00
- };
- //=========================================================
- #ifdef LCD_Work_Mode //如果定义了,则使用并口工作模式
- //=========================================================
- /**********************************************************
- * 函数功能 ---> LCD12864判断忙
- * 入口参数 ---> none
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void LCD_Check_Busy(void)
- {
- static u16 busytimeout; //忙超时
- //=====================================================
- #ifdef LCD_USE_DELAY /* 定义了则使用延时调整通讯频率 */
- //=====================================================
- ktdata = 0xf0; //数据口全部置位
- do
- {
- busytimeout++;
- if(busytimeout > 300) break;
- LCD_RS = 0;
- LCD_Delay();
- LCD_RW = 1;
- LCD_Delay();
- LCD_EN = 1;
- LCD_Delay();
- }while(ktdata & LCD_Busy == LCD_Busy); //等待LCD忙完
- LCD_EN = 0;
- //=====================================================
- #else /* 没定义则不使用 */
- //=====================================================
- ktdata = 0xf0; //数据口全部置位
- do
- {
- busytimeout++;
- if(busytimeout > 300) break;
- LCD_RS = 0;
- LCD_RW = 1;
- LCD_EN = 1;
- // LCD_Delay();
- }while(ktdata & LCD_Busy == LCD_Busy); //等待LCD忙完
- LCD_EN = 0;
- //=====================================================
- #endif
- //=====================================================
- if(busytimeout >= 300) printf("LCD Busy TimeOut...rn");
- busytimeout = 0;
- }
- /**********************************************************
- * 函数功能 ---> LCD写入一个字节命令或者数据,判断忙标志(8位数据一次发送完毕)
- * 入口参数 ---> dat:要写入的字节
- * ord:判断dat是命令还是数据依据,“0”为命令,“1”为数据
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void LCD_Write_Byte(u8 dat,u8 ord)
- {
- //=====================================================
- #ifdef LCD_USE_DELAY /* 定义了则使用延时调整通讯频率 */
- //=====================================================
- LCD_Check_Busy(); //判断是否在忙?
- LCD_EN = 0;
- LCD_Delay();
- LCD_RW = 0;
- LCD_Delay();
- if(ord & 0x01) LCD_RS = 1; //放上数据或者命令判断位
- else LCD_RS = 0;
- LCD_EN = 1;
- LCD_Delay();
- ktdata = dat; //放入数据
- LCD_Delay();
- LCD_EN = 0;
- //=====================================================
- #else /* 没定义则不使用 */
- //=====================================================
- LCD_Check_Busy(); //判断是否在忙?
- LCD_EN = 0;
- LCD_RW = 0;
- if(ord & 0x01) LCD_RS = 1; //放上数据或者命令判断位
- else LCD_RS = 0;
- LCD_EN = 1;
- ktdata = dat; //放入数据
- LCD_EN = 0;
- //=====================================================
- #endif
- //=====================================================
- }
- //=========================================================
- #else //没定义则使用串口通讯模式
- //=========================================================
- /**********************************************************
- * 函数功能 ---> LCD启动字节
- * 入口参数 ---> dt:传输的字节,高5位在函数内部设定为1
- * 只是确定RW和RS为,最后那位也是内部确定
- * 返回数值 ---> none
- * 功能说明 ---> 首先传送一个启动字节,送入连续5个“1”用来启
- * 动一个周期,此时传输计数被重置,并且串行传输
- * 被同步,紧接着的两个位指定传输方向(R/W,确
- * 定是读还是写)和传输性质(RS,确定是命令寄存
- * 器还是数据寄存器),最后的第八位是一个“0”
- **********************************************************/
- void LCD12864_Start(u8 dt)
- {
- u8 dat,j;
- dat = dt | 0xf8; //高5位设定为“1”,第八位设定为“0”
- LCD_SCL = 0;
- LCD_Delay();LCD_Delay();
- LCD_CS = 1; //选中显示屏,高电平有效
- for(j = 0;j < 8;j++)
- {
- if(dat & 0x80) LCD_SDA = 1; //放数据到数据线
- else LCD_SDA = 0;
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 1; //发送数据,上升沿有效
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 0;
- dat <<= 1; //左移一位,先发的是高位
- }
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 0;
- LCD_Delay();LCD_Delay();LCD_Delay(); //等待硬件反应(等待数据发送完全)
- }
- /**********************************************************
- * 函数功能 ---> LCD写入一个字节命令或者数据
- * 入口参数 ---> dat:要写入的命令或者数据
- * ord:命令或者数据判断为。0为命令,1为数据
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void LCD_Write_Byte(u8 dat,u8 ord)
- {
- u8 tem;
- u8 i,j;
- tem = dat & 0xf0; //先发送高4位
- LCD12864_Start((ord << 1) | 0xf0); //置RW为“0”、RS为“ord”并启动串行传输为数据格式
- for(j = 0;j < 2;j++) //一个字节数据或者命令分两次发送
- {
- LCD_SCL = 0; //允许数据线电平变化
- LCD_Delay();LCD_Delay();LCD_Delay();
- for(i = 0;i < 8;i++)
- {
- if(tem & 0x80) LCD_SDA = 1; //放上数据,屏蔽低4位
- else LCD_SDA = 0;
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 1; //发送数据,上升沿有效
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 0;
- tem <<= 1; //左移一位,先发的是高位
- }
- tem = (dat << 4) & 0xf0; //发完高4位,再次发送低4位
- }
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SDA = 0;
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_SCL = 0;
- LCD_Delay();LCD_Delay();LCD_Delay();
- LCD_CS = 0;
- LCD_Delay();LCD_Delay();LCD_Delay(); //等待硬件反应(等待数据发送完全)
- }
- //=========================================================
- #endif
- //=========================================================
- /**********************************************************
- * 函数功能 ---> 设置LCD显示位置
- * 入口参数 ---> x:行,取值范围:1 ~ 4
- * y:列,取值范围:0 ~ 7
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void LCD_Set_xy(u8 x,u8 y)
- {
- switch(x)
- {
- case 1:
- LCD_Write_Byte((One_LineAddress + y),0); //写入操作地址
- break;
- case 2:
- LCD_Write_Byte((Two_LineAddress + y),0); //写入操作地址
- break;
- case 3:
- LCD_Write_Byte((Three_LineAddress + y),0); //写入操作地址
- break;
- case 4:
- LCD_Write_Byte((Four_LineAddress + y),0); //写入操作地址
- break;
- default:
- LCD_Write_Byte((One_LineAddress + y),0); //写入操作地址
- break;
- }
- }
- /**********************************************************
- * 函数功能 ---> 写入自定义字符到LCD的CGRAM
- * 入口参数 ---> *data_code:写入的数组
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void LCD_Write_CGRAM(u8 *data_code)
- {
- u8 i;
- LCD_Write_Byte(0x34,0); //打开字符扩展指令
- LCD_Write_Byte(0x02,0); //SR=0,允许输入
- LCD_Write_Byte(0x30,0); //恢复基本指令
- LCD_Write_Byte(0x40,0); //CGRAM地址
- for(i = 0;i < CGRAM_Value;i++)
- {
- LCD_Write_Byte(data_code[i*2],1);
- LCD_Write_Byte(data_code[i*2+1],1);
- }
- }
- /**********************************************************
- * 函数功能 ---> 显示一个CGRAM内容
- * 入口参数 ---> x:行
- * y:列
- * *str为要显示的字符串
- * add_h:CGRAM高位地址
- * add_l:CGRAM低位地址
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void Display_CGRAM(u8 x,u8 y,u8 add_h,u8 add_l)
- {
- LCD_Set_xy(x,y); //设置显示地址
- LCD_Write_Byte(add_h,1);
- LCD_Write_Byte(add_l,1);
- }
- /**********************************************************
- * 函数功能 ---> LCD显示字符串
- * 入口参数 ---> x:行
- * y:列
- * *str:要显示的字符串
- * len:显示的长度
- * 返回数值 ---> none
- * 功能说明 ---> 只能从数组的开头开始显示len长度字符串
- **********************************************************/
- void Display_String(u8 x,u8 y,u8 *str,u8 len)
- {
- LCD_Set_xy(x,y); //设置显示地址
- while(len--)
- {
- LCD_Write_Byte(*str,1);
- str++;
- }
- }
- /**********************************************************
- * 函数功能 ---> LCD显示字符串
- * 入口参数 ---> x:行
- * y:列
- * *str:要显示的字符串
- * len:显示的长度
- * 返回数值 ---> none
- * 功能说明 ---> 可以从显示数组的任意位置starsum开始显示len长度的字符串
- **********************************************************/
- void Display_String1(u8 x,u8 y,u8 *str,u8 starsum,u8 len)
- {
- u8 i;
- LCD_Set_xy(x,y); //设置显示地址
- for(i = starsum;i < starsum + len;i++)
- {
- LCD_Write_Byte(str,1);
- }
- }
- /**********************************************************
- * 函数功能 ---> LCD写入GDRAM绘图
- * 入口参数 ---> x:行
- * y:列
- * width:显示图片的宽度
- * hieght:显示图片的高度
- * *bmp:要显示的字符串
- * dis_mode:显示模式,是半屏显示还是全屏显示
- * 0:半屏显示。1:全屏显示
- * 返回数值 ---> none
- * 功能说明 ---> none
- **********************************************************/
- void Display_GDRAM(u8 x,u8 y,u8 width,u8 height,u8 *bmp,u8 dis_mode)
- {
- u8 i,j,k;
- u8 base_x,base_y; //起始坐标
- /******全屏绘图显示******/
- if(dis_mode)
- {
- switch(x)
- {
- case 1:
- base_y = One_LineAddress + y;
- break;
- case 2:
- base_y = Two_LineAddress + y;
- break;
- case 3:
- base_y = Three_LineAddress + y;
- break;
- case 4:
- base_y = Four_LineAddress + y;
- break;
- default: break;
- }
- LCD_Write_Byte(MPU_8bit_Expansion_Draw_Close,0); //扩充指令
- LCD_Write_Byte(MPU_8bit_Expansion_Draw_Open,0); //打开绘图功能
- for(j = 0;j < height;j++) //32
- {
- LCD_Write_Byte(base_y + j,0); //写入行号,即第几行开始
- LCD_Write_Byte(One_LineAddress,0); //横坐标的第几个字节开始写
- for(i = 0;i < width;i++) //上半屏
- {
- LCD_Write_Byte(bmp[width * j + i],1); //开始写入数据
- }
- for(k = 0;k < width;k++) //下半屏
- {
- LCD_Write_Byte(bmp[width * (j + height) + k],1); //开始写入数据
- }
- }
- }
- /******分开上半屏或者下半屏写******/
- else
- {
- switch(x) //判断显示的横坐标,确定起始行
- {
- case 1: //上半屏
- base_x = One_LineAddress; //起始地址为0x80
- break;
- case 2: //下半屏
- base_x = One_LineAddress; //起始地址为0x80
- break;
- case 3: //下半屏
- base_x = Three_LineAddress; //起始地址为0x88
- break;
- default:
- break;
- }
- base_y = base_x + y; //x轴方向的偏移,基地址 + 偏移地址
- LCD_Write_Byte(MPU_8bit_Expansion_Draw_Close,0); //扩充指令
- LCD_Write_Byte(MPU_8bit_Expansion_Draw_Open,0); //打开绘图功能
- if(x == 1 || x == 3) //直接在同一个半屏的,直接写完32位数据
- {
- for(i = 0;i < 32;i++) //写地址有讲究,先写垂直再写水平,详见“设定绘图RAM地址”说明
- {
- LCD_Write_Byte(One_LineAddress + i,0); //写入垂直地址,不管上半屏还是下半屏
- LCD_Write_Byte(base_y,0); //写入水平地址
- for(j = 0;j < 2;j++) //两组8bit数据,组成16bit
- {
- LCD_Write_Byte(*bmp++,1); //写入数据
- }
- }
- }
- if(x == 2) //数据显示不在同一半屏上的,先写上半屏,在写下半屏
- {
- for(i = 0;i < 16;i++) //上半屏16行点阵数据
- {
- LCD_Write_Byte(Two_LineAddress + i,0); //写入垂直地址
- LCD_Write_Byte(base_y,0); //写入水平地址
- for(j = 0;j < 2;j++) //两组8bit数据,组成16bit
- {
- LCD_Write_Byte(*bmp++,1); //写入数据
- }
- }
- for(i = 0;i < 16;i++) //下半屏16行点阵数据
- {
- LCD_Write_Byte(Three_LineAddress + i,0); //写入垂直地址
- LCD_Write_Byte(base_y + 8,0); //写入水平地址
- for(j = 0;j < 2;j++) //两组8bit数据,组成16bit
- {
- LCD_Write_Byte(*bmp++,1); //写入数据
- ……………………
- …………限于本文篇幅 余下代码请从电子发烧友下载附件…………
所有资料51hei提供下载:
STM32F103VCT612864.rar
lcd12864.zip
JN12864J使用说明书.pdf
|