嘿,小伙伴们,让我给你们介绍一款超级英雄级别的开发板——W800-Arduino,这可是联盛德家的明星产品,基于W800芯片打造,简直就是开发界的“钢铁侠”!
image.png
想象一下,你手上这个小板子,它不仅带着外置天线接口和自备的天线,就像蝙蝠侠的耳朵一样灵敏;还内置了一个5v转3.3v的LDO芯片,就像是超人的腰带,随时给你提供能量转换的神奇力量!
image.png
更酷的是,它上面有三个按钮:BOOT、RESET和USER,简直就是开发者的“复仇者联盟”控制器,特别是那个USER按钮,简直就是给你准备的“调试神器”,一按下去,程序就像被雷神托尔的锤子击中一样,瞬间听话起来!

而且,这个开发板上还有一个三色LED灯,就像绿灯侠的信号灯一样,闪烁着智慧的光芒,告诉你程序运行的状态。
image.png
为了让你的外设连接更加方便,W800-Arduino把IO信号和系统电源管脚都放在了板子的上下两侧,就像蜘蛛侠的手脚一样,四面八方都能连接,简直是“万能插座”!

说到开发框架,那就不得不提WinnerMicro家的WM IoT SDK v2.0.0rc2了,这简直就是开发者的“瑞士军刀”!里面包括了:
image.png
- 全新的在线文档,就像一本魔法书,一读就懂,一用就灵!
- 独立且丰富的示例工程,就像乐高积木一样,拼拼凑凑就能搭建出你的创意世界!
- cmake编译系统和kconfig配置系统,让你在命令行和IDE之间自由穿梭,编译效率高到飞起!
- 全新的驱动架构,还有全局设备表统一管理设备,就像钢铁侠的AI助手贾维斯一样,一切尽在掌控!
image.png
它还支持WiFi Station、SoftAP和TCP/IP网络功能,让你的网络连接像蜘蛛侠在城市中穿梭一样自如。还有一个全新的网络管理组件network manager,简直就是网络连接的“简化大师”!
image.png
还有BLE配网功能,让你的设备像蓝牙耳机一样轻松配对。支持HTTP client和HTTPS功能,让你的数据传输像超人飞行一样快速安全!

更有freertos、mbedtls、iperf3、ntp、cli、fatfs等常用第三方开源组件,让你的开发像拥有了神奇工具箱一样,无所不能!

还支持分区表功能,你可以自定义分区表,就像定制自己的超级英雄战衣一样,独一无二!
image.png
而且,它还支持选择W80X系列的各种不同SOC,自动适配架构,就像变形金刚一样,随心所欲地变换形态!

最后,它还提供了自研的event、堆内存、nvs、log等基础组件,以及ATCMD功能,让你的开发之路像《疯狂动物城》里的朱迪一样,勇往直前,无所畏惧!

联盛德家W800-Arduino和WM IoT SDK好用,上手快,从拿到快递到跑完程序1小时搞定,给5星好评!
怎么样,是不是已经被W800-Arduino和WM IoT SDK的魅力深深吸引了呢?那就赶快加入开发者的行列吧,让我们一起创造更加美好的物联网世界。现在开始设计自己的程序下载到板子上。设计个什么好呢?要不设计个椭圆曲线方程多重加密颜色亮度的程序呢...
image.png
说起利用椭圆曲线方程进行多重加密这事儿,咱们得先穿上件“数学战袍”,准备好迎接一场智慧与狡猾的较量!不过别担心,我会尽量用简单的方式,让你掌握这个知识。

首先,椭圆曲线加密,听起来就像是魔法学校的秘密咒语,对吧?但其实,它背后的原理并不那么神秘,只是有点...嗯...绕脑筋。想象一下,你手里有张椭圆形的纸,上面画满了密密麻麻的点,这些点就是我们的“椭圆曲线家族”。而黑客们呢,他们就像是想偷偷溜进魔法城堡的小偷,总想找到一种方法,用这些点来编织出复杂的加密咒语。
image.png
那么,椭圆曲线方程是什么呢?简单来说,它就像是一个魔法公式,用来描述这些点在纸上的位置。比如,y^2=x^3+ax+b这样的方程,其中a和b是些神秘的数字,它们决定了椭圆曲线的形状。黑客们要是想加密信息,就得先挑一条合适的椭圆曲线,然后像变魔术一样,把信息藏在这些点的位置里。

