QuaX_Chow

个性签名:

有无生境自得其功

  • 2024-09-23
  • 回复了主题帖: 罗姆有奖直播 | 高输出功率激光二极管—助力激光雷达性能提升

    已报名参加

  • 2024-08-27
  • 回复了主题帖: >>征集 | 使用 MCU,哪些问题最令你头大?

    下载和调试接口不够统一,就比如最近用到的DAP:项目开源、成本较低、速度较快,但就是不能给某些芯片下载程序。有的厂家喜欢jtag,有的喜欢串口,有的喜欢自己设计专用下载器。做不同的项目就要备不同的下载器,切换也不够方便

  • 2024-08-22
  • 回复了主题帖: 运放电源接反的影响?

    电源压降这么厉害就应该检查一下负载,上电后电源异常优先查找短路。没底的话上电时用热成像看一下

  • 2024-08-21
  • 发表了主题帖: 【51篇】(7-1)C51单片机实现按键控制的MAX517四种波形输出并显示

    本帖最后由 QuaX_Chow 于 2024-8-21 22:12 编辑 声明及本系列注意事项优先阅读:🔗 工程源码及仿真文件入口在文末,如果没显示就是还在审核   任务要求:使用C51实现四按键控制MAX517分别产生方波、三角波、锯齿波和正弦波,波形通过Proteus内的示波器显示,在P2.0~P2.3接四个按键开关,分别对应与四种波形;时钟信号由,一开始无按键按下时无输出   想要实现以上功能,我们需要将任务拆分为以下几个部分: MAX517通信 中断按键判断     1.Proteus部分   波形显示使用的是虚拟仪器模式中的“OSCILLOSCOPE”四通道示波器:     搭建好的仿真电路如下:     如果在仿真时不小心把波形显示窗口关掉了,只需在仿真状态下点击菜单栏里的“调试”-“Digital Oscilloscope”,即可显示示波器界面     2.代码部分   (1)MAX517通信   在我们驱动MAX517之前,我们首先需要理清这颗芯片的时序 驱动MAX517需要使用两线串行接口,兼容IIC 见下图:     一条时钟线,一条数据线。声明如下:   sbit SCL = P1^0;//MAX517串行时钟 sbit SDA = P1^1;//MAX517串行数据   开始状态标志为时钟线高、数据线下降沿。结束状态标志为时钟线高、数据线上升沿。 在编程时我们就需要根据芯片时序,使用GPIO进行模拟。 以SC为示例编写函数:   void start(void)//起始条件子程序 { SDA= 1; SCL = 1; _nop_(); SDA =0; _nop_(); }   完整的传输过程如下图:     控制MAX517模拟输出需要根据上图步骤编写一个有着完整的:启动-发送地址-应答-命令-应答-数据-应答-结束,流程的函数:   void DACOut (uchar ch)//串行D/A转换子程序 { start();//发送启动信号 send(0x58);//发送地址字节 ack(); send(0x00);//发送命令字节 ack(); send(ch);//发送数据字节 ack(); stop();//结束一次转换 }   如果我们需要输出一个指定的电压,就只需要 DACOut(需要的值);  公式如下:   但是我们需要输出的是波形,而非稳定的电平,所以我们需要一直改变输出模拟量的值ch。 以输出正弦波为例,创建数组存储ch的值,使用在输出时仅需将元素递增:   uchar sindata[64]= { 0x80,0x8c,0x98,0xa5,0xb0,0xbc,0xc7,0xd1, 0xda,0xe2,0xea,0xf0,0xf6,0xfa,0xfd,0xff, 0xff,0xff,0xfd,0xfa,0xf6,0xf0,0xea,0xe3, 0xda,0xd1,0xc7,0xbc,0xb1,0xa5,0x99,0x8c, 0x80,0x73,0x67,0x5b,0x4f,0x43,0x39,0x2e, 0x25,0x1d,0x15,0xf,0x9,0x5,0x2,0x0,0x0, 0x0,0x2,0x5,0x9,0xe,0x15,0x1c,0x25,0x2e, 0x38,0x43,0x4e,0x5a,0x66,0x73};   方波、锯齿、三角波的实现思路类似,循环内递增、递减、延时即可,具体方法参见文末源码   (2)中断按键判断   要实现立刻切换输出波形的功能,我们需要使用到外部中断0,中断服务函数如下:   void intp0() interrupt 0 { if(P2_0 == 0) key = 0;//三角波 if(P2_1 == 0) key = 1;//方波 if(P2_2 == 0) key = 2;//正弦 if(P2_3 == 0) key = 3;//锯齿波 }       四种波形输出效果如下:       任务完成     2024/8/21 源码以及仿真文件 #本文首发于EEWORLD,版权归作者所有 补充内容 (2024-8-27 14:28): 勘误:任务要求部分:“时钟信号由,一开始无按键按下时无输出”改为“一开始无按键按下时无输出”

  • 2024-08-20
  • 上传了资料: C51单片机实现按键控制的MAX517四种波形输出并显示

  • 发表了日志: 【51篇】(1-1)片内RAM两字节的拆与拼

  • 2024-08-05
  • 回复了主题帖: 【大学生电子竞赛题目分析】——2024年C题《无线传输信号模拟系统》

    测评老师是不知道题目的,他们只会按照测评表上的要求进行测评。测量条件没满足直接不测,该项目完全没分。并且本次电赛设计赛题及测评的人极为不专业,甚致认为信号时延仅需调整初相位即可,忽略t趋近于+0时多径信号SM(t)应该为0

  • 2024-07-03
  • 发表了主题帖: 【51篇】(1-0)使用Keil5和Proteus的系列实验

    本帖最后由 QuaX_Chow 于 2024-7-3 21:56 编辑   新的一轮学习周期结束,有感而发,总结一下上个阶段的学习成果与心得。 虽是故知新说,但不想让炒了4个月的冷饭白炒,故开帖此系列👆   链接目录: (1-0)本篇:系列说明 (1-1)片内RAM两字节的拆与拼 (1-2)片内RAM单字节十进制值的百十个位拆分 (2-1)片内RAM单字节十进制值的百十个位拆分并显示 (3-1)C51单片机利用定时器输出PWM (4-1)C51单片机串行口扩展并行口 (4-2)C51单片机使用串口交换双机指定并口状态并使用LED显示 (5-1)C51单片机实现双按键控制八位数码管滚动十六进制数 (5-2)C51单片机实现有紧急时间的红绿灯控制 (6-1)C51单片机实现LCD1602两行滚动非等长含自定义字符 (7-1)C51单片机实现按键控制的MAX517四种波形输出并显示 (7-2)C51单片机实现按键控制的ADC0808八路模拟量测量并显示 (待续     1.软件说明   所有仿真使用的Proteus版本均为8.17,低版本大概率不兼容   所有代码部分使用的Keil版本均为5.39,低版本有概率不兼容   2.代码说明   所有上传的代码均进行过仿真验证,未进行实物验证 本人水平有限,不可能代码最简化且部分仿真会有小瑕疵,欢迎讨论   初始几个实验会使用汇编,后面均为C   2024/7/3     补充内容 (2024-8-21 22:14): “按键控制的MAX517四种波形输出并显示”已更新: https://bbs.eeworld.com.cn/thread-1291106-1-1.html

  • 发表了主题帖: 【51篇】(5-1)C51单片机实现双按键控制八位数码管滚动十六进制数

    本帖最后由 QuaX_Chow 于 2024-7-3 15:58 编辑 2024/5/27 新建帖子   声明及本系列注意事项优先阅读:🔗 工程源码及仿真文件入口在文末   任务要求:使用C51实现双按键控制八位数码管滚动十六进制数,反向滚动间隔时间为正向的两倍,一开始无按键按下时不显示   想要实现以上功能,我们需要将任务拆分为以下几个部分: ms级定时器 数码管扫描函数 中断按键判断 延时函数(用于数码管余辉)   1.Proteus部分   数字显示使用的是Proteus中的八段共阴数码管,型号为:7SEG-MPX-8-CC-BLUE:   搭建好的仿真电路如下。红框为基础电路,外部中断0与按键之间使用与门且拉高:   2.代码部分   阳极连接的是P0口,需要在扫描函数中将每个十六位进制数对应的字段码 字段码如下: smg[16]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};   而阴极连接单片机对应的片选代码如下: unsigned char code yang[8]={0xFE, 0xFD, 0xFB, 0xF7, 0xEF, 0xDF, 0xBF, 0x7F};   声明uint类型的direct变量用于判断方向。在main函数中实现数码管扫描的仿真效果更好。 void main() { unsigned char i; unsigned int k; init(); Timer0Init(); direct = 2;//初始无滚动方向 while(1) { while(direct == 0) { flag = 0; while(direct == 0) { for(i=0;i<8;i++) { k = flag+i; if( flag+i >= 16) k -= 16; choose = yang[i]; show = smg[k]; delay(1); } } } while(direct == 1) { flag = 16; while(direct == 1) { for(i=0;i<8;i++) { k = flag+i; if( flag+i < 0) k += 16; if( flag+i >= 16) k -= 16; choose = yang[i]; show = smg[k]; delay(1); } } } } }   参考中断表编写中断服务函数,外部中断0的中断号为0,定时器0为1:   外部中断0的中断函数中对按键进行了判断,仿真电路无需消抖: void change() interrupt 0// using 0 { // do{ // key(); // }while(j == 1); //中断函数,当按键按下时中断 // if(P3_2 == 0) // { if(P1_6 == 0) direct = 0; if(P1_7 == 0) direct = 1; // } }     定时器提供数码管刷新基准(flag),每当基准达到15则清零,反向滚动计数值为正向的两倍: void intp1() interrupt 1 { jm++; if(direct == 0) { if(jm == 12) { TF0 = 0; flag++; if(flag==16) flag = 0; jm = 0; } } if(direct == 1) { if(jm == 24) { TF0 = 0; flag--; if(flag==0) flag = 16; jm = 0; } } }     最终效果如下:     任务完成       2024/7/3 源码以及仿真文件 #本文首发于EEWORLD,版权归作者所有    

  • 发表了日志: 【51篇】(1-0)使用Keil5和Proteus的系列实验

  • 2024-05-27
  • 上传了资料: C51单片机实现双按键控制八位数码管滚动十六进制数

  • 2024-03-30
  • 发表了主题帖: 【得捷Follow me第4期】(补充)网络控制STM32从机、实现简易频率计功能

    本帖最后由 QuaX_Chow 于 2024-3-30 21:21 编辑 2024.3.30 本篇是Follow Me第四期任务提交的补充内容   分两个部分:网络控制STM32从机、实现简易频率计功能   1.网络控制从机   电脑上由网络调试助手使用TCP向W5500-EVB-Pico发送指令,再由W5500-EVB-Pico通过串口,向从机发送我们在从机设定好的指令,这样从机即可进行对应操作   框架示意图如下:   经查阅手册,从机主控F407的USART3为PB10和PB11:     连接即可:     对应在W5500-EVB-PICO上如下所示:     这里我们需要使用stlink给从机下载代码。 最终实物连接图如下:     功能实现代码如下:   from usocket import socket from machine import Pin, SPI, UART import network import time # 初始化UART uart = UART(0, baudrate=115200, bits=8, stop=1) # 初始化WIZNET5K以太网模块 def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) # spi, cs, reset引脚 nic.active(True) nic.ifconfig(('192.168.137.100', '255.255.255.0', '192.168.137.1', '8.8.8.8')) print('IP地址:', nic.ifconfig()) while not nic.isconnected(): time.sleep(1) # 服务器循环 def server_loop(): s = socket() s.bind(('192.168.137.100', 5050)) s.listen(5) conn, addr = s.accept() print("已连接到:", conn, "地址:", addr) print("服务器已开启") while True: data = conn.recv(2048) print("发送: ", data.decode('utf-8'), " 给从机") if data != b'NULL': uart.write(data) # 客户端循环 def client_loop(): s = socket() s.connect(('192.168.137.114', 5050)) print("循环客户端已连接!") while True: data = s.recv(2048) print(data.decode('utf-8')) if data != b'NULL': s.send(data) def main(): w5x00_init() while True: server_loop() if __name__ == "__main__": main()   通过输入1~4四个数字,即可控制对应led的状态:     2.实现简易频率计功能   模块:MCU与AK5522使用IIS通信,AK5522读取到阈值高电平,模块串口打印一次“1” 这里需要开启双核,一个核用于定时,一个计数   框架示意图如下:     W5500-EVB-Pico通过串口👇直接读取AK5522模块发送的数据     模块的部分原理图如下:     功能实现代码如下: from usocket import socket from machine import Pin, UART import time import _thread # 初始化UART1和UART0 uart1 = UART(1, baudrate=115200, bits=8, stop=1) uart0 = UART(0, baudrate=115200, bits=8, stop=1) # 初始化计数器 count = 0 # Core 0的线程函数,用于接收数据并计算1的数量 def receive_and_count(): global count while True: if uart1.any(): data = uart1.read(64) # 读取UART1接收到的数据 count += data.count(b'1') time.sleep(1) # 每秒计算一次1的数量 # Core 1的线程函数,用于打印1的数量 def print_count(): while True: uart0.write('FRE: {}\n'.format(count)) time.sleep(1) # 每秒打印一次计数结果 # 启动Core 0的线程 _thread.start_new_thread(receive_and_count, ()) # 在Core 1上运行打印1的数量的代码 print_count()   ,用补充1的F407开发板输出1KHz的PWM,串口助手显示如下:     可以看见开发板十分准确地每秒打印了当前频率   功能实现   (完)

  • 2024-02-25
  • 上传了资料: 【得捷Follow me第4期】玩转W5500-EVB-Pico 资料包

  • 2024-02-23
  • 回复了主题帖: 【得捷电子Follow me第4期】终极任务一:DigiKey电子元器件价格及库存监视器(上)

    tql

  • 2024-02-22
  • 加入了学习《直播回放: FollowMe 4 W5500-EVB-Pico 使用入门》,观看 W5500-EVB-Pico 使用入门

  • 2024-02-20
  • 发表了主题帖: 【得捷Follow me第4期】玩转W5500-EVB-Pico (全流程综合贴)

    2024.2.20(存个草稿先) 2024.2.21 这次给大家带来的是Follow Me第四期任务的速通教学(又鸽了很久 本次活动时间比较紧,加上放假在家也没啥动力,发帖比较晚 感谢主办方eeworld、得捷电子的支持,感谢各位提前发帖的大神坛友 于得捷下单的元件所制作的模块后续均会开源 内容一:3-5分钟短视频 内容二:本篇 内容三:本次活动的资料包(包含任务代码、官方资料、还有一些乱七八糟的东西) 附加:b站视频链接(同内容一,改完Type-C后上传)     1、Quick Start 开发环境搭建   首先我们快速搭建一下我们所需的开发环境,本次活动在Thonny中使用MicroPython编程。 (1)IDE安装 打开Thonny官网,把鼠标挪到右上角“download version...”上,再点击推荐给你的版本,就可以下载了     下载完成后打开安装包,一路“NEXT”下去就行,几十MB对C盘非常友好     安装完成后双击快捷方式打开Thonny 打开后界面如下:     (2)硬件简介与刷固件 本次活动使用到的是Wiznet的W5500-EVB-Pico,ad格式的原理图和pcb都是可以下载到的,资料已经放在了压缩包中 W5500-EVB-Pico板载了一块w5500通过spi与RP2040通信,支持python、c等语言。 整体还是非常精致的哈       当然,我们想要用micropython进行编程的话还需要将对应的固件刷到芯片内,固件同样已经打包进了资料包,或者从官网下载也是行的:地址 尽量还是选择较新的固件     固件下载完成后即可准备刷写mp的固件了,找一根micro usb-usb A的线,将micro usb一端连接开发板,按住BOOT键👇     再将usb A连接至电脑,即会弹出一个u盘,松开BOOT,将下载好的.uf2文件(即我们的固件)复制进u盘,粘贴完成后最好再按一下run键,固件就安装完成了 树莓派官网也有十分易懂的烧写过程演示,这里分享一下:     最后,如果我们在Thonny中可以在右下角的上拉菜单中找到“Micropython...Pi PICO ...COM...”,点击并且shell窗口无警告,说明成功刷写固件,我们就可以正常使用了   2、入门任务 BLINK,串口HelloWorld(附加呼吸灯)   (1)点个灯先 合乎嵌礼,点灯 python点灯的代码很简单,网上也一堆例程,随便写写 blink.py内容如下:   import machine import time #设置引脚 led_pin = machine.Pin(25, machine.Pin.OUT) while True: led_pin.value(1) # 点亮LED time.sleep(0.5) # 等待0.5秒 led_pin.value(0) # 熄灭LED time.sleep(0.5) # 等待0.5秒   实际效果如下: [localvideo]fa63556509e325e64f557e975c0dceed[/localvideo]   修改一下代码,调用PWM函数,即可实现呼吸灯效果   import machine import time #设置引脚 led_pin = machine.Pin(25, machine.Pin.OUT) def breathe_led(): pwm = machine.PWM(led_pin) while True: for duty_cycle in range(0, 5000, 100): #变亮 pwm.duty_u16(duty_cycle) time.sleep_ms(10) for duty_cycle in range(5000, 0, -100): #变暗 pwm.duty_u16(duty_cycle) time.sleep_ms(10) breathe_led()   实际效果如下: [localvideo]3010d9dc1cb982ae0eb62de6a8e95248[/localvideo]   使用python点灯流程十分简单,非常适合新手上手   (2)串口helloworld 这里就需要用到usb转串口的模块了,市面上常见的当然是沁恒的340x系列。 放假的时候手边只有一个DAP,有虚拟串口功能,直接拿来用     我们需要用到的是DAP的TX、RX、和GND(丝印三角):     与DAP相连的是PICO的UART0和GND,共地十分重要,后续SD卡模块和电机模块都是与PICO共地的     硬件连接:   DAP和PICO的连接参考以下表格。DAP需要使用Type-C转USB数据线与电脑连接    DAP    PICO    PIN     TX       RX        1     RX       TX        0   GND     GND 使用一根跳线连接PICO至电脑网口   连好的实物图:     代码也很简单,实现串口打印Helloworld的代码如下:   from machine import Pin,SPI,UART import time # UART0初始化 uart = UART(0, baudrate=115200, bits=8, stop=1) while True: # 打印"Hello World"到串口 uart.write("Hello World\r\n") # 等待 time.sleep(1)   查看串口打印内容需安装好串口助手,还需要打好对应驱动,网上教程很多这里就不详细说明了 使用串口助手查看我们接收到的消息,可以看到PICO正在反复发送Helloworld     任务完成!   3、基础任务一 完成主控板W5500初始化(静态IP配置),并能使用局域网电脑ping通,同时W5500可以ping通互联网站点;通过抓包软件(Wireshark、Sniffer等)抓取本地PC的ping报文,展示并分析。   (1)首先我们尝试ping通开发板。 参考wiznet在github上的官方测试代码,在Thonny中粘贴以下代码,开发板的IP和网关需要自己修改,直接CV一般是没法用的   from machine import Pin, SPI import network import time led = Pin(25, Pin.OUT) # 初始化 W5x00 芯片 def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) # 通过 SPI 连接 W5x00 芯片,设置 CS 和 RESET 引脚 nic.active(True) # 激活 W5x00 芯片 nic.ifconfig(('开发板IP', '255.255.0.0', '网关', '8.8.8.8')) # 设置网络配置信息 while not nic.isconnected(): # 等待网络连接建立 time.sleep(1) print(nic.regs()) # 打印寄存器信息 print(nic.ifconfig()) # 打印网络配置信息 def main(): w5x00_init() # 初始化 W5x00 芯片 while True: led.value(1) # 点亮 LED 灯 time.sleep(1) led.value(0) # 关闭 LED 灯 time.sleep(1) if __name__ == "__main__": main()   确保电脑ip地址和开发板ip地址在同一网关下,不然无法ping通,会像这样👇     设置正确后再次尝试,功能实现     设置开发板IP时可以先ipconfig,查看 “以太网适配器 以太网” 所显示IP   接着我们尝试ping通互联网站点 ping通互联网站点需要添加外部库:uping.py 可以直接新建一个uping.py并保存到开发板,其源代码如下,以下代码粘贴后可能会出现缩进问题,建议去原网页复制RAW代码   # μPing (MicroPing) for MicroPython # copyright (c) 2018 Shawwwn <shawwwn1@gmail.com> # License: MIT # Internet Checksum Algorithm # Author: Olav Morken # https://github.com/olavmrk/python-ping/blob/master/ping.py # @data: bytes def checksum(data): if len(data) & 0x1: # Odd number of bytes data += b'\0' cs = 0 for pos in range(0, len(data), 2): b1 = data[pos] b2 = data[pos + 1] cs += (b1 << 8) + b2 while cs >= 0x10000: cs = (cs & 0xffff) + (cs >> 16) cs = ~cs & 0xffff return cs def ping(host, count=4, timeout=5000, interval=10, quiet=False, size=64): import utime import uselect import uctypes import usocket import ustruct import urandom # prepare packet assert size >= 16, "pkt size too small" pkt = b'Q'*size pkt_desc = { "type": uctypes.UINT8 | 0, "code": uctypes.UINT8 | 1, "checksum": uctypes.UINT16 | 2, "id": uctypes.UINT16 | 4, "seq": uctypes.INT16 | 6, "timestamp": uctypes.UINT64 | 8, } # packet header descriptor h = uctypes.struct(uctypes.addressof(pkt), pkt_desc, uctypes.BIG_ENDIAN) h.type = 8 # ICMP_ECHO_REQUEST h.code = 0 h.checksum = 0 h.id = urandom.getrandbits(16) h.seq = 1 # init socket sock = usocket.socket(usocket.AF_INET, usocket.SOCK_RAW, 1) sock.setblocking(0) sock.settimeout(timeout/1000) addr = usocket.getaddrinfo(host, 1)[0][-1][0] # ip address sock.connect((addr, 1)) not quiet and print("PING %s (%s): %u data bytes" % (host, addr, len(pkt))) seqs = list(range(1, count+1)) # [1,2,...,count] c = 1 t = 0 n_trans = 0 n_recv = 0 finish = False while t < timeout: if t==interval and c<=count: # send packet h.checksum = 0 h.seq = c h.timestamp = utime.ticks_us() h.checksum = checksum(pkt) if sock.send(pkt) == size: n_trans += 1 t = 0 # reset timeout else: seqs.remove(c) c += 1 # recv packet while 1: socks, _, _ = uselect.select([sock], [], [], 0) if socks: resp = socks[0].recv(4096) resp_mv = memoryview(resp) h2 = uctypes.struct(uctypes.addressof(resp_mv[20:]), pkt_desc, uctypes.BIG_ENDIAN) # TODO: validate checksum (optional) seq = h2.seq if h2.type==0 and h2.id==h.id and (seq in seqs): # 0: ICMP_ECHO_REPLY t_elasped = (utime.ticks_us()-h2.timestamp) / 1000 ttl = ustruct.unpack('!B', resp_mv[8:9])[0] # time-to-live n_recv += 1 not quiet and print("%u bytes from %s: icmp_seq=%u, ttl=%u, time=%f ms" % (len(resp), addr, seq, ttl, t_elasped)) seqs.remove(seq) if len(seqs) == 0: finish = True break else: break if finish: break utime.sleep_ms(1) t += 1 # close sock.close() ret = (n_trans, n_recv) not quiet and print("%u packets transmitted, %u packets received" % (n_trans, n_recv)) return (n_trans, n_recv)   功能实现代码如下:   import time import uping from machine import Pin, SPI import network # 初始化串口 uart = machine.UART(0, baudrate=9600) # 初始化LED引脚 led = Pin(25, Pin.OUT) # 初始化W5500芯片 def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) # 初始化网络接口,设置SPI总线、CS引脚、复位引脚 nic.active(True) # 激活网络接口 nic.ifconfig(('192.168.137.100','255.255.255.0','192.168.137.1','8.8.8.8')) # 设置IP地址等网络配置信息 while not nic.isconnected(): # 等待网络连接成功 time.sleep(1) print(nic.regs()) # 打印芯片寄存器状态 print(nic.ifconfig()) # 打印配置信息 def main(): w5x00_init() # 初始化W5x00芯片 uping.ping('www.jd.com') # 发起ping请求 while True: led.value(1) # 点亮LED time.sleep(1) led.value(0) # 熄灭LED time.sleep(1) uart.write('PING JD Success!\n') # 通过串口发送消息 if __name__ == "__main__": main()   在shell窗口可以看到ping代码已经实现预期功能(不知道为啥显示收到的包只有一个。猜测是应答时间过快还没开始计数)     在循环中我添加了串口打印ping通成功的标志,当然看板上led也可以     (2)接下来我们通过抓包软件Wireshark(👇)抓取本地PC的ping报文,展示并分析。     安装完wireshark后打开,单击靠左上方的start键即可开始捕获。     等待ping通结束,再点击start左侧的end结束捕获,有需要的话可以将捕获的分组保存一下方便之后查看 在搜索框中输入ip.addr==你的开发板IP,即可查看ping报文。 可以看到,我们生成了8个报文(4个请求报文和4个应答报文)     我们只分析第一个请求报文,报文如下:     报文的整体描述是这样的:     我们可以读出一些基本消息,如该请求报文共98字节,世界标准送达时间等等 当然这只是以太网报文的一部分,不可能将以太网以帧格式表达出来   前1-6字节和7-12字节分别为目的地址和源地址 地址的第一字节的最后两个bit位: IG位为0表示这是一个单播MAC地址 LG位为0表示这是一个厂家出厂默认的MAC地址,为1表示是用户设置的 再后两字节0x0800表示报文为IPV4格式👇       后20字节为ip报文,按字节解释一下: 1.第一个字节: Bit 0-3: 版本号(Version)- 4位,表示IP协议的版本,通常为4 Bit 4-7: 首部长度(IHL)- 4位,表示IP首部的长度,以4字节为单位 2. 第二个字节: Bit 0-7: 服务类型(Type of Service)- 8位,用于标识数据包的服务质量要求 3. 第三、四字节: Bit 0-15: 总长度(Total Length)- 16位,表示整个IP数据包的长度,包括首部和数据部分 4. 第五、六字节: Bit 0-15: 标识(Identification)- 16位,用于标识数据包的唯一性 5. 第七、八字节: Bit 0-2: 标志位(Flags)- 3位,用于控制分片 Bit 3-15: 片偏移(Fragment Offset)- 13位,表示数据包在原始数据流中的偏移量 6. 第九、十字节: Bit 0-7: 生存时间(Time to Live)- 8位,表示数据包在网络中可传递的最大跳数 7. 第十一个字节: Bit 0-7: 协议(Protocol)- 8位,表示数据包上层协议的类型,如TCP、UDP等 8. 第十二字节: Bit 0-15: 首部校验和(Header Checksum)- 16位,用于校验IP首部的完整性 9. 第十三至十六字节: Bit 0-31: 源IP地址(Source IP Address)- 32位,表示数据包的源IP地址。即192.158.137.100 10. 第十七至二十字节: Bit 0-31: 目的IP地址(Destination IP Address)- 32位,表示数据包的目的IP地址。即36.152.105.3     参考以下表格 :     再接下来就是ICMP(Internet Control Message Protocol)了,按字节进行解释:  1. 第一个字节(8 bits):类型(Type) 表示ICMP消息的类型,指示报文的目的和功能。常见的类型包括: 0x00:回显应答(Echo Reply) 0x03:目的地不可达(Destination Unreachable) 0x08:回显请求(Echo Request)👈 其他类型表明不同的ICMP消息功能。 2. 第二个字节(8 bits):代码(Code) 和类型字段一起指定特定类型的具体细分。 类型TYPE 代码CODE 用途|描述 Description 查询类Query 差错类Error 0 0 Echo Reply——回显应答(Ping应答)👈 x   3 0 Network Unreachable——网络不可达   x 3 1 Host Unreachable——主机不可达   x 3 2 Protocol Unreachable——协议不可达   x 3 3 Port Unreachable——端口不可达   x 3 4 Fragmentation needed but no frag. bit set——需要进行分片但设置不分片比特   x 3 5 Source routing failed——源站选路失败   x 3 6 Destination network unknown——目的网络未知   x 3 7 Destination host unknown——目的主机未知   x 3 8 Source host isolated (obsolete)——源主机被隔离(作废不用)   x 3 9 Destination network administratively prohibited——目的网络被强制禁止   x 3 10 Destination host administratively prohibited——目的主机被强制禁止   x 3 11 Network unreachable for TOS——由于服务类型TOS,网络不可达   x 3 12 Host unreachable for TOS——由于服务类型TOS,主机不可达   x 3 13 Communication administratively prohibited by filtering——由于过滤,通信被强制禁止   x 3 14 Host precedence violation——主机越权   x 3 15 Precedence cutoff in effect——优先中止生效   x 4 0 Source quench——源端被关闭(基本流控制)     5 0 Redirect for network——对网络重定向     5 1 Redirect for host——对主机重定向     5 2 Redirect for TOS and network——对服务类型和网络重定向     5 3 Redirect for TOS and host——对服务类型和主机重定向     8 0 Echo request——回显请求(Ping请求) x   9 0 Router advertisement——路由器通告     10 0 Route solicitation——路由器请求     11 0 TTL equals 0 during transit——传输期间生存时间为0   x 11 1 TTL equals 0 during reassembly——在数据报组装期间生存时间为0   x 12 0 IP header bad (catchall error)——坏的IP首部(包括各种差错)   x 12 1 Required options missing——缺少必需的选项   x 13 0 Timestamp request (obsolete)——时间戳请求(作废不用) x   14   Timestamp reply (obsolete)——时间戳应答(作废不用) x   15 0 Information request (obsolete)——信息请求(作废不用) x   16 0 Information reply (obsolete)——信息应答(作废不用) x   17 0 Address mask request——地址掩码请求 x   18 0 Address mask reply——地址掩码应答 3. 第三和第四字节(16 bits):校验和(Checksum) 检验整个ICMP数据报的完整性,以确保数据在传输过程中没有出现错误。(无) 4. 后面还有四字节的标识码和序列码,参考以下描述即可解读: Identifier (BE): 27820 (0x6cac) 👈 Identifier (LE): 44140 (0xac6c) Sequence Number (BE): 1 (0x0001) 👈 Sequence Number (LE): 256 (0x0100) 5. 后续字段为数据字段(Data fields),具体内容取决于ICMP消息类型,共56字节,具体内容可以看下图     任务完成   4、基础任务二 主控板建立TCPIP,局域网PC使用TCPIP或UDP客户端进行连接并发送数据,主控板接收到数据后,通过串口打印显示;通过抓包软件抓取交互报文,展示并分析。(TCP和UDP二选一,或者全都操作)   TCP(传输控制协议)是一种面向连接的协议,提供可靠的数据传输和错误检测机制。   我们这次通过W5500芯片创建一个TCP服务器,可以接收客户端的连接并处理数据。参考代码链接:loopback   PICO代码如下: from usocket import socket from machine import Pin, SPI, UART import network import time uart = UART(0, baudrate=115200, bits=8, stop=1) # W5x00 chip initialization def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) # spi, cs, reset pin nic.active(True) # Static IP configuration nic.ifconfig(('192.168.137.100', '255.255.255.0', '192.168.137.1', '8.8.8.8')) # DHCP configuration # nic.ifconfig('dhcp') print('IP address:', nic.ifconfig()) while not nic.isconnected(): time.sleep(1) def server_loop(): s = socket() s.bind(('192.168.137.100', 5050)) # Source IP Address s.listen(5) print("TEST server") conn, addr = s.accept() print("Connected to:", conn, "address:", addr) print("Loopback server Open!") while True: data = conn.recv(2048) print(data.decode('utf-8')) if data != b'NULL': # Use byte literal for comparison uart.write(data) # Serial print conn.send(data) def client_loop(): s = socket() s.connect(('192.168.137.114', 5050)) # Destination IP Address print("Loopback client Connect!") while True: data = s.recv(2048) print(data.decode('utf-8')) if data != b'NULL': # Use byte literal for comparison s.send(data) def main(): w5x00_init() ### TCP SERVER ### while True: server_loop() ### TCP CLIENT ### # client_loop() if __name__ == "__main__": main()    下载好netassist(无需安装,解压即用)并打开,远程主机地址和远程主机端口需要和代码一致:     扩展选项默认不变直接确认:     运行程序,网络助手发送消息 成功👇     报文分析: 报文获取方式同上一任务 在搜索框中输入ip.addr==你的开发板IP,即可查看TCP报文。 可以看到,我们生成了9个报文。共3组,因为是互发3次报文,每组的第3次用于确认     只挑一个,报文描述如下 在数据字段(Data fields)中我们可以找到发送的内容(右下角):welcome to netassist     (TCP好图分享,来源:文末参考4)       5、进阶任务 从NTP服务器(注意数据交互格式的解析)同步时间,获取时间送串口显示。   ntp直接使用mp的特定库即可 基本思路:初始化W5500,连接到网络并手动设置IP地址、子网掩码、网关和DNS服务器地址。然后通过NTP服务器同步系统时间,最后不断地显示本地时间。 功能实现代码如下:   from usocket import socket from machine import Pin, SPI, UART, RTC import network import time import ntptime uart = machine.UART(0, baudrate=9600) #W5x00芯片初始化 def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) # 使用SPI总线,设置CS和RESET引脚 nic.active(True) #手动设置IP地址,子网掩码,网关和DNS服务器地址 nic.ifconfig(('192.168.xxx.xxx', '255.255.255.0', '192.168.xxx.xxx', '8.8.8.8')) print('IP address:', nic.ifconfig()) while not nic.isconnected(): time.sleep(1) #print(nic.regs()) # 可以打印芯片的寄存器状态进行调试 def show_local_time(timezone=8): rtc = RTC() now = time.time() now += timezone * 3600 t = time.localtime(now) print(f'{t[0]} - {t[1]:02d}-{t[2]:02d} {t[3]:02d}:{t[4]:02d}:{t[5]:02d}') uart.write(f'{t[0]} - {t[1]:02d}-{t[2]:02d} {t[3]:02d}:{t[4]:02d}:{t[5]:02d}\n') def main(): w5x00_init() #手动设置一个错误的系统时间 rtc = RTC() rtc.datetime((2021,1,1,1,1,1,1,1)) # 年、月、日、星期、时、分、秒、亚秒 print('校时前系统时间:') show_local_time() #使用NTP服务器校准时间 print('开始NTP校时...') ntptime.host = 'ntp1.aliyun.com' ntptime.settime() print('校时后系统时间:') show_local_time() while True: show_local_time() time.sleep(1) if __name__ == "__main__": main()   运行,即可看见串口每隔一秒打印当前时间     在实现这个功能时经常会出现报错,大概率是服务器访问量过大造成的。 解决方法有两个,一个是反复run,多试试总会好的,二是更换ntp服务器,并且尽量选国内的   6、终极任务二 使用外部存储器,组建简易FTP文件服务器,并能正常上传下载文件   既然要使用外部存储器,肯定需要我们自备存储模块和杜邦线,经过简易连接之后再进行操作,于是我掏出了之前在得捷下单的tf卡模块:     电路连接实物图与引脚说明如下图:     tf卡模块使用DAP的3V3供电,三个板均共地     想要在micropython下驱动sd卡,我们还需要添加一个额外的库sdcard.py,复制RAW代码,粘贴进Thonny后并保存至我们的开发板上。 通过W5500芯片进行网络通信和SD卡存储文件管理,初始化SD卡和网络设置,以及FTP服务器的功能实现,接收FTP客户端的命令并进行对应的文件管理操作。 FTP服务器通过指定端口进行数据传输,实现列出目录、发送文件、保存文件等。   功能实现代码如下:   from usocket import socket from machine import Pin, SPI import network import time import socket import uos import gc import sdcard from time import localtime # 初始化SD卡 spi = SPI(1, sck=Pin(10), mosi=Pin(11), miso=Pin(12)) cs = Pin(13) sd = sdcard.SDCard(spi, cs) uos.mount(sd, "/sd") # 挂载SD卡 print(uos.listdir('/sd')) # 列出SD卡中的文件 # 初始化网络 spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) nic.active(True) nic.ifconfig(('192.168.137.100', '255.255.255.0', '192.168.137.1', '8.8.8.8')) print('IP address:', nic.ifconfig()) while not nic.isconnected(): time.sleep(1) # 初始化W5x00芯片 def w5x00_init(): spi = SPI(0, 2_000_000, mosi=Pin(19), miso=Pin(16), sck=Pin(18)) nic = network.WIZNET5K(spi, Pin(17), Pin(20)) nic.active(True) nic.ifconfig(('192.168.137.100', '255.255.255.0', '192.168.137.1', '8.8.8.8')) print('IP address:', nic.ifconfig()) while not nic.isconnected(): time.sleep(1) return nic month_name = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"] # 发送目录列表数据 def send_list_data(path, dataclient, full): try: for fname in uos.listdir(path): dataclient.sendall(make_description(path, fname, full)) except: pattern = path.split("/")[-1] path = path[:-(len(pattern) + 1)] if path == "": path = "/" for fname in uos.listdir(path): if fncmp(fname, pattern): dataclient.sendall(make_description(path, fname, full)) # 生成文件描述 def make_description(path, fname, full): # 实现文件描述的生成 # ... # 发送文件数据 def send_file_data(path, dataclient): # 发送文件数据 # ... # 保存文件数据 def save_file_data(path, dataclient, mode): # 保存文件数据 # ... # 获取绝对路径 def get_absolute_path(cwd, payload): # 获取绝对路径 # ... # 比较文件名和模式 def fncmp(fname, pattern): # 比较文件名和模式 # ... # FTP服务器函数 def ftpserver(): DATA_PORT = 13333 ftpsocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) datasocket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 设置套接字选项 ftpsocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) datasocket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) # 绑定FTP套接字和数据套接字 ftpsocket.bind(socket.getaddrinfo("0.0.0.0", 21)[0][4]) datasocket.bind(socket.getaddrinfo("0.0.0.0", DATA_PORT)[0][4]) ftpsocket.listen(1) datasocket.listen(1) datasocket.settimeout(10) msg_250_OK = '250 OK\r\n' msg_550_fail = '550 Failed\r\n' try: dataclient = None fromname = None while True: cl, remote_addr = ftpsocket.accept() cl.settimeout(300) cwd = '/' try: cl.sendall("220 Hello, this is the RP2020.\r\n") while True: gc.collect() data = cl.readline().decode("utf-8").rstrip("\r\n") if len(data) <= 0: print("Client disappeared") break command = data.split(" ")[0].upper() payload = data[len(command):].lstrip() path = get_absolute_path(cwd, payload) # 处理FTP命令 # ... except Exception as err: print(err) finally: cl.close() cl = None finally: datasocket.close() ftpsocket.close() if dataclient is not None: dataclient.close() # 主函数 def main(): ftpserver() if __name__ == "__main__": main()   打开文件资源管理器,搜索框输入:ftp://你的开发板id即可访问,整个PICO板上的代码都是可以随意复制和下载的      文件夹也可打开     任务完成   7、额外模块(电机控制) 因为在订购板子时额外购买了其他元件,应要求,额外实现TB6642模块对直流减速电机的控制     模块底板已开源:项目地址 其实我这次用的电机是带编码器的,时间关系只做简单控制,不涉及编码器   原理很简单: 单路PWM调占空比控制电机转速,两路io控制电机正反转和刹车   简单写一下就是这样的:   import machine import utime # 设置8号脚为输出引脚,设置高电平 pin8 = machine.Pin(8, machine.Pin.OUT) pin8.value(1) # 设置9号脚为输出引脚,设置低电平 pin9 = machine.Pin(9, machine.Pin.OUT) pin9.value(0) # 设置7号脚为PWM输出 pwm = machine.PWM(machine.Pin(7)) while True: pwm.freq(1000) #设置PWM频率为1kHz pwm.duty_u16(32768) #50%占空比对应的duty cycle值为32768 utime.sleep(5) pwm.freq(500) #设置PWM频率为500Hz pwm.duty_u16(16384) #25%占空比 utime.sleep(5)   最终效果请看视频: [localvideo]4a3f7f2409bab3b98cd0dcdc8689bce7[/localvideo]   8、小节   在整个实践过程中我也遇到了不少困难和bug 其中最让我印象深刻的是一个让PICO跑飞的代码 报错如下 STDERR: Traceback (most recent call last):   File "<stdin>", line 1, in <module>   File "<stdin>", line 4, in __thonny_helper KeyboardInterrupt:    反复reset、重刷mp的固件都没用。 刷了官方的blink固件,再刷mp固件才好过来 网上找了一圈甚至没找到一样的报错 (Python粘贴错误优先查看:网址)   我觉得本次活动对我来说十分有意义,因为开发板又+1因为又新接触了一种语法,并且又增加了自己的ddl   (不是很习惯这块板子的micro口,以后有机会画一板type-c)   如有错误希望指正(   参考资料:1                  2                  3                  4 (完)2024/2/25  

  • 2024-02-13
  • 加入了学习《【得捷电子Follow me第4期】使用micropython完成全部任务》,观看 【得捷电子Follow me第4期】使用micropython完成全部任务

  • 2023-11-22
  • 回复了主题帖: 任务审核通过名单&返现通知|得捷电子 Follow me 第2期活动第一批(正常收货者)

    第三期申请了没通过

最近访客

< 1/2 >

统计信息

已有17人来访过

  • 芯积分:535
  • 好友:--
  • 主题:7
  • 回复:8

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言