电压采集系统

分析此题,先写数码管 

前两位熄灭,后面都是按次序输入,因此必须定义一个四位数组来承接输入的四位数字

变量:

数码管的模式一:

注意此处为case 0不是case 1.Seg_Input[i]是承接四位输入的

if(Seg_Buf[5] == 11)以及后面那段判断语句,是指在还没输入完最后一个的时候,数码管会一直闪烁,输入完成之后则不会闪烁。

写完之后,我们要完成Seg_Input的数组输入。

由题我们知道,1-10的独立键盘被用作为0-9的输入

因此我们在Key_proc中可以定义

如果键盘按1-10,在此基础上是在模式一且还没有输入完全的时候。

键盘上每次输入一个数,Seg_Input[ ]都会承接一个数,指针加一往后再循环。

知道Seg_Input_Index大于四(四个数全被输入完全)

我们看看按下按键十一之后,会将现在的数据采集,并且将会进行四舍五入。四舍五入处理完后的数据将会在case 1(数据显示界面中显示)

因此我们在键盘中要写case 11的作用。

由按键说明我们可以得知

一.如果在非电压采集界面,则会自动跳转到这一模式,以前所有数据全部清零

二.如果在电压采集界面,则会保存输入的四个数字,将其进行四舍五入后,跳转到电压显示界面

(如果输入不符合规定,则会自动清零)

	case 11:
			Key_Error_Count = 0;
			if(Seg_Disp_Mode == 0)//处于电压采集界面
			{
				if(Seg_Input_Index >= 4)//判断数据有效性,防止就输了两位数就可以保存
				{
					Voltage = (Seg_Input[0] * 1000 + Seg_Input[1] * 100 + Seg_Input[2] * 10 + Seg_Input[3] + 5) / 1000.0;
					if(Voltage >= 0.01)
						Seg_Disp_Mode = 1;//跳转到数据显示界面
					else
					{
						Seg_Input_Index = 0;//输入指针复位
						for(i = 0;i < 4;i++)//输入数组复位
							Seg_Input[i] = 11;
					}
				}
				else
				{
					Seg_Input_Index = 0;//输入指针复位
					for(i = 0;i < 4;i++)//输入数组复位
						Seg_Input[i] = 11;
				}
			}
			else//处于非电压采集界面
			{
				Seg_Disp_Mode = 0;//跳转到电压采集界面
				Seg_Input_Index = 0;//输入指针复位
				for(i = 0;i < 4;i++)//输入数组复位
				Seg_Input[i] = 11;
			}
		break;

中间的Vlotage的代码要好好看看。是如何进行四舍五入的

在这段代码中,四舍五入的原理是通过加5再除以1000.0来实现的。具体步骤如下:

1. Seg_Input[0] * 1000 + Seg_Input[1] * 100 + Seg_Input[2] * 10 + Seg_Input[3]**:这部分将输入的四个数字组合成一个整数。例如,如果输入是[1, 2, 3, 4],则组合后的整数为1234。

2. + 5:在组合后的整数上加5。这一步是为了实现四舍五入。如果组合后的整数的小数部分大于或等于0.5,加5后会使得整数部分增加1,从而实现四舍五入。

3. / 1000.0:将加5后的结果除以1000.0,将其转换为浮点数,并保留三位小数。

举例说明:
- 如果组合后的整数是1234,加5后为1239,除以1000.0后得到1.239。
- 如果组合后的整数是1235,加5后为1240,除以1000.0后得到1.240。

通过这种方式,代码实现了对输入数字的四舍五入处理。

浮点数的变量定义

接下来再写电压显示界面

case 1://数据显示界面
           

case 1://数据显示界面
			Seg_Point[3+(int)Voltage/10] = 1;//小数点显示,小数点往后面移一位
			Seg_Buf[0] = 12;
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = (int)Voltage/10?1:(unsigned char)Voltage % 10;
			Seg_Buf[4] = (unsigned int)(Voltage * 100) / 10 % 10;
			Seg_Buf[5] = (unsigned int)(Voltage * 100) % 10;
		break;

如果数据采集的是1234mv,转变为实际电压就是1.23v

但9999mv,在四舍五入之后,就是10000,在转变为实际电压的时候,就得变为

10.000放不下

因此第一位就得进行判断如果(int)Voltage /10等于1就直接输出1后面照常输出就行

小数点也随之变换

(就这一种特殊情况)

接下来接着写按键12

按键12只有在非电压采集界面才能使用,且每次使用,Seg_Disp_Mode都会++,当加到4的时候,又会回到1进行循环。

