找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 17619|回复: 17
收起左侧

基于51单片机 12864液晶显示数字函数

  [复制链接]
ID:262 发表于 2014-2-22 01:19 | 显示全部楼层 |阅读模式
今天晚上花了我两个小时,就为了写一个简单的函数,可能不足40行。但确实遇到了点问题,最后还是解决了。
函数的作用就是用12864液晶显示器,来显示任意位数的数字。为什么要写这个函数呢?因为我在使用12864的过程中经常用到一些接口函数,十分的方便。比如write_char();write_string();写字符和写字符串函数。
但是要写一个数字,却没法了,我可以一位数一位数拆开来用显示字符函数。但是这样很麻烦,最要命的一点是,由于12864的地址是2个字节单位的(这里有些不专业了),可能是为了写汉字,数字不能紧紧靠在一起,中间会空一格字节,很是浪费啊。于是就有了这个写数字函数。
void write_num(uchar x,uchar y,unsigned long int num)
{
uchar i=10;
switch (y)
{
case 0: Lcd_WriteCmd(0x80+x);break;
case 1: Lcd_WriteCmd(0x90+x);break;
case 2: Lcd_WriteCmd(0x88+x);break;
case 3: Lcd_WriteCmd(0x98+x);break;
default: ;
}
while(i>=1)
{
if((uchar)(num/pow(10,i-1))!=0)
break;
i--;
}
while(i)
{
Lcd_WriteData(num/(u32)(pow(10,i-1))+'0');
num=num%(u32)(pow(10,i-1));
i--;
}   
}
首先肯定不是任意位数了,毕竟显示屏就那么大,显示位数肯定有限。我们注意到C语言里
unsigned long int型是很大的了,是32位,4个字节,最大是4294967295..
这里是十个位数,所以我们的参数是u32类型,另XY参数就是在12864上显示的坐标位置。
这个函数值是先确定要写入的坐标,然后确定数的位数,然后从高位开始一位一位写入。
定义一个变量i;初始化位10。
值得一提的是,我遇到的问题,不知道其他人有没有遇到。
用pow函数时,由于库函数定义的都是double型的,在取余数是会报错。我先加了强制类型转换。发现不行,显示很多数都出错。经过仿真调试,觉得问题就出现在pow函数这里。
于是,我自己写pow函数,数据类型都用整型的,这样就免去数据类型转换时候的数据丢失了。
这样改了以后就可以了。ok
写上我写的pow函数把,,很简单的。
u32 pow(uchar a,uchar b)
{
u32 result=1;//  初始化为 1
for(;b>0;b--)
{
result*=a;
}
return result;
}

评分

参与人数 1黑币 +5 收起 理由
cottonma + 5 赞一个!

查看全部评分

回复

使用道具 举报

ID:1 发表于 2014-3-7 13:51 来自手机 | 显示全部楼层
你解决问题的思路很值得大家学习的
回复

使用道具 举报

ID:101003 发表于 2015-12-29 10:32 | 显示全部楼层
为什么 程序在KEIL里编译有很多错误?而且我不会改
回复

使用道具 举报

ID:126343 发表于 2016-9-30 14:36 来自手机 | 显示全部楼层
举个例说明一下恭耳详解
回复

使用道具 举报

ID:126343 发表于 2016-10-7 00:21 来自手机 | 显示全部楼层
jor 发表于 2016-9-30 14:36
举个例说明一下恭耳详解

无字符怎么写这个函数
回复

使用道具 举报

ID:141519 发表于 2016-10-7 07:38 | 显示全部楼层
借鉴学习一下
回复

使用道具 举报

ID:126343 发表于 2016-10-7 08:08 来自手机 | 显示全部楼层
楼主写一个无字库液晶显示任意数字的函数   给解释一下了解原理
回复

使用道具 举报

ID:126343 发表于 2016-10-8 07:47 来自手机 | 显示全部楼层
那位大神解释楼主的程序 无字库液晶怎么改写 邮箱1023010634@qq.com
回复

使用道具 举报

ID:183117 发表于 2017-4-4 17:24 | 显示全部楼层
用过之后发现有点问题,如果用程序显示0——100,循环,本应该是98——99——0——1——2这样的
实际会变成98——99——(09——19——......——99)——10——11——12,我括号那部分实际显示应该为0——9,由于两位数时,显示到99,个位最后显示9,重新置0后,此时的9无法消去
回复

使用道具 举报

ID:186071 发表于 2017-4-4 17:56 | 显示全部楼层

 这个好,资料详实,便于模仿。
回复

使用道具 举报

ID:192756 发表于 2017-5-2 21:11 | 显示全部楼层
我也遇到了这个问题。。,为了好看,就用数组往里面写
回复

使用道具 举报

ID:209845 发表于 2017-6-19 09:10 | 显示全部楼层
ghkjhk 发表于 2017-5-2 21:11
我也遇到了这个问题。。,为了好看,就用数组往里面写

您好,我的12864是不带字库的。请问可以教我下怎么用数组来显示数字嘛
回复

使用道具 举报

ID:182758 发表于 2017-6-19 10:00 | 显示全部楼层
楼主写一个无字库液晶显示任意数字的函数   给解释一下了解原理
回复

使用道具 举报

ID:274475 发表于 2018-1-10 19:10 | 显示全部楼层
各位大神,我想用有字库12864显示温度值,但变量就是显示不出来,哪位大神能帮帮我看看程序?

#include <stc12c5a60s2.h>
#include <stdio.h>
#define uchar unsigned char
#define uint unsigned int
sbit RS=P1^0;
sbit RW=P1^1;
sbit E=P1^2;
sbit DQ=P1^3;

