慎用长度未知的字符数组

啊哈,昨天一位群友问我怎么切换LCD上面显示的问题,我想当然的回了一句中断检测和状态机思想去做,然后我自己也顺便搞了个LCD显示的驱动,但在驱动的编写与调试过程中,我遇到了一些问题:调试过程当中,存在LCD显示异常,甚至出现意想不到的显示结果。
驱动编写后,由于我的硬件全部在学校啊(太惨了啊,呜呜呜),我只能用我的那个proteus来做一个仿真了。
仿真实现功能:
两个状态:
1正常,按键输入时,可以显示unsigned int长度以下的数字。
2显示日期,显示日期的时候不能通过按键显示数字。

功能通过外部中断0来触发。
话不多说,上仿真截图:
1,仿真全局图:
在这里插入图片描述
2.LCD状态图:
1)显示数字状态
在这里插入图片描述
2)菜单提示状态
在这里插入图片描述
3)显示日期状态
在这里插入图片描述
好,正当我调试着按键,利用中断标志和状态机思想实现LCD翻页本就不难,可问题出现了,当我在正常模式下,输入了五位数11111,再触发中断时,LCD显示界面变成了这样子:
在这里插入图片描述
what?!不应该是显示菜单吗,怎么是你这个鬼东西?!
于是我尝试再次触发中断,检测一下到底是LCD的显示没有被成功覆盖,还是内存被意外覆盖了,结果当我第二次触发中断时,原本应该显示"2 date|3 numbe"的,变成了“11”。
初步判断是内存被覆盖了,好,这个是原先的中断服务函数:

/***************************************************************************
* 函数名:void Int0()
* 输入:无
* 输出:无
* 使用到的全局变量:ALL_V(存储将要显示的数字)
*	KeyValue(存储当前按下的键值,通过算法赋给ALL_V)
* KEY_STATE(按键状态,枚举key_normal,key_judge,key_display_date,key_return)
*
* 功能:实现枚举变量KEY_STATE的切换,进而刷新LCD屏
*****************************************************************************/
void Int0()	interrupt 0
{
		u8 i;
	  int_flag=~int_flag;
		LcdWriteCom (0x01);//清屏
	  LcdWriteCom (0x80);//设置 (0,0 )为起点
	  KeyValue=0;
		ALL_v=0;
		for (i=0;i<strlen_it(displayDate3);i++)
		{
			LcdWriteData(displayDate3[i]);
		}
	  KEY_STATE=1;
		while(KEY_STATE==1)
		{
			if(int_flag)
			test=~test;
		KeyDown_it();
				if(KeyValue==2)
		   {
			  KEY_STATE=2;
				LcdInit();
				 while(LCD_busy()==1);
				for (i=0;i<strlen_it(displayDate1);i++)
				{
				LcdWriteData(displayDate1[i]);
				}
				break;				
		   }
		    else if(KeyValue==3)
		   { 	
    				KeyValue=0;
						lcd_refresh_flag=1;
				 		if(lcd_refresh_flag)
						{
							LcdInit();
							while(LCD_busy()==1);
							for (i=0;i<strlen_it(displayDate1);i++)
						  {
							 LcdWriteData(displayDate1[i]);
						   }
								for(i=0;i<strlen_it(null);i++)
								{
									LcdWriteData(null[i]);
								}
								lcd_refresh_flag=0;
						 }
						KEY_STATE=3;break;
		    }	
	}
}

现在我们做一个修改,做一个检测内存是否被覆盖的功能,因为被覆盖的话,字符串长度明显是变小的,所以我们只要检测字符串长度是否合理即可:

修改后的代码:
void Int0()	interrupt 0
{
		u8 i;
	  int_flag=~int_flag;
		LcdWriteCom (0x01);//清屏
	  LcdWriteCom (0x80);//设置 (0,0 )为起点
	  KeyValue=0;
		ALL_v=0;
	  //transfer_string[0]='\0';
	  if(strlen_it(displayDate3)>10)
		for (i=0;i<strlen_it(displayDate3);i++)
		{
			LcdWriteData(displayDate3[i]);
		}
			else
			LcdWriteData('k');//如果发现内存被覆盖,那么LCD显示‘k’
	  KEY_STATE=1;
		
		while(KEY_STATE==1)
		{
			if(int_flag)
			test=~test;
		KeyDown_it();
				if(KeyValue==2)
		   {
			  KEY_STATE=2;
				LcdInit();
				 while(LCD_busy()==1);
				for (i=0;i<strlen_it(displayDate1);i++)
				{
				LcdWriteData(displayDate1[i]);
				}
				break;				
		   }
		    else if(KeyValue==3)
		   { 	
    				KeyValue=0;
						lcd_refresh_flag=1;
				 		if(lcd_refresh_flag)
						{
							LcdInit();
							while(LCD_busy()==1);
							for (i=0;i<strlen_it(displayDate1);i++)
						  {
							 LcdWriteData(displayDate1[i]);
						   }
								for(i=0;i<strlen_it(null);i++)
								{
									LcdWriteData(null[i]);
								}
								lcd_refresh_flag=0;
						 }
						KEY_STATE=3;break;
		    }	
	}
}

果不其然,在我连续按下5次1之后,再进入中断后,发现LCD上面只显示了‘k’:
在这里插入图片描述
那么,问题已经确定了,那就是,原本用于存储菜单栏的字符串被覆盖了。经过分析,我认为是这样的:
首先,我在程序里面写了一个无符号整形转字符串的API,而其中要调用一个全局字符数组变量u8 transfer_string[]={‘0’};//中间字符串,留意到了,我在定义和赋值的时候,并没有给它规定长度,导致了这个时候,它占用的内存是不确定的,所以我一下子输入5位数的时候,这个中间字符数组一下子占用了5位的u8类型大小,但是一开始初始化的时候呢,我没有给它那么大的内存呐!那不好意思,我要强占后面的内存了,也就是把原本的"2 date|3 numbe"的内存区覆盖成了“x\0”的形式。
那细心的朋友可能要问了,你还有一个 //transfer_string[0]=’\0’;语句没有打开呢,在进入中断的时候,让它清零本就行了?前面说了,在计数的时候,就已经侵占了其他变量的内存,这个时候再清空它已经意义不大。
所以,我把驱动文件的extern u8 transfer_string[6];加上了长度限制,再次调试,未发现有LCD显示异常的情况。

总结:数组长度需要变化的变量,一定要记得先规定一个长度,谨防内存覆盖,另外,在嵌入式环境下,慎用malloc等内存申请函数,因为易造成内存分配不合理。

如果不才有什么技术纰漏,欢迎大佬前来评论区指正不才,万分感谢!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值