返回列表 发新帖我要提问本帖赏金: 100.00元(功能说明)

[MM32生态] 基于MM32与M26物联网入门:远程呼叫及开锁

[复制链接]
 楼主| xld0932 发表于 2022-3-15 15:21 | 显示全部楼层 |阅读模式
<
本帖最后由 xld0932 于 2022-3-16 08:14 编辑

#申请原创#   @21小跑堂

应用场景
适用于庭院大门,当有来客呼叫时,实现手动开锁、远程开锁的功能;

应用功能
通过MM32主控芯片与M26 2G通讯模块与远程服务器进行连接,当有访客按下CALL按键时,本地响应门铃(本应用暂未接门铃),同时进行远程呼叫;户主可以通过OPEN按键直接给访客开门,也可以通过服务器发送OPEN指令进行远程开门;

在没有访客呼叫时,MM32与服务器之间每间隔10秒钟进行一次心跳包传输,以保证与服务器之间SOCKET链路的连接;

在有访客呼叫时,若没有进行开锁动作,则每间隔3秒钟向服务器端发送一个呼叫指令;当接收到服务器端OPEN开锁命令时,执行开锁动作,开锁时间保持3秒钟,开销期间并向服务器反馈开锁是否成功的状态;

硬件模块
在网上淘到一块基于M262G通讯板,将主控MCU替换成MM32F0273D6P,这样省去了通讯板的设计及绘制,因为之前做过不少的工业远程控制项目,所以对通讯板的原理、控制都已经很熟悉了;通讯板如下图所示,带有5个接口及一个用户自己定义按键:1路光耦输出控制、2路带极性的光耦输入采集、1路无极性的光耦输入采集、以及1UART程序烧录接口;
通讯板.jpg

对硬件设计进行分析后,正好满足我们当前的硬件需求:1路光耦输出控制用于门锁的控制、2路带极性的光耦输入采集用于手动开锁按键和门外的呼叫按键、最后1路无极性的光耦输入采集则用于门锁的开关状态检测(我们选用的电磁锁是带有开关状态输出的);

为什么选用MM32F0273D6P这个芯片呢?基于通讯板,我们需要一个LQFP48封装的芯片,其次MM32F0273D6P是一个32位的Cortex-M0的控制芯片,最高工作主频可达到96MHz,运行速度够快;带有128KB FLASH程序存储空间,以及16KB SRAM的运行内存,能够满足在物联网工程项目功能上的应用;最后就是通讯板是通过UART下载程序的,MM32F0273D6P出厂自带了ISP功能,可以通过BOOT引脚来选择启动程序,配合上位机软件实现程序的烧录。

原理图设计
除了通讯板之外,我们还需要另外一块硬件单板配合演示/调试,功能如下:2个按键(1个手动开锁按键、1个门外呼叫按键)、1个门锁开关控制电路(继电器控制方式)、1个门锁开关状态检测电路(用于检测门锁的开关状态,以及确认门锁控制是否正常),最后就是开发板的供电(5V)以及门锁供电(12V);原理图如下所示:
Schematic_M26_LOCK_2022-03-15.png

PCB设计3D效果图
3D效果.png

整机实物图
整机图.jpg

功能实现代码:按键检测及处理
  1. /*******************************************************************************
  2. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  3. * @param      
  4. * @retval      
  5. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  6. *******************************************************************************/
  7. void KEY_SubScan(uint8_t *State, uint8_t *Count, uint8_t Value, char *Name)
  8. {
  9.     if(*State == 0)
  10.     {
  11.         if(Value == Bit_RESET) *Count += 1;
  12.         else                   *Count  = 0;

  13.         if(*Count > 5)
  14.         {
  15.             *Count = 0; *State = 1;
  16.             printf("\r\n%s Pressed", Name);

  17.             if(strcmp(Name, "OPEN") == 0)
  18.             {
  19.                 BSP_LOCK_Control(LOCK_MODE_MANUAL, ENABLE);

  20.                 if(RemoteState != 0)
  21.                 {
  22.                     RemoteState = 0;
  23.                     M26_SendMessage("Manual Open The Door!");
  24.                 }
  25.             }
  26.         }
  27.     }
  28.     else
  29.     {
  30.         if(Value != Bit_RESET) *Count += 1;
  31.         else                   *Count  = 0;

  32.         if(*Count > 5)
  33.         {
  34.             *Count = 0; *State = 0;
  35.             printf("\r\n%s Release", Name);

  36.             if(strcmp(Name, "OPEN") == 0)
  37.             {
  38.                 BSP_LOCK_Control(LOCK_MODE_MANUAL, DISABLE);
  39.             }
  40.             else if(strcmp(Name, "CALL") == 0)
  41.             {
  42.                 if(RemoteState == 0)
  43.                 {
  44.                     RemoteState = 1;
  45.                     M26_SendMessage("Calling...");
  46.                 }
  47.             }
  48.         }
  49.     }
  50. }


  51. /*******************************************************************************
  52. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  53. * @param      
  54. * @retval      
  55. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  56. *******************************************************************************/
  57. void KEY_Scan(void)
  58. {
  59.     static uint8_t KeyState[3] = {0, 0, 0};
  60.     static uint8_t KeyCount[3] = {0, 0, 0};

  61.     KEY_SubScan(&KeyState[0], &KeyCount[0], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_11), "KEY");
  62.     KEY_SubScan(&KeyState[1], &KeyCount[1], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_8), "CALL");
  63.     KEY_SubScan(&KeyState[2], &KeyCount[2], GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_4), "OPEN");
  64. }

