Multiplexación de pines con Seeed Studio XIAO RA4M1
Descripción general del hardware
Antes de empezar, es esencial conocer algunos parámetros básicos del producto. La siguiente tabla proporciona información sobre las características de Seeed Studio XIAO RA4M1.
Parte frontal

Parte trasera

Digital
El XIAO RA4M1 tiene hasta 11 pines GPIO normales, 6 pines analógicos y 8 puertos IO reutilizables en la parte posterior. En este ejemplo, utilizaremos el XIAO RA4M1, la placa de expansión XIAO y un relé para demostrar cómo usar diferentes pines digitales para lectura y escritura.
Preparación de hardware
| Seeed Studio XIAO R4M1 | Seeed Studio Expansion Base for XIAO with Grove OLED | Grove - Relay |
|---|---|---|
![]() | ![]() | ![]() |
Instala XIAO RA4M1 o Sense en la placa de expansión y conecta el relé a la interfaz A0/D0 de la placa de expansión mediante un cable Grove. Por último, conecta XIAO al ordenador mediante un cable USB-C.
Implementación de software
En este ejemplo, implementaremos el control del estado de encendido/apagado de un relé utilizando un botón conectado a la placa de expansión XIAO. Cuando se pulsa el botón, el relé se enciende y, cuando se suelta el botón, el relé se apaga.
const int buttonPin = D1; // the number of the pushbutton pin
int buttonState = 0; // variable for reading the pushbutton status
const int relayPin = D0;
void setup() {
// initialize the Relay pin as an output:
pinMode(relayPin, OUTPUT);
// initialize the pushbutton pin as an input:
pinMode(buttonPin, INPUT_PULLUP);
}
void loop() {
// read the state of the pushbutton value:
buttonState = digitalRead(buttonPin);
// check if the pushbutton is pressed. If it is, the buttonState is HIGH:
if (buttonState == HIGH) {
// turn Relay on:
digitalWrite(relayPin, HIGH);
} else {
// turn Relay off:
digitalWrite(relayPin, LOW);
}
}
Si todo va bien, después de cargar el programa deberías ver el siguiente efecto.

