你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

NUCLEO-F767ZI以太网功能实现笔记本电脑不开盖开机

[复制链接]
zoomdy 提问时间:2017-1-31 16:56 /
不想打开笔记本盖子按开机按钮开机?可以使用Wake-on-LAN远程唤醒。这里展示怎么用NUCELO-F767ZI以太网功能发送MagicPacket唤醒笔记本电脑。

http://blog.csdn.net/zoomdy/article/details/54799462
mingdu.zheng at gmail dot com

缘起:不想开盖按电源按钮
因为有一台23吋显示器,笔记本电脑在家里基本上当台式机用。每次开机的时候都要打开翻盖按一下电源按钮然后又合上,嫌开盖开机麻烦,然后就在网上找不开盖就能开机的方法,唯一靠谱的方案就是Wake-on-LAN,即局域网唤醒,简称WOL。正好有一块NUCLEO-F767ZI开发板,这是一款带以太网的开发板,可以用来发送MagicPacket唤醒我的笔记本电脑。
wakeonlan.jpg

设置BIOS
要使用Wake-on-LAN功能,首先要进入BIOS打开Wake-on-LAN功能,不同的机器其设置位置可能不同,进BIOS找一找。也有可能不被支持。

验证Wake-on-LAN可以工作
这里以Ubuntu 12.04为例,Windows环境可以问度娘。首先使用ethtool工具检查需要被唤醒的机器是否正确打开了Wake-on-LAN功能,请注意ethtool工具输出的两条信息 Supports Wake-on: pumbgWake-on: g,Supports Wake-on说明是否具备Wake-on-LAN功能,Wake-on为g说明已经打开了Wake-on-LAN,如果Wake-on为d说明Wake-on-LAN被关闭了,更具体的内容可以 man ethtool
  1. sudo apt-get install ethtool
  2. sudo ethtool eth0
复制代码
  1. Settings for eth0:
  2.     ......
  3.     Supports Wake-on: pumbg
  4.     Wake-on: g
复制代码
关闭需要被唤醒的机器,然后在另外一台电脑使用wakeonlan工具唤醒。
  1. sudo apt-get install wakeonlan
  2. wakeonlan 28:D2:44:3E:07:56
复制代码
  1. Sending magic packet to 255.255.255.255:9 with 28:D2:44:3E:07:56
复制代码

如果设置没有错的话,稍等几秒钟就可以看到机器被唤醒了。

唤醒的原理
wakeonlan命令会发送一个目标端口为9的UDP广播数据包:MagicPacket,待唤醒机器的网卡接收到MagicPacket后,就会唤醒计算机。MagicPacket的格式如下图所示,开头是6字节FF,后面复制16份待唤醒机器的MAC地址。
火狐截图_2017-01-31T07-59-54.981Z.png

关于Wake-on-LAN更详细的内容可以参考这里:http://wiki.wireshark.org/WakeOnLAN

用NUCLEO-F767ZI实现唤醒
如果要用另外一台电脑输入命令来唤醒我的笔记本电脑,那比开盖更麻烦啊!我的预期是:按下排插按钮就可以自动唤醒。正好我有一块NUCLEO-F767ZI开发板,这是一块带有以太网功能的开发板,可以用NUCLEO-F767ZI发送MagicPacket唤醒机器。

首先参考这篇http://blog.csdn.net/zoomdy/article/details/54784027将以太网功能跑通。

然后修改lwIP配置,使用静态地址方式,DHCP获取地址是需要时间的,静态地址可以快很多。
wol-1.png

编写代码,在NUCLEO-F767ZI上电后发送一个MagicPacket,这是一个UDP包,使用lwIP的udp_*系列API来实现。没有使用socket接口,也没有加入FreeRTOS,这是个简单的应用,简单一些就可以了。

