• 検索結果がありません。

ua1 01 programming 最近の更新履歴 kaimunantai

N/A
N/A
Protected

Academic year: 2018

シェア "ua1 01 programming 最近の更新履歴 kaimunantai"

Copied!
23
0
0

読み込み中.... (全文を見る)

全文

(1)

KAIMU-UA1

(Kaimunantai - Universal circuit board – AVR - no.1)

ソフトウェア開発説明書

※開発環境のインストールなどはua1-00-avr-start.pdfを参照してください。

※プログラム開発環境の操作については、

Mac

ではua1-crosspackavr-xcode.pdfを、

Windows

で はua1-atmelstudio-6.pdfを参照してください。

1

LEDを光らせる

(1) LEDをずーっと光らせる

 

Xcode

やテキストエディタで、次のコードを入力します。

 なお、

//

で始まる文字列は人間向けの注釈ですから、入力しなくてもプログラムは動作

します。

#include <avr/io.h>

int main(void) {

// I/O Port Initialization

DDRD = 0b11111111; // All PORTD ports as Output

while(1){

PORTD |= (1<<PD0); // LED ON }

return 0; }

DDRD

は、入出力ポート

(I/O

ポート)の入力/出力を切り替えるレジスタです。

0b11111111

は2進数です。

AVR-GCC

では、

0b

の後に1、0のビットパターンを書くと、 2進数として扱われます。

PORTD 7 6 5 4 3 2 1 0 に対応 DDRD = 0b 1 1 1 1 1 1 1 1;

DDRD7

1

のとき、

PORTD7 (PD7)

は出力モードに設定されます。

DDRD7

0

のとき、

PORTD7 (PD7)

は入力モードに設定されます。

(2)

(2) コードを読み取りやすくする工夫

 前のコードでは、

LED

を光らせる処理をしていることが今ひとつ伝わりにくかったので、

ちょっと変更してみます。

#include <avr/io.h>

static inline void initIo(void) // I/O ポートの初期化

{

DDRD = 0b11111111; // All PORTD ports as Output }

static inline void ledOn(void) // LED を点灯

{

PORTD |= (1<<PD0); }

int main(void) {

initIo(); // I/O ポートの初期化

while(1){

ledOn(); // LED を点灯 }

return 0; }

 

I/O

ポート初期化の処理や

LED

を点灯するコードをわかりやすい(英語ですが)文字

(3)

 同じように

LED

を消灯する処理をledOff()で表し、一定時間だけ待つ処理をwait(待つ

時間)で表すコードを書いてみます。

#include <avr/io.h>

static inline void initIo(void) {

DDRD = 0b11110011; // All PORTD ports as Output }

static inline void ledOn(void) // LED light ON

{

PORTD |= (1<<PD0); }

static inline void ledOff(void) // LED light OFF

{

PORTD &= ~(1<<PD0); }

static inline void wait(volatile unsigned long i) // wait for a while

{

while (i-->0); }

int main(void) {

// initialize I/O Ports initIo();

while(1){

ledOn(); // LED ON

wait(30000UL); // wait 30000 counts

ledOff(); // LED OFF

wait(10000UL); // wait 10000 counts }

return 0; }

(4)

(3) LEDの点滅

LED

を点滅させるだけならば、出力ポートのビットを反転するだけでよいので、プログラ

ムはもっと簡単になります。

#include <avr/io.h>

static inline void initIo(void) {

DDRD = 0b11110011; // All PORTD ports as Output }

static inline void ledOnOff(void) // LED light ON / OFF

{

PORTD ^= (1<<PD0); }

static inline void wait(volatile unsigned long i) // wait for a while

{

while (i-->0); }

int main(void) {

// initialize I/O Ports initIo();

while(1){

ledOnOff(); // LED ON / OFF

wait(30000UL); // wait 30000 counts }

(5)

2

スイッチを押すとLEDが光る

 以下のコードは、スイッチを押している間だけ

LED

が点灯するものです。

#include <avr/io.h>

static inline void initIo(void) // initialize I/O ports.

{

PORTD = (1<<PD2); // weak pull up resistor enable on PD2 DDRD = 0b11111011; // PD2 as Input, others Output

}

static inline void ledOn(void) // LED light ON

{

PORTD |= (1<<PD0); }

static inline void ledOff(void) // LED light OFF

{

PORTD &= ~(1<<PD0); }

static inline uint8_t isSwitchOn(void) {

return !( PIND & ( 1<<PD2 ) ); }

int main(void) {

// I/O Port Initialization initIo();

while(1){

if ( isSwitchOn() ) { ledOn(); // LED ON } else {

ledOff(); // LED OFF }

}

(6)

(1)  initIo()関数について

  スイッチの

ON/OFF

を判断するには、スイッチを入力ポートに接続する必要があります。

  本機ではスイッチがポート

PD2

に接続されているので、ポート

PD2

を入力モードに設 定します。

  また、スイッチが押されたときに0

V

、押されていないときに電源電圧となるように、

マイコン内の抵抗を有効

(weak pull up)

にします。   その設定方法は以下の通りです。

PORTD = (1<<PD2); //まず PD2 の内蔵抵抗を有効にします。 DDRD = 0b11111011; // PD2 を入力モード(0)に設定します。

(2)  isSwitchOn()関数について

  スイッチが押されているときに

0

以外の値(真、

TRUE

)を返し、そうでないときに

0

(偽、

FALSE

)を返します。

  

C

言語の

if

文では、条件式の値が「

0

でないとき」に「真」となるため、次のように 書くと、スイッチの状態によって処理を切り替えることができます。

if ( isSwitchOn() ) {

スイッチが押されたときの処理 } else {

(7)

3

音を鳴らす

(1)  スイッチが押されたときだけブザーが鳴る

  本機では、ブザーが PB0 に接続されていますから、DDRB レジスタの PD2 に対応するビッ トを1に設定して、出力ポートとします。PORTB の他のポートには何も接続されていないた め、簡単にするために全ポートを出力に設定してしまいます。

 以下のコードを実行してみてください。

#include <avr/io.h>

static inline void initIo(void) // initialize I/O ports.

{

PORTD = (1<<PD2); // weak pull up resistor enable on PD2 DDRD = 0b11111011; // PD2 as Input, others Output

DDRB = 0b11111111; // PORTB All Output }

static inline void buzOn(void) // Buzzer ON / OFF

{

PORTB ^= (1<<PB0); }

static inline uint8_t isSwitchOn(void) {

return !( PIND & ( 1<<PD2 ) ); }

static inline void wait(volatile unsigned long i) // wait for a while

// Arguments :: i : waiting length {

while ( i-- > 0 ); }

int main(void) {

// I/O Port Initialization initIo();

while(1){

if ( isSwitchOn() ) { buzOn();

wait(10); buzOn();

wait(100); }

}

(8)

(2)  スイッチが押されると指定した音の高さ(tone)と長さ(length)で音が鳴る。

 次のコードは、押しボタンスイッチを押すと、1 秒程度、音が鳴ります。

#include <avr/io.h>

static inline void wait(volatile unsigned long i) // wait for a while

// Arguments :: i : waiting length {

while ( i-- > 0 ); }

static inline void initIo(void) // initialize I/O ports.

{

PORTD = (1<<PD2); // weak pull up resistor enable on PD2 DDRD = 0b11111011; // PD2 as Input, others Output

DDRB = 0b11111111; // PORTB All Output }

static inline void buzOn(void) // Buzzer ON / OFF

{

PORTB ^= (1<<PB0); }

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); }

}

static inline uint8_t isSwitchOn(void) {

(9)

int main(void) {

// I/O Port Initialization initIo();

while(1){

if ( isSwitchOn() ) { beepOn(100, 50000UL); }

}

return 0; }

(3)  beepOn()関数について

  次のように音の高さとなっている時間の長さを指定します。

  beepOn(音の高さ, 音を鳴らす時間の長さ);

(10)

4

タイマ0割り込み

 3分間動作して自動的に電源が切れるシステムや1時間後に自動的に起動するシステムを 作る場合、タイマ割り込みという機能を使って動作時間を制御します。

 ここでは、ATmega168P のタイマ0(TIMER0)割り込みを使ったコードの例を紹介します。

(1) 割込みの基本コード ~ 1msごとに割込み発生 ~

 タイマ0(TIMER0)は、一定間隔で数を数えるカウンターです。

 その数が規定値を超えたときに割り込みを発生させることができます。この割り込みを TIMER0割り込みといいます。

 次のコードでは、1msごとに LED が点滅しています。(目で見るとずーっと点灯してい るように見えますが)

#include <avr/io.h>

#include <avr/interrupt.h>

static inline void ledOnOff(void) // LED light ON / OFF

{

PORTD ^= (1<<PD0); }

static inline void initIo(void) // initialize I/O ports.

{

DDRD = 0b11111011; // PD2 as Input, others Output }

static inline void initTimer0(void) // Initialize TIMER0

{

// CTC mode , TOP is OCR0A

TCCR0A = (1 << WGM01) | (0 << WGM00) ;

// I/O clock prescaler N = 8 →クロック周波数(1MHz)の 8 倍の周期(8us)でカウントする。

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 の値 =

割込み間隔 [s] * クロック周波数(f_clkio [Hz]) / クロックプリスケーラ(I/O clock prescaler) N

ここでは、0.001 * 1000000 / 8 = 125  となる。

     TIMER0 が 125 回カウントすると、割込みが発生するため、約 1ms で割込みが発生 することになる。

(11)

/*

* Interrupt */

ISR(TIMER0_COMPA_vect)

// Timer0 Timer counter Compair match Interrupt {

ledOnOff(); // TIMER0 割り込みが発生したら LED を点滅させる。 }

/*

* Main */

int main(void) {

initIo(); initTimer0();

sei(); // 割込み待ち受け処理の開始

while (1) {

}

(12)

(2) 割込みの実用コード ~ 2秒ごとに割込み発生 ~

 先ほどのコードでは、割込みの間隔が早すぎて、人間が使うタイマとしては、実用的では ありませんでした。

 そこで、割込みの発生回数を数えるグローバル変数TIMER0_COUNTERを使うことにします。

 TIMER0_COUNTERは、TIMER0割込みが発生すると1増加します。この変数の値を 0 にした 後、2000 になるまでの時間は、約2000 ms = 2 s となります。

 次のコードは、LED が 2 秒ごとに点滅します。

#include <avr/io.h>

#include <avr/interrupt.h>

static volatile unsigned long TIMER0_COUNTER = 0;

static inline void ledOnOff(void) // LED light ON / OFF

{

PORTD ^= (1<<PD0); }

static inline void initIo(void) // initialize I/O ports.

{

DDRD = 0b11111011; // PD2 as Input, others Output }

static inline void initTimer0(void) // Initialize TIMER0

{

// CTC mode , TOP is OCR0A

TCCR0A = (1 << WGM01) | (0 << WGM00) ;

// I/O clock prescaler N = 8 → クロック周波数(1MHz)の 8 倍の周期(8us)でカウン トする。

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 の値 =

割込み間隔 [s] * クロック周波数(f_clkio [Hz]) / クロックプリスケーラ(I/O clock prescaler) N

ここでは、0.001 * 1000000 / 8 = 125  となる。

     TIMER0 が 125 回カウントすると、割込みが発生するため、約 1ms で割込み が発生することになる。

(13)

/*

* Interrupt */

ISR(TIMER0_COMPA_vect)

// Timer0 Timer counter Compair match Interrupt {

TIMER0_COUNTER++;

if (TIMER0_COUNTER >= 2000) {

ledOnOff(); // TIMER0 割り込みが 2000 回発生したら LED を点滅させる。 TIMER0_COUNTER = 0; // TIMER0 Counter をリセット

} }

/* * Main */

int main(void) {

initIo(); initTimer0();

sei(); // 割込み待ち受け処理の開始

TIMER0_COUNTER = 0; // TIMER0 Counter をリセット

while (1) {

}

(14)

(3) TIMER0割込みの応用コード

 この前のコードでは、割込み処理関数( ISR(TIMER0_COMPA_vect) )で、LED の点滅を

制御していましたが、割込み処理関数の中で、複雑な処理をするのは好ましくありません。 他の割込み処理が追いつかなくなる恐れがあります。

 そこで、割込み処理関数では、割込み回数のカウントをする処理だけをすることにして、 LED の点滅はmain関数で行うように変更したのが、次のコードです。このコードでは、LED が 点滅する間隔を1秒にしてあります。

#include <avr/io.h>

#include <avr/interrupt.h>

static volatile unsigned long TIMER0_COUNTER = 0;

static inline void ledOnOff(void) // LED light ON / OFF

{

PORTD ^= (1<<PD0); }

static inline void initIo(void) // initialize I/O ports.

{

DDRD = 0b11111011; // PD2 as Input, others Output }

static inline void initTimer0(void) // Initialize TIMER0

{

// CTC mode , TOP is OCR0A

TCCR0A = (1 << WGM01) | (0 << WGM00) ;

// I/O clock prescaler N = 8 → クロック周波数(1MHz)の 8 倍の周期(8us)でカウン トする。

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 の値 =

割込み間隔 [s] * クロック周波数(f_clkio [Hz]) / クロックプリスケーラ(I/O clock prescaler) N

ここでは、0.001 * 1000000 / 8 = 125  となる。

     TIMER0 が 125 回カウントすると、割込みが発生するため、約 1ms で割込み が発生することになる。

(15)

/*

* Interrupt */

ISR(TIMER0_COMPA_vect)

// Timer0 Timer counter Compair match Interrupt {

TIMER0_COUNTER++; // TIMER0 割込みが起こったら、TIMER0_COUNTER を増やすだけ }

/* * Main */

int main(void) {

initIo(); initTimer0();

sei(); // 割込み待ち受け処理の開始

TIMER0_COUNTER = 0; // TIMER0 Counter をリセット

while (1) {

if (TIMER0_COUNTER >= 1000) {

ledOnOff(); // TIMER0 割り込みが 1000 回発生したら LED を点滅させる。 TIMER0_COUNTER = 0; // TIMER0 Counter をリセット

} }

(16)

5

INT0割込み

(1) 割込みを使用しない場合

次のプログラムは、押しボタンスイッチを押すと LED を消灯するつもりで作りました。しか

し、実行すると、ボタンを押すタイミングによって LED が消灯しないことがあります。

#include <avr/io.h>

#include <avr/interrupt.h>

enum { STAGE_LED_ON, STAGE_LED_OFF }; // 現在の状態(STAGE)を表す定数 volatile int STAGE = STAGE_LED_ON; // 現在の状態の初期値は STAGE_LED_ON

static inline void wait(volatile unsigned long i) {

while (i-- > 0); }

static inline void ledOn(void) // LED light ON / OFF

{

PORTD |= (1<<PD0); }

static inline void ledOff(void) // LED light ON / OFF

{

PORTD &= ~(1<<PD0); }

static inline int isSwitchOn(void)

// if Switch-ON -> return TRUE, else return False {

return ( !( PIND & (1<<PD2) ) ); }

static inline void initIo(void) // initialize I/O ports.

{

(17)

/* * Main */

int main(void) {

initIo();

while (1) {

switch ( STAGE ) { case STAGE_LED_ON: ledOn();

wait(100000UL); default:

ledOff(); }

if (isSwitchOn()) {

STAGE = STAGE_LED_OFF; ledOff();

} }

(18)

(2) INT0割込みの使用

そこで、INT0割込みを利用して、ボタンを押したらすぐに反応するように改良してみまし た。

#include <avr/io.h>

#include <avr/interrupt.h>

enum { STAGE_LED_ON, STAGE_LED_OFF }; // 現在の状態(STAGE)を表す定数 volatile int STAGE = STAGE_LED_ON; // 現在の状態の初期値は STAGE_LED_ON

static inline void wait(volatile unsigned long i) {

while (i-- > 0); }

static inline void ledOn(void) // LED light ON / OFF

{

PORTD |= (1<<PD0); }

static inline void ledOff(void) // LED light ON / OFF

{

PORTD &= ~(1<<PD0); }

static inline void initIo(void) // initialize I/O ports.

{

PORTD |= (1<<PD2); // PD2 weak pull up enable DDRD = 0b11111011; // PD2 as Input, others Output }

static inline void initInt0(void) // INT0 割込みの設定

{

EICRA |= (1<<ISC01) | (1<<ISC11); // INT0 Falling Edge, INT1 Falling edge EIMSK |= (1<<INT0) | (1<<INT1); // Enable Interrupt 0, 1

}

static inline int isSwitchOn(void)

// if Switch-ON -> return TRUE, else return False {

(19)

/*

* Interrupt */

ISR(INT0_vect)

// INT0 割込みが発生したとき(押しボタンスイッチを押したとき)の処理 {

switch (STAGE) { case STAGE_LED_ON: ledOff();

STAGE = STAGE_LED_OFF; break;

default:

STAGE = STAGE_LED_ON; }

}

/* * Main */

int main(void) {

initIo();

initInt0(); // INT0 割込みの設定 sei(); // 割込み待ち受け開始

while (1) {

switch ( STAGE ) { case STAGE_LED_ON: ledOn();

wait(100000UL); break;

default: ledOff(); }

}

(20)

6

デモンストレーション

 次のような動作をするタイマのプログラムです。

 LED が点滅→スイッチを押すと→LED が点灯→10 秒たつと→LED が点滅、ブザーが鳴る→

スイッチを押すと→最初に戻る

#include <avr/io.h>

#include <avr/interrupt.h>

static inline void wait(volatile unsigned long i) // wait for a while

// Arguments :: i : waiting length {

while ( i-- > 0 ); }

static inline void buzOn(void) // Buzzer ON / OFF

{

PORTB ^= (1<<PB0); }

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); }

}

static inline void ledOn(void) // LED light ON

{

PORTD |= (1<<PD0); }

static inline void ledOff(void) // LED light OFF

{

(21)

{

PORTD ^= (1<<PD0); }

static inline uint8_t isSwitchOn(void) {

return !( PIND & ( 1<<PD2 ) ); }

enum {

STAGE_READY, STAGE_LED, STAGE_ALARM };

static uint8_t STAGE = STAGE_READY;

/*

* initialize */

static inline void initIo(void) // initialize I/O ports.

{

PORTD = (1<<PD2); // weak pull up resistor enable on PD2 DDRD = 0b11111011; // PD2 as Input, others Output

DDRB = 0b11111111; // PORTB All Output }

static inline void initInt0(void) {

EICRA |= (1<<ISC01) | (1<<ISC11); // INT0 Falling Edge, INT1 Falling edge EIMSK |= (1<<INT0) | (1<<INT1); // Enable Interrupt 0, 1

}

static inline void initTimer0(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

}

(22)

* Interrupt */

volatile unsigned int TIMER0_COUNTER; // Timer0 interrupt counter

// #define TIMER0_10SEC 10000 // #define TIMER0_1SEC 1000 // #define TIMER0_500MSEC 500 #define TIMER0_LIMIT 10000

ISR(TIMER0_COMPA_vect)

// Timer0 Timer counter Compair match Interrupt {

TIMER0_COUNTER++; }

ISR(INT0_vect) // INT0 Interrupt {

beepOn(2,500); switch ( STAGE ) { case STAGE_READY : STAGE = STAGE_LED; TIMER0_COUNTER = 0; break;

case STAGE_LED :

STAGE = STAGE_READY; break;

case STAGE_ALARM : STAGE = STAGE_READY; }

while( isSwitchOn() ); }

/* * main */

int main(void) {

initIo(); initInt0(); initTimer0();

beepOn( 2 , 1000 ); ledOff();

(23)

while (1) {

switch ( STAGE) { case STAGE_READY: ledOnOff(); wait(10000); break; case STAGE_LED : ledOn();

if (TIMER0_COUNTER > TIMER0_LIMIT) { STAGE = STAGE_ALARM;

} break;

case STAGE_ALARM : beepOn( 2 , 1000 ); ledOnOff();

wait(3000); break; default: ledOff(); }

}

参照

関連したドキュメント

日臨技認定センターの認定は 5 年毎に登録更新が必要で、更新手続きは有効期間の最終

最近一年間の幹の半径の生長ヰま、枝葉の生長量

タッチON/OFF判定 CinX Data Registerの更新 Result Data 1/2 Registerの更新 Error Status Registerの更新 Error Status Channel 1/2 Registerの更新 (X=0,1,…,15).

進捗。3月末には45箇所程度になる見込み 2022年3月 完了 雑可燃物の焼却

8月 9月 10月 11月 12月 1月 2月 3月..

エリアP 雑固体廃棄物 焼却設備 処理設備     瓦礫保管エリア     伐採木保管エリア

廃棄物の処理及び清掃に関する法律の改正に伴い、令和元年 12 月 14 日から「成年被後見人又は被

固体廃棄物GMが認めた保管形態であること。 1回/3カ月 1回/週 1回/週 2021年9月27日. 「仮設集積場所設置表示」があること。 1回/3カ月