Digital como PWM
Todos los pines GPIO en XIAO RA4M1 admiten salida PWM. Por lo tanto, puedes usar cualquier pin para generar PWM y ajustar el brillo de las luces, controlar servos y otras funciones.
Preparación de hardware
| Seeed Studio XIAO RA4M1 | Seeed Studio Expansion Base for XIAO with Grove OLED | Grove - Variable Color LED |
|---|---|---|
![]() | ![]() | ![]() |
Instala XIAO RA4M1 o Sense en la placa de expansión y, a continuación, conecta el Variable Color LED a la interfaz A0/D0 de la placa de expansión utilizando un cable Grove. Por último, conecta XIAO a tu ordenador mediante un cable USB-C.
Implementación de software
En este ejemplo, mostraremos cómo utilizar la salida PWM para controlar el brillo de una luz.
int LED_pin = D0; // LED connected to digital pin 10
void setup() {
// declaring LED pin as output
pinMode(LED_pin, OUTPUT);
}
void loop() {
// fade in from min to max in increments of 5 points:
for (int fadeValue = 0 ; fadeValue <= 255; fadeValue += 3) {
// sets the value (range from 0 to 255):
analogWrite(LED_pin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
// fade out from max to min in increments of 5 points:
for (int fadeValue = 255 ; fadeValue >= 0; fadeValue -= 3) {
// sets the value (range from 0 to 255):
analogWrite(LED_pin, fadeValue);
// wait for 30 milliseconds to see the dimming effect
delay(30);
}
}
Si el programa se ejecuta correctamente, verás el siguiente efecto de funcionamiento.

Analógico
La placa de desarrollo XIAO RA4M1, que dispone de un ADC de hasta 14 bits para la lectura de alta resolución de valores de sensores analógicos, puede ayudarnos a leer valores más precisos. El convertidor analógico-digital (ADC) en una placa de desarrollo XIAO RA4M1, por defecto, tiene la resolución configurada a 10 bits, la cual se puede aumentar tanto a 12 bits como a 14 bits para mejorar la precisión en las lecturas analógicas.
Datos detallados según la precisión del ADC
- 10 bits: 0~1024
- 12 bits: 0~4096
- 14 bits: 0~16383
A continuación, elegiremos dos sensores para reflejar las características del ADC.
Preparación de hardware
| Seeed Studio XIAO RA4M1 | Grove-Variable Color LED | Grove-Rotary Angle Sensor | Seeed Studio Grove Base for XIAO |
|---|---|---|---|
![]() | ![]() | ![]() | ![]() |
Implementación de software
#define ADC_Bit_Fourteen 14
#define ADC_Bit_Twelve 12
#define ADC_Bit_Ten 10
const int analogInPin = A1; // Analog input pin that the potentiometer is attached to
const int analogOutPin = 9; // Analog output pin that the LED is attached to
int sensorValue = 0; // value read from the pot
int outputValue = 0; // value output to the PWM (analog out)
void setup() {
Serial.begin(115200);
// Ten_Bite_ADC_Config(); // 10bit
// Twelve_Bite_ADC_Config(); // 12bit
Fourteen_Bite_ADC_Config(); // 14bit
}
void loop() {
sensorValue = analogRead(analogInPin);
outputValue = map(sensorValue, 0, 4095, 0, 255);
analogWrite(analogOutPin, outputValue);
Serial.print("sensor = ");
Serial.print(sensorValue);
Serial.print("\t output = ");
Serial.println(outputValue);
delay(100);
}
void Ten_Bite_ADC_Config() {
analogReadResolution(ADC_Bit_Ten);
}
void Twelve_Bite_ADC_Config() {
analogReadResolution(ADC_Bit_Twelve);
}
void Fourteen_Bite_ADC_Config() {
analogReadResolution(ADC_Bit_Fourteen);
}
Si todo va bien, después de cargar el programa, deberías ver el siguiente efecto.

Serie
Al trabajar con Arduino IDE, la comunicación Serial es una parte esencial de muchos proyectos. Para usar Serial en Arduino IDE, debes comenzar abriendo la ventana del Monitor Serial. Esto se puede hacer haciendo clic en el icono Serial Monitor en la barra de herramientas o presionando la combinación de teclas Ctrl+Shift+M.
Uso general
Algunas de las funciones Serial más utilizadas incluyen:
Serial.begin()-- que inicializa la comunicación a una velocidad en baudios especificada;Serial.print()-- que envía datos al puerto Serial en un formato legible;Serial.write()-- que envía datos binarios al puerto Serial;Serial.available()-- que comprueba si hay algún dato disponible para ser leído desde el puerto Serial;Serial.read()-- que lee un solo byte de datos desde el puerto Serial;Serial.flush()-- que espera a que se complete la transmisión de los datos seriales salientes.
Al usar estas funciones Serial, puedes enviar y recibir datos entre la placa Arduino y tu ordenador, lo que abre muchas posibilidades para crear proyectos interactivos.
Aquí hay un programa de ejemplo:
void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
}
void loop() {
// send data to the serial port
Serial.println("Hello World!");
// read data from the serial port
if (Serial.available() > 0) {
// read the incoming byte:
char incomingByte = Serial.read();
// print the incoming byte to the serial monitor:
Serial.print("I received: ");
Serial.println(incomingByte);
}
// wait for a second before repeating the loop
delay(1000);
}
Uso de Serial1
De acuerdo con los diagramas de pines de XIAO RA4M1 anteriores para parámetros específicos, podemos observar que hay un pin TX y un pin RX. Esto es diferente de la comunicación serial, pero el uso también es muy similar, excepto que es necesario añadir algunos parámetros. Así que a continuación, utilizaremos los pines sacados por el chip para la comunicación serial.
#define BAUD 115200
void setup() {
Serial1.begin(BAUD);
}
void loop() {
if(Serial1.available() > 0)
{
char incominByte = Serial1.read();
Serial1.print("I received : ");
Serial1.println(incominByte);
}
delay(1000);
}
Uso de Software Serial
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX
void setup() {
// initialize serial communication
Serial.begin(9600);
while (!Serial);
// initialize software serial
mySerial.begin(9600);
}
void loop() {
// read data from software serial
if (mySerial.available()) {
char data = mySerial.read();
Serial.print("Received data: ");
Serial.println(data);
}
// write data to software serial
mySerial.print("Hello World!");
// wait for a second before repeating the loop
delay(1000);
}
En este programa, primero incluimos la biblioteca SoftwareSerial.h para usar software serial. Luego, creamos un nuevo objeto SoftwareSerial llamado mySerial usando los pines 2 y 3 como RX y TX, respectivamente.
En la función setup(), inicializamos tanto el serial por hardware (Serial.begin()) como el serial por software (mySerial.begin()).
En la función loop(), usamos la función mySerial.available() para comprobar si hay algún dato disponible para ser leído desde el serial por software. Si lo hay, leemos el byte entrante usando la función mySerial.read() y lo almacenamos en una variable llamada data. Luego usamos las funciones Serial.print() y Serial.println() para imprimir "Received data: " seguido del valor de data en el serial por hardware.
También usamos la función mySerial.print() para escribir "Hello World!" en el serial por software. Esto enviará los datos desde el XIAO al dispositivo conectado al puerto serial por software.
Finalmente, añadimos una función delay() para esperar un segundo antes de repetir el bucle.
IIC
XIAO RA4M1 tiene una interfaz I2C que se puede utilizar para la transmisión y el análisis de datos de muchos sensores, así como para usar algunas pantallas OLED.
Preparación de hardware
| Seeed Studio XIAO RA4M1 | Base de expansión Seeed Studio para XIAO con Grove OLED |
|---|---|
![]() | ![]() |
La pantalla OLED en la placa de expansión XIAO utiliza el protocolo I2C y está conectada a la interfaz I2C del XIAO a través del circuito I2C de la placa. Por lo tanto, podemos conectar directamente el XIAO a la placa de expansión y programarlo para mostrar contenido en la pantalla.
Implementación de software
Este ejemplo introduce cómo usar la pantalla OLED en la Base de expansión Seeed Studio para XIAO RA4M1.
Paso 1. Instala el Seeed Studio XIAO RA4M1 en la placa de expansión y luego conecta el cable Type-C
Paso 2. Instala la biblioteca u8g2
Paso 3. Copia el código y pégalo en el Arduino IDE y luego súbelo
#include <Arduino.h>
#include <U8x8lib.h>
#include <Wire.h>
U8X8_SSD1306_128X64_NONAME_HW_I2C u8x8(/* clock=*/ SCL, /* data=*/ SDA, /* reset=*/ U8X8_PIN_NONE); // OLEDs without Reset of the Display
void setup(void) {
u8x8.begin();
u8x8.setFlipMode(1); // set number from 1 to 3, the screen word will rotary 180
}
void loop(void) {
u8x8.setFont(u8x8_font_chroma48medium8_r);
u8x8.setCursor(0, 0);
u8x8.print("i'm XIAO RA4M1");
}
En las primeras líneas del código, incluimos las bibliotecas requeridas como Arduino.h, U8x8lib.h y Wire.h. La biblioteca U8x8lib.h proporciona funciones para controlar la pantalla OLED, y la biblioteca Wire.h proporciona funciones para la comunicación I2C.
En la función setup(), inicializamos la pantalla OLED usando la función u8x8.begin(). También configuramos el modo de giro de la pantalla usando la función u8x8.setFlipMode() para rotar la pantalla 180 grados.
En la función loop(), configuramos la fuente usando la función u8x8.setFont() y especificamos la posición del cursor en la pantalla usando la función u8x8.setCursor(). Finalmente, usamos la función u8x8.print() para mostrar la cadena "Hello World!" en la pantalla OLED.
Si subes un programa a XIAO RA4M1, verás contenido mostrado en la pantalla OLED de la placa de expansión.

SPI
El chip RA4M1 integra múltiples periféricos, incluido una interfaz SPI que se puede utilizar para conectar dispositivos SPI externos como memoria flash, pantallas, sensores y más. El XIAO RA4M1 también admite un modo de transferencia SPI de alta velocidad, que puede alcanzar una velocidad máxima de transferencia SPI de 80 MHz, satisfaciendo las necesidades de transferencia de datos de la mayoría de los dispositivos SPI.
Preparación de hardware
| Seeed Studio XIAO RA4M1 | Grove - OLED Display 1.12 (SH1107) V3.0 - SPI/IIC |
|---|---|
![]() | ![]() |
Después de preparar el hardware como se mencionó anteriormente, utiliza cables de puente para conectar la interfaz SPI del XIAO y el OLED. Consulta el siguiente diagrama para el método de cableado.
Implementación de software
A continuación, tomaremos el siguiente programa como ejemplo para introducir cómo utilizar la interfaz SPI para controlar la pantalla del OLED.
Instala la biblioteca u8g2.
#include <Arduino.h>
#include <U8g2lib.h>
#include <SPI.h>
#include <Wire.h>
U8G2_SH1107_128X128_1_4W_HW_SPI u8g2(U8G2_R3, /* cs=*/ D7, /* dc=*/ D4, /* reset=*/ D5);
void setup(void) {
u8g2.begin();
}
void loop(void) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_luBIS08_tf);
u8g2.drawStr(0,24,"Hello Seeed!");
} while ( u8g2.nextPage() );
}
En la función setup(), la clase U8G2_SH1107_128X128_1_4W_HW_SPI se instancia con los argumentos de constructor apropiados que especifican los pines utilizados para chip select (cs), data/command (dc) y reset. Luego, se llama a la función u8g2.begin() para inicializar la pantalla.
En la función loop(), la pantalla se actualiza con nuevo contenido utilizando las funciones u8g2.firstPage(), u8g2.setFont() y u8g2.drawStr(). La función u8g2.firstPage() configura el búfer de pantalla para escritura, mientras que u8g2.nextPage() muestra el contenido actualizado. El bucle do-while garantiza que el contenido se muestre continuamente hasta que el programa se detenga.
En general, este código demuestra cómo utilizar la biblioteca U8g2 para controlar una pantalla OLED y mostrar texto en ella.

