Seeed Studio XIAO RA4M1 com MicroPython
MicroPython é um interpretador Python com um recurso parcial de compilação de código nativo. Ele fornece um subconjunto de recursos do Python 3.5, implementado para processadores embarcados e sistemas com recursos limitados. É diferente do CircuitPython e você pode ler mais sobre as diferenças na documentação do MicroPython.
Usando MicroPython com XIAO RA4M1
A seguir, vou guiá-lo sobre como usar MicroPython no XIAO MG24 Senese e programá-lo com o Thonny IDE, com base no sistema operacional Windows.
Preparação de Hardware
| Seeed Studio XIAO RA4M1 | Seeed Studio XIAO Debug Mate |
|---|---|
![]() | ![]() |
Instalar o Thonny IDE
Escolha a versão apropriada para instalação. Aqui, estou instalando em um sistema Windows, então selecionei a versão para Windows.
Siga as instruções para a versão desejada do Python.

Depois, basta seguir as etapas padrão para configuração.
Baixar o repositório
Clone-o para a máquina local e, em seguida, lembre-se do caminho onde este MicroPython do XIAO RA4M1 está armazenado. Esse caminho será usado mais tarde.
git clone https://github.com/Seeed-Studio/micropython-seeed-boards.git
Exemplo de Piscar LED
Aqui vamos mostrar como acender o USER LED no XIAO MG24 usando MicroPython com Thonny IDE.
Etapa 1. Gravar o firmware MicroPython
-
Baixe o pacote XIAO RA4M1 MicroPython Firmware e extraia-o no local apropriado. Em seguida, abra o terminal nesta pasta.
-
Insira o XIAO RA4M1 no XIAO XIAO Debug Mate.

- Clique em xiao_ra4m1_flash.bat e aguarde a conclusão da programação.

- Para Mac / Linux
sudo chmod +x xiao_ra4m1_flash.sh && ./xiao_ra4m1_flash.sh
Este script possui comandos de toolchain de gravação pré-configurados. Se você estiver usando-o pela primeira vez, isso pode levar um pouco de tempo.
Após terminar de programar o firmware, você precisa desconectar o XIAO RA4M1 do XIAO XIAO XIAO Debug Mate e conectá-lo via USB-C.
Etapa 2. Configuração do Interpretador
Abra o Thonny IDE e clique no canto inferior direito da interface para configurar as opções do interpretador. Selecione MicroPython (generic) e a Porta. Após a configuração bem-sucedida, as informações da versão do MicroPython serão exibidas no Shell.

Etapa 3. Fazer upload do arquivo de placas
- Abra a visualização, selecione File e o caminho do gerenciador de arquivos será exibido na barra lateral esquerda.

- Abra o caminho do arquivo clonado ou baixado e abra
micropython-seeed-boards-master\examples-Há vários arquivos Python do xiao na pasta boards, mas a capacidade da memória flash do XIAO RAM41 é limitada, então você só precisa manter dois arquivos:xiao.pyexiao_ra4m1.py.

- Selecione a pasta boards e faça o upload para a flash. Em seguida, você conseguirá ver o arquivo enviado no dispositivo/flash MicroPython.

Etapa 4. Executar o Código
Clique em File -> New para criar um novo arquivo e salve-o como blink.py.
import time
from boards.xiao import XiaoPin
led = "led"
try:
# Initialize LED
led = XiaoPin(led, XiaoPin.OUT)
while True:
# LED 0.5 seconds on, 0.5 seconds off
led.value(1)
time.sleep(0.5)
led.value(0)
time.sleep(0.5)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
except Exception as e:
print("\nError occurred: %s" % {e})
finally:
led.value(1)
Explicação do Código:
-
Importar Módulos
timeImporta o módulo de tempoXiao PinImporta a classe de controle de pinos para a placa de desenvolvimento Seeed Xiao a partir do módulo boards.xiao, que é usada para operar os pinos na placa.
-
Definir Pinos
led = "led""Especifica que o pino está conectado ao pinoledda placa de desenvolvimento (aqui, o pino USER)
-
Lógica Principal (bloco try)
- O USER LED piscará em intervalos de 0,5 segundos.
Copie o código acima, depois clique no botão verde ou pressione F5 para executá-lo.

Assim que o código começar a ser executado, o USER LED piscará em intervalos de 0,5 segundos.
O resultado é o seguinte:

