[作品提交] 【得捷Follow me第3期】综合任务提交

xinmeng_wit   2023-12-14 21:03 楼主

第一部分  (3—5分钟短视频)


 

 

第二部分  (任务/项目总结报告)

必做任务1:使用MicroPython系统

任务目标:熟悉Seeed Studio XIAO ESP32C3开发板基本操作,安装esptool,并给开发板刷写MicroPython系统,完成入门程序的运行。

 

本任务主要是学会搭建Micro Python开发环境,并能运行第一个Micro Python程序。

包括Micro Python固件的烧录和PC端软件的安装。

ESP32C3支持使用MicroPython开发,但是出厂固件并不是MicroPython固件。

所以,需要先将开发板烧写成Micro Python固件。

根据官方资料显示,烧录MicroPython固件可以使用esptool。

 

环境搭建简要步骤如下,更加详细的环境搭建教程详见帖子:https://bbs.eeworld.com.cn/thread-1264550-1-1.html

1、安装esptool工具,如果电脑里已经有了esptool的同学可以跳过

2、下载MicroPython固件,网址:https://micropython.org/download/esp32c3/

11.jpg

3、将下载的固件放入到esptool工具目录下进行烧录

在esptool目录下运行cmd命令行

并运行如下命令:

esptool.exe --chip esp32c3 --port COM10 --baud 921600 --before default_reset --after hard_reset --no-stub  write_flash --flash_mode dio --flash_freq 80m 0x0 esp32c3-usb-20230426-v1.20.0.bin

其中,COM10需要替换为电脑实际使用的串口号,esp32c3-usb-20230426-v1.20.0.bin替换为实际使用的。

正常下载完成后,重启开发板,就运行的是Micro Python固件了。

 

4、运行第一个MicroPython程序

运行MircorPython代码就有很多工具了,我习惯使用Thonny进行MicroPython的开发,Thonny软件的安装没有什么特殊性,按照普通软件的安装方法安装即可,这里不再做介绍了。

下面直接使用Thonny连接ESP32C3运行第一个Hello World程序

22.jpg

心得体会:MicroPython固件下载的过程还是相对比较复杂,必须要使用esptool功能才能下载,希望后期可以使用更简单的方式来下载固件,比如usb 拖拽模式。

 

必做任务2:驱动扩展板上的OLED屏幕

任务目标:利用OLED屏幕显示文字图形图片等信息

 

根据seeed官网的信息,XIAO扩展板上集成了一块0.96寸的I2C接口的oled屏幕,使用的引脚是GPIO6和GPIO7。

33.bmp

对于OLED的驱动,网上已经有很多大神写的开源库了,这里也就不再重复造轮子了

因为OLED屏幕的驱动芯片是SSD1306,所以在网上找到ssd1306的micropython库即可,多如牛毛,随便找一个都能用。

这里直接上链接:https://github.com/timotet/SSD1306/tree/master

文本和图形显示比较简单,直接调用ssd1306的库函数就能实现了

例如下面的显示文本代码:

        # 显示文字
        oled.fill(0)  # Clear the screen
        oled.text("Hello, ESP32C3!", 10, 15)
        oled.text("EEWORLD!", 30, 40)
        oled.text("TEXT TESET...", 20, 55)
        oled.show()  # Show the text
        time.sleep(2)
44.jpg

 

图形显示也可以直接调用oled库函数:

        #显示图形
        oled.fill(0)  # Clear the screen
        oled.line(0, 0, 100, 100, 1) # 画线
        oled.rect(60, 10, 50, 30, 1) # 画矩形
        oled.show()
        time.sleep(2)
55.jpg

最后就是图片显示,图片显示会稍微复杂一点,会涉及到图片的简单处理。

第一步,准备一张128*64以内的图片,因为oled的屏幕像素大小是128*64的,所以不能超过这个尺寸

第二步,将图片设置为单色图片,也就是黑白的图片

66.bmp

第三步,将图片转为为.pbm格式并上传到ESP32C3设备中备用

图片格式转换的网址为:https://convertio.co/zh/

完成后如下:

77.bmp

第四步,编写代码显示上面准备的图片,代码中会用到famebuf库,步熟悉这个库的同学可以取看看这个库的详细介绍

        # 显示图片
        with open('MicroPython.pbm', 'rb') as f: # 读取图片文件
            f.readline() # 读取文件第一行,图片格式
            width, height = [int(v) for v in f.readline().split()] # 读取图片像素大小
            data = bytearray(f.read())  # 读取图片数据
            f.close()
        fbuf = framebuf.FrameBuffer(data, width, height, framebuf.MONO_HLSB) # 指定图片数据,大小及格式
        oled.fill(0)  # 清屏
        oled.blit(fbuf, 0, 0) # 数据放入缓冲区
        oled.show()   # 显示
        time.sleep(2)
