目次
前
次
画像処理下準備3
カメラから取得した画像データを、カラー液晶ディスプレイ
に表示して確認するのが、簡単な動作テストになりますが、
手持ちがないので、モノクログラフィック液晶に画像を表示
します。
利用するモノクログラフィック液晶は、128x64のTG12864を
使います。(傷を避けるために、シートを貼っています。)
ピン数の少ないマイコンに接続できるように、シフトレジスタ
を利用し、インタフェース回路は、次のようにしました。
回路を実装した基板は、次のようになります。
マイコンは、10ピンを次のように使います。
- Vcc
- T164_DAT
- T164_CLK
- LCW_RST
- LCW_CS2
- LCW_CS1
- LCW_RS
- LCW_RW
- LCW_E
- GND
キャラクタ型のLCDと似たインタフェースで
2つのレジスタを持っていると考えられます。
レジスタへのデータ転送は、次のシーケンスとします。
- LCW_RSの論理値を、指定値に
- シフトレジスタに8ビットデータ転送
- LCW_EをLに設定
- LCW_RWをLに設定
- LCW_EをHに設定
- ディレイ
- LCW_EをLに設定
- LCW_RWをHに設定
液晶は、64x64の画面を左右に2枚持っているので
上のシーケンスをひとつの関数にして、CS1、CS2
により左、右の表示領域を選びます。
これらの操作を加えて、液晶の表示のために作成
したテストファームウエアは、以下です。
(ATmega644Pを使っています。)
#include <avr/io.h>
#include <avr/interrupt.h>
typedef unsigned char UBYTE ;
typedef signed char SBYTE ;
typedef unsigned short UWORD ;
typedef signed short SWORD ;
typedef unsigned long ULONG ;
typedef signed long SLONG ;
#define OFF 0
#define ON 1
#define LCD_DAT 7
#define LCD_CLK 6
#define LCD_RST 5
#define LCD_CS2 4
#define LCD_CS1 3
#define LCD_RS 2
#define LCD_RW 1
#define LCD_E 0
#define LCD_RS_H 1
#define LCD_RS_L 0
#define MASKFF 0xFF
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01
#define MASKF0 0xF0
#define SEL_LEFT 2
#define SEL_RIGHT 1
#define SEL_NONE 0
#define GMAX 512
#define YMAX 8
#define XMAX 64
volatile UBYTE eflag ;
volatile UBYTE lgdat[GMAX] ;
volatile UBYTE rgdat[GMAX] ;
volatile UBYTE lgdatx[GMAX] ;
volatile UBYTE rgdatx[GMAX] ;
volatile UBYTE mode ;
volatile ULONG timcnt ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
void update_led(UBYTE x);
void send_data(UBYTE which,UBYTE x);
void select_plane(UBYTE x);
void display(UBYTE x);
void set_address(UBYTE x);
void set_page(UBYTE x);
void set_start_line(UBYTE x);
void set_display_data(UBYTE x);
void display_lcd(UBYTE which,UBYTE *x);
void init_lcd(void);
void display_bw(UBYTE x);
void display_black(void);
void display_white(void);
void rotate(UBYTE *x,UBYTE *y);
void rotate_gdat(UBYTE *s,UBYTE *d);
void delay_ms(UBYTE x);
/*------*/
/* main */
/*------*/
int main(void)
{
UWORD i ;
/* initialize I/O */
user_initialize();
/* enable interrupt */
sei() ;
/* initialize LCD */
init_lcd();
/* endless loop */
while ( ON ) {
/* get DIP switch data*/
PORTA = ((PINA & MASKF0) >> 4);
/* select mode */
if ( eflag ) {
/* clear flag */
eflag = OFF ;
/* get mode */
mode = (PIND & 3) ;
PORTA = (mode << 4) ^ MASKF0 ;
/* handling */
if ( mode == 1 ) { display_white(); }
if ( mode == 2 ) { display_black(); }
if ( mode == 3 ) { init_lcd(); }
if ( mode == 0 ) {
for ( i = 0 ; i < GMAX ; i++ ) {
/* initialize left area */
*(lgdatx+i) = 0x55 ;
/* initialize right area */
*(rgdatx+i) = 0xaa ;
if ( (i & 3) == 0 ) {
*(lgdatx+i) = 0x00 ;
*(rgdatx+i) = 0xff ;
}
}
/* rotate */
rotate_gdat((UBYTE *)lgdat,(UBYTE *)lgdatx);
rotate_gdat((UBYTE *)rgdat,(UBYTE *)rgdatx);
/* show */
display_lcd(SEL_LEFT ,(UBYTE *)lgdatx);
display_lcd(SEL_RIGHT,(UBYTE *)rgdatx);
}
}
}
/* dummy */
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
UWORD i ;
/* PORT A */
PORTA = 0b11111111 ; /* 11111111 */
DDRA = 0b11111111 ; /* oooooooo */
/* PORT B */
PORTB = 0b00000000 ; /* 00000000 */
DDRB = 0b11111111 ; /* oooooooo */
/* PORT C */
PORTC = 0b00100010 ; /* 00100010 */
DDRC = 0b11111111 ; /* oooooooo */
/* PORT D */
PORTD = 0b00001111 ; /* 00001111 */
DDRD = 0b11110000 ; /* ooooiiii */
/* initialize timer1 */
{
/* clear counter */
TCNT1 = 0 ;
/* set compare value */
OCR1A = 15999 ;
OCR1B = 30000 ;
/* prescaler 1/1 => 16MHz */
TCCR1B = (1 << WGM12) | (1 << CS10) ;
/* enable compare match */
TIMSK1 = (1 << OCIE1A) ;
}
/* initialize INT0 */
{
/* select falling edge */
EICRA = (1 << ISC01) ;
/* enable INT0 */
EIMSK = (1 << INT0);
}
/* initialize registers */
eflag = OFF ;
timcnt = 0 ;
mode = 0 ;
/* clear */
for ( i = 0 ; i < GMAX ; i++ ) {
*(lgdat+i) = 0 ;
*(rgdat+i) = 0 ;
*(lgdatx+i) = 0 ;
*(rgdatx+i) = 0 ;
}
}
void update_led(UBYTE x)
{
volatile UBYTE bport ;
/* generate code */
bport = (1 << x);
/* inverse */
bport ^= 0xff;
/* impress */
PORTB = bport ;
}
void send_data(UBYTE which,UBYTE x)
{
UBYTE loop ;
UBYTE tmp ;
/* get data */
tmp = x ;
/* Write mode */
PORTC &= ~(1 << LCD_RW);
/* data transfer to 74HC164 */
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* set bit datum */
PORTC &= ~(1 << LCD_DAT) ;
if ( tmp & MASK80 ) { PORTC |= (1 << LCD_DAT) ; }
/* CLOCK : H */
PORTC |= (1 << LCD_CLK) ;
/* shift */
tmp <<= 1 ;
/* CLOCK : L */
PORTC &= ~(1 << LCD_CLK) ;
}
/* confirm RS */
PORTC &= ~(1 << LCD_RS) ;
if ( which ) { PORTC |= (1 << LCD_RS) ; }
/* latch */
PORTC |= (1 << LCD_E) ;
PORTC &= ~(1 << LCD_DAT) ; /* dummy */
PORTC &= ~(1 << LCD_E) ;
/* read mode */
PORTC |= (1 << LCD_RW);
}
void select_plane(UBYTE x)
{
/* CS1 = 0 , CS2 = 0 */
PORTC &= ~(1 << LCD_CS1);
PORTC &= ~(1 << LCD_CS2);
/* */
if ( x == SEL_LEFT ) { PORTC |= (1 << LCD_CS1); }
if ( x == SEL_RIGHT ) { PORTC |= (1 << LCD_CS2); }
}
void display(UBYTE x)
{
send_data(LCD_RS_L,0x3E | x);
}
void set_address(UBYTE x)
{
/* check */
if ( x >= XMAX ) return ;
/* send address */
send_data(LCD_RS_L,0x40 | x);
}
void set_page(UBYTE x)
{
/* check */
if ( x >= YMAX ) return ;
/* send address */
send_data(LCD_RS_L,0xb8 | x);
}
void set_start_line(UBYTE x)
{
/* check */
if ( x >= XMAX ) return ;
/* send address */
send_data(LCD_RS_L,0xC0 | x);
}
void set_display_data(UBYTE x)
{
send_data(LCD_RS_H,x);
}
void display_lcd(UBYTE which,UBYTE *x)
{
UBYTE xx ;
UBYTE yy ;
UBYTE tmp ;
/* select plane */
select_plane(which);
/* show */
display(OFF);
/* transfer data */
set_start_line(0) ;
for ( yy = 0 ; yy < YMAX ; yy++ ) {
set_page(yy) ;
set_address(0) ;
for ( xx = 0 ; xx < XMAX ; xx++ ) {
tmp = *x ;
set_display_data( tmp ) ;
x++ ;
}
}
/* show */
display(ON);
/* disable all plane */
select_plane(SEL_NONE);
}
void init_lcd(void)
{
UBYTE i ;
/* send reset signal */
{
PORTC &= ~(1 << LCD_RST) ;
for ( i = 0 ; i < 32 ; i++ ) ; /* delay dummy */
PORTC |= (1 << LCD_RST) ;
}
/* delay 30 ms */
delay_ms( 30 ) ;
/* select first line */
send_data(OFF,0xC0);
/* display on */
send_data(OFF,0x3f);
}
void display_bw(UBYTE x)
{
UBYTE xx ;
UBYTE yy ;
UBYTE k ;
for ( k = 0 ; k < 2 ; k++ ) {
/* select plane */
select_plane(SEL_LEFT);
if ( k ) { select_plane(SEL_RIGHT); }
/* show */
display(OFF);
/* transfer data */
set_start_line(0) ;
for ( yy = 0 ; yy < YMAX ; yy++ ) {
set_page(yy) ;
set_address(0) ;
for ( xx = 0 ; xx < XMAX ; xx++ ) {
set_display_data( x ^ MASKFF ) ;
if ( k ) { set_display_data( x ) ; }
}
}
/* show */
display(ON);
/* disable all plane */
select_plane(SEL_NONE);
}
}
void display_black(void)
{
display_bw( 0 );
}
void display_white(void)
{
display_bw( MASKFF );
}
void rotate(UBYTE *x,UBYTE *y)
{
UBYTE adat[8] ;
UBYTE mask ;
UBYTE i ;
UBYTE j ;
UBYTE shf ;
UBYTE result ;
/* get */
for ( i = 0 ; i < 8 ; i++ ) { *(adat+i) = *(x+i) ; }
/* rotate */
for ( i = 0 ; i < 8 ; i++ ) {
/* shift counter */
shf = 7 - i ;
/* 80 40 20 10 08 04 02 01 */
mask = (1 << shf) ;
/* result */
result = 0 ;
/* bit operation */
for ( j = 7 ; j > 0 ; j-- ) {
result |= (((*(adat+j) & mask) >> shf) & 1) ;
result <<= 1 ;
}
result |= (((*(adat+0) & mask) >> shf) & 1) ;
/* put */
*(y+i) = result ;
}
}
void rotate_gdat(UBYTE *s,UBYTE *d)
{
UBYTE adat[8] ;
UBYTE bdat[8] ;
UBYTE i ;
UBYTE j ;
UBYTE k ;
UWORD ptr ;
/* destination pointer */
ptr = 0 ;
/* block handling */
for ( i = 0 ; i < 8 ; i++ ) {
for ( j = 0 ; j < 8 ; j++ ) {
/* get */
for ( k = 0 ; k < 8 ; k++ ) {
*(adat+k) = *(s+64*i+j+k*8);
}
/* rotate */
rotate(adat,bdat) ;
/* put */
for ( k = 0 ; k < 8 ; k++ ) {
*(d+ptr+k) = *(bdat+k);
ptr++ ;
}
}
}
}
/* INT0 interrupt */
ISR(INT0_vect)
{
eflag = ON ;
}
void delay_ms(UBYTE x)
{
ULONG last ;
last = timcnt + x ;
while ( timcnt < last ) ;
}
/* TIMER1 interrupt (1msec) */
ISR(TIMER1_COMPA_vect)
{
timcnt++ ;
}
仕様は単純で、次のようにしました。
セレクタスイッチで動作指定後、トリガーを
与えると、左あるいは右の領域に白を表示。
セレクタスイッチとして、次の基板を使いました。
すべてプッシュスイッチとしたので、動作を与える
には、次の仕様にします。
- (SEL1,SEL0)=(1,1)でトリガーを与えると、初期化リセット
- (SEL1,SEL0)=(1,0)でトリガーを与えると、左だけ白表示
- (SEL1,SEL0)=(0,1)でトリガーを与えると、右だけ白表示
左領域のみ白表示。
右領域のみ白表示。
初期化リセット。
画像を表示する場合、フレームバッファを持っていた方が
よいので、FPGAを使うなら、内部SRAMをフレームバッファ
とします。
利用している液晶は、画面を次のように使っているので
回転処理を実行する回路が必要になります。
ラスター(横)方向にデータを並べるのではなく、縦に
1バイトのデータを与えると、意図した画像になります。
単純な並べ変えなので、VHDLコードにするのは簡単でした。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity rotxtst is
port (
-- system
nRESET : in std_logic ;
CLOCK : in std_logic ;
-- trigger
TRG : in std_logic ;
-- select
SELIN : in std_logic_vector(2 downto 0) ;
SELOUT : in std_logic_vector(2 downto 0) ;
-- input
Din : in std_logic_vector(7 downto 0);
-- output
Dout : out std_logic_vector(7 downto 0)--;
);
end rotxtst;
architecture Behavioral of rotxtst is
-- trigger
signal iTRG_SFT : std_logic_vector(2 downto 0);
signal iTRG : std_logic ;
-- data input
signal iDin0 : std_logic_vector(7 downto 0);
signal iDin1 : std_logic_vector(7 downto 0);
signal iDin2 : std_logic_vector(7 downto 0);
signal iDin3 : std_logic_vector(7 downto 0);
signal iDin4 : std_logic_vector(7 downto 0);
signal iDin5 : std_logic_vector(7 downto 0);
signal iDin6 : std_logic_vector(7 downto 0);
signal iDin7 : std_logic_vector(7 downto 0);
-- data output
signal iDout0 : std_logic_vector(7 downto 0);
signal iDout1 : std_logic_vector(7 downto 0);
signal iDout2 : std_logic_vector(7 downto 0);
signal iDout3 : std_logic_vector(7 downto 0);
signal iDout4 : std_logic_vector(7 downto 0);
signal iDout5 : std_logic_vector(7 downto 0);
signal iDout6 : std_logic_vector(7 downto 0);
signal iDout7 : std_logic_vector(7 downto 0);
begin
-- trigger
process(nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iTRG_SFT <= "000" ;
elsif rising_edge(CLOCK) then
iTRG_SFT <= iTRG_SFT(1 downto 0) & TRG ;
end if;
end process;
iTRG <= '1' when( iTRG_SFT = "011" or iTRG_SFT = "001" ) else '0' ;
-- get data
process(nRESET,CLOCK)
begin
if ( nRESET = '0' ) then
iDin0 <= (others => '0') ;
iDin1 <= (others => '0') ;
iDin2 <= (others => '0') ;
iDin3 <= (others => '0') ;
iDin4 <= (others => '0') ;
iDin5 <= (others => '0') ;
iDin6 <= (others => '0') ;
iDin7 <= (others => '0') ;
elsif rising_edge(CLOCK) then
if ( iTRG = '1' ) then
if ( conv_integer(SELIN) = 0 ) then
iDin0 <= Din ;
end if ;
if ( conv_integer(SELIN) = 1 ) then
iDin1 <= Din ;
end if ;
if ( conv_integer(SELIN) = 2 ) then
iDin2 <= Din ;
end if ;
if ( conv_integer(SELIN) = 3 ) then
iDin3 <= Din ;
end if ;
if ( conv_integer(SELIN) = 4 ) then
iDin4 <= Din ;
end if ;
if ( conv_integer(SELIN) = 5 ) then
iDin5 <= Din ;
end if ;
if ( conv_integer(SELIN) = 6 ) then
iDin6 <= Din ;
end if ;
if ( conv_integer(SELIN) = 7 ) then
iDin7 <= Din ;
end if ;
end if ;
end if;
end process;
-- output
Dout <= iDout1 when ( SELOUT = "001" ) else
iDout2 when ( SELOUT = "010" ) else
iDout3 when ( SELOUT = "011" ) else
iDout4 when ( SELOUT = "100" ) else
iDout5 when ( SELOUT = "101" ) else
iDout6 when ( SELOUT = "110" ) else
iDout7 when ( SELOUT = "111" ) else
iDout0 ;
-- rotate
iDout0 <= iDin7(7) & iDin6(7) &iDin5(7) & iDin4(7) &iDin3(7) & iDin2(7) &iDin1(7) & iDin0(7);
iDout1 <= iDin7(6) & iDin6(6) &iDin5(6) & iDin4(6) &iDin3(6) & iDin2(6) &iDin1(6) & iDin0(6);
iDout2 <= iDin7(5) & iDin6(5) &iDin5(5) & iDin4(5) &iDin3(5) & iDin2(5) &iDin1(5) & iDin0(5);
iDout3 <= iDin7(4) & iDin6(4) &iDin5(4) & iDin4(4) &iDin3(4) & iDin2(4) &iDin1(4) & iDin0(4);
iDout4 <= iDin7(3) & iDin6(3) &iDin5(3) & iDin4(3) &iDin3(3) & iDin2(3) &iDin1(3) & iDin0(3);
iDout5 <= iDin7(2) & iDin6(2) &iDin5(2) & iDin4(2) &iDin3(2) & iDin2(2) &iDin1(2) & iDin0(2);
iDout6 <= iDin7(1) & iDin6(1) &iDin5(1) & iDin4(1) &iDin3(1) & iDin2(1) &iDin1(1) & iDin0(1);
iDout7 <= iDin7(0) & iDin6(0) &iDin5(0) & iDin4(0) &iDin3(0) & iDin2(0) &iDin1(0) & iDin0(0);
end Behavioral;
8バイトのデータを、8回に分けて与えると
内部で切貼りして、8バイトのデータになる
ようにしました。
内部にある8バイトの回転したデータは、8回
に分けて出力できるようになっています。
FPGA内部で入出力ピンが不要な場合は、次のVHDL
コードで回路を入れられます。
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.ALL;
use IEEE.STD_LOGIC_UNSIGNED.ALL;
entity rotxtst is
port (
-- input
Din0 : in std_logic_vector(7 downto 0);
Din1 : in std_logic_vector(7 downto 0);
Din2 : in std_logic_vector(7 downto 0);
Din3 : in std_logic_vector(7 downto 0);
Din4 : in std_logic_vector(7 downto 0);
Din5 : in std_logic_vector(7 downto 0);
Din6 : in std_logic_vector(7 downto 0);
Din7 : in std_logic_vector(7 downto 0);
-- output
Dout0 : out std_logic_vector(7 downto 0);
Dout1 : out std_logic_vector(7 downto 0);
Dout2 : out std_logic_vector(7 downto 0);
Dout3 : out std_logic_vector(7 downto 0);
Dout4 : out std_logic_vector(7 downto 0);
Dout5 : out std_logic_vector(7 downto 0);
Dout6 : out std_logic_vector(7 downto 0);
Dout7 : out std_logic_vector(7 downto 0)--;
);
end rotxtst;
architecture Behavioral of rotxtst is
-- data input
signal iDin0 : std_logic_vector(7 downto 0);
signal iDin1 : std_logic_vector(7 downto 0);
signal iDin2 : std_logic_vector(7 downto 0);
signal iDin3 : std_logic_vector(7 downto 0);
signal iDin4 : std_logic_vector(7 downto 0);
signal iDin5 : std_logic_vector(7 downto 0);
signal iDin6 : std_logic_vector(7 downto 0);
signal iDin7 : std_logic_vector(7 downto 0);
-- data output
signal iDout0 : std_logic_vector(7 downto 0);
signal iDout1 : std_logic_vector(7 downto 0);
signal iDout2 : std_logic_vector(7 downto 0);
signal iDout3 : std_logic_vector(7 downto 0);
signal iDout4 : std_logic_vector(7 downto 0);
signal iDout5 : std_logic_vector(7 downto 0);
signal iDout6 : std_logic_vector(7 downto 0);
signal iDout7 : std_logic_vector(7 downto 0);
begin
-- input
iDin0 <= Din0 ;
iDin1 <= Din1 ;
iDin2 <= Din2 ;
iDin3 <= Din3 ;
iDin4 <= Din4 ;
iDin5 <= Din5 ;
iDin6 <= Din6 ;
iDin7 <= Din7 ;
-- output
Dout1 <= iDout1 ;
Dout2 <= iDout2 ;
Dout3 <= iDout3 ;
Dout4 <= iDout4 ;
Dout5 <= iDout5 ;
Dout6 <= iDout6 ;
Dout7 <= iDout7 ;
Dout0 <= iDout0 ;
-- rotate
iDout0 <= iDin7(7) & iDin6(7) &iDin5(7) & iDin4(7) &iDin3(7) & iDin2(7) &iDin1(7) & iDin0(7);
iDout1 <= iDin7(6) & iDin6(6) &iDin5(6) & iDin4(6) &iDin3(6) & iDin2(6) &iDin1(6) & iDin0(6);
iDout2 <= iDin7(5) & iDin6(5) &iDin5(5) & iDin4(5) &iDin3(5) & iDin2(5) &iDin1(5) & iDin0(5);
iDout3 <= iDin7(4) & iDin6(4) &iDin5(4) & iDin4(4) &iDin3(4) & iDin2(4) &iDin1(4) & iDin0(4);
iDout4 <= iDin7(3) & iDin6(3) &iDin5(3) & iDin4(3) &iDin3(3) & iDin2(3) &iDin1(3) & iDin0(3);
iDout5 <= iDin7(2) & iDin6(2) &iDin5(2) & iDin4(2) &iDin3(2) & iDin2(2) &iDin1(2) & iDin0(2);
iDout6 <= iDin7(1) & iDin6(1) &iDin5(1) & iDin4(1) &iDin3(1) & iDin2(1) &iDin1(1) & iDin0(1);
iDout7 <= iDin7(0) & iDin6(0) &iDin5(0) & iDin4(0) &iDin3(0) & iDin2(0) &iDin1(0) & iDin0(0);
end Behavioral;
ラスター方向に並んでいる画像データを
手持ちグラフィック液晶で表示するため
上のVHDLコードを参考に、ファームウエア
を修正しました。
#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
typedef unsigned char UBYTE ;
typedef signed char SBYTE ;
typedef unsigned short UWORD ;
typedef signed short SWORD ;
typedef unsigned long ULONG ;
typedef signed long SLONG ;
#define OFF 0
#define ON 1
#define LCD_DAT 7
#define LCD_CLK 6
#define LCD_RST 5
#define LCD_CS2 4
#define LCD_CS1 3
#define LCD_RS 2
#define LCD_RW 1
#define LCD_E 0
#define LCD_RS_H 1
#define LCD_RS_L 0
#define MASKFF 0xFF
#define MASK80 0x80
#define MASK40 0x40
#define MASK20 0x20
#define MASK10 0x10
#define MASK08 0x08
#define MASK04 0x04
#define MASK02 0x02
#define MASK01 0x01
#define MASKF0 0xF0
#define SEL_LEFT 2
#define SEL_RIGHT 1
#define SEL_NONE 0
#define GMAX 512
#define YMAX 8
#define XMAX 64
volatile UBYTE eflag ;
volatile UBYTE eflagx ;
volatile UBYTE fbuf[GMAX] ;
volatile UBYTE lgdat[GMAX] ;
volatile UBYTE rgdat[GMAX] ;
volatile UBYTE lgdatx[GMAX] ;
volatile UBYTE rgdatx[GMAX] ;
volatile UBYTE mode ;
volatile ULONG timcnt ;
/*--------------------------------*/
/* Insert user functions protoype */
/*--------------------------------*/
void user_initialize(void);
void send_data(UBYTE which,UBYTE x);
void select_plane(UBYTE x);
void display(UBYTE x);
void set_address(UBYTE x);
void set_page(UBYTE x);
void set_start_line(UBYTE x);
void set_display_data(UBYTE x);
void display_lcd(UBYTE which,UBYTE *x);
void init_lcd(void);
void display_bw(UBYTE x,UBYTE which);
void display_black0(void);
void display_white0(void);
void display_black(void);
void display_white(void);
void rotate(UBYTE *x,UBYTE *y);
void rotate_gdat(UBYTE *s,UBYTE *d);
void delay_ms(UBYTE x);
void init_gdat(UBYTE *x,UBYTE y);
void show_sample(void);
/* sample data */
const UBYTE PROGMEM img_dat[]={
0x00,0x00,0x30,0x30,0x38,0xF8,0xF8,0x18,0x0C,0x08,0xE0,0xE0,0x60,0xFC,0xFC,0xFC,
0x00,0x00,0xF0,0xF0,0xF0,0x00,0x00,0x00,0x00,0xF8,0xF8,0xF8,0x18,0x18,0x18,0x18,
0x18,0x18,0x18,0x18,0x18,0xF8,0xF8,0xF8,0x00,0x00,0x00,0x00,0xC0,0xD8,0x58,0x58,
0x58,0x58,0x58,0x58,0xF8,0xF8,0xF8,0x58,0x58,0x58,0x58,0x58,0xD8,0xC0,0xC0,0x00,
0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x98,0x98,0x98,0xD8,0xD8,0xF8,0xF8,
0x78,0x38,0x10,0x00,0x00,0x00,0x20,0xF0,0xF0,0xC0,0x80,0x00,0x98,0xB8,0xF8,0xF8,
0xD8,0xD8,0xD8,0xF8,0xF8,0xB8,0xB8,0x98,0x00,0x00,0x00,0x18,0x98,0x98,0x98,0xF8,
0xF8,0xF8,0x98,0x9C,0x9C,0x9C,0x98,0xF8,0xF8,0xF8,0x98,0x98,0x98,0x18,0x00,0x00,
0x00,0x00,0xC3,0xE3,0x7F,0xFF,0xFF,0x3B,0x73,0x2C,0x0F,0x0F,0xC0,0xFF,0xFF,0x7F,
0xF8,0xDE,0x1F,0x0F,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x63,0x63,0x63,0x63,
0x63,0x63,0x63,0x63,0x63,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00,0x07,0xF7,0xF0,0xF5,
0x55,0x55,0x55,0x50,0xF7,0xF7,0xF7,0x50,0x55,0x55,0x55,0xF0,0xF7,0xF7,0x07,0x00,
0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,0xFF,0x1B,0x19,0x19,0x18,
0x18,0x18,0x18,0x18,0x00,0x00,0x0C,0x0C,0xFD,0xFD,0x00,0x00,0xFF,0xFF,0x6D,0x6D,
0x6D,0xFF,0xFF,0x6D,0x6D,0x6D,0xFF,0xFF,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0x31,
0xD9,0xDF,0xCF,0xC7,0xC1,0xCF,0xDF,0xDF,0xD9,0x19,0x19,0xFF,0xFF,0x00,0x00,0x00,
0x00,0x01,0x03,0x01,0x00,0x1F,0x1F,0x00,0x08,0x1C,0x0E,0x07,0x03,0x01,0x00,0x00,
0x01,0x07,0x0F,0x1E,0x0C,0x00,0x08,0x0C,0x1F,0x0F,0x07,0x01,0x00,0x00,0x00,0x00,
0x00,0x00,0x18,0x18,0x18,0x1F,0x1F,0x0F,0x00,0x00,0x00,0x00,0x00,0x07,0x07,0x07,
0x02,0x02,0x02,0x02,0x0F,0x1F,0x1F,0x1A,0x1A,0x1A,0x1A,0x1B,0x1B,0x1F,0x1E,0x0E,
0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x1F,0x1F,0x0F,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x08,0x1C,0x0E,0x07,0x03,0x06,0x0C,0x0B,0x1B,0x18,0x18,
0x18,0x1B,0x1B,0x18,0x1B,0x1B,0x1B,0x1B,0x18,0x08,0x00,0x00,0x1F,0x1F,0x1F,0x00,
0x0F,0x0F,0x0F,0x06,0x06,0x06,0x07,0x07,0x1F,0x18,0x18,0x1F,0x1F,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xE0,0x30,0xB0,0x38,0xB8,0x7C,0xFC,0x7C,0xFC,
0x7C,0xFC,0xFC,0xF8,0xF8,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x02,0x02,0x02,0x02,0x04,0x04,0x04,0x04,0x04,0x04,0x08,
0x08,0x08,0x08,0x38,0x24,0x24,0x3C,0x24,0x24,0x3C,0x44,0x48,0x78,0x48,0x48,0x78,
0x48,0x50,0x20,0x20,0x20,0x20,0x20,0x20,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xE0,0x20,0xD0,
0x30,0xD0,0x50,0x50,0x20,0xE0,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0xAA,0x00,0xAA,0x00,0xAA,0x00,0xAA,
0x00,0xAA,0x00,0xFE,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x0C,0xEC,0xEC,0xEC,0x0C,0x0C,0x0C,0x0C,0x3C,0xFC,0xFC,0x80,0x00,
0x00,0x00,0x00,0x00,0x00,0xD8,0xBC,0x78,0x20,0xD8,0xD8,0xD8,0xFC,0xFC,0xD8,0xD8,
0x18,0xFC,0xFC,0xFC,0xCC,0xFC,0xFC,0xFC,0x00,0x00,0x00,0xF0,0xF0,0xF0,0x30,0x30,
0x30,0x30,0x30,0xFC,0xFC,0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xE0,0x01,0x3E,
0xFE,0xC2,0x03,0x02,0x01,0xE0,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x04,0xFE,0x04,0x0A,0x08,0x0A,0xF8,0x0A,
0x08,0x1A,0xF0,0x1B,0x04,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x80,0xC0,0xF8,0xFF,0x3F,0x07,0x00,0x00,0x00,0x00,0x00,0x07,0x1F,0xFF,0xF8,
0xE0,0x80,0x00,0x00,0x00,0x01,0xF3,0xF3,0x62,0xBF,0xBF,0xBF,0xF2,0xF2,0xBF,0xBF,
0x80,0xFF,0xFF,0x7F,0x18,0xFF,0xFF,0xFF,0x00,0x00,0x80,0xFF,0xFF,0x3F,0xF0,0xF0,
0xF0,0x30,0x30,0x3F,0x3F,0x3F,0x33,0x33,0x33,0xF3,0xF3,0xF3,0x03,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x02,0xFC,
0x07,0x07,0x04,0xFC,0x02,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x7F,0x00,0x00,0x00,0x00,0xFF,0x00,
0x00,0x00,0x07,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x04,
0x0E,0x07,0x03,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,
0x07,0x0F,0x07,0x00,0x00,0x07,0x0F,0x03,0x00,0x01,0x01,0x01,0x0F,0x0F,0x01,0x01,
0x05,0x0F,0x07,0x0C,0x0C,0x0F,0x0F,0x87,0x80,0x84,0x8F,0x0F,0x03,0x00,0x0F,0x0F,
0x0F,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x06,0x0F,0x0F,0x0F,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,
0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x01,0x00,
0x00,0x00,0x00,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x08,0x08,0x08,0x08,0x08,0x14,0x12,
0x1E,0x12,0x12,0x1E,0x12,0x11,0x0F,0x09,0x09,0x0F,0x09,0x09,0x0E,0x02,0x02,0x02,
0x02,0x01,0x01,0x01,0x01,0x01,0x01,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
0x00,0x00,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00
};
/*------*/
/* main */
/*------*/
int main(void)
{
/* initialize I/O */
user_initialize();
/* enable interrupt */
sei() ;
/* initialize LCD */
init_lcd();
/* endless loop */
while ( ON ) {
/* get mode */
mode = (PIND & 3) ;
/* select mode (orange button) */
if ( eflag ) {
/* clear flag */
eflag = OFF ;
/* handling */
if ( mode == 1 ) { display_white(); }
if ( mode == 2 ) { display_black(); }
if ( mode == 3 ) { init_lcd(); }
}
/* select mode (yellow button) */
if ( eflagx ) {
/* clear flag */
eflagx = OFF ;
/* handling */
if ( mode == 0 ) { show_sample(); }
if ( mode == 1 ) { display_black0(); }
if ( mode == 2 ) { display_white0(); }
if ( mode == 3 ) {
/* initialize cross hatch */
init_gdat((UBYTE *)lgdat,0x00);
init_gdat((UBYTE *)rgdat,0xCC);
/* rotate */
rotate_gdat((UBYTE *)lgdat,(UBYTE *)lgdatx);
rotate_gdat((UBYTE *)rgdat,(UBYTE *)rgdatx);
/* show */
display_lcd(SEL_LEFT ,(UBYTE *)lgdatx);
display_lcd(SEL_RIGHT,(UBYTE *)rgdatx);
}
}
}
/* dummy */
return 0 ;
}
/*-----------------------*/
/* Insert user functions */
/*-----------------------*/
void user_initialize(void)
{
UWORD i ;
/* PORT A */
PORTA = 0b11111111 ; /* 11111111 */
DDRA = 0b11111111 ; /* oooooooo */
/* PORT B */
PORTB = 0b00000000 ; /* 00000000 */
DDRB = 0b11111111 ; /* oooooooo */
/* PORT C */
PORTC = 0b00100010 ; /* 00100010 */
DDRC = 0b11111111 ; /* oooooooo */
/* PORT D */
PORTD = 0b00001111 ; /* 00001111 */
DDRD = 0b11110000 ; /* ooooiiii */
/* initialize timer1 */
{
/* clear counter */
TCNT1 = 0 ;
/* set compare value */
OCR1A = 15999 ;
OCR1B = 30000 ;
/* prescaler 1/1 => 16MHz */
TCCR1B = (1 << WGM12) | (1 << CS10) ;
/* enable compare match */
TIMSK1 = (1 << OCIE1A) ;
}
/* initialize INT0 */
{
/* select falling edge */
EICRA = (1 << ISC11) | (1 << ISC01) ;
/* enable INT1 and INT0 */
EIMSK = (1 << INT1) | (1 << INT0) ;
}
/* initialize registers */
eflag = OFF ;
eflagx = OFF ;
timcnt = 0 ;
mode = 0 ;
/* clear */
for ( i = 0 ; i < GMAX ; i++ ) {
*(lgdat+i) = 0 ;
*(rgdat+i) = 0 ;
*(lgdatx+i) = 0 ;
*(rgdatx+i) = 0 ;
}
/* transfer */
for ( i = 0 ; i < GMAX ; i++ ) {
*(fbuf+i) = pgm_read_byte(&img_dat[i]);
}
}
void send_data(UBYTE which,UBYTE x)
{
UBYTE loop ;
UBYTE tmp ;
/* get data */
tmp = x ;
/* Write mode */
PORTC &= ~(1 << LCD_RW);
/* data transfer to 74HC164 */
for ( loop = 0 ; loop < 8 ; loop++ ) {
/* set bit datum */
PORTC &= ~(1 << LCD_DAT) ;
if ( tmp & MASK80 ) { PORTC |= (1 << LCD_DAT) ; }
/* CLOCK : H */
PORTC |= (1 << LCD_CLK) ;
/* shift */
tmp <<= 1 ;
/* CLOCK : L */
PORTC &= ~(1 << LCD_CLK) ;
}
/* confirm RS */
PORTC &= ~(1 << LCD_RS) ;
if ( which ) { PORTC |= (1 << LCD_RS) ; }
/* latch */
PORTC |= (1 << LCD_E) ;
PORTC &= ~(1 << LCD_DAT) ; /* dummy */
PORTC &= ~(1 << LCD_E) ;
/* read mode */
PORTC |= (1 << LCD_RW);
}
void select_plane(UBYTE x)
{
/* CS1 = 0 , CS2 = 0 */
PORTC &= ~(1 << LCD_CS1);
PORTC &= ~(1 << LCD_CS2);
/* */
if ( x == SEL_LEFT ) { PORTC |= (1 << LCD_CS1); }
if ( x == SEL_RIGHT ) { PORTC |= (1 << LCD_CS2); }
}
void display(UBYTE x)
{
send_data(LCD_RS_L,0x3E | x);
}
void set_address(UBYTE x)
{
/* check */
if ( x >= XMAX ) return ;
/* send address */
send_data(LCD_RS_L,0x40 | x);
}
void set_page(UBYTE x)
{
/* check */
if ( x >= YMAX ) return ;
/* send address */
send_data(LCD_RS_L,0xb8 | x);
}
void set_start_line(UBYTE x)
{
/* check */
if ( x >= XMAX ) return ;
/* send address */
send_data(LCD_RS_L,0xC0 | x);
}
void set_display_data(UBYTE x)
{
send_data(LCD_RS_H,x);
}
void display_lcd(UBYTE which,UBYTE *x)
{
UBYTE xx ;
UBYTE yy ;
UBYTE tmp ;
/* select plane */
select_plane(which);
/* show */
display(OFF);
/* transfer data */
set_start_line(0) ;
for ( yy = 0 ; yy < YMAX ; yy++ ) {
set_page(yy) ;
set_address(0) ;
for ( xx = 0 ; xx < XMAX ; xx++ ) {
tmp = *x ;
set_display_data( tmp ) ;
x++ ;
}
}
/* show */
display(ON);
/* disable all plane */
select_plane(SEL_NONE);
}
void init_lcd(void)
{
UBYTE i ;
/* send reset signal */
{
PORTC &= ~(1 << LCD_RST) ;
for ( i = 0 ; i < 32 ; i++ ) ; /* delay dummy */
PORTC |= (1 << LCD_RST) ;
}
/* delay 30 ms */
delay_ms( 30 ) ;
/* select first line */
send_data(OFF,0xC0);
/* display on */
send_data(OFF,0x3f);
}
void display_bw(UBYTE x,UBYTE which)
{
UBYTE xx ;
UBYTE yy ;
UBYTE k ;
/* disable all plane */
select_plane(SEL_NONE);
k = 0 ;
/* LEFT */
if ( which == SEL_LEFT ) {
select_plane(SEL_LEFT);
k++ ;
}
/* RIGHT */
if ( which == SEL_RIGHT ) {
select_plane(SEL_RIGHT);
k++ ;
}
/* judge */
if ( k == 0 ) return ;
/* show */
display(OFF);
/* transfer data */
set_start_line(0) ;
for ( yy = 0 ; yy < YMAX ; yy++ ) {
set_page(yy) ;
set_address(0) ;
for ( xx = 0 ; xx < XMAX ; xx++ ) {
set_display_data( x ) ;
}
}
/* show */
display(ON);
/* disable all plane */
select_plane(SEL_NONE);
}
void display_black0(void)
{
display_bw(0x00,SEL_LEFT);
display_bw(0x00,SEL_RIGHT);
}
void display_white0(void)
{
display_bw(MASKFF,SEL_LEFT);
display_bw(MASKFF,SEL_RIGHT);
}
void display_black(void)
{
display_bw(MASKFF,SEL_LEFT);
display_bw(0x00,SEL_RIGHT);
}
void display_white(void)
{
display_bw(0x00,SEL_LEFT);
display_bw(MASKFF,SEL_RIGHT);
}
void rotate(UBYTE *x,UBYTE *y)
{
UBYTE adat[8] ;
UBYTE mask ;
UBYTE i ;
UBYTE j ;
UBYTE shf ;
UBYTE result ;
/* get */
for ( i = 0 ; i < 8 ; i++ ) { *(adat+i) = *(x+i) ; }
/* rotate */
for ( i = 0 ; i < 8 ; i++ ) {
/* shift counter */
shf = 7 - i ;
/* 80 40 20 10 08 04 02 01 */
mask = (1 << shf) ;
/* result */
result = 0 ;
/* bit operation */
for ( j = 7 ; j > 0 ; j-- ) {
result |= (((*(adat+j) & mask) >> shf) & 1) ;
result <<= 1 ;
}
result |= (((*(adat+0) & mask) >> shf) & 1) ;
/* put */
*(y+i) = result ;
}
}
void rotate_gdat(UBYTE *s,UBYTE *d)
{
UBYTE adat[8] ;
UBYTE bdat[8] ;
UBYTE i ;
UBYTE j ;
UBYTE k ;
UWORD ptr ;
/* destination pointer */
ptr = 0 ;
/* block handling */
for ( i = 0 ; i < 8 ; i++ ) {
for ( j = 0 ; j< 8 ; j++ ) {
/* get */
for ( k = 0 ; k < 8 ; k++ ) {
*(adat+k) = *(s+64*i+j+k*8);
}
/* rotate */
rotate(adat,bdat) ;
/* put */
for ( k = 0 ; k < 8 ; k++ ) {
*(d+ptr+k) = *(bdat+k);
}
/* update pointer */
ptr += 8 ;
}
}
}
/* INT0 interrupt */
ISR(INT0_vect)
{
eflag = ON ;
}
/* INT1 interrupt */
ISR(INT1_vect)
{
eflagx = ON ;
}
void delay_ms(UBYTE x)
{
ULONG last ;
last = timcnt + x ;
while ( timcnt < last ) ;
}
void init_gdat(UBYTE *x,UBYTE y)
{
UBYTE xx ;
UBYTE yy ;
UWORD ptr ;
/* Y direction */
for ( yy = 0 ; yy < XMAX ; yy++ ) {
/* X direction */
for ( xx = 0 ; xx < YMAX ; xx++ ) {
/* calculate pointer */
ptr = 8 * yy + xx ;
/* store */
if ( xx & 1 ) {
*(x+ptr) = y ;
if ( yy & 4 ) { *(x+ptr) = y ^ MASKFF ; }
} else {
*(x+ptr) = y ^ MASKFF ;
if ( yy & 4 ) { *(x+ptr) = y ; }
}
}
}
}
void show_sample(void)
{
UBYTE x;
UBYTE y;
UBYTE buf ;
UWORD ptr ;
/* initialize pointer */
ptr = 0 ;
/* line handling */
for ( y = 0 ; y < YMAX ; y++ ) {
/* select left plane */
select_plane(SEL_LEFT);
set_page(y);
set_address(0) ;
select_plane(SEL_NONE);
/* select right plane */
select_plane(SEL_RIGHT);
set_page(y);
set_address(0) ;
select_plane(SEL_NONE);
/* raster handling */
for ( x = 0 ; x < 128 ; x++ ) {
/* get data from buffer */
buf = *(fbuf+ptr);
/* which plane */
if ( x < 64 ) {
select_plane(SEL_LEFT);
} else {
select_plane(SEL_RIGHT);
}
/* transfer data */
set_display_data(buf) ;
/* disable both plane */
select_plane(SEL_NONE);
/* update pointer */
ptr++;
}
}
}
/* TIMER1 interrupt (1msec) */
ISR(TIMER1_COMPA_vect)
{
timcnt++ ;
}
このファームウエアで液晶に画像を表示すると
以下のようになります。
フレームバッファに、ラスター方向に市松模様を
格納し、液晶の仕様にあわせてから、転送した例
です。
秋月電子のサンプルソースにあった画像データを
転送しました。画像データだけをサンプルソース
から取り出して、表示処理をあわせました。
フレームバッファに画像データを入れずに、片側だけ
白にした場合です。(右だけ白)
左だけ白にした例。
目次
前
次