找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

帖子
查看: 1073|回復(fù): 5
收起左側(cè)

51單片機(jī)定時(shí)器0內(nèi)調(diào)用lcd1602顯示函數(shù)就會(huì)出問題

[復(fù)制鏈接]
回帖獎(jiǎng)勵(lì) 1 黑幣 回復(fù)本帖可獲得 1 黑幣獎(jiǎng)勵(lì)! 每人限 1 次
ID:1081007 發(fā)表于 2024-6-18 20:25 | 顯示全部樓層 |閱讀模式
我在的定時(shí)器中斷函數(shù)內(nèi)寫了一個(gè)500ms閃爍的指示燈(定時(shí)器定時(shí)是10ms),在主函數(shù)內(nèi)調(diào)用lcd1602顯示時(shí)間,程序下載后指示燈正常閃爍,時(shí)間也能正常顯示,但當(dāng)我在定時(shí)器中斷函數(shù)內(nèi)調(diào)用lcd1602顯示函數(shù),程序下載后屏幕上就只顯示了個(gè)tete(定時(shí)器中斷內(nèi)lcd1602顯示的內(nèi)容),時(shí)間沒有顯示出來,隨后我又重新試了幾次,lcd屏幕要么顯示錯(cuò)誤的數(shù)據(jù),要么就只顯示tete,然后我又在main函數(shù)的while循環(huán)內(nèi)調(diào)用串口發(fā)送函數(shù)來發(fā)送"ok",按理說串口應(yīng)該會(huì)1ms接收一個(gè)數(shù)據(jù)(循環(huán)內(nèi)加1ms延時(shí)函數(shù)),但實(shí)際上要1分多鐘才能接收到一個(gè)數(shù)據(jù)!,而當(dāng)我把中斷內(nèi)的lcd顯示函數(shù)去掉后,串口就能正常接收了�。�!有沒有好心人說一下為什么呀
#include "public.h"
#include "lcd1602.h"
#include "ds1302.h"
#include"uart.h"
//uart.h,lcd1602.h內(nèi)的代碼都放在了最下面
sbit LED1=P2^4;

void lcd1602_showtime(void)
{
    u8 gDS1302_YEARDAY_Change[11];//日,月,年
    u8 gDS1302_TIME_Change[9];//秒,分,時(shí)
    ds1302_read_time();
    //BCD格式轉(zhuǎn)為10進(jìn)制
    gDS1302_TIME_Change[8]='\0';//數(shù)組末尾添加結(jié)束符
    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;//獲取時(shí)的低4位
    gDS1302_TIME_Change[0]=(gDS1302_TIME[2]>>4)+0x30;//獲取時(shí)的高4位
    gDS1302_TIME_Change[2]=':';

    gDS1302_YEARDAY_Change[10]='\0';////數(shù)組末尾添加結(jié)束符
    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)//定時(shí)器0初始化
{
        TMOD|=0X01;//選擇為定時(shí)器0模式,工作方式1
        TH0=0XDC;        //給定時(shí)器賦初值,定時(shí)10ms
        TL0=0X00;        
        ET0=1;//打開定時(shí)器0中斷允許
        EA=1;//打開總中斷
        TR0=1;//打開定時(shí)器0                    
}

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

        while(1)
        {
        temp++;
        uartsend_string("ok");//串口發(fā)送數(shù)據(jù)
        if(temp>=10)
        {
            //LED1=~LED1;           
        }
        delay_ms(1);        
        lcd1602_showtime();
        }        
}
void time0(void) interrupt 1 //定時(shí)器0中斷函數(shù)
{
    static u8 temp;
        TH0=0XDC;        //給定時(shí)器賦初值,定時(shí)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; //設(shè)置為工作方式 1
        TMOD|=0X20; //使用計(jì)時(shí)器1,工作方式 2(8位自動(dòng)重裝)
        PCON=0X80; //波特率加倍
        TH1=0xfa; //計(jì)數(shù)器初始值設(shè)置,對應(yīng)4800波特率
        TL1=0xfa;
        //ES=1; //打開串口中斷。注: 在只發(fā)送數(shù)據(jù)的情況下串口中斷不要打開,不然發(fā)送會(huì)出問題!
        EA=1; //打開總中斷
        TR1=1; //打開計(jì)數(shù)器1
        TI=0;//發(fā)送標(biāo)志清零
}

/*
函數(shù)功能:串口發(fā)送一個(gè)字節(jié)
dat :要發(fā)送的數(shù)據(jù)
*/
void uartsend_byte(u8 dat)
{
        SBUF=dat;//數(shù)據(jù)存入SBUF
        while(!TI);
        TI=0;//發(fā)送標(biāo)志清零,為下次發(fā)送做準(zhǔn)備   
}

