KAIMU-UA1 Ext. 01 I2C-LCD

ユニバーサル基板工作練習回路 機能拡張1 I2C接続液晶ディスプレイ編

( Kaimunantai–UA1 Extension no. 1 I2C Liquid Crystal Display )

概要

AVRマイコンを使った電子回路の製作練習キットKAIMU-UA1の機能拡張第1弾。

I2C接続の液晶ディスプレイを接続したもの。

使用部品

I2C接続薄型16文字×2行液晶 変換基板キット AQM1602XA-RN-GBW Sitronix ST7032 controled

ピンソケット 4ピン

カーボン抵抗器 10kΩ × 2個、1/4 W

配線材 Φ0.32mm

回路図

KAIMU-UA1-Ext.01 schematics

実体配線図

KAIMU-UA1-Ext.01 circuit board

デモ用ファームウェア

(機能)押しボタンスイッチを押すと、10秒カウントダウンして、アラームが鳴る。

LCDの制御用に、下記のコードを使用させていただいた。

(1) I2Cインタフェースライブラリ

ヘッダファイル i2cmaster.h

ソースコード twimaster.c

i2c-master interface for avrgcc ((C) 2015 Peter Fleury, GNU General Public License Version 3)

http://homepage.hispeed.ch/peterfleury/avr-software.html#libs

(2) 液晶ディスプレイの制御コード

ヘッダファイル i2c_lcd.h

ソースコード i2c_lcd.c

over80氏の下記URLに掲載されたコードを参考に、関数の書式を統一し、さらにKeinSoftで作成した拡張関数を追加したもの

http://d.hatena.ne.jp/over80/20141013/1413174967

ソースコード(AVR-GCC用)

//
//  kaimu-ua1-i2clcd-mega168.c
//
//  Created by kaimunantai on 2015/12/31.
/*
 * Target : ATmega168P / 328P
 * OUTPUT :
 *  LED     :   PD0 (PIN 2)
 *  Buzzer  :   PB0 (PIN14)
 *  LCD (AQM1602XA-RN-GBW) : I2C (TWI) SCL(PIN27) , SDA (PIN28)
 * INPUT :
 *  tact switch sw0 : PD2 / INT0 (PIN 4)
 *
 */
// #define F_CPU 1000000UL // define in makefile
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <util/twi.h>
#include <string.h>
#include "i2cmaster.h"
#include "i2c_lcd.h"
/*
 * i2c-master interface for avrgcc ((C) 2015 Peter Fleury, GNU General Public License Version 3)
 *http://homepage.hispeed.ch/peterfleury/avr-software.html#libs
 *
 */
/*
 * I/O Control MACROs
 */
#define led()       ( PORTD ^= (1<<PD0) )
#define ledOn()     ( PORTD |= (1<<PD0) )
#define ledOff()    ( PORTD &= ~(1<<PD0) )
#define isSw0On()     ( !( PIND & (1<<PD2) ) )
#define isSw0Off()    ( PIND & (1<<PD2) )
#define buzOn()   ( PORTB ^= (1<<PB0) )
/*
 * stage definition
 */
enum {
    STAGE_START,
    STAGE_READY,
    STAGE_COUNTDOWN,
    STAGE_ALARM,
    STAGE_END
};
static volatile uint8_t STAGE = STAGE_START;
static inline void wait(volatile unsigned long i)
{
    while (i-- > 0);
}
inline void beepOn(unsigned int tone, unsigned long length)
// beep by Buzzer
// Arguments :
//     tone :  tone height ,  tone 2 (high)  ~  1000 (low)
//     length :  beep sound time
{
    length /= tone;
    
    while (length-- > 0) {
        buzOn();
        wait(tone);
    }
}
/*
 *  initialize
 */
static inline void io_init(void)
{
    PORTD = (1<<PD2); // weak pull up resistor enagle on PD2
    DDRD = 0b11111011; // PD2 as Input, others Output
    DDRB = 0b11111111; // PORTB All Output
}
static inline void int0_init(void)
{
    EICRA |= (1<<ISC01) | (1<<ISC11); // INT0 Falling Edge, INT1 Falling edge
    EIMSK |= (1<<INT0) | (1<<INT1); // Enable Interrupt 0, 1
}
static inline void timer0_init(void)
// Initialize TIMER0
{
    // CTC mode , TOP is OCR0A
    TCCR0A = (1 << WGM01) | (0 << WGM00) ;
    // I/O clock prescaler N = 8
    TCCR0B = (0 << WGM02) | (0 << CS02) | (1 << CS01) | (0 << CS00);
    // Timer0 on OCR0A compare match interrupt enable
    TIMSK0 |= ( 1<< OCIE0A );
    // set TOP value . Interrupt every 1 ms
    OCR0A = 125; // OCR0A = interrupt period [s] * f_clkio [Hz] / I/O clock prescaler N
}
/*
 *  Interrupt
 */
