找回密码
 立即注册

QQ登录

只需一步,快速开始

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

关于STC8H1k08单片机中断竞争

[复制链接]
跳转到指定楼层
楼主
ID:1055194 发表于 2022-12-2 13:40 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
软件开发环境:Keil5,STC-ISP。
硬件环境:自己画的板子,两个外部中断都没有加外部上拉电阻(用的是STC内部的上拉电阻),I2C有外部上拉(STC的I2C管脚设为开漏)
我在试验使用一个旋转编码器控制OLED屏幕的显示内容,功能分为两个:1. 旋转编码器使用外部中断进行检测。
2. OLED屏用I2C中断通信。

我先把两个功能分别做好测试好了,但是组合在一起以后外部中断就完全无法响应(或者说一直被触发但没有执行,原因我贴在后面的代码里),I2C和UART功能正常。

想说用硬件仿真,结果每次仿真跑到:【P_SW2|=0x80; //访问扩展寄存器Enable】 的时候仿真就断了。实在无语。。。

然后尝试调整中断优先级,把外部中断优先级设为3(最高),I2C设为0(最低),结果没有变化,还是不行。

最后的解决方法是把I2C中断关闭,设置为询问式;把UART中断关闭,设为询问式,也就是只有外部中断,其他中断都禁止了。然后外部中断才能正常响应。

PS: 有人说你直接用例程拼起来就行啦,实际是官方的I2C例程有点问题,并不能正常运行。所以自己重新写了一个。

功能虽然勉强实现了,但问题始终没有解决,请有经验的大神指教指教,谢谢!

单片机代码:

#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);              //之前说外部中断一直被触发但没有执行,原因就在这里,我打印 TCON 寄存器的值,得到的都是0xFF,也就是外部触发标志位一直置位,就算手动清零也清不掉(试过,没用就把代码删了)。不用I2C中断之后,TCON寄存器的值就正常了,该响应响应。
                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;
        }
}
分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:1044091 发表于 2022-12-2 14:58 | 只看该作者
我的经验是,EC11尽量不要使用外部中断来检测,会干扰外设的正常运行。建议把EC11代码封装成函数,在while(1)中放一个1ms(实际上5ms以内都可以,时基大点防抖,小点反应灵敏,可试验确定最合适的时基),每隔1ms检测一下EC11函数,有动作就执行加减操作。我现在做的EC11数码管菜单就是这样用的,数值可从0.01到999,支持快慢转,没有问题。
回复

使用道具 举报

板凳
ID:1055194 发表于 2022-12-2 15:39 | 只看该作者
ningsy 发表于 2022-12-2 14:58
我的经验是,EC11尽量不要使用外部中断来检测,会干扰外设的正常运行。建议把EC11代码封装成函数,在while( ...

所以问题可能不是程序和电路,而是旋转编码器本身的特性造成外部中断出问题是吗?谢谢你的建议 :-D
回复

使用道具 举报

地板
ID:1044091 发表于 2022-12-2 15:58 | 只看该作者
素阳工坊 发表于 2022-12-2 15:39
所以问题可能不是程序和电路,而是旋转编码器本身的特性造成外部中断出问题是吗?谢谢你的建议 :-D

我觉的是程序的问题,不能用外部中断检测EC11。我的外设是步进电机,用外部中断检测EC11就会干扰步进电机运行。所以改用正常的I/O检测EC11通断,在while中查询EC11函数的状态。所以你的EC11代码需要改成正常的I/O检测。
回复

使用道具 举报

5#
ID:401564 发表于 2022-12-2 16:13 | 只看该作者
IIC硬件中断开启之后,必须在 interrupt 24 中断中执行清除IIC中断标志位 I2CMSST 的操作
不然就会卡在IIC中断出不去了
I2CMSST置位会触发中断,不清除的话,中断会一直触发,就一直卡在这不动了

        while (!(I2CMSST & 0x40));//程序在这应该是卡住了
        I2CMSST &= ~0x40;//开启了中断的话,这个语句应该是在中断中执行的,在这永远执行不到

8051的中断没有竞争,它有默认的中断执行和查询顺序,不会有竞争的
另外,对于EC11,赞同楼上的说法,不要用外部中断来检测EC11,外部中断在8051中有最高级别的中断等级,可以打断所有的中断,程序处理不好,容易出事
回复

使用道具 举报

6#
ID:1055194 发表于 2022-12-2 20:33 | 只看该作者
Y_G_G 发表于 2022-12-2 16:13
IIC硬件中断开启之后,必须在 interrupt 24 中断中执行清除IIC中断标志位 I2CMSST 的操作
不然就会卡在IIC ...

谢谢你的建议,I2CMSST的中断标志位我确实用软件清除了的,I2C功能在各个情况下都能正常运行。问题是TCON寄存器中 IE1 和 IE0 这两个外部中断的请求标志一直为 1,但外部中断程序响应了一次以后就再也响应不了, 也就是 IE1 和 IE0 要么没有被硬件自动清零,要么是一直在中断中出不去。我试一下在中断中添加EA=0,关了中断试试吧,谢谢!
回复

使用道具 举报

7#
ID:1034262 发表于 2022-12-2 20:38 | 只看该作者
首先,STC官方的I2C例程没有问题,我用过的,并且STC公司的例程他们的工程师也会严格测试的,否则那么多用户用过,有问题早改好了。
其次,8051的中断,高优先级的可以嵌套低优先级的,不会乱的,不存在竞争的问题。只要中断间隔大于中断执行时间,就不会有问题。如果中断处理时间长于中断间隔,则这个中断会几乎耗掉CPU的时间,MCU都会如此的。
回复

使用道具 举报

8#
ID:1034262 发表于 2022-12-2 20:39 | 只看该作者
再次,STC8H系列的MCU,带有2个硬件的编码器接口,楼主可以试试,我用着挺好,几百KHz都能响应。
回复

使用道具 举报

9#
ID:401564 发表于 2022-12-2 21:24 | 只看该作者
素阳工坊 发表于 2022-12-2 20:33
谢谢你的建议,I2CMSST的中断标志位我确实用软件清除了的,I2C功能在各个情况下都能正常运行。问题是TCON ...

那就是EC11那的问题
为什么一定要仿真呢?
EC11是一直短路到地的
回复

使用道具 举报

10#
ID:1055194 发表于 2022-12-2 21:47 | 只看该作者
coody_sz 发表于 2022-12-2 20:39
再次,STC8H系列的MCU,带有2个硬件的编码器接口,楼主可以试试,我用着挺好,几百KHz都能响应。

谢谢,我试试
回复

使用道具 举报

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

本版积分规则

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

Powered by 单片机教程网

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