张明峰的《PIC单片机入门与实战》第五章,PORTB改写为C程序,与汇编仿真结果不一致,帮忙

2020-02-09 11:36发布

书上原来是汇编程序,我给修改了用PORTD输出扫描到的按键码,可以正常的显示,按下某个按键,就会显示出某个按键码,延时结束后,LED就会灭掉。而修改成C程序,按下某个按键,可以正常显示按键码,但是延时结束后,仍然显示,直到按新的按键,才会发生变化。可以帮忙修改一下么?谢谢了!
另外,新手,尽量讲的详细一些,谢谢!

Proteus仿真电路以及汇编、C程序ourdev_556000.rar(文件大小:19K) (原文件名:按键中断仿真.rar)

Proteus仿真图片 (原文件名:仿真.jpg)

C源程序,这些都包含在附件中,这个是给不想下附件的看的。
//=============头文件及配置===================
#include<pic.h>
__CONFIG(HS & PROTECT & PWRTEN & BOREN & WDTDIS);
//============全局变量====================
unsigned char KeyCode[8];
unsigned char KeySaved=0x00;
unsigned char KeyCurrent=0x00;
//===========函数声明======================
void KeyCheck(unsigned char KeySaved,unsigned char KeyCurrent);
void Delay(void);
//===========主函数========================
main()
{
        TRISB=0xF0;//PORTB高4位输入,低4位输出
        TRISD=0x00;//PORTD全输出
        PORTD=0x00;//PORTD清零
        PORTB=0x00;//PORTB清零,PORTB=B'11110000'
        RBPU=0;//在C里,NOT_RBPU位即RBPU位,开启PORTB的内部弱上拉
        RBIE=1;//开启PORTB端口引脚状态变化中断
        GIE=1;//开启总中断
        while(1)
        {
                PORTD=0x00;
                PORTB=0x00;
                KeyCheck(KeySaved,KeyCurrent);//按键检测
        }               
}
//==============================================
void interrupt RbInt(void)
{
    unsigned char ScanCode=0xEF;//定义按键扫描
    unsigned int k;
     if(RBIE && RBIF)//判断中断使能和中断标志位
     {
         RBIF=0;//清零中断标志位
         if((PORTB & 0xF0)!=0xF0)//如果有按键按下
            {
                 for(k=0;k<5;k++)
                    {
                       PORTB=ScanCode;//输出初始扫描值,PORTB的引脚上逻辑电平高4为不变
                       if((PORTB & 0xF0)!=0xF0)
                       {
                           KeyCode[KeyCurrent]=PORTB;
                           break;
                          }
                      else
                        {
                           ScanCode=ScanCode>>1;//扫描码循环右移,这个移的乱七八糟的
                                               //不知道是仿真的问题,还是移位的问题
                                              //原理就是低4为依次循环输出0,而其他位为高
                            }
                    }                       
               }
              KeyCurrent++;//当前按键存储偏移位置加1
               KeyCurrent=KeyCurrent & 0x07;//确保按键存储偏移位置小于8
        }
}
//==============================================
void KeyCheck(unsigned char KeySaved,unsigned char KeyCurrent)//按键检测函数
{
       if(KeyCurrent!=KeySaved)//如果当前按键偏移位置和已有的按键偏移位置不相等,则有新的按键
          {
              PORTD=KeyCode[KeySaved];//读保存的按键码
              Delay();//延时显示
              KeySaved = KeyCurrent;//已有按键偏移位置加1,与当前按键偏移位置同步
              //KeySaved = KeySaved & 0x07;//确保按键已存储偏移位置小于8
          }
          else PORTD=0x00;
}
//==============================================
void  Delay(void)//延时
{
   int n;
   for(n=0;n<=5000;n++)
   continue;
}
//==============================================
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
17条回答
guyanqiu
2020-02-10 06:11
哈哈,不是单片机学的不明白,而是C没有学明白,我调试的时候,发现KeyCurrent的值是正常,而KeySaved的值在函数KeyCheck()中正常,可是出了函数的范围就又归零了。因为函数中重声明了KeyCurrent和KeySaved变量,就不再是原来的变量了,所以函数结束,并没有改变外部的KeySaved的值。重新修改函数KeyChek(),终于得到想要的结果了。
不过还有一个问题,就是长时间按着一个按键的话,仿真的时候,PORTB低4位引脚电平不停的循环,然后会有黄 {MOD}的叹号提示:
Simulation is not running in real time due to excessive CPU load。
如果短按键的话,下面的CPU Load才25%左右,不动作4%左右,长按键80%左右。对照汇编程序看了一下,发现汇编是在中断处理结束的时候才清除中断标志位的,把清除中断标志位放到中断函数的末尾,程序终于运行正常了。
还是要学好C,呵呵,基础不扎实啊。
有始有终,下面是修改好的C程序。
//=============头文件及配置===================
#include<pic.h>
__CONFIG(HS & PROTECT & PWRTEN & BOREN & WDTDIS);
//============全局变量====================
unsigned char KeyCode[8];
unsigned char KeySaved=0x00;
unsigned char KeyCurrent=0x00;
//===========函数声明======================
void KeyCheck(void);
void Delay(void);
//===========主函数========================
main()
{
        TRISB=0xF0;//PORTB高4位输入,低4位输出
        TRISD=0x00;//PORTD全输出
        PORTD=0x00;//PORTD清零
        PORTB=0xF0;//PORTB清零,PORTB=B'11110000'
        RBPU=0;//在C里,NOT_RBPU位即RBPU位,开启PORTB的内部弱上拉
        RBIE=1;//开启PORTB端口引脚状态变化中断
        GIE=1;//开启总中断
        while(1)
        {
                PORTD=0x00;
                PORTB=0xF0;
                KeyCheck();//按键检测
        }               
}
//==============================================
void interrupt RbInt(void)
{
        unsigned char ScanCode=0xF7;//定义按键扫描
        unsigned int k;
        if(RBIE && RBIF)//判断中断使能和中断标志位
        {
                //RBIF=0;//清零中断标志位,先清除的话问题多多
                if((PORTB & 0xF0)!=0xF0)//如果有按键按下
                {
                        for(k=0;k<4;k++)
                        {
                                PORTB=ScanCode;//输出初始扫描值,PORTB的引脚上逻辑电平高4为不变
                                if((PORTB & 0xF0)!=0xF0)
                                {
                                        KeyCode[KeyCurrent]=PORTB;
                                        break;
                                }
                                else
                                {
                                        ScanCode=ScanCode>>1;//扫描码循环右移
                                }
                        }
                        KeyCurrent++;//当前按键存储偏移位置加1
                        KeyCurrent=KeyCurrent & 0x07;//确保按键存储偏移位置小于8                               
                 }
        }
        RBIF=0;//清零中断标志位,中断处理完毕再清除,好像就正常了
}
//==============================================
void   KeyCheck(void)//按键检测函数
{
        if(KeyCurrent==KeySaved)
        {
                PORTD=0x00;
        }
        else
        {
                PORTD=KeyCode[KeySaved];//读保存的按键码
                Delay();//延时显示
                PORTD=0x00;
                KeySaved = KeyCurrent;//已有按键偏移位置加1,与当前按键偏移位置同步
         }
}
//==============================================
void  Delay(void)//延时
{
   int n;
   for(n=0;n<=5000;n++)
   continue;
}
//====================================================

一周热门 更多>