打印

万年历:希望大家能帮我看一下到底我的问题出在哪

[复制链接]
2914|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
wzhang04|  楼主 | 2008-6-3 20:37 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    一个万年历程序,自己写的,当然有参考一下别人的程序,lcd显示,用的是ds1302芯片调时,剩下就是一些按键之类的,现在问题是其他都正常,就是lcd显示正常计时的时候lcd上一些位置显示的是问号和数字间接闪烁,数字应该都读进去了,也可以正常读出,但是就是显示不正常。其他功能均正常。
    电路绝对没有问题,拿别人的万年历试验过完全可以用。
    都调了两天了,人都快疯了!可能我比较菜,但是我可以想到的办法都试过了,就是找不到问题所在,哪位好心人帮我看一下吧!或者跟我说个大概方向也成。
    PS:示波器之类我没有,也找不到,所以没有办法用那个。
    程序如下:
//调用函数库
#include<reg51.h>
#include<intrins.h>

//宏定义
#define uchar unsigned char
#define uint  unsigned int

//位定义
sbit  ACC0 = ACC^0;
sbit  ACC7 = ACC^7;

sbit T_CLK=P2^2;         //与硬件相关的连线  clk为DS1302的时钟信号线
sbit T_IO=P2^3;         //DAT为DS1302的I/O数据线
sbit T_RST=P2^4;        //RST为DS1302的RST信号线

sbit lcd_rs=P2^6;
sbit lcd_rw=P2^7;
sbit lcd_en=P2^5;

sbit DS=P2^1;                   //定义温度传感器接口

sbit sw_add=P1^0;                //定义增加键
sbit sw_move=P1^1;                //定义光标左移动键
sbit sw_changeweb=P1^3;            //定义翻页键
sbit sw_back=P3^0;                //定义回到计时按键

sbit ring_bell=P1^2;            //蜂鸣器接口

uchar a[7]={0x00,0x15,0x14,0x03,0x06,0x02,0x09};             //初始化日期
uchar week[21]={0x4d,0x6f,0x6e,0x54,0x75,0x65,0x57,0x65,0x64,0x54,0x68,0x75,
                   0x46,0x72,0x69,0x53,0x61,0x74,0x53,0x75,0x6e};

uchar welcome_screen1[10]="   Welcome";                  //开机画面
uchar welcome_screen2[14]="by wei and zao"; 

uchar numbuf1[4];        //定义一个数组用于存储温度各个位
uchar sec[7];             //用于存储1302中读出的时间
uchar week_buf;          //用于存储周
uchar clockring[2];       //用于闹钟存时
uchar ringdebug;                  //闹钟闹铃判断
uchar ringbiao;           //用于显示有闹钟
uchar ringbegin;          //闹钟开启判断
////////////////////////////////////////////////////////
//                                                    //
//             DS1820b温度传感器模块                  //
//                                                    //
//                                                    //
////////////////////////////////////////////////////////
void delay(uint count)      //delay   延时子程序
{
  uint i;
  while(count)
  {
    i=200;
    while(i>0)
    i--;
    count--;
  }
}

void rstds1820b(void)       //发送初始化命令子程序
{
  uint i;
  DS=0;
  i=103;
  while(i>0)i--;
  DS=1;
  i=4;
  while(i>0)i--;
}

bit readbit(void)       //read a bit    读一位
{
   uint i;
   bit dat;
   DS=0;i++;          //i++ for delay
   DS=1;i++;i++;
   dat=DS;
   i=8;while(i>0)i--;
   return (dat);
}

uchar readbyte(void)   //read a byte date     读一个字节
{
  uchar i,j,dat;
  dat=0;
  for(i=1;i<=8;i++)
  {
    j=readbit();
    dat=(j<<7)|(dat>>1);   //读出的数据最低位在最前面,这样刚好一个字节在DAT里
  }
  return(dat);
}

void writebyte(uchar dat)   //write a byte to ds18b20 给温度传感器写一个字节
{
  uint i;
  uchar j;
  bit testb;
  for(j=1;j<=8;j++)
  {
    testb=dat&0x01;
    dat=dat>>1;
    if(testb)     //write 1
    {
      DS=0;
      i++;i++;
      DS=1;
      i=8;while(i>0)i--;
    }
    else
    {
      DS=0;       //write 0
      i=8;while(i>0)i--;
      DS=1;
      i++;i++;
    }

  }
}

