单片机学习小组
直播中

李一天

7年用户 182经验值
私信 关注

stm32串行st7920 128*64屏显示字符源程序

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  





更多回帖

发帖
×
20
完善资料,
赚取积分