嵌入式学习-Day6

c语言day6

模拟获取co2,pm2.5的数值,并对co2的浓度,pm2.5的浓度做出划分,详情划分在代码注释

首先写写出模拟获取数值的函数,但是由于要对浓度划分,所以先枚举出来等级划分

typedef enum
{
	Excellent,//默认0往下递增
	Good,
	Average,
	Poor
}QualityLevel;

接着写出模拟获取co2函数(在这里用到了static关键字,静态函数能够确保只在co2的c文件使用以便于接下来在pm2的文件中使用)

static int32_t GetRawData(void)//模拟获取co2
{
	return 500; 
}

根据浓度值划分来写出对应的枚举参数

/*
小于100                                 对应           Excellent 0
大于等于100、小于200          对应           Good 1
大于等于200、小于300          对应           Average 2 
大于等于300                          对应           Poor 3~

*/
QualityLevel GetCo2Level(void)//等级划分
{
	int32_t raw = GetRawData();
	int32_t level = raw / 100;//除以100正好跟枚举的数值相匹配
	return (QualityLevel) level;
}

方面观察写一个打印co2当前的浓度等级

void DisplayCo2Level(QualityLevel lv)
{
	switch (lv)
	{
		case Excellent:
			printf("The air quality of co2 is excellent.\n");
			break;
		case Good:
			printf("The air quality of co2 is good.\n");
			break;
		case Average:
			printf("The air quality of co2 is average.\n");
			break;
		default:
			printf("The air quality of co2 is poor.\n");
			break;
	}
}	

记得在h文件对函数声明在main函数就可以获取co2的浓度划分了

    QualityLevel co2Level;//获取co2数值
	co2Level = GetCo2Level();
	DisplayCo2Level(co2Level);//打印

同理pm2.5的函数可以参考这个来写

static int32_t GetRawData(void)//模拟pm25原始数据
{
	return 50; 
}

/*
小于10                                  对应           Excellent
大于等于10、小于35             对应           Good
大于等于35、小于75             对应           Average 
大于等于75                           对应           Poor

*/
QualityLevel GetPm25Level(void)//对数据进行环境评判
{
	int32_t raw = GetRawData();
	QualityLevel level;
	if(raw < 10)
	{
		level = Excellent;
	}
	else if(raw >= 10 && raw < 35)
	{
		level = Good;
	}
	else if(raw >= 35 && raw < 75)
	{
		level = Average;
	}
	else
	{
		level = Poor;
	}
	return level;
}

void DisplayPm25Level(QualityLevel lv)//打印当前数据质量
{
	switch (lv)
	{
		case Excellent:
			printf("The air quality of pm2.5 is excellent.\n");
			break;
		case Good:
			printf("The air quality of pm2.5 is good.\n");
			break;
		case Average:
			printf("The air quality of pm2.5 is average.\n");
			break;
		default:
			printf("The air quality of pm2.5 is poor.\n");
			break;
			
	}
}

练习2,模拟传感器的温度值,并且转换成华氏温度,并且传入一个外部校准对温度值进行校准

根据这段话可以分析:模拟传感器的温度值-写出一个外部校准函数-对温度值进行5次求和在进行校准-转换成华氏温度

模拟传感器获得的温度

static float GetRawData(void)//模拟获取温度
{
	static uint8_t s_chgVal = 0;
	s_chgVal++;
	s_chgVal %= 5;//数值维持在1-4
	return 20.f + s_chgVal;
	
}

在main函数中写入一个外部校准函数

float GetTemCofHmi(void)//外部校准
{
	return 1.2f;
}

接着回到tem的c文件,要想在c文件调用这个函数,并且跟主函数的耦合性不大,可以在tem的c文件中写入一个获取外部校准的函数的变量,届时,在主函数借用两个函数就能完成传递,首先定义一个静态全局变量(确保在对温度值求和的时候校准使用)

static float g_temCof;

void SetTemCof(float temCof)//外部温度校准函数获得
{
	g_temCof = temCof;
}

接着对温度求和(这里用到了宏定义,温度小于最小的值,返回最小的值,大于最大的值返回最大的值)

