找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 1027|回复: 5
打印 上一主题 下一主题
收起左侧

51单片机定时器0内调用lcd1602显示函数就会出问题

[复制链接]
回帖奖励 1 黑币 回复本帖可获得 1 黑币奖励! 每人限 1 次
跳转到指定楼层
楼主
ID:1081007 发表于 2024-6-18 20:25 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我在的定时器中断函数内写了一个500ms闪烁的指示灯(定时器定时是10ms),在主函数内调用lcd1602显示时间,程序下载后指示灯正常闪烁,时间也能正常显示,但当我在定时器中断函数内调用lcd1602显示函数,程序下载后屏幕上就只显示了个tete(定时器中断内lcd1602显示的内容),时间没有显示出来,随后我又重新试了几次,lcd屏幕要么显示错误的数据,要么就只显示tete,然后我又在main函数的while循环内调用串口发送函数来发送"ok",按理说串口应该会1ms接收一个数据(循环内加1ms延时函数),但实际上要1分多钟才能接收到一个数据!,而当我把中断内的lcd显示函数去掉后,串口就能正常接收了!!!有没有好心人说一下为什么呀
#include "public.h"
#include "lcd1602.h"
#include "ds1302.h"
#include"uart.h"
//uart.h,lcd1602.h内的代码都放在了最下面
sbit LED1=P2^4;

void lcd1602_showtime(void)
{
    u8 gDS1302_YEARDAY_Change[11];//日,月,年
    u8 gDS1302_TIME_Change[9];//秒,分,时
    ds1302_read_time();
    //BCD格式转为10进制
    gDS1302_TIME_Change[8]='\0';//数组末尾添加结束符
    gDS1302_TIME_Change[7]=(gDS1302_TIME[0]&0x0f)+0x30;//获取秒的低4位
    gDS1302_TIME_Change[6]=(gDS1302_TIME[0]>>4)+0x30;//获取秒的高4位
    gDS1302_TIME_Change[4]=(gDS1302_TIME[1]&0x0f)+0x30;//获取分的低4位
    gDS1302_TIME_Change[3]=(gDS1302_TIME[1]>>4)+0x30;//获取分的高4位
    gDS1302_TIME_Change[5]=':';
    gDS1302_TIME_Change[1]=(gDS1302_TIME[2]&0x0f)+0x30;//获取时的低4位
    gDS1302_TIME_Change[0]=(gDS1302_TIME[2]>>4)+0x30;//获取时的高4位
    gDS1302_TIME_Change[2]=':';

    gDS1302_YEARDAY_Change[10]='\0';////数组末尾添加结束符
    gDS1302_YEARDAY_Change[9]=(gDS1302_TIME[3]&0x0f)+0x30;//获取日的低4位
    gDS1302_YEARDAY_Change[8]=(gDS1302_TIME[3]>>4)+0x30;//获取日的高4位
    gDS1302_YEARDAY_Change[6]=(gDS1302_TIME[4]&0x0f)+0x30;//获取月的低4位
    gDS1302_YEARDAY_Change[5]=(gDS1302_TIME[4]>>4)+0x30;//获取月的高4位
    gDS1302_YEARDAY_Change[7]='-';
    gDS1302_YEARDAY_Change[1]='0';//赋值年的千位
    gDS1302_YEARDAY_Change[0]='2';//赋值年的百位
    gDS1302_YEARDAY_Change[3]=(gDS1302_TIME[6]&0x0f)+0x30;//获取年的低4位
    gDS1302_YEARDAY_Change[2]=(gDS1302_TIME[6]>>4)+0x30;//获取年的高4位
    gDS1302_YEARDAY_Change[4]='-';
    lcd1602_show_string(0,0,gDS1302_YEARDAY_Change);
    lcd1602_show_string(0,1,gDS1302_TIME_Change);
}

void time0_init(void)//定时器0初始化
{
        TMOD|=0X01;//选择为定时器0模式,工作方式1
        TH0=0XDC;        //给定时器赋初值,定时10ms
        TL0=0X00;        
        ET0=1;//打开定时器0中断允许
        EA=1;//打开总中断
        TR0=1;//打开定时器0                    
}

void main()
{         
    u8 temp=0;
    lcd1602_init();
    UART_Init();//串口初始化
    lcd1602_clear();
    time0_init();  
    ds1302_init();   

        while(1)
        {
        temp++;
        uartsend_string("ok");//串口发送数据
        if(temp>=10)
        {
            //LED1=~LED1;           
        }
        delay_ms(1);        
        lcd1602_showtime();
        }        
}
void time0(void) interrupt 1 //定时器0中断函数
{
    static u8 temp;
        TH0=0XDC;        //给定时器赋初值,定时10ms
        TL0=0X00;
    temp++;
    if(temp==50)
    {
        temp=0;
        LED1=~LED1;
    }
    lcd1602_show_string(12,0,"tete");
}

