Blog 20

From BitWizard Wiki
Jump to navigation Jump to search

!BETA!Understanding the I2C example code

Hello, in this post I want to give explanation tips for the example I2C code you can see LCD. A link to the code:

I would recommend if you are new to arduino to search stuff you are unfamiliar with on the internet.
On Arduino's reference page you can find a lot of the commands well explained.

What does the code? The code is a counter, that counts one up of the previous code. So, you can say it counts the seconds it is on.

The full code:

#include <Wire.h> 

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
} 

#define I2C_LCD_ADDR (0x82>>1) 

void lcd_cls (void)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x10);                    // Send dummy byte to port 10: clear screen. 
  Wire.send (0);        
  Wire.endTransmission();    // stop transmitting
}

void lcd_print (char *str)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x0);                    // Send dummy byte to port 10: clear screen. 
  Wire.send (str);        
  Wire.endTransmission();    // stop transmitting
}

void lcd_gotoxy (int x, int y)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x11);                    // Send dummy byte to port 10: clear screen. 
  Wire.send ((y << 5) | (x&0x1f));        
  Wire.endTransmission();    // stop transmitting
}

void loop()
{
  char buf[0x10];
  static int x;
 
  lcd_cls ();
 
  lcd_gotoxy (x&0xf,1);
  lcd_print ("*");
  lcd_gotoxy (0,0);
   
  sprintf (buf, "x is: %d", x++);
  lcd_print (buf);

  delay(1000);
}

Open I2C Library:

#include <Wire.h> 

Set up the contact with I2C Bus.

void setup()
{
  Wire.begin(); // join i2c bus (address optional for master)
} 

Gives the address location.

#define I2C_LCD_ADDR (0x82>>1) 

The 0x82 is in this example bit shifted(>>) to the right with one. Bit shifting in this example let a the bits go to the right. So easy example with a 4 bits: 0010 will become 0001. The hexadecimal result should be: 0x41. This is an easy technique if you know the address value, but don't want to figure out what the hexadecimal value is when you divide it with 2.

(0x82>>1)

(cls = clear screen) This part can be called later in the script. The begin transmission write to the address given from I2C_LCD_ADDR with register 0x10 and the value 0. This will clear the screen of the lcd. After that is stops transmitting data.

void lcd_cls (void)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x10);                    // Send dummy byte to port 10: clear screen. 
  Wire.send (0);        
  Wire.endTransmission();    // stop transmitting
}

This will put characters in a string. He again start transmitting to the address to register 0x0 and with the value given in the str.

void lcd_print (char *str)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x0);                    // Send dummy byte to port 10: clear screen. 
  Wire.send (str);        
  Wire.endTransmission();    // stop transmitting
}

This will make contact to int x and int y. It will start transmitting to the address and talk to register 0x11. The bits value of y will be shifted 5 to the left. The '|' is an or function, what it does is that it wants one of or both of the two be 1. After that it will stop transmitting.

void lcd_gotoxy (int x, int y)
{
  Wire.beginTransmission(I2C_LCD_ADDR); // transmit to device #4
  Wire.send (0x11);                    // Send dummy byte to port 10: clear screen. 
  Wire.send ((y << 5) | (x&0x1f));        
  Wire.endTransmission();    // stop transmitting
}

The loop will make it that the arduino, will repeatedly repeat the code. The character in the array will get the in the string the value of '0x10'. The static make that x will only work with one function, and will stay with the same value. After that it makes contact with the cls function.

void loop()
{
  char buf[0x10];
  static int x;
 
  lcd_cls ();
 

Gives to lcd_gotoxy x & 0xf, and to the other one the value 1. Gives to lcd_print to the str, with 0x10. Gives to lcd_gotoxy the value 0,0 to clean it.

 lcd_gotoxy (x&0xf,1);
 lcd_print ("*");
 lcd_gotoxy (0,0);
  

It will print on the serial monitor(CTRL+M) with the array given value and will counts with x++ one more on the number. Let's the lcd print the given value in buf(Group or arrays with bytes). After that it waits 1000miliseconds = 1 seconds.

  sprintf (buf, "x is: %d", x++);
  lcd_print (buf);

  delay(1000);
}

Mistake in the code is in the comments, that there is several times said that: // Send dummy byte to port 10: clear screen. This only happens with the first one.


!BETA! Understanding the SPI example code

Here I will give extra information, about the SPI example you can see at LCD:
Arduino lcd SPI demo

I won't copy paste the full code, this time because I don't want to fill up the page. While I only explaining special parts of the code.

What does this code do? This code makes will count how long the code is running and print it out on the display. It counts in minutes, hours and days.

The const makes it that the 4 pins: CLK = Shift Clock MOSI = Master Out Slave Out MISO = Master In Slave Out SS = Slave Select will give a value that is read-only.

const int SPICLK  = 13;
const int SPIMOSI = 11;
const int SPIMISO = 12;
const int SPISS  = 10;

The pinMode lines will make all the pins outputs. After that it writes the value 1(HIGH) to the Slave Select pin.

(More about SPCR) SPCR(SPI Control Register) The _BV is the bit value.~

  • SPE(SPI Enable) - Enables the SPI when 1
  • MSTR(Master mode) - Sets the Arduino in master mode when 1, slave mode when 0
  • SPR1 and SPR0(Speed per round) - Sets the SPI speed, 00 is fastest (4MHz) 11 is slowest (250KHz)
