ok I have cleaned the code up a bit and commented almost everything. the TwoWire. functions will not be in there in an hour or so as they are from the arduino code that i made.
im going to e making a new I2C library as i am unable to find a slave one on-line :/ it will be based off of the arduino Wire library
/*
* PSUFrontDisplay.c
*
* Created: 02/09/2013 14:07:34
* Author: carbon dude oxide
* Avr used: ATMega328p
*/
/* Circuit Structure
7-Segment layout:
Common Anode displays
A
------
F | | B
| G |
------
E | | C
| D |
------ .P (DP)
Circuit is laid out like so:
the line above each 7-segment display shows which pin on the AVR the common anode is connected to,
the number in brackets corresponds to the ID number of each display used in arrays (index number) and for loops.
There are two sets of 4 displays with all their A segments connected together and all the B segments
together to perform a multiplexing task.
---------------------------------
PD1 (0) PD0 (1) PD7 (2) PD6 (3)
| --- | --- | --- | --- |
| | | | | | | | | | | | |
| --- | --- | --- | --- |
| | | | | | | | | | | | |
| --- | --- | --- | --- |
---------------------------------
PD5 (4) PD4 (5) PD3 (6) PD2 (7)
| --- | --- | --- | --- |
| | | | | | | | | | | | |
| --- | --- | --- | --- |
| | | | | | | | | | | | |
| --- | --- | --- | --- |
---------------------------------
each AVR pin used to control the segments is wired to an NPN transistor which in turn pulls each cathode
of the 7-Segment display low allowing the LED to light
A segments connected to pin: PC1
B segments connected to pin: PC0
C segments connected to pin: PC3
D segments connected to pin: PB4
E segments connected to pin: PB5
F segments connected to pin: PB2
G segments connected to pin: PB3
P segments connected to pin: PC2 (P is decimal point)
*/
#define F_CPU 16000000UL // 16 MHz clock frequency
#include <avr/io.h> //standard library loaded
#include <util/delay.h> //needed for delay on multiplexing
#include <stdio.h> //used for current method of displaying data
#include <string.h> //used for current method of displaying data
#include <custom/Wire/Wire.h> //modified Wire library from Arduino
/* displays data is used to determine which segment to light up on each 7 segment display
*
*/
char displays[8][11] = {"G", "G", "G", "G", "G", "G", "G", "G"};
/* chars data is which segments should be lit up when wanting to display a number for example:
* the number 0 needs "ABCDEF" segments to be lit
* the number 1 needs "BC" segments to be lit
* in the array there are two extra entries equating to numbers 10 and 11
* 10 is used for a blank display and 11 is used to display a negative symbol
*/
char chars[12][8] = {"ABCDEF", "BC", "ABDEG", "ABCDG", "BCFG", "ADCFG", "ACDEFG", "ABC", "ABCDEFG", "ABCFG", "X", "G"};
int main(void)
{
/* Set all used pins to outputs
* PD1, PD0, PD7, PD6, PD5, PD4, PD3 and PD2 for anodes for each of the 8 7-segment displays and
* PC1, PC0, PC3, PB4, PB5, PB2, PB3 and PC2 for NPN transistor for each segment of the 7-segment displays
*/
DDRB = (1 << PORTB0) | (1 << PORTB1) | (1 << PORTB2) | (1 << PORTB3) | (1 << PORTB4) | (1 << PORTB5);
DDRC = (1 << PORTC0) | (1 << PORTC1) | (1 << PORTC2) | (1 << PORTC3);
DDRD = (1 << PORTD0) | (1 << PORTD1) | (1 << PORTD2) | (1 << PORTD3) | (1 << PORTD4) | (1 << PORTD5) | (1 << PORTD6) | (1 << PORTD7);
//initiate the I2C Protocol
Wire.begin(2); // join i2c bus with address #2
Wire.onReceive(receiveEvent); // register event to handle requests
//the loop function for multiplexing
while(1)
{
for (int dID=0; dID<8; dID++) //cycle through display ID's 0-7 :D
{
//set all used display ports low and ignore other outputs
PORTB = PORTB & 0xC0; // set all ports except PORTB6 and PORTB7 low
PORTC = PORTC & 0x0F; // set all ports except PORTC4, PORTB5, PORTC6 and PORTB7 low
PORTD = 0x00; // set all ports low
/* scan the displays string data for a used letter example and turn the corresponding output on:
* displays[0] (for display id:0) contains "BC" which corresponds to the number 1 to be displayed (from chars array)
* this code will scan the string for each letter and come true for B and C so will turn on the B and C segments on all the displays
* but due to all the anodes being off (from last few lines of script) the segments will not light
*/
if (strstr(displays[dID],"A") != NULL) {PORTC = (1 << PORTC1);}
if (strstr(displays[dID],"B") != NULL) {PORTC = (1 << PORTC0);}
if (strstr(displays[dID],"C") != NULL) {PORTC = (1 << PORTC3);}
if (strstr(displays[dID],"D") != NULL) {PORTB = (1 << PORTB4);}
if (strstr(displays[dID],"E") != NULL) {PORTB = (1 << PORTB5);}
if (strstr(displays[dID],"F") != NULL) {PORTB = (1 << PORTB2);}
if (strstr(displays[dID],"G") != NULL) {PORTB = (1 << PORTB3);}
if (strstr(displays[dID],"P") != NULL) {PORTC = (1 << PORTC2);}
/* Now that all the segment data has been sifted through and has turned on each segment to be lit up for the display
* this is done by asking which dID (display ID) is currently being used in the for loop and then turning on the output
* for that 7-Segment display, in the previous chunk of code the segments were selected and in this chunk the 7-segment display
* is selected and tada it lights up
*/
if (dID == 0) {PORTD = (1 << PORTD1);}
else if (dID == 1) {PORTD = (1 << PORTD0);}
else if (dID == 2) {PORTD = (1 << PORTD7);}
else if (dID == 3) {PORTD = (1 << PORTD6);}
else if (dID == 4) {PORTD = (1 << PORTD5);}
else if (dID == 5) {PORTD = (1 << PORTD4);}
else if (dID == 6) {PORTD = (1 << PORTD3);}
else if (dID == 7) {PORTD = (1 << PORTD2);}
_delay_ms(1); //delay 1ms so that it does not go too crazy and lights up the segments correctly
}
}
}
void receiveEvent(int howMany) //custom function to be called when I2C slave address is acknowledged and is receiving bytes of data
{
while(Wire.available() > 4) //check to see if there are 5 bytes available in storage
{
/*
-----structure of incoming bytes-----
Ba is currently unused (will be for negative numbers data)
Bb Bit 0+1 is position of DP on 7 segment display 1 and bit 2-7 is upper bits for display 1.
Bc lower bits for display 1 ( put together to make a 16bit display 1 number to show between 0 and 9999.
Bd Bit 0+1 is position of DP on 7 segment display 2 and bit 2-7 is upper bits for display 2.
Be lower bits for display 2 ( put together to make a 16bit display 2 number to show between 0 and 9999.
*/
char Ba = TwoWire.read(); // receive byte as a character
char Bb = TwoWire.read(); // receive byte as a character
char Bc = TwoWire.read(); // receive byte as a character
char Bd = TwoWire.read(); // receive byte as a character
char Be = TwoWire.read(); // receive byte as a character
if (Ba == 0xFF)
{
//reset display info by setting displays arrays to X (blank display)
strcpy(displays[2], "x");
strcpy(displays[3], "x");
strcpy(displays[4], "x");
strcpy(displays[5], "x");
strcpy(displays[6], "x");
strcpy(displays[7], "x");
strcpy(displays[8], "x");
strcpy(displays[9], "x");
// determine dp position by adding a mask and bit shifting to give a value between 0-3 to represent which digit to have the dp on
// look at structure of incoming bytes to see why i bit shift and stuff
char dpp = Bb & 0xC0; // remove number data and leave DP position data
dpp = dpp >> 6; //bit shift to leave dp digit position a binary value between 0-3 (corresponding to which digit to display the DP on)
int idpp = 3 - dpp; // invert the displayID (as it is the wrong way round) and convert into a int corresponding to the 4 displays on the 1st block of displays (ID's 0-3)
strcpy(displays[idpp], strcat(displays[idpp],"P")); //add the letter P to the specific dID array which is calculated in the last few lines
Bb = Bb & 0x3F; //remove DP Position data and leave number data to we can calculate what number to be displays on the digits
short lb = (Bb << 8) | Bc; // combine upper and lower byte to form 16bit number data (so that we can have a number between 0 and 9999)
// set up individual numbers for each of the 4 displays in the 1st of the 2 blocks of 4 displays
int fbT;
int fbh;
int fbt;
int fbu;
if (lb <= 9999) //if received data wants to display number larger than 9999 then display ----
{
//decode binary into 4 individual digits.
short lbT = lb/1000;
fbT = lbT;
if ((fbT >= 10) || (fbT <= 0)) {fbT = 10;}
short lbh = (lb-(lbT*1000))/100;
fbh = lbh;
short lbt = (lb-(lbh*100)-(lbT*1000))/10;
fbt = lbt;
short lbu = (lb-(lbh*100)-(lbt*10)-(lbT*1000));
fbu = lbu;
}
else
{
//set digits as ---- because 11 corresponds to G segment being lit (view chars[11] array)
fbT = 11;
fbh = 11;
fbt = 11;
fbu = 11;
}
// determine dp position (for second block of displays) by adding a mask and bit shifting to give a value between 0-3 to represent which digit to have the dp on
// look at structure of incoming bytes to see why i bit shift and stuff
short dppb = Bd & 0xC0; // remove number data and leave DP position data
dppb = dppb >> 6; //bit shift to leave dp digit position a binary value between 0-3 (corresponding to which digit to display the DP on)
int idppb = 7 - dppb; // invert the displayID (as it is the wrong way round) and convert into a int corresponding to the 4 displays on the 2nd block of displays (ID's 4-7)
strcpy(displays[idppb], strcat(displays[idppb],"P")); //add the letter P to the specific dID array which is calculated in the last few lines
Bd = Bd & 0x3F; //remove DP Position data and leave number data to we can calculate what number to be displays on the digits
short lbb = (Bd << 8) | Be; // combine upper and lower byte to form 16bit number data (so that we can have a number between 0 and 9999)
// set up individual numbers for each of the 4 displays in the 2nd of the 2 blocks of 4 displays
int fbTb;
int fbhb;
int fbtb;
int fbub;
if (lbb <= 9999)//if received data wants to display number larger than 9999 then display ----
{
//decode binary into 4 individual digits.
short lbTb = lbb/1000;
fbTb = lbTb;
if ((fbTb >= 10) || (fbTb <= 0)) {fbTb = 10;}
short lbhb = (lbb-(lbTb*1000))/100;
fbhb = lbhb;
short lbtb = (lbb-(lbhb*100)-(lbTb*1000))/10;
fbtb = lbtb;
short lbub = (lbb-(lbhb*100)-(lbtb*10)-(lbTb*1000));
fbub = lbub;
}
else
{
//set digits as ---- because 11 corresponds to G segment being lit (view chars[11] array)
fbTb = 11;
fbhb = 11;
fbtb = 11;
fbub = 11;
}
/* add character data for each digit in both displays
* This works by getting the segment data from the chars array acording to the number calculated for each digit from the incomming I2C data
* It is then added onto the existing data that is already in dispays (the strcat() function) and then finaly is then inserted into the displays
* array where it replaces the existing data (hence the need to copy the existing data and add it to the new data before replacing it
*/
strcpy(displays[0], strcat(displays[0],chars[fbu]));
strcpy(displays[1], strcat(displays[1],chars[fbt]));
strcpy(displays[2], strcat(displays[2],chars[fbh]));
strcpy(displays[3], strcat(displays[3],chars[fbT]));
strcpy(displays[4], strcat(displays[4],chars[fbub]));
strcpy(displays[5], strcat(displays[5],chars[fbtb]));
strcpy(displays[6], strcat(displays[6],chars[fbhb]));
strcpy(displays[7], strcat(displays[7],chars[fbTb]));
}
}
}