找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開(kāi)始

搜索
查看: 2323|回復(fù): 9
收起左側(cè)

關(guān)于STC8H1k08單片機(jī)中斷競(jìng)爭(zhēng)

[復(fù)制鏈接]
ID:1055194 發(fā)表于 2022-12-2 13:40 | 顯示全部樓層 |閱讀模式
軟件開(kāi)發(fā)環(huán)境:Keil5,STC-ISP。
硬件環(huán)境:自己畫(huà)的板子,兩個(gè)外部中斷都沒(méi)有加外部上拉電阻(用的是STC內(nèi)部的上拉電阻),I2C有外部上拉(STC的I2C管腳設(shè)為開(kāi)漏)
我在試驗(yàn)使用一個(gè)旋轉(zhuǎn)編碼器控制OLED屏幕的顯示內(nèi)容,功能分為兩個(gè):1. 旋轉(zhuǎn)編碼器使用外部中斷進(jìn)行檢測(cè)。
2. OLED屏用I2C中斷通信。

我先把兩個(gè)功能分別做好測(cè)試好了,但是組合在一起以后外部中斷就完全無(wú)法響應(yīng)(或者說(shuō)一直被觸發(fā)但沒(méi)有執(zhí)行,原因我貼在后面的代碼里),I2C和UART功能正常。

想說(shuō)用硬件仿真,結(jié)果每次仿真跑到:【P_SW2|=0x80; //訪問(wèn)擴(kuò)展寄存器Enable】 的時(shí)候仿真就斷了。實(shí)在無(wú)語(yǔ)。。。

然后嘗試調(diào)整中斷優(yōu)先級(jí),把外部中斷優(yōu)先級(jí)設(shè)為3(最高),I2C設(shè)為0(最低),結(jié)果沒(méi)有變化,還是不行。

最后的解決方法是把I2C中斷關(guān)閉,設(shè)置為詢問(wèn)式;把UART中斷關(guān)閉,設(shè)為詢問(wèn)式,也就是只有外部中斷,其他中斷都禁止了。然后外部中斷才能正常響應(yīng)。

PS: 有人說(shuō)你直接用例程拼起來(lái)就行啦,實(shí)際是官方的I2C例程有點(diǎn)問(wèn)題,并不能正常運(yùn)行。所以自己重新寫(xiě)了一個(gè)。

功能雖然勉強(qiáng)實(shí)現(xiàn)了,但問(wèn)題始終沒(méi)有解決,請(qǐng)有經(jīng)驗(yàn)的大神指教指教,謝謝!

單片機(jī)代碼:

#include "STC8xxxx.h"
#include "config.h"

#include "STC8H_I2C.h"
#include "STC8H1K08ExINT.h"
#include "SSD1315.h"

#define PinB P12


void Delay10us(void)
{
        unsigned char i;
        _nop_();
        i = 155;//15
        while (--i) _nop_();
}

void Delay1000ms()                //@22.1184MHz
{
        unsigned char i, j, k;

        _nop_();
        _nop_();
        i = 85;
        j = 12;
        k = 155;
        do
        {
                do
                {
                        while (--k);
                } while (--j);
        } while (--i);
}




unsigned char Int0=0,Int1=0;


//================================================================================//
/**********************************************************************************/
//================================================================================//

void main(){
        unsigned char n=0,k=0,l=0,j=0,z=0;
        char i=1;
        P_SW2|=0x80;
        EA=1;
        
        
        i2c_init();
        i2c_pin_config(P14_P15);               
        INT_PinConfig(1,1);//set IN0/IN1 PIN PullUP
        set_INT1_falling_edge;
        set_INT0_falling_edge;
        Dis_INT0;
        Dis_INT1;
        
        P1M0|=0x08;// set P13 Beeper push/pull output, P12 High R input.
        P1M1|=0x04;// set P13 Beeper push/pull output, P12 High R input.
        P1PU|=0x04;// set P12 Pullup Resister enable.
        
        OLED_ini();
        OLED_Clear();
        
        
        Set_INT0_Priority(3);
        Set_INT1_Priority(3);
        
        
        while(1){
                En_INT0;
                En_INT1;
                TX1_write2buff(TCON);              //之前說(shuō)外部中斷一直被觸發(fā)但沒(méi)有執(zhí)行,原因就在這里,我打印 TCON 寄存器的值,得到的都是0xFF,也就是外部觸發(fā)標(biāo)志位一直置位,就算手動(dòng)清零也清不掉(試過(guò),沒(méi)用就把代碼刪了)。不用I2C中斷之后,TCON寄存器的值就正常了,該響應(yīng)響應(yīng)。
                if(Int1){                                        //Detect Encoder spining direction
                        Dis_INT1;
                        if(k){
                                if(PinB) l++;
                        }
                        Int1=0;
                        k++;
                        En_INT1;
                }
                if(k==2){
                        Dis_INT1;
                        if(l){
                                i--;
                                if(i<1){
                                        i=8;
                                }
                        }
                        else{
                                i++;
                                if(i>8){
                                        i=1;
                                }
                        }
                        OLED_Clear();
                        for(n=0;n<128;n++){
                                OLED_Set_Pos(n,i-1);
                                OLED_WR_Byte(0x01,Data);
                                write_img_flash(n,i-1,0x01);
                        }
                        Int1=0;
                        k=0;
                        l=0;
                        En_INT1;
                }
                if(Int0){
                        int x=10,y=7;
                        Dis_INT0;
                        
                        write_word(1,1,0,0);
                        
                        Combine_img(0,32,32,x,y,IMG_and);
                        Write_change_data(x,y,x+32,y+32);
                        
                        Int0=0;
                        En_INT0;
                }
        
        }
}

