はじめに
ArduinoにてOLED, LCDなどのグラフィックデバイスを使用する場合はu8glibを使用しています。
AtmelStudioとUSBtinyISPでAVR(AtMega, ATtiny)の開発環境を作る
にてAtmelSudioでの開発環境をととのえましたので、こちらの環境でもu8glibを使用できるようにしました。
用意するもの
AtmelStudio
AtmelStudioの開発環境はこちらを参照してください。
AtmelStudioとUSBtinyISPでAVR(AtMega, ATtiny)の開発環境を作る
u8glib
u8glib for avrのソースをダウンロードして適当な場所に展開しておきます。
u8glibをコンパイルする
運用はソースをプロジェクトにリンクする方法で行うつもりですので、コンパイルはソースエラーがないかチェックするために行います。
C Static Library Projectを作成します。
Solution Exprolerで右クリックしAdd->Existing Item...を選択
ソースを選択します
リンクで追加ではなく、Addで追加します。(ファイルがプロジェクトにコピーされます)
AVR/GNU C Compiler -> Symbolsに
F_CPU=16000000UL
CPUの動作周波数にあわせて適宜修正してください。
u8g_dev_t u8g_dev_rot = { u8g_dev_rot_dummy_fn, NULL, NULL };
でWarningが出ますが無視してOKです。
u8glibを使用したプロジェクトの作成
GCC C++ Executable Projectで作成します。
Solution Exprolerで右クリックしAdd->Existing Item...を選択
先程コンパイルしたソースを追加します。
Arduino Unoからソースを移植します。
///////////////////////////////////////////////////////////
// OLEDテスト
//
// 2018/10/13 First, Based on OFFICE_CLOCK_R2
//
////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// 1. ArduinoでOLED表示をする
// 2. プロジェクトをAtmelStudioに移植
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
// OLED with u8glib
//
// 1 VCC
// 2 GND
// 3 SCL -- Pin A5 -OLD common use
// 4 SDA -- Pin A4 -OLD common use
///////////////////////////////////////////////////////////////////////
# include "U8glib.h" // OLED disp library
U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
void setup() {
pinMode(0, INPUT_PULLUP); // BTN1
pinMode(1, INPUT_PULLUP); // BTN2
pinMode(2, INPUT_PULLUP); // BTN3
pinMode(3, INPUT_PULLUP); // BTN4
// flip screen, if required
// u8g.setRot180();
u8g.setContrast(0); // 液晶のコントラスト設定 0:暗い, 255:明るい(あんまり変らない)
// set SPI backup if required
//u8g.setHardwareBackup(u8g_backup_avr_spi);
// assign default color value
if ( u8g.getMode() == U8G_MODE_R3G3B2 ) {
u8g.setColorIndex(255); // white
}
else if ( u8g.getMode() == U8G_MODE_GRAY2BIT ) {
u8g.setColorIndex(3); // max intensity
}
else if ( u8g.getMode() == U8G_MODE_BW ) {
u8g.setColorIndex(1); // pixel on
}
else if ( u8g.getMode() == U8G_MODE_HICOLOR ) {
u8g.setHiColorByRGB(255, 255, 255);
}
// Font set
u8g.setFont(u8g_font_10x20);
}
void loop()
{
long i = 0;
if (1) // Setting
{
i = (analogRead(A0) / 10) * 5;
DispSetting(0, i );
}
else // ON Camera
{
}
delay( 50 );
}
////////////////////////////////////////////////////////
// 設定画面
void DispSetting(byte modeSts, int setting)
{
u8g.firstPage();
do {
drawStartupTime();
drawTextMsg();
drawMaruShikauSankaku();
} while ( u8g.nextPage() );
}
////////////////////////////////////////////////////////
// 撮影中画面
void DispOnCamera()
{
u8g.firstPage();
do {
} while ( u8g.nextPage() );
}
/////////////////////////////////////////////////////////////////////////////////////////////
// 設定画面SubFunc
////////////////////////////////////////////////////////////////////////////////////////////
char textbuffer[20];
/////////////////////////////////////////////////////////
// Time from Start up
void drawStartupTime()
{
GetTimeText(textbuffer, millis()/1000, 0 ); // hour無し
u8g.drawStr(5, 30 , textbuffer);
}
/////////////////////////////////////////////////////////
// DispMessage
void drawTextMsg()
{
u8g.drawStr(5, 62 , "**G8LIB**");
}
/////////////////////////////////////////////////////////
// 図形描画
void drawMaruShikauSankaku()
{
u8g.drawCircle(72, 24, 5);
u8g.drawCircle(85, 24, 5);
u8g.drawCircle(98, 24, 5);
}
/////////////////////////////////////////////////////////
// 時間フォーマットを返す
void GetTimeText(char* text, int time_sec, int format)
{
if ( format == 1 && (time_sec / 3600 != 0))
sprintf(text, "%01d:%02d", time_sec / 3600, (time_sec % 3600)/60 );
else
sprintf(text, "%02d:%02d", time_sec / 60, time_sec % 60 );
}
}
/////////////////////////////////////////////////////////
// 描画範囲のフレームを描く debug用途
void drawFlameBox()
{
u8g.drawFrame( 0, 1, 127, 63);
}
# ifndef F_CPU
# define F_CPU 16000000UL // 16MHz
# endif
# include <avr/io.h>
# include <util/delay.h>
# include <stdio.h>
# include "Timer.h"
///////////////////////////////////////////////////////////////////////
// OLED with u8glib
//
// 1 VCC
// 2 GND
// 3 SCL -- Pin A5 -OLD common use
// 4 SDA -- Pin A4 -OLD common use
///////////////////////////////////////////////////////////////////////
# include "..\..\u8glib/u8glib/u8g.h" // OLED disp library
//U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_DEV_0 | U8G_I2C_OPT_NO_ACK | U8G_I2C_OPT_FAST); // Fast I2C / TWI
u8g_t u8g;
Timer timer;
void DispSetting(unsigned char modeSts, int setting);
void DispOnCamera();
void drawStartupTime();
void drawTextMsg();
void drawMaruShikauSankaku();
void GetTimeText(char* text, int time_sec, int format);
void setup(void)
{
DDRB |= (1<<PB0); // PB0 (PIN8 in Arduino UNO) as outputs (LED)
DDRD = 0x00; // PORTD (Pin 2-5) Input
PORTD = 0x0F; // PORTD 0-3 PULL-UP
timer.StartTimer(); // 起動時からの時間
u8g_InitI2C( &u8g, &u8g_dev_ssd1306_128x64_2x_i2c, U8G_I2C_OPT_NONE );
// flip screen, if required
// u8g_SetRot180(&u8g)
u8g_SetContrast(&u8g, 0); // 液晶のコントラスト設定 0:暗い, 255:明るい(あんまり変らない)
// set SPI backup if required
// u8g_SetHardwareBackup(&u8g, u8g_backup_avr_spi);
// assign default color value
if ( u8g_GetMode(&u8g) == U8G_MODE_R3G3B2 ) {
u8g_SetColorIndex(&u8g, 255); // white
}
else if ( u8g_GetMode(&u8g) == U8G_MODE_GRAY2BIT ) {
u8g_SetColorIndex(&u8g,3); // max intensity
}
else if ( u8g_GetMode(&u8g) == U8G_MODE_BW ) {
u8g_SetColorIndex(&u8g,1); // pixel on
}
else if ( u8g_GetMode(&u8g) == U8G_MODE_HICOLOR ) {
u8g_SetHiColorByRGB(&u8g, 255, 255, 255);
}
// Font set
u8g_SetFont(&u8g,u8g_font_10x20);
}
int main(void)
{
// setup
setup();
/* Replace with your application code */
while (1)
{
DispSetting(0, 0 );
_delay_ms(50);
}
}
////////////////////////////////////////////////////////
// 設定画面
void DispSetting(unsigned char modeSts, int setting)
{
u8g_FirstPage(&u8g);
do {
drawStartupTime();
drawTextMsg();
drawMaruShikauSankaku();
} while ( u8g_NextPage(&u8g) );
}
////////////////////////////////////////////////////////
// 撮影中画面
void DispOnCamera()
{
u8g_FirstPage(&u8g);
do {
} while ( u8g_NextPage(&u8g) );
}
/////////////////////////////////////////////////////////////////////////////////////////////
// 設定画面SubFunc
////////////////////////////////////////////////////////////////////////////////////////////
char textbuffer[20];
/////////////////////////////////////////////////////////
// Time from Start up
void drawStartupTime()
{
GetTimeText(textbuffer, timer.GetTime()/ 1000, 0 ); // hour無し
u8g_DrawStr(&u8g, 5, 30 , textbuffer);
}
/////////////////////////////////////////////////////////
// DispMessage
void drawTextMsg()
{
u8g_DrawStr(&u8g, 5, 62 , "**G8LIB**");
}
/////////////////////////////////////////////////////////
// 図形描画
void drawMaruShikauSankaku()
{
u8g_draw_circle(&u8g, 72, 24, 5, U8G_DRAW_ALL);
u8g_draw_circle(&u8g, 85, 24, 5, U8G_DRAW_ALL);
u8g_draw_circle(&u8g, 98, 24, 5, U8G_DRAW_ALL);
}
/////////////////////////////////////////////////////////
// 時間フォーマットを返す
void GetTimeText(char* text, int time_sec, int format)
{
if ( format == 1 && (time_sec / 3600 != 0))
sprintf(text, "%01d:%02d", time_sec / 3600, (time_sec % 3600)/60 );
else
sprintf(text, "%02d:%02d", time_sec / 60, time_sec % 60 );
}
AVRのライブラリはCのコードですので、Arduinoとは呼出方法が変更となりますが、単純に置き換えていけば良いのでそれほど手間ではありません。
書き込み
ビルドが通ったら書き込むだけです。
同じ表示となりました。
終りに。
グラフィックもAtmelStudioで開発したくなり試してみました。Arduinoと異り、AtmelStudioではPULL-UPの設定にするにも仕様書を観る必要がありました。Arduinoでは色々と隠蔽されており御気軽ではありますが、動作が不安定になった場合何が問題なのかが追求しにくくなります。
一方AtmelStudioではコンフィグレジスタ等まで気を使ってソースを記載することになるため、本質の勉強になります。
あとIntentが気持ちわるく無いし、Intellisenseはあるしで最高ですね。
2018-10-14 Ikeda