This is a sample program to drive a 128x128 LCD with t6963 controller through SPI by means of an MCP23S17 16-Bit I/O Expander with Serial Interface
Diff: main.cpp
- Revision:
- 3:fc101c00b5be
- Parent:
- 2:9071445a6895
- Child:
- 4:fd7c6559a56d
--- a/main.cpp Mon Dec 06 20:45:00 2010 +0000 +++ b/main.cpp Tue Jun 28 17:02:24 2011 +0000 @@ -1,218 +1,409 @@ -#include "mbed.h" -#include "mcp_lcd.h" - -// for 21 characters on a row (6x8 font) -// #define LCDFONTSEL 0xFF -// for 16 characters on a row (8x8 font) -#define LCDFONTSEL 0xDF - -// lcd dimensions in pixels -#define LCD_XWIDTH 128 -#define LCD_YHEIGHT 128 - -#if LCDFONTSEL == 0xFF -// lcd dimensions in characters -#define LCD_WIDTH 22 -#define LCD_HEIGHT 16 -#else -#define LCD_WIDTH 16 -#define LCD_HEIGHT 16 -#endif - -#define TEXT_STARTADDRESS 0x0000 -#define GRAPHIC_STARTADDRESS 0x1000 - -DigitalOut myled(LED1); -SPI spi(p5, p6, p7); // mosi, miso, sclk -DigitalOut cs(p20); - -Serial pc(USBTX, USBRX); // tx, rx - - -// write 8 bits lcd data -void lcd_data(unsigned char d) -{ - cs=0; - spi.write(0x40); - spi.write(GPIOB); // select GPIOB - spi.write(d); // set data byte - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL-LCD_CE-LCD_CD); - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL - LCD_WR - LCD_CE - LCD_CD); - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL - LCD_CD); - cs=1; - -} - -// write 8 bits lcd command -void lcd_command(unsigned char c) -{ - cs=0; - spi.write(0x40); - spi.write(GPIOB); // select GPIOB - spi.write(c); // set data byte - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL-LCD_CE); - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL - LCD_WR - LCD_CE); - cs=1; - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA - spi.write(LCDFONTSEL); - cs=1; -} - -void lcd_init() -{ - cs=0; - spi.write(0x40); - spi.write(IODIRA); // select IODIRA at start - spi.write(0x00); // IODIRA all outputs - spi.write(0x00); // IODIRB all outputs - cs=1; - wait(0.1); - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA at start - spi.write(LCDFONTSEL-LCD_RST); // activate reset - spi.write(0x00); // all B outputs 0 - cs=1; - wait(0.1); - - cs=0; - spi.write(0x40); - spi.write(GPIOA); // select GPIOA at start - spi.write(LCDFONTSEL); // deactivate reset - cs=1; - wait(0.1); - - // set text home address at 0x0000 - lcd_data(TEXT_STARTADDRESS%0x100); - lcd_data(TEXT_STARTADDRESS/0x100); - lcd_command(TXHOME); - - // set graphic home address at 0x1000 - lcd_data(GRAPHIC_STARTADDRESS%0x100); - lcd_data(GRAPHIC_STARTADDRESS/0x100); - lcd_command(GRHOME); - - // set text area - lcd_data(LCD_WIDTH); - lcd_data(0x00); - lcd_command(TXAREA); - - // set graphic area - lcd_data(LCD_WIDTH); - lcd_data(0x00); - lcd_command(GRAREA); - - // mode set (internal character generation mode) - lcd_command(0x80); - - // set offset register - lcd_data(0x02); - lcd_data(0x00); - lcd_command(OFFSET); - - // display mode (text on graphics on cursor off) - lcd_command(0x90+0x08+0x04); - -} - -// put a text string at position x,y (character row,column) -void lcd_string(char x,char y,char *s) -{ - int adr; - adr=TEXT_STARTADDRESS+x+y*LCD_WIDTH; - lcd_data(adr%0x100); - lcd_data(adr/0x100); - lcd_command(ADPSET); - lcd_command(AWRON); - - while (s[0]) - { - // convert from ascii to t6963 - lcd_data(s[0]-32); - s++; - } - lcd_command(AWROFF); -} - -// clear lcd display memory (8k) -void lcd_cls() -{ - int a; - lcd_data(0x00); - lcd_data(0x00); - lcd_command(ADPSET); - lcd_command(AWRON); - for (a=0; a<8192; a++) lcd_data(0); - lcd_command(AWROFF); -} - -// set or reset a pixel on the display on position x,y with color 0 or 1 -void lcd_plot(char x,char y,char color) -{ - int adr; - adr = GRAPHIC_STARTADDRESS + ((LCD_WIDTH) * y) + (x/8); // calculate offset - lcd_data(adr%0x100); // set low byte - lcd_data(adr/0x100); // set high byte - lcd_command(ADPSET); // set address pointer - if (color) lcd_command(BS + (7-(x%8))); // use bit set mode - else lcd_command(BR + (7-(x%8))); // use bit reset mode -} - -int main() { - - int a; - pc.printf("SPI test\n"); - - // set SPI to full speed (10 MHz mode) - spi.format(8,0); - spi.frequency(10000000); -// spi.frequency(10000); - wait(0.1); - - pc.printf("MCP init\n"); - lcd_init(); - lcd_cls(); - - // write some text - lcd_string(0,0,"Hello World!"); - lcd_string(0,2,"0123456789"); - lcd_string(0,15,"abcdefghijklmnopqrstuvwxyz"); - - for (a=0; a<128; a++) lcd_plot(a,a/2+48,1); - - while(1) { - myled = 1; - wait(0.2); - myled = 0; - wait(0.2); - } -} +#include "mbed.h" +#include "mcp_lcd.h" + +// for 21 characters on a row (6x8 font) +#define LCDFONTSEL 0xFF +// for 16 characters on a row (8x8 font) +// #define LCDFONTSEL 0xDF + +// lcd dimensions in pixels +#define LCD_XWIDTH 128 +#define LCD_YHEIGHT 128 + +#if LCDFONTSEL == 0xFF +// lcd dimensions in characters +#define LCD_WIDTH 22 +#define LCD_HEIGHT 16 +#define PIXELWIDTH 6 +#else +#define LCD_WIDTH 16 +#define LCD_HEIGHT 16 +#define PIXELWIDTH 8 +#endif + +#define TEXT_STARTADDRESS 0x0000 +#define GRAPHIC_STARTADDRESS 0x1000 + + +#define CENTERX 64 +#define CENTERY 64 +#define INNER_RADIUS 45 +#define OUTER_RADIUS 50 +#define CENTER_CIRCLE 5 + +DigitalOut myled(LED1); +SPI spi(p5, p6, p7); // mosi, miso, sclk +DigitalOut cs(p20); + +Serial pc(USBTX, USBRX); // tx, rx + + +// write 8 bits lcd data +void lcd_data(unsigned char d) +{ + cs=0; + spi.write(0x40); + spi.write(GPIOB); // select GPIOB + spi.write(d); // set data byte + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL-LCD_CE-LCD_CD); + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL - LCD_WR - LCD_CE - LCD_CD); + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL - LCD_CD); + cs=1; + +} + +// write 8 bits lcd command +void lcd_command(unsigned char c) +{ + cs=0; + spi.write(0x40); + spi.write(GPIOB); // select GPIOB + spi.write(c); // set data byte + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL-LCD_CE); + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL - LCD_WR - LCD_CE); + cs=1; + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA + spi.write(LCDFONTSEL); + cs=1; +} + +void lcd_init() +{ + cs=0; + spi.write(0x40); + spi.write(IODIRA); // select IODIRA at start + spi.write(0x00); // IODIRA all outputs + spi.write(0x00); // IODIRB all outputs + cs=1; + wait(0.1); + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA at start + spi.write(LCDFONTSEL-LCD_RST); // activate reset + spi.write(0x00); // all B outputs 0 + cs=1; + wait(0.1); + + cs=0; + spi.write(0x40); + spi.write(GPIOA); // select GPIOA at start + spi.write(LCDFONTSEL); // deactivate reset + cs=1; + wait(0.1); + + // set text home address at 0x0000 + lcd_data(TEXT_STARTADDRESS%0x100); + lcd_data(TEXT_STARTADDRESS/0x100); + lcd_command(TXHOME); + + // set graphic home address at 0x1000 + lcd_data(GRAPHIC_STARTADDRESS%0x100); + lcd_data(GRAPHIC_STARTADDRESS/0x100); + lcd_command(GRHOME); + + // set text area + lcd_data(LCD_WIDTH); + lcd_data(0x00); + lcd_command(TXAREA); + + // set graphic area + lcd_data(LCD_WIDTH); + lcd_data(0x00); + lcd_command(GRAREA); + + // mode set (internal character generation mode) + lcd_command(0x80); + + // set offset register + lcd_data(0x02); + lcd_data(0x00); + lcd_command(OFFSET); + + // display mode (text on graphics on cursor off) + lcd_command(0x90+0x08+0x04); + +} + +// put a text string at position x,y (character row,column) +void lcd_string(char x,char y,char *s) +{ + int adr; + adr=TEXT_STARTADDRESS+x+y*LCD_WIDTH; + lcd_data(adr%0x100); + lcd_data(adr/0x100); + lcd_command(ADPSET); + lcd_command(AWRON); + + while (s[0]) + { + // convert from ascii to t6963 + lcd_data(s[0]-32); + s++; + } + lcd_command(AWROFF); +} + +// clear lcd display memory (8k) +void lcd_cls() +{ + int a; + lcd_data(0x00); + lcd_data(0x00); + lcd_command(ADPSET); + lcd_command(AWRON); + for (a=0; a<8192; a++) lcd_data(0); + lcd_command(AWROFF); +} + +// set or reset a pixel on the display on position x,y with color 0 or 1 +void lcd_plot(char x,char y,char color) +{ + int adr; + adr = GRAPHIC_STARTADDRESS + ((LCD_WIDTH) * y) + (x/PIXELWIDTH); // calculate offset + lcd_data(adr%0x100); // set low byte + lcd_data(adr/0x100); // set high byte + lcd_command(ADPSET); // set address pointer + if (color) lcd_command(BS + ((PIXELWIDTH-1)-(x%PIXELWIDTH))); // use bit set mode + else lcd_command(BR + ((PIXELWIDTH-1)-(x%PIXELWIDTH))); // use bit reset mode +} + +// Bresenham line routine +void lcd_line(int x0, int y0, int x1, int y1,char color) +{ + char steep=1; + int i,dx,dy,e; + signed char sx,sy; + + dx = abs(x1-x0); + sx = ((x1 - x0) >0) ? 1 : -1; + dy=abs(y1-y0); + sy = ((y1 - y0) >0) ? 1 : -1; + + if (dy > dx) + { + steep=0; + // swap X0 and Y0 + x0=x0 ^ y0; + y0=x0 ^ y0; + x0=x0 ^ y0; + + // swap DX and DY + dx=dx ^ dy; + dy=dx ^ dy; + dx=dx ^ dy; + + // swap SX and SY + sx=sx ^ sy; + sy=sx ^ sy; + sx=sx ^ sy; + } + + e = (dy << 1) - dx; + + for (i=0; i<=dx; i++) + { + if (steep) + { + lcd_plot(x0,y0,color); + } + else + { + lcd_plot(y0,x0,color); + } + while (e >= 0) + { + y0 += sy; + e -= (dx << 1); + } + x0 += sx; + e += (dy << 1); + } + } + +// Bresenham circle routine +void lcd_circle(int x0,int y0, int radius, char color) +{ + + int f = 1 - radius; + int dx = 1; + int dy = -2 * radius; + int x = 0; + int y = radius; + + lcd_plot(x0, y0 + radius,color); + lcd_plot(x0, y0 - radius,color); + lcd_plot(x0 + radius, y0,color); + lcd_plot(x0 - radius, y0,color); + + while(x < y) + { + if(f >= 0) + { + y--; + dy += 2; + f += dy; + } + x++; + dx += 2; + f += dx; + lcd_plot(x0 + x, y0 + y,color); + lcd_plot(x0 - x, y0 + y,color); + lcd_plot(x0 + x, y0 - y,color); + lcd_plot(x0 - x, y0 - y,color); + lcd_plot(x0 + y, y0 + x,color); + lcd_plot(x0 - y, y0 + x,color); + lcd_plot(x0 + y, y0 - x,color); + lcd_plot(x0 - y, y0 - x,color); + } +} + +int main() { + + + float a,b,f; + float pi=3.14159265; + float h_pi=pi/6; + float m_pi=pi/30; + + char buf[40]; + time_t seconds; + int sec,min,hour; + int s_sx,s_sy,s_ex,s_ey; + int m_sx,m_sy,m_ex,m_ey; + int h_sx,h_sy,h_ex,h_ey; + + // setup time structure + struct tm t; + t.tm_sec = 00; // 0-59 + t.tm_min = 30; // 0-59 + t.tm_hour = 21; // 0-23 + t.tm_mday = 14; // 1-31 + t.tm_mon = 11; // 0-11 + t.tm_year = 110; // year since 1900 + seconds = mktime(&t); + // set_time(seconds); + + + pc.printf("SPI test\n"); + + // set SPI to full speed (10 MHz mode) + spi.format(8,0); + spi.frequency(10000000); +// spi.frequency(10000); + wait(0.1); + + pc.printf("MCP init\n"); + lcd_init(); + lcd_cls(); + + // write some text 345678901234567890 + lcd_string(0,0,"* Hello mbed World! *"); + // lcd_string(0,15,"abcdefghijklmnopqrstuvwxyz"); + + + // draw outer circle of analog clock + lcd_circle(CENTERX,CENTERY,OUTER_RADIUS+1,1); + + // draw hour markings + for (min=0; min<59; min+=5) + { + b=min*m_pi; + m_sx=sin(b)*INNER_RADIUS+CENTERX; + m_sy=-cos(b)*INNER_RADIUS+CENTERY; + m_ex=sin(b)*OUTER_RADIUS+CENTERX; + m_ey=-cos(b)*OUTER_RADIUS+CENTERY; + lcd_line(m_sx,m_sy,m_ex,m_ey,1); + } + + + for(;;) + { + seconds = time(NULL); + + // 13:24:00 dd/mm/yyyy + strftime(buf,40, "%H:%M:%S %d/%m/%Y", localtime(&seconds)); + lcd_string(0,15,buf); + + strftime(buf,40, "%I %M %S", localtime(&seconds)); + sscanf(buf,"%d %d %d",&hour,&min,&sec); + + b=sec*m_pi; + s_sx=CENTERX; + s_sy=CENTERY; + s_ex=sin(b)*(INNER_RADIUS-3)+CENTERX; + s_ey=-cos(b)*(INNER_RADIUS-3)+CENTERY; + + + b=min*m_pi; + m_sx=sin(b)*(CENTER_CIRCLE)+CENTERX; + m_sy=-cos(b)*(CENTER_CIRCLE)+CENTERY; + m_ex=sin(b)*(INNER_RADIUS-10)+CENTERX; + m_ey=-cos(b)*(INNER_RADIUS-10)+CENTERY; + + // advancing hour hand + if (hour<12) + { + // draw hour hand with an offset + // calculated by dividing minutes by 12 + b=(hour*5+min/12)*m_pi; + } + else + { + // hour would be 0 offset at 12 o'clock + // so we can leave it out of the equation... + b=(min/12)*m_pi; + } + h_sx=sin(b)*(CENTER_CIRCLE)+CENTERX; + h_sy=-cos(b)*(CENTER_CIRCLE)+CENTERY; + h_ex=sin(b)*(INNER_RADIUS-20)+CENTERX; + h_ey=-cos(b)*(INNER_RADIUS-20)+CENTERY; + + // draw 'new' hands + lcd_line(s_sx,s_sy,s_ex,s_ey,1); + lcd_line(m_sx,m_sy,m_ex,m_ey,1); + lcd_line(h_sx,h_sy,h_ex,h_ey,1); + + lcd_circle(CENTERX,CENTERY,CENTER_CIRCLE,1); + lcd_circle(CENTERX,CENTERY,1,1); + + myled = !myled; + + // now wait until the seconds change + while (seconds==time(NULL)) wait(0.1); + + // erase 'old' hands + lcd_line(s_sx,s_sy,s_ex,s_ey,0); + lcd_line(m_sx,m_sy,m_ex,m_ey,0); + lcd_line(h_sx,h_sy,h_ex,h_ey,0); + + } +}