「AVR活用ブック」のサンプルプログラムで「LCDがうまく表示できない」というご指摘を頂いたので、対策してみました。
▲ストップウォッチ(3章-1)を実行させて、うまく表示できない場合の例です。LCDに対して信号がうまく出てないようです。
▲原因は、最適化オプションを「-O0」以外に設定してるからです(信号が早く出すぎる)。今のところだと、スイッチを「-O0」にすると大丈夫みたいです。
▲問題はlcd_waitにあります。
ループ回数で時間を作ってます。できるだけシンプルに載せたいので、あえてローテクに作ってたのですが、動作の安定性がよくありません。
なので、タイマ2を使って、時間を待つように改造してみました。
こうすると、どんな最適化をしてもちゃんと表示されます。
//----------------------------------------------------------- // LCD出力関数 lcd.c //最適化オプションを入れても動くように対応しました。 //----------------------------------------------------------- #include <avr/io.h> #include "lcd.h" #define LCD_PORT PORTD // ポート #define LCD_PORTO DDRD // ポート入出力設定 #define LCD_E (1 << 3) // ENABLE #define LCD_RS (1 << 2) // REGISTER SELECT #define LCD_D4 4 // Data Bus D4 #define LCD_DATMASK 0xf // Data Bus用マスク(4ビット送信) void lcd_put_4bit(char bitdata); void lcd_wait( long m ); //----------------------------------------------------------- // ウエイト // 引数 m: 単位msec // timer2を使ってます。注意 //----------------------------------------------------------- void lcd_wait( long m ) { #define F_CPU 8000000 // CPUクロック周波数 [Hz] #define PRESCALE 1024 // プリスケーラ値 #define PRESCALER 7 // プリスケーラレジスタ値 long cntmax; cntmax = (F_CPU/PRESCALE)* m/1000; TCCR2A = 0; // タイマ モード TCCR2B = PRESCALER; // タイマ プリスケーラ設定 TCNT2 = 0x100- cntmax; TIFR2 |= (1<<TOV2); while((TIFR2 & (1<<TOV2))==0); } //----------------------------------------------------------- // LCD初期化 //----------------------------------------------------------- void lcd_init(void) { lcd_wait(30); LCD_PORTO = LCD_E | LCD_RS | (LCD_DATMASK<<LCD_D4); LCD_PORT &= ~LCD_RS; // RS = L lcd_put_4bit( 0x3 ); // Function Set Mode lcd_wait(4); lcd_put_4bit( 0x3 ); lcd_wait(1); lcd_put_4bit( 0x3 ); lcd_put_4bit( 0x2 ); // Function Set Mode=4bit lcd_put_ch( 0x28 ); // Mode=4bit / Line=2 / Font=5x7dot lcd_put_ch( 0x0E ); // Display=ON / Cursor=ON / Blink=ON lcd_put_ch( 0x06 ); // Cursor=Increment / Display_shift=OFF lcd_put_ch( 0x01 ); // Display Clear lcd_wait(2); LCD_PORT |= LCD_RS; // RS = H } //----------------------------------------------------------- // LCD表示位置の設定 // 引数:char tx :x座標 // 引数:char ty :y座標 //----------------------------------------------------------- void lcd_position(char tx ,char ty) { LCD_PORT &= ~LCD_RS; // RS = L lcd_put_ch(0x80 | tx | (0x40 * ty)); // Address = 0 LCD_PORT |= LCD_RS; // RS = H } //----------------------------------------------------------- // LCD 4ビット送信 // 引数: char bitdata : DB7-4に与えるデータ //----------------------------------------------------------- void lcd_put_4bit(char bitdata) { LCD_PORT &= ~(LCD_DATMASK << LCD_D4); LCD_PORT |= (LCD_DATMASK & bitdata)<<LCD_D4; //データを格納 lcd_wait(1); LCD_PORT ^= LCD_E; // ENABLE = L lcd_wait(1); LCD_PORT ^= LCD_E; // ENABLE = H } //----------------------------------------------------------- // LCD 1バイト送信 // 引数: char ch : LCDモジュールへの送信データ //----------------------------------------------------------- int lcd_put_ch(char ch) { lcd_put_4bit(ch >> 4); // 上位4ビット送信 lcd_put_4bit(LCD_DATMASK & ch); // 下位4ビット送信 lcd_wait(1); return(0); }
「Hello world」2-1
http://nicotak.com/avr/prog2_1.lzh
「ストップウォッチ」3-1
http://nicotak.com/avr/prog3_1.lzh