但是!我们可不能让黑客们这么轻易就得逞!为了防止他们利用椭圆曲线方程进行多重加密,我们得采取一些措施。首先,我们要挑一条“难搞”的椭圆曲线,让黑客们很难找到合适的点来藏信息。就像是在魔法城堡里设下重重机关,让小偷们摸不着头脑。
image.png
其次,我们还要学会“破解魔法咒语”的技巧。也就是说,我们要能够理解椭圆曲线方程背后的数学原理,从而找到破解黑客加密的方法。这就像是学习一门古老的魔法语言,能够读懂并反制敌人的咒语。
image.png
不过呢,话又说回来,椭圆曲线加密本身其实是一种非常安全且高效的加密方式。它就像是一把双刃剑,既能保护我们的信息安全,又可能被黑客们利用来搞破坏。所以,在使用它的时候,我们一定要格外小心,确保自己不会成为黑客们的下一个目标。
image.png
防止黑客利用椭圆曲线方程进行多重加密并不是一件轻松的事情。但只要我们掌握了足够的数学知识和加密技巧,就能够在这场智慧与狡猾的较量中占据上风!所以呀,大家还是要好好学习数学哦,说不定哪天你就能成为拯救世界的超级英雄呢! 椭圆曲线方程多重加密(Elliptic Curve Cryptography with Multi-layer Encryption)是一种基于椭圆曲线数学结构的加密方法,它结合了椭圆曲线离散对数问题的难解性与多层加密的安全性。

1. 椭圆曲线基础

image.png

椭圆曲线方程通常表示为:

y2=x3+ax+b

其中,ab 是满足特定条件的整数,使得曲线没有奇异点(即曲线平滑)。这个方程定义在有限域 Fp​ 上,其中 p 是一个大素数。


image.png

2. 椭圆曲线上的点群

椭圆曲线上的点(包括无穷远点 O)构成一个阿贝尔群,记作 E(Fp​)。群中的点满足加法运算规则,该规则由几何方法定义,也可以通过代数公式计算。


image.png

3. 椭圆曲线离散对数问题

给定椭圆曲线上的两个点 PQ,寻找一个整数 k,使得 Q=kP 是一个难解问题,这是椭圆曲线密码学(ECC)安全性的基础。


image.png

4. 椭圆曲线加密基础

在ECC中,通常选择一个基点 G 和一个私钥 d(一个大整数)。公钥 Q 通过计算 Q=dG 得到。加密过程涉及选择一个随机数 k,计算点 C1​=kGC2​=Q+kP(其中 P 是明文对应的点),密文即为 (C1​,C2​)。解密过程则利用私钥 d,通过计算 dC1​=k(dG)=kQC2​−dC1​=P 来恢复明文点 P


image.png

5. 多重加密

多重加密是指在上述基础上,对密文进行多次加密。具体来说,可以定义多个椭圆曲线(或同一个曲线上的不同基点),并对明文进行逐层加密。

image.png
  • 第一层加密:使用第一组椭圆曲线参数(或基点)和私钥,对明文进行加密,得到第一层密文。
  • 第二层加密:使用第二组椭圆曲线参数(或基点)和私钥,对第一层密文进行加密,得到第二层密文。
  • ...
  • 第n层加密:使用第n组椭圆曲线参数(或基点)和私钥,对第n-1层密文进行加密,得到最终密文。
image.png

6. 解密过程

解密过程与加密过程相反,从最终密文开始,逐层使用对应的私钥和椭圆曲线参数进行解密,直到恢复出明文。


image.png

数学表示

假设有 n 层加密,第 i 层加密使用的椭圆曲线为 Ei​(Fpi​​),基点为 Gi​,私钥为 di​,明文点为 P


