12. Output devices¶
Individual Assignment:
- Add an output device to a microcontroller board you’ve designed, and program it to do something
Group Assignment:
- Measure the power consumption of an output device
Design¶
I decided to choose the SSD1306 OLED display as it would be useful for displaying information for my final project. In addition, the display uses I2C communications, so I connected the SCL and SDA pins of the display to the corresponding pins on the ATTiny412 MCU. These pins are reserved for the faster hardware I2C support.
I utilized the same 1/64 Bantam Tools DRC file and autorouter to generate the traces.
However, Mr. Rudolph recommended some changes to the board design. He advised that I should have pull-up resistors on the SCL and SDA lines and the capacitor next to the VCC and ground of the MCU.
Here is the milled board:
Soldering¶
I first soldered the board with the OLED display soldered directly to the SMD pads. For the pullup resistors, I searched online and found an answer that said that 4.99K resistors generally work, so I sued 4.99K resistors.
However, I realized that the SCL and SDA pads were flipped, so I was forced to solder on right angle pins to use jumper wire. In addition, I looked at Neil’s board design and saw that he used 10K pull-up resistors, so I switched out the 4.99K resistors for 10K resistors.
Programming¶
Programming was the most difficult part as I had no experience with interfacing through I2C. First, I tried Neil’s code, but Neil’s code was written for the ATTiny45s and it was incompatable with the new tinyAVR 1-series.
Next, I tried external libraries. The first library that I tried was the Adafruit SSD1306 library. However, the Adafruit library was too large to fit onto the memory of the ATTiny412.
The next library that I tried was the u8g2 library. The u8g2 library encountered the same size issues as the Adafruit library.
With little options left, I decided to bite the bullet and attempt to port Neil’s code over to the ATTiny412 MCU. I first tried to make changes in the register defines as the compiler complained about invalid register names. The changes did not cause the OLED display to display anything.
#define SCL_pin (1 << 2)
#define SCL_pins PORTA.IN
#define SCL_port PORTA.OUT
#define SCL_direction PORTA.DIR
#define SDA_pin (1 << 1)
#define SDA_pins PORTA.IN
#define SDA_port PORTA.OUT
#define SDA_direction PORTA.DIR
Next, I replaced the macros used to manipulate the registers. The result did not change.
//ATTiny 412 Macros
#define outputT412(bit_mask) PORTA.DIRSET |= bit_mask
#define inputT412(bit_mask) PORTA.DIRCLR |= bit_mask
#define setT412(bit_mask) VPORTA.OUT |= bit_mask
#define clearT412(bit_mask) VPORTA.OUT &= (~bit_mask)
#define pin_testT412(bit_mask) VPORTA.IN & bit_mask
Meanwhile, I realized that I had not changed the defined I2C address of the display. It had been set to 0x3C
, but the display’s address was 0x78
. However, this did not fix the issue.
//#define I2C_slave_address 0x3C
//#define I2C_slave_address 0x3D
#define I2C_slave_address 0x78
//#define I2C_slave_address 0x7A
#define I2C_delay() _delay_us(5)
I began to surmise that Neil’s code was the software implementation of I2C since he directly manipulated the signals of the ports. Since I connected SCL and SDA to the hardware I2C pins, it made sense that I would have to utilise a special API for hardware I2C communications.
On the internet, I found an AVR Freaks thread where a forum member had shared several functions that utilised the TWI API.
Looking on the ATTiny412 datasheet, I realized that the TWI API was in fact the method to communicate over I2C.
I also realized that the I2C_master_write()
function was the main function to write bytes over the SDA and SCL ports. All other functions depended on the I2C_master_write()
function for sending display data, so I surmised that this function was the main culprit.
I decided to delete any old code relating to data writing, including the I2C_master_write()
function, and wrote the TWI_master_write()
function with the helper functions as the direct replacement. I replaced the logic and functions used within the I2C_master_write()
function with the equivalent functions from the forum member. In the OLED128x64init()
function, I changed the initialization function from I2C_init()
to TWI_init()
. Neil’s code to start I2C and send the slave address was replaced by a call to the TWI_start()
start that serves both purposes. Neil’s function to write individuals bits over the SDA and SCL lines was replaced with the equivalent TWI_write()
function. Neil’s code to stop the I2C transaction was replaced by the TWI_stop()
function.
#include <avr/io.h>
#include <util/delay.h>
#include <avr/pgmspace.h>
#include <stdlib.h>
#define I2C_slave_address 0x78
#define I2C_delay() _delay_us(5)
#define TWI0_BAUD(F_SCL) ((((float)F_CPU / (float)F_SCL)) - 10 )
void TWI_init()
{
TWI0.MBAUD = (uint8_t)TWI0_BAUD(100000); // Set MBAUD register for 100kHz
TWI0.MCTRLA = 1 << TWI_ENABLE_bp // Enable TWI Master: enabled
| 0 << TWI_QCEN_bp // Quick Command Enable: disabled
| 0 << TWI_RIEN_bp // Read Interrupt Enable: disabled
| 1 << TWI_SMEN_bp // Smart Mode Enable: enabled
| TWI_TIMEOUT_DISABLED_gc // Bus Timeout Disabled
| 0 << TWI_WIEN_bp; // Write Interrupt Enable: disabled
TWI0.MCTRLB |= TWI_FLUSH_bm; // Purge MADDR and MDATA
TWI0.MSTATUS |= TWI_BUSSTATE_IDLE_gc; // Force TWI state machine into IDLE state
TWI0.MSTATUS |= (TWI_RIF_bm | TWI_WIF_bm);
}
uint8_t TWI_start(uint8_t deviceAddr)
{
if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) != TWI_BUSSTATE_BUSY_gc) //Verify Bus is not busy
{
TWI0.MCTRLB &= ~(1 << TWI_ACKACT_bp);
TWI0.MADDR = deviceAddr ;
if (deviceAddr&0x01) {while(!(TWI0.MSTATUS & TWI_RIF_bm));} // If addressRead
else {while(!(TWI0.MSTATUS & TWI_WIF_bm));} // If addressWrite
return 0;
}
else return 1; // Bus is busy
}
uint8_t TWI_read(uint8_t ACK) // ACK=1 send ACK ; ACK=0 send NACK
{
if ((TWI0.MSTATUS & TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc) // Verify Master owns the bus
{
while(!(TWI0.MSTATUS & TWI_RIF_bm)); // Wait until RIF set
uint8_t data=TWI0.MDATA;
if(ACK==1) {TWI0.MCTRLB &= ~(1<<TWI_ACKACT_bp);} // If ACK=1 Put 0 ACKACT => action send ack
else {TWI0.MCTRLB |= (1<<TWI_ACKACT_bp); } // Else if (ACK=0) => put 1 ACKACT => nack prepared for actionstop
return data ;
}
else
return 1; //Master does not own the bus
}
uint8_t TWI_write(uint8_t write_data)
{
if ((TWI0.MSTATUS&TWI_BUSSTATE_gm) == TWI_BUSSTATE_OWNER_gc) // Verify Master owns the bus
{
TWI0.MDATA = write_data;
while (!((TWI0.MSTATUS & TWI_WIF_bm) | (TWI0.MSTATUS & TWI_RXACK_bm))); // Wait until WIF set and RXACK cleared
return 0;
}
else
return 1; // Master does not own the bus
}
void TWI_stop(void)
{
TWI0.MCTRLB |= TWI_ACKACT_NACK_gc;
TWI0.MCTRLB |= TWI_MCMD_STOP_gc;
}
// This function is central to I2C communications. Normal pin setting is replaced with TWI functions.
char TWI_master_write(unsigned char* data,unsigned char nbytes,unsigned char slave_address)
{
unsigned char index, ret, slave_address_write;
// Send start and send slave address
slave_address_write = slave_address << 1;
if (TWI_start(slave_address) != 0)
// No ACK,return 1
return 1;
// Loop over bytes
for (index = 0; index < nbytes; ++index) {
ret = TWI_write((data[index]));
if (ret != 0)
// No ACK, return 1
break;
// Yes ACK, continue
}
//Send stop
TWI_stop();
return ret;
}
static const uint8_t MonospaceBold7x8[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,223,223,0,0,0,0,7,0,7,0,0,32,228,62,231,124,39,4,0,76,154,255,154,112,0,39,37,23,232,168,228,0,0,112,247,159,241,192,240,0,0,0,7,0,0,0,0,0,24,126,195,0,0,0,0,195,126,24,0,0,0,18,12,63,12,18,0,0,16,16,124,16,16,0,0,128,112,48,0,0,0,0,0,48,48,48,0,0,0,0,192,192,0,0,0,0,0,192,56,6,1,0,0,126,255,129,137,255,126,0,129,129,255,255,128,128,0,129,193,161,153,143,134,0,129,137,137,137,247,118,0,48,44,38,255,255,32,0,143,143,137,137,249,113,0,124,255,139,137,249,112,0,1,129,241,125,31,3,0,118,247,137,137,247,118,0,14,159,145,209,255,62,0,0,204,204,0,0,0,0,0,204,204,0,0,0,0,48,48,120,72,72,204,0,40,40,40,40,40,40,0,204,72,72,120,48,48,0,2,217,215,7,0,0,124,130,57,69,69,254,0,0,192,252,47,47,252,192,0,255,255,137,137,247,118,0,60,126,195,129,129,66,0,255,255,129,129,255,60,0,255,255,137,137,137,129,0,255,255,9,9,9,1,0,60,126,195,145,241,242,0,255,255,8,8,255,255,0,129,129,255,255,129,129,0,64,128,129,129,255,127,0,255,255,24,62,227,193,0,255,255,128,128,128,128,0,255,254,28,28,254,255,0,255,255,14,112,255,255,0,126,255,129,129,255,126,0,255,255,17,17,31,14,0,126,255,129,129,255,126,0,255,255,17,17,111,206,128,78,143,153,153,241,114,0,1,1,255,255,1,1,0,127,255,128,128,255,127,0,3,63,240,240,63,3,15,255,240,12,240,255,15,0,129,231,60,60,231,129,0,1,15,252,252,15,1,0,193,225,185,141,135,131,0,0,255,255,129,0,0,0,1,6,56,192,0,0,0,0,129,255,255,0,0,4,6,3,3,6,4,0,128,128,128,128,128,128,128,0,1,3,2,0,0,0,0,96,244,148,148,252,248,0,255,255,136,136,248,112,0,120,252,204,132,132,132,0,112,248,136,136,255,255,0,120,252,148,148,156,152,0,8,254,255,9,9,0,0,28,190,162,162,254,126,0,255,255,8,8,248,240,0,136,136,251,251,128,128,0,136,136,251,123,0,0,0,255,255,16,124,196,128,1,1,127,255,128,128,0,0,252,252,4,252,4,252,0,252,252,4,4,252,248,0,120,252,132,132,252,120,0,254,254,34,34,62,28,0,28,62,34,34,254,254,0,0,252,252,4,4,4,0,88,156,180,180,228,104,4,4,255,255,132,132,0,0,124,252,128,128,252,252,0,12,124,224,224,124,12,12,252,224,16,224,252,12,0,132,204,120,120,204,132,0,130,142,248,56,14,2,0,196,228,164,148,156,140,0,16,16,239,239,129,129,0,0,0,255,0,0,0,0,129,129,239,239,16,16,0,16,16,16,32,32,32};
static const uint8_t MonospaceBold10x16lo[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,254,254,0,0,0,0,0,0,30,30,0,0,30,30,0,0,0,48,176,248,62,50,240,254,62,48,0,112,248,216,254,152,152,0,0,0,28,34,162,162,156,64,64,32,32,0,0,0,220,126,230,198,134,12,128,128,0,0,0,0,30,30,0,0,0,0,0,0,0,224,252,30,2,0,0,0,0,0,2,30,252,224,0,0,0,0,0,72,120,48,254,48,120,72,0,0,0,128,128,128,240,240,128,128,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,240,60,14,2,0,0,240,252,14,198,198,14,252,248,0,0,0,12,6,254,254,0,0,0,0,0,12,6,6,6,134,198,124,56,0,0,12,6,198,198,198,198,252,56,0,0,128,192,112,24,14,254,254,0,0,0,254,126,102,102,102,230,198,128,0,0,240,252,206,102,102,230,204,128,0,0,6,6,6,6,230,254,62,14,0,0,56,252,198,198,198,198,252,56,0,0,120,252,206,134,134,206,252,248,0,0,0,0,0,224,224,0,0,0,0,0,0,0,0,224,224,0,0,0,0,0,128,128,192,64,96,96,32,48,0,0,96,96,96,96,96,96,96,96,0,0,48,32,96,96,64,192,128,128,0,0,12,6,134,198,102,126,28,0,0,224,240,56,156,204,204,220,248,240,0,0,0,192,252,62,62,252,192,0,0,0,254,254,198,198,198,198,252,60,0,0,240,252,12,6,6,6,6,12,0,0,254,254,6,6,6,12,252,240,0,0,254,254,198,198,198,198,198,6,0,0,254,254,198,198,198,198,198,6,0,0,240,252,12,6,134,134,134,140,0,0,254,254,192,192,192,192,254,254,0,0,0,6,6,254,254,6,6,0,0,0,0,0,0,6,6,6,254,254,0,0,254,254,224,240,252,14,6,2,0,0,254,254,0,0,0,0,0,0,0,0,254,254,62,240,240,62,254,254,0,0,254,254,30,240,192,0,254,254,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,124,124,0,0,240,252,14,6,6,14,252,240,0,0,254,254,198,198,198,198,252,60,0,0,56,124,230,198,198,198,140,0,0,0,6,6,6,254,254,6,6,6,0,0,254,254,0,0,0,0,254,254,0,0,6,254,252,0,0,252,254,6,0,30,254,224,0,240,240,0,224,254,30,0,2,14,62,248,248,62,14,2,0,2,14,62,120,224,224,120,62,14,2,0,6,6,134,198,246,126,30,14,0,0,0,0,254,254,2,2,0,0,0,0,2,14,56,224,128,0,0,0,0,0,0,2,2,254,254,0,0,0,0,16,24,28,14,6,14,28,24,16,0,0,0,0,0,0,0,0,0,0,0,0,0,1,3,6,4,0,0,0,0,0,0,96,48,176,176,176,240,224,0,0,254,254,96,48,48,112,224,192,0,0,192,224,112,48,48,48,48,96,0,0,192,224,112,48,48,96,254,254,0,0,192,224,176,176,176,176,224,192,0,0,48,48,252,254,54,54,54,0,0,0,192,224,112,48,48,96,240,240,0,0,254,254,96,48,48,48,240,224,0,0,0,48,48,247,247,0,0,0,0,0,0,48,48,247,247,0,0,0,0,0,254,254,128,224,112,48,16,0,0,0,6,6,254,254,0,0,0,0,0,0,240,240,48,240,224,48,240,224,0,0,240,240,96,48,48,48,240,224,0,0,192,224,112,48,48,112,224,192,0,0,240,240,96,48,48,112,224,192,0,0,192,224,112,48,48,96,240,240,0,0,0,240,240,96,48,48,48,48,0,0,224,240,176,176,176,176,48,96,0,0,48,48,252,252,48,48,48,0,0,0,240,240,0,0,0,0,240,240,0,0,48,240,224,0,0,224,240,48,0,112,240,0,0,192,192,0,0,240,112,0,16,48,240,192,192,240,48,16,0,0,16,240,240,128,0,240,240,48,0,0,48,48,48,48,176,240,112,48,0,0,0,0,0,252,254,2,2,0,0,0,0,0,0,254,254,0,0,0,0,0,0,2,2,254,252,0,0,0,0,0,128,192,192,192,128,128,128,192,0,0,0,0,0};
static const uint8_t MonospaceBold10x16hi[] PROGMEM = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,25,25,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,27,31,3,3,31,15,3,3,0,0,12,24,24,127,25,31,15,0,0,1,1,0,0,14,17,17,17,14,0,0,7,15,28,24,25,31,30,31,19,0,0,0,0,0,0,0,0,0,0,0,0,0,7,63,120,64,0,0,0,0,0,64,120,63,7,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,1,1,1,15,15,1,1,1,0,0,0,0,64,124,60,0,0,0,0,0,0,3,3,3,3,3,0,0,0,0,0,0,0,28,28,0,0,0,0,0,32,56,30,7,1,0,0,0,0,0,3,15,28,24,24,28,15,7,0,0,24,24,24,31,31,24,24,24,0,0,24,28,30,27,25,24,24,24,0,0,12,24,24,24,24,25,15,15,0,0,3,3,3,3,3,31,31,3,0,0,12,24,24,24,24,28,15,7,0,0,7,15,28,24,24,28,15,7,0,0,0,16,28,15,3,0,0,0,0,0,15,15,24,24,24,24,15,15,0,0,0,12,25,25,25,28,15,3,0,0,0,0,0,28,28,0,0,0,0,0,0,0,64,124,60,0,0,0,0,0,1,1,3,2,6,6,4,12,0,0,6,6,6,6,6,6,6,6,0,0,12,4,6,6,2,3,1,1,0,0,0,0,27,27,0,0,0,0,0,7,31,56,115,103,102,102,119,39,0,0,24,31,15,3,3,15,31,24,0,0,31,31,24,24,24,24,31,15,0,0,3,15,12,24,24,24,24,12,0,0,31,31,24,24,24,12,15,3,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,0,0,0,0,0,0,0,3,15,12,24,25,25,31,15,0,0,31,31,0,0,0,0,31,31,0,0,0,24,24,31,31,24,24,0,0,0,12,24,24,24,24,24,15,15,0,0,31,31,0,0,3,15,30,24,0,0,31,31,24,24,24,24,24,24,0,0,31,31,0,1,1,0,31,31,0,0,31,31,0,0,3,30,31,31,0,0,3,15,28,24,24,28,15,3,0,0,31,31,0,0,0,0,0,0,0,0,3,15,28,24,24,60,111,7,0,0,31,31,0,0,1,3,31,30,16,0,12,24,24,24,24,25,15,15,0,0,0,0,0,31,31,0,0,0,0,0,7,15,28,24,24,28,15,7,0,0,0,0,31,31,31,31,0,0,0,0,31,31,30,1,1,30,31,31,0,0,16,28,31,3,3,31,28,16,0,0,0,0,0,31,31,0,0,0,0,0,28,30,31,27,24,24,24,24,0,0,0,0,127,127,64,64,0,0,0,0,0,0,0,0,3,14,56,32,0,0,0,64,64,127,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,31,27,25,25,13,31,31,0,0,31,31,12,24,24,28,15,7,0,0,7,15,28,24,24,24,24,12,0,0,7,15,28,24,24,12,31,31,0,0,7,15,29,25,25,25,25,13,0,0,0,0,31,31,0,0,0,0,0,0,7,111,220,216,216,204,255,127,0,0,31,31,0,0,0,0,31,31,0,0,24,24,24,31,31,24,24,24,0,0,192,192,192,255,127,0,0,0,0,0,31,31,1,3,7,30,24,16,0,0,0,0,15,31,24,24,24,0,0,0,31,31,0,31,31,0,31,31,0,0,31,31,0,0,0,0,31,31,0,0,7,15,28,24,24,28,15,7,0,0,255,255,12,24,24,28,15,7,0,0,7,15,28,24,24,12,255,255,0,0,0,31,31,0,0,0,0,0,0,0,12,25,25,25,25,27,31,14,0,0,0,0,15,31,24,24,24,0,0,0,15,31,24,24,24,12,31,31,0,0,0,1,15,30,30,15,1,0,0,0,7,31,30,3,3,30,31,7,0,0,16,24,30,7,7,30,24,16,0,0,0,192,195,255,63,15,1,0,0,0,24,28,30,27,25,24,24,24,0,0,0,1,1,126,254,128,128,0,0,0,0,0,0,255,255,0,0,0,0,0,0,128,128,254,126,1,1,0,0,0,1,0,0,0,1,1,1,0,0,0,0,0,0};
void OLEDcommand(uint8_t c) {
static uint8_t data[2];
data[0] = 0;
data[1] = c;
TWI_master_write(data,2,I2C_slave_address);
}
void OLEDcommands(uint8_t c1,uint8_t c2) {
static uint8_t data[3];
data[0] = 0;
data[1] = c1;
data[2] = c2;
TWI_master_write(data,3,I2C_slave_address);
}
void OLEDdata(uint8_t d) {
static uint8_t data[2];
data[0] = 0x40;
data[1] = d;
TWI_master_write(data,2,I2C_slave_address);
}
void OLED7x8string(uint8_t row,uint8_t col,char str[]) {
static uint8_t index,offset,pointer;
static char chr;
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 7; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold7x8[7*pointer+offset])));
}
++index;
}
}
void OLED10x16string(uint8_t row,uint8_t col,char str[]) {
static uint8_t index,offset,pointer;
static char chr;
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 10; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold10x16lo[10*pointer+offset])));
}
++index;
}
OLEDcommands(0x00+(col & 0x0F),0x10+((col >> 4) & 0x0F));
OLEDcommand(0xB0+row+1);
index = 0;
while (1) {
chr = str[index];
if (chr == '\0') break;
pointer = chr-' ';
for (offset = 0; offset < 10; ++offset) {
OLEDdata(pgm_read_byte(&(MonospaceBold10x16hi[10*pointer+offset])));
}
++index;
}
}
void OLED128x64init() {
uint8_t i,j;
//Init TWI
TWI_init();
//Init SSD1306
OLEDcommand(0xae); // Display off
OLEDcommands(0xa8,0x3f); // Set multiplex ratio, ratio 63
OLEDcommands(0xd3,0x00); // Set display offset, no offset
OLEDcommand(0x40); // Set display start line
OLEDcommand(0xa1); // Set segment remap col 127 to seg 0
OLEDcommand(0xc8); // Set COM output reverse
OLEDcommands(0xda,0x12); // COM pin config, alt bottom to top
OLEDcommands(0x81,0xff); // Set contrast, max contrast
OLEDcommand(0xa4); // Resume to RAM display
OLEDcommand(0xa6); // Normal non-inverted display
OLEDcommands(0xd5,0x80); // Set clock divider, default
OLEDcommands(0x8d,0x14); // Set charge pump, enable
OLEDcommands(0x20,0x02); // Set memory mode, page addressing
OLEDcommand(0xaf); // Display on
//
// clear screen
//
for (j = 0; j < 8; ++j) {
OLEDcommands(0x00,0x10);
OLEDcommand(0xB0+j);
for (i = 0; i < 128; ++i) OLEDdata(0);
}
}
uint16_t count = 0;
char str[3];
void setup() {
// Initialize OLED
OLED128x64init();
// Static text
OLED7x8string(0,0,"Hello World!");
OLED7x8string(1,28,"in a 7x8 font");
OLED10x16string(2,0,"Hello World!");
OLED10x16string(4,0,"in 10x16 font");
OLED10x16string(6,0,"Count:");
}
void loop() {
itoa(count,str,10);
OLED10x16string(6,60,str);
++count;
if (count == 1000) {
OLED10x16string(6,80," ");
count = 0;
}
}
After applying the changes, the screen finally displayed the Hello World code. Here is a video of the OLED in action:
This week will aid in the development of my final project because it allowed me to explore and sucessfully implement the I2C protocol on my boards. I am now more famaliar with master and slave communication which will enable me to create robust communications for other devices in my final projects. In addition, my experience with displaying text on the screen will help me to display information for my final project.