void INT1_Service() interrupt 2 {
        Int1=1;
}


void INT0_Service() interrupt 0 {
        Int0=1;
}





//---------------------   STC8H1K08ExINT.H:-------------------//

#ifndef _STC8H1K08ExINT_H_
#define        _STC8H1K08ExINT_H_



#define En_INT IE|=0x80;                //Set IE bit.7 EA to 1, GlobalInterupt Control Enable.
#define Dis_INT IE&=~0x80;        //Set IE bit.7 EA to 0, GlobalInterupt Control Disable.

#define En_INT1 IE|=0x04           //Set IE bit.2 EX1 to 1, External Interupt 1 Enable.
#define Dis_INT1 IE&=~0x04         //Set IE bit.2 EX1 to 0, External Interupt 1 Disable.

#define En_INT0 IE|=0x01                //Set IE bit.0 EX0 to 1, External Interupt 1 Enable.
#define Dis_INT0 IE&=~0x01        //Set IE bit.0 EX0 to 0, External Interupt 1 Disable.

#define set_INT1_rising_and_falling_edge  TCON&= ~0x04        //Set TCON bit.2 to 0, INT1 rising&falling edge detect.
#define set_INT1_falling_edge  TCON|=0x04                                                                //Set TCON bit.2 to 1, falling edge detect.

#define set_INT0_rising_and_falling_edge  TCON&= ~0x01        //Set TCON bit.0 to 0, INT0 rising&falling edge detect.
#define set_INT0_falling_edge  TCON|=0x01                                                                //Set TCON bit.0 to 1, INT0 falling edge detect.


void INT_PinConfig(unsigned char ,unsigned char );//set IN0/IN1 PIN PullUP
void Set_INT0_Priority(unsigned char );
void Set_INT1_Priority(unsigned char );



#endif




//---------------------   STC8H1K08ExINT.c:-------------------//
#include "STC8xxxx.h"
#include "STC8H1K08ExINT.h"


void INT_PinConfig(unsigned char IN0,unsigned char IN1)//set IN0/IN1 PIN State
{
        if(IN0) {
                P3PU|=0x04;                //set P3PU bit.2 to 1, Interal PullUP R Enable.
                P3M0&=~0x04;        //set P3M0 bit.2 to 0, High R Input.
                P3M1|=0x04;                //set P3M1 bit.2 to 1, High R Input.
        }
        else{
                P3PU&=~0x04;        //set P3PU bit.2 to 0, Interal PullUP R Disable.
                P3M0&=~0x04;        //set P3M0 bit.2 to 0.
                P3M1&=~0x04;        //set P3M1 bit.2 to 0.
        }
        if(IN1) {
                P3PU|=0x08;                //set P3PU bit.3 to 1, Interal PullUP R Enable.
                P3M0&=~0x08;        //set P3M0 bit.3 to 0, High R Input.
                P3M1|=0x08;                //set P3M1 bit.3 to 1, High R Input.
        }
        else{
                P3PU&=~0x08;        //set P3PU bit.3 to 0, Interal PullUP R Disable.
                P3M0&=~0x08;        //set P3M0 bit.3 to 0.
                P3M1&=~0x08;        //set P3M1 bit.3 to 0.
        }
}

