MSP430 Nokia 3310 LCD (PCD8544)

msp430_nokia3310_LCDHier entsteht eine kleine Bibliothek für Grafik-LCDs. Angefangen habe ich mit einem Nokia 3310 LCD (PCD8544 Controller). Eine kleine Demonstration kann man in dem Video sehen. Die Bibliothek wird in nächster Zeit noch ein paar Funktionen dazu bekommen (es fehlen noch viele Funktionen, wie z.B. Linien zeichnen, Rechtecke, Kreise etc.). Bei dem verwendeten Nokia 3310 LCD handelt sich um ein Ersatz-Display (kann auf Ebay bestellt werden). Der sichtbare Bereich des Displays beträgt 96×64 Pixel (der Display-Speicher ist aber etwas größer). WICHTIG: Das originale Nokia 3310 LCD hat eine Auflösung von 84×48 Pixel! Die Ansteuerung (besonders die Initialsierung) ist bei diesem Display ziemlich einfach, da es nicht viele Einstellmöglichkeiten gibt, beschränkt sich also auf ein paar Befehle. Angesteuert wird das LCD über einen MSP430G2553 (per SPI).

Video

Schaltplan

msp430_nokia3310_LCD

Source-Code

Der komplette Source-Code: DOWNLOAD SOURCE

Zwei Ausschnitte: main.c und lib_lcd.c

