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
回路図
実体配線図
デモ用ファームウェア
(機能)押しボタンスイッチを押すと、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