完整的源代码请访问:http://git.oschina.net/zoomdy/Wake-on-LAN,这里给出关键代码。

  1. /*
  2. * Src/wol.c
  3. * http://wiki.wireshark.org/WakeOnLAN
  4. *
  5. * Packet Format
  6. *  |Synchronization Stream   |Target MAC   |Password (optional)  |
  7. *  |6                        |96           |0, 4 or 6            |
  8. *
  9. * The Synchronization Stream is defined as 6 bytes of FFh.
  10. *
  11. * The Target MAC block contains 16 duplications of the IEEE address
  12. * of the target, with no breaks or interruptions.
  13. *
  14. * The Password field is optional, but if present, contains either 4
  15. * bytes or 6 bytes. The WakeOnLAN dissector was implemented to dissect
  16. * the password, if present, according to the command-line format that
  17. * ether-wake uses, therefore, if a 4-byte password is present, it will
  18. * be dissected as an IPv4 address and if a 6-byte password is present,
  19. * it will be dissected as an Ethernet address.
  20. */

  21. #include <stdint.h>
  22. #include <string.h>
  23. #include "stm32f7xx_hal.h"
  24. #include "lwip.h"
  25. #include "lwip/udp.h"
  26. #include "wol.h"

  27. void Error_Handler(void);

  28. // 被唤醒机器的MAC地址
  29. static const uint8_t targetAddress[ETHARP_HWADDR_LEN] =
  30.   { 0x28, 0xd2, 0x44, 0x3e, 0x07, 0x56 };

  31. static void fillMagicPacket(uint8_t buf[])
  32. {
  33.   int i;

  34.   memset(&buf[0], 0xff, ETHARP_HWADDR_LEN);

  35.   for (i = 0; i < 16; i++)
  36.   {
  37.     memcpy(&buf[(1 + i) * ETHARP_HWADDR_LEN], &targetAddress[0],
  38.         ETHARP_HWADDR_LEN);
  39.   }
  40. }

  41. static void sendMagicPacket(void)
  42. {
  43.   static struct udp_pcb *pcb = NULL;
  44.   struct pbuf *pbuf = NULL;
  45.   err_t err;

  46.   if (pcb == NULL)
  47.   {
  48.     pcb = udp_new();
  49.     if (pcb == NULL)
  50.     {
  51.       Error_Handler();
  52.     }

  53.     err = udp_connect(pcb, IP_ADDR_BROADCAST, 9);
  54.     if (err != ERR_OK)
  55.     {
  56.       Error_Handler();
  57.     }
  58.   }

  59.   pbuf = pbuf_alloc(PBUF_TRANSPORT, (1 + 16) * ETHARP_HWADDR_LEN,
  60.       PBUF_RAM);
  61.   if (pbuf == NULL)
  62.   {
  63.     Error_Handler();
  64.   }

  65.   fillMagicPacket(pbuf->payload);

  66.   err = udp_send(pcb, pbuf);
  67.   if (err != ERR_OK)
  68.   {
  69.     Error_Handler();
  70.   }

  71.   pbuf_free(pbuf);
  72.   pbuf = NULL;

  73. #if 0 // 不要释放pcb,后面还要用
  74.   udp_remove(pcb);
  75.   pcb = NULL;
  76. #endif

  77. }

  78. void WOL_Process(void)
  79. {
  80.   static int fired = 0;
  81.   uint32_t tick;

  82.   tick = HAL_GetTick();
  83.   if(fired == 0 && tick >= 2000) // 上电2秒后发送Magic Packet
  84.   {
  85.     sendMagicPacket();
  86.     HAL_GPIO_WritePin(GPIOB, LED_RED_Pin, GPIO_PIN_SET);
  87.     fired = 1;
  88.   }
  89. }

  90. void BTN_Process(void)
  91. {
  92.   static uint32_t tick_prev = 0;
  93.   static uint32_t btn_state = 0;
  94.   uint32_t tick;

  95.   tick = HAL_GetTick();
  96.   if(tick != tick_prev)
  97.   {
  98.     tick_prev = tick;
  99.     btn_state <<= 1;
  100.     if(HAL_GPIO_ReadPin(BTN_USER_GPIO_Port, BTN_USER_Pin))
  101.     {
  102.       btn_state |= 1;
  103.       HAL_GPIO_WritePin(GPIOB, LED_BLUE_Pin, GPIO_PIN_SET);
  104.       HAL_GPIO_WritePin(GPIOB, LED_RED_Pin, GPIO_PIN_RESET);
  105.     }
  106.     else
  107.     {
  108.       btn_state |= 0;
  109.       HAL_GPIO_WritePin(GPIOB, LED_BLUE_Pin, GPIO_PIN_RESET);
  110.     }

  111.     if(btn_state == 0xffff0000) // 按钮释放立即发送Magic Packet
  112.     {
  113.       sendMagicPacket();
  114.       HAL_GPIO_WritePin(GPIOB, LED_RED_Pin, GPIO_PIN_SET);
  115.     }
  116.   }
  117. }

  118. void LED_Process(void)
  119. {
  120.   if(HAL_GetTick() & 0x100)
  121.   {
  122.     HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin, GPIO_PIN_SET);
  123.   }
  124.   else
  125.   {
  126.     HAL_GPIO_WritePin(GPIOB, LED_GREEN_Pin, GPIO_PIN_RESET);
  127.   }
  128. }
