This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

基于TM4C129的nokia5100驱动分享

// Nokia5110.c和Nokia5110.h代码

// Nokia5110.c
// Runs on LM4F120/TM4C123
// Use SSI0 to send an 8-bit code to the Nokia5110 48x84
// pixel LCD to display text, images, or other information.
// Daniel Valvano
// September 16, 2013

// Font table, initialization, and other functions based
// off of Nokia_5110_Example from Spark Fun:
// 7-17-2011
// Spark Fun Electronics 2011
// Nathan Seidle
// dlnmh9ip6v2uc.cloudfront.net/.../Nokia_5110_Example.pde

/* This example accompanies the book
"Embedded Systems: Introduction to ARM Cortex M Microcontrollers",
ISBN: 978-1469998749, Jonathan Valvano, copyright (c) 2014

Copyright 2014 by Jonathan W. Valvano, valvano@mail.utexas.edu
You may use, edit, run or distribute this file
as long as the above copyright notice remains
THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
For more information about my classes, my research, and my books, see
users.ece.utexas.edu/.../
*/
#include "TM4C129.h"                    // Device header


// Blue Nokia 5110
// ---------------
// Signal        (Nokia 5110) LaunchPad pin
// Reset         (RST, pin 1) connected to PK1
// SSI1Fss       (CE,  pin 2) connected to PB4
// Data/Command  (DC,  pin 3) connected to PK0
// SSI1Tx        (Din, pin 4) connected to PE4
// SSI1Clk       (Clk, pin 5) connected to PB5
// 3.3V          (Vcc, pin 6) power
// back light    (BL,  pin 7) not connected, consists of 4 white LEDs which draw ~80mA total
// Ground        (Gnd, pin 8) ground

// Red SparkFun Nokia 5110 (LCD-10168)
// -----------------------------------
// Signal        (Nokia 5110) LaunchPad pin
// 3.3V          (VCC, pin 1) power
// Ground        (GND, pin 2) ground
// SSI1Fss       (SCE, pin 3) connected to PB4
// Reset         (RST, pin 4) connected to PK1
// Data/Command  (D/C, pin 5) connected to PK0
// SSI1Tx        (DN,  pin 6) connected to PE4
// SSI1Clk       (SCLK, pin 7) connected to PB5
// back light    (LED, pin 8) not connected, consists of 4 white LEDs which draw ~80mA total

#include <stdint.h>
#include "nokia5110LCD.h"
#include "timer.h"
// *************************** Screen dimensions ***************************
#define SCREENW     84
#define SCREENH     48

#define DC                      (*((volatile uint32_t *)(GPIOK_BASE + (1ul << 2))))
#define DC_COMMAND              0
#define DC_DATA                 0x01
#define RESET                   (*((volatile uint32_t *)(GPIOK_BASE + (1ul << 3))))
#define RESET_LOW               0
#define RESET_HIGH              0x02

enum typeOfWrite
{
    COMMAND,                              // the transmission is an LCD command
    DATA                                  // the transmission is data
};