77.jpg

oled


心得体会:OLED屏幕的使用在ssd1306库的加持下还是比较简单的,显示英文文本,图形,图片都不是一件很难的事情。

但是无法直接支持中文的显示,中文显示需要另外处理,在有中文显示需求的情况下需要研究一下怎么显示中文的问题。

 

必做任务3:控制蜂鸣器播放音乐

任务目标:学会使用控制蜂鸣器,并能根据音乐简谱让蜂鸣器播放对应的音乐

 

XIAO扩展板上集成了一颗蜂鸣器,根据seeed官方的资料显示,蜂鸣器接在扩展板上的A3引脚,在对应到ESP32C3的引脚是GPIO5。

于是,就可以根据引脚信息来对引脚进行配置。

由于我们需要使用蜂鸣器发出不同频率的声音,所以这里就使用pwm功能来进行调整变频率。

GPIO5引脚初始化:

    from machine import PWM,Pin

    # Buzzer settings
    buzzer = PWM(Pin(5),freq=1024,duty=512)

初始频率指定为1024Hz,占空比参数为512,即50% (范围0~1023),初始freq和duty可以随意指定,因为后面会根据音符来动态调整。

这样初始化完成后,蜂鸣器就能发出声音了,但是这个声音是固定不变的。

要想让蜂鸣器根据乐谱来播放音乐,就必须将乐谱量化成代码可以识别的数字,那么对于乐谱来说,基本上量化出来的参数就是两个,一个是频率,一个是时长。

每一个音符(1,2,3,4,5,6,7)对应了一种频率,这些频率都是知道的,可以在网络上查找相关的资料。

补充一点的是,每个音符又分为高音,中音和低音,分别对应不同的频率,也就是每个音符可以对应三种频率,具体要根据音乐简谱来定

对于时长,就需要根据实际的音乐简谱来对应了,每一个歌曲都是不一样的。

下面就是歌曲《沧海一声笑》的简朴,根据这个简朴就可以知道每个音符的频率和时长

88.jpg

量化后的频率和时长:

    X0 = -1   # 休止符
    D5 = 262  # 低音(5)
    D6 = 294  # 低音(6)
    Z1 = 349  # 中音(1)
    Z2 = 392  # 中音(2)
    Z3 = 440  # 中音(3)
    Z5 = 523  # 中音(5)
    Z6 = 587  # 中音(6)

    # 频率
    tune = [ Z6,Z5,Z3,Z2,Z1,     Z3,Z2,Z1,D6,D5,X0,    D5,D6,D5,D6,Z1,Z2,Z3,Z5,   Z6,Z5,Z3,Z2,Z1,Z2,
          Z6,Z6,Z5,Z3,Z2,Z1,     Z3,Z2,Z1,D6,D5,X0,    D5,D6,D5,D6,Z1,Z2,Z3,Z5,   Z6,Z5,Z3,Z2,Z1,Z2,
          Z6,Z6,Z5,Z3,Z2,Z1,     Z3,Z2,Z1,D6,D5,X0,    D5,D6,D5,D6,Z1,Z2,Z3,Z5,   Z6,Z5,Z3,Z2,Z1,Z2,
          Z6,Z6,Z5,Z3,Z2,Z1,     Z3,Z2,Z1,D6,D5,X0,    D5,D6,D5,D6,Z1,Z2,Z3,Z5,   Z6,Z5,Z3,Z2,Z1
             ]

    # 时长
    duration = [ 0.75,0.25,0.5,0.5,2,   0.75,0.25,0.5,0.5,1.8,0.2,  0.75,0.25,0.75,0.25,0.75,0.25,0.5,0.5,   0.75,0.25,0.5,0.25,0.25,2,
            0.75,0.25,0.25,0.5,0.5,2,   0.75,0.25,0.5,0.5,1.8,0.2,  0.75,0.25,0.75,0.25,0.75,0.25,0.5,0.5,   0.75,0.25,0.5,0.25,0.25,2,
            0.75,0.25,0.25,0.5,0.5,2,   0.75,0.25,0.5,0.5,1.8,0.2,  0.75,0.25,0.75,0.25,0.75,0.25,0.5,0.5,   0.75,0.25,0.5,0.25,0.25,2, 
            0.75,0.25,0.25,0.5,0.5,2,   0.75,0.25,0.5,0.5,1.8,0.2,  0.75,0.25,0.75,0.25,0.75,0.25,0.5,0.5,   0.75,0.25,0.5,0.5,2
             ]

