在这里插入图片描述

一、串口通信底层代码

由于本题只需要利用串口发送信息,所以在main.c中不用写串口数据处理函数void UartProc()和串口中断函数,在串口初始化中不用额外添加EA = ES = 1;,只需要重载putchar函数利用printf函数发送数据即可。

uart.c

#include <uart.h>

void Uart1_Init(void)	//9600bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x01;		//串口1选择定时器2为波特率发生器
	AUXR &= 0xFB;		//定时器时钟12T模式
	T2L = 0xE6;			//设置定时初始值
	T2H = 0xFF;			//设置定时初始值
	AUXR |= 0x10;		//定时器2开始计时
}

extern char putchar(char ch)
{
	SBUF = ch;
	while(!TI);
	TI = 0;
	return ch;
}

二、发送页面

在这里插入图片描述
数据输入从右向左推入,看起来很难,实际上做起来也不简单,要实现这个功能需要你对for循环的灵活运用。
下面定义的是输入内容存放的数组和其索引。

pdata u8 Input[7] = {10,10,10,10,10,10,10};
idata u8 InputIndex;

下面的这个for循环要写起来可以一步一步的写,毕竟你没有提前接触过是比较不可能直接写出来的,可以按照以下步骤逐步实现:

/*
*第一步,循环条件选取
*由于输入的内容是和数组索引有关系的,所以循环变量应该和索引有关
*/
for(i = 0; i < InputIndex; i++)
/*
*第二步,根据所选用的循环变量初步实现第一次输入数据的功能
*输入一个数据,索引InputIndex为1
*这个时候要让数码管的最右边等于Input的第1位(Input[0])
*也就是SegBuf[7]=Input[0]
*在for循环中实现:SegBuf[7-i]=Input[i]
*/
for(i = 0; i < InputIndex; i++)
	SegBuf[7-i]=Input[i]
/*
*第三步
*当输入两个数据的时候,数码管的第六位存放的是第一次输入的数据
*数码管的第二位存放的是第二次输入的数据
*根据这两个条件对for循环进行完善
*SegBuf[7]=Input[1],SegBuf[6]=Input[0]
*可以得出输入内容数组赋值是和其索引有关的
*[7-i] = Input[InputIndex-i-1];
*/
for(i = 0; i < InputIndex; i++)
	SegBuf[7-i] = Input[InputIndex-i-1];
idata u8 SegMode;  //0-输入页面 1-报警页面

void SegProc()
{
	u8 i;
	if(!SegMode)
	{
		SegBuf[0] = 11;
		for(i = 0; i < InputIndex; i++)
			SegBuf[7-i] = Input[InputIndex-i-1];
	}
}

三、输入数据

在这里插入图片描述

void KeyProc()
{
	u8 send = 0x00;
	u8 i;
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyOld = KeyVal;
	
	switch(KeyDown)
	{
		case 8://输入数字1
			if(!SegMode && InputIndex < 7)
			{
				Input[InputIndex++] = 1;
			}
		break;
			
		case 12://输入数字0,要求:第一个输入的数据不能是0
			if(!SegMode && InputIndex < 7 && InputIndex > 0)
			{
				Input[InputIndex++] = 0;
			}
		break;
	}
}

四、发送数据(先不考虑报警功能)

在这里插入图片描述
在这里插入图片描述
由于串口发送的数据是以ASCLL码的形式发送的,上面存放输入数据的是数组,所以在发送前要将数组的每位数据取出合成一个以二进制(十六进制也行)表示的数据。
这个过程和Led的底层代码一样,代码可以自行推理。

for(i = 0; i < InputIndex; i++)
	send |= (Input[i] << (InputIndex-i-1));
void KeyProc()
{
	u8 send = 0x00;
	u8 i;
	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyOld = KeyVal;
	
	switch(KeyDown)
	{
		case 4:
			//处于发送页面
			if(!SegMode)
			{
				if(InputIndex > 0)
				{
					//数据处理
					for(i = 0; i < InputIndex; i++)
						send |= (Input[i] << (InputIndex-i-1));
					//向串口发送数据
					printf("%c",send);
					//发送完数据后清空缓存区
					memset(Input,10,InputIndex);
					InputIndex = 0;
					//清空缓存区的瞬间清空数码管
					for(i = 1; i < 8; i++)
						SegBuf[i] = 10;	
				}
			}
			
		break;
	}
}

五、报警处理

在这里插入图片描述
数值范围转成十进制就是0 ~ 31,转成十六进制是0x00 ~ 0x1f,0b0111 1111也就是0x7f,所以在串口发送数据前可以加上下面代码:

void KeyProc()
{
	//...
	switch(KeyDown)
	{
		case 4:
			if(!SegMode)
			{
				if(InputIndex > 0)
				{
					//数据处理
					for(i = 0; i < InputIndex; i++)
						send |= (Input[i] << (InputIndex-i-1));
					//报警处理
					//0~31 31:0x1f 127:16*7+15
					if(send >= 0x00 && send <= 0x1f || send == 0x7f)
						SegMode = 1;
					//数据发送
					else
						printf("%c",send);
				}
			}
			else//处于报警页面
				SegMode = 0;
			//由于串口发送完成和关闭报警页面都需要清空缓存区
			//所以可以将清空缓存区放到最后
			memset(Input,10,InputIndex);
			InputIndex = 0;
			for(i = 1; i < 8; i++)
				SegBuf[i] = 10;	
		break;
	}
}