// This table contains the hex values that represent pixels
// for a font that is 5 pixels wide and 8 pixels high
static const uint8_t ASCII[][5] = 
{
    {0x00, 0x00, 0x00, 0x00, 0x00}, // 20
    {0x00, 0x00, 0x5f, 0x00, 0x00}, // 21 !
    {0x00, 0x07, 0x00, 0x07, 0x00}, // 22 "
    {0x14, 0x7f, 0x14, 0x7f, 0x14}, // 23 #
    {0x24, 0x2a, 0x7f, 0x2a, 0x12}, // 24 $
    {0x23, 0x13, 0x08, 0x64, 0x62}, // 25 %
    {0x36, 0x49, 0x55, 0x22, 0x50}, // 26 &
    {0x00, 0x05, 0x03, 0x00, 0x00}, // 27 '
    {0x00, 0x1c, 0x22, 0x41, 0x00}, // 28 (
    {0x00, 0x41, 0x22, 0x1c, 0x00}, // 29 )
    {0x14, 0x08, 0x3e, 0x08, 0x14}, // 2a *
    {0x08, 0x08, 0x3e, 0x08, 0x08}, // 2b +
    {0x00, 0x50, 0x30, 0x00, 0x00}, // 2c ,
    {0x08, 0x08, 0x08, 0x08, 0x08}, // 2d -
    {0x00, 0x60, 0x60, 0x00, 0x00}, // 2e .
    {0x20, 0x10, 0x08, 0x04, 0x02}, // 2f /
    {0x3e, 0x51, 0x49, 0x45, 0x3e}, // 30 0
    {0x00, 0x42, 0x7f, 0x40, 0x00}, // 31 1
    {0x42, 0x61, 0x51, 0x49, 0x46}, // 32 2
    {0x21, 0x41, 0x45, 0x4b, 0x31}, // 33 3
    {0x18, 0x14, 0x12, 0x7f, 0x10}, // 34 4
    {0x27, 0x45, 0x45, 0x45, 0x39}, // 35 5
    {0x3c, 0x4a, 0x49, 0x49, 0x30}, // 36 6
    {0x01, 0x71, 0x09, 0x05, 0x03}, // 37 7
    {0x36, 0x49, 0x49, 0x49, 0x36}, // 38 8
    {0x06, 0x49, 0x49, 0x29, 0x1e}, // 39 9
    {0x00, 0x36, 0x36, 0x00, 0x00}, // 3a :
    {0x00, 0x56, 0x36, 0x00, 0x00}, // 3b ;
    {0x08, 0x14, 0x22, 0x41, 0x00}, // 3c <
    {0x14, 0x14, 0x14, 0x14, 0x14}, // 3d =
    {0x00, 0x41, 0x22, 0x14, 0x08}, // 3e >
    {0x02, 0x01, 0x51, 0x09, 0x06}, // 3f ?
    {0x32, 0x49, 0x79, 0x41, 0x3e}, // 40 @
    {0x7e, 0x11, 0x11, 0x11, 0x7e}, // 41 A
    {0x7f, 0x49, 0x49, 0x49, 0x36}, // 42 B
    {0x3e, 0x41, 0x41, 0x41, 0x22}, // 43 C
    {0x7f, 0x41, 0x41, 0x22, 0x1c}, // 44 D
    {0x7f, 0x49, 0x49, 0x49, 0x41}, // 45 E
    {0x7f, 0x09, 0x09, 0x09, 0x01}, // 46 F
    {0x3e, 0x41, 0x49, 0x49, 0x7a}, // 47 G
    {0x7f, 0x08, 0x08, 0x08, 0x7f}, // 48 H
    {0x00, 0x41, 0x7f, 0x41, 0x00}, // 49 I
    {0x20, 0x40, 0x41, 0x3f, 0x01}, // 4a J
    {0x7f, 0x08, 0x14, 0x22, 0x41}, // 4b K
    {0x7f, 0x40, 0x40, 0x40, 0x40}, // 4c L
    {0x7f, 0x02, 0x0c, 0x02, 0x7f}, // 4d M
    {0x7f, 0x04, 0x08, 0x10, 0x7f}, // 4e N
    {0x3e, 0x41, 0x41, 0x41, 0x3e}, // 4f O
    {0x7f, 0x09, 0x09, 0x09, 0x06}, // 50 P
    {0x3e, 0x41, 0x51, 0x21, 0x5e}, // 51 Q
    {0x7f, 0x09, 0x19, 0x29, 0x46}, // 52 R
    {0x46, 0x49, 0x49, 0x49, 0x31}, // 53 S
    {0x01, 0x01, 0x7f, 0x01, 0x01}, // 54 T
    {0x3f, 0x40, 0x40, 0x40, 0x3f}, // 55 U
    {0x1f, 0x20, 0x40, 0x20, 0x1f}, // 56 V
    {0x3f, 0x40, 0x38, 0x40, 0x3f}, // 57 W
    {0x63, 0x14, 0x08, 0x14, 0x63}, // 58 X
    {0x07, 0x08, 0x70, 0x08, 0x07}, // 59 Y
    {0x61, 0x51, 0x49, 0x45, 0x43}, // 5a Z
    {0x00, 0x7f, 0x41, 0x41, 0x00}, // 5b [
    {0x02, 0x04, 0x08, 0x10, 0x20}, // 5c '\'
    {0x00, 0x41, 0x41, 0x7f, 0x00}, // 5d ]
    {0x04, 0x02, 0x01, 0x02, 0x04}, // 5e ^
    {0x40, 0x40, 0x40, 0x40, 0x40}, // 5f _
    {0x00, 0x01, 0x02, 0x04, 0x00}, // 60 `
    {0x20, 0x54, 0x54, 0x54, 0x78}, // 61 a
    {0x7f, 0x48, 0x44, 0x44, 0x38}, // 62 b
    {0x38, 0x44, 0x44, 0x44, 0x20}, // 63 c
    {0x38, 0x44, 0x44, 0x48, 0x7f}, // 64 d
    {0x38, 0x54, 0x54, 0x54, 0x18}, // 65 e
    {0x08, 0x7e, 0x09, 0x01, 0x02}, // 66 f
    {0x0c, 0x52, 0x52, 0x52, 0x3e}, // 67 g
    {0x7f, 0x08, 0x04, 0x04, 0x78}, // 68 h
    {0x00, 0x44, 0x7d, 0x40, 0x00}, // 69 i
    {0x20, 0x40, 0x44, 0x3d, 0x00}, // 6a j
    {0x7f, 0x10, 0x28, 0x44, 0x00}, // 6b k
    {0x00, 0x41, 0x7f, 0x40, 0x00}, // 6c l
    {0x7c, 0x04, 0x18, 0x04, 0x78}, // 6d m
    {0x7c, 0x08, 0x04, 0x04, 0x78}, // 6e n
    {0x38, 0x44, 0x44, 0x44, 0x38}, // 6f o
    {0x7c, 0x14, 0x14, 0x14, 0x08}, // 70 p
    {0x08, 0x14, 0x14, 0x18, 0x7c}, // 71 q
    {0x7c, 0x08, 0x04, 0x04, 0x08}, // 72 r
    {0x48, 0x54, 0x54, 0x54, 0x20}, // 73 s
    {0x04, 0x3f, 0x44, 0x40, 0x20}, // 74 t
    {0x3c, 0x40, 0x40, 0x20, 0x7c}, // 75 u
    {0x1c, 0x20, 0x40, 0x20, 0x1c}, // 76 v
    {0x3c, 0x40, 0x30, 0x40, 0x3c}, // 77 w
    {0x44, 0x28, 0x10, 0x28, 0x44}, // 78 x
    {0x0c, 0x50, 0x50, 0x50, 0x3c}, // 79 y
    {0x44, 0x64, 0x54, 0x4c, 0x44}, // 7a z
    {0x00, 0x08, 0x36, 0x41, 0x00}, // 7b {
    {0x00, 0x00, 0x7f, 0x00, 0x00}, // 7c |
    {0x00, 0x41, 0x36, 0x08, 0x00}, // 7d }
    {0x10, 0x08, 0x08, 0x10, 0x08}, // 7e ~
    //    {0x78, 0x46, 0x41, 0x46, 0x78}, // 7f DEL
    {0x1f, 0x24, 0x7c, 0x24, 0x1f}, // 7f UT sign
};