//uart.c
void UART_Init(void)//串口初始化。波特率:4800*2
{
        SCON|=0X50; //设置为工作方式 1
        TMOD|=0X20; //使用计时器1,工作方式 2(8位自动重装)
        PCON=0X80; //波特率加倍
        TH1=0xfa; //计数器初始值设置,对应4800波特率
        TL1=0xfa;
        //ES=1; //打开串口中断。注: 在只发送数据的情况下串口中断不要打开,不然发送会出问题!
        EA=1; //打开总中断
        TR1=1; //打开计数器1
        TI=0;//发送标志清零
}

/*
函数功能:串口发送一个字节
dat :要发送的数据
*/
void uartsend_byte(u8 dat)
{
        SBUF=dat;//数据存入SBUF
        while(!TI);
        TI=0;//发送标志清零,为下次发送做准备   
}

/*
函数功能: 串口发送多个数据
dat :数据指针
len :数据长度
*/
void uartsend_string(u8 *pdat)
{
    while(*pdat!='\0')  
    {
            SBUF=*pdat;//数据存入SBUF
            while(!TI);
            TI=0;//发送标志清零,为下次发送做准备
        pdat++;
    }
}

//lcd1602.c
/*******************************************************************************
* 函 数 名       : lcd1602_write_cmd
* 函数功能                 : LCD1602写命令
* 输    入       : cmd:指令
* 输    出             : 无
*******************************************************************************/
void lcd1602_write_cmd(u8 cmd)//8位lcd
{
        LCD1602_RS=0;//选择命令,RS=1时为写命令,等于0时为写数据
        LCD1602_RW=0;//选择写,RW=1为读,等于0位写
        LCD1602_E=0;//使能脚
        LCD1602_DATAPORT=cmd;//准备命令,8位并行数据口
        delay_ms(1);
        LCD1602_E=1;//使能脚E先上升沿写入
        delay_ms(1);
        LCD1602_E=0;//使能脚E后负跳变完成写入        
}

/*******************************************************************************
* 函 数 名       : lcd1602_write_data
* 函数功能                 : LCD1602写数据
* 输    入       : dat:数据
* 输    出             : 无
*******************************************************************************/
void lcd1602_write_data(u8 dat)
{
        LCD1602_RS=1;//选择数据
        LCD1602_RW=0;//选择写
        LCD1602_E=0;
        LCD1602_DATAPORT=dat;//准备数据
        delay_ms(1);
        LCD1602_E=1;//使能脚E先上升沿写入
        delay_ms(1);
        LCD1602_E=0;//使能脚E后负跳变完成写入               
}


void lcd1602_init(void)//lcd1602初始化
{
//        u8 i=0;
        lcd1602_write_cmd(0x38);//数据总线8位,显示2行,5*7点阵/字符
//        for(i=0;i<200;i++)
                lcd1602_write_cmd(0x0c);//显示功能开,无光标,光标闪烁

        lcd1602_write_cmd(0x06);//写入新数据后光标右移,显示屏不移动
        lcd1602_write_cmd(0x01);//清屏        
}


/*******************************************************************************
* 函 数 名       : lcd1602_show_string
* 函数功能                 : LCD1602显示字符串
* 输    入       : x,y:显示坐标,x=0~15,y=0~1;
                                   str:显示字符串
* 输    出             : 无
*******************************************************************************/
void lcd1602_show_string(u8 x,u8 y,u8 *str)
{
        u8 i=0;

        if(y>1||x>15)return;//行列参数不对则强制退出

        if(y<1)        //第1行显示
        {        
                while(*str!='\0')//字符串是以'\0'结尾,只要前面有内容就显示
                {
                        if(i<16-x)//如果字符长度超过第一行显示范围,则在第二行继续显示
                        {
                                lcd1602_write_cmd(0x80+i+x);//第一行显示地址设置        
                        }
                        else
                        {
                                lcd1602_write_cmd(0x40+0x80+i+x-16);//第二行显示地址设置        
                        }
                        lcd1602_write_data(*str);//显示内容
                        str++;//指针递增
                        i++;        
                }        
        }
        else        //第2行显示
        {
                while(*str!='\0')
                {
                        if(i<16-x) //如果字符长度超过第二行显示范围,则在第一行继续显示
                        {
                                lcd1602_write_cmd(0x80+0x40+i+x);        
                        }
                        else
                        {
                                lcd1602_write_cmd(0x80+i+x-16);        
                        }
                        lcd1602_write_data(*str);
                        str++;
                        i++;        
                }        
        }                                
}