void SegProc()
{
	u8 i;
	if(!SegMode)
	{
		SegBuf[0] = 11;
		for(i = 0; i < InputIndex; i++)
			SegBuf[7-i] = Input[InputIndex-i-1];
		//如果你在发送串口后不想写清空数码管,写以下代码也可以
	//	  for (; i < 7; i++)
	//    {
	//      SegBuf[7-i] = 10;
	//    }
	}
	else//报警页面
	{
		SegBuf[0] = 12;
		SegBuf[1] = 12;
		SegBuf[2] = 10;
		SegBuf[3] = 10;
		SegBuf[4] = 10;
		SegBuf[5] = 10;
		SegBuf[6] = 10;
		SegBuf[7] = 10;
	}
}

六、完整代码

如果你发现了什么错误或者有什么疑问,请在评论区留言或者私信我,我看到会及时解决。

#include <STC15F2K60S2.H>
#include <string.h>
#include <stdio.h>
#include "Init.h"
#include "Key.h"
#include "Seg.h"
#include "uart.h"

typedef unsigned char u8;
typedef unsigned int u16;
typedef unsigned long int u32;

idata unsigned char Key_Slow; //按键减速变量 10ms 
idata unsigned int Seg_Slow; //数码管减速变量 500ms   
/*按键*/
idata u8 KeyVal,KeyDown,KeyOld;
pdata u8 Input[7] = {10,10,10,10,10,10,10};
idata u8 InputIndex;
/*数码管*/
idata u8 SegPos;
pdata u8 SegBuf[8] = {10,10,10,10,10,10,10,10};
pdata u8 SegPoint[8] = {0,0,0,0,0,0,0,0};
idata u8 SegMode;  //0-输入页面 1-报警页面
void KeyProc()
{
	u8 send = 0x00;
	u8 i;

	if(Key_Slow) return;
	Key_Slow = 1; //按键减速

	KeyVal = KeyDisp();
	KeyDown = KeyVal & ~KeyOld;
	KeyOld = KeyVal;
	
	switch(KeyDown)
	{
		case 4:
			if(!SegMode)
			{
				if(InputIndex > 0)
				{
					//数据处理
					for(i = 0; i < InputIndex; i++)
						send |= (Input[i] << (InputIndex-i-1));
					//0~31 31:0x1f 127:16*7+15
					if(send >= 0x00 && send <= 0x1f || send == 0x7f)
						SegMode = 1;
					//数据发送
					else
						printf("%c",send);
				}
			}
			else
				SegMode = 0;
			
			memset(Input,10,InputIndex);
			InputIndex = 0;
			for(i = 1; i < 8; i++)
				SegBuf[i] = 10;	
		break;
		
		case 8://输入数字1
			if(!SegMode && InputIndex < 7)
			{
				Input[InputIndex++] = 1;
			}
		break;
			
		case 12://输入数字0
			if(!SegMode && InputIndex < 7 && InputIndex > 0)
			{
				Input[InputIndex++] = 0;
			}
		break;
	}
}

void SegProc()
{
	u8 i;

	if(Seg_Slow) return;
	Seg_Slow = 1; //数码管减速

	if(!SegMode)
	{
		SegBuf[0] = 11;
		for(i = 0; i < InputIndex; i++)
			SegBuf[7-i] = Input[InputIndex-i-1];
//		for (; i < 7; i++)
//    {
//      SegBuf[7-i] = 10;
//    }
	}
	else
	{
		SegBuf[0] = 12;
		SegBuf[1] = 12;
		SegBuf[2] = 10;
		SegBuf[3] = 10;
		SegBuf[4] = 10;
		SegBuf[5] = 10;
		SegBuf[6] = 10;
		SegBuf[7] = 10;
	}
}

void Timer0_Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0x7F;			//定时器时钟12T模式
	TMOD &= 0xF0;			//设置定时器模式
	TL0 = 0x18;				//设置定时初始值
	TH0 = 0xFC;				//设置定时初始值
	TF0 = 0;				//清除TF0标志
	TR0 = 1;				//定时器0开始计时
	ET0 = 1;				//使能定时器0中断
	EA = 1;
}

void Timer0_Isr(void) interrupt 1
{
	if(++Key_Slow == 10) Key_Slow = 0; //按键延迟
	if(++Seg_Slow == 100) Seg_Slow = 0; //数码管延迟
	if(++SegPos == 8) SegPos = 0;
	SegDisp(SegPos,SegBuf[SegPos],SegPoint[SegPos]);
}
void main()
{
	SystemInit();
	Uart1_Init();
	Timer0_Init();
	while(1)
	{
		Key_Proc(); 
		Seg_Proc();
	}
}
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