// The Data/Command pin must be valid when the eighth bit is
// sent.  The SSI module has hardware input and output FIFOs
// that are 8 locations deep.  Based on the observation that
// the LCD interface tends to send a few commands and then a
// lot of data, the FIFOs are not used when writing
// commands, and they are used when writing data.  This
// ensures that the Data/Command pin status matches the byte
// that is actually being transmitted.
// The write command operation waits until all data has been
// sent, configures the Data/Command pin for commands, sends
// the command, and then waits for the transmission to
// finish.
// The write data operation waits until there is room in the
// transmit FIFO, configures the Data/Command pin for data,
// and then adds the data to the transmit FIFO.

// This is a helper function that sends an 8-bit message to the LCD.
// inputs: type     COMMAND or DATA
//         message  8-bit code to transmit
// outputs: none
// assumes: SSI0 and port A have already been initialized and enabled
void static lcdwrite(enum typeOfWrite type, uint8_t message)
{
    if(type == COMMAND)
    {
        while(SSI1->SR & 0x00000010){};    // wait until SSI0 not busy/transmit FIFO empty
        DC = DC_COMMAND;
        SSI1->DR = message;                            // command out
        while(SSI1->SR & 0x00000010){};    // wait until SSI0 not busy/transmit FIFO empty
    } 
    else
    {
        while(!(SSI1->SR & 0x00000002)){}; // wait until transmit FIFO not full
        DC = DC_DATA;
        SSI1->DR = message;                // data out
    }
}

void static lcddatawrite(uint8_t data)
{
    while(!(SSI1->SR & 0x00000002)){};     // wait until transmit FIFO not full
    DC = DC_DATA;
    SSI1->DR = data;                       // data out
}

//********Nokia5110_Init*****************
// Initialize Nokia 5110 48x84 LCD by sending the proper
// commands to the PCD8544 driver.  One new feature of the
// LM4F120 is that its SSIs can get their baud clock from
// either the system clock or from the 16 MHz precision
// internal oscillator.
// inputs: none
// outputs: none
// assumes: system clock rate of 80 MHz