功能实现代码:M26启动及配置
  1. uint8_t  M26_Buffer[1000];
  2. uint16_t M26_Length  =  0;


  3. /*******************************************************************************
  4. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  5. * @param      
  6. * @retval      
  7. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  8. *******************************************************************************/
  9. void M26_InitBuffer(void)
  10. {
  11.     M26_Length = 0;
  12.     memset(M26_Buffer, 0, sizeof(M26_Buffer));
  13. }


  14. /*******************************************************************************
  15. * [url=home.php?mod=space&uid=247401]@brief[/url]      
  16. * @param      
  17. * @retval      
  18. * [url=home.php?mod=space&uid=93590]@Attention[/url]   
  19. *******************************************************************************/
  20. void M26_SendData(uint8_t Data)
  21. {
  22.     UART_SendData(UART2, Data);
  23.     while(UART_GetFlagStatus(UART2, UART_IT_TXIEN) == RESET);
  24. }


  25. /*******************************************************************************
  26. * @brief      
  27. * @param      
  28. * @retval      
  29. * @attention   
  30. *******************************************************************************/
  31. void M26_SendString(char *str)
  32. {
  33.     while(*str)
  34.     {
  35.         M26_SendData(*str++);
  36.     }
  37. }


  38. /*******************************************************************************
  39. * @brief      
  40. * @param      
  41. * @retval      
  42. * @attention   
  43. *******************************************************************************/
  44. uint32_t M26_AT_WaitForReply(char *Keyword, uint32_t Timeout)
  45. {
  46.     M26_InitBuffer();

  47.     while(Timeout--)
  48.     {
  49.         if(QUEUE_EMPTY(QUEUE_M26_RX_IDX) == 0)
  50.         {
  51.             M26_Buffer[M26_Length++] = QUEUE_READ(QUEUE_M26_RX_IDX);

  52.             if(strstr((char *)M26_Buffer, Keyword) != NULL)
  53.             {
  54.                 printf("\r\n%s", (char *)M26_Buffer);break;
  55.             }
  56.         }

  57.         SysTick_DelayMS(1);
  58.     }

  59.     return Timeout;
  60. }


  61. /*******************************************************************************
  62. * @brief      
  63. * @param      
  64. * @retval      
  65. * @attention   
  66. *******************************************************************************/
  67. uint32_t M26_AT_SendCommand(char *Command, char *Response, uint32_t Timeout)
  68. {
  69.     if(Command != NULL)
  70.     {
  71.         M26_SendString(Command);
  72.         M26_SendString("\r\n");
  73.     }

  74.     if(Timeout != 0)
  75.     {
  76.         return (Timeout - M26_AT_WaitForReply(Response, Timeout));
  77.     }
  78.     else
  79.     {
  80.         return 1;
  81.     }
  82. }


  83. /*******************************************************************************
  84. * @brief      
  85. * @param      
  86. * @retval      
  87. * @attention   
  88. *******************************************************************************/
  89. void M26_SendMessage(char *str)
  90. {
  91.     char Buffer[200];

  92.     memset(Buffer, 0, sizeof(Buffer));

  93.     sprintf(Buffer, "AT+QISEND=0,%d", strlen(str));

  94.     M26_AT_SendCommand(Buffer, ">", 1000);

  95.     M26_SendString(str);

  96.     printf("\t%dms", M26_AT_SendCommand(NULL, "SEND OK", 1000));
  97. }


  98. /*******************************************************************************
  99. * @brief      
  100. * @param      
  101. * @retval      
  102. * @attention   
  103. *******************************************************************************/
  104. void M26_AT_Startup(void)
  105. {
  106.     printf("\t%dms", M26_AT_SendCommand(NULL, "RDY",          10000));
  107.     printf("\t%dms", M26_AT_SendCommand(NULL, "+CFUN: 1",     10000));
  108.     printf("\t%dms", M26_AT_SendCommand(NULL, "+CPIN: READY", 10000));
  109.     printf("\t%dms", M26_AT_SendCommand(NULL, "Call Ready",   10000));
  110.     printf("\t%dms", M26_AT_SendCommand(NULL, "SMS Ready",    10000));
  111.     printf("\t%dms", M26_AT_SendCommand("AT", "OK",           10000));

  112.     while(M26_AT_SendCommand("AT+CSQ", "OK", 500) != 0)
  113.     {
  114.         if(strstr((char *)M26_Buffer, "99,99") == NULL)
  115.         {
  116.             break;
  117.         }

  118.         SysTick_DelayMS(500);
  119.     }


  120.     M26_AT_SendCommand("AT+CCID",   "OK", 500);

  121.     M26_AT_SendCommand("AT+COPS?",  "OK", 500);

  122.     M26_AT_SendCommand("AT+CREG?",  "OK", 500);

  123.     M26_AT_SendCommand("AT+CGATT?", "OK", 500);


  124.     M26_AT_SendCommand("AT+QIFGCNT=0", "OK", 500);

  125.     M26_AT_SendCommand("AT+QICSGP=1,"CMMTM"", "OK", 500);

  126.     M26_AT_SendCommand("AT+QIDNSIP=1", "OK", 500);

  127.     M26_AT_SendCommand("AT+QIMUX=1", "OK", 500);

  128.     M26_AT_SendCommand("AT+QIOPEN=0,"TCP","xld0932.xicp.net",10520", NULL, 0);

  129.     printf("\t%dms", M26_AT_SendCommand(NULL, "CONNECT OK", 20000));
  130. }