float GetCelTem(void)
{
	float cel1 = GetRawData();//获取5次温度值
	printf("cel1 = %.1f.\n", cel1);
	float cel2 = GetRawData();
	printf("cel2 = %.1f.\n", cel2);
	float cel3 = GetRawData();
	printf("cel3 = %.1f.\n", cel3);
	float cel4 = GetRawData();
	printf("cel4 = %.1f.\n", cel4);
	float cel5 = GetRawData();
	printf("cel5 = %.1f.\n", cel5);
	float cel = (cel1 + cel2 + cel3 + cel4 + cel5) / 5;//求和
	cel *= g_temCof;//温度校准
	if (cel < CEL_MIN_VALUE)
	{
		cel = CEL_MIN_VALUE;
	}
	if (cel > CEL_MAX_VALUE)
	{
		cel = CEL_MAX_VALUE;
	}
	return cel;
}

根据公式获得华氏温度(在这里把公式宏定义)

float GetFahTem(void)//转换成华氏温度
{
	float raw = GetRawData();
	float fah = CEL_TO_FAH(raw) * 1.2f;

	return fah;
}

h文件的宏定义

#define CEL_MAX_VALUE  55.0f
#define CEL_MIN_VALUE  5.0f
#define CEL_TO_FAH(t)  ((t) *  9.0f / 5.0f + 32)

在main函数中调用这两个函数

    volatile float celTem;//获取温度
	
	SetTemCof(GetTemCofHmi());//调用函数来完成外部校准系数的传递
	
	celTem = GetCelTem();//温度
	printf("Temperature is %.1f cel degrees.\n", celTem);
	
	float fahTem = GetFahTem();//华氏温度
	printf("Temperature is %.1f fah degrees.\n", fahTem);

栈溢出的危害:

如果函数实际使用的栈空间超过栈最大值,就会发生栈溢出,导致程序异常

避免栈溢出

  • 不要定义占用内存较多的局部变量,可以将此类型变量修改指针从堆空间分配内存
  • 函数参数中不要传递大型数据结构,应该使用或引用指针作为函数参数,传递地址
  • 较少函数调用层次,慎用递归函数:A->B->C->D->A(环形调用)

增加栈的最大值,在保证硬件内存空间够用的情况下

一维数组应用案例:给一个数组NUMS,数组中有2n个元素,按照[x1,x2,x3.....xn,y1,y2,y3....yn]的格式排列,请将数组按照[x1,y1,x2,y2,....xn,yn]格式重新排列

示例:nums=[2,5,1,3,4,7],n = 3;

观察实列可得每次访问的2个目标数组元素的下标和 i 对应关系为:(2*i)和(2*i+1)

每次访问的2个目标原始数组元素的下标和 i 的对应关系:(i)和(2*i+1)

nums = [2,5,1,3,4,7],n = 3;
for(uint32_t i = 0; i < n; i++)
{
    res[2*i] = nums[i];
    res[2*i+1] = nums[i+n]; 
}
for(uint32_t i = 0; i < 2*n; i++)
{
    printf("%d.",res[i]);
}
  printf("\n");

二维数组:数据类型 数组名称[行数][列数]

int32_t buffer[3][4];//buffer为3行4列的数组

嵌入式学习-Day6_第1张图片

  • 所有元素具有相同的数据类型
  • 一旦创建,不能改变元素数量
  • 元素在内存中是连续依次排列的
  • 不可以省略列数,行数可以

应用案例:在一维数组的基础上,增加温度传感器数量到3个,这样可以检测3个环境点位的温度,在main函数中,每个点位都要保持5个温度数据

static float g_temCof;

static float GetRawData(uint8_t sensorID)//模拟获取温度
{
	static uint8_t s_chgVal = 0;
	s_chgVal++;
	s_chgVal %= 5;//数值维持在1-4
	return 20.f + s_chgVal;
	
}
void SetTemCof(float temCof)//外部温度校准
{
	g_temCof = temCof;
}
float GetCelTem(uint8_t sensorID)
{
	float cel = GetRawData(sensorID);//获取5次温度值
	
	cel *= g_temCof;//温度校准
	if (cel < CEL_MIN_VALUE)
	{
		cel = CEL_MIN_VALUE;
	}
	if (cel > CEL_MAX_VALUE)
	{
		cel = CEL_MAX_VALUE;
	}
	return cel;
}
float GetFahTem(void)//转换成华氏温度
{
	float raw = GetRawData(sensorID);
	float fah = CEL_TO_FAH(raw) * 1.2f;

	return fah;
}

在main函数首先对传感器的型号遍历接着进入温度遍历

volatile float celTem[3][5];
	for(uint8_t i = 0; i < 3; i++)
{
	for(uint8_t j = 0; j < 5; j++)
	{
		celTem[i][j] = GetCelTem(i);
		printf ("tem of sensor%d = %.1f by %d tem.\n",i,celTem[i][j],j);
	}
}	

你可能感兴趣的:(学习)