/*
Pull-ups can be used to avoid unnecessary toggles on the QSSI pins, which can take
the slave to a wrong state. In addition, if the SSIClk signal is programmed to steady
state High through the SPO bit in the SSICR0 register, then software must also configure
the GPIO port pin corresponding to the SSInClk signal as a pull-up in the GPIO Pull-Up
Select (GPIOPUR) register.
*/

void Nokia5110_Init(void)
{
    volatile uint32_t delay;
    SYSCTL->RCGCSSI |= 0x02;            // activate SSI1

    SYSCTL->RCGCGPIO |= (1ul << 1) | (1ul << 4) | (1ul << 9);           // activate port B - E - K

    GPIOB_AHB->AFSEL |= 0x30;           // PB4-PB5 Enable Alternate Function
    GPIOB_AHB->DEN |= 0x30;             // PB4-PB5 Enable Digital IO
    GPIOB_AHB->PCTL |= 0x00FF0000;      // PB4-PB5 Select Digital Function (SSI1Fss - SSI1Clk)
    GPIOB_AHB->PDR |= 0x20;
//    GPIOD_AHB->AFSEL |= 0x30;           // PD4-PD5 Enable Alternate Function
//    GPIOD_AHB->DEN |= 0x30;             // PD4-PD5 Enable Digital IO
//    GPIOD_AHB->PCTL |= 0x00FF0000;      // PD4-PD5 Select Digital Function (SSI1XDAT2 - SSI1XDAT3)
    
    GPIOE_AHB->AFSEL |= 0x30;           // PE4-PE5 Enable Alternate Function
    GPIOE_AHB->DEN |= 0x30;             // PE4-PE5 Enable Digital IO
    GPIOE_AHB->PCTL |= 0x00FF0000;      // PE4-PE5 Select Digital Function (SSI1XDAT0 - SSI1XDAT1)
    
    GPIOK->DIR |= 0x03;                 // PD4-PD5 output (RESET and DATA/COMMAND PINS)
    GPIOK->DEN |= 0x03;                 // PD4-PD5 Enable Digital IO
    
    SSI1->CR1 &= ~0x02;                 // disable SSI(clearing SSE bit)
    SSI1->CR1 &= ~0x04;                 // master mode
                                        
    SSI1->CC = 0;                       // configure for Sysclk baud clock source (80)
    
                                        // clock divider for 3.3 MHz SSIClk (80 MHz PLL/24)
                                        // CLK/(CPSDVSR*(1+SCR)) (datasheet page1242)
                                        // 16/(1*(1+4)) = 3.2 MHz (slower than 4 MHz which is max operation MHz of Nokia LCD)
    SSI1->CPSR = 24;                    // must be even number (datasheet page 1252)
    SSI1->CR0 &= ~(0x0000FF00 |         // SCR = 0 (3.33 Mbps data rate)
                   0x00000080 |         // SPH = 0 (serial clock phase --> data is captured on the first clock edge transition)
                   0x00000040);         // SPO = 0 (clock parity --> steady state low)
                                    
    SSI1->CR0 = (SSI1->CR0 & ~0x00000030);                  // FRF = Freescale format (freescale SPI format)                                            
    SSI1->CR0 = (SSI1->CR0 &~ 0x0000000F) + 0x00000007;     // DSS = 8-bit data
    
    SSI1->CR1 |= 0x02;                  // enable SSI

    RESET = RESET_LOW;                  // reset the LCD to a known state
    timer_delay_us(200);                // min 100us
    RESET = RESET_HIGH;                 // negative logic

    lcdwrite(COMMAND, 0x21);            // chip active; horizontal addressing mode (V = 0); use extended instruction set (H = 1)
                                        // set LCD Vop (contrast), which may require some tweaking:
    lcdwrite(COMMAND, ((CONTRAST & 0x7F) | 0x40)); // try 0xB1 (for 3.3V red SparkFun), 0xB8 (for 3.3V blue SparkFun), 0xBF if your display is too dark, or 0x80 to 0xFF if experimenting
    lcdwrite(COMMAND, 0x04);            // set temp coefficient
    lcdwrite(COMMAND, 0x14);            // LCD bias mode 1:48: try 0x13 or 0x14

    lcdwrite(COMMAND, 0x20);            // we must send 0x20 before modifying the display control mode // normal instruction set
    lcdwrite(COMMAND, 0x0C);            // set display control to normal mode: 0x0D for inverse
}