CAN (Placa de expansión XIAO CAN Bus)
Preparación de hardware
| Seeed Studio XIAO RA4M1 | XIAO CAN Bus Expansion Board |
|---|---|
![]() | ![]() |
Paso 1. Prepara dos CAN Bus Breakout Board y XIAO RA4M1
Paso 2. Inserta estos dos XIAO RA4M1 por separado en la CAN Bus Breakout Board
Paso 3. Prepara la conexión con cables DuPont

Preparación de software
Proporcionamos una biblioteca de Arduino para la placa MCP2515.
La biblioteca incluye varios ejemplos, entre ellos:
- OBDII-PIDs - recuperar datos de la interfaz OBD-II
- send - enviar una trama al bus CAN
- recv - recibir una trama desde el bus CAN
- set_mask_filter_recv - recibir una trama desde el bus CAN con configuración de máscara y filtro
Implementación de software
No está permitido encender y descargar programas simultáneamente para dos XIAO RA4M1, ya que esto provocará errores al descargar por el puerto serie. Después de descargar uno, desconéctalo, luego enciende el otro XIAO RA4M1 para descargar el programa y, finalmente, enciende ambos al mismo tiempo para comprobar el mensaje del puerto serie
Código de escritura CAN
/* send a frame from can bus
CAN Baudrate,
#define CAN_5KBPS 1
#define CAN_10KBPS 2
#define CAN_20KBPS 3
#define CAN_25KBPS 4
#define CAN_31K25BPS 5
#define CAN_33KBPS 6
#define CAN_40KBPS 7
#define CAN_50KBPS 8
#define CAN_80KBPS 9
#define CAN_83K3BPS 10
#define CAN_95KBPS 11
#define CAN_100KBPS 12
#define CAN_125KBPS 13
#define CAN_200KBPS 14
#define CAN_250KBPS 15
#define CAN_500KBPS 16
#define CAN_666KBPS 17
#define CAN_1000KBPS 18
*/
#include <mcp_can.h>
#include <SPI.h>
/* Please modify SPI_CS_PIN to adapt to your board.
CANBed V1 - 17
CANBed M0 - 3
CAN Bus Shield - 9
CANBed 2040 - 9
CANBed Dual - 9
OBD-2G Dev Kit - 9
OBD-II GPS Kit - 9
Hud Dev Kit - 9
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
*/
#define SPI_CS_PIN D7
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while(!Serial);
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
// pinMode(A3, OUTPUT);
// digitalWrite(A3, HIGH);
// below code need for OBD-II GPS Dev Kit RP2040 version
// pinMode(12, OUTPUT);
// digitalWrite(12, HIGH);
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
{
Serial.println("CAN BUS FAIL!");
delay(100);
}
Serial.println("CAN BUS OK!");
}
unsigned char stmp[8] = {0, 1, 2, 3, 4, 5, 6, 7};
void loop()
{
CAN.sendMsgBuf(0x00, 0, 8, stmp);
delay(100); // send data per 100ms
}
// END FILE
Código de lectura CAN
/* receive a frame from can bus
CAN Baudrate,
#define CAN_5KBPS 1
#define CAN_10KBPS 2
#define CAN_20KBPS 3
#define CAN_25KBPS 4
#define CAN_31K25BPS 5
#define CAN_33KBPS 6
#define CAN_40KBPS 7
#define CAN_50KBPS 8
#define CAN_80KBPS 9
#define CAN_83K3BPS 10
#define CAN_95KBPS 11
#define CAN_100KBPS 12
#define CAN_125KBPS 13
#define CAN_200KBPS 14
#define CAN_250KBPS 15
#define CAN_500KBPS 16
#define CAN_666KBPS 17
#define CAN_1000KBPS 18
CANBed V1: https://www.longan-labs.cc/1030008.html
CANBed M0: https://www.longan-labs.cc/1030014.html
CAN Bus Shield: https://www.longan-labs.cc/1030016.html
OBD-II CAN Bus GPS Dev Kit: https://www.longan-labs.cc/1030003.html
*/
#include <SPI.h>
#include "mcp_can.h"
/* Please modify SPI_CS_PIN to adapt to your board.
CANBed V1 - 17
CANBed M0 - 3
CAN Bus Shield - 9
CANBed 2040 - 9
CANBed Dual - 9
OBD-2G Dev Kit - 9
OBD-II GPS Kit - 9
Hud Dev Kit - 9
Seeed Studio CAN-Bus Breakout Board for XIAO and QT Py - D7
*/
#define SPI_CS_PIN D7
MCP_CAN CAN(SPI_CS_PIN); // Set CS pin
void setup()
{
Serial.begin(115200);
while(!Serial);
// below code need for OBD-II GPS Dev Kit Atemga32U4 version
// pinMode(A3, OUTPUT);
// digitalWrite(A3, HIGH);
// below code need for OBD-II GPS Dev Kit RP2040 version
// pinMode(12, OUTPUT);
// digitalWrite(12, HIGH);
while (CAN_OK != CAN.begin(CAN_500KBPS)) // init can bus : baudrate = 500k
{
Serial.println("CAN BUS FAIL!");
delay(100);
}
Serial.println("CAN BUS OK!");
}
void loop()
{
unsigned char len = 0;
unsigned char buf[8];
if(CAN_MSGAVAIL == CAN.checkReceive()) // check if data coming
{
CAN.readMsgBuf(&len, buf); // read data, len: data length, buf: data buf
unsigned long canId = CAN.getCanId();
Serial.println("-----------------------------");
Serial.print("Get data from ID: ");
Serial.println(canId, HEX);
for(int i = 0; i<len; i++) // print the data
{
Serial.print(buf[i], HEX);
Serial.print("\t");
}
Serial.println();
}
}
// END FILE
En este ejemplo, necesitas soldar uno de los pines del terminal P1 de la placa de expansión CAN Bus. Solo entonces se puede utilizar cualquier velocidad; de lo contrario, solo puedes usar una tasa de baudios CAN por debajo de 125.