main.c

  1. /*******************************
  2.  *          __                   
  3.  *         /\ \                  
  4.  *  __  _  \_\ \     __    ___   
  5.  * /\ \/'\ /'_' \  /'__'\ /'___\
  6.  * \/>  <//\ \ \ \/\  __//\ \__/
  7.  *  /\_/\_\ \___,_\ \____\ \____\
  8.  *  \//\/_/\/__,_ /\/____/\/____/
  9.  *
  10.  *  Author: declis (xdec.de)
  11.  ********************************/
  12.  
  13. #include <msp430g2553.h>
  14. #include "lib_lcd.h"
  15. #include "delay.h"
  16. #include "bitmaps.h"
  17. #include "data.h"
  18.  
  19. void main(void)
  20. {
  21.     signed int x=0,y=-184,num=0,x1=0,y1=0;
  22.  
  23.     WDTCTL=WDTPW+WDTHOLD;  
  24.     BCSCTL1=CALBC1_8MHZ;                // SMCLK=~8MHz  
  25.     DCOCTL=CALDCO_8MHZ;
  26.  
  27.     init_USCI();
  28.     init_LCD();
  29.  
  30.     // SCENE 00 - "Countdown" ----------------------------
  31.     wait_ms(500);
  32.     countdown('3');
  33.     countdown('2');
  34.     countdown('1');
  35.     wait_ms(500);
  36.     write_string(3,2,gogo,5);
  37.     wait_ms(1000);
  38.     fill_display(lcd_width,lcd_height,0);
  39.     // ---------------------------------------------------
  40.     // SCENE 01 - "Motoko Vertical-Scroller" -------------
  41.     while(y!=16)
  42.     {
  43.         draw_bitmap(0,y++,ghost_w,ghost_h,ghost);
  44.         wait_ms(80);
  45.     }
  46.     write_string(0,0,moto,1);
  47.     wait_ms(2000);
  48.     while(y!=-85)
  49.     {
  50.         draw_bitmap(0,y--,ghost_w,ghost_h,ghost);
  51.         wait_ms(80);
  52.     }
  53.     wait_ms(2000);
  54.     // ---------------------------------------------------
  55.     // SCENE 02 - "Motoko Horizontal-Overlap-Scroller" ---
  56.     y=0;
  57.     while(x!=-lcd_width)
  58.     {
  59.         draw_bitmap(x--,-85,ghost_w,ghost_h,ghost);
  60.         draw_bitmap(y++,-85,ghost_w,ghost_h,ghost);
  61.     }
  62.     while(x<=lcd_width)
  63.     {
  64.         draw_bitmap(x++,-85,ghost_w,ghost_h,ghost);
  65.         draw_bitmap(y--,-85,ghost_w,ghost_h,ghost);
  66.     }
  67.     wait_ms(500);
  68.     // ---------------------------------------------------
  69.     // SCENE 03 - "String-Typer" -------------------------
  70.     string_typer(3,0,powa0,0,typer_ms);
  71.     string_typer(3,1,powa1,1,typer_ms);
  72.     string_typer(3,3,powa2,0,typer_ms);
  73.     wait_ms(typer_ms);
  74.     draw_bitmap(0,29,boo_w,boo_h,boo);
  75.     wait_ms(typer_ms);
  76.     string_typer(3,4,powa3,3,typer_ms);
  77.     string_typer(3,7,powa4,0,typer_ms);
  78.     wait_ms(4000);
  79.     fill_display(lcd_width,lcd_height,0);
  80.     // ---------------------------------------------------
  81.     // SCENE 04 - "Bitmap-FadeIn-Destruction -------------
  82.     x=0;
  83.     while(x<=29)
  84.     {
  85.         draw_bitmap(0,0,x++,ichi_h,ichi);
  86.         wait_ms(300);
  87.     }
  88.     wait_ms(1000);
  89.     // ---------------------------------------------------
  90.     // SCENE 05 - "Classic-Scrolling" --------------------
  91.     x=lcd_width;
  92.     y=lcd_width;
  93.     y1=sizeof(sine)-1;
  94.     x1=sizeof(sine)-21;
  95.     num=6*sizeof(scroll0);
  96.     while(x!=-num)
  97.     {
  98.         if(!y1) y1=sizeof(sine)-1;
  99.         if(!x1) x1=sizeof(sine)-1;
  100.         f_scroller_normal(x--,0,scroll1);
  101.         if(y!=-num)
  102.         {
  103.             f_scroller_normal(y,56,scroll0);
  104.             y-=2;
  105.         }
  106.         else y=lcd_width;
  107.         draw_bitmap(0,0,ichi_w,ichi_h-8,ichi);
  108.         draw_bitmap(35,sine[y1--]/2+8,boo_w,boo_h,boo);
  109.         draw_bitmap(70,sine[x1--]/2+8,boo_w,boo_h,boo);
  110.         wait_ms(50);
  111.     }
  112.     // ---------------------------------------------------
  113.     // SCENE 06 - "FadeOut Scene 05" ---------------------
  114.     wait_ms(500);
  115.     x=0;
  116.     y=8;
  117.     while(y<=lcd_height)
  118.     {
  119.         if(x>=-ichi_w)
  120.             draw_bitmap(x--,0,ichi_w,ichi_h,ichi);
  121.         draw_bitmap(35,sine[y1]/2+y,boo_w,boo_h,boo);
  122.         draw_bitmap(70,sine[x1]/2+y++,boo_w,boo_h,boo);
  123.         wait_ms(70);
  124.     }
  125.     // ---------------------------------------------------
  126.     // SCENE 07 - "Sine-Scroller" / "END" ----------------
  127.     x=lcd_width;
  128.     num=6*sizeof(scroll3);
  129.     write_string(3,6,end,2);
  130.     while(x!=-num)
  131.     {  
  132.         f_scroller_func(x--,0,scroll3,sine,sizeof(sine)-1);
  133.         write_h_string(0,0,powa3,1);
  134.         write_h_string(15,0,powa3,1);
  135.         wait_ms(70);
  136.         fill_display(lcd_width,32,0);
  137.     }
  138.     // ---------------------------------------------------
  139.     fill_display(lcd_width,lcd_height,0);
  140.     while(1);
  141. }
/*******************************
 *          __                   
 *         /\ \                  
 *  __  _  \_\ \     __    ___   
 * /\ \/'\ /'_' \  /'__'\ /'___\ 
 * \/>  <//\ \ \ \/\  __//\ \__/ 
 *  /\_/\_\ \___,_\ \____\ \____\
 *  \//\/_/\/__,_ /\/____/\/____/
 * 
 *  Author: declis (xdec.de)
 ********************************/ 

#include <msp430g2553.h>
#include "lib_lcd.h"
#include "delay.h"
#include "bitmaps.h"
#include "data.h"