//********Nokia5110_OutChar*****************
// Print a character to the Nokia 5110 48x84 LCD.  The
// character will be printed at the current cursor position,
// the cursor will automatically be updated, and it will
// wrap to the next row or back to the top if necessary.
// One blank column of pixels will be printed on either side
// of the character for readability.  Since characters are 8
// pixels tall and 5 pixels wide, 12 characters fit per row,
// and there are six rows.
// inputs: data  character to print
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutChar(char data)
{
    int i;
    lcddatawrite(0x00);        // blank vertical line padding
    for(i=0; i<5; i=i+1)
    {
        lcddatawrite(ASCII[data - 0x20][i]);
    }
    lcddatawrite(0x00);        // blank vertical line padding
}

//********Nokia5110_OutString*****************
// Print a string of characters to the Nokia 5110 48x84 LCD.
// The string will automatically wrap, so padding spaces may
// be needed to make the output look optimal.
// inputs: ptr  pointer to NULL-terminated ASCII string
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutString(char *ptr)
{
    while(*ptr)
    {
        Nokia5110_OutChar((unsigned char)*ptr);
        ptr = ptr + 1;
    }
}

//********Nokia5110_OutUDec*****************
// Output a 16-bit number in unsigned decimal format with a
// fixed size of five right-justified digits of output.
// Inputs: n  16-bit unsigned number
// Outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_OutUDec(uint16_t n)
{
    if(n < 10)
    {
        Nokia5110_OutString("    ");
        Nokia5110_OutChar(n+'0'); /* n is between 0 and 9 */
    } 
    else if(n<100)
    {
        Nokia5110_OutString("   ");
        Nokia5110_OutChar(n/10+'0'); /* tens digit */
        Nokia5110_OutChar(n%10+'0'); /* ones digit */
    } 
    else if(n<1000)
    {
        Nokia5110_OutString("  ");
        Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
        n = n%100;
        Nokia5110_OutChar(n/10+'0'); /* tens digit */
        Nokia5110_OutChar(n%10+'0'); /* ones digit */
    }
    else if(n<10000)
    {
        Nokia5110_OutChar(' ');
        Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
        n = n%1000;
        Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
        n = n%100;
        Nokia5110_OutChar(n/10+'0'); /* tens digit */
        Nokia5110_OutChar(n%10+'0'); /* ones digit */
    }
    else 
    {
        Nokia5110_OutChar(n/10000+'0'); /* ten-thousands digit */
        n = n%10000;
        Nokia5110_OutChar(n/1000+'0'); /* thousands digit */
        n = n%1000;
        Nokia5110_OutChar(n/100+'0'); /* hundreds digit */
        n = n%100;
        Nokia5110_OutChar(n/10+'0'); /* tens digit */
        Nokia5110_OutChar(n%10+'0'); /* ones digit */
    }
}

//********Nokia5110_SetCursor*****************
// Move the cursor to the desired X- and Y-position.  The
// next character will be printed here.  X=0 is the leftmost
// column.  Y=0 is the top row.
// inputs: newX  new X-position of the cursor (0<=newX<=11)
//         newY  new Y-position of the cursor (0<=newY<=5)
// outputs: none
void Nokia5110_SetCursor(uint8_t newX, uint8_t newY)
{
    if((newX > 11) || (newY > 5))
    {        // bad input
        return;                             // do nothing
    }
    // multiply newX by 7 because each character is 7 columns wide
    lcdwrite(COMMAND, 0x80|(newX*7));     // setting bit 7 updates X-position
    lcdwrite(COMMAND, 0x40|newY);         // setting bit 6 updates Y-position
}

//********Nokia5110_Clear*****************
// Clear the LCD by writing zeros to the entire screen and
// reset the cursor to (0,0) (top left corner of screen).
// inputs: none
// outputs: none
void Nokia5110_Clear(void)
{
    int i;
    for(i=0; i<(MAX_X*MAX_Y/8); i=i+1)
    {
        lcddatawrite(0x00);
    }
    Nokia5110_SetCursor(0, 0);
}

//********Nokia5110_DrawFullImage*****************
// Fill the whole screen by drawing a 48x84 bitmap image.
// inputs: ptr  pointer to 504 byte bitmap
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_DrawFullImage(const uint8_t *ptr)
{
    int i;
    Nokia5110_SetCursor(0, 0);
    for(i=0; i<(MAX_X*MAX_Y/8); i=i+1)
    {
        lcddatawrite(ptr[i]);
    }
}