CAN (Otro transceptor)
Nos gustaría agradecer a Arduino por proporcionar los tutoriales y el código.
Preparación de hardware
El protocolo CAN requiere que el extremo emisor reciba el mensaje que envía. Simplemente conectar TX y RX no es suficiente para completar la comunicación; se debe conectar un transceptor para la comunicación. Aquí utilizamos el módulo divisor SN65HVD230 oficial de Arduino.
| 3.3 V | GND | D9(CANRX0) | D10 (CANTX0) |
|---|---|---|---|
| VCC | GND | CANRX | CANTX |
Preparación de software
Código de escritura CAN
/*
CANWrite
Write and send CAN Bus messages
See the full documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/can
*/
/**************************************************************************************
* INCLUDE
**************************************************************************************/
#include <Arduino_CAN.h>
/**************************************************************************************
* CONSTANTS
**************************************************************************************/
static uint32_t const CAN_ID = 0x20;
/**************************************************************************************
* SETUP/LOOP
**************************************************************************************/
void setup()
{
Serial.begin(115200);
while (!Serial) { }
if (!CAN.begin(CanBitRate::BR_250k))
{
Serial.println("CAN.begin(...) failed.");
for (;;) {}
}
}
static uint32_t msg_cnt = 0;
void loop()
{
/* Assemble a CAN message with the format of
* 0xCA 0xFE 0x00 0x00 [4 byte message counter]
*/
uint8_t const msg_data[] = {0xCA,0xFE,0,0,0,0,0,0};
memcpy((void *)(msg_data + 4), &msg_cnt, sizeof(msg_cnt));
CanMsg const msg(CanStandardId(CAN_ID), sizeof(msg_data), msg_data);
/* Transmit the CAN message, capture and display an
* error core in case of failure.
*/
if (int const rc = CAN.write(msg); rc < 0)
{
Serial.print ("CAN.write(...) failed with error code ");
Serial.println(rc);
for (;;) { }
}
/* Increase the message counter. */
msg_cnt++;
/* Only send one message per second. */
delay(1000);
}
Código de lectura CAN
/*
CANRead
Receive and read CAN Bus messages
See the full documentation here:
https://docs.arduino.cc/tutorials/uno-r4-wifi/can
*/
/**************************************************************************************
* INCLUDE
**************************************************************************************/
#include <Arduino_CAN.h>
/**************************************************************************************
* SETUP/LOOP
**************************************************************************************/
void setup()
{
Serial.begin(115200);
while (!Serial) { }
if (!CAN.begin(CanBitRate::BR_250k))
{
Serial.println("CAN.begin(...) failed.");
for (;;) {}
}
}
void loop()
{
if (CAN.available())
{
CanMsg const msg = CAN.read();
Serial.println(msg);
}
}
¿Cuándo necesito conectar la resistencia terminal?
-
- Comunicación a larga distancia: Si el bus CAN es largo (por ejemplo, más de 1 metro), se deben conectar resistencias terminales en ambos extremos del bus para evitar problemas de comunicación causados por la reflexión de la señal.
-
- Comunicación multinodo: Si se conectan múltiples nodos al mismo bus CAN, las resistencias terminales también son indispensables. Garantizan la estabilidad de la impedancia del bus, evitando así la distorsión de la señal.
¿Cuándo se puede desconectar la resistencia terminal?
-
- Comunicación a corta distancia: En algunas aplicaciones de corta distancia (generalmente menos de 1 metro), se pueden omitir las resistencias terminales porque el impacto de la reflexión de la señal en la comunicación es relativamente pequeño.
-
- Comunicación de un solo nodo: Si solo hay un nodo en el bus (como en un entorno de depuración) y la distancia es corta, la resistencia terminal se puede desconectar temporalmente.
| Resultado del código del emisor | Resultado del código del receptor |
|---|---|
![]() | ![]() |
Soporte técnico y debate sobre el producto
Gracias por elegir nuestros productos. Estamos aquí para ofrecerte diferentes tipos de soporte y garantizar que tu experiencia con nuestros productos sea lo más fluida posible. Ofrecemos varios canales de comunicación para adaptarnos a diferentes preferencias y necesidades.






_V3.0/img/10402050_Main-02.png)