根据这两张表去设置pwm的频率和时长就能让蜂鸣器播放出歌曲《沧海一声笑》了。

如下就是根据这两张表动态设置pwm参数的程序,来源于seeed官方例程,稍作修改:

    def buzzer_play():
        total_notes = len(tune)
        for i in range(total_notes):
            current_note = tune[i]
            wait = duration[i]
            if current_note != -1:
                buzzer.duty(512)  # Set duty cycle for sound
                buzzer.freq(current_note)  # Set frequency of the note
            else:
                buzzer.duty(0)  # Turn off the sound
            time.sleep_ms(int(wait * 800))
            buzzer.duty(0)  # Turn off the sound

另外,代码里面time.sleep_ms(int(wait * 800))是用来控制播放速度的,可以根据实际情况做调整。

其实,更确切地说,这个地方实际上是控制音乐每一拍的时长。

buzzer

心得体会:蜂鸣器播放音乐实际上就是控制蜂鸣器的发声频率和时长,理解了这一点,播放音乐还是非常简单的。

 

必做任务4:连接WiFi网络

任务目标:使用开发板连接wifi网络并访问互联网

 

ESP32最大的优势就联网,再加上MicroPython,联网就更加方便了。

使用network库来进行联网是真的好用

调用接口network.WLAN(network.STA_IF)设置network的模式

调用接口station.scan()来进行wifi热点扫描

调用接口station.connect(wifi_ssid, wifi_password)来连接到wifi网络

对,联网就是如此简单。

 

import network
import utime as time

# Network settings
wifi_ssid = "CMCC-eP9M"
wifi_password = "y634ybku"

def scan_and_connect():
    station = network.WLAN(network.STA_IF)
    station.active(True)

    print("Scanning for WiFi networks, please wait...")
    for ssid, bssid, channel, RSSI, authmode, hidden in station.scan():
        print("* {:s}".format(ssid))
        print("   - Channel: {}".format(channel))
        print("   - RSSI: {}".format(RSSI))
        print("   - BSSID: {:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}".format(*bssid))
        print()

    while not station.isconnected():
        print("Connecting...")
        station.connect(wifi_ssid, wifi_password)
        time.sleep(10)

    print("Connected!")
    print("My IP Address:", station.ifconfig()[0])

联网以后,就可以获取到互联网上的一些信息,比如时间还有天气等等。

使用urequests库可以方便的请求互联网信息

获取时间,日期和时区:

import urequests
import ujson
import oled

url = "http://worldtimeapi.org/api/timezone/Asia/Shanghai"

def get_date_time():
    # Perform HTTP GET request on a non-SSL web
    response = urequests.get(url)
    # Check if the request was successful
    if response.status_code == 200:
        # Parse the JSON response
        data = ujson.loads(response.text)
        # Extract the "datetime" field for New York
        ny_datetime = data["datetime"]
        # Split the date and time components
        date_part, time_part = ny_datetime.split("T")
        # Get only the first two decimal places of the time
        time_part = time_part[:8]
        # Get the timezone
        timezone = data["timezone"]
        
        print("Date:\r\n" + date_part)
        print("Time:\r\n" + time_part)
        print("Timezone:\r\n" + timezone)
        
        oled.oled.fill(0)
        oled.oled.text("Date:", 0, 0)
        oled.oled.text(date_part, 0, 10)
        oled.oled.text("Time:", 0, 20)
        oled.oled.text(time_part, 0, 30)
        oled.oled.text("Timezone:", 0, 40)
        oled.oled.text(timezone, 0, 50)
        # Update the display
        oled.oled.show()        
    else:
        print("Failed to get the time")

获取天气信息也是同样的道理:

import urequests
import ujson
import oled


url = 'https://api.seniverse.com/v3/weather/now.json?key={}&location={}&language=en&unit=c'
key = 'your key'
city = 'shanghai'

def get_weather():
    result1=urequests.get(url.format(key, city))
    j1=ujson.loads(result1.text)
    city_name = "City:" + j1['results'][0]['location']['name']
    weather = "Weather:" + j1['results'][0]['now']['text']
    temp = "Temp:" + j1['results'][0]['now']['temperature'] + " C"

    oled.oled.fill(0)
    oled.oled.text(city_name, 0, 0)
    # oled.oled.text(date_part, 0, 10)
    oled.oled.text(weather, 0, 20)
    # oled.oled.text(time_part, 0, 30)
    oled.oled.text(temp, 0, 40)
    # oled.oled.text(timezone, 0, 50)
    # Update the display
    oled.oled.show()
    
    print(j1['results'][0]['location']['name'],end=' ')
    print(j1['results'][0]['now']['text'],end=' ')
    print(j1['results'][0]['now']['temperature'],end='℃ ')
    print(j1['results'][0]['last_update'])