void Nokia5110_inverse_mod(bool t)
{    
    if(t == true)
        lcdwrite(COMMAND, 0x0D);
    else
        lcdwrite(COMMAND, 0x0C);
}

uint8_t Screen[SCREENW*SCREENH/8]; // buffer stores the next image to be printed on the screen

//********Nokia5110_PrintBMP*****************
// Bitmaps defined above were created for the LM3S1968 or
// LM3S8962's 4-bit grayscale OLED display.  They also
// still contain their header data and may contain padding
// to preserve 4-byte alignment.  This function takes a
// bitmap in the previously described format and puts its
// image data in the proper location in the buffer so the
// image will appear on the screen after the next call to
//   Nokia5110_DisplayBuffer();
// The interface and operation of this process is modeled
// after RIT128x96x4_BMP(x, y, image);
// inputs: xpos      horizontal position of bottom left corner of image, columns from the left edge
//                     must be less than 84
//                     0 is on the left; 82 is near the right
//         ypos      vertical position of bottom left corner of image, rows from the top edge
//                     must be less than 48
//                     2 is near the top; 47 is at the bottom
//         ptr       pointer to a 16 color BMP image
//         threshold grayscale colors above this number make corresponding pixel 'on'
//                     0 to 14
//                     0 is fine for ships, explosions, projectiles, and bunkers
// outputs: none
void Nokia5110_PrintBMP(uint8_t xpos, uint8_t ypos, const uint8_t *ptr, uint8_t threshold)
{
    int32_t width = ptr[18], height = ptr[22], i, j;
    uint16_t screenx, screeny;
    uint8_t mask;
    // check for clipping
    if((height <= 0) ||           // bitmap is unexpectedly encoded in top-to-bottom pixel order
    ((width%2) != 0) ||           // must be even number of columns
    ((xpos + width) > SCREENW) || // right side cut off
    (ypos < (height - 1)) ||      // top cut off
    (ypos > SCREENH))           
    { // bottom cut off
        return;
    }
    if(threshold > 14)
    {
        threshold = 14;             // only full 'on' turns pixel on
    }
    // bitmaps are encoded backwards, so start at the bottom left corner of the image
    screeny = ypos/8;
    screenx = xpos + SCREENW*screeny;
    mask = ypos%8;                // row 0 to 7
    mask = 0x01<<mask;            // now stores a mask 0x01 to 0x80
    j = ptr[10];                  // byte 10 contains the offset where image data can be found
    
    for(i=1; i<=(width*height/2); i=i+1)
    {
        // the left pixel is in the upper 4 bits
        if(((ptr[j]>>4)&0xF) > threshold)
        {
            Screen[screenx] |= mask;
        }
        else
        {
            Screen[screenx] &= ~mask;
        }
        
        screenx = screenx + 1;
        // the right pixel is in the lower 4 bits
        if((ptr[j]&0xF) > threshold)
        {
            Screen[screenx] |= mask;
        }
        else
        {
            Screen[screenx] &= ~mask;
        }
        
        screenx = screenx + 1;
        j = j + 1;
        
        if((i%(width/2)) == 0)
        {     // at the end of a row
            if(mask > 0x01)
            {
                mask = mask>>1;
            } 
            else
            {
                mask = 0x80;
                screeny = screeny - 1;
            }
            screenx = xpos + SCREENW*screeny;
            // bitmaps are 32-bit word aligned
            switch((width/2)%4)
            {      // skip any padding
                case 0: j = j + 0; break;
                case 1: j = j + 3; break;
                case 2: j = j + 2; break;
                case 3: j = j + 1; break;
            }
        }
    }
}

// There is a buffer in RAM that holds one screen
// This routine clears this buffer
void Nokia5110_ClearBuffer(void)
{
    int i;
    for(i=0; i<SCREENW*SCREENH/8; i=i+1)
    {
        Screen[i] = 0;              // clear buffer
    }
}

//********Nokia5110_DisplayBuffer*****************
// Fill the whole screen by drawing a 48x84 screen image.
// inputs: none
// outputs: none
// assumes: LCD is in default horizontal addressing mode (V = 0)
void Nokia5110_DisplayBuffer(void)
{
    Nokia5110_DrawFullImage(Screen);
}