void Set_INT0_Priority(unsigned char pr){
        switch(pr){
                case 0:IP&=~0x01;IPH&=~0x01;
                case 1:IP|=0x01;IPH&=~0x01;
                case 2:IP&=~0x01;IPH|=0x01;
                case 3:IP|=0x01;IPH|=0x01;
        }
}

void Set_INT1_Priority(unsigned char pr){
        switch(pr){
                case 0:IP&=~0x04;IPH&=~0x04;
                case 1:IP|=0x04;IPH&=~0x04;
                case 2:IP&=~0x04;IPH|=0x04;
                case 3:IP|=0x04;IPH|=0x04;
        }
}




//---------------------   STC8H_I2C.H:-------------------//
#ifndef _STC8H_I2C_H_
#define        _STC8H_I2C_H_



#define P14_P15 1
#define P33_P32 4

void i2c_init(void);

void Wait(void);

void i2c_start(void);

void i2c_stop(void);

void Set_I2C_INT_Priority(unsigned char);

void i2c_pin_config(unsigned char );


#endif


//---------------------   STC8H_I2C.C:-------------------//
#include "STC8xxxx.h"


void i2c_init(void){
        P_SW2 |=0x80;
        IE|=0x80;
        //最高400kHz
        I2CCFG|=0xCD;//D8
        I2CMSCR|=0x00;
        I2CMSAUX|=0x01;
        I2CMSST=0x00;
        
}

void i2c_pin_config(unsigned char pin){
        switch(pin){
                case 1: P1M1|=0x30;        P1M0|=0x30;        //P14,P15 Open Drain
                case 4: P3M1|=0x0C; P3M0|=0x0C; //P33,P32 Open Drain
        }
}

void Wait(){
        P_SW2 |= 0x80;
        while (!(I2CMSST & 0x40));
        I2CMSST &= ~0x40;
}

void i2c_start(void){
        I2CMSCR=0X01;
        Wait();
}

void i2c_stop(void){
        I2CMSCR=0X06;
        Wait();
}


void Set_I2C_INT_Priority(unsigned char pr){
        switch(pr){
                case 0:IP2&=~0x40;IP2H&=~0x40;
                case 1:IP2|=0x40;IP2H&=~0x40;
                case 2:IP2&=~0x40;IP2H|=0x40;
                case 3:IP2|=0x40;IP2H|=0x40;
        }
}
回復(fù)

使用道具 舉報(bào)

ID:1044091 發(fā)表于 2022-12-2 14:58 | 顯示全部樓層
我的經(jīng)驗(yàn)是,EC11盡量不要使用外部中斷來(lái)檢測(cè),會(huì)干擾外設(shè)的正常運(yùn)行。建議把EC11代碼封裝成函數(shù),在while(1)中放一個(gè)1ms(實(shí)際上5ms以內(nèi)都可以,時(shí)基大點(diǎn)防抖,小點(diǎn)反應(yīng)靈敏,可試驗(yàn)確定最合適的時(shí)基),每隔1ms檢測(cè)一下EC11函數(shù),有動(dòng)作就執(zhí)行加減操作。我現(xiàn)在做的EC11數(shù)碼管菜單就是這樣用的,數(shù)值可從0.01到999,支持快慢轉(zhuǎn),沒(méi)有問(wèn)題。
回復(fù)

使用道具 舉報(bào)

