RSS Feed Email Facebook Twitter Stumbleupon Google Bookmark

C Code Cache

Here's a collection of various bite-sized bits of C code that I've written and accumulated over time. This code was written for embedded systems that employed various processors and microcontrollers, using various compilers, but most of it should be fairly portable. If you find anything useful, grab it.


SPI Routines

This code is used to communicate via the SPI (Serial Peripheral Interface) on the 68HC11 (but should also work with the 6805). It was written for the IAR compiler, but should work with others. It assumes that the HC11 registers have been defined with their standard names.

There's not much to this. Call SPI_Init() during system initialization. Call SPI_Transfer() to simultaneously send and receive a byte of data. If you want to send only, and ignore the received byte, precede the name of the function with a (void) when you call it, to tell the compiler that you're purposely ignoring the return value.


/*
*********************************************************************************************************
*
* SPI_Init()
*
* Description: SPI initialization function.  SPI_Init() must be called
*              before calling any other SPI functions.
* Arguments  : none
* Returns    : none
*********************************************************************************************************
*/
void SPI_Init (void)
{
  SPCR = 0x5d;    // initialize SPI Control Register
                  //  (7) SPIE = 0 -- disable SPI interrupts
                  //  (6) SPE  = 1 -- enable SPI system
                  //  (5) DWOM = 0 -- normal CMOS outputs (not wired-or)
                  //  (4) MSTR = 1 -- this is the SPI master
                  //  (3) CPOL = 1 -- SCLK is high in idle state
                  //  (2) CPHA = 1 -- data is clocked on rising edge of SCLK
                  //  (1) 0 \ SPI clock rate = E / 4
                  //  (0) 1 /   (500KHz @ 2MHz E clock)
}


/*
*********************************************************************************************************
*
* SPI_Transfer()
*
* Description : Transfer data to/from the SPI port
* Arguments   : data to send
* Returns     : received data
*********************************************************************************************************
*/
unsigned char SPI_Transfer (unsigned char data_out)
{
  SPDR = data_out;              // send data out spi port
  while (!(SPSR & 0x80));       // wait for transfer to complete
  return = SPDR;                // return data from spi register
}

long_to_string()

This code is used to convert an unsigned long (32 bits) to an ASCII string suitable for displaying. It is intended as a replacement for the standard library ltoa() function, for cases where your compiler doesn't supply it, or it's slow and/or fat. This code was written for the 68HC11 and the IAR compiler, but should be fairly generic.

Call long_to_string() to convert a long to a string, with leading zeros suppressed. If you want leading zeros, use long_to_string_lz(). These two functions could be combined into a single function, but it would require an extra parameter. Be sure to allocate enough space for the resulting string before calling these functions. Failure to do so will cause bad things to happen.


/*
*********************************************************************************************************
* long_to_string()
*
* Description : Convert a "long" to a null-terminated string
*               (base = decimal)
* Arguments   : input = number to be converted
*               str = pointer to string (i.e. display buffer)
*               numdigits = number of digits to display
* Returns     : none
*********************************************************************************************************
*/
void long_to_string (unsigned long input, char *str, char numdigits)
{
  char digit;
  char blank = TRUE;

  long_to_string_lz(input, str, numdigits);

  for (digit=0; digit < numdigits-1; digit++) {
    if (str[digit] == '0') {
      if (blank == TRUE) str[digit] = ' ';
    }
    else {
      blank = FALSE;
    }
  }
}


/*
*********************************************************************************************************
* long_to_string_lz()
*
* Description : Convert a "long" to a null-terminated string, with leading zeros
*               (base = decimal)
* Arguments   : input = number to be converted
*               str = pointer to string (i.e. display buffer)
*               numdigits = number of digits to display
* Returns     : none
*********************************************************************************************************
*/
void long_to_string_lz (unsigned long input, char *str, char numdigits)
{
  char digit;

  for (digit=numdigits; digit > 0; digit--) {
    str[digit-1] = (input % 10) + '0';
    input = input / 10;
  }
  str[numdigits] = 0;    // null-terminate the string
}

uword_to_hexstring() and hexstring_to_uword()

This code is used to convert an unsigned integer (16 bits) to an ASCII hexidecimal string suitable for displaying. Note that this only creates the digits -- if you want a leading "0x" or "$", it's up to the calling function to add it. This code was written for the 68HC11 and the IAR compiler, but should be fairly generic.

Be sure to allocate enough space for the resulting string before calling uword_to_hexstring(). Failure to do so will cause bad things to happen.

hexstring_to_uword() is simply the inverse of uword_to_hexstring(). Given a string of hex digits (0-9, A-F, a-f), it converts them intil an unsigned integer. Note that it requires the standard library function isxdigit().


/*
*********************************************************************************************************
* uword_to_hexstring()
*
* Description : Convert an unsigned int to a null-terminated string
*               (base = hexidecimal)
* Arguments   : input = number to be converted
*               str = pointer to string (i.e. display buffer)
*               numdigits = number of digits to display
* Returns     : none
*********************************************************************************************************
*/
void uword_to_hexstring (unsigned int input, char *str, char numdigits)
{
  char digit;

  for (digit=numdigits; digit > 0; digit--) {
    char temp = input % 0x10;
    if (temp <= 0x09)
      str[digit-1] = temp + '0';
    else
      str[digit-1] = temp - 0x0a + 'A';
    input = input / 0x10;
  }
  str[numdigits] = 0;    // null-terminate the string
}


/*
*********************************************************************************************************
* hexstring_to_uword()
*
* Description : Convert a null-terminated string (base = hexidecimal)
*               to an unsigned int (16 bits);
* Arguments   : str = pointer to string
* Returns     : result
* Note        : Adapted from a function in the "Snippets" collection, by Bob Stout.
*********************************************************************************************************
*/
unsigned int hexstring_to_uword (char *str)
{
  unsigned int i, j = 0;

  while (str && *str && isxdigit(*str)) {
    i = *str++ - '0';
    if (9 < i)
      i -= 7;
    j <<= 4;
    j |= (i & 0x0f);
  }
  return(j);
}

LCD Routines

Refer to the LCD Project page for a nifty little project to control a character-mode LCD from the PC printer port. It includes a schematic and code. The code was written for Borland C, but should be easily adaptable for most compilers. I'm using essentially the same code in an HC11 project, to control a 4x20 LCD.


MAX7219 LED Display Driver Routines

The Maxim MAX7219 is an LED display driver that can control up to 64 individual LEDs, or eight 7-segment LED digits, or any combination of individual LEDs and digits, connected in a matrix of eight rows and eight columns. It frees the host from the chore of constantly multiplexing the 8 rows and 8 columns.

Visit the MAX7219 Project page for details and the source code.


Xicor SPI Serial Memory Interface Routines

Xicor offers a number of interesting and useful memory devices, including a line of serial EEPROMs and SerialFlash memories, which communicate using SPI-compatible signals. These routines implement a driver for the X25xxxx series of devices.

Visit the Xicor25 Driver page for details and the source code.


PC Printer Port I/O Module

While not strictly an embedded application, the standard PC printer port is handy for testing and controlling devices. It provides an easy way to implement a small amount of digital I/O.

Visit the Parallel Port page for details and the source code.


Disclaimer

There is no warranty, either expressed or implied, with respect to the code contained on this page, it's quality, performance, or fitness for any particular purpose. All code is offered "as is". I am not responsible for what you do with the code (or what the code does to you). In other words, you're on your own ...

Also, I make no claims that this is great code. There are nearly always better and/or different ways to do things. These routines work for me, but your mileage may vary ...


blog comments powered by Disqus