void main(void)
{
	signed int x=0,y=-184,num=0,x1=0,y1=0;

	WDTCTL=WDTPW+WDTHOLD;	
	BCSCTL1=CALBC1_8MHZ;                // SMCLK=~8MHz  
  	DCOCTL=CALDCO_8MHZ;

  	init_USCI();
  	init_LCD();

	// SCENE 00 - "Countdown" ----------------------------
	wait_ms(500);
	countdown('3');
	countdown('2');
	countdown('1');
	wait_ms(500);
	write_string(3,2,gogo,5);
	wait_ms(1000);
	fill_display(lcd_width,lcd_height,0);
	// ---------------------------------------------------
	// SCENE 01 - "Motoko Vertical-Scroller" -------------
	while(y!=16)
	{
  		draw_bitmap(0,y++,ghost_w,ghost_h,ghost);
  		wait_ms(80);
  	}
  	write_string(0,0,moto,1);
  	wait_ms(2000);
  	while(y!=-85)
  	{
  		draw_bitmap(0,y--,ghost_w,ghost_h,ghost);
  		wait_ms(80);
  	}
  	wait_ms(2000);
  	// ---------------------------------------------------
  	// SCENE 02 - "Motoko Horizontal-Overlap-Scroller" ---
  	y=0;
  	while(x!=-lcd_width)
  	{
  		draw_bitmap(x--,-85,ghost_w,ghost_h,ghost);
  		draw_bitmap(y++,-85,ghost_w,ghost_h,ghost);
  	} 
  	while(x<=lcd_width)
  	{
  		draw_bitmap(x++,-85,ghost_w,ghost_h,ghost);
  		draw_bitmap(y--,-85,ghost_w,ghost_h,ghost);
  	}
  	wait_ms(500);
  	// ---------------------------------------------------
  	// SCENE 03 - "String-Typer" -------------------------
  	string_typer(3,0,powa0,0,typer_ms);
  	string_typer(3,1,powa1,1,typer_ms);
  	string_typer(3,3,powa2,0,typer_ms);
  	wait_ms(typer_ms);
  	draw_bitmap(0,29,boo_w,boo_h,boo);
  	wait_ms(typer_ms);
  	string_typer(3,4,powa3,3,typer_ms);
  	string_typer(3,7,powa4,0,typer_ms);
  	wait_ms(4000);
  	fill_display(lcd_width,lcd_height,0);
  	// ---------------------------------------------------
  	// SCENE 04 - "Bitmap-FadeIn-Destruction -------------
  	x=0;
  	while(x<=29)
  	{
  		draw_bitmap(0,0,x++,ichi_h,ichi);
  		wait_ms(300);
  	}
  	wait_ms(1000);
  	// ---------------------------------------------------
  	// SCENE 05 - "Classic-Scrolling" --------------------
  	x=lcd_width;
  	y=lcd_width;
  	y1=sizeof(sine)-1;
  	x1=sizeof(sine)-21;
  	num=6*sizeof(scroll0);
  	while(x!=-num)
  	{
  		if(!y1) y1=sizeof(sine)-1;
		if(!x1) x1=sizeof(sine)-1;
  		f_scroller_normal(x--,0,scroll1);
  		if(y!=-num)
  		{
  			f_scroller_normal(y,56,scroll0);
  			y-=2;
  		}
  		else y=lcd_width;
  		draw_bitmap(0,0,ichi_w,ichi_h-8,ichi);
  		draw_bitmap(35,sine[y1--]/2+8,boo_w,boo_h,boo);
  		draw_bitmap(70,sine[x1--]/2+8,boo_w,boo_h,boo);
  		wait_ms(50);
  	}
  	// ---------------------------------------------------
  	// SCENE 06 - "FadeOut Scene 05" ---------------------
  	wait_ms(500);
  	x=0;
  	y=8;
  	while(y<=lcd_height)
  	{
  		if(x>=-ichi_w)
  			draw_bitmap(x--,0,ichi_w,ichi_h,ichi);
  		draw_bitmap(35,sine[y1]/2+y,boo_w,boo_h,boo);
  		draw_bitmap(70,sine[x1]/2+y++,boo_w,boo_h,boo);
  		wait_ms(70);
  	}
	// ---------------------------------------------------
	// SCENE 07 - "Sine-Scroller" / "END" ----------------
	x=lcd_width;
	num=6*sizeof(scroll3);
	write_string(3,6,end,2);
	while(x!=-num)
	{	
		f_scroller_func(x--,0,scroll3,sine,sizeof(sine)-1);
		write_h_string(0,0,powa3,1);
		write_h_string(15,0,powa3,1);
		wait_ms(70);
		fill_display(lcd_width,32,0);
	}
	// ---------------------------------------------------
	fill_display(lcd_width,lcd_height,0);
    while(1);
}