time.jpg
 
weather.jpg

wifi

心得体会:联网应用非常简单,有时候联网需要一定的时间,可能是信号问题

 

必做任务5:使用外部传感器

任务目标:连接环境光传感器和温湿度传感器,获取传感器的数值,并转换成真实的物理量。

 

本次follow me选配了2个外部传感器模块,分别是温湿度传感器模块AHT20和环境光传感器模块。

前者可以测量环境的温度和湿度,为I2C接口,后者可以测量环境的光强度,为模拟量接口。

需要注意的是AHT20有现成的库可以使用,只需简单的调用读温度/湿度的接口就能获取到温度/湿度,使用非常简单。

AHT20库下载地址:https://github.com/targetblank/micropython_ahtx0.git

环境的光强度是通过AD口测量的,调用ADC的读取接口就能获取到数字量或者电压值,也很简单。

温湿度读取:

import utime
from machine import Pin, I2C
import oled

import ahtx0

i2c = I2C(scl=Pin(7), sda=Pin(6))

# Create the sensor object using I2C
sensor = ahtx0.AHT10(i2c)

def get_temp_humi():
    print("\nTemperature: %0.2f C" % sensor.temperature)
    print("Humidity: %0.2f %%" % sensor.relative_humidity)
    
    oled.oled.fill(0)
    oled.oled.text("Temp: %0.2f C" % sensor.temperature, 0, 20)
    oled.oled.text("Humi: %0.2f %%" % sensor.relative_humidity, 0, 40)
    # Update the display
    oled.oled.show()  

光强度读取:

from machine import ADC,Pin
import utime
import oled

adc = ADC(2,atten = ADC.ATTN_11DB)

def get_light_voltage():
    voltage = adc.read_uv() / 1000000
    print("{}v ".format(voltage))
    
    oled.oled.fill(0)
    oled.oled.text(f'Voltage:{voltage:.3f}V', 0, 30)
    # Update the display
    oled.oled.show()  

111.bmp
112.bmp

light_temp_humi

心得体会:温湿度一般都不会出现很快速的变化,因此读取间隔应该尽量长一点,高频率读取没有意义同时也不够准确。

 

可选任务6:3选1即可(选做,非必做):从以下任务要求中,任选一个完成,也可以根据自己的兴趣爱好和能力特长,自定义难度相仿的任务并完成。

■  分任务1:寻找WiFi发射源的位置
■  分任务2:温湿度数据记录仪
■  分任务3:开灯提醒器

任务目标:实现开灯提醒器

 

开灯提醒器实际上就是利用环境光传感器检测周围的环境光的强度,如果光线很暗检测到的光强度就会很低,如果光线很亮检测到的光强度就会很高,通过这种方式可以在光线很暗的情况下给出提醒,提醒用户开灯。报警方式有屏幕显示和声音提醒。

有前面任务5的传感器使用作为基础,开灯提醒器其实就非常简单了,拿到传感器的数据后只需做简单的判读处理就可以实现了。

from machine import ADC,Pin
import utime
import oled
import buzzer

VOLTAGE_THRESHOLD = 50
adc = ADC(2,atten = ADC.ATTN_11DB)
    
def light_check():
    voltage = adc.read_uv() / 1000  # 获取电压mv
    print("{}mv ".format(voltage))
    
    if voltage < VOLTAGE_THRESHOLD:
        buzzer.buzzer_alarm_on()
        # oled.oled.fill(0)
        oled.oled.text('Dim Light', 24, 50)
        # Update the display
        # oled.oled.show()
    else:
        buzzer.buzzer_alarm_off()      
    
    oled.oled.show()

单电压小于50mv时认为光线比较暗,显示“Dim Light”,同时蜂鸣器发出声音,提醒光线太暗,需要开灯。

除了这个功能以外,还提供了AHT的温湿度和wifi获取到的天气信息的循环显示。

IMG_20231211_205534.jpg
IMG_20231211_205536.jpg

Dim_Light

心得体会:开灯提醒器可能时这三个自选任务中最简单的任务了,获取到传感器数据后稍作处理就行了。

当然了,这三个任务在MicroPython的加持下都不是很难。

 

第三部分  (可编译下载的代码)

https://download.eeworld.com.cn/detail/xinmeng_wit/630259

 

本帖最后由 xinmeng_wit 于 2023-12-14 21:02 编辑

回复评论 (1)

楼主的分享十分有用,先收藏起来,慢慢学习,非常感谢楼主的无私奉献

点赞  2023-12-15 22:41
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复