Difference between revisions of "Blog 20"

From BitWizard WIKI
Jump to: navigation, search
(Created page with "== Understanding the 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: *[http://www.bitwi...")
 
(!BETA!Understanding the I2C example code)
 
(19 intermediate revisions by the same user not shown)
Line 1: Line 1:
== Understanding the example code ==
+
== !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]].  
+
Hello, in this post I want to give explanation for the example I2C code you can see at the [[LCD]] page.  
A link to the code:
+
A direct link to the code:
 
*[http://www.bitwizard.nl/software/ar_i2c_lcd_demo.pde AR I2C LCD DEMO]
 
*[http://www.bitwizard.nl/software/ar_i2c_lcd_demo.pde AR I2C LCD DEMO]
  
I would recommend if you are new to arduino to search stuff you are unfamiliar with on the internet.<br>On [https://www.arduino.cc/en/Reference/HomePage Arduino's reference page] you can find a lot of the commands well explained.
+
I would recommend if you are new to arduino to search stuff up you are unfamiliar with.<br>On [https://www.arduino.cc/en/Reference/HomePage Arduino's reference page] you can find a lot of the commands well explained.
  
 
What does the code?
 
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 code is a counter, that counts how long the code is running.
 +
It counts in seconds, minutes and hours.
  
 
The full code:
 
The full code:
Line 65: Line 66:
 
  #include <Wire.h>  
 
  #include <Wire.h>  
  
Set up the contact with I2C Bus.  
+
Make contact with I2C Bus.  
 
  void setup()
 
  void setup()
 
  {
 
  {
Line 74: Line 75:
 
  #define I2C_LCD_ADDR (0x82>>1)  
 
  #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 0x82 is in this example bit shifted(>>) to the right by one. Bit shifting in this example let's all the bits go to the right. So what will happen:
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 (Hex) = 1000 0010  
(0x82>>1)
+
1000 010 >> 1 = 01000001 = 0x41 (Hex)
 +
( As you can see all the 1 bits are going to the right )
  
(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.  
+
In this example Using bit shifting is an easy technique, so that you don't have to calculate what the I2c address value is.
 +
 
 +
(cls = clear screen) 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)
 
  void lcd_cls (void)
 
  {
 
  {
Line 87: Line 91:
 
  }
 
  }
  
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.  
+
char *str, will make a pointer to str. For new people like me that can be confusing so it is recommended for now to see it as: 'char str[]'.
 +
He again start transmitting to the address to register 0x0 and with the value given in the str.  
 +
 
 
  void lcd_print (char *str)
 
  void lcd_print (char *str)
 
  {
 
  {
Line 96: Line 102:
 
  }
 
  }
  
This will make contact to int x and int y. It will start transmitting to the address and talk to register 0x11.  
+
This will put the print text on the wanted position on the display. It says the x and y position from the printed information.  
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.  
+
It will start transmitting to the address and talk to register 0x11, where you can give the coordination.  
 +
The bits value of y will be shifted 5 to the left. The '|' is an or function, that switches to the other one with it's coordination.  
 
After that it will stop transmitting.  
 
After that it will stop transmitting.  
  
Line 109: Line 116:
  
 
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 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.  
+
The static make that x will only work with one function, and will stay with the same value. After that it runs the cls screen function.  
  
 
  void loop()
 
  void loop()
Line 126: Line 133:
 
   lcd_gotoxy (0,0);
 
   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.  
+
It will print on the serial monitor(CTRL+M) with the array given value and will counts with x++ one to the number.  
 
Let's the lcd print the given value in buf(Group or arrays with bytes).  
 
Let's the lcd print the given value in buf(Group or arrays with bytes).  
 
After that it waits 1000miliseconds = 1 seconds.   
 
After that it waits 1000miliseconds = 1 seconds.   
Line 139: Line 146:
 
This only happens with the first one.
 
This only happens with the first one.
  
==Useful links ==
+
== !BETA! Understanding the SPI example code ==
 +
 
 +
Here I will give extra information, about the SPI example you can see at [[LCD]]:<br>
 +
[http://www.bitwizard.nl/software/ardemo_lcd.pde 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 seconds, minutes and hours. ( Also does days if you remove the comments(//).
 +
 
 +
The const makes it that the 4 pins:
 +
*SPICLK = SPI Shift Clock
 +
*SPIMOSI = SPI Master Out Slave Out
 +
*SPIMISO = SPI Master In Slave Out
 +
*SPISS = SPI 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.
 +
 
 +
([https://www.arduino.cc/en/Tutorial/SPIEEPROM 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 ==
 +
*[[SPI versus I2C protocols]]
 +
*[[General SPI protocol]]
 +
*[[General I2C protocol]]
 +
*[[Lcd protocol 1.6]]
 
*[[LCD]]
 
*[[LCD]]
 +
*[[7FETs]]
 +
*[[Servo]]
 +
*[[SPI connector pinout]]
 
*[https://www.arduino.cc/en/Reference/HomePage Arduino's reference page]
 
*[https://www.arduino.cc/en/Reference/HomePage Arduino's reference page]
 +
*[https://www.arduino.cc/en/Reference/PortManipulation Port Manipulation]
 +
*[https://www.arduino.cc/en/Tutorial/SPIEEPROM SPI EEPROM]

Latest revision as of 15:21, 1 December 2015

!BETA!Understanding the I2C example code

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

I would recommend if you are new to arduino to search stuff up you are unfamiliar with.
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 how long the code is running. It counts in seconds, minutes and hours.

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> 

Make 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 by one. Bit shifting in this example let's all the bits go to the right. So what will happen:

0x82 (Hex) = 1000 0010 
1000 010 >> 1 = 01000001 = 0x41 (Hex)

( As you can see all the 1 bits are going to the right )

In this example Using bit shifting is an easy technique, so that you don't have to calculate what the I2c address value is.

(cls = clear screen) 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
}

char *str, will make a pointer to str. For new people like me that can be confusing so it is recommended for now to see it as: 'char str[]'. 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 put the print text on the wanted position on the display. It says the x and y position from the printed information. It will start transmitting to the address and talk to register 0x11, where you can give the coordination. The bits value of y will be shifted 5 to the left. The '|' is an or function, that switches to the other one with it's coordination. 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 runs the cls screen 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 to 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 seconds, minutes and hours. ( Also does days if you remove the comments(//).

The const makes it that the 4 pins:

  • SPICLK = SPI Shift Clock
  • SPIMOSI = SPI Master Out Slave Out
  • SPIMISO = SPI Master In Slave Out
  • SPISS = SPI 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