功能实现代码:呼叫及开锁控制
  1. /*******************************************************************************
  2. * @brief      
  3. * @param      
  4. * @retval      
  5. * @attention   
  6. *******************************************************************************/
  7. void BSP_LOCK_Control(uint8_t Mode, uint8_t Enable)
  8. {
  9.     LockMode = Mode;

  10.     if(Enable == 0)
  11.     {
  12.         GPIO_WriteBit(GPIOA, GPIO_Pin_6, Bit_SET);      /* 上锁 */
  13.     }
  14.     else
  15.     {
  16.         GPIO_WriteBit(GPIOA, GPIO_Pin_6, Bit_RESET);    /* 开锁 */
  17.     }
  18. }


  19. /*******************************************************************************
  20. * @brief      
  21. * @param      
  22. * @retval      
  23. * @attention   
  24. *******************************************************************************/
  25. void BSP_LOCK_Handler(void)
  26. {
  27.     static uint8_t LockTimeout = 0;

  28.     if(LockMode == LOCK_MODE_REMOTE)
  29.     {
  30.         LockTimeout++;

  31.         if(LockTimeout == 15)
  32.         {
  33.             if(!GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5))
  34.             {
  35.                 M26_SendMessage("Open The Door Failure!!!");
  36.             }
  37.             else
  38.             {
  39.                 M26_SendMessage("Open The Door Successfully!");
  40.             }
  41.         }

  42.         if(LockTimeout >= 30)
  43.         {
  44.             RemoteState = 0;
  45.             BSP_LOCK_Control(LOCK_MODE_MANUAL, DISABLE);
  46.         }
  47.     }
  48.     else
  49.     {
  50.         LockTimeout = 0;
  51.     }
  52. }


  53. /*******************************************************************************
  54. * @brief      
  55. * @param      
  56. * @retval      
  57. * @attention   
  58. *******************************************************************************/
  59. void REMOTE_Handler(void)
  60. {
  61.     if(RemoteState == 0)
  62.     {
  63.         if(RemoteHeartbeat++ >= 100)
  64.         {
  65.             RemoteHeartbeat = 0;
  66.             M26_SendMessage("Alive!!!");
  67.         }
  68.     }

  69.     if(RemoteState == 1)
  70.     {
  71.         RemoteCount++;

  72.         if(RemoteCount >= 30)
  73.         {
  74.             RemoteCount = 0;
  75.             M26_SendMessage("Calling...");
  76.         }
  77.     }
  78.     else
  79.     {
  80.         RemoteCount = 0;
  81.     }
  82. }


  83. /*******************************************************************************
  84. * @brief      
  85. * @param      
  86. * @retval      
  87. * @attention   
  88. *******************************************************************************/
  89. void MESSAGE_Handler(void)
  90. {
  91.     if(QUEUE_EMPTY(QUEUE_M26_RX_IDX) == 0)
  92.     {
  93.         MSG_Buffer[MSG_Length++] = QUEUE_READ(QUEUE_M26_RX_IDX);

  94.         /* 远程开锁控制 & 返回开锁成功或失败 */
  95.         if(strstr((char *)MSG_Buffer, "OPEN") != NULL)
  96.         {
  97.             RemoteState = 2;

  98.             BSP_LOCK_Control(LOCK_MODE_REMOTE, ENABLE);

  99.             MSG_Length = 0;
  100.             memset(MSG_Buffer, 0, sizeof(MSG_Buffer));
  101.         }
  102.     }
  103. }