volatile unsigned int T0count; // Timer0 interrupt counter
#define TIMER0_LIMIT    65535
#define TIMER0_10SEC    10000
#define TIMER0_1SEC     1000
#define TIMER0_500MSEC   500
ISR(TIMER0_COMPA_vect)
// Timer0 Timer counter Compair match Interrupt
{
    if ( T0count > TIMER0_LIMIT ) {
        T0count = 0;
    } else {
        T0count++;
    }
    
}
ISR(INT0_vect)
// INT0 Interrupt
{
    switch ( STAGE ) {
        case STAGE_START :
            STAGE = STAGE_READY;
            break;
        case  STAGE_READY :
            STAGE = STAGE_COUNTDOWN;
            break;
        case STAGE_COUNTDOWN :
            STAGE = STAGE_END;
            break;
        case STAGE_ALARM :
            STAGE = STAGE_START;
            break;
        default :
            STAGE = STAGE_START;
            
    }
    beepOn(10, 5000);
    while(isSw0On());
}
inline void putMinSec(int minutes, int seconds)
{
    i2c_lcd_putNumberRC(2, 10, (unsigned)minutes, 2);
    i2c_lcd_putStringRC(2, 12, ":");
    i2c_lcd_putNumberRC(2, 13, (unsigned)seconds, 2);
}
/*
 *  main
 */
int main(void)
{
    int minutes = 0, seconds = 0; // minutes , seconds for timer
    
    io_init();
    int0_init();
    timer0_init();
    
    i2c_lcd_init();
    
    ledOn();
    while(isSw0On()); // wait until switch released
    
    ledOff();
    
    sei(); // Enable Interrupt
    
    i2c_lcd_setContrast(20);
    i2c_lcd_clearDisplay();
    
    while (1) {
        switch ( STAGE ) {
            case STAGE_START :
                i2c_lcd_putStringRC(1, 1, " LCD-TIMER168   ");
                i2c_lcd_putStringRC(2, 1, "   by KeinSoft  ");
                break;
            case STAGE_READY :
                i2c_lcd_putStringRC(2, 1, "**START*        ");
                seconds = 10;
                STAGE = STAGE_COUNTDOWN;
                T0count = 0;
                putMinSec(minutes, seconds);
                break;
            case STAGE_COUNTDOWN :
                if (T0count >= TIMER0_1SEC) {
                    led();
                    seconds--;
                    
                    if (minutes <= 0 && seconds <= 0) {
                        STAGE = STAGE_ALARM;
                        ledOff();
                        i2c_lcd_putStringRC(2, 1, "!!! ALARM !!!!   ");
                    } else {
                        
                        if ( seconds <= 0) {
                            seconds = 59;
                            minutes--;
                        }
                        putMinSec(minutes, seconds);
                    }
                    T0count = 0;
                }
                break;
            case STAGE_ALARM :
                led();
                beepOn(5,10000);
                wait(5000);
                break;
            case STAGE_END :
                i2c_lcd_putStringRC(1, 1, " KeinSoft 2015  ");
                i2c_lcd_putStringRC(2, 1, "      BYE-BYE   ");
                break;
            default :
                ledOff();
        }
    }
    
    return 0;
}

Makefile

# AVR-GCC Makefile
 PROJECT=kaimu-ua1-i2clcd-mega168
 SOURCES=$(PROJECT).c twimaster.c i2c_lcd.c
 CC=avr-gcc
 OBJCOPY=avr-objcopy
 F_CPU=1000000
 
 MMCU=atmega168
 TARGETDEV=m168p
 #MMCU=atmega328p
 #TARGETDEV=atmega328p
 
 CFLAGS=-g -O2 -mmcu=$(MMCU) -Wall -DF_CPU=$(F_CPU)
 
 $(PROJECT).hex: $(PROJECT).out

$(OBJCOPY) -j .text -j .data -O ihex $(PROJECT).out $(PROJECT).hex

 
 $(PROJECT).out: $(SOURCES)

$(CC) $(CFLAGS) -I./ -o $(PROJECT).out $(SOURCES)

 
 program: $(PROJECT).hex

sudo avrdude -p $(TARGETDEV) -P usb -c avrispmkII -e -U flash:w:$(PROJECT).hex

 clean:

rm -f $(PROJECT).out

rm -f $(PROJECT).hex