lib_lcd.c

  1. #include <msp430g2553.h>
  2. #include "ascii_char.h"
  3. #include "lib_lcd.h"
  4. #include "delay.h"
  5.  
  6. #define max_f_size      8   // cache size for "font resize function"
  7.  
  8. unsigned char byte,bit_num;
  9.  
  10. void write_h_string(unsigned char x, unsigned char y, const char *string, unsigned char f_size)
  11. {
  12.     while(*string!=0)
  13.     {
  14.         write_char(x,y,*string++,f_size);
  15.         if(f_size==1) y+=f_size+1;
  16.         else if(f_size>1) y+=f_size;
  17.         else y++;
  18.     }
  19. }
  20.  
  21. void string_typer(unsigned char x, unsigned char y, const char *string, unsigned char f_size, unsigned int ms)
  22. {
  23.     while(*string!=0)
  24.     {
  25.         write_char(x,y,*string++,f_size);
  26.         if(f_size>1) x+=f_size;
  27.         else x++;
  28.         wait_ms(ms);
  29.     }
  30. }
  31.  
  32. void f_scroller_func(signed int x, signed int y, const char *string, const char *func, unsigned char func_size)
  33. {
  34.     byte=0;
  35.     while(*string!=0&&x<lcd_width)
  36.     {
  37.         if(x>func_size) byte=x-func_size; // use abs() here
  38.         else byte=x;
  39.         draw_bitmap(x,y+func[byte],f_width,8,ascii_table[*string++]);
  40.         set_instruction(1,0);   // clear byte before
  41.         x+=f_width+space_char;
  42.         byte++;
  43.     }
  44. }
  45.  
  46. void f_scroller_normal(signed int x, signed int y, const char *string)
  47. {
  48.     while(*string!=0&&x<lcd_width)
  49.     {
  50.         draw_bitmap(x,y,f_width,8,ascii_table[*string++]);
  51.         set_instruction(1,0);   // clear byte before
  52.         x+=f_width+space_char;
  53.     }
  54. }
  55.  
  56. void countdown(unsigned char num)
  57. {
  58.     signed char size=8;
  59.     while(size!=-1)
  60.     {
  61.         write_char(4,0,num,size--);
  62.         wait_ms(111);
  63.         fill_display(96,64,0);
  64.     }
  65. }
  66.  
  67. void draw_bitmap(signed int x, signed int y, unsigned int b_width, unsigned int b_height, const char *bmap)
  68. {
  69.     unsigned int h_index=0,w_index=0,width_max=0,x_off=0,y_off=0;
  70.     byte=0;
  71.  
  72.     if(y+(signed int)b_height<0) return;    // outside display
  73.     if(x+(signed int)b_width<0) return;
  74.     if(y>=lcd_height) return;
  75.     if(x>=lcd_width) return;
  76.  
  77.     if(x<0)
  78.     {
  79.         w_index=x*-1;       // set bmap x-offset
  80.         x_off=w_index;
  81.         x=0;                // start at display position x=0 with x-offset
  82.     }
  83.  
  84.     if(b_height%8) b_height+=8;
  85.     b_height/=8;
  86.  
  87.     if(x+(signed int)b_width>=lcd_width)    // width overflow check
  88.         width_max=lcd_width-x;
  89.     else width_max=b_width;
  90.  
  91.     if(y<0)
  92.     {
  93.         y*=-1;
  94.         y_off=y/8;
  95.         b_height-=y_off;
  96.         while(h_index<b_height)
  97.         {
  98.             set_cursor(x,h_index);
  99.             while(w_index<width_max)
  100.             {
  101.                 byte=bmap[w_index+((h_index+y_off)*b_width)]>>(y%8);
  102.                 if(h_index+1!=b_height)
  103.                     byte|=bmap[w_index+((h_index+y_off+1)*b_width)]<<(8-(y%8));
  104.                 set_instruction(1,byte);
  105.                 w_index++;
  106.                 byte=0;
  107.             }
  108.             h_index++;
  109.             w_index=x_off;
  110.             if(h_index>=lcd_height_b) return;
  111.         }
  112.     }
  113.     else
  114.     {
  115.         y_off=y/8;
  116.         while(h_index<=b_height)
  117.         {
  118.             set_cursor(x,y_off+h_index);
  119.             while(w_index<width_max)
  120.             {
  121.                 if(h_index!=b_height)
  122.                     byte=bmap[w_index+(h_index*b_width)]<<(y%8);                   
  123.                 if(h_index)
  124.                     byte|=(bmap[w_index+((h_index-1)*b_width)]>>(8-(y%8))); // byte before
  125.                 set_instruction(1,byte);
  126.                 w_index++;
  127.                 byte=0;
  128.             }
  129.             h_index++;
  130.             w_index=x_off;     
  131.             if(h_index+y_off>=lcd_height_b) return;
  132.             if(h_index==b_height&&!(y%8)) return;
  133.         }
  134.     }
  135. }
  136.  
  137. void convert_font_size(unsigned char x, unsigned char y, unsigned char character, unsigned char f_size)
  138. {
  139.     unsigned char x_char=0,bit_num_b=0,size=0,px_size=0,y_pos_new=0,x_pos_new=0;
  140.     unsigned char cache[max_f_size],i=0;
  141.     byte=0;
  142.     bit_num=0;
  143.  
  144.     if (f_size==1) size=2;
  145.     else size=f_size;
  146.  
  147.     while(x_char<f_width)                                                   // test byte, starting at 0 to f_width (font width)
  148.     {
  149.         while(bit_num<8)                                                    // test bit 0..7 of current byte
  150.         {
  151.             if(ascii_table[character][x_char]&(1<<bit_num))                 // if bit=1 in byte...
  152.             {
  153.                 while(px_size<size)                                         // duplicate bits (f_size*f_size)
  154.                 {
  155.                     if(bit_num_b>7&&px_size>0)                              // byte overflow, new byte
  156.                     {
  157.                         set_cursor(x+x_pos_new,y+y_pos_new++);              // set cursor to next y-address
  158.                         set_instruction(1,byte);                            // send byte
  159.                         bit_num_b=0;                                        // reset bit counter
  160.                         cache[i++]=byte;                                    // save byte in cache
  161.                         byte=0;                                             // reset byte
  162.                     }
  163.                     byte|=(1<<bit_num_b);                                   // set bit in byte
  164.                     px_size++;                                              // increment pixel duplicate counter
  165.                     bit_num_b++;                                            // calculate new bit position
  166.                 }
  167.                 px_size=0;                                                  // reset pixel duplicate counter
  168.             }
  169.             else bit_num_b+=size;                                           // bit=0, calculate new bit position in byte
  170.  
  171.             if(bit_num_b>7)                                                 // byte overflow, new byte
  172.             {
  173.                 set_cursor(x+x_pos_new,y+y_pos_new++);
  174.                 set_instruction(1,byte);
  175.                 bit_num_b-=8;                                              
  176.                 cache[i++]=byte;
  177.                 byte=0;
  178.             }
  179.             bit_num++;                                                      // test next byte in array
  180.         }
  181.         y_pos_new=0;                                                        // reset y-offset
  182.         x_pos_new++;                                                        // increment x-position                    
  183.         i=0;                                                                // reset cache counter
  184.         if(f_size==1) size=0;                                               // double height font (only for f_size=1)
  185.         else size--;                                                        // first row is ready, only size-1
  186.         while(size--)                                                      
  187.         {
  188.             while(i<f_size)
  189.             {  
  190.                 set_cursor(x+x_pos_new,y+y_pos_new++);
  191.                 set_instruction(1,cache[i++]);
  192.             }
  193.             i=0;
  194.             y_pos_new=0;
  195.             x_pos_new++;
  196.         }  
  197.         x_char++;
  198.         if(f_size==1) size=2;
  199.         else size=f_size;      
  200.         i=0;
  201.         bit_num=0;
  202.     }
  203. }
  204.  
  205. void write_string(unsigned char x, unsigned char y, const char *string, unsigned char f_size)
  206. {
  207.     x*=(f_width+space_char);
  208.     set_cursor(x,y);
  209.     while(*string!=0)
  210.     {
  211.         if(f_size)
  212.         {
  213.             convert_font_size(x,y,*string++,f_size);
  214.             x+=(f_size*f_width+space_char);
  215.         }
  216.         else
  217.         {
  218.             send_data_array(ascii_table[*string++],f_width);
  219.             y=space_char;
  220.             while(y--)
  221.                 set_instruction(1,0);
  222.         }
  223.     }
  224. }
  225.  
  226. void write_char(unsigned char x, unsigned char y, unsigned char character, unsigned char f_size)
  227. {
  228.     x*=(f_width+space_char);
  229.     set_cursor(x,y);
  230.     if(f_size)
  231.         convert_font_size(x,y,character,f_size);
  232.     else
  233.         send_data_array(ascii_table[character],f_width);
  234. }
  235.  
  236. void send_data_array(const char *d_array, unsigned char size)
  237. {  
  238.     while(size--)
  239.         set_instruction(1,*d_array++);
  240. }
  241.  
  242. void set_cursor(unsigned char x, unsigned char y)
  243. {
  244.     set_instruction(0,0x80+x);
  245.     set_instruction(0,0x40+y);
  246. }
  247.  
  248. void fill_display(unsigned char width, unsigned char height, unsigned char byte)
  249. {  
  250.     height/=8;                         
  251.     while(height--)
  252.     {  
  253.         set_cursor(0,height);
  254.         while(width--)
  255.             set_instruction(1,byte);
  256.         width=lcd_width;
  257.     }
  258. }
  259.  
  260. void set_instruction(unsigned char register_sel, unsigned char number)
  261. {
  262.     if(register_sel)
  263.         P1OUT|=DC;
  264.     else P1OUT&=~DC;
  265.  
  266.     P1OUT&=~CS;                 // start condition
  267.     while(IFG2&UCB0TXIFG);      // TX buffer ready?
  268.     UCB0TXBUF=number;           // start transmission
  269. }
  270.  
  271. void init_LCD(void)
  272. {
  273.     wait_ms(100);
  274.     P1OUT|=RES;
  275.  
  276.     set_instruction(0,0x21);            // function set, extended instruction set (h=1)
  277.     set_instruction(0,0xCF);            // set Vop, contrast
  278.     set_instruction(0,0x04);            // temperature control, set coefficient
  279.     set_instruction(0,0x17);            // set bias system
  280.     set_instruction(0,0x20);            // function set, basic instruction set (h=0)
  281.     set_instruction(0,0x0C);            // display control, normal mode
  282.  
  283.     fill_display(lcd_width,lcd_height_real,0);  // display RAM is undefined after reset, clean dat shit
  284. }
  285.  
  286. void init_USCI(void)
  287. {
  288.     P1DIR|=RES+DC+CS;
  289.     P1OUT&=~RES+DC;
  290.     P1OUT&=~CS;
  291.  
  292.     P1SEL|=SDIN+SCLK;
  293.     P1SEL2|=SDIN+SCLK;
  294.  
  295.     UCB0CTL1|=UCSWRST;                  // USCI in reset state
  296.     // SPI Master, 8bit, MSB first, synchronous mode
  297.     UCB0CTL0|=UCMST+UCSYNC+UCCKPH+UCMSB;       
  298.     UCB0CTL1|=UCSSEL_2;                 // USCI CLK-SRC=SMCLK=~8MHz
  299.     UCB0CTL1&=~UCSWRST;                 // USCI released for operation
  300.     IE2|=UCB0TXIE;                      // enable TX interrupt
  301.     IFG2&=~UCB0TXIFG;
  302.     _EINT();                            // enable interrupts
  303. }
  304.  
  305. #pragma INTERRUPT (USCI)
  306. #pragma vector=USCIAB0TX_VECTOR
  307. void USCI(void)
  308. {
  309.     P1OUT|=CS;              // transmission done
  310.     IFG2&=~UCB0TXIFG;       // clear TXIFG
  311. }
