190 likes | 204 Views
Explore LCD panel geometry, drawing characters, utilizing utilities, managing interrupt handlers, and updating scores in this comprehensive demo.
E N D
Arch1 LCD Lab Eric Freudenthal
Topics • Score Demo • LCD • Panel Geometry • Utilities to draw to the display • Drawing characters • Buttons • Nuisance: multiple versions • Interrupt handlers • Timer interrupt handler • To update score • Ball Demo • Drawing Ball • Motion • Paddle Demo • Buttons • Drawing paddle
Minor(row % 8) Panel geometry Major(row / 8) Row # • Panel dimensions (lcd_backend.h) • Rows: • Top: 0 • Bottom: 68 (MAX_X) • Broken into 8 row “chunks” • major = row/8, minor=row%8 • Columns • Left: 0 • Right: 96 (MAX_X) 0 0 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 Bit 0 1 0 1 2 0 2 3 0 3 4 0 4 5 0 5 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 Bit 7 6 0 6 7 0 7 8 1 0 9 1 1 0 0x00 0x20 1 0x10 2 0x08 3 4 0x04 0x02 5 6 0x00 8 0x00 10 1 2 11 1 3 12 1 4 13 1 5 14 1 6 15 1 7
lcd_char.c const char font5x7[][5] = { // basic 5x7 font indexed as [char][chunk#] {0x00, 0x00, 0x00, 0x00, 0x00} // 20 (space) ,{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
lcd_utils.h #ifndeflcd_utils_included #define lcd_utils_included #include "booster1202.h" #include "lcd_backend.h" /* compute major & minor row numbers */ u_charlcd_getYMajor(u_char y); u_charlcd_getYMinor(u_char y); /* displays a chunk (byte of binary pixels) at the given address */ void lcd_setAddr(u_char x, u_charyMajor); /* set addr of next write */ void lcd_writeChunk(char chunk); /* write chunk and increment x */ /* set addr & write */ void lcd_writeChunkAddr(char chunk, u_charxPos, u_charyMajor); /* converts ints to character sequences */ char* itoa(int value, char* result, int base); #endif // lcd_utils_included
lcd_char.c void _lcd_writeChar(char c); /* forward declaration */ void lcd_writeString(const char *string, u_char x, u_charyMajor) { lcd_setAddr(x,yMajor); while (*string) { _lcd_writeChar(*string++); lcd_writeChunk(0); /* whitespace after char */ } } // helper: writes 1 char at current column, advances column void _lcd_writeChar(char c) { char i; for (i = 0; i < 5; i++) { lcd_writeChunk(font5x7[c - 0x20][i]); } } void lcd_writeChar(char c, u_char x, u_charyMajor) { lcd_setAddr(x,yMajor); _lcd_writeChar(c); }
paddle_buttons.h /* P2 bits for paddle buttons */ # define LeftSw BIT2 # define DownSw BIT3 # define UpSw BIT4 #if LCD1202_VERSION == 3 # define RightSw BIT1 #elif LCD1202_VERSION == 1 || LCD1202_VERSION == 2 || LCD1202_VERSION == 4 # define RightSw BIT5 #else # error +++++ # error +++++ LCD1202_VERSION not (properly) defined. See note in Makefile. # error +++++ #endif
score_demomain() void main(void) { WDTCTL = WDTPW + WDTHOLD; // Stop watchdog timer lcdinit(); // init LCD (also: CPU clock to 16MHz) CCTL0 = CCIE; // CCR0 interrupt enabled TACTL = TASSEL_2 + MC_1 + ID_3; // Set timer clock to CPU clock/8 CCR0 = 50000; // Interrupt every 10 ms initializeSwitchInterrupts(); resetPaddle(); or_sr(0x18); // CPU off, GIE on }
score_demo.cscores & timer interrupt Timer_0: push r15 push r14 push r13 push r12 mov &clockDivide, r15 mov r15, r14 add #1, r14 mov r14, &clockDivide cmp #21, r15 jl .L9 call #updateScore mov #0, &clockDivide .L9: pop r12 pop r13 pop r14 pop r15 reti void updateScore(void) { char numString[] = " "; score++; lcd_writeString(" ",72,0); itoa(score, numString, 10); lcd_writeString(numString,72,0); } void resetScore(void) { score = 0; } /* timer interrupt */ interrupt(TIMER0_A0_VECTOR) Timer_0(void) { static intclockDivide = 0; if (clockDivide++ > 20) { updateScore(); clockDivide = 0; } }
paddle_buttons.h /* P2 bits for paddle buttons */ # define LeftSw BIT2 # define DownSw BIT3 # define UpSw BIT4 #if LCD1202_VERSION == 3 # define RightSw BIT1 #elif LCD1202_VERSION == 1 || LCD1202_VERSION == 2 || LCD1202_VERSION == 4 # define RightSw BIT5 #else # error +++++ # error +++++ LCD120_VERSION not (properly) defined. See note in Makefile. # error +++++ #endif
score_demo.csetupswitchinterrupts unsigned char oldP1SwVal, oldP2SwVal; #define P1SwMask SW1 //P1.3 #define P2SwMask (UpSw + DownSw + LeftSw + RightSw) void initializeSwitchInterrupts() /* setup interrupts on switch */ { P1REN |= P1SwMask; /* resistors for switches */ P2REN |= P2SwMask; P1OUT |= P1SwMask; /* pull-ups for switches */ P2OUT |= P2SwMask; oldP1SwVal = P1IN & P1SwMask; /* remember current switch vales */ oldP2SwVal = P2IN & P2SwMask; P1IES = oldP1SwVal; /* interrupt when switch bits change */ P2IES = oldP2SwVal; P1IE = P1SwMask; /* enable interrupts from switches */ P2IE = P2SwMask; }
Output from gcc –S –O1 __isr_2: push r15 push r14 push r13 push r12 push r11 mov.b &__P1IN, r11 and.b #8, r11 mov.b r11, &__P1IES mov.b #0, &__P1IFG jne .L6 mov.b &oldP1SwVal, r15 and #8, r15 jeq .L6 call #resetScore .L6: mov.b r11, &oldP1SwVal pop r11 pop r12 pop r13 pop r14 pop r15 reti . score_demo.cSW1 interrupt handlers /* Switches on P1 (far right switch) */ interrupt(PORT1_VECTOR) Port_1(void) { unsigned char p1Val = P1IN & P1SwMask; /* read switches from p1 */ P1IES= p1Val; /* interrupt on value change */ P1IFG = 0; /* clear pending P1 interrupts */ if (!(p1Val & SW1) && (oldP1SwVal & SW1)) /* unpressed to pressed? */ resetScore(); /* re-initialize score */ oldP1SwVal = p1Val; }
Topics • Score Demo • LCD • Panel Geometry • Utilities to draw to the display • Drawing characters • Buttons • Nuisance: multiple versions • Interrupt handlers • Timer interrupt handler • To update score • Ball Demo • Drawing Ball • Motion • Paddle Demo • Buttons • Drawing paddle
Ball_demo.cdrawing 2x2 ball void drawBall(u_char x, u_char y) { u_charmajorYTop = lcd_getYMajor(y); u_charmajorYBot = lcd_getYMajor(y+1); u_charminorYTop = lcd_getYMinor(y); u_charminorYBot = lcd_getYMinor(y+1); clearBall(last_ball_x, last_ball_y); if (majorYTop == majorYBot) { // set the appropriate bits within the upper byte u_char chunk = (3 << minorYTop); lcd_writeChunkAddr(chunk, x, majorYTop); lcd_writeChunk(chunk); } else { // set the appropriate bit for the upper byte u_char chunk = (1 << minorYTop); lcd_writeChunkAddr(chunk, x, majorYTop); lcd_writeChunk(chunk); // set the appropriate bit for the lower byte chunk = (1 << minorYBot); lcd_writeChunkAddr(chunk, x, majorYBot); lcd_writeChunk(chunk); } last_ball_x = x; last_ball_y = y; } static void clearBall(u_char x, u_char y) { u_charyMajor = lcd_getYMajor(y); lcd_writeChunkAddr(0, x, yMajor); lcd_writeChunk(0); // x+1 lcd_writeChunkAddr(0, x, yMajor + 1); lcd_writeChunk(0); // x+1 }
Ball_demo.ctimer & buttoninterrupt handlers /* timer interrupt */ interrupt(TIMER0_A0_VECTOR) Timer_0(void) { static intclockDivide = 0; if (clockDivide++ > 20) { updateBall(); clockDivide = 0; } } interrupt(PORT1_VECTOR) Port_1(void) { unsigned char p1Val = P1IN & P1SwMask; /* read switches from p1 */ P1IES= p1Val; /* interrupt on value change */ P1IFG = 0; /* clear pending P1 interrupts */ if (!(p1Val & SW1) && (oldP1SwVal & SW1)) /* transition from unpressed to pressed? */ resetBall(); /* re-initialize paddle */ oldP1SwVal = p1Val; }
Ball_demo.cball motion updateBall() { /* reverse ball direction at court boundaries */ if ((ballXPos == 0) || (ballXPos == MAX_X -2)) ballXVel = -ballXVel; if ((ballYPos == 0) || (ballYPos == MAX_Y -2)) ballYVel = -ballYVel; /* move ball */ ballXPos += ballXVel; ballYPos += ballYVel; /* draw ball */ drawBall(ballXPos, ballYPos); }
Topics • Score Demo • LCD • Panel Geometry • Utilities to draw to the display • Drawing characters • Buttons • Nuisance: multiple versions • Interrupt handlers • Timer interrupt handler • To update score • Ball Demo • Drawing Ball • Motion • Paddle Demo • Drawing paddle • Buttons • Motion
draw_paddle.c void drawPaddle(u_charyPos) /* ypos is middle of paddle */ { char paddleTopYMajor = lcd_getYMajor(yPos-paddleSize); char paddleBotYMajor = lcd_getYMajor(yPos+paddleSize); u_charyMajor; /* yMajor row index */ u_charyMajorLimit = max(paddleBotYMajor, oldPaddleBotYMajor); for (yMajor = min(paddleTopYMajor, oldPaddleTopYMajor); yMajor <= yMajorLimit;yMajor++) { // yMajor in paddle lcd_setAddr(0, yMajor); if (yMajor < paddleTopYMajor || yMajor > paddleBotYMajor) lcd_writeChunk(0); /* erase if above or below paddle */ else { u_char chunk = 0xffu; /* default: all pixels on */ if (yMajor == paddleTopYMajor) { /* top chunk, clear top pixels */ chunk &= ~chunkMasks[lcd_getYMinor(yPos-paddleSize)]; } if (yMajor == paddleBotYMajor) { /* bot chunk, clear bottom pixels */ chunk &= chunkMasks[1+lcd_getYMinor(yPos+paddleSize)]; } lcd_writeChunk(chunk); } } oldPaddleBotYMajor = paddleBotYMajor; /* remember state */ oldPaddleTopYMajor = paddleTopYMajor; } static constu_charchunkMasks[] = {0x00, 0x01, 0x03, 0x07, 0xf, 0x1f, 0x3f, 0x7f, 0xff};
paddle_demobuttonsmotion /* Switches on P2 (direction pad) */ interrupt(PORT2_VECTOR) Port_2(void) { unsigned char p2Val = P2IN & P2SwMask; /* read switches from p2 */ P2IES= p2Val; /* interrupt on value change */ P2IFG = 0; /* clear pending P2 interrupts */ /* just remember button state */ oldP2SwVal = p2Val; } void updatePaddle(void) /* called by timer interrupt handler */ { // check if up switch is pressed if (!(oldP2SwVal & UpSw)) { if (paddleY > 6) paddleY--; drawPaddle(paddleY); } // check if down switch is pressed if (!(oldP2SwVal & DownSw)) { paddleY++; drawPaddle(paddleY); } }