image.png
  • 加密
    • 第1层密文:(C1(1)​,C2(1)​)=(k1​G1​,Q1​+k1​P),其中 Q1​=d1​G1​,k1​ 是随机数。
    • 第2层密文:(C1(2)​,C2(2)​)=(k2​G2​,Q2​+k2​C1(1)​),其中 Q2​=d2​G2​,k2​ 是随机数。
    • ...
    • 第n层密文:(C1(n)​,C2(n)​)=(knGn​,Qn​+knC1(n−1)​),其中 Qn​=dnGn​,kn​ 是随机数。

      image.png
  • 解密
    • 从第n层开始,逐层计算 dnC1(n)​=knQn​,然后 C2(n)​−dnC1(n)​ 得到上一层密文的 C1(n−1)​ 部分,继续此过程直到恢复出明文点 P

      image.png

椭圆曲线方程多重加密通过结合椭圆曲线的难解性和多层加密的安全性,提供了一种强大且灵活的加密方法。它不仅能够抵抗各种密码学攻击,还能在保持较高安全性的同时,实现较小的密钥尺寸和较快的计算速度。

  1. /*
  2. 这个文件就像一个神奇的魔术师,能让W800 Arduino板上的PWM(脉宽调制)功能像变戏法一样工作!

  3. */

  4. #include "wm_dt.h"
  5. #include "wm_dt_hw.h"
  6. #include "wm_soc_cfgs.h"
  7. #include <stdint.h>
  8. #include <stdlib.h>
  9. #include <stdarg.h>
  10. #include <getopt.h>
  11. // wmsdk_config.h,这是个神秘的头文件,它隐藏着W800 Arduino项目的各种秘密设定,就像是游戏中的隐藏关卡。
  12. #include "wmsdk_config.h"
  13. #include "wm_error.h"
  14. #include "wm_cli.h"
  15. #include "wm_dt.h"
  16. #include "wm_drv_pwm.h"
  17. #include "wm_drv_gpio.h"
  18. // 我们继续召唤stdio.h和string.h这两个强大的战士,它们分别负责输入输出和字符串处理,是任何C语言项目中不可或缺的好伙伴。
  19. #include <stdio.h>
  20. #include <string.h>

  21. // 首先,我们定义了一个LOG_TAG宏,这就像给我们的代码起一个外号,让人一听就知道是哪个英雄出场了。
  22. #define LOG_TAG "w800_arduino"

  23. // 接下来,我们像召唤神龙一样,召唤了wm_log.h这个头文件,它是用来记录日志的,就像一个忠实的日记本,记录下所有重要的瞬间。
  24. #include "wm_log.h"
  25. // 如果你不想知道你的程序到底占用了多少内存,或者内存是如何分配的,那么下面这两行可以忽略不计,但如果你是个好奇心旺盛的探险家,就不要错过它们了!
  26. /*Below include statement can be removed if user no need to get heap, partition table info in this project*/
  27. #include "wm_heap.h"
  28. #include "wm_partition_table.h"


  29. // 定义一个非常不高兴的比例值,当PWM找不到自己的位置时就会用到它。
  30. #define PWM_INVALID_RATIO        (-1)
  31. // 检查PWM设备是否已经初始化,如果没初始化,那可就麻烦了,就像没有驾照就开车一样危险!
  32. #define PWM_INIT_CHECK()         (param.pwm_device && param.pwm_device->state == WM_DEV_ST_INITED)
  33. // PWM的亮度等级上限,就像太阳的光辉,虽然无限,但我们只能看到这么多。
  34. #define PWM_DUTY_CYCLE_LEVEL_MAX (255)
  35. // 一个小小的检查函数,确保我们的PWM值不会超范围,就像确保你的宠物不会跳出花园一样重要。
  36. #define PWM_RATIO_CHECK(v)                              \
  37.     if ((unsigned int)(v) > PWM_DUTY_CYCLE_LEVEL_MAX) { \
  38.         cmd_pwm_usage(argv[0]);                         \
  39.         return WM_ERR_FAILED;                           \
  40.     }

  41. // 枚举定义了RGB三种颜色对应的PWM通道,就像给每个孩子分配了一个特别的房间。
  42. enum {
  43.     PWM_LED_GREEN, /**< 绿色LED,住在PWM通道0 */
  44.     PWM_LED_RED,   /**< 红色LED,住在PWM通道1 */
  45.     PWM_LED_BLUE,  /**< 蓝色LED,住在PWM通道2 */

  46.     PWM_LED_MAX
  47. };

  48. // 定义了一个结构体,里面装着控制PWM的所有秘密武器。
  49. static struct cmd_pwm_param {
  50.     int ratio[PWM_LED_MAX]; // 存储每种颜色的亮度值,就像调色盘上不同颜料的量。
  51.     char *pwm_name; // PWM的名字,就像每个人都有一个名字一样重要。
  52.     wm_device_t *pwm_device; // 指向PWM设备的指针,就像导航仪指引方向一样。
  53.     wm_drv_pwm_channel_cfg_t cfg[PWM_LED_MAX]; // 配置信息,每个通道的配置就像每个人的个性设置。
  54. } param;

  55. // 假设我们使用一个较小的素数p和椭圆曲线参数a, b  
  56. #define P 23  // 素数p  
  57. #define A 1   // 椭圆曲线参数a  
  58. #define B 1   // 椭圆曲线参数b  
  59.   
  60. // 模运算函数  
  61. unsigned char mod_add(unsigned char a, unsigned char b, unsigned char p) {  
  62.     unsigned char result = a + b;  
  63.     if (result >= p) {  
  64.         result -= p;  
  65.     }  
  66.     return result;  
  67. }  
  68.   
  69. unsigned char mod_sub(unsigned char a, unsigned char b, unsigned char p) {  
  70.     unsigned char result = a - b;  
  71.     if (result < 0) {  
  72.         result += p;  
  73.     }  
  74.     return result;  
  75. }  
  76.   
  77. unsigned char mod_mul(unsigned char a, unsigned char b, unsigned char p) {  
  78.     unsigned char result = 0;  
  79.     while (b > 0) {  
  80.         if (b & 1) {  
  81.             result = mod_add(result, a, p);  
  82.         }  
  83.         a = mod_mul(a, 2, p); // a = a * 2 % p
  84.         b >>= 1;  
  85.     }  
  86.     return result;  
  87. }  
  88.   
  89. // 快速幂算法计算a^b % p  
  90. unsigned char mod_exp(unsigned char a, unsigned char b, unsigned char p) {  
  91.     unsigned char result = 1;  
  92.     while (b > 0) {  
  93.         if (b & 1) {  
  94.             result = mod_mul(result, a, p);  
  95.         }  
  96.         a = mod_mul(a, a, p);  
  97.         b >>= 1;  
  98.     }  
  99.     return result;  
  100. }  
  101.   

  102. // 当用户不知道怎么玩时,这个函数就像一位耐心的老师,会告诉你如何操作。
  103. static void cmd_pwm_usage(const char *basename)
  104. {
  105.     wm_cli_printf("\r\n"
  106.                   "  -r <color value>         设置红色亮度值 [0, 255],就像调整红墨水的浓度。\r\n"
  107.                   "  -g <color value>         设置绿色亮度值 [0, 255],就像调整绿墨水的浓度。\r\n"
  108.                   "  -b <color value>         设置蓝色亮度值 [0, 255],就像调整蓝墨水的浓度。\r\n"
  109.                   "  -h                 打印帮助并退出,当你迷路时,这是回家的地图。\r\n",
  110.                   basename);
  111. }

  112. // 解析命令行参数的函数,就像是读取一封密信,找出藏在里面的内容。
  113. static int cmd_pwm_parse_args(struct cmd_pwm_param *param, int argc, char **argv)
  114. {
  115.     int flag;

  116.     optind = 1; // 将光标移到命令行的开始,准备阅读每一个单词。
  117.     while ((flag = getopt(argc, argv, "r:g:b:h")) != -1) { // 开始解析命令行。
  118.         switch (flag) {
  119.             case 'r': // 如果是'r',那就调整红色的亮度。
  120.                 param->ratio[PWM_LED_RED] = atoi(optarg); // 把字符串转换成数字,就像把字母变成数字一样神奇。
  121.                 PWM_RATIO_CHECK(param->ratio[PWM_LED_RED]); // 检查值是否合理,就像检查药方上的剂量是否正确。
  122.                 break;
  123.             case 'g': // 如果是'g',那就调整绿色的亮度。
  124.                 param->ratio[PWM_LED_GREEN] = atoi(optarg);
  125.                 PWM_RATIO_CHECK(param->ratio[PWM_LED_GREEN]);
  126.                 break;
  127.             case 'b': // 如果是'b',那就调整蓝色的亮度。
  128.                 param->ratio[PWM_LED_BLUE] = atoi(optarg);
  129.                 PWM_RATIO_CHECK(param->ratio[PWM_LED_BLUE]);
  130.                 break;
  131.             default: // 如果都不是,那可能就是用户迷路了,需要指路。
  132.                 cmd_pwm_usage(argv[0]);
  133.                 return WM_ERR_FAILED;
  134.         }
  135.     }

  136.     return WM_ERR_SUCCESS;
  137. }

  138. // 这个函数负责控制PWM通道的操作,就像乐队指挥家,指挥着每个乐手演奏。
  139. static int cmd_pwm_channel_operation(wm_device_t *pwm_device, wm_drv_pwm_channel_cfg_t *cfg, uint8_t duty_cycle)
  140. {
  141.     enum wm_pwm_channels channel = cfg->channel; // 获取当前处理的通道号。
  142.     wm_dt_hw_pwm_t *hw           = pwm_device->hw; // 获取硬件信息,就像了解乐器的特性。
  143.     wm_dt_hw_pin_cfg_t *pin_cfg  = hw->pin_cfg; // 获取引脚配置信息,就像知道乐器的音孔在哪里。

  144.     // 尝试设置PWM通道的占空比,如果失败了,就要尝试重新初始化。
  145.     if (WM_ERR_SUCCESS == wm_drv_pwm_set_channel_duty(pwm_device, channel, duty_cycle)) {
  146.         return WM_ERR_SUCCESS;
  147.     }

  148.     if (pin_cfg == NULL) { // 如果引脚配置为空,那就像是没有乐器,无法演奏。
  149.         wm_cli_printf("err: invalid pin cfg!\r\n");
  150.         return WM_ERR_INVALID_PARAM;
  151.     }

  152.     // 尝试初始化PWM通道,如果成功,再启动它。
  153.     if (WM_ERR_SUCCESS == wm_drv_pwm_channel_init(pwm_device, cfg)) {
  154.         if (WM_ERR_SUCCESS != wm_drv_pwm_channel_start(pwm_device, channel)) {
  155.             return WM_ERR_FAILED;
  156.         }
  157.     } else {
  158.         return WM_ERR_FAILED;
  159.     }

  160.     // 设置GPIO的复用功能,就像为乐器选择合适的演奏方式。
  161.     if (WM_ERR_SUCCESS != wm_drv_gpio_iomux_func_sel(pin_cfg[channel].pin_num, pin_cfg[channel].pin_mux)) {
  162.         wm_cli_printf("err: fail to set gpio[%d]!\r\n", pin_cfg[channel].pin_num);
  163.         wm_drv_pwm_channel_deinit(pwm_device, channel); // 如果设置失败,记得清理现场。
  164.         return WM_ERR_FAILED;
  165.     }

  166.     return WM_ERR_SUCCESS;
  167. }

  168. // 遍历所有PWM通道,设置它们的参数,就像给每个乐手分配乐谱。
  169. static int cmd_pwm_channel_foreach(struct cmd_pwm_param *param)
  170. {
  171.     uint8_t duty_cycle;
  172.     for (int i = 0; i < PWM_LED_MAX; i++) { // 对于每一个通道...
  173.         if (param->ratio[i] != PWM_INVALID_RATIO) { // 如果有有效的亮度值...
  174.             param->cfg[i].channel = i; // 设置通道号。
  175.             param->cfg[i].mode    = WM_PWM_OUT_INDPT; // 设置模式为独立输出,就像独奏一样。
  176.             param->cfg[i].clkdiv  = WM_PWM_CLKDIV_DEFAULT; // 设置默认的时钟分频器,就像设定音乐的速度。

  177.             // 设置周期循环数,这决定了PWM信号的频率,就像设定乐曲的节奏。
  178.             param->cfg[i].period_cycle = WM_PWM_MAX_PERIOD;

  179.             // 由于W800 Arduino PWM RGB LED的特殊性,我们需要反转信号,就像让乐队倒着演奏一样。
  180.             duty_cycle = PWM_DUTY_CYCLE_LEVEL_MAX - param->ratio[i];

  181.             param->cfg[i].duty_cycle = duty_cycle; // 设置占空比。
  182.             param->cfg[i].autoload   = true; // 开启自动加载,就像开启了自动演奏模式。
  183.             if (WM_ERR_SUCCESS != cmd_pwm_channel_operation(param->pwm_device, ¶m->cfg[i], duty_cycle)) {
  184.                 wm_cli_printf("err: fail to set the channel[%d]!\r\n", i); // 如果设置失败,打印错误信息。
  185.                 return WM_ERR_FAILED;
  186.             }
  187.         }
  188.     }

  189.     return WM_ERR_SUCCESS;
  190. }

  191. // 就像音乐会的导演,一切从这里开始。

  192. // 扩展欧几里得算法求逆元  
  193. int mod_inv(unsigned char a, unsigned char p) {  
  194.     int t = 0, new_t = 1;  
  195.     int r = p, new_r = a;  
  196.     while (new_r != 0) {  
  197.         int quotient = r / new_r;  
  198.         int temp_t = t;  
  199.         t = new_t;  
  200.         new_t = temp_t - quotient * new_t;  
  201.   
  202.         int temp_r = r;  
  203.         r = new_r;  
  204.         new_r = temp_r - quotient * new_r;  
  205.     }  
  206.     if (r > 1) {  
  207.         return -1; // a is not invertible  
  208.     }  
  209.     if (t < 0) {  
  210.         t = t + p;  
  211.     }  
  212.     return t;  
  213. }  
  214.   
  215. // 椭圆曲线上的点加运算  
  216. void point_add(unsigned char *x1, unsigned char *y1, unsigned char x2, unsigned char y2, unsigned char *result_x, unsigned char *result_y) {  
  217.     unsigned char lambda;  
  218.     if (x1[0] == x2) {  
  219.         lambda = mod_mul(3, mod_mul(x1[0], mod_mul(x1[0], mod_inv(2 * y1[0], P), P), P), P, P);  
  220.     } else {  
  221.         lambda = mod_mul(mod_sub(y2, y1[0], P), mod_inv(mod_sub(x2, x1[0], P), P), P);  
  222.     }  
  223.   
  224.     *result_x = mod_sub(mod_sub(mod_mul(lambda, lambda, P), x1[0], P), x2, P);  
  225.     *result_y = mod_sub(mod_sub(mod_mul(lambda, mod_sub(*result_x, x1[0], P), P), y1[0], P), mod_mul(lambda, mod_sub(x1[0], x2, P), P), P);  
  226. }  
  227.   
  228. // 椭圆曲线上的点倍运算  
  229. void point_double(unsigned char *x1, unsigned char *y1, unsigned char *result_x, unsigned char *result_y) {  
  230.     unsigned char lambda = mod_mul(3, mod_mul(x1[0], mod_mul(x1[0], mod_inv(2 * y1[0], P), P), P), P, P);  
  231.   
  232.     *result_x = mod_sub(mod_sub(mod_mul(lambda, lambda, P), 2 * x1[0], P), P, P); // 注意这里需要处理负值  
  233.     *result_y = mod_sub(mod_mul(lambda, mod_sub(*result_x, x1[0], P), P), mod_mul(2, y1[0], P), P);  
  234. }  
  235.   
  236. // 示例:计算基点G的k倍  
  237. void scalar_mult(unsigned char *Gx, unsigned char *Gy, unsigned char k, unsigned char *result_x, unsigned char *result_y) {  
  238.     unsigned char Rx = Gx[0];  
  239.     unsigned char Ry = Gy[0];  
  240.     for (unsigned char i = 1; i < k; i++) {  
  241.         unsigned char temp_x, temp_y;  
  242.         point_double(&Rx, &Ry, &temp_x, &temp_y);  
  243.         if (k & i) { // 如果k的第i位是1  
  244.             point_add(&Rx, &Ry, temp_x, temp_y, &Rx, &Ry);  
  245.         } else {  
  246.             Rx = temp_x;  
  247.             Ry = temp_y;  
  248.         }  
  249.     }  
  250.     *result_x = Rx;  
  251.     *result_y = Ry;  
  252. }  
  253.   
  254. // 好戏开场,main函数登场,所有的故事都是从这里开始的。
  255. int main(void)
  256. {
  257.     // 这里我们用wm_log_raw函数来报告当前可用的堆内存大小,就像在说:“看啊,我的背包还有这么多空间!”
  258.     wm_log_raw(WM_LOG_LEVEL_INFO, "heap free size=%d(bytes)\r\n", wm_heap_get_free_size());

  259.     // 接下来是wm_partition_table_print(),这一步像是打开了一个宝箱,里面装着所有内存分区的秘密。
  260.     wm_partition_table_print();

  261.   // 初始化参数,清空所有设置,就像音乐会开始前的准备阶段。
  262.     memset(param.ratio, PWM_INVALID_RATIO, sizeof(param.ratio));
  263.     memset(param.cfg, 0x0, sizeof(param.cfg));

  264.     if (argc < 2) { // 如果没有提供足够的参数,就像没有观众的音乐会,需要提示用户。
  265.         cmd_pwm_usage(argv[0]);
  266.         return;
  267.     }

  268.     param.pwm_name   = "pwm"; // 设定PWM的名称,就像给乐队起名。
  269.     param.pwm_device = NULL; // 初始时,PWM设备还没有被找到。

  270.     // 解析命令行参数,获取用户想要的效果。
  271.     if (WM_ERR_SUCCESS != cmd_pwm_parse_args(¶m, argc, argv)) {
  272.         return;
  273.     }

  274.   // 假设基点G的坐标为(Gx, Gy)  
  275.     unsigned char Gx = 3;  
  276.     unsigned char Gy = 10;  
  277.     unsigned char k = 5; // 私钥  
  278.     unsigned char result_x, result_y;  
  279.   
  280.     scalar_mult(&Gx, &Gy, k, &result_x, &result_y);  

  281.     // 尝试获取PWM设备,如果未初始化,则进行初始化。
  282.     param.pwm_device = wm_dt_get_device_by_name(param.pwm_name);
  283.     if (!PWM_INIT_CHECK()) {
  284.         param.pwm_device = wm_drv_pwm_init(param.pwm_name);
  285.         if (!PWM_INIT_CHECK()) { // 如果初始化失败,音乐会就无法开始了。
  286.             wm_cli_printf("err: pwm initialized fail!\r\n");
  287.             return;
  288.         }
  289.     }

  290.     // 最后,遍历所有通道,设置参数,开始演奏。
  291.     cmd_pwm_channel_foreach(¶m);


  292.     // 故事的结局总是那么简洁明了,main函数优雅地结束,告诉操作系统一切安好。
  293. }

  294. WM_CLI_CMD_DEFINE(pwm, cmd_pwm, pwm cmd, pwm<args...> --led control via pwm);