#include <msp430g2553.h>
#include "ascii_char.h"
#include "lib_lcd.h"
#include "delay.h"

#define max_f_size		8	// cache size for "font resize function"

unsigned char byte,bit_num;

void write_h_string(unsigned char x, unsigned char y, const char *string, unsigned char f_size)
{
	while(*string!=0)
	{
		write_char(x,y,*string++,f_size);
		if(f_size==1) y+=f_size+1;
		else if(f_size>1) y+=f_size;
		else y++;
	}
}

void string_typer(unsigned char x, unsigned char y, const char *string, unsigned char f_size, unsigned int ms)
{
	while(*string!=0)
	{
		write_char(x,y,*string++,f_size);
		if(f_size>1) x+=f_size;
		else x++;
		wait_ms(ms);
	}
}

void f_scroller_func(signed int x, signed int y, const char *string, const char *func, unsigned char func_size)
{
	byte=0;
	while(*string!=0&&x<lcd_width)
	{
		if(x>func_size) byte=x-func_size; // use abs() here
		else byte=x;
		draw_bitmap(x,y+func[byte],f_width,8,ascii_table[*string++]);
		set_instruction(1,0);	// clear byte before
		x+=f_width+space_char;
		byte++;
	}
}

void f_scroller_normal(signed int x, signed int y, const char *string)
{
	while(*string!=0&&x<lcd_width)
	{
		draw_bitmap(x,y,f_width,8,ascii_table[*string++]);
		set_instruction(1,0);	// clear byte before
		x+=f_width+space_char;
	}
}