void temchange(void)  //DS18B20 begin change   发送温度转换命令
{
  rstds1820b();
  delay(1);
  writebyte(0xcc);  // address all drivers on bus
  writebyte(0x44);  //  initiates a single temperature conversion
}

uint gettem()               //得到温度值
{
  float tt;
  uchar a,b;
  uint temp;            //定义一个变量用来表示温度
  rstds1820b();
  delay(1);
  writebyte(0xcc);
  writebyte(0xbe);
  a=readbyte();
  b=readbyte();
  temp=b;
  temp<<=8;             //将实型数据变成整型数据
  temp=temp|a;
  tt=temp*0.0625;
  temp=tt*10+0.5;
  return temp;
}

void getnum()           //得到温度的十、个、小数位
{
     uchar A;
     temchange();
     numbuf1[0]=gettem()/100+0x30;
     A=gettem()%100;
     numbuf1[1]=A/10+0x30;
     numbuf1[2]=0x2e;
     numbuf1[3]=A%10+0x30;    
}


////////////////////////////////////////////////////////
//                                                    //
//                 lcd1602显示模块                    //
//                                                    //
//                                                    //
////////////////////////////////////////////////////////

//延时函数
void delay1(uint ms)                      //对于AT89S51来说大概延时为每单位4.5ms
{
    int i;
    while(ms--)
    {
        for(i=0;i<250;i++)
        {
            _nop_();        
            _nop_();
            _nop_();
            _nop_();
        }
    }
}

void delay2(uint us)      //每单位大约延时50us
{
    while(us--)
    {
        _nop_();
    }
}

//判断是否准备好
uchar lcd_ready()
{
    uchar result;
    lcd_rs=0;
    lcd_rw=1;
    lcd_en=1;
    delay2(4);
    result=P0&0x80;         //读寄存器BF位看是否忙
    lcd_en=0;
    return result;
}

//写指令代码
void lcd_inputcode(uchar cmd)
{
    while(lcd_ready());
    lcd_en=0;
    lcd_rs=0;
    lcd_rw=0;    
        delay2(2);
    P0=cmd;
    delay2(4);
    lcd_en=1;         //EN下降沿写指令代码
        delay2(4);
    lcd_en=0;
}

//写数据代码
void lcd_inputdata(uchar dat)
{
    while(lcd_ready());
    lcd_en=0;
    lcd_rs=1;
    lcd_rw=0;
    P0=dat;
    delay2(4);
    lcd_en=1;
    delay2(4);
    lcd_en=0;
}

//设定显示位置
void lcd_pos(uchar XPOS,uchar YPOS)
{  XPOS&=0x0f;
   YPOS&=0x03;
   if(YPOS==0x00)
      lcd_inputcode(XPOS|0x80);
   else if(YPOS==0x01)
      lcd_inputcode((XPOS+0x40)|0x80);
}

//在指定位置显示一个字符
void displayonechar(uchar X, uchar Y, uchar dat)
{
   lcd_pos(X,Y);                        //根据参数定位
   lcd_inputdata(dat);                  //写入字符数据
}

//显示字符串
void displaychar(uchar dat[],line)
{
    uchar i;
    while(dat!='\0')
    {
        displayonechar(i,line,dat);
        i++;
    }
    i=0;
}
//初始化程序
void lcd_init()
{
    delay1(20);
    lcd_inputcode(0x38);         //工作方式设置
    delay1(5);
    lcd_inputcode(0x38);
    delay1(5);

    lcd_inputcode(0x0c);         //显示光标及闪烁设置
    delay1(5);
    lcd_inputcode(0x06);
    delay1(5);
    lcd_inputcode(0x01);         //清DDRAM和AC值
    delay1(5);
}

//清屏程序
void lcd_clr()
{
    lcd_inputcode(0x01);
    delay1(5);
}

