梗概:在前者基础上,添加一盏灯。可以同时控制两盏灯;

新增知识点:数组(常量值字符串),

2023年4月26日:  代码有需要修改的地方。命名太长,没有把函数抽出来,部分逻辑冗余...待修改


源程序

  • main.c

        修改了判断的条件,新增一个存储变量(存储开关状态值)。

#include "controlDevices.h"

#include <stdio.h>
#include <string.h>


struct Devices* findDevByName(char* DevName, struct Devices* pDevicesHead);  //找设备
void control_DevLight(struct Devices* pDevicesHead, int status); //控制


int main()
{

	if (wiringPiSetup() == -1)  //上电检查
	{
		printf("wiringPiSetup error!\n");
		return -1;
	}

	char DevName[2][70] =  //找设备的判断条件|依据
	{
	"UPSTAIRLIGHT",
	"BATHROOMLIGHT"
	};
	
	int userCmd;  //用户指令
	int status = 1; //开关的状态(0为开,1为关)。通过判断用户指令来得到
	
	struct Devices* pDevicesHead;
	struct Devices* pSomeoneDev;
	pDevicesHead = NULL;
	pSomeoneDev = NULL;
    

	/* 1. 设备工厂链表的初始化|创建 */
	pDevicesHead = addUpstairLightToDeviceLink(pDevicesHead); 
	pDevicesHead = addBathroomLightToDeviceLink(pDevicesHead); 


    /*
	// 检验链表的完整性。可删
    struct Devices* pTest;  
	pTest = NULL;
	pTest = pDevicesHead;

	while (pTest != NULL)
	{
		printf("%s\n",pTest->devName);
		printf("%d\n",pTest->pinNum);
		pTest = pTest->next;
	}
    */


	/* 2. 开始用户输入 */
	while (1)
	{
		printf("请输入指令\n");
		printf("1,2为开灯,10,20为关灯\n");
		scanf("%d",&userCmd);
		getchar(); //delete enter
		printf("get = %d\n",userCmd); //检查输入信息

        // 3. 根据输入,判断并反馈设备对象
		if (userCmd == 1 || userCmd == 10)  
		{
			pSomeoneDev = findDevByName(DevName[0], pDevicesHead); //1对应的是二楼灯
		}
		else if (userCmd == 2 || userCmd == 20)  
		{
			pSomeoneDev = findDevByName(DevName[1], pDevicesHead); //2对应的是浴室灯
		}
		else 
		{
			printf("input error,plese input agin\n============\n\n"); 	//其余的是输入有误,请重新输入
			continue;
		}


        // 4. 根据输入,判断并反馈状态值
		if (userCmd == 1 || userCmd == 2)
		{
			status = 0; //需要开灯
		}
		else
		{
			status = 1; //需要关灯
		}


		// 5. 有了设备的地址以及状态。可以直接控制对应灯的亮灭
		if (pSomeoneDev != NULL)
		{
			pSomeoneDev->initdevice(pSomeoneDev->pinNum); //初始化模式
			control_DevLight(pSomeoneDev, status); //控制浴室灯;需要两个参数,设备的对象及状态
			delayMicroseconds(1000000);
		}
	}

	return 0;
}


struct Devices* findDevByName(char* DevName, struct Devices* pDevicesHead)
{
	struct Devices* pHead;
	pHead = pDevicesHead;

	if (pDevicesHead == NULL)  
	{
		return pDevicesHead;
	}
	else
	{
		while (pHead != NULL)
		{
			if (strcmp((pHead->devName), DevName) == 0) //找到对应灯
			{
				printf("已找到%s设备\n",DevName);
				return pHead;

			}
			pHead = pHead->next;
		}
		printf("dev not find!\n");
		return pDevicesHead;
	}
}

void control_DevLight(struct Devices* pDevicesHead, int status)
{
		if (status == 0)
		{
			pDevicesHead->open(pDevicesHead->pinNum);
			printf("%s 已打开\n",pDevicesHead->devName);
			printf("=====================");
		}
		else if (status == 1)
		{
			pDevicesHead->close(pDevicesHead->pinNum);
			printf("%s 已关闭\n",pDevicesHead->devName);
			printf("=====================");
		}
}
  • controlDevices.h

        新增一个函数。用于插入链表。

