debug手法案例
创始人
2025-05-29 17:16:52
0

案例一

1、问题出现

如下代码程序运行效果与个人设计不符

//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define	Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0;    //记录按下时长,刻10ms
static u8 lock = 0;       //lock变量用于判断是否是第一次进行按键确认状态
typedef enum
{KEY_CHECK = 0,     //检测状态KEY_COMFIRM = 1,   //按键确认,已经识别到了前沿抖动KEY_RELEASE = 2    //按键释放,
}KEY_STATE;  
static  KeyState =0;   // 初始化按键状态为检测状态
static u8 g_KeyFlag = 0;                // 按键有效标志,0: 按键值无效; 1:按键值有效
typedef enum 
{NULL_KEY = 0,SHORT_KEY =1,LONG_KEY=2
}KEY_TYPE;
static KEY_TYPE g_KeyActionFlag;		//用于区别长按和短按static int shortCnt;
static int longtCnt;/***/
void Key_Scan(void)
{  switch (KeyState){//按键未按下状态,此时判断Key的值case   0:    if(!Key)   {KeyState =  1;  //如果按键Key值为0,说明按键开始按下,进入下一个状态 }TimeCnt = 0;                  break;case   1:if(!Key)                     //查看当前Key是否还是0,还是就计数加一{          TimeCnt++; if(TimeCnt > 61) {}if(TimeCnt > 8) {}}   else                         // 不还是0,按键释放了{KeyState = 2;TimeCnt = 0;             //计数复位} break;case  2:if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态{ KeyState =  0;    }break;default: break;}    
}
/*-------------------------------------------------*  函数名:interrupt ISR*	功能:  定时器0的中断处理*  输入:  无*  输出:  无--------------------------------------------------*/
void interrupt ISR(void)			
{ static u8 cnt; if(T0IE && T0IF)		 //开定时器/计数器0中断&&中断标志置位{cnt++;if(cnt>2)           // 每 8.16*n ms执行一次按键扫描程序{Key_Scan();cnt = 0;}T0IF = 0;           //清零time0中断标志} 
} /*-------------------------------------------------*	函数名称:	TIMER0_INITIAL*	功能:    	初始化设置定时器0*	设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255*					=(1/16000000)*2*256*255=8.16ms                      -------------------------------------------------*/
void TIMER0_INITIAL (void)  
{OPTION = 0B00000111;//Bit5: 	T0CS Timer0时钟源选择 //			1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)//Bit4: 	T0CKI引脚触发方式 1-下降沿 0-上升沿//Bit3: 	PSA 预分频器分配位 0-Timer0 1-WDT //Bit[2:0]: PS2 8个预分频比 111 - 1:256T0IF = 0;						//清空T0软件中断
}//***********************函数声明**************************
void configurate_initial(void);            //上电系统初始化/*-------------------------------------------------
* 函数名:main 
* 功能:  主函数
* 输入:  无
* 输出:  无--------------------------------------------------*/
void main()
{u8 i=0;//上电初始化configurate_initial();     //初始化配置TIMER0_INITIAL();      //每8.16ms 执行一次按键扫描程序GIE = 1; 			   //开中断T0IE = 1;			   //开定时器/计数器0中断u8 switch11=0;
//    PA7=1;//开启电源
//    PC3=1;//开启激光发射器//上电初始化完毕后while(1){if(KeyState==1&&TimeCnt > 61)     //16ms*61=1s{PA7=1;//开启电源PC3=1;//开启激光发射器if(i==1){PA7=0;//关闭电源}i++;}//       if(KeyState==1&&TimeCnt > 8)   //16ms*8=128ms
//       {
//           PC3=~PC3;//取反激光发射器的开关  
//       }}
}/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能:  上电系统初始化
* 输入:  无
* 输出:  无--------------------------------------------------*/	
void configurate_initial(void) 
{ //中断与时钟配置OSCCON = 0B01110001;	//IRCF=111=16MHz/2T=8MHz,0.125usINTCON = 0;  			//暂禁止所有中断PORTA = 0B00000000;		//将PA0~7的引脚状态初始为0PORTC = 0B00000000; 	//将PC0~7的引脚状态初始为0OPTION = 0B00001000;	//地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000MSCKCON = 0B00000000;   //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出;  Bit5->0,TIMER2时钟为Fosc;  Bit4->0,禁止LVR       CMCON0 = 0B00000111; 	//关闭比较器,CxIN为数字IO口//PA4TRISA = 0B00010000;		//地址TRISA处的Bit4=1,表输入WPUA = 0B00010000;     	//地址WPUA处的Bit4=1,表开上拉//PC3 TRISC = 0B00000000;		//地址TRISA处的Bit3=0,表输出WPUC = 0B00001000;     	//地址WPUA处的Bit3=0,表开上拉//PA7TRISA = 0B00000000;		//地址TRISA处的Bit7=0,表输出WPUA = 0B10000000;     	//地址WPUA处的Bit7=1,表开上拉
}

2、减少代码量,使用指示灯PC3

去掉一些代码,希望多按几次按键后引脚PC3可以在示波器上出现上升沿和下降沿。
在这里插入图片描述
事实是PC3一直保存高电平

//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define	Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0;    //记录按下时长,刻10msstatic  KeyState =0;   // 初始化按键状态为检测状态/***/
void Key_Scan(void)
{  switch (KeyState){//按键未按下状态,此时判断Key的值case   0:    if(!Key)   {KeyState =  1;  //如果按键Key值为0,说明按键开始按下,进入下一个状态 PC3=1;}TimeCnt = 0;   			break;case   1:if(!Key)                     //查看当前Key是否还是0,还是就计数加一{          TimeCnt++; 				}   else                         // 不还是0,按键释放了{KeyState = 2;PC3=0;TimeCnt = 0;             //计数复位} break;case  2:if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态{ KeyState =  0;  PC3=1;				 }break;default: break;}    
}
/*-------------------------------------------------*  函数名:interrupt ISR*	功能:  定时器0的中断处理*  输入:  无*  输出:  无--------------------------------------------------*/
void interrupt ISR(void)			
{ static u8 cnt; if(T0IE && T0IF)		 //开定时器/计数器0中断&&中断标志置位{cnt++;if(cnt>2)           // 每 8.16*n ms执行一次按键扫描程序{Key_Scan();cnt = 0;}T0IF = 0;           //清零time0中断标志} 
} /*-------------------------------------------------*	函数名称:	TIMER0_INITIAL*	功能:    	初始化设置定时器0*	设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255*					=(1/16000000)*2*256*255=8.16ms                      -------------------------------------------------*/
void TIMER0_INITIAL (void)  
{OPTION = 0B00000111;//Bit5: 	T0CS Timer0时钟源选择 //			1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)//Bit4: 	T0CKI引脚触发方式 1-下降沿 0-上升沿//Bit3: 	PSA 预分频器分配位 0-Timer0 1-WDT //Bit[2:0]: PS2 8个预分频比 111 - 1:256T0IF = 0;						//清空T0软件中断
}/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能:  上电系统初始化
* 输入:  无
* 输出:  无--------------------------------------------------*/	
void configurate_initial(void) 
{ //中断与时钟配置OSCCON = 0B01110001;	//IRCF=111=16MHz/2T=8MHz,0.125usINTCON = 0;  			//暂禁止所有中断PORTA = 0B00000000;		//将PA0~7的引脚状态初始为0PORTC = 0B00000000; 	//将PC0~7的引脚状态初始为0OPTION = 0B00001000;	//地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000MSCKCON = 0B00000000;   //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出;  Bit5->0,TIMER2时钟为Fosc;  Bit4->0,禁止LVR       CMCON0 = 0B00000111; 	//关闭比较器,CxIN为数字IO口//PA4TRISA = 0B00010000;		//地址TRISA处的Bit4=1,表输入WPUA = 0B00010000;     	//地址WPUA处的Bit4=1,表开上拉//PC3 TRISC = 0B00000000;		//地址TRISA处的Bit3=0,表输出WPUC = 0B00001000;     	//地址WPUA处的Bit3=0,表开上拉//PA7TRISA = 0B00000000;		//地址TRISA处的Bit7=0,表输出WPUA = 0B10000000;     	//地址WPUA处的Bit7=1,表开上拉
}/*-------------------------------------------------
* 函数名:main 
* 功能:  主函数
* 输入:  无
* 输出:  无--------------------------------------------------*/
void main()
{//上电初始化configurate_initial();     //初始化配置TIMER0_INITIAL();      //每8.16ms 执行一次按键扫描程序GIE = 1; 			   //开中断T0IE = 1;			   //开定时器/计数器0中断PA7=1;//开启电源PC3=1;//开启激光发射器//上电初始化完毕后while(1){}
}

3、继续减少代码量

去掉了函数Key_Scan。改成PC3=~PC3;希望可以在示波器上看到方波,每隔8.16ms变换一次电频。
成功输出了:
在这里插入图片描述
问题就在函数Key_Scan中。

//*********************************************************
#include "SYSCFG.h"
//***********************宏定义****************************
typedef unsigned char u8;
#define	Key PA4
//***********************变量定义****************************
static u8 TimeCnt = 0;    //记录按下时长,刻10msstatic  KeyState =0;   // 初始化按键状态为检测状态/***/
void Key_Scan(void)
{  switch (KeyState){//按键未按下状态,此时判断Key的值case   0:    if(!Key)   {KeyState =  1;  //如果按键Key值为0,说明按键开始按下,进入下一个状态 PC3=1;}TimeCnt = 0;   			break;case   1:if(!Key)                     //查看当前Key是否还是0,还是就计数加一{          TimeCnt++; 				}   else                         // 不还是0,按键释放了{KeyState = 2;PC3=0;TimeCnt = 0;             //计数复位} break;case  2:if(Key)                     //当前Key值为1,说明按键已经释放,返回开始状态{ KeyState =  0;  PC3=1;				 }break;default: break;}    
}
/*-------------------------------------------------*  函数名:interrupt ISR*	功能:  定时器0的中断处理*  输入:  无*  输出:  无--------------------------------------------------*/
void interrupt ISR(void)			
{ static u8 cnt; if(T0IE && T0IF)		 //开定时器/计数器0中断&&中断标志置位{cnt++;if(cnt>2)           // 每 8.16*n ms执行一次按键扫描程序{PC3=~PC3;cnt = 0;}T0IF = 0;           //清零time0中断标志} 
} /*-------------------------------------------------*	函数名称:	TIMER0_INITIAL*	功能:    	初始化设置定时器0*	设置TMR0定时时长=(1/系统时钟频率)*指令周期*预分频值*255*					=(1/16000000)*2*256*255=8.16ms                      -------------------------------------------------*/
void TIMER0_INITIAL (void)  
{OPTION = 0B00000111;//Bit5: 	T0CS Timer0时钟源选择 //			1-外部引脚电平变化T0CKI 0-内部时钟(FOSC/2)//Bit4: 	T0CKI引脚触发方式 1-下降沿 0-上升沿//Bit3: 	PSA 预分频器分配位 0-Timer0 1-WDT //Bit[2:0]: PS2 8个预分频比 111 - 1:256T0IF = 0;						//清空T0软件中断
}/*-------------------------------------------------
* 函数名:POWER_INITIAL
* 功能:  上电系统初始化
* 输入:  无
* 输出:  无--------------------------------------------------*/	
void configurate_initial(void) 
{ //中断与时钟配置OSCCON = 0B01110001;	//IRCF=111=16MHz/2T=8MHz,0.125usINTCON = 0;  			//暂禁止所有中断PORTA = 0B00000000;		//将PA0~7的引脚状态初始为0PORTC = 0B00000000; 	//将PC0~7的引脚状态初始为0OPTION = 0B00001000;	//地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000MSCKCON = 0B00000000;   //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出;  Bit5->0,TIMER2时钟为Fosc;  Bit4->0,禁止LVR       CMCON0 = 0B00000111; 	//关闭比较器,CxIN为数字IO口//PA4TRISA = 0B00010000;		//地址TRISA处的Bit4=1,表输入WPUA = 0B00010000;     	//地址WPUA处的Bit4=1,表开上拉//PC3 TRISC = 0B00000000;		//地址TRISA处的Bit3=0,表输出WPUC = 0B00001000;     	//地址WPUA处的Bit3=0,表开上拉//PA7TRISA = 0B00000000;		//地址TRISA处的Bit7=0,表输出WPUA = 0B10000000;     	//地址WPUA处的Bit7=1,表开上拉
}/*-------------------------------------------------
* 函数名:main 
* 功能:  主函数
* 输入:  无
* 输出:  无--------------------------------------------------*/
void main()
{//上电初始化configurate_initial();     //初始化配置TIMER0_INITIAL();      //每8.16ms 执行一次按键扫描程序GIE = 1; 			   //开中断T0IE = 1;			   //开定时器/计数器0中断PA7=1;//开启电源PC3=1;//开启激光发射器//上电初始化完毕后while(1){}
}

4、"事故"位置找到,分析事故现场

1)反推法

中断程序可以按照设定的时间,一次又一次的执行。
中断函数里的Key_Scan函数却不能正常执行。
PC3恒为1,所以PC3=0没有被执行。
PC3=0要执行的话,Key就要等于0。
所以Key一直没有等于0,一直为1。

为什么一直为1?
设计是要Key,即引脚PA4做上拉输入。当按键按下时被拉低为0。
在这里插入图片描述

2)祸根

看看PA4的配置

void configurate_initial(void) 
{ //中断与时钟配置OSCCON = 0B01110001;	//IRCF=111=16MHz/2T=8MHz,0.125usINTCON = 0;  			//暂禁止所有中断PORTA = 0B00000000;		//将PA0~7的引脚状态初始为0PORTC = 0B00000000; 	//将PC0~7的引脚状态初始为0OPTION = 0B00001000;	//地址OPTION处的Bit3控制看门狗时钟和时钟0的共用分频电路归谁。为1归看门狗,Bit2~0是分频电路的分频系数PS=000MSCKCON = 0B00000000;   //地址MSCKCON处的Bit6->0,禁止PA4,PC5稳压输出;  Bit5->0,TIMER2时钟为Fosc;  Bit4->0,禁止LVR       CMCON0 = 0B00000111; 	//关闭比较器,CxIN为数字IO口//PA4TRISA = 0B00010000;		//地址TRISA处的Bit4=1,表输入WPUA = 0B00010000;     	//地址WPUA处的Bit4=1,表开上拉//PC3 TRISC = 0B00000000;		//地址TRISA处的Bit3=0,表输出WPUC = 0B00001000;     	//地址WPUA处的Bit3=0,表开上拉//PA7TRISA = 0B00000000;		//地址TRISA处的Bit7=0,表输出WPUA = 0B10000000;     	//地址WPUA处的Bit7=1,表开上拉
}

可以发现PA4被配置成了关闭上拉的输出。祸根就是它。
在这里插入图片描述

相关内容

热门资讯

监控摄像头接入GB28181平... 流程简介将监控摄像头的视频在网站和APP中直播,要解决的几个问题是:1&...
Windows10添加群晖磁盘... 在使用群晖NAS时,我们需要通过本地映射的方式把NAS映射成本地的一块磁盘使用。 通过...
protocol buffer... 目录 目录 什么是protocol buffer 1.protobuf 1.1安装  1.2使用...
Fluent中创建监测点 1 概述某些仿真问题,需要创建监测点,用于获取空间定点的数据࿰...
educoder数据结构与算法...                                                   ...
MySQL下载和安装(Wind... 前言:刚换了一台电脑,里面所有东西都需要重新配置,习惯了所...
MFC文件操作  MFC提供了一个文件操作的基类CFile,这个类提供了一个没有缓存的二进制格式的磁盘...
在Word、WPS中插入AxM... 引言 我最近需要写一些文章,在排版时发现AxMath插入的公式竟然会导致行间距异常&#...
有效的括号 一、题目 给定一个只包括 '(',')','{','}'...
【Ctfer训练计划】——(三... 作者名:Demo不是emo  主页面链接:主页传送门 创作初心ÿ...