梗概:在前者基础上,添加一盏灯。可以同时控制两盏灯;
新增知识点:数组(常量值字符串),
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"
};
- 赋值符号用错
等号用成了双等号:插入链表的函数里,指针执行用等号,错用了双等号。
【这是很明显的低级错误,未能第一时间发现。】
调试作为一种基本功。多多跟踪打印。通过跟踪创建链表这一步,发现只创建了一个节点,查看创建的函数,发现时用错符号,难怪没有新增成功。
这又提醒我们,程序跑通了,未必程序就没有错误了。因为你的程序里有的分支并没有参与运作,发现不了问题。
- 修改函数的注意问题
修改函数的传递参数时,若声明和定义分开来写,记得要同步修改。我一开始改了定义,却忘记了主函数上边还有格式声明没有同步修改。