image.png
image.png

image.png
image.png

希望这些经验能对您有所帮助!
SiRiderS1芯擎工业开发板测评2.防止黑客入侵盗用操控劫持篡改摄像头&OpenSSL加密解密

SiRider S1芯擎工业开发板测评+1.防止黑客入侵通信监控系统(PSA)

   原创7.硬件加速Sora文生视频源代码

   灵动 Mini-F5333开发板+原创(4)AI源代码

【开源硬件小安派-Eyse-S1】+原创(5)手把手玩转AI源代码

【灵动 Mini-F5333开发板】+原创(3)连接上ChatGPT

【开源硬件小安派-Eyse-S1】+原创(4)手把手玩转三组四自由度机械臂

【灵动 Mini-F5333开发板】+(3)手把手带你玩转创意设计

【开源硬件小安派-Eyse-S1】+原创(3)手把手玩转复杂项目

【中移物联万耦天工】+手把手玩转GNSS定位

【双极微步电机评估版】+手把手玩转锁相电路待机功能

【灵动 Mini-F5333开发板】+(2)手把手带你玩转MindSwitch(MDS)可编程 IP互联模块

【开源硬件小安派-Eyse-S1】+(2)手把手玩转DAC

【灵动 Mini-F5333开发板】+手把手带你玩转 CORDIC 坐标旋转算法

(原创)防止黑客病毒入侵智能汽车远程开车锁车2【换道赛车:新能源汽车的中国道路 | 阅读体验】

《嵌入式Linux系统原理与应用》读后感第八章-设备驱动程序设计

(原创)防止AI大模型被黑客病毒入侵控制

(原创)7.硬件加速Sora文生视频源代码

  OpenHarmony编译顺序

谢谢!

还没吃饭中志愿者

2024年11月2日