void countdown(unsigned char num)
{
	signed char size=8;
	while(size!=-1)
  	{
  		write_char(4,0,num,size--);
  		wait_ms(111);
  		fill_display(96,64,0);
  	}
}

void draw_bitmap(signed int x, signed int y, unsigned int b_width, unsigned int b_height, const char *bmap)
{
	unsigned int h_index=0,w_index=0,width_max=0,x_off=0,y_off=0;
	byte=0;

	if(y+(signed int)b_height<0) return;	// outside display
	if(x+(signed int)b_width<0) return;
	if(y>=lcd_height) return;
	if(x>=lcd_width) return;

	if(x<0)
	{
		w_index=x*-1;		// set bmap x-offset
		x_off=w_index;
		x=0;				// start at display position x=0 with x-offset
	}

	if(b_height%8) b_height+=8;
	b_height/=8;

	if(x+(signed int)b_width>=lcd_width) 	// width overflow check
		width_max=lcd_width-x;
	else width_max=b_width;

	if(y<0)
	{
		y*=-1;
		y_off=y/8;
		b_height-=y_off;
		while(h_index<b_height)
		{
			set_cursor(x,h_index);
			while(w_index<width_max)
			{
				byte=bmap[w_index+((h_index+y_off)*b_width)]>>(y%8);
				if(h_index+1!=b_height)
					byte|=bmap[w_index+((h_index+y_off+1)*b_width)]<<(8-(y%8));
				set_instruction(1,byte);
				w_index++;
				byte=0;
			}
			h_index++;
			w_index=x_off;
			if(h_index>=lcd_height_b) return;
		}
	}
	else
	{
		y_off=y/8;
		while(h_index<=b_height)
		{
			set_cursor(x,y_off+h_index);
			while(w_index<width_max)
			{
				if(h_index!=b_height)
					byte=bmap[w_index+(h_index*b_width)]<<(y%8);					
				if(h_index) 
					byte|=(bmap[w_index+((h_index-1)*b_width)]>>(8-(y%8)));	// byte before
				set_instruction(1,byte);
				w_index++;
				byte=0;
			}
			h_index++;
			w_index=x_off;		
			if(h_index+y_off>=lcd_height_b) return;
			if(h_index==b_height&&!(y%8)) return;
		}
	}
}

