これまでに作ったプログラムをひとつにまとめる。リセット信号はATmega328Pと共用することにした。
#include "TD4_external.h" /* ニモニック(のようなもの)一覧: MOV_A(Im) : AレジスタにImを転送 MOV_B(Im) : BレジスタにImを転送 MOV_AB : AレジスタにBレジスタを転送 MOV_BA : BレジスタにAレジスタを転送 ADD_A(Im) : AレジスタにImを加算 ADD_B(Im) : BレジスタにImを加算 IN_A : 入力ポートからAレジスタへ転送 IN_B : 入力ポートからBレジスタへ転送 OUT(Im) : 出力ポートへImを転送 OUT_B : 出力ポートへBレジスタを転送 JMP(Im) : Im番地へジャンプ JNC(Im) : Cフラグが1ではないときにIm番地へジャンプ */ int main(){ // アセンブル(のようなこと)をしてROM (と見なした排列)へ格納する。 _[0] = OUT_B; _[1] = ADD_B(1); _[2] = JMP(0); // アドレスの変化に応じて排列からデータが出力できるようにする。 enable_rom(); // PD2のスイッチ入力に応じてPD5から手動クロックが出力できるようにする。 enable_manual_clock(); //PD7から10Hzを、PD6から1Hzを出力する。 enable_1Hz_10Hz_clock(); // PD2の入力をディバウンスしてPD5から出力する(押してH出力、放してL出力)。 while(1) debounce_PD2_to_PD5(); return 0; }
#ifndef TD4_EXTERNAL_H_ #define TD4_EXTERNAL_H_ #define F_CPU 8000000UL #include <avr/io.h> #include <avr/interrupt.h> #include <util/delay.h> #define MOV_A(Im) ( 3 << 4 | ((Im) & 0xF)) // AレジスタにImを転送 #define MOV_B(Im) ( 7 << 4 | ((Im) & 0xF)) // BレジスタにImを転送 #define MOV_AB ( 1 << 4) // AレジスタにBレジスタを転送 #define MOV_BA ( 4 << 4) // BレジスタにAレジスタを転送 #define ADD_A(Im) ( 0 << 4 | ((Im) & 0xF)) // AレジスタにImを加算 #define ADD_B(Im) ( 5 << 4 | ((Im) & 0xF)) // BレジスタにImを加算 #define IN_A ( 2 << 4) // 入力ポートからAレジスタへ転送 #define IN_B ( 6 << 4) // 入力ポートからBレジスタへ転送 #define OUT(Im) (11 << 4 | ((Im) & 0xF)) // 出力ポートへImを転送 #define OUT_B ( 9 << 4) // 出力ポートへBレジスタを転送 #define JMP(Im) (15 << 4 | ((Im) & 0xF)) // Im番地へジャンプ #define JNC(Im) (14 << 4 | ((Im) & 0xF)) // Cフラグが1ではないときにIm番地へジャンプ volatile uint8_t _[16]; // 命令を格納しておく排列。 volatile uint8_t switch_changed = 0; volatile int8_t counter = 10; ISR(INT0_vect){ // 手動クロック用のタクトスイッチが押されるか放されるかしたら、 switch_changed = 1; // そのフラグを立てる } ISR(PCINT1_vect){ // アドレスが変化したら、 PORTB = _[PINC & 0x0F]; // そのアドレスに応じたデータを出力する。 } ISR(TIMER1_COMPA_vect){ PORTD ^= (1 << PD7); // 20Hzの頻度でPD7出力をトグルする。結局10Hzの方形波が出力される。 if(--counter <= 0){ // その方形波を10分周してPD6から出力する。結局1Hzの方形波が出力される。 PORTD ^= (1 << PD6); counter = 10; } } /* void enable_reset(){ DDRD |= (1 << PD3); // PD3から!リセット信号を出力することにする。 PORTD &= ~(1 << PD3); // 最初に!リセット信号をLにしておいて、 _delay_ms(100 - 65); // 適当にリセット時間を設けて、(65msはATmega328P自体のリセットからの遅延時間) PORTD |= (1 << PD3); // リセット期間が明けたら!リセット信号をHに戻す。 } */ void enable_manual_clock(){ DDRD |= (1 << PD5); // PD5から手動クロックを出力することにする。 PORTD &= ~(1 << PD5); // 最初はLを出力しておく。 DDRD &= ~(1 << PD2); // PD2をスイッチ入力にする。 PORTD |= (1 << PD2); // PD2を内部プルアップする。 EICRA |= (1 << ISC00); // INT0 (PD2)が変化したときに割り込み要求を出すことにする。 EIMSK |= (1 << INT0); // 外部割り込みINT0を有効にする。 sei(); } void debounce_PD2_to_PD5(){ if(switch_changed){ // PD2に接続したスイッチが変化したら、 switch_changed = 0; _delay_ms(5); // バウンスの収まるまで待ってから、 if(PIND & (1 << PD2)){PORTD &= ~(1 << PD5);} // スイッチが放されていたらPD5からLを出力し、 else {PORTD |= (1 << PD5);} // スイッチが押されていたらPD5からHを出力する。 } } void enable_rom(){ DDRC &= ~0x0F; // PC3:0にアドレスを入力することにする。 //PORTC |= 0x0F; // PC3:0を内部プルアップする。★実際にTD4に接続するときは内部プルアップは不要。 DDRB = 0xFF; // PB7:0から命令を出力することにする。 PORTB = _[0]; // 最初のクロックが立ち上がる前に0番地の命令を命令デコーダーへ与えておく。 // PCINT11:8 (PC3:0)からピン変化割り込みをかけることにする。 PCICR |= (1 << PCIE1); PCMSK1 |= ((1 << PCINT11)|(1 << PCINT10)|(1 << PCINT9)|(1 << PCINT8)); sei(); } void enable_1Hz_10Hz_clock(){ DDRD |= (1 << PD6)|(1 << PD7); // クロックを出力する端子を指定する。 TCCR1B |= (1 << WGM12); // タイマー1をCTCモードで動かす。 TCCR1B |= (1 << CS11); // 8分周してタイマー1でカウントする。 OCR1A = 49999; // コンペア値。(F_CPU/8分周)/(10Hz*2)-1 = 49999 TIMSK1 |= (1 << OCIE1A); // タイマー1のコンペアマッチ割り込みを有効にする。 sei(); } /*テキストの3分15秒ラーメンタイマー(クロックは1Hz) _[ 0] = OUT(0b0111); // LEDを3つ点灯 _[ 1] = ADD_A(1); _[ 2] = JNC(1); // 16回ループ _[ 3] = ADD_A(1); _[ 4] = JNC(3); // 16回ループ _[ 5] = OUT(0b0110); // LEDを2つ点灯 _[ 6] = ADD_A(1); _[ 7] = JNC(6); // 16回ループ _[ 8] = ADD_A(1); _[ 9] = JNC(8); // 16回ループ _[10] = OUT(0b0000); _[11] = OUT(0b0100); _[12] = ADD_A(1); _[13] = JNC(10); // LED点滅を16回ループ点滅 _[14] = OUT(0b1000); // LEDを1つ点灯 _[15] = JMP(15); // ここにとどまる。 */ /*テキストのLEDちかちか _[0] = OUT(0b0011); _[1] = OUT(0b0110); _[2] = OUT(0b1100); _[3] = OUT(0b1000); _[4] = OUT(0b1000); _[5] = OUT(0b1100); _[6] = OUT(0b0110); _[7] = OUT(0b0011); _[8] = OUT(0b0001); _[9] = JMP(0); */ /* 外部入力をそのまま外部出力する。 _[0] = IN_B; _[1] = OUT_B; _[2] = JMP(0); */ /* 0~15まで1ずつインクリメントする、を繰り返す。 _[0] = OUT_B; _[1] = ADD_B(1); _[2] = JMP(0); */ #endif