case 12:
			if(Seg_Disp_Mode != 0)//处于非电压采集界面
			{
				Key_Error_Count = 0;
				if(Seg_Disp_Mode == 2)
					Voltage_Parameter = Voltage_Parameter_Ctrol;//保存当前设置参数
				if(++Seg_Disp_Mode == 4)
					Seg_Disp_Mode = 1;
			}
			else
				Key_Error_Count++;
		break;

下面写case 2

定义两个数,一个用来显示,一个用来改变​,再某一刻再进行保存

	case 2://参数设置界面
			Seg_Point[3+(int)Voltage/10] = 1;
			Seg_Buf[0] = 13;
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = (unsigned char)Voltage_Parameter % 10;
			Seg_Buf[4] = (unsigned int)(Voltage_Parameter * 100) / 10 % 10;
			Seg_Buf[5] = (unsigned int)(Voltage_Parameter * 100) % 10;			
		break;

什么时候保存呢?就是在按键12再一次切换到电压设置界面的时候

按键15和按键16为加减设置值的选项

	case 15:
			if(Seg_Disp_Mode == 2)//处于参数设置界面
			{
				Key_Error_Count = 0;
				Voltage_Parameter += 0.5;
				if(Voltage_Parameter > 6)
					Voltage_Parameter = 1;
			}
			else
				Key_Error_Count++;
		break;
		case 16:
			if(Seg_Disp_Mode == 2)//处于参数设置界面
			{
				Key_Error_Count = 0;
				Voltage_Parameter -=0.5;
				if(Voltage_Parameter < 1)
					Voltage_Parameter = 6;
			}
			else
				Key_Error_Count++;
		break;

计数统计界面

一.实际电压小于参数电压

二.重新设置之后,参数电压大于实际电压

计数统计加1

因此在满足条件一之后,要设置一个标志位,之后再满足条件二之后才能加1.

	if(Voltage > Voltage_Parameter_Ctrol)//当实际电压大于参考电压时
		Voltage_Flag = 1;//拉高标志位
	else if(Voltage_Flag == 1)
	{
		Voltage_Flag = 0;//标志位复位
		Count++;//计数值+1
	}

​​​​​​中间省略了一下,原样式

	if(Voltage > Voltage_Parameter_Ctrol)//当实际电压大于参考电压时
		Voltage_Flag = 1;//拉高标志位
	else if(Voltage < Voltage_Parameter_Ctrol)) 
     
{
      if(Voltage_Flag == 1)
	{
		Voltage_Flag = 0;//标志位复位
		Count++;//计数值+1
	}}

 计数统计

case 3://计数统计界面
			Seg_Point[3+(int)Voltage/10] = 0;
			Seg_Buf[0] = 14;
			Seg_Buf[1] = Count / 10000 % 10;
		  Seg_Buf[2] = Count / 1000 % 10;
			Seg_Buf[3] = Count / 100 % 10;
			Seg_Buf[4] = Count / 10 % 10;
			Seg_Buf[5] = Count % 10;
			while(Seg_Buf[j] == 0)
			{
				Seg_Buf[j] = 10;
				if(++j == 5) break;
			}
		break;

按键14

在case 0 会将所有清零,重新输入

在case 3将所有的统计全部清零

if(Seg_Disp_Mode == 0)
			{
				Key_Error_Count = 0;
				Seg_Input_Index = 0;//输入指针复位
				for(i = 0;i < 4;i++)//输入数组复位
					Seg_Input[i] = 11;
			}
			else if(Seg_Disp_Mode == 3)
			{
				Key_Error_Count = 0;
				Count = 0;
			}
			else
				Key_Error_Count++;

最后写Led灯,将两个底层代码驱动编写进去

#include <Led.h>

void Led_Disp(unsigned char addr,enable)
{
	static unsigned char temp = 0x00;
	static unsigned char temp_old = 0xff;
	if(enable)
		temp |= 0x01 << addr;
	else
		temp &= ~(0x01 << addr);
	if(temp != temp_old)
	{
		P1 = ~temp;
		temp_old = temp;
	}
}
#include <REGX52.H>

void Led_Disp(unsigned char addr,enable);

 代码

void Led_Proc()
{
	if(Voltage < Voltage_Parameter_Ctrol)
	{
		if(Sys_Tick >= 5000)
			ucLed[0] = 1;
	}
	else
	{
		Sys_Tick = ucLed[0] = 0;
	}
	ucLed[1] = Count % 2;
	ucLed[2] = Key_Error_Count / 3;
}
/* 头文件声明区 */
#include <REGX52.H>//单片机寄存器专用头文件
#include <Key.h>//按键底层驱动专用头文件
#include <Seg.h>//数码管底层驱动专用头文件
#include <Led.h>//Led底层驱动专用头文件