/*
函數(shù)功能: 串口發(fā)送多個(gè)數(shù)據(jù)
dat :數(shù)據(jù)指針
len :數(shù)據(jù)長度
*/
void uartsend_string(u8 *pdat)
{
    while(*pdat!='\0')  
    {
            SBUF=*pdat;//數(shù)據(jù)存入SBUF
            while(!TI);
            TI=0;//發(fā)送標(biāo)志清零,為下次發(fā)送做準(zhǔn)備
        pdat++;
    }
}

//lcd1602.c
/*******************************************************************************
* 函 數(shù) 名       : lcd1602_write_cmd
* 函數(shù)功能                 : LCD1602寫命令
* 輸    入       : cmd:指令
* 輸    出             : 無
*******************************************************************************/
void lcd1602_write_cmd(u8 cmd)//8位lcd
{
        LCD1602_RS=0;//選擇命令,RS=1時(shí)為寫命令,等于0時(shí)為寫數(shù)據(jù)
        LCD1602_RW=0;//選擇寫,RW=1為讀,等于0位寫
        LCD1602_E=0;//使能腳
        LCD1602_DATAPORT=cmd;//準(zhǔn)備命令,8位并行數(shù)據(jù)口
        delay_ms(1);
        LCD1602_E=1;//使能腳E先上升沿寫入
        delay_ms(1);
        LCD1602_E=0;//使能腳E后負(fù)跳變完成寫入        
}

/*******************************************************************************
* 函 數(shù) 名       : lcd1602_write_data
* 函數(shù)功能                 : LCD1602寫數(shù)據(jù)
* 輸    入       : dat:數(shù)據(jù)
* 輸    出             : 無
*******************************************************************************/
void lcd1602_write_data(u8 dat)
{
        LCD1602_RS=1;//選擇數(shù)據(jù)
        LCD1602_RW=0;//選擇寫
        LCD1602_E=0;
        LCD1602_DATAPORT=dat;//準(zhǔn)備數(shù)據(jù)
        delay_ms(1);
        LCD1602_E=1;//使能腳E先上升沿寫入
        delay_ms(1);
        LCD1602_E=0;//使能腳E后負(fù)跳變完成寫入               
}


void lcd1602_init(void)//lcd1602初始化
{
//        u8 i=0;
        lcd1602_write_cmd(0x38);//數(shù)據(jù)總線8位,顯示2行,5*7點(diǎn)陣/字符
//        for(i=0;i<200;i++)
                lcd1602_write_cmd(0x0c);//顯示功能開,無光標(biāo),光標(biāo)閃爍

        lcd1602_write_cmd(0x06);//寫入新數(shù)據(jù)后光標(biāo)右移,顯示屏不移動(dòng)
        lcd1602_write_cmd(0x01);//清屏        
}


/*******************************************************************************
* 函 數(shù) 名       : lcd1602_show_string
* 函數(shù)功能                 : LCD1602顯示字符串
* 輸    入       : x,y:顯示坐標(biāo),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;//行列參數(shù)不對則強(qiáng)制退出

        if(y<1)        //第1行顯示
        {        
                while(*str!='\0')//字符串是以'\0'結(jié)尾,只要前面有內(nèi)容就顯示
                {
                        if(i<16-x)//如果字符長度超過第一行顯示范圍,則在第二行繼續(xù)顯示
                        {
                                lcd1602_write_cmd(0x80+i+x);//第一行顯示地址設(shè)置        
                        }
                        else
                        {
                                lcd1602_write_cmd(0x40+0x80+i+x-16);//第二行顯示地址設(shè)置        
                        }
                        lcd1602_write_data(*str);//顯示內(nèi)容
                        str++;//指針遞增
                        i++;        
                }        
        }
        else        //第2行顯示
        {
                while(*str!='\0')
                {
                        if(i<16-x) //如果字符長度超過第二行顯示范圍,則在第一行繼續(xù)顯示
                        {
                                lcd1602_write_cmd(0x80+0x40+i+x);        
                        }
                        else
                        {
                                lcd1602_write_cmd(0x80+i+x-16);        
                        }
                        lcd1602_write_data(*str);
                        str++;
                        i++;        
                }        
        }                                
}

/*******************************************************************************
* 函 數(shù) 名       : lcd1602_show_char
* 函數(shù)功能                 : LCD1602顯示字符
* 輸    入       : x,y:顯示坐標(biāo),x=0~15,y=0~1;
                                   str:顯示字符
* 輸    出             : 無
*******************************************************************************/
void lcd1602_show_char(u8 x,u8 y,u8 chr)
{
        if(y>1||x>15)return;//行列參數(shù)不對則強(qiáng)制退出

        if(y<1)        //第1行顯示
        {        
                lcd1602_write_cmd(0x80+x);//第一行顯示地址設(shè)置        
                lcd1602_write_data(chr);//顯示內(nèi)容               
        }
        else        //第2行顯示
        {
            lcd1602_write_cmd(0x80+0x40+x);        
                lcd1602_write_data(chr);               
        }                                
}

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


