---
# System prepended metadata

title: Micro 2

---

# Micro 2
Stephen Cruz Wright
521476
Vladislav Serafimov
509761

## Assignment 1
### Task
• Connect 2 arduino’s with serial communication.
• Connect a potentiometer to each of the arduino’s (analogue input)
• Connect 4 led’s two each arduino.
• Result must be: give a 4 bit representation from the input from the other arduino. (So simultanious on both arduino’s)
### Steps taken:
1. Write a code to send a signal
2. Write a code to receive said signal from the other arduino (completing half duplex)
3. Complete the full duplex by combining sending and receiving in a single piece of code, running in paralell (when one turns off, the other reads)
![](https://i.imgur.com/W3SgZ0X.jpg)


### Half-duplex
Here we tested sending and receiving individually, kinda like unit testing, 
![](https://i.imgur.com/inidnH4.jpg)

#### Sending
![](https://i.imgur.com/LP6aVhM.jpg)
```c=
/*
 * main.c
 *
 * Created: 12/14/2022 8:04:15 AM
 *  Author: vladi
 */ 

#include <xc.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/io.h>

#define F_CPU 16000000L
#define BAUD 9600
#define VAL ((F_CPU/16/BAUD) - 1)

void initADC();

volatile int value = 1;

int main(void)
{
	//setup
	DDRD = (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
	PORTD |= (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
	_delay_ms(1000);
	PORTD ^= (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
 
	initUSART();
	initADC();
    while(1)
	{
		ADCSRA |= (1 << ADSC); //start conversion
		_delay_ms(20);
		
		
		
		int val = ADCH;
		
		// wait for previous transmission to be over
		while (!( UCSR0A & (1<<UDRE0)));
		UDR0 = val;
		
	}
}

void initADC(){
	//initializing ADC
	ADMUX = 0;
	ADMUX |= (1 << REFS0) | (1 << ADLAR); //using ADC5, AVref and left-adjusted result
	ADCSRA |= (1 << ADEN) | (0b111 << ADPS0); //enable ADC, interrupt and set prescaler to 128
	//DIDR0 |= (1 << ADC5D); //disable buffering for ADC5
}

void initUSART(){
	//Set baud rate 
	UBRR0H = (unsigned char)(VAL>>8);
	UBRR0L = (unsigned char)VAL;
	//Enable receiver and transmitter 
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	// Set frame format: 8data, 2stop bit 
	UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}

```

#### Receiving
in order for signal transferrence to be completed we needed to get the recieving up and running.
```c=
    /*
 *  main.c
 *  Author: Steve
 */ 
 #include <xc.h>
 #include <avr/interrupt.h>
 #include <util/delay.h>
 #include <avr/io.h>

 #define F_CPU 16000000L
 #define BAUD 9600
 #define VAL ((F_CPU/16/BAUD) - 1)

 void initADC();

 volatile int value = 1;

 int main(void)
 { 
 // Set pins 8 - 13 as outputs
 DDRD |= 0b11111100; // Set all pins as output
 // Turn off all LEDs
 initUSART();
 while (1) {
     
     while ( !(UCSR0A & (1<<RXC0)));
     
     int val = UDR0;
     PORTD = val;
 }
 }


 void initUSART(){
 //Set baud rate
 UBRR0H = (unsigned char)(VAL>>8);
 UBRR0L = (unsigned char)VAL;
 //Enable receiver and transmitter
 UCSR0B = (1<<RXEN0)|(1<<TXEN0);
 // Set frame format: 8data, 2stop bit
 UCSR0C = (1<<USBS0)|(3<<UCSZ00);
 }
 
```

### Duplex code
This code is almost the same as the transmitting code, but it runs on both devices and the two added lines make it receive as well as transmit. Both devices display the value they receive on `PORTD`.
```c=
/*
 * main.c
 *
 * Created: 12/14/2022 8:04:15 AM
 *  Author: vladi
 */ 

#include <xc.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <avr/io.h>

#define F_CPU 16000000L
#define BAUD 9600
#define VAL ((F_CPU/16/BAUD) - 1)

void initADC();

volatile int value = 1;

int main(void)
{
	//setup
	DDRD = (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
	PORTD |= (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
	_delay_ms(1000);
	PORTD ^= (1 << PORTD5) | (1 << PORTD4) | (1 << PORTD3) | (1 << PORTD2);
 
	initUSART();
	initADC();
    while(1)
	{
		ADCSRA |= (1 << ADSC); //start conversion
		_delay_ms(20);
		
		
		
		int val = ADCH;
		
		// wait for previous transmission to be over
		while (!( UCSR0A & (1<<UDRE0)));
		UDR0 = val;
		while (!( UCSR0A & (1<<UDRE0)));
		PORTD =  UDR0;
		
	}
}

void initADC(){
	//initializing ADC
	ADMUX = 0;
	ADMUX |= (1 << REFS0) | (1 << ADLAR); //using ADC5, AVref and left-adjusted result
	ADCSRA |= (1 << ADEN) | (0b111 << ADPS0); //enable ADC, interrupt and set prescaler to 128
	//DIDR0 |= (1 << ADC5D); //disable buffering for ADC5
}

void initUSART(){
	//Set baud rate 
	UBRR0H = (unsigned char)(VAL>>8);
	UBRR0L = (unsigned char)VAL;
	//Enable receiver and transmitter 
	UCSR0B = (1<<RXEN0)|(1<<TXEN0);
	// Set frame format: 8data, 2stop bit 
	UCSR0C = (1<<USBS0)|(3<<UCSZ00);
}
```

## Assignment 2

### Step 1:

Using last week's half-duplex code we and Tera Term (it displays the serial data stream in a console) we can see that we are writing something
![](https://i.imgur.com/XvAyI61.png)

### Step 2
This is what the python code for reading the signal looks like. Its main function is debouncing the data and removing fluctuations.
```python=
import tkinter as tk
import serial


def get_val():
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.port = 'COM3'
    ser.timeout = 0
    ser.open()
    s = ser.read(100)
    global pp
    pp = 1000
    # debouncing
    while pp > 256:
        # process value
        pp = int(int.from_bytes(s, "big").__str__()[0:3])
    while 1:
        s = ser.read(100)
        if s:
            # process value
            p = int(int.from_bytes(s, "big").__str__()[0:3])
            # debouncing
            if p <= 255:
                if abs(p - pp) < 20:
                    return (5 * p / 255).__str__()
                pp = p


if __name__ == '__main__':
    print("Voltage: " + get_val() + "V")
```

This GUI code partially worked, but it only did one measurement.
```python=
import tkinter
import tkinter as tk
from struct import pack
from tkinter import ttk
from tkinter import messagebox
import serial

root = tk.Tk()
val = tk.StringVar()


def get_val():
    return val.get()


def set_val(var):
    val.set(var)


def get_var():
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.port = 'COM3'
    ser.timeout = 0
    ser.open()
    s = ser.read(100)
    global pp
    pp = 1000
    # debouncing
    while pp > 256:
        # process value
        pp = int(int.from_bytes(s, "big").__str__()[0:3])
    while 1:
        s = ser.read(100)
        if s:
            # process value
            p = int(int.from_bytes(s, "big").__str__()[0:3])
            # debouncing
            if p <= 255:
                if abs(p - pp) < 20:
                    set_val(5 * p / 255)
                    return 5 * p / 255

                pp = p


def run_me(label):
    label.config(text=f"result: {get_val()}")


print(f"Voltage: {get_var():.02f} V")
root.geometry("200x70")

label = tk.Label(root, text=get_val())

button = tk.Button(root, text="Run", command=lambda: run_me(label))

label.pack()
button.pack()

root.mainloop()

```

so we added some lines of code to make it update concurrently:

```python=
import tkinter
import tkinter as tk
from struct import pack
from tkinter import ttk
from tkinter import messagebox
import serial

root = tk.Tk()
val = tk.StringVar()


def get_val():
    return val.get()


def set_val(var):
    val.set(var)


def get_var():
    ser = serial.Serial()
    ser.baudrate = 9600
    ser.port = 'COM3'
    ser.timeout = 0
    ser.open()
    s = ser.read(100)
    global pp
    pp = 1000
    # debouncing
    while pp > 256:
        # process value
        pp = int(int.from_bytes(s, "big").__str__()[0:3])
    while 1:
        s = ser.read(100)
        if s:
            # process value
            p = int(int.from_bytes(s, "big").__str__()[0:3])
            # debouncing
            if p <= 255:
                if abs(p - pp) < 20:
                    set_val(5 * p / 255)
                    return 5 * p / 255

                pp = p


def run_me(label):
    while 1:
        label.config(text=f"result: {get_var()}")
        label.after(1000, label.update())


print(f"Voltage: {get_var():.02f} V")
root.geometry("200x70")

label = tk.Label(root, text=get_val())

button = tk.Button(root, text="Run", command=lambda: run_me(label))

label.pack()
button.pack()

root.mainloop()

```

## Assignment 3

1. Copy the example program and show what it does on the board
2. Study the mpc3201 ADC
3. Show the mpc3201 ADC value on the leds
4. Show the mpc3201 ADC value on the serial port

### Step 1
After copying the code we noted that the values correspond to their given bit from left to right: clock, MISO, MOSI and chip select. The CS/SS pin is negated so it a 1 is written to it so that that chip is selected.

![](https://i.imgur.com/XkUBy2d.jpg)

After connecting it to the SPI board we can see that the code is a binary counter.

![](https://i.imgur.com/XRi0WSG.jpg)

It also outputs to USART, giving us this in our serial monitor.

![](https://i.imgur.com/yTTkJMN.png)


```c=
/*
 * SPIexample
 * The example shows how to work with the  SPI Expander chip MCP23s08 as output
 * The example also remembers you how to work with the USART
 * Created: 9-10-2015 07:35:40 /april 2016 / february 2019
 * Author : Tom IJsselmuiden/Hans Stokkink
 */ 

#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#define SS 2        // pin 10 arduino uno
#define MOSI 3      // pin 11 arduino uno
#define MISO 4      // pin 12 arduino uno
#define SCK 5       // pin 13 arduino uno
#define TXD 1

#define ENABLE_SS PORTB &= ~(1 << SS)
#define DISABLE_SS PORTB |= (1 << SS)
#define ENABLE_SS2 PORTB &= ~(1 << PORTB1)  //pin 9 arduino = pin portb1 for other spi chips
#define DISABLE_SS2 PORTB |= (1 << PORTB1)

#define  FOSC 16000000
#define  BAUD 9600
#define  MYUBBR FOSC/16/BAUD -1

#define UART_BUFF_SIZE 10


#define A 0
#define B 1



#define READ 1
#define WRITE 0

#define IODIR 0
#define OUTP_LATCH 10

//void uart_init(void);
void USART_Init(void);
void init(void);
uint8_t spi_tranceiver (uint8_t data);
void USART_Transmit(uint8_t data);

int16_t Temp_read(void);
void IOEXP_IODIR(uint8_t data);
void IOEXP_datalatch(uint8_t data);

uint8_t RX_buf[UART_BUFF_SIZE];
uint8_t TX_buf[UART_BUFF_SIZE];
uint8_t RX_index = 0;
uint8_t TX_index = 0;

ISR(USART_RX_vect)
{
	RX_buf[RX_index++] = UDR0;
	USART_Transmit(RX_buf[RX_index-1]);
}

int main(void)
{
	int x=0;
	init();
	/* Clearing buffers */
	memset(RX_buf,0,sizeof(RX_buf));
	memset(TX_buf,0,sizeof(TX_buf));
	
	/* Enable interrupts */ 
	sei();
	
	/* set all pins of I/0 expander to output */
	IOEXP_IODIR(0);
	/* set lower 4 bits (leds) high*/
	IOEXP_datalatch(0x0f);
	_delay_ms(1000);
	/* set higher 4 bits (leds) high*/
	IOEXP_datalatch(0xf0);
	_delay_ms(1000);
	int16_t data = 0xaa;
   IOEXP_datalatch(data);   //set led
    while (1) 
    {	 
		data++;
		//int16_t data = 0xaa;
		IOEXP_datalatch(data);   //set led
		USART_Transmit(data);    // give same value to USART
		_delay_ms(100);
    }
}

void init()
{
	USART_Init();
	/* Set SS, MOSI and SCK output, all others input */
	DDRB = (1<<SS)|(1<<MOSI)|(1<<SCK)|(1 << PORTB1);
	/* LED PIN */ 
	DDRB |= (1 << PORTB0);
	/* Set TXD as an output */
	DDRD = (1 << TXD);
	
	/* Set the slave select pin (Active low) */ 
	DISABLE_SS;
	DISABLE_SS2;
	
	/* Enable SPI, Master, set clock rate fosc/16 */
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
	
	}

// function to initialize UART
void USART_Init(void)
{
	
	// Set baud rate:
	UBRR0=103;                 //UBRR= Fosc /(16*9600) -1 =103.166= 103

	// enable receiver and transmitter
	UCSR0B |=(1<<RXEN0 |(1 <<TXEN0));

	// Set frame format : 8 data 2 stop bit

	UCSR0C = (1<<USBS0 )|(3<<UCSZ00);
}

void USART_Transmit( uint8_t data )
{
	/* Wait for empty transmit buffer */
	while ( !( UCSR0A & (1<<UDRE0)) );
	/* Put data into buffer, sends the data */
	UDR0 = data;
}

/* spi data buffer load and send */
uint8_t spi_tranceiver (uint8_t data)
{
	// Load data into the buffer
	SPDR = data;
	
	//Wait until transmission complete
	while(!(SPSR & (1<<SPIF) ));
	
	// Return received data
	return(SPDR);
}



/* IO expander data direction set */
void IOEXP_IODIR(uint8_t data)
{
	uint8_t r_data = 0;
					// Make slave select go low
				ENABLE_SS;
				/* Send device address + r/w */
				spi_tranceiver((1<<6)|WRITE);
				/* Send command */
				spi_tranceiver(IODIR);

				spi_tranceiver(data);
				// Make slave select go high
				DISABLE_SS;
				
}


/* IO expander latch  set */
void IOEXP_datalatch(uint8_t data)
{
	// Make slave select go low
	ENABLE_SS;
	/* Send device address + r/w */
	spi_tranceiver((1<<6)|WRITE);
	/* Send command */
	spi_tranceiver(OUTP_LATCH);
	spi_tranceiver(data);
	// Make slave select go high
	DISABLE_SS;
	
}
```


### Step 2+3
The debug code was used to determine whether or not the problem was in the IO expander code.

```c=
/*
 * SPIexample
 * The example shows how to work with the  SPI Expander chip MCP23s08 as output
 * The example also remembers you how to work with the USART
 * Created: 9-10-2015 07:35:40 /april 2016 / february 2019
 * Author : Tom IJsselmuiden/Hans Stokkink
 */ 

#define F_CPU 16000000UL
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include <string.h>
#include <avr/interrupt.h>
#include <stdlib.h>

#define SS 2        // pin 10 arduino uno
#define MOSI 3      // pin 11 arduino uno
#define MISO 4      // pin 12 arduino uno
#define SCK 5       // pin 13 arduino uno
#define TXD 1

#define ENABLE_SS PORTB &= ~(1 << SS)
#define DISABLE_SS PORTB |= (1 << SS)
#define ENABLE_SS2 PORTB &= ~(1 << PORTB1)  //pin 9 arduino = pin portb1 for other spi chips
#define DISABLE_SS2 PORTB |= (1 << PORTB1)

#define  FOSC 16000000
#define  BAUD 9600
#define  MYUBBR FOSC/16/BAUD -1

#define UART_BUFF_SIZE 10


#define A 0
#define B 1



#define READ 1
#define WRITE 0

#define IODIR 0
#define OUTP_LATCH 10

//void uart_init(void);
void USART_Init(void);
void init(void);
uint8_t spi_tranceiver (uint8_t data);
void USART_Transmit(uint8_t data);

int16_t Temp_read(void);
void IOEXP_IODIR(uint8_t data);
void IOEXP_datalatch(uint8_t data);

uint8_t read_ADC();
void debug();

uint8_t RX_buf[UART_BUFF_SIZE];
uint8_t TX_buf[UART_BUFF_SIZE];
uint8_t RX_index = 0;
uint8_t TX_index = 0;

ISR(USART_RX_vect)
{
	RX_buf[RX_index++] = UDR0;
	USART_Transmit(RX_buf[RX_index-1]);
}

int main(void)
{
	int x=0;
	init();
	/* Clearing buffers */
	memset(RX_buf,0,sizeof(RX_buf));
	memset(TX_buf,0,sizeof(TX_buf));
	
	/* Enable interrupts */ 
	sei();
	
	/* set all pins of I/0 expander to output */
	IOEXP_IODIR(0);
	/* set lower 4 bits (leds) high*/
	IOEXP_datalatch(0x0f);
	_delay_ms(1000);
	/* set higher 4 bits (leds) high*/
	IOEXP_datalatch(0xf0);
	_delay_ms(1000);
	//int16_t data = 0xaa;
   IOEXP_datalatch(0x00);   //set led
    while (1) 
    {	 
		ENABLE_SS2;
		_delay_ms(5);
		USART_Transmit(SPDR);
		IOEXP_datalatch(SPDR);
		DISABLE_SS2;
		_delay_ms(100);
		//debug();
    }
}

void debug(){
	_delay_ms(100);
	IOEXP_datalatch(0xff);
	_delay_ms(100);
	IOEXP_datalatch(0x00);
}
	
uint8_t read_ADC(){
	debug();
	ENABLE_SS2;
	_delay_ms(5);
	uint8_t data = SPDR;
	IOEXP_datalatch(SPDR);
	DISABLE_SS2;
	return data;
}

void init()
{
	USART_Init();
	/* Set SS, MOSI and SCK output, all others input */
	DDRB = (1<<SS)|(1<<MOSI)|(1<<SCK)|(1 << PORTB1);
	/* LED PIN */ 
	DDRB |= (1 << PORTB0);
	/* Set TXD as an output */
	DDRD = (1 << TXD);
	
	/* Set the slave select pin (Active low) */ 
	DISABLE_SS;
	DISABLE_SS2;
	
	/* Enable SPI, Master, set clock rate fosc/16 */
	SPCR = (1<<SPE)|(1<<MSTR)|(1<<SPR0);
	
	}

// function to initialize UART
void USART_Init(void)
{
	
	// Set baud rate:
	UBRR0=103;                 //UBRR= Fosc /(16*9600) -1 =103.166= 103

	// enable receiver and transmitter
	UCSR0B |=(1<<RXEN0 |(1 <<TXEN0));

	// Set frame format : 8 data 2 stop bit

	UCSR0C = (1<<USBS0 )|(3<<UCSZ00);
}

void USART_Transmit( uint8_t data )
{
	/* Wait for empty transmit buffer */
	while ( !( UCSR0A & (1<<UDRE0)) );
	/* Put data into buffer, sends the data */
	UDR0 = data;
}

/* spi data buffer load and send */
uint8_t spi_tranceiver (uint8_t data)
{
	// Load data into the buffer
	SPDR = data;
	
	//Wait until transmission complete
	while(!(SPSR & (1<<SPIF) ));
	
	// Return received data
	return(SPDR);
}



/* IO expander data direction set */
void IOEXP_IODIR(uint8_t data)
{
	uint8_t r_data = 0;
					// Make slave select go low
				ENABLE_SS;
				/* Send device address + r/w */
				spi_tranceiver((1<<6)|WRITE);
				/* Send command */
				spi_tranceiver(IODIR);

				spi_tranceiver(data);
				// Make slave select go high
				DISABLE_SS;
				
}


/* IO expander latch  set */
void IOEXP_datalatch(uint8_t data)
{
	// Make slave select go low
	ENABLE_SS;
	/* Send device address + r/w */
	spi_tranceiver((1<<6)|WRITE);
	/* Send command */
	spi_tranceiver(OUTP_LATCH);
	spi_tranceiver(data);
	// Make slave select go high
	DISABLE_SS;
	
}


}
```
### Step 4:

This is the code for the GUI and we just re-used the rest of the code from step 3.
```python=
import serial

ser = serial.Serial()
ser.baudrate = 9600
ser.port = 'COM3'
ser.timeout = 0
ser.open()
while True:
    s = ser.read(100)
    pp = int(int.from_bytes(s, "little")) * 5 / int(0xfff)
    if s != b'':
        print(pp)
```

## Assignment 4

1. Copy the example program and show what it does on the board
2. Study the mpc9800 temperature sensor
3. Show the mpc9800 temperature sensor value on the leds
4. Show the mpc9800 temperature sensor value on the serial port

### Step 1:
Light goes :sparkles:blinky blink:sparkles: 
```c=
//***************************************************************************
//  File Name	 : I2Cvb1ioexp.c
//  Version	 : 1.0
//  Description  : AVR I2C Bus Master
//  IDE          : Atmel AVR Studio 
//  Programmer   : Stokkink
//               : 
//  Last Updated : April 2016
//***************************************************************************
#include <avr/io.h>
#include <util/delay.h>
#include <compat/twi.h> //alt #include <compat/twi.h> 
#define MAX_TRIES 50
#define MCP23008_ID    0x40  // MCP23008 Device Identifier
#define MCP23008_ADDR  0x00  // MCP23008 Device Address
#define IODIR 0x00           // MCP23008 I/O Direction Register
#define GPIO  0x09           // MCP23008 General Purpose I/O Register
#define OLAT  0x0A           // MCP23008 Output Latch Register
#define I2C_START 0
#define I2C_DATA 1
#define I2C_DATA_ACK 2
#define I2C_STOP 3
#define ACK 1
#define NACK 0
#define DATASIZE 32


/* START I2C Routine */
unsigned char i2c_transmit(unsigned char type) {
	switch(type) {
		case I2C_START:    // Send Start Condition
		TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
		break;
		case I2C_DATA:     // Send Data with No-Acknowledge
		TWCR = (1 << TWINT) | (1 << TWEN);
		break;
		case I2C_DATA_ACK: // Send Data with Acknowledge
		TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
		break;
		case I2C_STOP:     // Send Stop Condition
		TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
		return 0;
	}
	// Wait for TWINT flag set on Register TWCR
	while (!(TWCR & (1 << TWINT)));
	// Return TWI Status Register, mask the prescaler bits (TWPS1,TWPS0)
	return (TWSR & 0xF8);
}
char i2c_start(unsigned int dev_id, unsigned int dev_addr, unsigned char rw_type)
{
	unsigned char n = 0;
	unsigned char twi_status;
	char r_val = -1;
	i2c_retry:
	if (n++ >= MAX_TRIES) return r_val;
	// Transmit Start Condition
	twi_status=i2c_transmit(I2C_START);

	// Check the TWI Status
	if (twi_status == TW_MT_ARB_LOST) goto i2c_retry;
	if ((twi_status != TW_START) && (twi_status != TW_REP_START)) goto i2c_quit;
	// Send slave address (SLA_W)
	TWDR = (dev_id & 0xF0) | (dev_addr & 0x0E) | rw_type;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_DATA);
	// Check the TWSR status
	if ((twi_status == TW_MT_SLA_NACK) || (twi_status == TW_MT_ARB_LOST)) goto i2c_retry;
	if (twi_status != TW_MT_SLA_ACK) goto i2c_quit;
	r_val=0;
	i2c_quit:
	return r_val;
}
void i2c_stop(void)
{
	unsigned char twi_status;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_STOP);
}
char i2c_write(char data)
{
	unsigned char twi_status;
	char r_val = -1;
	// Send the Data to I2C Bus
	TWDR = data;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_DATA);
	// Check the TWSR status
	if (twi_status != TW_MT_DATA_ACK) goto i2c_quit;
	r_val=0;
	i2c_quit:
	return r_val;
}
char i2c_read(char *data,char ack_type)
{
	unsigned char twi_status;
	char r_val = -1;

	if (ack_type) {
		// Read I2C Data and Send Acknowledge
		twi_status=i2c_transmit(I2C_DATA_ACK);
		if (twi_status != TW_MR_DATA_ACK) goto i2c_quit;
		} else {
		// Read I2C Data and Send No Acknowledge
		twi_status=i2c_transmit(I2C_DATA);
		if (twi_status != TW_MR_DATA_NACK) goto i2c_quit;
	}
	// Get the Data
	*data=TWDR;
	r_val=0;
	i2c_quit:
	return r_val;
}
void Write_MCP23008(unsigned char reg_addr,unsigned char data)
{
	// Start the I2C Write Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_WRITE);
	// Sending the Register Address
	i2c_write(reg_addr);
	// Write data to MCP23008 Register
	i2c_write(data);
	// Stop I2C Transmission
	i2c_stop();
}
unsigned char Read_MCP23008(unsigned char reg_addr)
{
	char data;
	// Start the I2C Write Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_WRITE);
	// Read data from MCP23008 Register Address
	i2c_write(reg_addr);
	// Stop I2C Transmission
	i2c_stop();

	// Re-Start the I2C Read Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_READ);
	i2c_read(&data,NACK);

	// Stop I2C Transmission
	i2c_stop();

	return data;
}

void i2c_init(void)
{
	// Initial ATMega328P TWI/I2C Peripheral
	TWSR = 0x00;         // Select Prescaler of 1
	// SCL frequency = 11059200 / (16 + 2 * 48 * 1) = 98.743 kHz
	TWBR = 0x30;        // 48 Decimal
}

int main(void)
{
	
  int x=0;
	// Initial Master I2C
	i2c_init();
	// Initial the MCP23008 GP0 to GP7 as Output
	Write_MCP23008(IODIR,0b00000000);
	Write_MCP23008(GPIO,0b00000000);    // Reset all the Output Port

	// Loop Forever
	while(1) {
		
			// Write to MCP23008 GPIO Register
			Write_MCP23008(GPIO,x++);

				_delay_ms(100);
		}


	return 0;
}
/* EOF: I2Cvb1ioexp.c */
```

### Step 2+3:
```c=
//***************************************************************************
//  File Name	 : I2Cvb1ioexp.c
//  Version	 : 1.0
//  Description  : AVR I2C Bus Master
//  IDE          : Atmel AVR Studio
//  Programmer   : Stokkink
//               :
//  Last Updated : April 2016
//***************************************************************************
#include <avr/io.h>
#include <util/delay.h>
#include <util/twi.h>
#define MAX_TRIES 50
#define MCP23008_ID    0x40			// MCP23008 Device Identifier
#define MCP23008_ADDR  0x00			// MCP23008 Device Address

#define MCP9800_ID	   0x50			// temp sensor ID
#define MCP9800_INIT   0b11010000   // temp sensor initialize address
#define MCP9800_ADDR   0x01		    // temp sensor address

#define TEMP_T 0x00					// temperature register
#define TEMP_CONF 0x01				// configuration register
#define 

#define IODIR 0x00					// MCP23008 I/O Direction Register
#define GPIO  0x09					// MCP23008 General Purpose I/O Register
#define OLAT  0x0A					// MCP23008 Output Latch Register

#define I2C_START 0
#define I2C_DATA 1
#define I2C_DATA_ACK 2
#define I2C_STOP 3
#define ACK 1
#define NACK 0
#define DATASIZE 32


/* START I2C Routine */
unsigned char i2c_transmit(unsigned char type) {
	switch(type) {
		case I2C_START:    // Send Start Condition
		TWCR = (1 << TWINT) | (1 << TWSTA) | (1 << TWEN);
		break;
		case I2C_DATA:     // Send Data with No-Acknowledge
		TWCR = (1 << TWINT) | (1 << TWEN);
		break;
		case I2C_DATA_ACK: // Send Data with Acknowledge
		TWCR = (1 << TWEA) | (1 << TWINT) | (1 << TWEN);
		break;
		case I2C_STOP:     // Send Stop Condition
		TWCR = (1 << TWINT) | (1 << TWEN) | (1 << TWSTO);
		return 0;
	}
	// Wait for TWINT flag set on Register TWCR
	while (!(TWCR & (1 << TWINT)));
	// Return TWI Status Register, mask the prescaler bits (TWPS1,TWPS0)
	return (TWSR & 0xF8);
}
char i2c_start(unsigned int dev_id, unsigned int dev_addr, unsigned char rw_type)
{
	unsigned char n = 0;
	unsigned char twi_status;
	char r_val = -1;
	i2c_retry:
	if (n++ >= MAX_TRIES) return r_val;
	// Transmit Start Condition
	twi_status=i2c_transmit(I2C_START);

	// Check the TWI Status
	if (twi_status == TW_MT_ARB_LOST) goto i2c_retry;
	if ((twi_status != TW_START) && (twi_status != TW_REP_START)) goto i2c_quit;
	// Send slave address (SLA_W)
	TWDR = (dev_id & 0xF0) | (dev_addr & 0x0E) | rw_type;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_DATA);
	// Check the TWSR status
	if ((twi_status == TW_MT_SLA_NACK) || (twi_status == TW_MT_ARB_LOST)) goto i2c_retry;
	if (twi_status != TW_MT_SLA_ACK) goto i2c_quit;
	r_val=0;
	i2c_quit:
	return r_val;
}
void i2c_stop(void)
{
	unsigned char twi_status;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_STOP);
}
char i2c_write(char data)
{
	unsigned char twi_status;
	char r_val = -1;
	// Send the Data to I2C Bus
	TWDR = data;
	// Transmit I2C Data
	twi_status=i2c_transmit(I2C_DATA);
	// Check the TWSR status
	if (twi_status != TW_MT_DATA_ACK) goto i2c_quit;
	r_val=0;
	i2c_quit:
	return r_val;
}
char i2c_read(char *data,char ack_type)
{
	unsigned char twi_status;
	char r_val = -1;

	if (ack_type) {
		// Read I2C Data and Send Acknowledge
		twi_status=i2c_transmit(I2C_DATA_ACK);
		if (twi_status != TW_MR_DATA_ACK) goto i2c_quit;
		} else {
		// Read I2C Data and Send No Acknowledge
		twi_status=i2c_transmit(I2C_DATA);
		if (twi_status != TW_MR_DATA_NACK) goto i2c_quit;
	}
	// Get the Data
	*data=TWDR;
	r_val=0;
	i2c_quit:
	return r_val;
}
void Write_MCP23008(unsigned char reg_addr,unsigned char data)
{
	// Start the I2C Write Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_WRITE);
	// Sending the Register Address
	i2c_write(reg_addr);
	// Write data to MCP23008 Register
	i2c_write(data);
	// Stop I2C Transmission
	i2c_stop();
}
unsigned char Read_MCP23008(unsigned char reg_addr)
{
	char data;
	// Start the I2C Write Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_WRITE);
	// Read data from MCP23008 Register Address
	i2c_write(reg_addr);
	// Stop I2C Transmission
	i2c_stop();

	// Re-Start the I2C Read Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_READ);
	i2c_read(&data,NACK);

	// Stop I2C Transmission
	i2c_stop();

	return data;
}

void i2c_init(void)
{
	// Initial ATMega328P TWI/I2C Peripheral
	TWSR = 0x00;         // Select Prescaler of 1
	// SCL frequency = 11059200 / (16 + 2 * 48 * 1) = 98.743 kHz
	TWBR = 0x30;        // 48 Decimal
}

int main(void)
{
	
	int x=0;
	// Initial Master I2C
	i2c_init();
	// Initial the MCP23008 GP0 to GP7 as Output
	Write_MCP23008(IODIR,0b00000000);
	Write_MCP23008(GPIO,0b00000000);    // Reset all the Output Port

	// Loop Forever
	while(1) {
		
		// Write to MCP23008 GPIO Register
		Write_MCP23008(GPIO,x++);

		_delay_ms(1000);
	}


	return 0;
}

void Write_TEMP(unsigned char reg_addr,unsigned char data){
	// Start the I2C Write Transmission
	i2c_start(MCP23008_ID,MCP23008_ADDR,TW_WRITE);
	// Sending the Register Address
	i2c_write(reg_addr);
	// Write data to MCP23008 Register
	i2c_write(data);
	// Stop I2C Transmission
	i2c_stop();
}
/* EOF: I2Cvb1ioexp.c */

```

### Step 4:


# Pe