const unsigned char Masks[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

//------------Nokia5110_ClrPxl------------
// Clear the Image pixel at (i, j), turning it dark.
// Input: i  the row index  (0 to 47 in this case),    y-coordinate
//        j  the column index  (0 to 83 in this case), x-coordinate
// Output: none		
void Nokia5110_ClrPxl(uint32_t i, uint32_t j)
{
    Screen[84*(i>>3) + j] &= ~Masks[i&0x07];
}

//------------Nokia5110_SetPxl------------
// Set the Image pixel at (i, j), turning it on.
// Input: i  the row index  (0 to 47 in this case),    y-coordinate
//        j  the column index  (0 to 83 in this case), x-coordinate
// Output: none		
void Nokia5110_SetPxl(uint32_t i, uint32_t j)
{
    Screen[84*(i>>3) + j] |= Masks[i&0x07];
}
  • #ifndef _NOKIA5110LCD_H
    #define _NOKIA5110LCD_H
    
    #include "types.h"
    // Nokia5110.h
    // Runs on LM4F120/TM4C123
    // Use SSI0 to send an 8-bit code to the Nokia5110 48x84
    // pixel LCD to display text, images, or other information.
    // Daniel Valvano
    // September 16, 2013
    
    // Font table, initialization, and other functions based
    // off of Nokia_5110_Example from Spark Fun:
    // 7-17-2011
    // Spark Fun Electronics 2011
    // Nathan Seidle
    // dlnmh9ip6v2uc.cloudfront.net/.../Nokia_5110_Example.pde
    
    /* This example accompanies the book
    "Embedded Systems: Real Time Interfacing to Arm Cortex M Microcontrollers",
    ISBN: 978-1463590154, Jonathan Valvano, copyright (c) 2014
    
    Copyright 2014 by Jonathan W. Valvano, valvano@mail.utexas.edu
    You may use, edit, run or distribute this file
    as long as the above copyright notice remains
    THIS SOFTWARE IS PROVIDED "AS IS".  NO WARRANTIES, WHETHER EXPRESS, IMPLIED
    OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
    VALVANO SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
    OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
    For more information about my classes, my research, and my books, see
    users.ece.utexas.edu/.../
    */
    
    // Blue Nokia 5110
    // ---------------
    // Signal        (Nokia 5110) LaunchPad pin
    // Reset         (RST, pin 1) connected to PA7
    // SSI0Fss       (CE,  pin 2) connected to PA3
    // Data/Command  (DC,  pin 3) connected to PA6
    // SSI0Tx        (Din, pin 4) connected to PA5
    // SSI0Clk       (Clk, pin 5) connected to PA2
    // 3.3V          (Vcc, pin 6) power
    // back light    (BL,  pin 7) not connected
    // Ground        (Gnd, pin 8) ground
    
    // Red SparkFun Nokia 5110 (LCD-10168)
    // -----------------------------------
    // Signal        (Nokia 5110) LaunchPad pin
    // 3.3V          (VCC, pin 1) power
    // Ground        (GND, pin 2) ground
    // SSI0Fss       (SCE, pin 3) connected to PA3
    // Reset         (RST, pin 4) connected to PA7
    // Data/Command  (D/C, pin 5) connected to PA6
    // SSI0Tx        (DN,  pin 6) connected to PA5
    // SSI0Clk       (SCLK, pin 7) connected to PA2
    // back light    (LED, pin 8) not connected
    
    // Maximum dimensions of the LCD, although the pixels are
    // numbered from zero to (MAX-1).  Address may automatically
    // be incremented after each transmission.
    #define MAX_X                   84
    #define MAX_Y                   48
    
    // Contrast value 0xB1 looks good on red SparkFun
    // and 0xB8 looks good on blue Nokia 5110.
    // Adjust this from 0xA0 (lighter) to 0xCF (darker) for your display.
    #define CONTRAST                0xFF
    
    
    //********Nokia5110_Init*****************
    // Initialize Nokia 5110 48x84 LCD by sending the proper
    // commands to the PCD8544 driver.  One new feature of the
    // LM4F120 is that its SSIs can get their baud clock from
    // either the system clock or from the 16 MHz precision
    // internal oscillator.  If the system clock is faster than
    // 50 MHz, the SSI baud clock will be faster than the 4 MHz
    // maximum of the Nokia 5110.
    // inputs: none
    // outputs: none
    // assumes: system clock rate of 50 MHz or less
    extern void Nokia5110_Init(void);
    
    extern void Nokia5110_inverse_mod(bool);
    
    //********Nokia5110_OutChar*****************
    // Print a character to the Nokia 5110 48x84 LCD.  The
    // character will be printed at the current cursor position,
    // the cursor will automatically be updated, and it will
    // wrap to the next row or back to the top if necessary.
    // One blank column of pixels will be printed on either side
    // of the character for readability.  Since characters are 8
    // pixels tall and 5 pixels wide, 12 characters fit per row,
    // and there are six rows.
    // inputs: data  character to print
    // outputs: none
    // assumes: LCD is in default horizontal addressing mode (V = 0)
    extern void Nokia5110_OutChar(char);
    
    //********Nokia5110_OutString*****************
    // Print a string of characters to the Nokia 5110 48x84 LCD.
    // The string will automatically wrap, so padding spaces may
    // be needed to make the output look optimal.
    // inputs: ptr  pointer to NULL-terminated ASCII string
    // outputs: none
    // assumes: LCD is in default horizontal addressing mode (V = 0)
    extern void Nokia5110_OutString(char *);
    
    //********Nokia5110_OutUDec*****************
    // Output a 16-bit number in unsigned decimal format with a
    // fixed size of five right-justified digits of output.
    // Inputs: n  16-bit unsigned number
    // Outputs: none
    // assumes: LCD is in default horizontal addressing mode (V = 0)
    extern void Nokia5110_OutUDec(uint16_t);
    
    //********Nokia5110_SetCursor*****************
    // Move the cursor to the desired X- and Y-position.  The
    // next character will be printed here.  X=0 is the leftmost
    // column.  Y=0 is the top row.
    // inputs: newX  new X-position of the cursor (0<=newX<=11)
    //         newY  new Y-position of the cursor (0<=newY<=5)
    // outputs: none
    extern void Nokia5110_SetCursor(uint8_t, uint8_t);
    
    //********Nokia5110_Clear*****************
    // Clear the LCD by writing zeros to the entire screen and
    // reset the cursor to (0,0) (top left corner of screen).
    // inputs: none
    // outputs: none
    extern void Nokia5110_Clear(void);
    
    //********Nokia5110_DrawFullImage*****************
    // Fill the whole screen by drawing a 48x84 bitmap image.
    // inputs: ptr  pointer to 504 byte bitmap
    // outputs: none
    // assumes: LCD is in default horizontal addressing mode (V = 0)
    extern void Nokia5110_DrawFullImage(const uint8_t *);
    
    //********Nokia5110_PrintBMP*****************
    // Bitmaps defined above were created for the LM3S1968 or
    // LM3S8962's 4-bit grayscale OLED display.  They also
    // still contain their header data and may contain padding
    // to preserve 4-byte alignment.  This function takes a
    // bitmap in the previously described format and puts its
    // image data in the proper location in the buffer so the
    // image will appear on the screen after the next call to
    //   Nokia5110_DisplayBuffer();
    // The interface and operation of this process is modeled
    // after RIT128x96x4_BMP(x, y, image);
    // inputs: xpos      horizontal position of bottom left corner of image, columns from the left edge
    //                     must be less than 84
    //                     0 is on the left; 82 is near the right
    //         ypos      vertical position of bottom left corner of image, rows from the top edge
    //                     must be less than 48
    //                     2 is near the top; 47 is at the bottom
    //         ptr       pointer to a 16 color BMP image
    //         threshold grayscale colors above this number make corresponding pixel 'on'
    //                     0 to 14
    //                     0 is fine for ships, explosions, projectiles, and bunkers
    // outputs: none
    extern void Nokia5110_PrintBMP(uint8_t, uint8_t, const uint8_t *, uint8_t );
    
    // There is a buffer in RAM that holds one screen
    // This routine clears this buffer
    extern void Nokia5110_ClearBuffer(void);
    
    //********Nokia5110_DisplayBuffer*****************
    // Fill the whole screen by drawing a 48x84 screen image.
    // inputs: none
    // outputs: none
    // assumes: LCD is in default horizontal addressing mode (V = 0)
    extern void Nokia5110_DisplayBuffer(void);
    
    //------------Nokia5110_ClrPxl------------
    // Clear the Image pixel at (i, j), turning it dark.
    // Input: i  the row index  (0 to 47 in this case),    y-coordinate
    //        j  the column index  (0 to 83 in this case), x-coordinate
    // Output: none		
    extern void Nokia5110_ClrPxl(uint32_t, uint32_t);
    
    //------------Nokia5110_SetPxl------------
    // Set the Image pixel at (i, j), turning it on.
    // Input: i  the row index  (0 to 47 in this case),    y-coordinate
    //        j  the column index  (0 to 83 in this case), x-coordinate
    // Output: none		
    extern void Nokia5110_SetPxl(uint32_t, uint32_t);
    
    #endif