# 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