ID:1055194 發(fā)表于 2022-12-2 15:39 | 顯示全部樓層
ningsy 發(fā)表于 2022-12-2 14:58
我的經(jīng)驗(yàn)是,EC11盡量不要使用外部中斷來(lái)檢測(cè),會(huì)干擾外設(shè)的正常運(yùn)行。建議把EC11代碼封裝成函數(shù),在while( ...

所以問(wèn)題可能不是程序和電路,而是旋轉(zhuǎn)編碼器本身的特性造成外部中斷出問(wèn)題是嗎?謝謝你的建議 :-D
回復(fù)

使用道具 舉報(bào)

ID:1044091 發(fā)表于 2022-12-2 15:58 | 顯示全部樓層
素陽(yáng)工坊 發(fā)表于 2022-12-2 15:39
所以問(wèn)題可能不是程序和電路,而是旋轉(zhuǎn)編碼器本身的特性造成外部中斷出問(wèn)題是嗎?謝謝你的建議 :-D

我覺(jué)的是程序的問(wèn)題,不能用外部中斷檢測(cè)EC11。我的外設(shè)是步進(jìn)電機(jī),用外部中斷檢測(cè)EC11就會(huì)干擾步進(jìn)電機(jī)運(yùn)行。所以改用正常的I/O檢測(cè)EC11通斷,在while中查詢EC11函數(shù)的狀態(tài)。所以你的EC11代碼需要改成正常的I/O檢測(cè)。
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2022-12-2 16:13 | 顯示全部樓層
IIC硬件中斷開(kāi)啟之后,必須在 interrupt 24 中斷中執(zhí)行清除IIC中斷標(biāo)志位 I2CMSST 的操作
不然就會(huì)卡在IIC中斷出不去了
I2CMSST置位會(huì)觸發(fā)中斷,不清除的話,中斷會(huì)一直觸發(fā),就一直卡在這不動(dòng)了

        while (!(I2CMSST & 0x40));//程序在這應(yīng)該是卡住了
        I2CMSST &= ~0x40;//開(kāi)啟了中斷的話,這個(gè)語(yǔ)句應(yīng)該是在中斷中執(zhí)行的,在這永遠(yuǎn)執(zhí)行不到

8051的中斷沒(méi)有競(jìng)爭(zhēng),它有默認(rèn)的中斷執(zhí)行和查詢順序,不會(huì)有競(jìng)爭(zhēng)的
另外,對(duì)于EC11,贊同樓上的說(shuō)法,不要用外部中斷來(lái)檢測(cè)EC11,外部中斷在8051中有最高級(jí)別的中斷等級(jí),可以打斷所有的中斷,程序處理不好,容易出事
回復(fù)

使用道具 舉報(bào)

ID:1055194 發(fā)表于 2022-12-2 20:33 | 顯示全部樓層
Y_G_G 發(fā)表于 2022-12-2 16:13
IIC硬件中斷開(kāi)啟之后,必須在 interrupt 24 中斷中執(zhí)行清除IIC中斷標(biāo)志位 I2CMSST 的操作
不然就會(huì)卡在IIC ...

謝謝你的建議,I2CMSST的中斷標(biāo)志位我確實(shí)用軟件清除了的,I2C功能在各個(gè)情況下都能正常運(yùn)行。問(wèn)題是TCON寄存器中 IE1 和 IE0 這兩個(gè)外部中斷的請(qǐng)求標(biāo)志一直為 1,但外部中斷程序響應(yīng)了一次以后就再也響應(yīng)不了, 也就是 IE1 和 IE0 要么沒(méi)有被硬件自動(dòng)清零,要么是一直在中斷中出不去。我試一下在中斷中添加EA=0,關(guān)了中斷試試吧,謝謝!
回復(fù)

使用道具 舉報(bào)

ID:1034262 發(fā)表于 2022-12-2 20:38 | 顯示全部樓層
首先,STC官方的I2C例程沒(méi)有問(wèn)題,我用過(guò)的,并且STC公司的例程他們的工程師也會(huì)嚴(yán)格測(cè)試的,否則那么多用戶用過(guò),有問(wèn)題早改好了。
其次,8051的中斷,高優(yōu)先級(jí)的可以嵌套低優(yōu)先級(jí)的,不會(huì)亂的,不存在競(jìng)爭(zhēng)的問(wèn)題。只要中斷間隔大于中斷執(zhí)行時(shí)間,就不會(huì)有問(wèn)題。如果中斷處理時(shí)間長(zhǎng)于中斷間隔,則這個(gè)中斷會(huì)幾乎耗掉CPU的時(shí)間,MCU都會(huì)如此的。
回復(fù)

使用道具 舉報(bào)

ID:1034262 發(fā)表于 2022-12-2 20:39 | 顯示全部樓層
再次,STC8H系列的MCU,帶有2個(gè)硬件的編碼器接口,樓主可以試試,我用著挺好,幾百KHz都能響應(yīng)。
回復(fù)

使用道具 舉報(bào)

ID:401564 發(fā)表于 2022-12-2 21:24 | 顯示全部樓層
素陽(yáng)工坊 發(fā)表于 2022-12-2 20:33
謝謝你的建議,I2CMSST的中斷標(biāo)志位我確實(shí)用軟件清除了的,I2C功能在各個(gè)情況下都能正常運(yùn)行。問(wèn)題是TCON ...

那就是EC11那的問(wèn)題
為什么一定要仿真呢?
EC11是一直短路到地的
回復(fù)

使用道具 舉報(bào)

ID:1055194 發(fā)表于 2022-12-2 21:47 | 顯示全部樓層
coody_sz 發(fā)表于 2022-12-2 20:39
再次,STC8H系列的MCU,帶有2個(gè)硬件的編碼器接口,樓主可以試試,我用著挺好,幾百KHz都能響應(yīng)。

謝謝,我試試
回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

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

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

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