uchar code table1[]="温度:";
uchar code table2[]="°C";
void display1();
void display2();
void display3();
unsigned int read_temp();
void init_12864();
void write_com(uchar com);
unsigned char str[10] ;
unsigned int t ;       

void main()
{
       
       
        init_12864();
        display1();
        display2();
        while(1)
        {
                t=read_temp();
          sprintf(str,"%d",t);
                display3();
                write_com(0x01);
        }
       
}

void DELAY_MS (unsigned int a)//毫秒级延时函数
{
        unsigned int i;
        while( a-- != 0){
                for(i = 0; i < 600; i++);
        }
}


void delay(unsigned int time)
{
        while(--time);
}


void write_com(uchar com)//写入一个命令
{
        RS=0;
        RW=0;
        E=0;
        DELAY_MS(1);
        P0=com;//通过P0把命令给12864
        DELAY_MS(1);
        E=1;
        DELAY_MS(5);
        E=0;
        DELAY_MS(5);
       
}
       
void write_dat(uchar dat)//写入一个数据
{
        RS=1;
        RW=0;
        E=0;
        DELAY_MS(1);
        P0=dat;//通过P0把数据给12864
        DELAY_MS(1);
        E=1;
        DELAY_MS(5);
        E=0;
        DELAY_MS(5);
}

void init_12864()//12864液晶初始化(根据时序图编写)
{
        DELAY_MS(100);
        write_com(0x30);
        DELAY_MS(1);
        write_com(0x0e);//打开所有显示
        DELAY_MS(1);
        write_com(0x0c);//不显示光标
        DELAY_MS(1);
        write_com(0x06);//地址指针自动加一
        DELAY_MS(1);
        write_com(0x01);//清屏
        DELAY_MS(1);
}

void display1()
{
        uchar i;
        write_com(0x80);
        for(i=0;i<6;i++)
        {
                write_dat(table1[i]);
                DELAY_MS (5);
        }
}
               
void display2()
{
        uchar i;
        write_com(0x86);
        for(i=0;i<4;i++)
        {
                write_dat(table2[i]);
                DELAY_MS(5);
        }
}

void display3()
{
        uchar i;
        write_com(0x88);
        for(i=0;i<16;i++)
        {
                write_dat(str[i]);
                DELAY_MS(5);
        }
}




// ****************DS18B20复位函数************************/
void OwReset(void)
{
    DQ=1;//从高拉倒低
    delay(200);
    DQ=0;
    delay(1000);           //550 us
    DQ=1;
    delay(1000);            //延时500 us  这是DQ应该为0 说明复位成功 这里没有用死循环判断 怕干扰时钟


    DQ=1;                   //拉高电平
}


/****************DS18B20写命令函数************************/
//向1-WIRE 总线上写1个字节
void WriteByte(unsigned char val)
{
  unsigned char i;
  for(i=8;i>0;i--)
  {
   DQ=1;                 //从高拉倒低
   DQ=0;                  //5 us
   DQ=val&0x01;                           //最低位移出
   delay(100);                              //66 us
   val=val/2;                             //右移1位
   }
   DQ=1;
   delay(1);
}
//
/****************DS18B20读1字节函数************************/
//从总线上取1个字节

unsigned char ReadByte(void)
{
unsigned char i;
unsigned char value=0;
for(i=8;i>0;i--)
{
  DQ=1;
  value>>=1;   //value=value>>1
  DQ=0;                                           //4 us
  DQ=1;                                         //4 us
  if(DQ)value|=0x80;
  delay(100);                                     //66 us
}
DQ=1;
return(value);
}

/****************读出温度函数************************/
//

unsigned int ReadTemp()                                        //读温度并转换成三位有效数字
{
unsigned char a=0;
unsigned char b=0;
  unsigned int t,m;
  OwReset();                  //总线复位
  delay(500);
  WriteByte(0xcc);            //发命令
  WriteByte(0x44);            //发转换命令
  OwReset();
  delay(100);
  WriteByte(0xcc);            //发命令
  WriteByte(0xbe);
  a=ReadByte();    //读温度值的第字节
  b=ReadByte();    //读温度值的高字节
  t=b;

  t <<=8;       // 低位补0 即0x00
  t =t |a;      // 两字节合成一个整型变量。
  t=t>>4;       //高位补1

  m=b;
  m<<=8;
  m=m|a;
  m=m&0x0f;
  
  t=t*10+m;
  return t;
  }
回复

使用道具 举报

ID:457140 发表于 2018-12-29 10:51 | 显示全部楼层
确实不错,我喜欢
回复

使用道具 举报

ID:449525 发表于 2018-12-29 12:19 | 显示全部楼层
岁月无痕 发表于 2018-1-10 19:10
**** 作者被禁止或删除 内容自动屏蔽 ****

你自己对比下模块代码,网上也有很多,直接把这么多代码贴出来,帮你解决的人基本上很少
回复

使用道具 举报

ID:449525 发表于 2018-12-29 12:20 | 显示全部楼层
我看到你的函数,和我之前玩ht1621驱动lcd屏幕一样,计算地址和要写的数据
一样的道理
回复

使用道具 举报

ID:454000 发表于 2018-12-29 23:51 | 显示全部楼层
值得支持!灵感来自善于解决问题的人!能将要显示的数字做到只在函数里只填3个数字,这本身就是一个创举!如果只会在网上复制粘贴永远成就不了自己!

评分

参与人数 2黑币 +30 收起 理由
还有谁? + 15
zhengchong60 + 15

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表