查看: 7059|回复: 1

关于51单片机外部中断只能触发一次的问题

[复制链接]
  • TA的每日心情
    奋斗
    2018-10-29 22:48
  • 签到天数: 731 天

    连续签到: 1 天

    [LV.9]以坛为家II

    发表于 2014-8-24 14:16:22 | 显示全部楼层 |阅读模式
    分享到:
    很久没有玩51单片机了,周末拿出来以前自己做的51单片机板子,顺手用写ARM芯片程序的风格为51单片机写了个基础固件库。写到外部中断的时候遇到了一个问题,当使用下降沿触发的时候只能触发一次,再次触发就没反应了。我找了一些51单片机的样例程序,绝大多数都是驱动外设的,51片上这几个模块的演示不多。我把代码贴出来让熟悉51的大侠们帮忙看一下。

    根据在其它芯片上经验,总结51中断的几个相关的配置:
    EA:总中断开关
    IT0/IT1: 配置外部中断触发方式。1:下降沿触发;0:低电平触发。
    IE0/IE1: 外部中断触发标志位。当产生中断请求时,该标志位置1。在下降沿触发模式下,该标志位自动清零;低电平触发模式下需手动清。
    EX0/EX1: 外部中断各自使能控制位。1:开中断;0:关中断。
    PS:麻烦诸位帮忙确认一下这部分内容,毕竟程序运行不正常,每个环节都值得怀疑。

    在电路上,我在INT0(P3.2)和INT1(P3.3)引脚上各接了一个带上拉电阻的按键。想用这两个按键分别控制开灯和关灯。
    主要代码附后,现象是复位后,分别按下两个按键(部分先后顺序),串口都有信息输出来。但是,再按按键,串口就没反映了。也就是说,INT0和INT1只能接受第一次中断事件。再次复位后,现象重复。

    根据以往的经验猜测如下:
    1. 是不是还有标志需要清一下。如果是这样,那在下降沿触发模式下自动清标志无效,还是需要手动清标志IE0/IE1。
    2. 产生了中断嵌套,主循环的程序没有机会执行。
    3. 主循环的应用程序设计不合适。

    猜测的问题点自己也做了一些实验,仍没有排除错误情况,必然还有疏漏之处。

    代码:
    ==================================================================
    /* main.c */

    volatile bit bINT0Flag = 0;
    volatile bit bINT1Flag = 0;

    int main(void)
    {
        IT0 = 1;  /* Trigger by falling edge. */
        IT1 = 1;
        EX0 = 1; /* Enable external interrupt. */
        EX1 = 1;
        EA = 1; /* Enable global Interrupts. */

        while (1)
        {
            if (1 == bINT0Flag)
            {
                bINT0Flag = 0;
                /* LED on */
                UART_PutStr("LED on.\r\n");
            }
            if (1 == bINT1Flag)
            {
                bINT1Flag = 0;
                /* LED off */
                UART_PutStr("LED off.\r\n");
            }
        }
    }

    void INT0_IRQHandler(void) interrupt 0
    {
        EX0 = 0;
        bINT0Flag = 1;
        EX0 = 1;
    }

    void INT1_IRQHandler(void) interrupt 2
    {
        EX1 = 0;
        bINT1Flag = 1;
        EX1 = 1;
    }

    ==================================================================



    回复

    使用道具 举报

  • TA的每日心情
    奋斗
    2018-10-29 22:48
  • 签到天数: 731 天

    连续签到: 1 天

    [LV.9]以坛为家II

     楼主| 发表于 2014-8-25 00:02:09 | 显示全部楼层
    终于找到原因了,程序是没问题的,这里多谢@骑蚂蚁闯红灯,帮忙验证了程序。这兄弟是一个51单片机学习QQ群的朋友,自己也做了一块51开发板。

    这里贴出的程序是OK的,而我实际用的程序上用了自己封装的GPIO操作驱动程序。在GPIO的驱动程序中用的是读改写整个端口寄存器对实现单个比特位的操作,实际上这也是其它大多数非51单片机实现GPIO操作的方式。但是这种方式在51单片机中就是不行!

    在51单片机中,如果要设定一个引脚的数据方向为输入,在读数据之前要向引脚对应的数据寄存器位写1,这是跟51单片机GPIO的电路实现有关的,具体内容在STC的手册中有详细说明。在我实际用的程序中,INT0、INT1及一个LED均位于P3口,当第一次INT0被下降沿触发时,GPIO的API操作P3口,先是读P3整个端口的内容,注意,这个时候读到的INT0引脚电平为低!然后改掉小灯作为那一个比特位的值,最后将整个P3口的8位值写回去。这个时候INT0口对应的数据位已经被写0了,INT0引脚上的电平也成了低电平,不能识别之后的下降沿了。INT1也是同样的情况。所以就出现了帖子中描述的INT0和INT1只能触发一次的情况。

    后来在固件库的源文件中,为每个端口开出一个全局变量,专门记录设定引脚的数据方向。在读改写操作端口的数据值时,如果之前配置引脚方向的是输入,则无论在引脚上读到的是什么电平,写回去的时候还是要保持为高电平。这样,在不需要修改原有的应用程序的前提下,就把问题解决啦。

    折腾了一个周末,到这个时候终于有了点成就感,呵呵。
    回复 支持 反对

    使用道具 举报

    您需要登录后才可以回帖 注册/登录

    本版积分规则

    关闭

    站长推荐上一条 /4 下一条



    手机版|小黑屋|与非网

    GMT+8, 2024-11-15 09:55 , Processed in 0.117682 second(s), 17 queries , MemCache On.

    ICP经营许可证 苏B2-20140176  苏ICP备14012660号-2   苏州灵动帧格网络科技有限公司 版权所有.

    苏公网安备 32059002001037号

    Powered by Discuz! X3.4

    Copyright © 2001-2024, Tencent Cloud.