//闪动程序
void flash()
{
    delay1(150);
    lcd_inputcode(0x08);
    delay1(150);
    lcd_inputcode(0x0c);
    delay1(150);
    lcd_inputcode(0x08);
    delay1(150);
    lcd_inputcode(0x0c);
    delay1(150);
}

//温度获取
void get1820()
{
    uchar i;
    getnum();
    i=0;
    while(i!=4)
    {
        displayonechar(9+i,1,numbuf1);
        i++;
    }
    displayonechar(13,1,0xdf);
    displayonechar(14,1,0x43);
    i=0;        
}

//开机显示画面
void dispaly_begin()
{
    uchar i,j;
    lcd_clr();
    lcd_inputcode(0x80|0x11);     //DDRAM地址设置两行显示
    for(i=0;i<10;i++)
        lcd_inputdata(welcome_screen1);
    lcd_inputcode(0x80|0x51);
    for(i=0;i<14;i++)
        lcd_inputdata(welcome_screen2);
    for(j=0;j<16;j++)
    {
        lcd_inputcode(0x18);
        delay1(50);
    }
    flash();
}
////////////////////////////////////////////////////////
//                                                    //
//               时钟芯片1302显示模块                 //
//                                                    //
//                                                    //
////////////////////////////////////////////////////////
void DS1302InputByte(uchar d)     //实时时钟写入一字节(内部函数)

    unsigned char i;
    ACC = d;
    for(i=8; i>0; i--)
    {
        T_IO = ACC0;               //相当于汇编中的 RRC
        T_CLK = 1;
        T_CLK = 0;
        ACC = ACC >> 1; 
    } 
}

uchar DS1302OutputByte(void)     //实时时钟读取一字节(内部函数)

    uchar i;
    for(i=8; i>0; i--)
    {
        ACC = ACC >>1;                     //相当于汇编中的 RRC 
        ACC7 = T_IO;
        T_CLK = 1;
        T_CLK = 0;
    } 
    return(ACC); 
}