void SPIinit(void)
{
  pinMode (SPICLK,  OUTPUT);
  pinMode (SPIMOSI, OUTPUT);
  pinMode (SPIMISO, OUTPUT);
  pinMode (SPISS,   OUTPUT);
  digitalWrite (SPISS, 1);
  
  SPCR    =  _BV(SPE) | _BV(MSTR) | _BV(SPR1) | _BV(SPR0);
}

character ~ When SPSR(SPI Status Register) & the bit value from SPIF(SPI Interrupt Flag) is 1, it will return the received SPDR(SPI Data Register) value.

char SPI(char d) 
{  // send character over SPI
  char received = 0;
  SPDR = d;
  while(!(SPSR & _BV(SPIF)));
  received = SPDR;
  return (received);
}

When spi starts spkt it will write Slave select 0 and after that it will make it 1 again.

void SPI_startpkt (void)
{
  digitalWrite (SPISS, 0);
}

void SPI_endpkt (void)
{
  digitalWrite (SPISS, 1);
}

Name the address 0x82, that can't be changed.

static unsigned char addr = 0x82;

Makes WAIT1 be 25miliseconds, and WAIT2 be 15miliseconds.

#define WAIT1 25
#define WAIT2 15

Send to the lcd.

void send_lcd (unsigned char rnum, unsigned char len, char *s)
{  
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr);
  delayMicroseconds (WAIT2);
  SPI (rnum);
  delayMicroseconds (WAIT2);
  while (len--) {
    SPI (*s++);
    delayMicroseconds (WAIT2);
  }
  SPI_endpkt ();
}

Send to lcd string length

void write_lcd (char *s)
{
  send_lcd (0, strlen (s), s);
}

Unsigned char is an unsigned datatype, works the same as byte. Value y gets bit shifted 5 steps to the left. ( More about bit shifting you can read above at the I2C part.)

void write_at_lcd (unsigned char x, unsigned char y, char *s)
 
{ 
  char c; 
  c = (y << 5) | (x & 0x1f);
  send_lcd (0x11, 1, &c);
  write_lcd (s);
}

(cls = Clear Screen )

void cls_lcd (void)
{ 
  char c; 
  send_lcd (0x10, 1, &c);
}

Direction to set_var, where address, register and value can be given. It has several waits, that direct to the times given before at #WAIT1 and #WAIT2.

void set_var (unsigned char addr, unsigned char a, unsigned char v)
{
  SPI_startpkt ();
  delayMicroseconds (WAIT1);
  SPI (addr);
  delayMicroseconds (WAIT2);
  SPI (a);
  delayMicroseconds (WAIT2);
  SPI (v);
  delayMicroseconds (WAIT2);
  SPI_endpkt ();   
}

Make clear what the addresses are from the servo and 7FETs.

static unsigned char spi_servo_addr = 0x86;
static unsigned char spi_7fet_addr = 0x88;
void set_servo_var (unsigned char a, unsigned char v)
{
  set_var (spi_servo_addr, a, v);
}

void set_7fet_var (unsigned char a, unsigned char v)
{
  set_var (spi_7fet_addr, a, v);
}

DDRC - The Port C Data Direction Register - read/write PORTC - The Port C Data Register - read/write PINC - The Port C Input Pins Register - read only

void setup (void)
{
  int i;
   
  SPIinit ();  
  Serial.begin (9600);
  DDRC = 0x30;
  PORTC = 0x20;
  for (i=0;i<10;i++) {
    PINC = 0x30;
    delay (300);
  }
  cls_lcd ();
}

static long makes that the number can't be negative. Millis = Returns the number of milliseconds since the Arduino board began running the current program. So, if it is more than value next update 1000 milliseconds(1 second) it wil run the script. In the script it will count at s ( seconds ) 1. (s+) If S is higher than 59 it will set s back to 0. And will count 1 at the (m)minutes section. This works the same for the minutes section when it is geting above 59 it will count 1 to (h)hours.

void loop (void) 
{
  static long nextupdate = 1000;
  static unsigned char h, m, s;
  char buf[17];
  
  if (millis () > nextupdate) {
    nextupdate += 1000;
    if (s < 59) s++;
    else {
       s = 0;
       if (m < 59) m++;
      else {
	 m = 0;
 	 if (h < 23) h++;
	 else {
	 h = 0;	
        // days ++;
        }
      }
    }

Here it will print out the given value from the if statement above. (%02d) And will print it out in 2 numbers on the display in decimals. Gives the values to open writing to display. And puts with buf the information in it from the arrays.

    sprintf (buf, "%02d:%02d:%02d", h, m, s);
    write_at_lcd (8, 1, buf);
    Serial.write (buf);
    Serial.write ("\r\n");
//    sprintf (buf, "%ld %ld", nextupdate, millis ());
//    write_at_lcd (0, 0, buf);

   // delay (100);
  }

This is for talking to the servo and the 7FETs. Register 0x20, with value s an reference 0xf gets bit shifted 4 times to the left.

  {
    static unsigned char olds;
   
    if (olds != s) {
      olds = s;
      set_servo_var (0x20, (s & 0xf) << 4); 
    }
  }
  

Makes a string, of four values. For values 1, 4, 2 and 8. Olds will than read what the latest values is that is given to s. At 7FETs address the register 10 will set the given outputs at value to zero.

  {
    static unsigned char olds;
    
    if (olds != s) {
      static unsigned char values[4] = { 1, 4, 2, 8};
      olds = s;
     
      set_7fet_var (0x10, values [s & 0x3]); 
    }
  }

}

Useful links