演示效果
服务器我们使用花生壳内网穿透映射的方式,将域名及端口号映射到本地内网的IP和端口,再使用网络调试助手软件建立一个TCP/IP服务器,来进行演示,如下图:
服务器.png

ISP下载程序
1.ISP下载程序.gif

系统启动&M26初始化配置
2.系统启动&amp;M26初始化配置.gif

呼叫后手动开锁
3.呼叫后手动开锁.gif

呼叫后远程开锁
4.呼叫后远程开锁.gif

附件
原理图: Schematic_M26_LOCK_2022-03-15.pdf (59.37 KB, 下载次数: 22)
工程源代码: Template.zip (732.96 KB, 下载次数: 18)
其它手册资料: Quectel_M26_AT命令手册_V1.1.pdf (3.25 MB, 下载次数: 11) Quectel_M26_硬件设计手册_V1.2.pdf (1.04 MB, 下载次数: 11)


   

打赏榜单

21小跑堂 打赏了 100.00 元 2022-03-17
理由:恭喜通过原创文章审核!请多多加油哦!

ap0405209 发表于 2022-3-25 17:46 | 显示全部楼层
请问主控板上的按键是什么型号的按键?能否告知?或者发个链接?谢谢
 楼主| xld0932 发表于 2022-3-25 18:13 | 显示全部楼层
ap0405209 发表于 2022-3-25 17:46
请问主控板上的按键是什么型号的按键?能否告知?或者发个链接?谢谢

TPB01-107L1B,带红色灯 带支架:https://item.szlcsc.com/2885279.html
redone 发表于 2022-3-30 11:02 | 显示全部楼层
理解为类似只能门锁的远程开门?
 楼主| xld0932 发表于 2022-3-30 17:55 | 显示全部楼层
redone 发表于 2022-3-30 11:02
理解为类似只能门锁的远程开门?

只是一个雏形,基于这个可以加上摄像头、手机APP、语音等等,就是一个完整的产品了
redone 发表于 2022-4-2 10:33 | 显示全部楼层
xld0932 发表于 2022-3-30 17:55
只是一个雏形,基于这个可以加上摄像头、手机APP、语音等等,就是一个完整的产品了 ...

很不错
tpgf 发表于 2022-4-3 09:58 | 显示全部楼层
安全性能如何呀
aoyi 发表于 2022-4-3 10:21 | 显示全部楼层
整个系统的里子都有了
nawu 发表于 2022-4-3 10:30 | 显示全部楼层
这个有有效距离的说法吗
zljiu 发表于 2022-4-3 10:37 | 显示全部楼层
是不是还需要什么声波识别啊
gwsan 发表于 2022-4-3 10:46 | 显示全部楼层
这个是要加一个通讯卡吗
tfqi 发表于 2022-4-3 10:58 | 显示全部楼层
感觉在国内的话用的不会很多
caigang13 发表于 2022-4-3 11:22 来自手机 | 显示全部楼层
不错,帮顶一下
ap0405209 发表于 2022-5-12 16:14 | 显示全部楼层
xld0932 发表于 2022-3-25 18:13
TPB01-107L1B,带红色灯 带支架:https://item.szlcsc.com/2885279.html

谢谢楼主,
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部
个人签名:King.Xu

77

主题

3023

帖子

38

粉丝
快速回复 在线客服 返回列表 返回顶部