Exemplo de PWM
No XIAO RA4M1, os pinos D5–D10 suportam a função PWM. Vamos apresentar como usar a função PWM com um exemplo de luz respiratória PWM.
Preparação de Hardware
| Seeed Studio XIAO RA4M1 | Seeed Studio Grove Base for XIAO | Grove - Variable Color LED |
|---|---|---|
![]() | ![]() | ![]() |
Software
- Crie um novo arquivo chamado pwm.py e copie o código de referência para ele.
- Como apenas os pinos D5–D10 do XIAO RA4M1 suportam a função PWM, o pino D9 é selecionado aqui.
import time
from boards.xiao import XiaoPWM
led = 9 #D9
try:
# set the frequency and period of the PWM signal
FREQ = 1000
PERIOD_NS = int(1_000_000_000 // FREQ)
# set the number of steps to fade the LED and the delay between steps
FADE_STEPS = 255
STEP_DELAY = 0.01
STEP_SIZE = 3
# initialize the PWM with a frequency and a 0% duty cycle
pwm = XiaoPWM(led)
pwm.init(freq=FREQ, duty=0)
while True:
# fade the LED in and out
for fade in range(0, FADE_STEPS + 1, STEP_SIZE):
duty_ns = int((fade * PERIOD_NS) / FADE_STEPS)
if duty_ns < 20:
duty_ns = 20
elif duty_ns > 960000:
duty_ns = 960000
pwm.duty_ns(duty_ns)
time.sleep(STEP_DELAY)
# fade the LED in and out again
for fade in range(FADE_STEPS, -1, -STEP_SIZE):
duty_ns = int((fade * PERIOD_NS) / FADE_STEPS)
if duty_ns < 20:
duty_ns = 20
elif duty_ns > 960000:
duty_ns = 960000
pwm.duty_ns(duty_ns)
time.sleep(STEP_DELAY)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
except Exception as e:
print("\nError occurred: %s",repr(e))
finally:
if pwm is not None:
try:
pwm.deinit()
except Exception:
pass
Explicação do código:
-
Importar módulos
time: Importa o módulo de tempo padrão para lidar com atrasos (usado para controlar a velocidade do efeito de respiração).XiaoPWM: Importa a classe de controle PWM (Modulação por Largura de Pulso) do móduloboards.xiao, usada para gerar sinais semelhantes a analógicos no pino digital.
-
Definir pinos e constantes
PIN = 0: Especifica que o dispositivo está conectado ao pino D0 na placa de desenvolvimento. -FREQ / PERIOD_NS: Define a frequência PWM para 1000 Hz e calcula o período total em nanossegundos (1 segundo / 1000).FADE_STEPS / STEP_DELAY: Configura a resolução da animação (255 passos) e a velocidade (espera de 0,01 s entre as mudanças).
-
Lógica principal (bloco try)
- Inicialização: O código inicializa o objeto PWM no pino D0 começando com 0% de brilho (ciclo de trabalho).
- Loop de respiração: Dentro do loop infinito
while True, dois loopsforcontrolam o brilho do LED:- Aumentar brilho (Fade In): Aumenta gradualmente o
duty_ns(largura de pulso) de 0 até a duração total do período. - Diminuir brilho (Fade Out): Diminui gradualmente o
duty_nsdo período completo de volta para 0.
- Aumentar brilho (Fade In): Aumenta gradualmente o
-
Cálculo do ciclo de trabalho: A fórmula
(fade * PERIOD_NS) // FADE_STEPSmapeia o passo do loop (0-255) para o tempo em nanossegundos necessário para o hardware PWM.- Segurança/Limpeza: O bloco
finallygarante quepwm.deinit()seja chamado para liberar os recursos de hardware se o programa for interrompido (por exemplo, via Ctrl+C).
- Segurança/Limpeza: O bloco
Gráfico de resultado
Depois que o programa for executado, o LED terá um efeito de fade, e você pode ajustar o tamanho do passo de PWM de acordo com suas necessidades reais.

Exemplo analógico
A placa de desenvolvimento XIAO RA4M1 possui ADC de 12 bits para leitura de alta resolução de valores de sensores analógicos, o que pode nos ajudar a ler valores mais precisos.
Em seguida, escolheremos dois sensores para refletir as características do ADC.
Preparação de hardware
| Seeed Studio XIAO RA4M1 | Seeed Studio Grove Base for XIAO | Grove - Variable Color LED | Grove-Rotary Angle Sensor |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Software
- Crie um novo arquivo chamado adc.py e copie o código de referência para ele.
import time
from boards.xiao import XiaoPin, XiaoADC, XiaoPWM
adc_pin = 0 #D0
pwm_pin = 9 #D9
try:
adc = XiaoADC(adc_pin)
pwm = XiaoPWM(pwm_pin)
FREQ = 1000
PERIOD_NS = 1000000000 // FREQ
pwm.freq(FREQ)
pwm.duty_ns(0)
MAX_VOLTAGE = 3.3
DEAD_ZONE = 0.02
last_duty = -1
while True:
raw_value = adc.read_u16()
voltage = (raw_value / 65535.0) * MAX_VOLTAGE
# Calculate the base percentage (0.0 - 1.0)
duty_percent = voltage / MAX_VOLTAGE
# scope limitation
if duty_percent < 0: duty_percent = 0
if duty_percent > 1: duty_percent = 1
if abs(duty_percent - last_duty) < DEAD_ZONE:
time.sleep(0.05)
continue
inverted_duty = 1.0 - duty_percent
duty_ns = int(inverted_duty * PERIOD_NS)
if duty_ns < 20: duty_ns = 20
elif duty_ns > (PERIOD_NS * 0.96): duty_ns = int(PERIOD_NS * 0.96)
pwm.duty_ns(duty_ns)
print("Voltage: {:.2f}V, Brightness: {:.1f}%".format(voltage, duty_percent * 100))
last_duty = duty_percent
time.sleep(0.05)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
except Exception as e:
print("\nError occurred: {}".format(e))
finally:
pwm.deinit()
-
Importar módulos
time: Importa o módulo de tempo padrão para lidar com atrasos (usado para controlar a velocidade do efeito de respiração).XiaoPWM: Importa a classe de controle PWM (Modulação por Largura de Pulso) do móduloboards.xiao, usada para gerar sinais semelhantes a analógicos no pino digital. Explicação do código:
-
Importar módulos
time: Importa o módulo de tempo padrão para lidar com atrasos (usado para controlar a taxa de amostragem do loop).XiaoADC,XiaoPWM: Importa as classes de controle de hardware do móduloboards.xiao.XiaoADClida com a entrada analógica (potenciômetro) eXiaoPWMlida com a saída de modulação por largura de pulso (LED).
-
Definir pinos e constantes
adc_pin = 0/pwm_pin = 1: Mapeia os pinos físicos. O pino D0 é usado para o sensor de entrada e o pino D1 é usado para o LED de saída.FREQ / PERIOD_NS: Define a frequência de operação do PWM para 1000 Hz e calcula a duração do período em nanossegundos (1.000.000 ns).MAX_VOLTAGE / DEAD_ZONE: Define a tensão de referência (3,3 V) e uma zona morta de 2% para filtrar ruído elétrico e evitar que o LED pisque.
-
Lógica principal (bloco try)
- Inicialização: Configura os objetos ADC e PWM. O PWM começa com um ciclo de trabalho de 0.
- Loop de controle: Dentro do loop
while True, o código monitora continuamente o sensor:- Ler e normalizar: Lê o inteiro bruto de 16 bits (0-65535) do ADC e o converte em uma tensão de ponto flutuante (0,0 V - 3,3 V).
- Filtro de jitter: Compara a leitura atual com
last_duty. Se a mudança for menor queDEAD_ZONE, o loop ignora a atualização para manter a estabilidade.
-
Cálculo do ciclo de trabalho e inversão de lógica
- Lógica ativa em nível baixo (Active Low): A linha
inverted_duty = 1.0 - duty_percentinverte a lógica. - Motivo: Seu LED provavelmente é Active Low (conectado ao VCC).
- Efeito: À medida que a tensão aumenta,
duty_nsse torna menor (mantendo o pino em nível LOW por mais tempo), tornando o LED mais brilhante.
- Lógica ativa em nível baixo (Active Low): A linha
-
Limites de segurança (Safety Clamps): O código limita o sinal de saída entre um mínimo de 20 ns e um máximo de 96% do período. Isso protege o hardware e garante que o sinal permaneça dentro de uma faixa válida.
-
Saída e limpeza
- Feedback: Imprime a tensão atual e a porcentagem de brilho no console usando
.format()para compatibilidade com versões mais antigas do MicroPython. - Safety/Cleanup: O bloco
finallygarante quepwm.deinit()seja executado quando o programa parar, desligando com segurança os recursos de hardware de PWM.
- Feedback: Imprime a tensão atual e a porcentagem de brilho no console usando
Gráfico de resultado
- Gire o Grove-Rotary Angle Sensor e o brilho do LED mudará de acordo.

- A janela Shell também imprimirá a tensão e a porcentagem de brilho.

Exemplo de UART
UART é um dos protocolos de comunicação mais comumente usados. Ele permite a transmissão de dados com apenas duas linhas de dados, e seu baixo custo faz com que seja amplamente utilizado em muitos campos. A seguir, demonstraremos a aplicação da comunicação serial tomando como exemplo a transmissão de dados de um módulo GPS.
Preparação de hardware
| Seeed Studio XIAO RA4M1 | L76K GNSS Module for Seeed Studio XIAO |
|---|---|
![]() | ![]() |
Software
- Crie um novo arquivo chamado uart.py e copie o código de referência para ele.
Reference Code
from boards.xiao import XiaoUART
import time
import math
uart = "uart1"
baudrate = 9600
tx = 6 # D6
rx = 7 # D7
# Coordinate structure
class Coordinates:
def __init__(self, Lon=0.0, Lat=0.0):
self.Lon = Lon
self.Lat = Lat
# GPS data structure
class GNRMC:
def __init__(self):
self.Lon = 0.0 # GPS Longitude
self.Lat = 0.0 # GPS Latitude
self.Lon_area = '' # E or W
self.Lat_area = '' # N or S
self.Time_H = 0 # Time Hour
self.Time_M = 0 # Time Minute
self.Time_S = 0 # Time Second
self.Status = 0 # 1: Successful positioning, 0: Positioning failed
# Convert WGS-84 to GCJ-02
def transformLat(x, y):
ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * math.sqrt(abs(x))
ret += (20.0 * math.sin(6.0 * x * pi) + 20.0 * math.sin(2.0 * x * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(y * pi) + 40.0 * math.sin(y / 3.0 * pi)) * 2.0 / 3.0
ret += (160.0 * math.sin(y / 12.0 * pi) + 320 * math.sin(y * pi / 30.0)) * 2.0 / 3.0
return ret
# Convert WGS-84 to GCJ-02
def transformLon(x, y):
ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * math.sqrt(abs(x))
ret += (20.0 * math.sin(6.0 * x * pi) + 20.0 * math.sin(2.0 * x * pi)) * 2.0 / 3.0
ret += (20.0 * math.sin(x * pi) + 40.0 * math.sin(x / 3.0 * pi)) * 2.0 / 3.0
ret += (150.0 * math.sin(x / 12.0 * pi) + 300.0 * math.sin(x / 30.0 * pi)) * 2.0 / 3.0
return ret
# Convert GCJ-02 to BD-09
def bd_encrypt(gg):
bd = Coordinates()
x = gg.Lon
y = gg.Lat
z = math.sqrt(x * x + y * y) + 0.00002 * math.sin(y * x_pi)
theta = math.atan2(y, x) + 0.000003 * math.cos(x * x_pi)
bd.Lon = z * math.cos(theta) + 0.0065
bd.Lat = z * math.sin(theta) + 0.006
return bd
# Convert WGS-84 to GCJ-02
def transform(gps):
gg = Coordinates()
dLat = transformLat(gps.Lon - 105.0, gps.Lat - 35.0)
dLon = transformLon(gps.Lon - 105.0, gps.Lat - 35.0)
radLat = gps.Lat / 180.0 * pi
magic = math.sin(radLat)
magic = 1 - ee * magic * magic
sqrtMagic = math.sqrt(magic)
dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi)
dLon = (dLon * 180.0) / (a / sqrtMagic * math.cos(radLat) * pi)
gg.Lat = gps.Lat + dLat
gg.Lon = gps.Lon + dLon
return gg
# Convert to Baidu coordinates (BD-09)
def L76X_Baidu_Coordinates(gps):
wgs84_coords = Coordinates(gps.Lon, gps.Lat)
gcj02_coords = transform(wgs84_coords)
bd09_coords = bd_encrypt(gcj02_coords)
return bd09_coords
# Convert to Google coordinates (GCJ-02)
def L76X_Google_Coordinates(gps):
wgs84_coords = Coordinates(gps.Lon, gps.Lat)
gcj02_coords = transform(wgs84_coords)
return gcj02_coords
# Parse GNRMC NMEA sentence
def parse_gnrmc(nmea_sentence):
gps = GNRMC()
if not nmea_sentence.startswith(b'$GNRMC') and not nmea_sentence.startswith(b'$PNRMC'):
return gps
try:
# Convert to string and split by commas
sentence_str = nmea_sentence.decode('ascii', 'ignore')
fields = sentence_str.split(',')
if len(fields) < 12:
return gps
# Parse time field (HHMMSS.sss)
if fields[1]:
time_str = fields[1]
if '.' in time_str:
time_str = time_str.split('.')[0]
if len(time_str) >= 6:
gps.Time_H = int(time_str[0:2]) + 8 # GMT+8
gps.Time_M = int(time_str[2:4])
gps.Time_S = int(time_str[4:6])
if gps.Time_H >= 24:
gps.Time_H -= 24
# Parse status
gps.Status = 1 if fields[2] == 'A' else 0
if gps.Status == 1:
# Parse latitude (DDMM.MMMMM)
if fields[3] and fields[4]:
lat_str = fields[3]
if '.' in lat_str:
degrees = float(lat_str[0:2])
minutes = float(lat_str[2:])
gps.Lat = degrees + minutes / 60.0
gps.Lat_area = fields[4]
# Parse longitude (DDDMM.MMMMM)
if fields[5] and fields[6]:
lon_str = fields[5]
if '.' in lon_str:
degrees = float(lon_str[0:3])
minutes = float(lon_str[3:])
gps.Lon = degrees + minutes / 60.0
gps.Lon_area = fields[6]
except Exception as e:
print("Parse error:", e)
return gps
# Print formatted GPS data
def print_gps_data(gps):
print("\n--- GPS Data ---")
print("Time (GMT+8): {:02d}:{:02d}:{:02d}".format(gps.Time_H, gps.Time_M, gps.Time_S))
if gps.Status == 1:
print("Latitude (WGS-84): {:.6f} {}".format(gps.Lat, gps.Lat_area))
print("Longitude (WGS-84): {:.6f} {}".format(gps.Lon, gps.Lon_area))
# Coordinate conversion
baidu_coords = L76X_Baidu_Coordinates(gps)
google_coords = L76X_Google_Coordinates(gps)
print("Baidu Latitude: {:.6f}".format(baidu_coords.Lat))
print("Baidu Longitude: {:.6f}".format(baidu_coords.Lon))
print("Google Latitude: {:.6f}".format(google_coords.Lat))
print("Google Longitude: {:.6f}".format(google_coords.Lon))
print("GPS positioning successful.")
else:
print("GPS positioning failed or no valid data.")
try:
uart = XiaoUART(uart, baudrate, tx, rx)
# Initialize UART
uart.init(9600, bits=8, parity=None, stop=1)
# Buffer to accumulate complete messages
buffer = bytearray()
# Constants for coordinate transformation
pi = 3.14159265358979324
a = 6378245.0
ee = 0.00669342162296594323
x_pi = 3.14159265358979324 * 3000.0 / 180.0
while True:
available = uart.any()
if available > 0:
# Read all available bytes
data = uart.read(available)
buffer.extend(data)
# Check if we have a complete line (ends with newline)
if b'\n' in buffer:
# Find the newline position
newline_pos = buffer.find(b'\n')
# Extract the complete message
complete_message = buffer[:newline_pos + 1]
# Remove the processed part from buffer
buffer = buffer[newline_pos + 1:]
# Parse GNRMC sentences
if complete_message.startswith(b'$GNRMC') or complete_message.startswith(b'$PNRMC'):
gps_data = parse_gnrmc(complete_message)
print_gps_data(gps_data)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
except Exception as e:
print("\nError occurred: %s" % {e})
finally:
uart.deinit()
Explicação do código:
-
Importar módulos
XiaoUARTImporta a classe de comunicação UART para a placa de desenvolvimento Seeed Xiao a partir do móduloboards.xiao, usada para inicializar e controlar a comunicação serial.timeImporta o módulo de tempo para oferecer suporte a funções relacionadas a temporização (embora não seja usado diretamente aqui, é importado para uso futuro em potencial ou compatibilidade).mathImporta funções matemáticas (sin,cos,sqrt,atan2, etc.) necessárias para algoritmos de transformação de coordenadas.
-
Definir Configuração de UART
uart = "uart1"Especifica a instância do controlador UART a ser usada — aqui,uart1.baudrate = 9600Define a taxa de transmissão para comunicação serial em 9600 bps.tx = 6Especifica que o pino de transmissão UART (TX) está conectado ao pino digital D6.rx = 7Especifica que o pino de recepção UART (RX) está conectado ao pino digital D7.
-
Definir Estruturas de Dados
- Classe
Coordinates: Um contêiner simples para armazenar valores de longitude/latitude como números de ponto flutuante. - Classe
GNRMC: Representa dados de GPS analisados a partir de uma sentença NMEA$GNRMC. Contém:- Latitude/Longitude em graus decimais
- Indicadores de hemisfério (
N/S,E/W) - Hora (hora, minuto, segundo — ajustada para GMT+8)
- Flag de status (1 = correção válida, 0 = sem correção)
- Classe
-
Funções de Transformação de Coordenadas
transformLat(x, y)&transformLon(x, y)— Funções auxiliares que implementam parte do algoritmo de conversão WGS-84 → GCJ-02 (usado na China para ofuscação de mapas).bd_encrypt(gg)— Converte coordenadas GCJ-02 para o sistema de coordenadas BD-09 da Baidu aplicando deslocamento e rotação adicionais.transform(gps)— Função principal que converte coordenadas WGS-84 (GPS bruto) para GCJ-02 usando fórmulas trigonométricas complexas baseadas no modelo elíptico da Terra.L76X_Baidu_Coordinates(gps)— Wrapper que converte GPS bruto (WGS-84) → GCJ-02 → BD-09 (formato do Baidu Maps).L76X_Google_Coordinates(gps)— Wrapper que converte GPS bruto (WGS-84) → GCJ-02 (formato do Google Maps na China).
-
Analisar Sentença GNRMC
parse_gnrmc(nmea_sentence)— Analisa uma string NMEA bruta$GNRMCou$PNRMCem um objetoGNRMCestruturado.- Extrai a hora (converte de UTC para GMT+8).
- Verifica o status (
A= correção ativa/válida,V= inválida). - Analisa latitude/longitude do formato DDMM.MMMMM → graus decimais.
- Retorna o objeto
GNRMCpreenchido ou um objeto vazio padrão se a análise falhar.
-
Exibir Dados de GPS Formatados
print_gps_data(gps)— Imprime informações de GPS legíveis por humanos incluindo:- Hora local (GMT+8)
- Coordenadas WGS-84 brutas com hemisfério
- Coordenadas convertidas GCJ-02 (compatíveis com Google) e BD-09 (compatíveis com Baidu)
- Mensagem de status indicando se o posicionamento foi bem-sucedido
-
Lógica Principal (bloco try)
- Inicializa a interface UART com os parâmetros especificados.
- Define constantes globais necessárias para a matemática de coordenadas (
pi,a,ee,x_pi) — parâmetros do elipsoide da Terra e fatores de escala. - Entra em um loop infinito para ler continuamente os dados de GPS recebidos via UART.
- Usa
bufferpara acumular mensagens parciais até que uma linha completa (terminada com\n) seja recebida. - Quando uma linha completa chega:
- Verifica se ela começa com
$GNRMCou$PNRMC - Se sim, a analisa usando
parse_gnrmc() - Exibe a saída formatada via
print_gps_data()
- Verifica se ela começa com
- Usa
- Trata exceções:
KeyboardInterrupt: Sai graciosamente ao pressionar Ctrl+C.Exceptiongeral: Captura e imprime quaisquer erros inesperados.
- Por fim, chama
uart.deinit()para liberar os recursos de UART antes de sair.
Gráfico de resultado
- Abra qualquer ferramenta de porta serial e defina a taxa de transmissão para 9600.
- O módulo GPS deve ser usado em uma área externa aberta.
- O programa imprimirá as informações de GPS da sua localização.

Exemplo I2C
O XIAO RAM41 possui uma interface I2C que pode ser usada para transmissão e análise de dados de muitos sensores, bem como para o uso de telas OLED.
Preparação de Hardware
| Seeed Studio XIAO RA4M1 | Base de Expansão Seeed Studio para XIAO com Grove OLED |
|---|---|
![]() | ![]() |
Software
- Crie um novo arquivo chamado i2c.py e copie o código de referência nele.
Código de Referência
import time
from boards.xiao import XiaoI2C
sda = 4 #D4
scl = 5 #D5
i2c = "i2c0"
frq = 400000
i2c = XiaoI2C(i2c, sda, scl, frq)
# Basic 8x8 font
font_data = {
' ': [0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00],
'D': [0x78,0x44,0x42,0x42,0x42,0x44,0x78,0x00],
'E': [0x7C,0x40,0x40,0x78,0x40,0x40,0x7C,0x00],
'H': [0x44,0x44,0x44,0x7C,0x44,0x44,0x44,0x00],
'L': [0x40,0x40,0x40,0x40,0x40,0x40,0x7C,0x00],
'O': [0x3C,0x42,0x42,0x42,0x42,0x42,0x3C,0x00],
'R': [0x7C,0x42,0x42,0x7C,0x48,0x44,0x42,0x00],
'W': [0x42,0x42,0x42,0x42,0x5A,0x66,0x42,0x00],
}
# Write a single command byte to SSD1306 via I2C
def ssd1306_write_command(cmd):
i2c.writeto(0x3C, bytes([0x00, cmd]))
# Write multiple command bytes to SSD1306 via I2C
def ssd1306_write_commands(cmds):
data = bytearray([0x00] + list(cmds))
i2c.writeto(0x3C, data)
# Write display data bytes to SSD1306 via I2C
def ssd1306_write_data(data):
buffer = bytearray(len(data) + 1)
buffer[0] = 0x40
buffer[1:] = data
i2c.writeto(0x3C, buffer)
# Clear the entire SSD1306 display
def ssd1306_clear():
ssd1306_write_commands(bytearray([0x21, 0, 127]))
ssd1306_write_commands(bytearray([0x22, 0, 7]))
empty_data = bytearray(128)
for _ in range(8):
ssd1306_write_data(empty_data)
ssd1306_write_commands([0x21, 0, 127])
# Initialize SSD1306 display with recommended settings
def ssd1306_init():
commands = [
bytearray([0xAE]),
bytearray([0xD5, 0x80]),
bytearray([0xA8, 63]),
bytearray([0xD3, 0x00]),
bytearray([0x40]),
bytearray([0x8D, 0x14]),
bytearray([0x20, 0x00]),
bytearray([0xA1]),
bytearray([0xC8]),
bytearray([0xDA, 0x12]),
bytearray([0x81, 0xCF]),
bytearray([0xD9, 0xF1]),
bytearray([0xDB, 0x40]),
bytearray([0xA4]),
bytearray([0xA6]),
bytearray([0xAF])
]
for cmd in commands:
ssd1306_write_commands(cmd)
ssd1306_clear()
print("SSD1306 initialized successfully")
ssd1306_write_commands([0x21, 0, 127])
# Draw a string of text at specified column and page (row) on SSD1306
def ssd1306_draw_text(text, x, y):
ssd1306_write_commands(bytearray([0x21, x, x + len(text) * 8 - 1]))
ssd1306_write_commands(bytearray([0x22, y, y + 0]))
display_data = bytearray()
for char in text:
font_bytes = font_data.get(char.upper(), font_data[' '])
for col in range(7, -1, -1):
val = 0
for row in range(8):
if font_bytes[row] & (1 << col):
val |= (1 << row)
display_data.append(val)
ssd1306_write_data(display_data)
try:
i2c_addr = i2c.scan()
if 0x3C not in i2c_addr:
raise Exception("SSD1306 not found on I2C bus")
else:
print("SSD1306 found on I2C bus: 0x3C")
# Initialize display
ssd1306_init()
ssd1306_draw_text("HELLO WORLD", 20, 4)
while True:
time.sleep(1)
except KeyboardInterrupt:
print("\nProgram interrupted by user")
except Exception as e:
print("\nError occurred: %s" % {e})
Explicação do Código:
-
Importar Módulos
time: Importa o módulo padrão de tempo para lidar com pausas e atrasos do programa (usado aqui para owhileloop sleep).XiaoI2C: Importa a classe I2C específica de hardware deboards.xiao, que lida com o protocolo de comunicação de baixo nível para a placa de desenvolvimento XIAO.
-
Definir Configuração de I2C
sda = 4,scl = 5: Atribui as linhas de dados (SDA) e clock (SCL) do I2C aos pinos digitais D4 e D5, respectivamente. -i2c = "i2c0": Seleciona o barramento periférico I2C de hardware específico (barramento 0) no microcontrolador.frq = 400000: Define a velocidade de comunicação para 400 kHz (Modo Rápido), permitindo atualizações rápidas da tela.i2c = XiaoI2C(...): Instancia o objeto I2C com as configurações de pinos e frequência definidas.
-
Definir Dados de Fonte
font_data: Um dicionário atuando como uma tabela de consulta. Ele mapeia caracteres (como 'H', 'E') para uma lista de 8 bytes hexadecimais. Esses bytes representam a máscara de bits para os pixels desse caractere em uma grade 8x8.
-
Funções Auxiliares (Driver de Baixo Nível)
ssd1306_write_command(cmd): Envia uma única instrução de controle para o display. Ela prefixa o byte com0x00, informando ao controlador SSD1306 que o byte seguinte é um comando, não dados de pixel.ssd1306_write_commands(cmds): Envia de forma eficiente uma sequência de comandos de configuração em uma única transação I2C para minimizar a sobrecarga.ssd1306_write_data(data): Envia dados gráficos para a RAM da tela. Ele prefixa os dados com0x40, indicando que os bytes seguintes representam pixels que devem ser acesos.
-
Funções Auxiliares (Controle de Alto Nível)
ssd1306_clear(): Limpa o conteúdo da tela. Define o endereço de coluna (0-127) e o endereço de página (0-7) para cobrir a tela inteira e, em seguida, grava zeros (pixels em branco) em cada posição de memória.ssd1306_init(): Envia uma sequência rigorosa de códigos hexadecimais (por exemplo,0xAEpara desligar o display,0x8D 0x14para ativar a bomba de carga) para configurar a tensão do painel OLED, a direção de varredura e o modo de endereçamento antes de ligá‑lo.ssd1306_draw_text(text, x, y): A função gráfica principal.- Ela define a janela de desenho na tela usando os comandos
0x21(Endereço de Coluna) e0x22(Endereço de Página). - Ela itera pela string de entrada, obtém os bytes da fonte e executa operações bit a bit (
val |= (1 << row)) para transpor/rotacionar os dados de modo a corresponder à estrutura de memória específica do SSD1306.
-
Lógica Principal (Fluxo de Execução)
i2c.scan(): Detecta todos os dispositivos conectados ao barramento I2C para garantir que a fiação esteja correta.- Validação de Endereço: Verifica se o display está presente no endereço
0x3C. Se não for encontrado, gera um erro para interromper a execução; caso contrário, imprime uma confirmação. ssd1306_init(): Ativa o display e aplica as configurações.ssd1306_draw_text("HELLO WORLD", 20, 4): Renderiza o texto "HELLO WORLD" começando na coluna de pixel 20 na página 4 (aproximadamente no meio à esquerda da tela).while True: Entra em um loop infinito que dorme por 1 segundo repetidamente, mantendo o programa em execução para que o display permaneça ativo.try...except: Envolve a lógica principal em um manipulador de erros para capturar problemas (como hardware ausente) ou uma interrupção do usuário (Ctrl+C), garantindo que o programa seja encerrado graciosamente com uma mensagem legível.
Gráfico de resultado
- Assim que o programa começar a ser executado, ele exibirá HELLO WORLD na tela.

Resumo
Parabéns! Tendo concluído os tutoriais acima, você adquiriu a capacidade de desenvolvimento e depuração básicos com o XIAO RA4M1 e MicroPython. Estamos ansiosos para ver você criar projetos mais interessantes com base nessas habilidades fundamentais
Suporte Técnico e Discussão de Produtos
Obrigado por escolher nossos produtos! Estamos aqui para fornecer diferentes tipos de suporte para garantir que sua experiência com nossos produtos seja a mais tranquila possível. Oferecemos vários canais de comunicação para atender a diferentes preferências e necessidades.