/* 变量声明区 */
unsigned char Key_Val,Key_Down,Key_Old;//按键专用变量
unsigned char Key_Slow_Down;//按键减速专用变量
unsigned char Seg_Buf[6] = {10,10,10,10,10,10};//数码管显示数据存放数组
unsigned char Seg_Pos;//数码管扫描专用变量
unsigned int Seg_Slow_Down;//数码管减速专用变量
unsigned char Seg_Disp_Mode;//数码管显示模式标志位 0-电压采集 1-数据显示 2-参数设置 3-计数统计
unsigned char Seg_Input[4] = {11,11,11,11};//数码管输入数据储存数组
unsigned char Seg_Input_Index;//数码管输入数据储存数组指针
unsigned int Timer_500Ms;//五百毫秒计时变量
unsigned char Seg_Point[6] = {0,0,0,0,0,0};//数码管小数点显示数组
unsigned char ucLed[8] = {0,0,0,0,0,0,0,0};//Led显示数据存放数组
unsigned char Led_Pos;
unsigned int Count;// 计数值专用变量
unsigned int Sys_Tick;//系统计时器
unsigned char Key_Error_Count;//无效按键统计变量
float Voltage;//实际电压变量
float Voltage_Parameter = 3.0;//电压设置参数
float Voltage_Parameter_Ctrol = 3.0;//实际电压设置参数  默认值3.0V
bit Seg_Flag;//数码管闪烁标志位
bit Voltage_Flag ;//电压参考标志位

/* 键盘处理函数 */
void Key_Proc()
{
	unsigned char i;//用于For循环
	if(Key_Slow_Down) return;
	Key_Slow_Down = 1;//键盘减速程序

	Key_Val = Key_Read();//实时读取键码值
	Key_Down = Key_Val & (Key_Old ^ Key_Val);//捕捉按键下降沿
	Key_Old = Key_Val;//辅助扫描变量
	
	if(Key_Down >= 1 && Key_Down <= 10)//键盘使能条件
	{
		if(Seg_Disp_Mode == 0 && Seg_Input_Index < 4)
		{
			Seg_Input[Seg_Input_Index] = Key_Down - 1;
			Seg_Input_Index++;
			Key_Error_Count = 0;
		}
		else
			Key_Error_Count++;
	}
	
	switch(Key_Down)
	{
		case 11:
			Key_Error_Count = 0;
			if(Seg_Disp_Mode == 0)//处于电压采集界面
			{
				if(Seg_Input_Index >= 4)//判断数据有效性,防止就输了两位数就可以保存
				{
					Voltage = (Seg_Input[0] * 1000 + Seg_Input[1] * 100 + Seg_Input[2] * 10 + Seg_Input[3] + 5) / 1000.0;
					if(Voltage >= 0.01)
						Seg_Disp_Mode = 1;//跳转到数据显示界面
					else
					{
						Seg_Input_Index = 0;//输入指针复位
						for(i = 0;i < 4;i++)//输入数组复位
							Seg_Input[i] = 11;
					}
				}
				else
				{
					Seg_Input_Index = 0;//输入指针复位
					for(i = 0;i < 4;i++)//输入数组复位
						Seg_Input[i] = 11;
				}
			}
			else//处于非电压采集界面
			{
				Seg_Disp_Mode = 0;//跳转到电压采集界面
				Seg_Input_Index = 0;//输入指针复位
				for(i = 0;i < 4;i++)//输入数组复位
				Seg_Input[i] = 11;
			}
		break;
		case 12:
			if(Seg_Disp_Mode != 0)//处于非电压采集界面
			{
				Key_Error_Count = 0;
				if(Seg_Disp_Mode == 2)
					Voltage_Parameter = Voltage_Parameter_Ctrol;//保存当前设置参数
				if(++Seg_Disp_Mode == 4)
					Seg_Disp_Mode = 1;
			}
			else
				Key_Error_Count++;
		break;
		case 15:
			if(Seg_Disp_Mode == 2)//处于参数设置界面
			{
				Key_Error_Count = 0;
				Voltage_Parameter += 0.5;
				if(Voltage_Parameter > 6)
					Voltage_Parameter = 1;
			}
			else
				Key_Error_Count++;
		break;
		case 16:
			if(Seg_Disp_Mode == 2)//处于参数设置界面
			{
				Key_Error_Count = 0;
				Voltage_Parameter -=0.5;
				if(Voltage_Parameter < 1)
					Voltage_Parameter = 6;
			}
			else
				Key_Error_Count++;
		break;
		case 14:
			if(Seg_Disp_Mode == 0)
			{
				Key_Error_Count = 0;
				Seg_Input_Index = 0;//输入指针复位
				for(i = 0;i < 4;i++)//输入数组复位
					Seg_Input[i] = 11;
			}
			else if(Seg_Disp_Mode == 3)
			{
				Key_Error_Count = 0;
				Count = 0;
			}
			else
				Key_Error_Count++;
		break;
	}
}

