QuaX_Chow

个性签名:

有无生境自得其功

  • 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    

  • 发表了主题帖: 【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期活动第一批(正常收货者)

    第三期申请了没通过

  • 2023-11-07
  • 点评了资料: c++ prime plus 第六版中文版

  • 2023-10-14
  • 上传了资料: 【得捷电子Follow me第2期】玩转Adafruit ESP32-S3 TFT Feather 新资料包

  • 发表了主题帖: 【得捷电子Follow me第2期】玩转Adafruit ESP32-S3 TFT Feather (全流程综合贴)

    本帖最后由 QuaX_Chow 于 2023-10-14 16:18 编辑 2023.8.19(开始动工,存个草稿先) 2023.10.6 这次给大家带来的是Follow Me第二期任务的速通教学(鸽了很久 本次活动基本查阅查阅手册就可以通过 感谢主办方eeworld、得捷电子的支持,感谢各位提前发帖的大神坛友 内容一:3-5分钟短视频 内容二:本篇 内容三:本人整理的资料包(包含示例代码、任务代码、官方资料、部分外部库,打不开就是还没审核,可以先用老的资料包)   1、Quick Start 首先我们快速搭建一下我们所需的开发环境,本次使用的是官方推荐的Mu Editor编写CircuitPython。 使用数据线将开发板与电脑相连,并连按两次reset键(如下所示) 当Neo灯绿灯常亮,红色LED呼吸灯闪烁时,电脑就会显示连接到了一个新磁盘。将资料包-other中的adafruit-circuitpython-adafruit_feather_esp32s3_tft-en_US-8.2.3.uf2拖入新磁盘的根目录即可为开发板快速添加circuitpython支持包。 或者直接去官网下载,下载链接:circuitpy包 待文件移动完成后开发板屏幕上即会显示开发板信息和uid(如下图)同时出现一个新u盘 PS:circuitpython其实还有个中文包,但在屏幕上显示的是拼音。。(adafruit-circuitpython-adafruit_feather_esp32s3_tft-zh_Latn_pinyin-8.2.3.uf2如下所示) 再在电脑上安装好Mu Editor(下载地址),当然如thonny啥的也是可以的。   我们想要编辑代码的话,直接打开根目录(如下所示)下的code.py并编辑即可   首先我们先刷两个测试程序,程序都可以在手册或者对应库的示例代码里找到 第一个是可以直接使用的点灯程序,直接cv进code.py即可。 下载成功即可看见板载LED闪烁。 import board import digitalio import time led = digitalio.DigitalInOut(board.LED) led.direction = digitalio.Direction.OUTPUT while True: led.value = True time.sleep(0.5) led.value = False time.sleep(0.5) 测试代码① [localvideo]ba7b0fc12f974d27bb46217792c6c5cc[/localvideo]   第二个是图片显示代码,添加资料包中other-lib中的imageload库即可实现。 import board import displayio import adafruit_imageload image, palette = adafruit_imageload.load( "images/ysqd.bmp", bitmap=displayio.Bitmap, palette=displayio.Palette ) tile_grid = displayio.TileGrid(image, pixel_shader=palette) group = displayio.Group() group.append(tile_grid) #显示 board.DISPLAY.show(group) # while True: pass 测试代码② 添加外部库的方法:打开外部库的压缩包,将对应文件夹复制进开发板u盘根目录下的lib文件夹即可(如imageload库)     本代码需在根目录下创建image文件夹,并在该文件夹下粘贴下面这张已转格式的图片↓ 测试图片 [localvideo]592c1c6f2e1052a365979a234290f9c1[/localvideo]   2、任务1:控制屏幕显示中文(必做任务) 我们想要控制屏幕显示中文的话,需要使用bitmap库将点阵字体加载到displayio中,可以使用bdf、pcf等格式,非常简单   import board import displayio from adafruit_display_text import label, wrap_text_to_lines from adafruit_bitmap_font import bitmap_font # 设置要显示的字符串 dis_str = "完成屏幕的控制并且能显示中文" def screen_dispstr(str): # 根据屏幕旋转角度确定每行显示的字符数 if board.DISPLAY.rotation % 180 == 0: char_num = 23 # 横屏 else: char_num = 13 # 竖屏 strbuf = "" for i in range(len(str) / char_num): # 将字符串按每行字符数拆分,并添加换行符 strbuf = strbuf + str[i * char_num:(i + 1) * char_num] + "\n" return strbuf # 初始化显示屏 display = board.DISPLAY board.DISPLAY.brightness = 0.35 board.DISPLAY.rotation = 0 # 加载字体和设置颜色 font = bitmap_font.load_font("wenquanyi_10pt.pcf") color = 0x00FFFF # 创建显示文本的组和标签 text_group = displayio.Group() text_area = label.Label(font, text=screen_dispstr(dis_str), color=color) text_area.x = 2 text_area.y = 6 text_area.line_spacing = 0.8 text_area.scale = 1 text_group.append(text_area) display.show(text_group) # 持续显示 while True: pass     初始化显示屏模块,并设置亮度和旋转角度 加载所需的字体文件 创建显示文本的组和标签对象,并设置文本内容、颜色、位置和缩放 将文本标签对象添加到显示文本的组中 使用display.show将显示文本的组添加到显示屏上进行显示 进入持续显示的循环,保持文本显示在屏幕上     [localvideo]052190d984f2c9797f8de3e3d875010e[/localvideo]       3、任务2:网络功能使用(必做任务) 首先我们为开发板配置一下网络功能所需的信息。 在根目录下新建一个文本文档,命名为settings,保存后将后缀改为.toml(结果如下图)。 想要编辑的话以文本格式打开直接编辑或者有VS Code的话也可以直接编辑。   想实现Adafruit ESP32-S3 TFT Feather的网络功能也十分简单,参考手册P143(如下图所示)就行,但与手册方法不同的是,我们的配置信息存在了settings.toml文件中。 手册P143截图 我们先连接WiFi 在settings.toml中,配置你想要连接的WiFi的ID和密码。 PS:只支持2.4G频段,手机开个热点就行 具体如下: WIFI_SSID = "HOMO" WIFI_PASSWORD = "1145141919810" 配置完成后,直接在code.py中使用示例代码即可 # SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT import os import wifi print("ESP32-S3 Station Test") print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}") print("Available WiFi networks:") for network in wifi.radio.start_scanning_networks(): print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"), network.rssi, network.channel)) wifi.radio.stop_scanning_networks() print(f"Connecting to {os.getenv('WIFI_SSID')}") wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD")) print(f"Connected to {os.getenv('WIFI_SSID')}") print(f"My IP address: {wifi.radio.ipv4_address}") 连接WiFi   [localvideo]40f220f6ef3cb8015f12689d1bf52c2c[/localvideo]     再创建热点 在settings.toml中,配置开发板AP的ID和密码。 具体如下: AP_SSID = "HOMO" AP_PASSWORD = "1145141919810" 以下代码基于自带的库   #创建热点 import os import wifi import adafruit_requests print("ESP32-S3 Access Point Test") print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}") wifi.radio.start_ap(os.getenv("AP_SSID"), os.getenv("AP_PASSWORD")) #显示网络信息 print(f"My SSID: {"HOMO"}") print(f"My PASSWORD: {"1145141919810"}") while True: pass 创建热点   [localvideo]71eb1eac5585e87ecedc19ac19ce4277[/localvideo]         4、任务3:控制WS2812B(必做任务) 要控制WS2812B,只需在lib中添加外部库neopixel.py(详见other-lib) 再再参考一下示例代码(笑 稍微改一下,用数组存储颜色信息 按钮直接用杜邦线代替,反正原理是一样的。同时添加软件消抖,效果不错 import time import board import digitalio import neopixel button_pin = board.D5 Color_Num = 0 # 彩虹数组 RAINBOW_COLORS = [ (255, 0, 0), # 红 (255, 165, 0), # 橙 (255, 255, 0), # 黄 (0, 255, 0), # 绿 (0, 0, 255), # 蓝 (75, 0, 130), # 靛蓝 (238, 130, 238) # 紫 ] #初始为红 Color = RAINBOW_COLORS[0] button = digitalio.DigitalInOut(button_pin) button.direction = digitalio.Direction.INPUT button.pull = digitalio.Pull.UP debounce_delay = 0.1 # 消抖延迟,单位为秒 button_pressed = False pixel = neopixel.NeoPixel(board.NEOPIXEL, 1) pixel.brightness = 0.3 while True: if not button.value and not button_pressed: # 按键被按下且之前未被按下 button_pressed = True time.sleep(debounce_delay) # 延迟一段时间进行消抖 if not button.value: # 确认按键仍然被按下 Color = RAINBOW_COLORS[Color_Num] # 设置led颜色 pixel.fill(Color) Color_Num += 1 if Color_Num == 7: Color_Num -= 7 elif button.value: # 按键未被按下 button_pressed = False   [localvideo]c15ee3badbac483f54592bbf4c8aea51[/localvideo]   七彩循环: [localvideo]4d3b4125253d2ba6cf10679a9a82cbd0[/localvideo]       5、任务4.1:日历&时钟(选做任务)   导入所需的库和模块,包括wifi、os、ssl、socketpool、adafruit_requests。 连接wifi,发送HTTP请求获取无锡的天气信息的JSON数据。 解析JSON数据,提取需要显示的天气信息,包括城市信息、当前时间、空气质量、温度范围、湿度、PM2.5等。 显示,结束(   ##连接wifi -------------------------------------------------------------------------------------- # SPDX-FileCopyrightText: 2020 Brent Rubell for Adafruit Industries # # SPDX-License-Identifier: MIT import os import wifi print("ESP32-S3 Station Test") print(f"My MAC address: {[hex(i) for i in wifi.radio.mac_address]}") print("Available WiFi networks:") for network in wifi.radio.start_scanning_networks(): print("\t%s\t\tRSSI: %d\tChannel: %d" % (str(network.ssid, "utf-8"), network.rssi, network.channel)) wifi.radio.stop_scanning_networks() print(f"Connecting to {os.getenv('WIFI_SSID')}") wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD")) print(f"Connected to {os.getenv('WIFI_SSID')}") print(f"My IP address: {wifi.radio.ipv4_address}") ## END连接wifi -------------------------------------------------------------------------------------- ## 访问网络 -------------------------------------------------------------------------------------- import ssl import socketpool import adafruit_requests # 请求获取JSON ## api http://t.weather.sojson.com/api/weather/city/101280601 JSON_TIME_URL = "http://t.weather.itboy.net/api/weather/city/101190201" pool = socketpool.SocketPool(wifi.radio) requests = adafruit_requests.Session(pool, ssl.create_default_context()) ## END访问网络 -------------------------------------------------------------------------------------- ## 读取解析Json --------------------------------------------------------------------------------------- print(f"Fetching and parsing json from {JSON_TIME_URL}") response = requests.get(JSON_TIME_URL) print("-" * 40) ## print(f"Time: {response.json()['sysTime2']}") print("-" * 40) print(response.json()) weather = response.json() cityInfo = weather['cityInfo'] city_weather = weather['data'] forecast = city_weather['forecast'] dis_str = ""+cityInfo['parent']+' '+cityInfo['city'] +' '+weather['time'][:11] + forecast[0]['week'] dis_str += '\n 空气质量:'+city_weather['quality'] +" " +forecast[0]['type'] dis_str += "\n 最"+forecast[0]['high']+' 最'+forecast[0]['low'] dis_str += "\n 湿度: "+city_weather['shidu'] dis_str += "\n PM2.5:"+str(city_weather['pm25']) +' PM10:'+str(city_weather['pm10']) dis_str += "\n 注意!! "+forecast[0]['notice'] ## END读取解析Json --------------------------------------------------------------------------------------- ## 显示天气信息 --------------------------------------------------- import board import displayio from adafruit_display_text import label, wrap_text_to_lines from adafruit_bitmap_font import bitmap_font display = board.DISPLAY board.DISPLAY.brightness = 0.9 board.DISPLAY.rotation = 0 font = bitmap_font.load_font("wenquanyi_10pt.pcf") ## 字体颜色 color = 0x9499CA text_group = displayio.Group() text_area = label.Label(font, text=dis_str, color=color) text_area.x = 0 text_area.y = 10 text_area.line_spacing = 0.8 text_area.scale = 1 text_group.append(text_area) display.show(text_group) while True: pass ## END显示天气信息 ---------------------------------------------------     使用WiFi模块连接到无线网络,SocketPool和Requests库访问API,获取天气预报的JSON数据 然后,解析JSON数据并提取所需的天气信息 使用Displayio库在TFT显示屏上显示天气信息   [localvideo]2a2ad95d472c96e229bd25cfb1e091e9[/localvideo]       6、任务4.2:WS2812B效果控制(选做任务) 先瞅一眼任务要求: 完成一个Neopixel(12灯珠或以上)控制器,通过按键和屏幕切换展示效果 凑巧上学期末整了块DFRobot 8*8的RGB灯板👇 硬件有了那直接开整 控制部分直接参考上面neo的程序就行 循环切换7个颜色 屏幕显示颜色只要在循环加个判断就行   #以下是一起动捏 import board import digitalio import time import neopixel led_pin = board.D13 button_pin = board.D5 # 设置LED数量和引脚 NUM_LEDS = 64 LED_PIN = board.D12 Color_Num = 0 # 初始化Neopixel对象 pixels = neopixel.NeoPixel(LED_PIN, NUM_LEDS, brightness=0.2, auto_write=False) # 彩虹数组 RAINBOW_COLORS = [ (255, 0, 0), # 红 (255, 165, 0), # 橙 (255, 255, 0), # 黄 (0, 255, 0), # 绿 (0, 0, 255), # 蓝 (75, 0, 130), # 靛蓝 (238, 130, 238) # 紫 ] #初始为红 Color = RAINBOW_COLORS[0] led = digitalio.DigitalInOut(led_pin) led.direction = digitalio.Direction.OUTPUT button = digitalio.DigitalInOut(button_pin) button.direction = digitalio.Direction.INPUT button.pull = digitalio.Pull.UP debounce_delay = 0.1 # 消抖延迟,单位为秒 button_pressed = False while True: if not button.value and not button_pressed: # 按键被按下且之前未被按下 button_pressed = True time.sleep(debounce_delay) # 延迟一段时间进行消抖 if not button.value: # 确认按键仍然被按下 led.value = not led.value # 在每个LED上设置彩虹颜色 for i in range(NUM_LEDS): Color = RAINBOW_COLORS[Color_Num] pixels[i] = Color pixels.show() time.sleep(0.001) Color_Num += 1 if Color_Num == 7: Color_Num -= 7 elif button.value: # 按键未被按下 button_pressed = False   通过设置LED的数量和引脚,初始化Neopixel,定义彩虹颜色数组 DigitalInOut来控制LED和按钮的引脚。将LED引脚设置为输出模式,按钮引脚设置为输入模式,启用上拉电阻 使用time模块来进行延迟和消抖操作。在按键按下时延迟一段时间进行消抖,确保只有有效的按键触发 循环检测按钮状态。当按钮被按下时,切换LED的状态并设置Neopixel的像素颜色为彩虹颜色。每次按下按钮,彩虹颜色的索引加一,当达到最大索引时重新开始   [localvideo]d9cfb14092142ebff4b9a9c0e4ed6847[/localvideo]       7、任务5:通过网络控制WS2812B(可选任务,非必做) 翻手册翻手册翻手册 官方手册P148 链接直达Adafruit IO:链接 说实话,我还是第一次接触mqtt,但跟着例程走一遍也是没啥问题的 (后半段有所修改)   import time import ssl import os from random import randint import microcontroller import socketpool import wifi import board import neopixel import displayio import terminalio import adafruit_minimqtt.adafruit_minimqtt as MQTT from adafruit_io.adafruit_io import IO_MQTT from adafruit_display_text import bitmap_label, label # WiFi try: print("Connecting to %s" % os.getenv("WIFI_SSID")) wifi.radio.connect(os.getenv("WIFI_SSID"), os.getenv("WIFI_PASSWORD")) print("Connected to %s!" % os.getenv("WIFI_SSID")) # Wi-Fi connectivity fails with error messages, not specific errors, so this except is broad. except Exception as e: # pylint: disable=broad-except print("Failed to connect to WiFi. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset() # Initialise NeoPixel pixel = neopixel.NeoPixel(board.NEOPIXEL, 1, brightness=0.3) # Set up TFT display display = board.DISPLAY board.DISPLAY.brightness = 0.35 board.DISPLAY.rotation = 0 group = displayio.Group() weather_color=0x00FF00 neopixel_area = label.Label(terminalio.FONT, text="NeoPixel", color=weather_color) neopixel_area.x = 2 neopixel_area.y = 30 neopixel_area.line_spacing = 0.8 neopixel_area.scale = 1 main_group = displayio.Group() main_group.append(group) main_group.append(neopixel_area) # Show the main group on the display display.show(main_group) # Define callback functions which will be called when certain events happen. def connected(client): print("Connected to Adafruit IO! Listening for NeoPixel changes...") # Subscribe to Adafruit IO feed called "neopixel" client.subscribe("neopixel") def message(client, feed_id, payload): # pylint: disable=unused-argument print("Feed {0} received new value: {1}".format(feed_id, payload)) #neopixel_area.text = "Feed {0} received new value: {1}".format(feed_id, payload) if feed_id == "neopixel": pixel.fill(int(payload[1:], 16)) # Create a socket pool pool = socketpool.SocketPool(wifi.radio) # Initialize a new MQTT Client object mqtt_client = MQTT.MQTT( broker="io.adafruit.com", username=os.getenv("AIO_USERNAME"), password=os.getenv("AIO_KEY"), socket_pool=pool, ssl_context=ssl.create_default_context(), ) # Initialize Adafruit IO MQTT "helper" io = IO_MQTT(mqtt_client) # Set up the callback methods above io.on_connect = connected io.on_message = message timestamp = 0 while True: try: # 如果Adafruit IO未连接... if not io.is_connected: # 连接到MQTT代理 print("Connecting to Adafruit IO...") io.connect() # 显示颜色信息 neopixel_area.text = "Color: #{:02X}{:02X}{:02X}".format(*pixel[0]) # 更新文本显示 # 显示更新后的屏幕 display.refresh() # 显示延迟 # time.sleep(0.5) # 显式处理消息循环 io.loop() # 处理可能的失败 except Exception as e: # pylint: disable=broad-except print("Failed to get or send data, or connect. Error:", e, "\nBoard will hard reset in 30 seconds.") time.sleep(30) microcontroller.reset()   使用WiFi模块连接到无线网络,并在TFT显示屏上显示连接状态 使用MQTT协议连接到Adafruit IO,并订阅"neopixel"的feed 当接收到"neopixel" feed的新值时,更新NeoPixel的颜色,并在TFT显示屏上显示颜色信息   [localvideo]e8fde4e6d8d6d32fa4da71c619f00773[/localvideo]       对本活动的心得体会   我觉得本次活动对我来说十分有意义,因为开发板+1因为新接触了一种语法,并且增加了自己的ddl   任务总体难度适中,且可查的中文资料较少,可以培养rtfm的好习惯   建议下次活动直接来块小Linux开发板   (完)2023/10/14    

  • 2023-10-07
  • 上传了资料: 【得捷电子Follow me第2期】玩转Adafruit ESP32-S3 TFT Feather资料包

  • 2023-08-24
  • 回复了主题帖: 【得捷电子Follow me第2期】任务4.2要求没看懂

    lugl4313820 发表于 2023-8-24 10:14 这个屏是触控的吗,如果是就是通过触控来实现对灯的控制,并同时显示灯的亮度。如果不是就是在屏上同步显示 ... 不带触控,再添个显示的代码就行

  • 2023-08-23
  • 回复了主题帖: 【得捷电子Follow me第2期】任务4.2要求没看懂

    Jacktang 发表于 2023-8-23 07:27 通过屏幕切换展示效果, 不理解什么?   我的理解是:在屏幕上显示当前RGB灯珠的状态。但不是太确定

  • 2023-08-22
  • 发表了主题帖: 【得捷电子Follow me第2期】任务4.2要求没看懂

    分任务2的要求是:完成一个Neopixel(12灯珠或以上)控制器,通过按键和屏幕切换展示效果 直接使用8x8的模块实现 一个引脚用杜邦线接触供电排针的GND引脚实现开关效果   效果如下 [localvideo]f88ce95fb01c2e74e0293bc0ce9fa2cd[/localvideo] 控制颜色的方法也很简单 代码部分确认开关按下(io接地)后执行: # 在每个LED上设置彩虹颜色 for i in range(NUM_LEDS): Color = RAINBOW_COLORS[Color_Num] pixels[i] = Color pixels.show() time.sleep(0.001) 通过按键实现颜色切换已经满足,但要求里说“通过屏幕切换展示效果”实在是不理解 望指点

最近访客

< 1/2 >

统计信息

已有15人来访过

  • 芯积分:411
  • 好友:--
  • 主题:6
  • 回复:4

留言

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


现在还没有留言