AtmelStudioでu8glibを使用した開発環境を作る

#はじめに
ArduinoにてOLED, LCDなどのグラフィックデバイスを使用する場合はu8glibを使用しています。

[AtmelStudioとUSBtinyISPでAVR(AtMega, ATtiny)の開発環境を作る](https://qiita.com/tlab/items/eded982637a786486829)
にてAtmelSudioでの開発環境をととのえましたので、こちらの環境でもu8glibを使用できるようにしました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/003b0461-e288-2954-9279-bb4acc5b7eb8.png)
AtmelStudioでの開発

#用意するもの
##AtmelStudio
AtmelStudioの開発環境はこちらを参照してください。
[AtmelStudioとUSBtinyISPでAVR(AtMega, ATtiny)の開発環境を作る](https://qiita.com/tlab/items/eded982637a786486829)

##u8glib
[u8glib for avrのソース](https://github.com/mirpm/u8glib-avr)をダウンロードして適当な場所に展開しておきます。

#u8glibをコンパイルする
運用はソースをプロジェクトにリンクする方法で行うつもりですので、コンパイルはソースエラーがないかチェックするために行います。

C Static Library Projectを作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/f9c9a9fd-1238-3264-3c8e-f78a92bf3430.png)

Solution Exprolerで右クリックしAdd->Existing Item...を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/eac4853b-e77a-1b40-46a4-707b36b3b431.png)

ソースを選択します
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/c8a1dad3-78fa-9cd5-40ec-dc2297e34499.png)
リンクで追加ではなく、Addで追加します。(ファイルがプロジェクトにコピーされます)

AVR/GNU C Compiler -> Symbolsに

```
F_CPU=16000000UL
```

を追加
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/d76da834-e31f-e767-eb2a-de0eacf6b19d.png)

CPUの動作周波数にあわせて適宜修正してください。

ビルドします。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/4eb6e41f-a1ff-6d4a-aa4b-9caf7924687a.png)

```
u8g_dev_t u8g_dev_rot = { u8g_dev_rot_dummy_fn, NULL, NULL };
```

でWarningが出ますが無視してOKです。

#u8glibを使用したプロジェクトの作成

GCC C++ Executable Projectで作成します。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/2aaa54b1-1ef7-896f-73f7-e4c03703dc9f.png)

Solution Exprolerで右クリックしAdd->Existing Item...を選択
![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/eac4853b-e77a-1b40-46a4-707b36b3b431.png)
先程コンパイルしたソースを追加します。

Arduino Unoからソースを移植します。

```CPP: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);
}
```

```CPP:AtmelStudioのソース

#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とは呼出方法が変更となりますが、単純に置き換えていけば良いのでそれほど手間ではありません。

#書き込み
ビルドが通ったら書き込むだけです。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/46206691-b3bb-e0be-58b2-f9f72443b156.png)
Arduinoでの開発

![image.png](https://qiita-image-store.s3.amazonaws.com/0/211703/003b0461-e288-2954-9279-bb4acc5b7eb8.png)
AtmelStudioでの開発

同じ表示となりました。

#終りに。
グラフィックもAtmelStudioで開発したくなり試してみました。Arduinoと異り、AtmelStudioではPULL-UPの設定にするにも仕様書を観る必要がありました。Arduinoでは色々と隠蔽されており御気軽ではありますが、動作が不安定になった場合何が問題なのかが追求しにくくなります。
一方AtmelStudioではコンフィグレジスタ等まで気を使ってソースを記載することになるため、本質の勉強になります。

あとIntentが気持ちわるく無いし、Intellisenseはあるしで最高ですね。

2018-10-14 Ikeda