// カラー電光掲示板(16×16×5文字, ATtiny85, Fck=14.32MHz) // 2007.6.29 koyama@cc.hirosaki-u.ac.jp #include #include #include #include #define T1000 61 #define Fck 14.32 #define VS 156 #define HS 12 #define SYN 0x04 #define BLK 0x05 #define GRY 0x06 #define WHT 0x07 #define SCl 0x05 #define SCh 0x06 #define SCREEN_W 80 #define SCREEN_H 16 #define LINEtop 56 #define LINEdup 8 #define LINEext (LINEtop+SCREEN_H*LINEdup) #define FONT_W 8 #define FONT_H 16 #define SWon() bit_is_clear(PINB,2) #define SWoff() bit_is_set(PINB,2) #define nop() asm volatile("nop"::) #define sc(a,b) {PORTB=a;PORTB=a; PORTB=b;PORTB=b;} #define sc8(a,b) {sc(a,b);sc(a,b);sc(a,b);sc(a,b);sc(a,b);sc(a,b);sc(a,b);sc(a,b);} #include "font.c" // 8x16および16×16のフォント #if defined(_WHITE) #define pxl(x) {if(x){PORTB=WHT;nop();}else{PORTB=BLK;nop();nop();}} #define pxl8(x) {pxl(x&0x80); pxl(x&0x40); pxl(x&0x20); pxl(x&0x10); pxl(x&0x08); pxl(x&0x04); pxl(x&0x02); pxl(x&0x01);} #else #define pxl(x,r1,r2) asm volatile("rol %0\n\t" \ "out 0x18,%1\n\t"\ "brcc L1_%=\n\t" \ "out 0x18,%2\n\t"\ "L1_%=: nop\n\t" \ "out 0x18,%1\n\t"\ "brcc L2_%=\n\t" \ "out 0x18,%2\n\t"\ "L2_%=:" \ : \ : "d" (x), "r" (r1), "r" (r2) ) #define pxl8(x) {pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);pxl(x,blk,wht);} #endif prog_uint8_t *q; // mesのポインタ uint8_t mmode=NMES+1; // 表示モード(初めは連続表示モード) uint8_t imes=0; // 表示中のメッセージ番号 uint8_t mescnt; // mes表示回数 // (SCREEN_W+8)×SCREEN_Hドットvramとポインタ(ただしTV表示はSCREEN_W×SCREEN_H) uint8_t vram[(SCREEN_W/8+2)*SCREEN_H]; // (SCREEN_W+16)×SCREEN_Hドット uint8_t swcntr=0; // SWのチャタリング防止カウンタ uint8_t pcntr=0; // ポーズカウンタ uint8_t dcntr=0; // ドットカウンタ void setc(){ // 次の文字のフォントをvramにセット uint8_t i,j,c; uint16_t v; c=pgm_read_byte(q++); // cはmesの次の文字コード if(c==255){ // 文字列の終わり if(pgm_read_byte(&patt[imes])&1!=0) pcntr=T1000; // 行末でポーズ if(NMES>1 && mmode==NMES+1){// 2以上の連続表示モードならimesを更新 if(++imes==NMES){ imes=0; if(pcntr==0) mescnt++; // mes表示回数更新 } }else if(pcntr==0) mescnt++; // mes表示回数更新 q=(prog_uint8_t *)mes[imes]; c=pgm_read_byte(q++); } i=SCREEN_W/8; if(c<0x80){ // 8x16ドットフォント dcntr=8; for(j=0;j>8; vram[i+1]=v&0xff; } } } ISR(TIM1_COMPA_vect){} // 64us ISR(INT0_vect){ swcntr=255; GIMSK=0;}// Ext SW チャタリング防止(64*255=16.3ms) int main (void){ uint8_t b0,b1,b2,b3,b4,b5,b6,b7,b8,b9,b10, blk, wht, i,j,k; uint8_t line=0; // 走査線カウンタで64us毎にカウントアップ uint8_t fcntr=0; // フレームカウンタ uint8_t S=0; // スイッチ操作に伴う状態 uint8_t *p; // vram[]のポインタ PORTB=0x04; DDRB=0x03; // xxxxxroo OCR1A=OCR1C=227; TCCR1=0x83; // CTC on OCR1C=227(63.687us),CK/4 q=(prog_uint8_t *)mes[imes]; TIMSK=(1<0){ if(SWon()) swcntr=255; else if(--swcntr==0){ // Ext SW を離して16.3ms後 for(i=0;i<(SCREEN_W/8+2)*SCREEN_H;i++) vram[i]=0;// vramクリヤ GIMSK=(1<NMES+1 || NMES==1 && mmode==2) imes=mmode=0;//mes[0]の単一表示 else if(mmode==NMES){ // 次のSW操作までsleep if(NMES==1) mmode=0; // NMESが1なら常に連続表示モード set_sleep_mode(SLEEP_MODE_PWR_DOWN); PORTB=0x04; DDRB=0x00; // xxxxxrii sleep_mode(); // SE=1, sleep, SE=0 PORTB=0x04; DDRB=0x03; // xxxxxroo Ext SWでwake up imes=0; // (wakeup後は連続表示モード) }else if(mmode==NMES+1) imes=0; // mes[0]から連続表示 else imes=mmode; // mes[mmode]の単一表示 q=(prog_uint8_t *)mes[imes]; mescnt=0; } } set_sleep_mode(SLEEP_MODE_IDLE);sleep_mode(); // SE=1, sleep, SE=0 // タイマー割り込みでスリープからwake up(64usに同期) // V周期は 4/Fck * 228 * 256=16.3ms PORTB=SYN; for(i=0;i=LINEtop && line0){ nop();nop();nop();nop();nop();nop();} else if(fcntr&1){ nop();nop();nop();} // スムーズスクロール else{ nop();nop();nop();nop();nop();nop();nop();nop();} #if !defined(_WHITE) if(mescnt&1){ // R (M-B-G-R) #if defined(_RED) nop();nop();nop(); #elif defined(_MAGENTA) nop();nop();nop();nop(); #elif defined(_BLUE) nop(); #elif defined(_GREEN) nop();nop(); #else nop();nop();nop(); // デフォルトは赤 #endif }else{ #if defined(_GREEN) nop();nop();nop(); #elif defined(_BLUE) nop();nop(); #elif defined(_MAGENTA) nop(); #elif defined(_RED) nop();nop();nop();nop(); #else nop();nop();nop(); // デフォルトは緑 #endif } #endif b0=*p; b1=*(p+1);b2=*(p+2);b3=*(p+3);b4=*(p+4); b5=*(p+5); b6=*(p+6);b7=*(p+7);b8=*(p+8);b9=*(p+9); blk=BLK; wht=WHT; pxl8(b0);pxl8(b1);pxl8(b2);pxl8(b3);pxl8(b4); pxl8(b5);pxl8(b6);pxl8(b7);pxl8(b8);pxl8(b9); PORTB=BLK; if(line%LINEdup==LINEdup-1) p+=(SCREEN_W/8+2); // ライン重複 }else if(line==LINEext) p=vram; else if(line>LINEext && line<=LINEext+SCREEN_H && pcntr==0 && dcntr>0 && fcntr&1){ b0=*p; b1=*(p+1);b2=*(p+2);b3=*(p+3);b4=*(p+4); b5=*(p+5); b6=*(p+6);b7=*(p+7);b8=*(p+8);b9=*(p+9); b10=*(p+10);i=*(p+11); b0<<=1; if(b1&0x80) *p++=b0|1; else *p++=b0;// vramスクロール b1<<=1; if(b2&0x80) *p++=b1|1; else *p++=b1; b2<<=1; if(b3&0x80) *p++=b2|1; else *p++=b2; b3<<=1; if(b4&0x80) *p++=b3|1; else *p++=b3; b4<<=1; if(b5&0x80) *p++=b4|1; else *p++=b4; b5<<=1; if(b6&0x80) *p++=b5|1; else *p++=b5; b6<<=1; if(b7&0x80) *p++=b6|1; else *p++=b6; b7<<=1; if(b8&0x80) *p++=b7|1; else *p++=b7; b8<<=1; if(b9&0x80) *p++=b8|1; else *p++=b8; b9<<=1; if(b10&0x80)*p++=b9|1; else *p++=b9; b10<<=1;if(i&0x80) *p++=b10|1; else *p++=b10; *p++=(i<<1); }else if(line==LINEext+SCREEN_H+1 && pcntr==0){ if(dcntr>0 && fcntr&1) dcntr--; if(dcntr==0) setc(); }else if(line==255){ fcntr++; if(pcntr>0 && --pcntr==0){ for(i=k=0;i