void convert_font_size(unsigned char x, unsigned char y, unsigned char character, unsigned char f_size)
{
	unsigned char x_char=0,bit_num_b=0,size=0,px_size=0,y_pos_new=0,x_pos_new=0;
	unsigned char cache[max_f_size],i=0;
	byte=0;
	bit_num=0;

	if (f_size==1) size=2;
	else size=f_size;

	while(x_char<f_width)													// test byte, starting at 0 to f_width (font width)
	{
		while(bit_num<8)													// test bit 0..7 of current byte
		{
			if(ascii_table[character][x_char]&(1<<bit_num))					// if bit=1 in byte...
			{
				while(px_size<size)											// duplicate bits (f_size*f_size)
				{
					if(bit_num_b>7&&px_size>0)								// byte overflow, new byte
					{
						set_cursor(x+x_pos_new,y+y_pos_new++);				// set cursor to next y-address
						set_instruction(1,byte);							// send byte
						bit_num_b=0;										// reset bit counter
						cache[i++]=byte;									// save byte in cache
						byte=0;												// reset byte
					}
					byte|=(1<<bit_num_b);									// set bit in byte
					px_size++;												// increment pixel duplicate counter
					bit_num_b++;											// calculate new bit position
				}
				px_size=0;													// reset pixel duplicate counter
			}
			else bit_num_b+=size;											// bit=0, calculate new bit position in byte

			if(bit_num_b>7)													// byte overflow, new byte
			{
				set_cursor(x+x_pos_new,y+y_pos_new++);
				set_instruction(1,byte);
				bit_num_b-=8;												
				cache[i++]=byte;
				byte=0;
			}
			bit_num++;														// test next byte in array
		}
		y_pos_new=0;														// reset y-offset
		x_pos_new++;														// increment x-position						
		i=0;																// reset cache counter
		if(f_size==1) size=0;												// double height font (only for f_size=1)
		else size--;														// first row is ready, only size-1
		while(size--)														
		{
			while(i<f_size) 
			{	
				set_cursor(x+x_pos_new,y+y_pos_new++);
				set_instruction(1,cache[i++]);
			}
			i=0;
			y_pos_new=0;
			x_pos_new++;
		}	
		x_char++;
		if(f_size==1) size=2;
		else size=f_size;		
		i=0;
		bit_num=0;
	}
}