复制代码
  1. /*
  2. * Src/main.c 仅给出main函数部分
  3. */
  4. int main(void)
  5. {

  6.   /* USER CODE BEGIN 1 */

  7.   /* USER CODE END 1 */

  8.   /* MCU Configuration----------------------------------------------------------*/

  9.   /* Reset of all peripherals, Initializes the Flash interface and the Systick. */
  10.   HAL_Init();

  11.   /* Configure the system clock */
  12.   SystemClock_Config();

  13.   /* Initialize all configured peripherals */
  14.   MX_GPIO_Init();
  15.   MX_USART3_UART_Init();
  16.   MX_LWIP_Init();

  17.   /* USER CODE BEGIN 2 */

  18.   /* USER CODE END 2 */

  19.   /* Infinite loop */
  20.   /* USER CODE BEGIN WHILE */
  21.   while (1)
  22.   {
  23.   /* USER CODE END WHILE */

  24.   /* USER CODE BEGIN 3 */
  25.     MX_LWIP_Process();
  26.     WOL_Process();
  27.     BTN_Process();
  28.     LED_Process();
  29.     __WFE(); // Save 40mA
  30.   }
  31.   /* USER CODE END 3 */

  32. }
复制代码

最后
用NUCLEO-F767ZI做这么简单的工作是不是大材小用了?过了元宵节,买块NUCLEO-F207ZG,终于有理由买NUCLEO-F207ZG了。

评分

参与人数 1 ST金币 +20 收起 理由
zero99 + 20

查看全部评分

收藏 5 评论9 发布时间:2017-1-31 16:56

举报

9个回答
peter001 回答时间:2017-1-31 21:29:25
支持一下
stm2i 回答时间:2017-1-31 23:19:16
也支持一下!
党国特派员 回答时间:2017-2-3 10:06:44
学习了。。。
Veikoboy 回答时间:2017-2-9 17:10:58
项一个
jolay 回答时间:2017-2-10 18:31:39
屌。。。。
sphinxly 回答时间:2017-2-13 09:31:20
顶顶顶
sphinxly 回答时间:2017-2-13 09:33:03
什么鬼啊  怎么回复会消耗ST币。。。ST币不够还回复不了
wofei1314 回答时间:2017-2-13 09:56:59
Cool~

谢谢分享!
zld9251 回答时间:2017-2-13 23:10:25
厉害了啊

所属标签

相似问题

关于意法半导体
我们是谁
投资者关系
意法半导体可持续发展举措
创新和工艺
招聘信息
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
关注我们
st-img 微信公众号
st-img 手机版