回復(fù)

使用道具 舉報(bào)

ID:1080935 發(fā)表于 2024-6-19 08:37 | 顯示全部樓層
為什么要在中斷中調(diào)用顯示函數(shù),顯示函數(shù)運(yùn)行時(shí)間長,可能已經(jīng)影響了你的定時(shí)時(shí)間,導(dǎo)致不正常(程序運(yùn)行時(shí)間大于中斷定時(shí)時(shí)間,中斷程序剛執(zhí)行完,馬上又進(jìn)入中斷,也就是 基本在執(zhí)行中斷程序)。
回復(fù)

使用道具 舉報(bào)

ID:161164 發(fā)表于 2024-6-19 09:34 | 顯示全部樓層
因?yàn)槟銓?602顯示函數(shù)延時(shí)太長了,
根本用不了1ms,40us就夠了
清屏后才需要2ms延時(shí)

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

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

  7. //lcd1602.c
  8. /*******************************************************************************
  9. * 函 數(shù) 名       : lcd1602_write_cmd
  10. * 函數(shù)功能                 : LCD1602寫命令
  11. * 輸    入       : cmd:指令
  12. * 輸    出             : 無
  13. *******************************************************************************/
  14. void lcd1602_write_cmd(u8 cmd)//8位lcd
  15. {
  16.         LCD1602_RS=0;//選擇命令,RS=1時(shí)為寫命令,等于0時(shí)為寫數(shù)據(jù)
  17.         LCD1602_RW=0;//選擇寫,RW=1為讀,等于0位寫
  18.         LCD1602_E=0;//使能腳
  19.         LCD1602_DATAPORT=cmd;//準(zhǔn)備命令,8位并行數(shù)據(jù)口
  20.         LCD1602_E=1;//使能腳E先上升沿寫入
  21.         LCD1602_E=0;//使能腳E后負(fù)跳變完成寫入
  22.                 Delay40us();//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
  23. }

  24. /*******************************************************************************
  25. * 函 數(shù) 名       : lcd1602_write_data
  26. * 函數(shù)功能                 : LCD1602寫數(shù)據(jù)
  27. * 輸    入       : dat:數(shù)據(jù)
  28. * 輸    出             : 無
  29. *******************************************************************************/
  30. void lcd1602_write_data(u8 dat)
  31. {
  32.         LCD1602_RS=1;//選擇數(shù)據(jù)
  33.         LCD1602_RW=0;//選擇寫
  34.         LCD1602_E=0;
  35.         LCD1602_DATAPORT=dat;//準(zhǔn)備數(shù)據(jù)
  36.         LCD1602_E=1;//使能腳E先上升沿寫入
  37.         LCD1602_E=0;//使能腳E后負(fù)跳變完成寫入
  38.                 Delay40us();//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<            
  39. }


  40. void lcd1602_init(void)//lcd1602初始化
  41. {
  42. //        u8 i=0;
  43.         lcd1602_write_cmd(0x38);//數(shù)據(jù)總線8位,顯示2行,5*7點(diǎn)陣/字符
  44. //        for(i=0;i<200;i++)
  45.                 lcd1602_write_cmd(0x0c);//顯示功能開,無光標(biāo),光標(biāo)閃爍

  46.         lcd1602_write_cmd(0x06);//寫入新數(shù)據(jù)后光標(biāo)右移,顯示屏不移動(dòng)
  47.         lcd1602_write_cmd(0x01);//清屏   
  48.         delay_ms(2);//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<         
  49. }
復(fù)制代碼
回復(fù)

使用道具 舉報(bào)

ID:123289 發(fā)表于 2024-6-20 20:23 | 顯示全部樓層
T0的優(yōu)先級比較高,當(dāng)它進(jìn)行服務(wù)程序后,其它低級的中斷就無法立即響應(yīng)了,可以會(huì)丟失中斷。
回復(fù)

使用道具 舉報(bào)

ID:675287 發(fā)表于 2024-6-21 11:47 | 顯示全部樓層
這個(gè)顯示函數(shù)沒必要在中斷里面調(diào)用,運(yùn)行時(shí)間大于中斷的間隔時(shí)間就會(huì)出問題了
回復(fù)

使用道具 舉報(bào)

ID:313517 發(fā)表于 2024-6-21 23:07 | 顯示全部樓層
中斷時(shí)間夠不夠,程序運(yùn)行時(shí)間太長了,中斷時(shí)間太短了
回復(fù)

使用道具 舉報(bào)

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表