Home

Figuring out the SparkFun Serial LCD (SerLCD)

February 23, 2010

In my grand plans, there is an LCD display. I have to figure out how to drive it using interrupts, because there will be other things happening (wheel spins, A/D conversions, somewhat time-sensitive actions) that makes it not necessarily a good idea to be waiting in a serial timing loop.

I’m clearly mistaken about something (clock speed? counter operation? interrupt timing?) but I don’t know what yet. Most of the examples on the net don’t use interrupts, so I think it is useful to get this out there.

/* Blinker and SerLCD Demo */

/* Include useful pre-defined functions */
#include     // Defines pins, ports, etc to make programs easier to read
#define F_CPU 1200000UL       // Sets up the default speed for delay.h
#include 
#include 

/* ATTiny13 clock is apparently defaulted to
   9.6MHz, divided by 8 = 1.2Mhz.  To get to
   9600 baud is 125 ticks exactly.
   */
   
/* ATTiny25/45/85 is defaulted to 8Mhz, divided by 8 = 1Mhz.
   To get to 9600 baud is 104-1/6 ticks.
 */

unsigned int BAUD=9600;
unsigned short ocr_val = 114; /* 125 = 1,200,000/9600, but that doesn't seem to work. */
/* Empirically, lo = 112, high=115, outside that range does not work. */
/* I clearly don't entirely understand what is going on here;
   I was under the impression that the counting goes continuously,
   despite interrupts etc, 
   but the counter-limit is different when the bit-banging code is
   in the interrupt routine (114, vs 104).
 */
#define OUT_PIN PB3
#define ONE (_BV(OUT_PIN));

char * s = "0123456789abcdefghijKLMNOPQRSTuvwxyz+-?!";

char outch = 0;
int outchi = 0;
int i = 0;

ISR(TIM0_COMPA_vect) {
  if (outch != 0) {
     if (outchi == 0) {
        /* Start bit. */
        PORTB &= ~ONE;
        outchi++;
     } else if (outchi == 9) {
        /* Stop bit */
        PORTB |= ONE;
        outchi = 0;
        outch = s[++i];
     } else {
        /* 1-8 */
        int j = outchi-1;
        if (((1 << j) & outch) != 0) {
           PORTB |= ONE;
        } else {
           PORTB &= ~ONE;
        }
        outchi++;
     }
  }

}

/* WGM02:0 = 2 Clear Timer on Compare Match */
/* TCCR0A = 2 = WGM02 */
/* OCR0A = max timer value */

int main(){

  cli();
  TCCR0A = 2; /* Clear timer on compare match */
  TCCR0B = 1; /* /1 prescalar = 1200000 Hz */
  OCR0A = ocr_val; 
  TIMSK0 = 4;   /* OCF0A */
  DDRB = _BV(PB4) | _BV(OUT_PIN);         /* enable outputs */

  PORTB = 1 << OUT_PIN; /* Write a STOP bit */

  /* Enter loop with interrupts disabled. */
  int counter = BAUD;
  int first = 1;
  
  while(1){

     sleep_enable();
     sei();
     sleep_cpu();
     sleep_disable();
          
     if (--counter == 0) {
        PORTB = PORTB ^ _BV(PB4); /* does this work? */
        counter = BAUD;
        i = 0;
        if (first) /* One second delay, get the display happy. */
           first = 0;
        else
           outch = s[i];
     }
     cli();

  }

  return(0);
}

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: