- 2023-09-19
-
回复了主题帖:
颁奖:ADI•世健工业嘉年华——电子书下载
恭喜中奖的小伙伴们啊
- 2023-08-19
-
回复了主题帖:
出色完成任务奖励名单|得捷电子 Follow me 第一期活动
感谢EEWORLD的节点西举办这么精彩的活动,希望越办越好!!!
- 2023-07-14
-
加入了学习《picow_eeworld_taikongrenbiaopan》,观看 picow太空人表盘
- 2023-06-15
-
加入了学习《Digi-Key KOL 系列:商务车型的影音娱乐系统应用方案》,观看 商务车型的影音娱乐系统应用方案
- 2023-06-11
-
发表了主题帖:
【得捷电子Follow me第1期】+ GPS智能手杖定位器
内容一:3-5分钟短视频
[localvideo]4bd2399304d12f45d3f4de8b2d76b1fc[/localvideo]
内容二: 项目总结报告
1. 项目描述
GPS智能手杖定位器是一款智能化辅助设备,它可以通过GPS技术获取当前位置信息,方便用户了解设备的活动范围和行踪,同时也可以通过设置安全围栏,一旦设备离开围栏区域,会自动向用户发送警报信息,提高用户的安全保障。
除了实时定位和安全围栏功能外,GPS智能手杖定位器还具备多项实用功能,如电子时钟、温度预警、SOS求救、低功耗模式等。其中,电子时钟可以显示当前时间,温度预警可以在温度超出设定阈值时发出蜂鸣器警报,SOS求救可以通过设备上的SOS按钮向用户发送求救信息,并提供当前位置信息,低功耗模式可以通过降低功耗延长设备的使用时间,节约能源。
在实现这些功能的过程中,我们需要利用PICO相应模块,实现带有网络、显示、声音功能的创意制作,可以增加其它传感器、外设。首先,需要通过网络获取时间,ADC获取温度,配置PWM控制蜂鸣器,UART获取GPS信息,全都打印到屏幕上,这样用户可以一目了然地看到设备的状态信息。其次,在一个while循环里判断是否超出温度、GPS设定的阈值,超出则报警,实现安全围栏和温度预警等功能。
在扩展这个项目时,可以考虑增加历史轨迹功能,让用户可以查看设备过去一段时间内的运动轨迹,便于了解设备的活动范围和行踪。同时,也可以进一步优化SOS求救功能,可以通过联网实现将位置信息上传到云端服务器,用户可以在手机或电脑上查看设备所在位置,提高用户的安全保障。
此外,为了提高用户的使用体验,可以考虑增加语音播报功能,让设备可以通过声音提示用户当前的状态,如时间、温度、位置等。同时,也可以增加蓝牙功能,将设备与手机或其他智能设备进行连接,方便用户实现更多的操作和功能。
此外,还可以考虑增加生物识别功能,如指纹识别、面部识别等,提高设备的安全性和私密性。另外,可以增加心率监测、步数计数等健康监测功能,让设备可以成为用户健康生活的助手。
总之,GPS智能手杖定位器是一款实用性强的智能化辅助设备,可以为用户提供多种功能,如实时定位、安全围栏、电子时钟、温度预警、SOS求救、低功耗模式等,同时也可以通过扩展功能,如历史轨迹和云端上传等,进一步提升用户的使用体验和安全保障。未来,随着技术的不断进步,GPS智能手杖定位器也将不断升级和完善,为用户带来更加便利和舒适的使用体验。
2. 各功能对应的主要代码片段及说明
配置联网:
#配置联网
ssid = '汤圆和奶茶'
password = 'tangyuan888'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid,password)
#尝试联网
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print("等待连接")
time.sleep(1)
#判断联网状态
if wlan.status() != 3:
raise RuntimeError("联网失败")
else:
print("网络已连接")
status = wlan.ifconfig()
print("ip = " + status[0])
配置各种外设
#配置OLED屏幕
#Grove Shield For Pi Pico I2C1
i2c = I2C(1,sda=Pin(6),scl=Pin(7),freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
#配置温度传感器
sensor_temp = machine.ADC(4)
conversion_factor = 3.3/(65535)
#配置蜂鸣器
# Construct PWM object, with BEEP on Pin(16).
pwm = PWM(Pin(16))
# Set the PWM frequency.
pwm.freq(1000)
#配置GPS
#Grove Shield For Pi Pico UART0
uart0 = UART(0, baudrate=9600, tx = Pin(0), rx = Pin(1))
#print(gps_module)
time.sleep(0.1)
rxData = bytes()
my_gps = MicropyGPS()
实时显示温度
#显示实时温度
read = sensor_temp.read_u16() * conversion_factor
temp = 27 - (read - 0.706) / 0.001721
print("温度:{:.1f}".format(temp))
oled.fill(0)
oled.text(f'temp is {temp:.1f}', 0, 12, 1)
#oled.show()
显示实时时间
#显示实时时间
timezone=8
rtc = RTC()
now = time.time()
now += timezone * 3600
t = time.localtime(now)
year, month, day, hour, minute, second, *_ = t
time_str = f"{year}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}"
print("时间:", time_str)
oled.text(time_str, 0, 0, 1)
#oled.show()
温度报警
#温度超出30度报警
if temp>32:
pwm.duty_u16(1000)
time.sleep(1)
pwm.duty_u16(0)
显示GPS模块并实现安全围栏
if uart0.any():
stat = my_gps.update(uart0.read(1).decode('ascii')) # Note the conversion to to chr, UART outputs ints normally
if stat:
#显示GPS信息
stat = my_gps.update(uart0.read(1).decode("ascii"))
# Note the conversion to to chr, UART outputs ints normally
print("纬度:", my_gps.latitude_string())
print("经度:", my_gps.longitude_string())
print(
"Speed:",
my_gps.speed_string("kph"),
"or",
my_gps.speed_string("mph"),
"or",
my_gps.speed_string("knot"),
)
lat_disp = my_gps.latitude_string()
oled.text(lat_disp,0,24,1)
lon_disp = my_gps.longitude_string()
oled.text(lon_disp,0,36,1)
lon_disp = my_gps.speed_string()
oled.text(lon_disp,0,48,1)
oled.show()
#安全围栏
if my_gps.latitude_string()>'30' and my_gps.longitude_string()>'123':
pwm.duty_u16(1000)
time.sleep(1)
pwm.duty_u16(0)
3. 功能展示及说明
实时定位:可以通过 GPS 技术获取当前位置
安全围栏:可以设置安全围栏,一旦设备离开围栏区域,会自动向用户发送警报信息。(场地原因无法拍照实现)
电子时钟:显示屏实时显示当前时间。
温度预警:超出温度蜂鸣器将会报警。
4. 对本活动的心得体会
很高兴参加这样一场面向电子爱好者的活动,通过购买指定的开发板和器件,参与者可以学习到如何使用这些设备实现各种功能,同时还可以获得报销和奖励。这种方式不仅提高了参与者的DIY技能,也推广了这些开发板和器件的使用。希望未来还能有更多这样的活动,让更多人加入到电子爱好者的行列中。
内容三:可编译下载的代码
-
加入了学习《2022得捷创新设计大赛-USB 便携式可编程仪表》,观看 2022 得捷创新设计大赛-USB 便携式可编程仪表(多功能USB电源)
- 2023-06-02
-
发表了主题帖:
【得捷电子Follow me第1期】第五贴: 扩展任务——GPS智能手杖定位器
【得捷电子Follow me第1期】第五贴: 扩展任务——GPS智能手杖定位器
扩展任务就是利用PICO相应模块,实现带有网络、显示、声音功能的创意制作,可以增加其它传感器、外设。
那么本次就做一个GPS只能手杖定位器,简单来说就是智杖!
GPS智能手杖定位器一般具有以下功能:
实时定位:可以通过 GPS 技术获取当前位置
安全围栏:可以设置安全围栏,一旦设备离开围栏区域,会自动向用户发送警报信息。
电子时钟:显示屏实时显示当前时间。
温度预警:超出温度蜂鸣器将会报警。
进阶选项:开发者可自行添加:
历史轨迹:可以查看设备过去一段时间内的运动轨迹,便于用户了解设备的活动范围和行踪。
SOS 求救:可以通过设备上的 SOS 按钮向用户发送求救信息,并提供当前位置信息,便于用户快速找到设备。
低功耗模式:可以通过低功耗模式延长设备的使用时间,节约能源。
实时定位:将位置信息上传到云端服务器,用户可以在手机或电脑上查看设备所在位置
首先,研发思路还是把这些模块一一实现,联网、屏幕、温度传感器、蜂鸣器、GPS。
其次,通过网络获取时间,ADC获取温度,配置PWM控制蜂鸣器,UART获取GPS信息,全都打印到屏幕上,并在一个while循环里判断是否超出温度、GPS设定的阈值,超出则报警,实现安全围栏和温度预警等功能。
以下为代码具体实现:
import time
import ntptime
import network
import hashlib
import framebuf
from micropyGPS import MicropyGPS
from machine import RTC, Pin, I2C, PWM, UART
from ssd1306 import SSD1306_I2C
#配置联网
ssid = '汤圆和奶茶'
password = 'tangyuan888'
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid,password)
#尝试联网
max_wait = 10
while max_wait > 0:
if wlan.status() < 0 or wlan.status() >= 3:
break
max_wait -= 1
print("等待连接")
time.sleep(1)
#判断联网状态
if wlan.status() != 3:
raise RuntimeError("联网失败")
else:
print("网络已连接")
status = wlan.ifconfig()
print("ip = " + status[0])
#配置OLED屏幕
#Grove Shield For Pi Pico I2C1
i2c = I2C(1,sda=Pin(6),scl=Pin(7),freq=400000)
oled = SSD1306_I2C(128, 64, i2c)
#配置温度传感器
sensor_temp = machine.ADC(4)
conversion_factor = 3.3/(65535)
#配置蜂鸣器
# Construct PWM object, with BEEP on Pin(16).
pwm = PWM(Pin(16))
# Set the PWM frequency.
pwm.freq(1000)
#配置GPS
#Grove Shield For Pi Pico UART0
uart0 = UART(0, baudrate=9600, tx = Pin(0), rx = Pin(1))
#print(gps_module)
time.sleep(0.1)
rxData = bytes()
my_gps = MicropyGPS()
while True:
#显示实时温度
read = sensor_temp.read_u16() * conversion_factor
temp = 27 - (read - 0.706) / 0.001721
print("温度:{:.1f}".format(temp))
oled.fill(0)
oled.text(f'temp is {temp:.1f}', 0, 12, 1)
#oled.show()
#显示实时时间
timezone=8
rtc = RTC()
now = time.time()
now += timezone * 3600
t = time.localtime(now)
year, month, day, hour, minute, second, *_ = t
time_str = f"{year}-{month:02d}-{day:02d} {hour:02d}:{minute:02d}:{second:02d}"
print("时间:", time_str)
oled.text(time_str, 0, 0, 1)
#oled.show()
#温度超出30度报警
if temp>38:
pwm.duty_u16(1000)
time.sleep(1)
pwm.duty_u16(0)
if uart0.any():
stat = my_gps.update(uart0.read(1).decode('ascii')) # Note the conversion to to chr, UART outputs ints normally
if stat:
#显示GPS信息
stat = my_gps.update(uart0.read(1).decode("ascii"))
# Note the conversion to to chr, UART outputs ints normally
print("纬度:", my_gps.latitude_string())
print("经度:", my_gps.longitude_string())
print(
"Speed:",
my_gps.speed_string("kph"),
"or",
my_gps.speed_string("mph"),
"or",
my_gps.speed_string("knot"),
)
lat_disp = my_gps.latitude_string()
oled.text(lat_disp,0,24,1)
lon_disp = my_gps.longitude_string()
oled.text(lon_disp,0,36,1)
lon_disp = my_gps.speed_string()
oled.text(lon_disp,0,48,1)
oled.show()
#安全围栏
if my_gps.latitude_string()>'30' and my_gps.longitude_string()>'123':
pwm.duty_u16(1000)
time.sleep(1)
pwm.duty_u16(0)
以下为用充电宝实现的智杖!当然,目前还没有制作外壳哈哈哈,有兴趣想做完成品的可以加上外壳~
-
加入了学习《Digi-Key: Follow Me 系列(1) 直播回放及答疑记录》,观看 Raspberry Pi Pico W 使用入门
- 2023-05-30
-
加入了学习《开源PWM机械臂(51版本)》,观看 51单片机之开发板介绍
- 2023-05-28
-
回复了主题帖:
EEWorld邀你来拆解(第10期)——玩具总动员
积极参入“EEWorld”举办的拆解(第10期)活动!
一.选择拆品
1.激光剑
二.申请拆解理由
1.我非常喜欢这个玩具,但是我想了解更多关于它内部结构和工作原理的信息。因此,我想向EEWorld申请拆解这个玩具的许可。
2.我相信,通过拆解这个玩具,我可以更好地了解它的组成部分,以及如何让它更好地工作。同时,我也希望能够通过这次拆解,发掘出这个玩具可能存在的问题,并提供一些改进的建议,以便在未来的产品开发中有所参考。
3.通过以下详细流程进行拆解
准备工具:需要准备一些基本的工具,例如螺丝刀、扁嘴钳、镊子、剥线钳等。还需要准备一块软垫子或软布,以便在拆解过程中保护玩具的外壳。
拆卸外壳:首先,需要使用螺丝刀将玩具外壳上的螺丝拧下。然后,您可以使用扁嘴钳或镊子轻轻地拆下外壳。我回小心不要损坏外壳和内部组件。
拆卸电路板:一旦拆下了外壳,会看到电路板。使用剥线钳或镊子拆下电路板上的连接器。在拆下电路板之前,小心地记录每个连接器的位置和方向,以便在组装时正确连接它们。
拆卸其他组件:在电路板下方,会看到其他一些组件,例如发光二极管、电池和开关。使用镊子或剥线钳轻轻地拆下这些组件。我还会小心地拆卸它们,并将它们放在安全的地方以免丢失。
清洁和整理:在拆卸完所有组件之后,我会按照顺序整理防止好各个组件,再进行拆解的学习验证。
测试和验证:在拆解学习验证之后,重新组装玩具,并进行测试和验证。我会正确连接了所有电子组件,并且所有组件都在正确的位置上。
我会在拆解和组装玩具时,小心谨慎,并确保不会损坏任何组件。当碰到任何问题是,我会咨询更加专业人士的帮助。
三. 我是一名具有丰富研发和拆解电子产品经验的嵌入式程序员,拥有许多技能和工具来拆解复杂的电子产品。我具有扎实的电子知识和技能,能够快速准确地分析和识别电子元件。我的工作经验和技能可以确保拆解过程的安全,并确保不会损坏设备或人员。同时,我的团队也具有丰富的电子产品经验,可以为整个拆解过程提供支持和帮助。
-
发表了主题帖:
【得捷电子Follow me第1期】第四贴: GPS定位
GPS模块可以说是最贵的一个模块了,我们接下来就试试去驱动它。
首先将GPS模块连接到UART0
还要调用相应的库才能驱动,用的是这个micropyGPS,仓库地址:https://github.com/inmcm/micropyGPS/blob/master/micropyGPS.py
把GPS的库上传到开发板,micropyGPS.py内容如下:
"""
# MicropyGPS - a GPS NMEA sentence parser for Micropython/Python 3.X
# Copyright (c) 2017 Michael Calvin McCoy (calvin.mccoy@protonmail.com)
# The MIT License (MIT) - see LICENSE file
"""
# TODO:
# Time Since First Fix
# Distance/Time to Target
# More Helper Functions
# Dynamically limit sentences types to parse
from math import floor, modf
# Import utime or time for fix time handling
try:
# Assume running on MicroPython
import utime
except ImportError:
# Otherwise default to time module for non-embedded implementations
# Should still support millisecond resolution.
import time
class MicropyGPS(object):
"""GPS NMEA Sentence Parser. Creates object that stores all relevant GPS data and statistics.
Parses sentences one character at a time using update(). """
# Max Number of Characters a valid sentence can be (based on GGA sentence)
SENTENCE_LIMIT = 90
__HEMISPHERES = ('N', 'S', 'E', 'W')
__NO_FIX = 1
__FIX_2D = 2
__FIX_3D = 3
__DIRECTIONS = ('N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W',
'WNW', 'NW', 'NNW')
__MONTHS = ('January', 'February', 'March', 'April', 'May',
'June', 'July', 'August', 'September', 'October',
'November', 'December')
def __init__(self, local_offset=0, location_formatting='ddm'):
"""
Setup GPS Object Status Flags, Internal Data Registers, etc
local_offset (int): Timzone Difference to UTC
location_formatting (str): Style For Presenting Longitude/Latitude:
Decimal Degree Minute (ddm) - 40° 26.767′ N
Degrees Minutes Seconds (dms) - 40° 26′ 46″ N
Decimal Degrees (dd) - 40.446° N
"""
#####################
# Object Status Flags
self.sentence_active = False
self.active_segment = 0
self.process_crc = False
self.gps_segments = []
self.crc_xor = 0
self.char_count = 0
self.fix_time = 0
#####################
# Sentence Statistics
self.crc_fails = 0
self.clean_sentences = 0
self.parsed_sentences = 0
#####################
# Logging Related
self.log_handle = None
self.log_en = False
#####################
# Data From Sentences
# Time
self.timestamp = [0, 0, 0.0]
self.date = [0, 0, 0]
self.local_offset = local_offset
# Position/Motion
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.coord_format = location_formatting
self.speed = [0.0, 0.0, 0.0]
self.course = 0.0
self.altitude = 0.0
self.geoid_height = 0.0
# GPS Info
self.satellites_in_view = 0
self.satellites_in_use = 0
self.satellites_used = []
self.last_sv_sentence = 0
self.total_sv_sentences = 0
self.satellite_data = dict()
self.hdop = 0.0
self.pdop = 0.0
self.vdop = 0.0
self.valid = False
self.fix_stat = 0
self.fix_type = 1
########################################
# Coordinates Translation Functions
########################################
@property
def latitude(self):
"""Format Latitude Data Correctly"""
if self.coord_format == 'dd':
decimal_degrees = self._latitude[0] + (self._latitude[1] / 60)
return [decimal_degrees, self._latitude[2]]
elif self.coord_format == 'dms':
minute_parts = modf(self._latitude[1])
seconds = round(minute_parts[0] * 60)
return [self._latitude[0], int(minute_parts[1]), seconds, self._latitude[2]]
else:
return self._latitude
@property
def longitude(self):
"""Format Longitude Data Correctly"""
if self.coord_format == 'dd':
decimal_degrees = self._longitude[0] + (self._longitude[1] / 60)
return [decimal_degrees, self._longitude[2]]
elif self.coord_format == 'dms':
minute_parts = modf(self._longitude[1])
seconds = round(minute_parts[0] * 60)
return [self._longitude[0], int(minute_parts[1]), seconds, self._longitude[2]]
else:
return self._longitude
########################################
# Logging Related Functions
########################################
def start_logging(self, target_file, mode="append"):
"""
Create GPS data log object
"""
# Set Write Mode Overwrite or Append
mode_code = 'w' if mode == 'new' else 'a'
try:
self.log_handle = open(target_file, mode_code)
except AttributeError:
print("Invalid FileName")
return False
self.log_en = True
return True
def stop_logging(self):
"""
Closes the log file handler and disables further logging
"""
try:
self.log_handle.close()
except AttributeError:
print("Invalid Handle")
return False
self.log_en = False
return True
def write_log(self, log_string):
"""Attempts to write the last valid NMEA sentence character to the active file handler
"""
try:
self.log_handle.write(log_string)
except TypeError:
return False
return True
########################################
# Sentence Parsers
########################################
def gprmc(self):
"""Parse Recommended Minimum Specific GPS/Transit data (RMC)Sentence.
Updates UTC timestamp, latitude, longitude, Course, Speed, Date, and fix status
"""
# UTC Timestamp
try:
utc_string = self.gps_segments[1]
if utc_string: # Possible timestamp found
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
self.timestamp = [hours, minutes, seconds]
else: # No Time stamp yet
self.timestamp = [0, 0, 0.0]
except ValueError: # Bad Timestamp value present
return False
# Date stamp
try:
date_string = self.gps_segments[9]
# Date string printer function assumes to be year >=2000,
# date_string() must be supplied with the correct century argument to display correctly
if date_string: # Possible date stamp found
day = int(date_string[0:2])
month = int(date_string[2:4])
year = int(date_string[4:6])
self.date = (day, month, year)
else: # No Date stamp yet
self.date = (0, 0, 0)
except ValueError: # Bad Date stamp value present
return False
# Check Receiver Data Valid Flag
if self.gps_segments[2] == 'A': # Data from Receiver is Valid/Has Fix
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[3]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[4]
# Longitude
l_string = self.gps_segments[5]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[6]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Speed
try:
spd_knt = float(self.gps_segments[7])
except ValueError:
return False
# Course
try:
if self.gps_segments[8]:
course = float(self.gps_segments[8])
else:
course = 0.0
except ValueError:
return False
# TODO - Add Magnetic Variation
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
# Include mph and hm/h
self.speed = [spd_knt, spd_knt * 1.151, spd_knt * 1.852]
self.course = course
self.valid = True
# Update Last Fix Time
self.new_fix_time()
else: # Clear Position Data if Sentence is 'Invalid'
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.speed = [0.0, 0.0, 0.0]
self.course = 0.0
self.valid = False
return True
def gpgll(self):
"""Parse Geographic Latitude and Longitude (GLL)Sentence. Updates UTC timestamp, latitude,
longitude, and fix status"""
# UTC Timestamp
try:
utc_string = self.gps_segments[5]
if utc_string: # Possible timestamp found
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
self.timestamp = [hours, minutes, seconds]
else: # No Time stamp yet
self.timestamp = [0, 0, 0.0]
except ValueError: # Bad Timestamp value present
return False
# Check Receiver Data Valid Flag
if self.gps_segments[6] == 'A': # Data from Receiver is Valid/Has Fix
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[1]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[2]
# Longitude
l_string = self.gps_segments[3]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[4]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
self.valid = True
# Update Last Fix Time
self.new_fix_time()
else: # Clear Position Data if Sentence is 'Invalid'
self._latitude = [0, 0.0, 'N']
self._longitude = [0, 0.0, 'W']
self.valid = False
return True
def gpvtg(self):
"""Parse Track Made Good and Ground Speed (VTG) Sentence. Updates speed and course"""
try:
course = float(self.gps_segments[1]) if self.gps_segments[1] else 0.0
spd_knt = float(self.gps_segments[5]) if self.gps_segments[5] else 0.0
except ValueError:
return False
# Include mph and km/h
self.speed = (spd_knt, spd_knt * 1.151, spd_knt * 1.852)
self.course = course
return True
def gpgga(self):
"""Parse Global Positioning System Fix Data (GGA) Sentence. Updates UTC timestamp, latitude, longitude,
fix status, satellites in use, Horizontal Dilution of Precision (HDOP), altitude, geoid height and fix status"""
try:
# UTC Timestamp
utc_string = self.gps_segments[1]
# Skip timestamp if receiver doesn't have on yet
if utc_string:
hours = (int(utc_string[0:2]) + self.local_offset) % 24
minutes = int(utc_string[2:4])
seconds = float(utc_string[4:])
else:
hours = 0
minutes = 0
seconds = 0.0
# Number of Satellites in Use
satellites_in_use = int(self.gps_segments[7])
# Get Fix Status
fix_stat = int(self.gps_segments[6])
except (ValueError, IndexError):
return False
try:
# Horizontal Dilution of Precision
hdop = float(self.gps_segments[8])
except (ValueError, IndexError):
hdop = 0.0
# Process Location and Speed Data if Fix is GOOD
if fix_stat:
# Longitude / Latitude
try:
# Latitude
l_string = self.gps_segments[2]
lat_degs = int(l_string[0:2])
lat_mins = float(l_string[2:])
lat_hemi = self.gps_segments[3]
# Longitude
l_string = self.gps_segments[4]
lon_degs = int(l_string[0:3])
lon_mins = float(l_string[3:])
lon_hemi = self.gps_segments[5]
except ValueError:
return False
if lat_hemi not in self.__HEMISPHERES:
return False
if lon_hemi not in self.__HEMISPHERES:
return False
# Altitude / Height Above Geoid
try:
altitude = float(self.gps_segments[9])
geoid_height = float(self.gps_segments[11])
except ValueError:
altitude = 0
geoid_height = 0
# Update Object Data
self._latitude = [lat_degs, lat_mins, lat_hemi]
self._longitude = [lon_degs, lon_mins, lon_hemi]
self.altitude = altitude
self.geoid_height = geoid_height
# Update Object Data
self.timestamp = [hours, minutes, seconds]
self.satellites_in_use = satellites_in_use
self.hdop = hdop
self.fix_stat = fix_stat
# If Fix is GOOD, update fix timestamp
if fix_stat:
self.new_fix_time()
return True
def gpgsa(self):
"""Parse GNSS DOP and Active Satellites (GSA) sentence. Updates GPS fix type, list of satellites used in
fix calculation, Position Dilution of Precision (PDOP), Horizontal Dilution of Precision (HDOP), Vertical
Dilution of Precision, and fix status"""
# Fix Type (None,2D or 3D)
try:
fix_type = int(self.gps_segments[2])
except ValueError:
return False
# Read All (up to 12) Available PRN Satellite Numbers
sats_used = []
for sats in range(12):
sat_number_str = self.gps_segments[3 + sats]
if sat_number_str:
try:
sat_number = int(sat_number_str)
sats_used.append(sat_number)
except ValueError:
return False
else:
break
# PDOP,HDOP,VDOP
try:
pdop = float(self.gps_segments[15])
hdop = float(self.gps_segments[16])
vdop = float(self.gps_segments[17])
except ValueError:
return False
# Update Object Data
self.fix_type = fix_type
# If Fix is GOOD, update fix timestamp
if fix_type > self.__NO_FIX:
self.new_fix_time()
self.satellites_used = sats_used
self.hdop = hdop
self.vdop = vdop
self.pdop = pdop
return True
def gpgsv(self):
"""Parse Satellites in View (GSV) sentence. Updates number of SV Sentences,the number of the last SV sentence
parsed, and data on each satellite present in the sentence"""
try:
num_sv_sentences = int(self.gps_segments[1])
current_sv_sentence = int(self.gps_segments[2])
sats_in_view = int(self.gps_segments[3])
except ValueError:
return False
# Create a blank dict to store all the satellite data from this sentence in:
# satellite PRN is key, tuple containing telemetry is value
satellite_dict = dict()
# Calculate Number of Satelites to pull data for and thus how many segment positions to read
if num_sv_sentences == current_sv_sentence:
# Last sentence may have 1-4 satellites; 5 - 20 positions
sat_segment_limit = (sats_in_view - ((num_sv_sentences - 1) * 4)) * 5
else:
sat_segment_limit = 20 # Non-last sentences have 4 satellites and thus read up to position 20
# Try to recover data for up to 4 satellites in sentence
for sats in range(4, sat_segment_limit, 4):
# If a PRN is present, grab satellite data
if self.gps_segments[sats]:
try:
sat_id = int(self.gps_segments[sats])
except (ValueError,IndexError):
return False
try: # elevation can be null (no value) when not tracking
elevation = int(self.gps_segments[sats+1])
except (ValueError,IndexError):
elevation = None
try: # azimuth can be null (no value) when not tracking
azimuth = int(self.gps_segments[sats+2])
except (ValueError,IndexError):
azimuth = None
try: # SNR can be null (no value) when not tracking
snr = int(self.gps_segments[sats+3])
except (ValueError,IndexError):
snr = None
# If no PRN is found, then the sentence has no more satellites to read
else:
break
# Add Satellite Data to Sentence Dict
satellite_dict[sat_id] = (elevation, azimuth, snr)
# Update Object Data
self.total_sv_sentences = num_sv_sentences
self.last_sv_sentence = current_sv_sentence
self.satellites_in_view = sats_in_view
# For a new set of sentences, we either clear out the existing sat data or
# update it as additional SV sentences are parsed
if current_sv_sentence == 1:
self.satellite_data = satellite_dict
else:
self.satellite_data.update(satellite_dict)
return True
##########################################
# Data Stream Handler Functions
##########################################
def new_sentence(self):
"""Adjust Object Flags in Preparation for a New Sentence"""
self.gps_segments = ['']
self.active_segment = 0
self.crc_xor = 0
self.sentence_active = True
self.process_crc = True
self.char_count = 0
def update(self, new_char):
"""Process a new input char and updates GPS object if necessary based on special characters ('$', ',', '*')
Function builds a list of received string that are validate by CRC prior to parsing by the appropriate
sentence function. Returns sentence type on successful parse, None otherwise"""
valid_sentence = False
# Validate new_char is a printable char
ascii_char = ord(new_char)
if 10 <= ascii_char <= 126:
self.char_count += 1
# Write Character to log file if enabled
if self.log_en:
self.write_log(new_char)
# Check if a new string is starting ($)
if new_char == '$':
self.new_sentence()
return None
elif self.sentence_active:
# Check if sentence is ending (*)
if new_char == '*':
self.process_crc = False
self.active_segment += 1
self.gps_segments.append('')
return None
# Check if a section is ended (,), Create a new substring to feed
# characters to
elif new_char == ',':
self.active_segment += 1
self.gps_segments.append('')
# Store All Other printable character and check CRC when ready
else:
self.gps_segments[self.active_segment] += new_char
# When CRC input is disabled, sentence is nearly complete
if not self.process_crc:
if len(self.gps_segments[self.active_segment]) == 2:
try:
final_crc = int(self.gps_segments[self.active_segment], 16)
if self.crc_xor == final_crc:
valid_sentence = True
else:
self.crc_fails += 1
except ValueError:
pass # CRC Value was deformed and could not have been correct
# Update CRC
if self.process_crc:
self.crc_xor ^= ascii_char
# If a Valid Sentence Was received and it's a supported sentence, then parse it!!
if valid_sentence:
self.clean_sentences += 1 # Increment clean sentences received
self.sentence_active = False # Clear Active Processing Flag
if self.gps_segments[0] in self.supported_sentences:
# parse the Sentence Based on the message type, return True if parse is clean
if self.supported_sentences[self.gps_segments[0]](self):
# Let host know that the GPS object was updated by returning parsed sentence type
self.parsed_sentences += 1
return self.gps_segments[0]
# Check that the sentence buffer isn't filling up with Garage waiting for the sentence to complete
if self.char_count > self.SENTENCE_LIMIT:
self.sentence_active = False
# Tell Host no new sentence was parsed
return None
def new_fix_time(self):
"""Updates a high resolution counter with current time when fix is updated. Currently only triggered from
GGA, GSA and RMC sentences"""
try:
self.fix_time = utime.ticks_ms()
except NameError:
self.fix_time = time.time()
#########################################
# User Helper Functions
# These functions make working with the GPS object data easier
#########################################
def satellite_data_updated(self):
"""
Checks if the all the GSV sentences in a group have been read, making satellite data complete
:return: boolean
"""
if self.total_sv_sentences > 0 and self.total_sv_sentences == self.last_sv_sentence:
return True
else:
return False
def unset_satellite_data_updated(self):
"""
Mark GSV sentences as read indicating the data has been used and future updates are fresh
"""
self.last_sv_sentence = 0
def satellites_visible(self):
"""
Returns a list of of the satellite PRNs currently visible to the receiver
:return: list
"""
return list(self.satellite_data.keys())
def time_since_fix(self):
"""Returns number of millisecond since the last sentence with a valid fix was parsed. Returns 0 if
no fix has been found"""
# Test if a Fix has been found
if self.fix_time == 0:
return -1
# Try calculating fix time using utime; if not running MicroPython
# time.time() returns a floating point value in secs
try:
current = utime.ticks_diff(utime.ticks_ms(), self.fix_time)
except NameError:
current = (time.time() - self.fix_time) * 1000 # ms
return current
def compass_direction(self):
"""
Determine a cardinal or inter-cardinal direction based on current course.
:return: string
"""
# Calculate the offset for a rotated compass
if self.course >= 348.75:
offset_course = 360 - self.course
else:
offset_course = self.course + 11.25
# Each compass point is separated by 22.5 degrees, divide to find lookup value
dir_index = floor(offset_course / 22.5)
final_dir = self.__DIRECTIONS[dir_index]
return final_dir
def latitude_string(self):
"""
Create a readable string of the current latitude data
:return: string
"""
if self.coord_format == 'dd':
formatted_latitude = self.latitude
lat_string = str(formatted_latitude[0]) + '° ' + str(self._latitude[2])
elif self.coord_format == 'dms':
formatted_latitude = self.latitude
lat_string = str(formatted_latitude[0]) + '° ' + str(formatted_latitude[1]) + "' " + str(formatted_latitude[2]) + '" ' + str(formatted_latitude[3])
else:
lat_string = str(self._latitude[0]) + '° ' + str(self._latitude[1]) + "' " + str(self._latitude[2])
return lat_string
def longitude_string(self):
"""
Create a readable string of the current longitude data
:return: string
"""
if self.coord_format == 'dd':
formatted_longitude = self.longitude
lon_string = str(formatted_longitude[0]) + '° ' + str(self._longitude[2])
elif self.coord_format == 'dms':
formatted_longitude = self.longitude
lon_string = str(formatted_longitude[0]) + '° ' + str(formatted_longitude[1]) + "' " + str(formatted_longitude[2]) + '" ' + str(formatted_longitude[3])
else:
lon_string = str(self._longitude[0]) + '° ' + str(self._longitude[1]) + "' " + str(self._longitude[2])
return lon_string
def speed_string(self, unit='kph'):
"""
Creates a readable string of the current speed data in one of three units
:param unit: string of 'kph','mph, or 'knot'
:return:
"""
if unit == 'mph':
speed_string = str(self.speed[1]) + ' mph'
elif unit == 'knot':
if self.speed[0] == 1:
unit_str = ' knot'
else:
unit_str = ' knots'
speed_string = str(self.speed[0]) + unit_str
else:
speed_string = str(self.speed[2]) + ' km/h'
return speed_string
def date_string(self, formatting='s_mdy', century='20'):
"""
Creates a readable string of the current date.
Can select between long format: Januray 1st, 2014
or two short formats:
11/01/2014 (MM/DD/YYYY)
01/11/2014 (DD/MM/YYYY)
:param formatting: string 's_mdy', 's_dmy', or 'long'
:param century: int delineating the century the GPS data is from (19 for 19XX, 20 for 20XX)
:return: date_string string with long or short format date
"""
# Long Format Januray 1st, 2014
if formatting == 'long':
# Retrieve Month string from private set
month = self.__MONTHS[self.date[1] - 1]
# Determine Date Suffix
if self.date[0] in (1, 21, 31):
suffix = 'st'
elif self.date[0] in (2, 22):
suffix = 'nd'
elif self.date[0] == (3, 23):
suffix = 'rd'
else:
suffix = 'th'
day = str(self.date[0]) + suffix # Create Day String
year = century + str(self.date[2]) # Create Year String
date_string = month + ' ' + day + ', ' + year # Put it all together
else:
# Add leading zeros to day string if necessary
if self.date[0] < 10:
day = '0' + str(self.date[0])
else:
day = str(self.date[0])
# Add leading zeros to month string if necessary
if self.date[1] < 10:
month = '0' + str(self.date[1])
else:
month = str(self.date[1])
# Add leading zeros to year string if necessary
if self.date[2] < 10:
year = '0' + str(self.date[2])
else:
year = str(self.date[2])
# Build final string based on desired formatting
if formatting == 's_dmy':
date_string = day + '/' + month + '/' + year
else: # Default date format
date_string = month + '/' + day + '/' + year
return date_string
# All the currently supported NMEA sentences
supported_sentences = {'GPRMC': gprmc, 'GLRMC': gprmc,
'GPGGA': gpgga, 'GLGGA': gpgga,
'GPVTG': gpvtg, 'GLVTG': gpvtg,
'GPGSA': gpgsa, 'GLGSA': gpgsa,
'GPGSV': gpgsv, 'GLGSV': gpgsv,
'GPGLL': gpgll, 'GLGLL': gpgll,
'GNGGA': gpgga, 'GNRMC': gprmc,
'GNVTG': gpvtg, 'GNGLL': gpgll,
'GNGSA': gpgsa,
}
if __name__ == "__main__":
pass
库导入成功以后,可以把测试代码添加进来,代码如下:
from machine import UART, Pin
import time
import hashlib
from micropyGPS import MicropyGPS
from machine import Pin
import time
from machine import PWM
from machine import I2C
from ssd1306 import SSD1306_I2C
import framebuf
WIDTH = 128
HEIGHT = 64
i2c = I2C(1)
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
# Init I2C using I2C0 defaults, SCL=Pin(GP9), SDA=Pin(GP8), freq=400000
uart0 = UART(0, baudrate=9600, tx=Pin(0), rx=Pin(1))
time.sleep(0.1)
rxData = bytes()
my_gps = MicropyGPS()
while True:
if uart0.any():
stat = my_gps.update(uart0.read(1).decode('ascii')) # Note the conversion to to chr, UART outputs ints normally
if stat:
oled.fill(0)
lat_disp = my_gps.latitude_string()
oled.text(lat_disp,5,10)
lon_disp = my_gps.longitude_string()
oled.text(lon_disp,5,30)
time_disp = my_gps.date_string('s_dmy')
oled.text(time_disp,5,50)
oled.show()
print('Latitude:', my_gps.latitude_string())
print('Longitude:', my_gps.longitude_string())
print('Speed:', my_gps.speed_string('kph'), 'or', my_gps.speed_string('mph'), 'or', my_gps.speed_string('knot'))
print('Date (Long Format):', my_gps.date_string('long'))
print('Date (Short D/M/Y Format):', my_gps.date_string('s_dmy'))
print('timestamp (Short [H,M,S] Format):', my_gps.timestamp)
stat = None
整体思路也是借鉴大佬的:
连接GPS模块:大多数GPS模块都使用UART串口通信协议。因此,我们需要将GPS模块的VCC和GND引脚接到Pico W的相应引脚,将TX和RX引脚接到Pico W的UART引脚,然后使用Micropython库中的UART库打开串口,以从GPS模块接收数据。
解析GPS数据:GPS模块将实时地发送位置、时间和其他信息。首先,我们需要将GPS数据流解析为可读的数据。通常,GPS数据流是NMEA语句,包括GPGGA、GPRMC、GPVTG、GPGSA等语句。我们可以使用Micropython库中的UART库读取串口数据,并使用Python的字符串分析和处理方法来解析每个语句中的位置、时间和卫星信息。
显示位置信息:在解析GPS数据流之后,我们可以使用SSD1306 OLED屏幕显示位置信息。我们可以使用Micropython的GPIO库来控制OLED屏幕,并使用SSD1306库来处理图形和字符。在OLED屏幕上,可以显示当前位置、经度、纬度和其他相关信息。
扩展(待完成):上传位置信息:如果我们想要将定位数据上传到云端或其他设备,我们可以使用HTTP或其他网络协议将数据打包并上传到服务器端。我们可以使用Python的库,如requests、urllib等,来连接Web服务,并将GPS数据上传到服务器端。
GPS调试需要把天线放室外,否则很难定位,我这里是带着笔记本跑到了室外。
- 2023-05-21
-
发表了主题帖:
【得捷电子Follow me第1期】第三帖 连接网络获取天气预报
今天再更一期链接网络获取天气预报,也是跟着大佬步骤走
第一步是连接WiFi,我们可以通过Micropython库中的network和socket库实现Wi-Fi连接并获取IP地址。
我们需要使用pycopy_upip库安装network库,然后通过network.WLAN类,使用WLAN.STA模式连接Wi-Fi接入点,并使用socket库实现TCP/IP通信。
第二部获取天气预报。
可以使用Python的requests库(需要安装)访问天气预报API,然后解析返回的JSON数据。天气预报服务提供商的API可以提供当前天气、未来几天的天气和其他相关信息。我们这里使用高德的接口,然后使用Micropython库中的urllib库和JSON库来连接API并解析数据。
第三步因为我的oled有点问题,有需要的可以参照这个办法显示出来。
我们可以使用Pico W的SSD1306 OLED屏幕显示天气预报信息。我们可以使用Micropython的GPIO库来控制OLED屏幕,并使用SSD1306库来处理图形和字符。在OLED屏幕上,可以显示当前天气、温度、湿度、气压等等信息,以及未来几天的天气趋势。
由于考虑定位问题,这里直接通过网络获取公网IP,查询所在城市,在通过高德的接口获取到城市代码,从而实现自动获取所在地区的天气。
以下是代码:
import network
import socket
from time import sleep
from picozero import pico_temp_sensor, pico_led
import machine
import ubinascii
import urequests
import ujson
from machine import Pin
import time
from machine import PWM
from machine import I2C
from ssd1306 import SSD1306_I2C
ssid = '汤圆和奶茶'
password = 'tangyuan888'
TEMP = "12"
HUMI = "13"
def connect():
#Connect to WLAN
wlan = network.WLAN(network.STA_IF)
wlan.active(True)
wlan.connect(ssid, password)
while wlan.isconnected() == False:
print('Waiting for connection...')
sleep(1)
print(wlan.ifconfig())
ip = wlan.ifconfig()[0]
print(f'Connected on {ip}')
def open_socket():
ip = urequests.get('http://ip.42.pl/raw')
ip_str = ip.content.decode('ascii')
print(ip_str)
ip.close()
str_data = 'https://restapi.amap.com/v3/ip?ip='+ip_str+'&output=JSON&key=1e459c41f6b32822efa6442e74ca09c0'
city = urequests.get(str_data)
city_str = city.content.decode('ascii')
#print(city_str)
parsed_city = ujson.loads(city_str)
adcode = parsed_city["adcode"]
city.close()
r = urequests.get('https://restapi.amap.com/v3/weather/weatherInfo?key=1e459c41f6b32822efa6442e74ca09c0&city='+adcode)
w_str = r.content.decode('ascii')
print(r.text)
#print(w_str)
parsed_w = ujson.loads(w_str)
#print (parsed_w)
#w_f = parsed_w["temperature"]
temp_str = parsed_w["lives"][0]["temperature_float"]
humi_str = parsed_w["lives"][0]["humidity_float"]
global TEMP
TEMP = temp_str
global HUMI
HUMI = humi_str
#print(parsed_w["lives"][0]["temperature"])
print (temp_str)
print (humi_str)
#print (parsed_wf)
r.close()
WIDTH = 128
HEIGHT = 64
i2c = I2C(1)
#oled = SSD1306_I2C(WIDTH, HEIGHT, i2c)
try:
connect()
open_socket()
while True:
time.sleep(0.1)
#oled.fill(0)
TEMP_disp = "temp:"+TEMP
#oled.text(TEMP_disp,5,10)
HUMI_disp = "humi:"+HUMI
#oled.text(HUMI_disp,5,30)
#oled.show()
except KeyboardInterrupt:
machine.reset()
现象如下:
-
发表了主题帖:
【得捷电子Follow me第1期】第二帖 驱动外设:OLED、蜂鸣器
昨天安装环境弄完了,今天再驱动外设就很简单。参考大佬给的文档,我们也做做试验。
一、驱动蜂鸣器
参考raspberry-pi-pico-python-sdk.pdf的3.8. PWM
我们将蜂鸣器接到如下位置左边第三个
蜂鸣器的SIG对应GP16
编写如下代码,通过修改占空比实现蜂鸣器响度的控制
# Example using PWM to fade an BEEP.
import time
from machine import Pin, PWM
# Construct PWM object, with BEEP on Pin(16).
pwm = PWM(Pin(16))
# Set the PWM frequency.
pwm.freq(1000)
# Fade the BEEP in and out a few times.
duty = 0
direction = 1
for _ in range(8 * 256):
duty += direction
if duty > 255:
duty = 255
direction = -1
elif duty < 0:
duty = 0
direction = 1
pwm.duty_u16(duty * duty)
time. Sleep(0.001)
运行代码可以听到蜂鸣器响度逐渐变化。
二、驱动OLED
oled接到I2C0处
刚开始以为copy大佬代码就可以,没想到出错了,忘了安装外设的环境,需要添加一些库。
参考大佬的调教教程继续安装库。
驱动OLED
在包管理器搜索驱动ssd1306
选择安装micropython-ssd1306,安装完毕,在lib目录可以看到ssd1306.py了
下载库不成功可以添加驱动代码
https://github.com/stlehmann/micropython-ssd1306/blob/master/ssd1306.py
Thonny中创建ssd1306.py复制上述文件内容保存到pico中。
# MicroPython SSD1306 OLED driver, I2C and SPI interfaces
from micropython import const
import framebuf
# register definitions
SET_CONTRAST = const(0x81)
SET_ENTIRE_ON = const(0xA4)
SET_NORM_INV = const(0xA6)
SET_DISP = const(0xAE)
SET_MEM_ADDR = const(0x20)
SET_COL_ADDR = const(0x21)
SET_PAGE_ADDR = const(0x22)
SET_DISP_START_LINE = const(0x40)
SET_SEG_REMAP = const(0xA0)
SET_MUX_RATIO = const(0xA8)
SET_COM_OUT_DIR = const(0xC0)
SET_DISP_OFFSET = const(0xD3)
SET_COM_PIN_CFG = const(0xDA)
SET_DISP_CLK_DIV = const(0xD5)
SET_PRECHARGE = const(0xD9)
SET_VCOM_DESEL = const(0xDB)
SET_CHARGE_PUMP = const(0x8D)
# Subclassing FrameBuffer provides support for graphics primitives
# http://docs.micropython.org/en/latest/pyboard/library/framebuf.html
class SSD1306(framebuf.FrameBuffer):
def __init__(self, width, height, external_vcc):
self.width = width
self.height = height
self.external_vcc = external_vcc
self.pages = self.height // 8
self.buffer = bytearray(self.pages * self.width)
super().__init__(self.buffer, self.width, self.height, framebuf.MONO_VLSB)
self.init_display()
def init_display(self):
for cmd in (
SET_DISP | 0x00, # off
# address setting
SET_MEM_ADDR,
0x00, # horizontal
# resolution and layout
SET_DISP_START_LINE | 0x00,
SET_SEG_REMAP | 0x01, # column addr 127 mapped to SEG0
SET_MUX_RATIO,
self.height - 1,
SET_COM_OUT_DIR | 0x08, # scan from COM[N] to COM0
SET_DISP_OFFSET,
0x00,
SET_COM_PIN_CFG,
0x02 if self.width > 2 * self.height else 0x12,
# timing and driving scheme
SET_DISP_CLK_DIV,
0x80,
SET_PRECHARGE,
0x22 if self.external_vcc else 0xF1,
SET_VCOM_DESEL,
0x30, # 0.83*Vcc
# display
SET_CONTRAST,
0xFF, # maximum
SET_ENTIRE_ON, # output follows RAM contents
SET_NORM_INV, # not inverted
# charge pump
SET_CHARGE_PUMP,
0x10 if self.external_vcc else 0x14,
SET_DISP | 0x01,
): # on
self.write_cmd(cmd)
self.fill(0)
self.show()
def poweroff(self):
self.write_cmd(SET_DISP | 0x00)
def poweron(self):
self.write_cmd(SET_DISP | 0x01)
def contrast(self, contrast):
self.write_cmd(SET_CONTRAST)
self.write_cmd(contrast)
def invert(self, invert):
self.write_cmd(SET_NORM_INV | (invert & 1))
def show(self):
x0 = 0
x1 = self.width - 1
if self.width == 64:
# displays with width of 64 pixels are shifted by 32
x0 += 32
x1 += 32
self.write_cmd(SET_COL_ADDR)
self.write_cmd(x0)
self.write_cmd(x1)
self.write_cmd(SET_PAGE_ADDR)
self.write_cmd(0)
self.write_cmd(self.pages - 1)
self.write_data(self.buffer)
class SSD1306_I2C(SSD1306):
def __init__(self, width, height, i2c, addr=0x3C, external_vcc=False):
self.i2c = i2c
self.addr = addr
self.temp = bytearray(2)
self.write_list = [b"\x40", None] # Co=0, D/C#=1
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.temp[0] = 0x80 # Co=1, D/C#=0
self.temp[1] = cmd
self.i2c.writeto(self.addr, self.temp)
def write_data(self, buf):
self.write_list[1] = buf
self.i2c.writevto(self.addr, self.write_list)
class SSD1306_SPI(SSD1306):
def __init__(self, width, height, spi, dc, res, cs, external_vcc=False):
self.rate = 10 * 1024 * 1024
dc.init(dc.OUT, value=0)
res.init(res.OUT, value=0)
cs.init(cs.OUT, value=1)
self.spi = spi
self.dc = dc
self.res = res
self.cs = cs
import time
self.res(1)
time.sleep_ms(1)
self.res(0)
time.sleep_ms(10)
self.res(1)
super().__init__(width, height, external_vcc)
def write_cmd(self, cmd):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(0)
self.cs(0)
self.spi.write(bytearray([cmd]))
self.cs(1)
def write_data(self, buf):
self.spi.init(baudrate=self.rate, polarity=0, phase=0)
self.cs(1)
self.dc(1)
self.cs(0)
self.spi.write(buf)
self.cs(1)
测试
复制EEWORLDLINKTK1下的测试代码
# Display Image & text on I2C driven ssd1306 OLED display
from machine import Pin, I2C
from ssd1306 import SSD1306_I2C
import framebuf
WIDTH = 128 # oled display width
HEIGHT = 64 # oled display height
i2c = I2C(0) # Init I2C using I2C0 defaults, SCL=Pin(GP9), SDA=Pin(GP8), freq=400000
#print("I2C Address : "+hex(i2c.scan()[0]).upper()) # Display device address
#print("I2C Configuration: "+str(i2c)) # Display I2C config
oled = SSD1306_I2C(WIDTH, HEIGHT, i2c) # Init oled display
# Raspberry Pi logo as 32x32 bytearray
buffer = bytearray(b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00|?\x00\x01\x86@\x80\x01\x01\x80\x80\x01\x11\x88\x80\x01\x05\xa0\x80\x00\x83\xc1\x00\x00C\xe3\x00\x00~\xfc\x00\x00L'\x00\x00\x9c\x11\x00\x00\xbf\xfd\x00\x00\xe1\x87\x00\x01\xc1\x83\x80\x02A\x82@\x02A\x82@\x02\xc1\xc2@\x02\xf6>\xc0\x01\xfc=\x80\x01\x18\x18\x80\x01\x88\x10\x80\x00\x8c!\x00\x00\x87\xf1\x00\x00\x7f\xf6\x00\x008\x1c\x00\x00\x0c \x00\x00\x03\xc0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
# Load the raspberry pi logo into the framebuffer (the image is 32x32)
fb = framebuf.FrameBuffer(buffer, 32, 32, framebuf.MONO_HLSB)
# Clear the oled display in case it has junk on it.
oled.fill(0)
# Blit the image from the framebuffer to the oled display
oled.blit(fb, 96, 0)
# Add some text
oled.text("Raspberry Pi",5,5)
oled.text("Pico",5,15)
# Finally update the oled display so the image & text is displayed
oled.show()
Thonny中创建oled1.py复制上述文件内容保存到pico中。
运行
可以看到oled显示如下
- 2023-05-17
-
发表了主题帖:
【得捷电子Follow me第1期】第一贴:开箱+驱动+点亮LED
首先,感谢 Digi-Key 联合 EEWORLD 发起的这次活动,第一次做测评还是很有意思的~
1
一、开箱
今天是 5 月 17 号,其实快递 5 月 13 号都到了,这两天工作太忙,没时间写开箱,不过录了个小视频,大家可以来看看。
8.48 seb:/ 树莓派 PICO W,Esp8266 替代,你玩过吗?# 嵌入式 # c 语言 # 单片机 # 计算机 # 物联网 https://v.douyin.com/UjSoEpj/ ( https://v.douyin.com/UjSoEpj/ ) 复制此链接,打开 Dou 音搜索,直接观看视频!
二、驱动
买的板子不自带 usb 线,我就拿了我自己 ESP8266 得烧录线,反正接口都一样,先拿过来用吧!
连接好树莓派发现没有驱动,随即看前辈写好的帖子看经验,http://bbs.eeworld.com.cn/thread-1239338-1-1.html,这位大佬把资料都准备好了,那我就找找看用哪个可以把驱动装上 ( http://bbs.eeworld.com.cn/thread-1239338-1-1.html,这位大佬把资料都准备好了,那我就找找看用哪个可以把驱动装上 )。
打开了一遍,发现“pico w 介绍网站”是有教学的,“这个网站”里面是驱动固件,则按照教程开始装驱动。
这个是教程:
https://picockpit.com/raspberry-pi/zh/%e5%85%b3%e4%ba%8e%e6%a0%91%e8%8e%93%e6%b4%be%e7%9a%84%e4%b8%80%e5%88%87-pico-w/#Raspberry_Pi_Pico_W_pinout
所以,只需要将 UF2 固件下载之后,按住 BOOTSEL 按钮,放到这个文件夹里就行。下面是下载网址:
https://micropython.org/download/rp2-pico-w/
下载这个固件
经过一通操作,果然 COM 口出来了。
三、点亮 LED
下面我们继续跟着教程,下载 Thonny IDE 软件,点亮 LED。
打开网址,这个提示真的 dhsfouadshfdafhdsjlakf!!!
继续点击下载
下载成功继续安装
打开软件,可以把语言改为中文和初始化改为树莓派
打开可以看到我们的开发界面
直接把大佬的代码复制一下,看看是不是能跑成功
import machineimport timeled = machine.Pin('LED', machine.Pin.OUT)while (True): led.on() time.sleep(.2) led.off() time.sleep(.2)
这里是右下角没有选择我们的开发板,改成我们的开发板
再点击运行测试
成功,开发板 LED 在闪烁!!!
代码效果就是 led 间隔 0.2s blingbling 的,效果如下。
- 2023-04-25
-
加入了学习《开源PWM机械臂(Arduion版本)》,观看 Arduino之点亮1个LED(一)
-
加入了学习《开源PWM机械臂(Arduion版本)》,观看 资料导读
-
加入了学习《开源PWM机械臂(51版本)》,观看 51机械臂 - 图形化调试总线舵机机械臂
-
加入了学习《开源PWM机械臂(51版本)》,观看 51机械臂 - 图形化调试机械臂加mp3语音
-
加入了学习《开源PWM机械臂(51版本)》,观看 51单片机之数字传感器应用(避障+循迹+声音+光敏+震动+触摸)
-
加入了学习《开源PWM机械臂(51版本)》,观看 51单片机之PS2手柄解析控制马达