For this week's individual assignment we were asked to add an output device to a microcontroller board that I designed and program it to do something. Here you can see the group task
This week in Fabacademy, I established communication between an Attiny45, with a PCB designed and made during week 11, and a Xiao RP2040, whose board was manufactured in the electronics production week. Through UART, I transferred data from an ultrasonic sensor processed by the Attiny45 to the Xiao RP2040, allowing the received values to display on the Arduino serial monitor.
Networking protocols like I2C (Inter-Integrated Circuit) and UART (Universal Asynchronous Receiver-Transmitter) are key to facilitating communication between microcontrollers and peripheral devices in embedded systems. I2C is a single-ended, packet-switched serial bus supporting multiple devices and controllers. It operates with two bidirectional open-drain lines, for data (SDA) and clock (SCL), making it well-suited for sensor networks due to its simplicity and efficiency. I2C also supports multiple controller devices through addressing, allowing several devices to communicate without complex wiring.
UART, on the other hand, is a hardware-based protocol for asynchronous communication with adjustable speed. Unlike I2C, UART only needs two wires for data transfer: transmit (TX) and receive (RX). This enables direct, bidirectional communication across devices, making UART particularly useful for longer-distance communication and for connecting with serial peripherals like GPS or Bluetooth modules. Though UART doesn’t require a clock line, both devices must match in baud rate, data format, and error-checking setup. While I2C is more suitable for short-distance, complex communication between multiple devices, UART excels at simple, point-to-point communication over longer distances. Both protocols are foundational in embedded systems and offer unique benefits depending on application needs.
Other important protocols in embedded systems include SPI (Serial Peripheral Interface) and CAN (Controller Area Network). SPI provides high-speed, synchronous serial communication over short distances using four lines (SCK, MOSI, MISO, and CS) and is valued for its speed and ease in connecting multiple devices. CAN, widely used in automotive and industrial applications, is a robust protocol that enables reliable communication between microcontrollers without needing a host, supporting real-time data transmission with error correction. This makes CAN ideal for environments that require high reliability and fault tolerance.
To start practicing and understanding the language more I was looking at several song options which I was playing with and it was very helpful to me since I understood them from the examples I had, although it was a bit difficult for me. Here was where I found some examples for arduino
To start programming my code, I first needed to know what the natural scale and its semitones were, the times of the musical notes and the frequencies with which I am going to work (the same notes in different octaves will cause the frequency to change. )
First I declare the pin which to use and create variables with each of the notes and their respective frequency depending on what octave my song is in
I will also program the timing of the notes so I can make the song sound good. I will define the constants in which I will create functions for the white notes, quarter notes, eighth notes and sixteenth notes so as not to avoid writing the time values of each note in the code
I will use the SPEED_FACTOR functions to control the speed at which notes are played. and I will give the value of 0.5 which means that all notes will be played at 50% of their original duration, speeding up playback.
I will also use playNote for the function that will be responsible for playing a note or producing silence for a period of specified time.
I will use the tone function to generate the sound on a specific pin (SPEAKER_PIN).
I will also use delay to wait for the duration of the note set by SPEED_FACTOR.s
The value in the rhythm array is a number that represents a fraction of an EIGHTH_NOTE. Multiplying rhythm[i] by EIGHTH_NOTE gives the correct duration in milliseconds for the desired note.
Now that all the constants and pins are defined correctly, I will add the melody and rhythm to the code.
I will create a for loop that will loop through each note in the melody array and its corresponding duration in the rhythm array.
For each iteration of the loop, the playNote function is called with two arguments which are: the frequency of the note (melody[i]) and the duration in milliseconds (rhythm[i] * EIGHTH_NOTE).