void write_string(unsigned char x, unsigned char y, const char *string, unsigned char f_size)
{
	x*=(f_width+space_char);
	set_cursor(x,y);
	while(*string!=0)
	{
		if(f_size)
		{
			convert_font_size(x,y,*string++,f_size);
			x+=(f_size*f_width+space_char);
		}
		else
		{
			send_data_array(ascii_table[*string++],f_width);
			y=space_char;
			while(y--)
				set_instruction(1,0);
		}
	}
}

void write_char(unsigned char x, unsigned char y, unsigned char character, unsigned char f_size)
{
	x*=(f_width+space_char);
	set_cursor(x,y);
	if(f_size)
		convert_font_size(x,y,character,f_size);
	else 
		send_data_array(ascii_table[character],f_width);
}

void send_data_array(const char *d_array, unsigned char size)
{	
	while(size--)
		set_instruction(1,*d_array++);
}

void set_cursor(unsigned char x, unsigned char y)
{
	set_instruction(0,0x80+x);
	set_instruction(0,0x40+y);
}

void fill_display(unsigned char width, unsigned char height, unsigned char byte)
{	
	height/=8;							
	while(height--)
	{	
		set_cursor(0,height);
		while(width--)
			set_instruction(1,byte);
		width=lcd_width;
	}
}

void set_instruction(unsigned char register_sel, unsigned char number)
{
	if(register_sel) 
		P1OUT|=DC;
	else P1OUT&=~DC;

	P1OUT&=~CS;					// start condition
	while(IFG2&UCB0TXIFG);		// TX buffer ready?
  	UCB0TXBUF=number;			// start transmission
}

void init_LCD(void)
{
	wait_ms(100);
	P1OUT|=RES;

	set_instruction(0,0x21);			// function set, extended instruction set (h=1)
	set_instruction(0,0xCF);			// set Vop, contrast
	set_instruction(0,0x04);			// temperature control, set coefficient
	set_instruction(0,0x17);			// set bias system
	set_instruction(0,0x20);			// function set, basic instruction set (h=0)
	set_instruction(0,0x0C);			// display control, normal mode	

	fill_display(lcd_width,lcd_height_real,0);	// display RAM is undefined after reset, clean dat shit
}

void init_USCI(void)
{
	P1DIR|=RES+DC+CS;
	P1OUT&=~RES+DC;
	P1OUT&=~CS;

	P1SEL|=SDIN+SCLK;
	P1SEL2|=SDIN+SCLK;

  	UCB0CTL1|=UCSWRST;					// USCI in reset state
  	// SPI Master, 8bit, MSB first, synchronous mode
  	UCB0CTL0|=UCMST+UCSYNC+UCCKPH+UCMSB;		
  	UCB0CTL1|=UCSSEL_2;					// USCI CLK-SRC=SMCLK=~8MHz
  	UCB0CTL1&=~UCSWRST;					// USCI released for operation
  	IE2|=UCB0TXIE;						// enable TX interrupt
  	IFG2&=~UCB0TXIFG;
  	_EINT();							// enable interrupts
}

#pragma INTERRUPT (USCI)
#pragma vector=USCIAB0TX_VECTOR
void USCI(void)
{
	P1OUT|=CS;				// transmission done
	IFG2&=~UCB0TXIFG;		// clear TXIFG
}

 

One thought on “MSP430 Nokia 3310 LCD (PCD8544)

  1. Recep

    Good work dude. It works fine for nokia 2100 lcd(96×64) with little modification. Thanks..

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

Time limit is exhausted. Please reload CAPTCHA.