/* 信息处理函数 */
void Seg_Proc()
{
	unsigned char i;//用于For循环
	unsigned char j = 1;//用于While循环
	if(Seg_Slow_Down) return;
	Seg_Slow_Down = 1;//数码管减速程序
	
	if(Voltage > Voltage_Parameter_Ctrol)//当实际电压大于参考电压时
		Voltage_Flag = 1;//拉高标志位
	else if(Voltage_Flag == 1)
	{
		Voltage_Flag = 0;//标志位复位
		Count++;//计数值+1
	}
	switch(Seg_Disp_Mode)
	{
		case 0://电压采集界面
			Seg_Point[3+(int)Voltage/10] = 0;
			Seg_Buf[0] = Seg_Buf[1] = 10;
			for(i = 0;i< 4;i++)
				Seg_Buf[2+i] = Seg_Input[i];
			if(Seg_Buf[5] == 11)//只有当最后一位为-时 才实现数码管闪烁功能,只要在输入的过程中就会闪烁
				Seg_Buf[2+Seg_Input_Index] = Seg_Flag?Seg_Input[Seg_Input_Index]:10;
		break;
		case 1://数据显示界面
			Seg_Point[3+(int)Voltage/10] = 1;//小数点显示,小数点往后面移一位
			Seg_Buf[0] = 12;
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = (int)Voltage/10?1:(unsigned char)Voltage % 10;
			Seg_Buf[4] = (unsigned int)(Voltage * 100) / 10 % 10;
			Seg_Buf[5] = (unsigned int)(Voltage * 100) % 10;
		break;
		case 2://参数设置界面
			Seg_Point[3+(int)Voltage/10] = 1;
			Seg_Buf[0] = 13;
			Seg_Buf[1] = Seg_Buf[2] = 10;
			Seg_Buf[3] = (unsigned char)Voltage_Parameter % 10;
			Seg_Buf[4] = (unsigned int)(Voltage_Parameter * 100) / 10 % 10;
			Seg_Buf[5] = (unsigned int)(Voltage_Parameter * 100) % 10;			
		break;
		case 3://计数统计界面
			Seg_Point[3+(int)Voltage/10] = 0;
			Seg_Buf[0] = 14;
			Seg_Buf[1] = Count / 10000 % 10;
		  Seg_Buf[2] = Count / 1000 % 10;
			Seg_Buf[3] = Count / 100 % 10;
			Seg_Buf[4] = Count / 10 % 10;
			Seg_Buf[5] = Count % 10;
			while(Seg_Buf[j] == 0)
			{
				Seg_Buf[j] = 10;
				if(++j == 5) break;
			}
		break;
	}
}

/* 其他显示函数 */
void Led_Proc()
{
	if(Voltage < Voltage_Parameter_Ctrol)
	{
		if(Sys_Tick >= 5000)
			ucLed[0] = 1;
	}
	else
	{
		Sys_Tick = ucLed[0] = 0;
	}
	ucLed[1] = Count % 2;
	ucLed[2] = Key_Error_Count / 3;
}

/* 定时器0中断初始化函数 */
void Timer0Init(void)		//1毫秒@12.000MHz
{
	TMOD &= 0xF0;		//设置定时器模式
	TMOD |= 0x01;		//设置定时器模式
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值
	TF0 = 0;		//清除TF0标志
	TR0 = 1;		//定时器0开始计时
	ET0 = 1;    //定时器0中断打开
	EA = 1;     //总中断打开
}

/* 定时器0中断服务函数 */
void Timer0Server() interrupt 1
{
 	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值   
	if(++Key_Slow_Down == 10) Key_Slow_Down = 0;//键盘减速专用
	if(++Seg_Slow_Down == 500) Seg_Slow_Down = 0;//数码管减速专用
	if(++Seg_Pos == 6) Seg_Pos = 0;//数码管显示专用
	if(++Led_Pos == 8) Led_Pos = 0;
	Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);
	Led_Disp(Led_Pos,ucLed[Led_Pos]);
	if(Voltage < Voltage_Parameter_Ctrol)
		Sys_Tick++;
	if(++Timer_500Ms == 500)
	{
		Timer_500Ms = 0;
		Seg_Flag ^= 1;
	}
}

/* Main */
void main()
{
	Timer0Init();
	while (1)
	{
		Key_Proc();
		Seg_Proc();
		Led_Proc();
	}
}

链接:https://pan.baidu.com/s/19PTGQ2GmlBk9SfogMF0TNg 
提取码:c7ci

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