#include <wiringPi.h>

#include <stdio.h>

struct Devices
{
	char devName[128];  
	int status;
	int pinNum;

	int (*open)(int pinNum);
	int (*close)(int pinNum);
	int (*initdevice)(int pinNum);

	int (*readStatus)();
	int (*changeStatus)(int status);

	struct Devices* next;
};

struct Devices* addUpstairLightToDeviceLink(struct Devices* pHead);
struct Devices* addBathroomLightToDeviceLink(struct Devices* pHead);
  •  Light_upstair.c

        新增的文件。克隆Light_bathroom.c的结构即可,基本只改名称。

#include "controlDevices.h"


int openUpstairLight(int pinNum)
{
	digitalWrite(pinNum,LOW); //表现为开灯

}

int closeUpstairLight(int pinNum)
{
	digitalWrite(pinNum,HIGH); //表现为关灯
}

int initUpstairLight(int pinNum)
{
	pinMode(pinNum,OUTPUT);
	digitalWrite(pinNum,HIGH); //初始的表现为关灯
}


struct Devices Dev_UpstairLight =
{
	.devName = "UPSTAIRLIGHT",
	.pinNum = 21,
	.open = openUpstairLight,
	.close = closeUpstairLight,
	.initdevice = initUpstairLight,
	.changeStatus = changeUpstairLightStatus
};

struct Devices* addUpstairLightToDeviceLink(struct Devices* pHead)
{
	if (pHead == NULL)
	{
		return &Dev_UpstairLight; //先前没有头,那现在有了
	}
	else
	{
		Dev_UpstairLight.next = pHead;
		pHead = &Dev_UpstairLight; //新的头
		
		return pHead;
	}

}
  • Light_bathroom.c

        无改动。

#include "controlDevices.h"


int openBathroomLight(int pinNum)
{
	digitalWrite(pinNum,LOW); //表现为开灯

}

int closeBathroomLight(int pinNum)
{
	digitalWrite(pinNum,HIGH); //表现为关灯
}

int initBathroomLight(int pinNum)
{
	pinMode(pinNum,OUTPUT);
	digitalWrite(pinNum,HIGH); //初始的表现为关灯
}

int changeBathroomLightStatus(int status)
{


}


struct Devices Dev_bathroomLight =
{
	.devName = "BATHROOMLIGHT",
	.pinNum = 22,
	.open = openBathroomLight,
	.close = closeBathroomLight,
	.initdevice = initBathroomLight,
	.changeStatus = changeBathroomLightStatus
};

struct Devices* addBathroomLightToDeviceLink(struct Devices* pHead)
{
	if (pHead == NULL)
	{
		return &Dev_bathroomLight; //先前没有头,那现在有了
	}
	else
	{
		Dev_bathroomLight.next = pHead;
		pHead = &Dev_bathroomLight; //新的头
		
		return pHead;
	}

}

项目心得

  • 数组的定义格式

【对数组的用法有了更深刻的理解,尝试用了中括号、指针等等,编译都是报错,最后参考了别人的数组代码,发现这种格式可以使用。】

单个常量字符串的定义:

char DevName[] = "BATHROOMLIGHT";

多个字符串的定义:

char DevName[2][70] =  //需要二维数组来存储
     {
     "UPSTAIRLIGHT",
     "BATHROOMLIGHT"
     };
  • 赋值符号用错

等号用成了双等号:插入链表的函数里,指针执行用等号,错用了双等号。

【这是很明显的低级错误,未能第一时间发现。】

调试作为一种基本功。多多跟踪打印。通过跟踪创建链表这一步,发现只创建了一个节点,查看创建的函数,发现时用错符号,难怪没有新增成功。

这又提醒我们,程序跑通了,未必程序就没有错误了。因为你的程序里有的分支并没有参与运作,发现不了问题。

  • 修改函数的注意问题

修改函数的传递参数时,若声明和定义分开来写,记得要同步修改。我一开始改了定义,却忘记了主函数上边还有格式声明没有同步修改。