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

查看: 2467|回复: 9

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

[复制链接]

14

主题

293

回帖

17

蝴蝶豆

金牌会员

最后登录
2019-5-9
发表于 2017-1-31 16:56:05 | 显示全部楼层 |阅读模式
不想打开笔记本盖子按开机按钮开机?可以使用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了。

评分

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

查看全部评分

<
回复

使用道具 举报

11

主题

1139

回帖

0

蝴蝶豆

金牌会员

最后登录
2020-7-10
发表于 2017-1-31 21:29:25 | 显示全部楼层
支持一下
回复 支持 反对

使用道具 举报

7

主题

62

回帖

4

蝴蝶豆

金牌会员

最后登录
2020-9-25
发表于 2017-1-31 23:19:16 | 显示全部楼层
也支持一下!
回复 支持 反对

使用道具 举报

76

主题

5715

回帖

4

蝴蝶豆

论坛元老

最后登录
2020-10-15
发表于 2017-2-3 10:06:44 | 显示全部楼层
学习了。。。
回复 支持 反对

使用道具 举报

3

主题

82

回帖

2

蝴蝶豆

高级会员

最后登录
2018-2-1
发表于 2017-2-9 17:10:58 | 显示全部楼层
项一个
回复 支持 反对

使用道具 举报

0

主题

17

回帖

0

蝴蝶豆

初级会员

最后登录
2020-7-14
发表于 2017-2-10 18:31:39 | 显示全部楼层
屌。。。。
回复 支持 反对

使用道具 举报

1

主题

15

回帖

0

蝴蝶豆

新手上路

最后登录
2017-3-1
发表于 2017-2-13 09:31:20 | 显示全部楼层
顶顶顶
回复 支持 反对

使用道具 举报

1

主题

15

回帖

0

蝴蝶豆

新手上路

最后登录
2017-3-1
发表于 2017-2-13 09:33:03 | 显示全部楼层
什么鬼啊  怎么回复会消耗ST币。。。ST币不够还回复不了
回复 支持 反对

使用道具 举报

39

主题

934

回帖

45

蝴蝶豆

论坛元老

最后登录
2020-6-18
发表于 2017-2-13 09:56:59 | 显示全部楼层
Cool~

谢谢分享!
回复 支持 反对

使用道具 举报

2

主题

43

回帖

0

蝴蝶豆

中级会员

最后登录
2020-5-15
发表于 2017-2-13 23:10:25 | 显示全部楼层
厉害了啊
回复 支持 反对

使用道具 举报

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
STM32N6 AI生态系统
STM32MCU,MPU高性能GUI
ST ACEPACK电源模块
意法半导体生物传感器
STM32Cube扩展软件包
关注我们
st-img 微信公众号
st-img 手机版