/*******************************************************************************
* 函 数 名       : lcd1602_show_char
* 函数功能                 : LCD1602显示字符
* 输    入       : x,y:显示坐标,x=0~15,y=0~1;
                                   str:显示字符
* 输    出             : 无
*******************************************************************************/
void lcd1602_show_char(u8 x,u8 y,u8 chr)
{
        if(y>1||x>15)return;//行列参数不对则强制退出

        if(y<1)        //第1行显示
        {        
                lcd1602_write_cmd(0x80+x);//第一行显示地址设置        
                lcd1602_write_data(chr);//显示内容               
        }
        else        //第2行显示
        {
            lcd1602_write_cmd(0x80+0x40+x);        
                lcd1602_write_data(chr);               
        }                                
}

void lcd1602_clear(void)
{
        lcd1602_write_cmd(0x01);        
}


分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1080935 发表于 2024-6-19 08:37 | 只看该作者
为什么要在中断中调用显示函数,显示函数运行时间长,可能已经影响了你的定时时间,导致不正常(程序运行时间大于中断定时时间,中断程序刚执行完,马上又进入中断,也就是 基本在执行中断程序)。
回复

使用道具 举报

板凳
ID:161164 发表于 2024-6-19 09:34 | 只看该作者
因为你写1602显示函数延时太长了,
根本用不了1ms,40us就够了
清屏后才需要2ms延时

  1. void Delay40us(void)        //@11.0592MHz
  2. {
  3.         unsigned char data i;

  4.         i = 15;
  5.         while (--i);
  6. }

  7. //lcd1602.c
  8. /*******************************************************************************
  9. * 函 数 名       : lcd1602_write_cmd
  10. * 函数功能                 : LCD1602写命令
  11. * 输    入       : cmd:指令
  12. * 输    出             : 无
  13. *******************************************************************************/
  14. void lcd1602_write_cmd(u8 cmd)//8位lcd
  15. {
  16.         LCD1602_RS=0;//选择命令,RS=1时为写命令,等于0时为写数据
  17.         LCD1602_RW=0;//选择写,RW=1为读,等于0位写
  18.         LCD1602_E=0;//使能脚
  19.         LCD1602_DATAPORT=cmd;//准备命令,8位并行数据口
  20.         LCD1602_E=1;//使能脚E先上升沿写入
  21.         LCD1602_E=0;//使能脚E后负跳变完成写入
  22.                 Delay40us();//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  23. }

  24. /*******************************************************************************
  25. * 函 数 名       : lcd1602_write_data
  26. * 函数功能                 : LCD1602写数据
  27. * 输    入       : dat:数据
  28. * 输    出             : 无
  29. *******************************************************************************/
  30. void lcd1602_write_data(u8 dat)
  31. {
  32.         LCD1602_RS=1;//选择数据
  33.         LCD1602_RW=0;//选择写
  34.         LCD1602_E=0;
  35.         LCD1602_DATAPORT=dat;//准备数据
  36.         LCD1602_E=1;//使能脚E先上升沿写入
  37.         LCD1602_E=0;//使能脚E后负跳变完成写入
  38.                 Delay40us();//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<            
  39. }


  40. void lcd1602_init(void)//lcd1602初始化
  41. {
  42. //        u8 i=0;
  43.         lcd1602_write_cmd(0x38);//数据总线8位,显示2行,5*7点阵/字符
  44. //        for(i=0;i<200;i++)
  45.                 lcd1602_write_cmd(0x0c);//显示功能开,无光标,光标闪烁

  46.         lcd1602_write_cmd(0x06);//写入新数据后光标右移,显示屏不移动
  47.         lcd1602_write_cmd(0x01);//清屏   
  48.         delay_ms(2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<         
  49. }
复制代码
回复

使用道具 举报

地板
ID:123289 发表于 2024-6-20 20:23 | 只看该作者
T0的优先级比较高,当它进行服务程序后,其它低级的中断就无法立即响应了,可以会丢失中断。
回复

使用道具 举报

5#
ID:675287 发表于 2024-6-21 11:47 | 只看该作者
这个显示函数没必要在中断里面调用,运行时间大于中断的间隔时间就会出问题了
回复

使用道具 举报

6#
ID:313517 发表于 2024-6-21 23:07 | 只看该作者
中断时间够不够,程序运行时间太长了,中断时间太短了
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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