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
main.cpp
- Committer:
- gertk
- Date:
- 2011-10-17
- Revision:
- 4:fd7c6559a56d
- Parent:
- 3:fc101c00b5be
File content as of revision 4:fd7c6559a56d:
// Demo program displaying an analog clock // on a T6963 based LCD connected to the mbed through // SPI with a MCP23S17 thereby using only 4 pins I/O // by Gert van der Knokke 2010 #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); } }