//先写地址,后写命令数据
void W1302(uchar ucAddr,uchar ucDa)    //ucAddr: DS1302地址, ucData: 要写的数据
{
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    DS1302InputByte(ucAddr);           // 地址,命令 
    DS1302InputByte(ucDa);           // 写1Byte数据
    T_CLK = 1;
    T_RST = 0;


//先写地址,后后读命令数据
uchar R1302(uchar ucAddr)    //读取DS1302某地址的数据
{
    uchar ucData;
    T_RST = 0;
    T_CLK = 0;
    T_RST = 1;
    DS1302InputByte(ucAddr);        // 地址,命令 
    ucData = DS1302OutputByte();         // 读1Byte数据
    T_CLK = 1;
    T_RST = 0;
    return(ucData);
}

//读全部1302模块
void read_1302()
{
    uchar i;
    uchar uccode;
    uccode=0x8d;
    for(i=0;i<7;i++)
    {
        sec=R1302(uccode);
        uccode=uccode-2;
    }
}

//写单个位1302模块
void write1302_bit(uchar ucAddr,uchar num)
{
     W1302(0x8e,0x00);
     W1302(ucAddr,num);
     W1302(0x8e,0x80);      
}

//显示单个时间,例如年,月等子程序
display1302_bit(uchar i,uchar address,uchar line)
{
        displayonechar(address,line,((sec>>4)&0x0f)+0x30);
        displayonechar(address+1,line,(sec&0x0f)+0x30);        
}

//初始时间
void write1302()
{
    uchar i1;
    uchar ucAddr = 0x80; 
    W1302(0x8e,0x00);           // 控制命令,WP=0,写操作
    for(i1 =0; i1<7; i1++)
    { 
        W1302(ucAddr,a[i1]);  // 秒 分 时 日 月 星期 年 
       
        ucAddr +=2;
    }
    W1302(0x8e,0x80);           // 控制命令,WP=1,写保护    
}

//1302显示模块
void get1302()
{
    read_1302();
    displayonechar(0x01,0,0x32);
    displayonechar(0x02,0,0x30);
    display1302_bit(0,0x03,0);           //显示年
    displayonechar(0x05,0,0x2d);              //分隔符
    display1302_bit(2,0x06,0);           //显示月
    displayonechar(0x08,0,0x2d);              //分隔符
    display1302_bit(3,0x09,0);           //显示日
    week_buf=((sec[1]&0x0f)-1)*3;
    displayonechar(0x0c,0,week[week_buf]);    //显示周
    displayonechar(0x0d,0,week[week_buf+1]); 
    displayonechar(0x0e,0,week[week_buf+2]); 

    display1302_bit(4,0x00,1);           //显示时
    displayonechar(0x02,1,0x3a);              //分隔符
    display1302_bit(5,0x03,1);           //显示分
    displayonechar(0x05,1,0x3a);              //分隔符
    display1302_bit(6,0x06,1);           //显示秒

    if(ringbiao==1)                              //判断时钟是否开启
    {
        displayonechar(0x08,1,0xef);
    }
}

void ds1302_init()
{
    write1302_bit(0x90,0xa9);              //开涓流充电                      
    W1302(0x8e,0x80);                      //写保护 
}

////////////////////////////////////////////////////////
//                                                    //
//                  按键调时模块                      //
//                                                    //
//                                                    //
////////////////////////////////////////////////////////
//延时模块,一个单位延时大概为1ms
void delayms(uint z)
{
    uint x,y;
        for(x=z;x>0;x--)
            for(y=122;y>0;y--);
}

//每一位调时模块
void changetime_bit0(uchar i,uchar code_change,uchar address_change,uchar line)
{
    sec=sec+1;
    write1302_bit(code_change,sec);
    if((sec&0x0f)>9)sec=sec&0xf0;
    displayonechar(address_change,line,sec%16+0x30);
    lcd_inputcode(0x80+0x40*line+address_change);

}

void changetime_bit1(uchar i,uchar j,uchar code_change,uchar address_change,uchar line)
{
    sec=sec+0x10;
    write1302_bit(code_change,sec);
    if((sec>>4)>j)sec=sec&0x0f;
    displayonechar(address_change,line,sec/16+0x30);;
    lcd_inputcode(0x80+0x40*line+address_change);    
}

//调时模块
void changetime()               //调时钟时间
{    
    uchar i;                                       //保证第一次在个位分            
    if(sw_add==0)
        {
        delayms(15);
        if(sw_add==0)        //加按键判定
            {
            while(!sw_add);        //松手判定
            delayms(15);
            while(!sw_add);        //松手判定
            if(i==0)                         //个位秒的修改
                changetime_bit0(6,0x80,0x07,1);    
            else if(i==1)                    //十位秒的修改                
                changetime_bit1(6,5,0x80,0x06,1);
            else if(i==2)                   //个位分的修改
                changetime_bit0(5,0x82,0x04,1);
            else if(i==3)                    //十位分的修改                
                changetime_bit1(5,5,0x82,0x03,1);
            else if(i==4)                    //个位小时修改
                changetime_bit0(4,0x84,0x01,1);
            else if(i==5)                    //十位小时修改
                changetime_bit1(4,2,0x84,0x00,1);
            else if(i==6)                    //周修改
                {
                sec[3]=sec[3]+1;
                write1302_bit(0x8a,sec[3]);
                if(sec[3]>7)sec[3]=0x01;
                week_buf=(sec[3]%16-1)*3;
                displayonechar(0x0c,0,week[week_buf]); //显示周
                displayonechar(0x0d,0,week[week_buf+1]); 
                displayonechar(0x0e,0,week[week_buf+2]); 
                lcd_inputcode(0x80+0x0c);
                 }
            else if(i==7)                     //日个位修改
                changetime_bit0(2,0x86,0x0a,0);
            else if(i==8)                     //日十位修改
                changetime_bit1(2,3,0x86,0x09,0);
            else if(i==9)                     //月个位修改
                changetime_bit0(1,0x88,0x07,0);
            else if(i==10)                     //月十位修改
                changetime_bit1(1,1,0x88,0x06,0);
            else if(i==11)                     //年个位修改
                changetime_bit0(0,0x8c,0x04,0);
            else                              //年十位修改
                changetime_bit1(0,9,0x8c,0x03,0);
        }
}
    if(sw_move==0)                //移动按键判定
        {
        delayms(20);
        if(sw_move==0)
            {
                while(!sw_move);        //松手判定
                delayms(20);
                while(!sw_move);        //松手判定
                if(i<12)  i++;
                else        i=0;
            }    
        if(i==0)        lcd_inputcode(0x80+0x40+7);
        else if(i==1)    lcd_inputcode(0x80+0x40+6);
        else if(i==2)    lcd_inputcode(0x80+0x40+4);
        else if(i==3)    lcd_inputcode(0x80+0x40+3);
        else if(i==4)    lcd_inputcode(0x80+0x40+1);
        else if(i==5)    lcd_inputcode(0x80+0x40);
        else if(i==6)    lcd_inputcode(0x80+0x0c);
        else if(i==7)    lcd_inputcode(0x80+0x0a);
        else if(i==8)    lcd_inputcode(0x80+0x09);
        else if(i==9)    lcd_inputcode(0x80+0x07);
        else if(i==10)    lcd_inputcode(0x80+0x06);
        else if(i==11)    lcd_inputcode(0x80+0x04);
        else             lcd_inputcode(0x80+0x03);
        }    
}    

void changering_bit0(uchar i,uchar address_ring)
{
    clockring=clockring+1;
    if((clockring&0x0f)>9)clockring=clockring&0xf0;
    displayonechar(address_ring,1,clockring%16+0x30);
    lcd_inputcode(0x80+0x40+address_ring);
}

void changering_bit1(uchar i,uchar j,uchar address_ring)
{
    clockring=clockring+0x10;
    if((clockring>>4)>j)clockring=clockring&0x0f;
    displayonechar(address_ring,1,clockring/16+0x30);
    lcd_inputcode(0x80+0x40+address_ring);    
}

void changering()                    //调闹钟时间
{    
    uchar i;            
    if(sw_add==0)
        {
        delayms(15);
        if(sw_add==0)        //按键判定
            {
            while(!sw_add);        //松手判定
            delayms(15);
            while(!sw_add);        //松手判定
            ringbiao=1;
            ringbegin=1;
            if(i==0)                         //个位分的修改
                changering_bit0(0,0x0a);
            else if(i==1)                    //十位分的修改                
                changering_bit1(0,5,0x09);
            else if(i==2)                    //个位小时修改
                changering_bit0(1,0x07);
            else if(i==3)                    //十位小时修改
                changering_bit1(1,2,0x06);
            }
         }
    if(sw_move==0)                //按键判定
        {
        delayms(20);
        if(sw_move==0)
            {
                while(!sw_move);        //松手判定
                delayms(20);
                while(!sw_move);        //松手判定
                if(i<3)    i++;
                else      i=0;
            }    
        if(i==0)    lcd_inputcode(0x80+0x40+0x0a);       //光标移动
        else if(i==1)    lcd_inputcode(0x80+0x40+9);
        else if(i==2)    lcd_inputcode(0x80+0x40+7);
        else if(i==3)    lcd_inputcode(0x80+0x40+6);
        }    

}

void change1302_bit(uchar address_1302,uchar line,uchar i)
{
    displayonechar(address_1302,line,sec/16+0x30); 
    displayonechar(address_1302+1,line,sec%16+0x30);    
}

void display1302()                     //对当前sec数值进行提取显示
{
    lcd_clr();
    displayonechar(0x01,0,0x32);
    displayonechar(0x02,0,0x30);
    change1302_bit(0x03,0,0);                //显示年

    displayonechar(0x05,0,0x2d);            //分隔符
    
    change1302_bit(0x06,0,1);                //显示月
    
    displayonechar(0x08,0,0x2d);            //分隔符
    
    change1302_bit(0x09,0,2);
    
    week_buf=(sec[3]%16-1)*3;
    displayonechar(0x0c,0,week[week_buf]);  //显示周
    displayonechar(0x0d,0,week[week_buf+1]); 
    displayonechar(0x0e,0,week[week_buf+2]); 

    change1302_bit(0x00,1,4);                 //显示时

    displayonechar(0x02,1,0x3a);             //分隔符
    
    change1302_bit(0x03,1,5);                 //显示分

    displayonechar(0x05,1,0x3a);             //分隔符
    
    change1302_bit(0x06,1,6);                 //显示秒
}

//不同屏幕的显示函数
void screen0()
{
    lcd_clr();
    display1302();
    get1820();
}
void screen1()
{
    lcd_clr();
    displaychar("  made in fzu   ",0);
}
void screen2()
{
    lcd_clr();
    ringdebug=0;
    displaychar("   bell ring    ",0);     
    displayonechar(0x06,1,clockring[1]/16+0x30); //显示时
    displayonechar(0x07,1,clockring[1]%16+0x30);

    displayonechar(0x08,1,0x3a);        //分隔符
    
    displayonechar(0x09,1,clockring[0]/16+0x30); //显示分
    displayonechar(0x0a,1,clockring[0]%16+0x30);
}

//闹时界面
void displaybellring()
{
    lcd_clr();
    ringbiao=0;
    displaychar(" it's the time  ",0);
    displaychar("press sw to stop",1);        
}
//换屏幕显示
void changescreen()
{
    uchar i;
    if(sw_changeweb==0)
        {
        delayms(5);
        if(sw_changeweb==0)
            {
            if(i<2)    i++;
            else    i=0;
            }
         if(i==1)
             screen1();
        else if(i==2)
            screen2();
        else 
            screen0();
         }
    while(sw_changeweb!=1); 
    if(i==0)    changetime();
    if(i==2)    changering();    
}

//对时钟进行调时
void changeclock() interrupt 2
{
    lcd_inputcode(0x0f);          //开光标
    lcd_inputcode(0x80|0x4f);     //将光标移位至最后一位
    while(sw_back!=0)
    {
    changescreen();
    }
    lcd_inputcode(0x0c);         //关光标
}

//闹钟判断
void bellring()
{
    if(clockring[0]==sec[5]&&clockring[1]==sec[4]&&ringdebug==0&&ringbegin==1)
    {
        lcd_clr();
        displaybellring();
        ring_bell=0;
        while(sw_back!=0);
        ring_bell=1;
        lcd_clr();
        ringdebug++;
    }
}

//按键初始化模块
void sw_init()
{
    IT1=0;            //使得外部中断的触发方式为低电平触发;
    EX1=1;            //允许外部的中断0的中断请求
    PX1=1;            //设置外部中断为高优先级        
    //开中断终端设置
    EA=1;            //开中断总允许位
}


void main()
{
    lcd_init();
    lcd_clr();
    sw_init();
    dispaly_begin();
    ds1302_init();
    write1302();
    lcd_clr();
    while(1)
    { 
        get1820();
        get1302();
        bellring();
        delayms(500); 
    }
        //flash();
        
}
沙发
xieyuanbin| | 2008-6-4 07:38 | 只看该作者

晕死,这么长的程序看也看几天

我想你一定是在什么地方有不必要的数据误送进LCD了.你可以看看是否什么东西调用了你的LCD通讯,或者是程序有什么不对的地方跳转到LCD通讯中去了.

使用特权

评论回复
板凳
ayb_ice| | 2008-6-4 10:56 | 只看该作者

可能发送一半时,被打断了,比如中断

而且中断时间较长

使用特权

评论回复
地板
01dxwlm| | 2008-6-8 22:34 | 只看该作者

应该是你LCD显示平率太高,

建议
1:把发送LCD的数据频率降低
2;发送期间关闭中断
3:如果LCD模块本身有RC震荡的话,把RC平率降低

使用特权

评论回复
5
bojiazu| | 2008-6-15 12:59 | 只看该作者

是时钟和延时的问题

具体我也不太清楚

使用特权

评论回复
6
bojiazu| | 2008-6-15 13:11 | 只看该作者

程序改动

写数据:
void lcd_inputdata(uchar dat)
{
    while(lcd_ready());
    lcd_rs=1;
    lcd_rw=0;
    P0=dat;
    lcd_en=1;
    delay2(?);
    lcd_en=0;
}

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

2

主题

1

帖子

0

粉丝