我用鸿蒙开发板做了个“自动门锁”
The following article is from 鸿蒙技术社区 Author Hello_Kun
如若转载请联系原公众号
有一天半夜宿舍门被一个喝晕的哥们打开了,(说他晕吧他居然知道钥匙在门框上)于是有了设计自动门锁的想法。正好一直想用 Hi3861 做一个 IoT 落地项目,一切刚好!
需求分析
如下:
无钥匙进入
手机端操作
不影响使用钥匙开门
无损安装、卸载自动开门机构
宿舍门锁考察
水平向右移动拉闩 1cm 左右即可开门,由于宿舍们老旧,拉力实测在 2.5L 水左右。
经过粗略计算,如果使用 9g 舵机来驱动,单杠驱动结构的话,杠杆长度比为 2500/9≈278,尺寸有些夸张。
不想在机械结构上费时间,所以选取大扭矩舵机驱动。
方案设计
①机械结构
典型的曲柄滑块结构。选取了绳索拉动、连杆方案。综合考虑耐用度和安装便携性,选取绳索驱动方案。
②控制逻辑
软件层
https://harmonyos.51cto.com/posts/1384
本项目只需要将:服务器地址改为自己的 IP、订阅自己 web 端的 Topic、提取消息数据。
/*连接web端 只展示主要逻辑,完整见附件*/
int mqtt_connect(void)
{
//0.连接web端
char* payload = "Hello Kun,have a Nice Day!";
int payloadlen = strlen(payload);
int len = 0;
char *host = "192.168.xxx.xx"; //自己的ip
int port = 1883; //mqtt服务端口
mysock = transport_open(host, port);
/* 1.订阅web端话题 */
topicString.cstring = "porsche";
if (MQTTPacket_read(buf, buflen, transport_getdata) == SUBACK) /* wait for suback */
{
rc = MQTTDeserialize_suback(&submsgid, 1, &subcount, &granted_qos, buf, buflen);
}
/*2. 循环接收发布者的话题消息 */
topicString.cstring = "hi3861";
char door_passward[] ="notfound404"; //开门密令
char cmd_msg[12]; //存储web端发来的数据
while (!toStop)
{
if (MQTTPacket_read(buf, buflen, transport_getdata) == PUBLISH)
{
MQTTString receivedTopic;
rc = MQTTDeserialize_publish(&dup, &qos, &retained, &msgid, &receivedTopic,
&payload_in, &payloadlen_in, buf, buflen);
for ( i = 0; i < payloadlen_in; i++)
{
cmd_msg[i]=*payload_in; //save message from MQTT web
payload_in++; //pointer
printf("%c",cmd_msg[i]);
}
printf("cmd_msg:%s\n",cmd_msg);
}
}
Hi3861 控制舵机之前这篇文章有配置过:
https://harmonyos.51cto.com/posts/8645
调整 20ms 控制周期内高电平的占空比模拟 PWM 代码如下,进行了一下简单的封装,使用哪个 IO 口记得要初始化输出即可。
/** * @brief Servo control *
@param servoID number of servo (GPIO) 7-8-9-10 *
@param angle input value: 0-200 *
*/
void My_servo(uint8_t servoID,int angle)
{
int j=0;
int k=2000/200; //实际应该是2000/180
angle = k*angle;
for (j=0;j<5;j++)
{
GpioSetOutputVal(servoID, 1);
hi_udelay(angle); //angle ms
GpioSetOutputVal(servoID, 0);
hi_udelay(20000-angle);//
}//20ms 控制舵机
}
项目完整工程见附件 1,主要代码如下:
/*逻辑代码为了适应另外一个iot项目。看起来比较臃肿,但能用*/
int count =3; //开门次数
switch (cmd_msg[0])
{
case 'a': //一键开门
printf("up\n");
cmd_msg[0]='n';
break;
case 'z': //一键上锁
printf("down\n");
cmd_msg[0]='p';
count = 3;
break;
case 's': //连接上led闪烁
printf("Start\n");
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_9, 0);
usleep(LED_INTERVAL_TIME_US);
GpioSetOutputVal(WIFI_IOT_IO_NAME_GPIO_9, 1);
usleep(LED_INTERVAL_TIME_US);
break;
default:
break;
}
if(!(strcmp(cmd_msg,door_passward)))
{
if(count)
{ count --;
printf("Open the Door!\n");
My_servo(10,100);
}
else count = 0;
}
else
{
printf("Close the Door!\n");
My_servo(10,50);
}
测试
其他案例
这里展示一下读取 max30102 原始数据的函数,完整资源见附件 2。代码如下:
/**
* @brief Send Write command to MAX30102 device before Read a register.
* @param regAddr the register address to Read or Writen.
* @return Returns{@link IOT_SUCCESS} if the operation is successful;
* returns an error code defined in {@link iot_errno.h} otherwise.
* */
uint8_t MAX_Cmd(uint8_t regAddr)
{
hi_i2c_idx id = MAX_I2C_IDX;
uint8_t buffer[] = {regAddr};
hi_i2c_data i2cData;
i2cData.receive_buf = NULL;
i2cData.receive_len = 0;
i2cData.send_buf = buffer;
i2cData.send_len = sizeof(buffer)/sizeof(buffer[0]);
return hi_i2c_write((hi_i2c_idx)id, MAX30102_WR_address, &i2cData); //==发送器件地址+写命令 + 寄存器regAddr
}
/**
* @brief Read a data byte from MAX30102 device.
* @param regAddr the register address. 8bit data
* @return *data
* */
uint32_t MAX_Read_Data(uint8_t regAddr, uint8_t *data, unsigned int dataLen)
{
hi_i2c_idx id = MAX_I2C_IDX;
hi_i2c_data i2cData;
i2cData.send_buf = NULL;
i2cData.send_len = 0;
i2cData.receive_buf = data;
i2cData.receive_len = dataLen;
MAX_Cmd(regAddr); // write device add 0xAE + reg_ADD [目标寄存器]
return hi_i2c_read((hi_i2c_idx)id, I2C_READ_ADDR, &i2cData);
}
/**
* @brief read FIFO data in max30102 FIFO register 0x07
*
* @param RED_channel_data
* @param IR_channel_data
*/
void max30102_FIFO_Read_Data(uint8_t *RED_channel_data, uint8_t *IR_channel_data)
{
uint8_t buff[6]; //LSB
/*组合数据
uint8_t H,M,L;
H=buff[0]&0x03; //bit17-bit16
M=buff[1]; //bit8-bit15
L=buff[2]; //bit0-bit7
*RED_channel_data = (H<<16)|(M<<8)|L; */
int res;
res=MAX_Read_Data(REG_FIFO_DATA, &buff ,6);
if(res == IOT_SUCCESS)
{
*RED_channel_data=((buff[0]<<16)|(buff[1]<<8)|(buff[2]) & 0x03ffff); //buff[0-2] 组合
*IR_channel_data=((buff[3]<<16)|(buff[4]<<8)|(buff[5]) & 0x03ffff); //buff[3-5] 组合
}
}
读取到的数据:
套件的模块除了 NFC 之外,其他都开发了一遍,不一一细说了,具体内容见附件 3-个人开发 PPT。
结语
NFC 开门是不是更加便捷呢?手里没有运行 HarmoneyOS 的手机,软总线方案技术上自己估计做不到,先做做硬件层的吧,下一步抽空实现,只要有 NFC 功能的手机都可开门~估计得明年喽!
https://harmonyos.51cto.com/posts/9822
推荐阅读:
每日打卡赢积分兑换书籍入口