• ベストアンサー

割り込みで並列処理

ATmega168とWinAVRで割り込みのプログラミングをしています。 #include <avr/io.h> #include <avr/interrupt.h> ISR(TIMER1_OVF_vect) { TCNT1 = 65500; PORTC ^= 0x02; } int main() { int i; DDRC = 0x07; PORTC ^= 0x01; TCCR1B = 0x00; TCNT1 = 65500; TIMSK1 = _BV(TOIE1); TCCR1B = 0x05; sei(); while (1) { PORTC ^= 0x04; for(i=0;i=500;i++){} } } 上記のプログラムを組んでみたのですが。while文に入ってfor文に少し入ってからISRの処理が始まるのですが。ISRの処理が終わってから又for文の処理に戻ろうとしません。なのでPORTC0x04の点滅が起こりません。PORTC0x04の点滅もしながらPORTC0x02の点滅もしたいのですがどうすれば良いのでしょうか?

  • RWSP
  • お礼率93% (124/133)

質問者が選んだベストアンサー

  • ベストアンサー
  • zwi
  • ベストアンサー率56% (730/1282)
回答No.3

>回答ありがとうございます。プログラムの確認はWinAVRのシュミレーションで確認しました。 シミュレータ上でデバッガで停止させて確認したと認識よろしいですか? なぜ、mainに戻っていないと確信を得たか教えてください。 >あと割り込みと言うのはmain()文を中心に処理するが割り込みの条件がはいったならばmain文の処理をいったん停止し、割り込みの内容を優先する。割り込みの処理が終了したらmain文の処理に戻っていくという認識をしているのですが合っているのでしょうか? main文だとmain関数の中だけ見たいですが、割り込み処理以外の部分でプログラムが走っている場合は、どこの処理中でも割り込み信号が発生した瞬間に処理を中断して割り込み処理終了後に続きの処理に戻ります。 割り込む命令の単位はマシン語1命令の単位でありC言語の文の単位では有りません。 >メインでPORTCを変更する間は割り込みを禁止してください。 cil(); PORTC ^= 0x04; sei(); ここらを参考に↓ http://avrwiki.jpn.ph/wiki.cgi?page=Getting+Started+Notes+-+%B3%E4%A4%EA%B9%FE%A4%DF

RWSP
質問者

お礼

回答ありがとうございます。 それはプログラム的に言うと int main(){   ・   ・ while (1) { cil(); PORTC ^= 0x04; sei(); for(i=0;i=500;i++){} } } こういうことで良いんでしょうか? うまくいきません。

その他の回答 (5)

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.6

>F11を押すとプログラムが一つずつ進んでいくのでそれを見ていると >ISRに入った後main文に戻らずにISR文の中でずっとループしていました。 ループ構造を持たないISRの中でループするのは変だと思いません? それは、割り込みタイマがステップ実行中(F11)でも無関係にカウントダウンしてオーバーフローしてるんじゃないでしょうか?なので割り込みを抜けると直ぐ再度割り込んでいるんじゃ? 割り込みのデバッグはF11で実行しないで下さい。必ずブレーク設定して調べたい命令の所で止めましょう。

RWSP
質問者

お礼

回答ありがとうございました。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.5

R32Cさんの指摘まで基本的すぎて見落としてましたが、このコードは確実に無限ループします。 >for(i=0;i=500;i++){} >} i=500は代入文で条件式では無いので常に真でループから抜けることが出来ません。つまり無限ループです。 >シミュレータ上でデバッガで停止させて確認したと認識よろしいですか? >なぜ、mainに戻っていないと確信を得たか教えてください。 こちらは答えてもらえないんでしょうか? デバッガがちゃんと使えたら無限ループしていることは直ぐに確認できたのに勿体無いですね。

RWSP
質問者

お礼

i=500になったら終了と言うことではなかったのですね。 シュミレータはデバッガと言うよりビルド&ランをしていました。 F11を押すとプログラムが一つずつ進んでいくのでそれを見ていると ISRに入った後main文に戻らずにISR文の中でずっとループしていました。

  • R32C
  • ベストアンサー率39% (115/290)
回答No.4

>for(i=0;i=500;i++){} 無限ループしているのでは?

RWSP
質問者

お礼

回答ありがとうございます。 for文を抜けるとwhile文で戻ってまたportにいきますよね。 それがいかないんです。だからiが500に成ったら自動的に上に戻るはずなんですけどね。まだ良くわかっていません。

  • zwi
  • ベストアンサー率56% (730/1282)
回答No.2

プログラムを見る限りは正常に動作するとは思えません。 PORTC ^= 0x04; はアセンブラ1命令に置き換えれませんよね? (1)レジスタ←PORTC (2)レジスタ←レジスタ XOR 0x04 (3)レジスタ→PORTC となるはずですので(1)~(3)の間のどこかで割り込む可能性が出てきます。もし(2)で割り込んだらPORTCの書き換えが割り込み中で行われるので(2)の時点でレジスタが保持している値と実際のPORTCの値が違う可能性かが出てきます。 >上記のプログラムを組んでみたのですが。while文に入ってfor文に少し入ってからISRの処理が始まるのですが。ISRの処理が終わってから又for文の処理に戻ろうとしません。 これはどのようにして確認しましたか? LEDの点滅以外のデバッガ等で確認しましたか? >なのでPORTC0x04の点滅が起こりません。PORTC0x04の点滅もしながらPORTC0x02の点滅もしたいのですがどうすれば良いのでしょうか? メインでPORTCを変更する間は割り込みを禁止してください。

RWSP
質問者

お礼

回答ありがとうございます。プログラムの確認はWinAVRのシュミレーションで確認しました。 あと割り込みと言うのはmain()文を中心に処理するが割り込みの条件がはいったならばmain文の処理をいったん停止し、割り込みの内容を優先する。割り込みの処理が終了したらmain文の処理に戻っていくという認識をしているのですが合っているのでしょうか?

  • pyonmae
  • ベストアンサー率64% (40/62)
回答No.1

こんにちは。 ええと、多分ですが、関数ISRが割り込みハンドラとしてコンパイルされていないため、正しくリターンできていないのではないでしょうか。 割り込みハンドラとしてのコンパイルの仕方は、コンパイラのマニュアル等を見てください。 あと、蛇足ですが、PORTCをメインルーチンと割り込みの両方から変更していますが、メインルーチンで変更する間は割り込み禁止にするとかしないと、動きがおかしくなると思います。

RWSP
質問者

お礼

回答ありがとうございます。 割り込み禁止とはcil();のことでしょうか? 具体的にどこに入れれば良いのでしょうか? ソースで示していただけると大変うれしいです。 どうか、よろしくお願いします。

関連するQ&A

  • AVRプログラム 関数から戻ってこない

    AtmelStudio6 で、ATmega64A向けにプログラム行なっているのですが、 すごく、単純なところで困っています。 ICEは、AVR JTAGICE です。 main() のみで処理をさせると普通に動くのですが、関数に飛ばすと飛んだ先の 関数から戻ってこなくなるのです。 ツールかレジスタの設定が不十分なのかもしれません。 -- 問題のプログラム -- #include <avr/io.h> #include <avr/iom64a.h> #include <avr/interrupt.h> #include <util/delay.h> void test(void){ DDRA = 0xC0;//<ここは、実行される }//デバッガで見ると、ここで止まっている。 int main(void) { cli();//この関数はライブラリにあるので戻ってくる test();//この関数から帰ってこない // DDRA = 0xC0; //test();の内容をここに書くと、正常に処理して通過する。 PORTB = 0xFF; //B出力レジスタ DDRB = 0xF7; //B方向レジスタ PORTC = 0xFF; DDRC = 0xDB; while(1) { //TODO:: Please write your application code LEDを点滅させるプログラム <略> } } ------------------------------------------------------- 何方か心当たりのある方は居ないでしょうか?

  • 割り込み処理について

    割り込み処理について 初心者です。 AVRマイコンの割り込み処理について質問させて頂きます。 INT0割り込みルーチンの途中で、条件1により割り込み発生元(メインルーチン)に復帰させてたいのですが、下記のソースに何か問題はございますか? ISR(INT0_vect,ISR_NOBLOCK) {     int0割り込み禁止          条件1         return;     処理1          条件2         return;     処理2 } よろしくお願い致します。

  • AVRのサーボ制御で困っています。

    AVRマイコンを用いてサーボを8個制御するプログラムをC言語で作っています。使っているマイコンはATmega64LでサーボはフタバのS3003、AVRstudio4.17とAVR-GCCを用いてコンパイルやシュミレートをしています。 プログラムはサーボを8個動かすために タイマ2の比較一致割り込みで2.5msの周期をつくり タイマ0の比較一致割り込みで0.5ms~2.5msのパルスをつくり main関数でサーボの角度を制御するというものです。サーボ8個の角度の保持にはグローバル変数を用いています。 「サーボ初期位置→サーボ2個移動して固定」はうまくいくんですが「サーボ初期位置→※サーボ2個移動→さらに他のサーボ2個移動→はじめに動かしたサーボ2個を初期位置へ」というプログラムを書いたら、なぜか※をつけた「サーボ2個移動」の部分が実行されずその次の行動から実行されてしまいます。これはAVRに書き込んで確認したもので、シュミレータで確認するためにwait()などの待つ処理を除いてシュミレートしてみたのですが、「サーボ2個移動」の2行を飛ばして実行してしまっています。 具体的に飛ばされている部分は後述のソースコードのdo{・・・}while(1);の中の servopos[FR_LEG]=31; servopos[RL_LEG]=31; で、do{・・・}while(1);の無限ループはservopos[FR_JOINT]=70;からservopos[RL_LEG]=94;を無限ループしています。 電気回路、C言語ともに初心者なので見当がつかず、いろいろ試したり調べてみてもわかりませんでした。 質問は「なぜこのようにプログラムを数行飛ばして実行してしまっているのか」です。ソースコードの指摘をしていただけると有り難いです。 ソースコード #include <avr/io.h> #include <avr/interrupt.h> #define RL_JOINT 0 #define FR_JOINT 1 #define FL_LEG 2 #define RL_LEG 3 #define FL_JOINT 4 #define RR_JOINT 5 #define RR_LEG 6 #define FR_LEG 7 uint8_t phase=0; uint8_t servopos[8]={94,94,94,94,94,94,94,94}; /* void wait(uint16_t w){ while(w--){ volatile uint16_t i=200; while(i--); } } */ ISR(TIMER2_COMP_vect){ PORTC=0x00; TCNT0=0; } ISR(TIMER0_COMP_vect){ PORTC |= (1<<phase); OCR0 = servopos[phase]; phase++; if(phase>7){phase=0;} } int main( void ){ //ポート設定 DDRC=0xFF; PORTC=0x00; //タイマ0設定 OCR0 = 94; TCCR0 |= (1<<WGM01)|(1<<CS02)|(1<<CS00); TIMSK |= (1<<OCIE0); //タイマ2設定 OCR2 = 79; TCCR2 |= (1<<WGM21)|(1<<CS22); TIMSK |= (1<<OCIE2); // 全体割り込み許可 sei(); do{ // wait(10000); servopos[FR_LEG]=31; servopos[RL_LEG]=31; // wait(1000); servopos[FR_JOINT]=70; servopos[RL_JOINT]=70; // wait(1000); servopos[FR_LEG]=94; servopos[RL_LEG]=94; }while(1); }

  • 割り込み処理について

    割り込み処理について 初心者です。 AVRマイコンの割り込み処理について質問させて頂きます。 INT0割り込みの割り込みが入ったら、割り込みルーチン中の他の割り込みを許可し、かつINT0の割り込みを禁止したいのですが、下記ソースで問題はありませんか? INT0割り込みが終了して、メインルーチンに復帰した直後にINT0割り込みを許可したいのですが、下記ソース(1)で問題はありませんか(メインルーチンに復帰した直後に許可したいのですが、方法がわかりません)? ISR(INT0_vect,ISR_NOBLOCK) {     int0割り込み禁止      ・      ・      ・      ・    (int0割り込み要求フラグクリア) ・・・・(1)        (int0割り込み許可)         ・・・・(1)   } よろしくお願い致します。

  • 並列処理プログラム

    並列処理について。 画像imageの値が0より大きい場合に、managerを実行しますが、managerの計算時間が長いです。 そこで、4つのコアでpthreadにより、並列処理をさせたいんですが、 どのようにプログラムを書けばいいかすみませんが教えてください。 あるボクセルを計算中に、次のボクセルを計算するようなプログラム。。。 for (int z=0; z<32; z++){  for (int y=0; y<32; y++){   for (int x=0; x<32; x++){    if(image(x,y,z) > 0){     total += manager(x,y,z);    }   }  } }

  • 並列処理(SCore)

    並列処理(SCore) 自分はSCOREを用いて並列処理を行おうとしている初心者です。 [環境] ・CPU Intel Core2 Quad 2.83GHz ・メモリ 8GB ・スイッチングハブ FXG-08IMB(ギガビット) これをサーバー兼計算ホスト1台、計算ホスト3台の計4台でSCoreによって並列環境として接続しました。 ・使用したプログラムは、初期値を設定し、ラプラス方程式を逐次的に計算させるプログラムです。 ・並列処理を行うためのプログラムとして、MPIを使用しました。 いろいろなパターンでプログラムを実行した結果を図に貼り付けておきます。 クアッドコアなので、1PCで4ノード扱うことができています。 やや頭でっかちとなってしまいましたが、ここからが質問です。 [質問?] たとえば、1つのPCで、4ノードで並列処理を行った場合と、 4つのPCで各1ノードずつ、合計4ノードで並列処理を行った場合に、 4PCで1ノードずつを並列接続したほうが"約1.8倍"の演算性能を誇っているのはなぜでしょうか? [質問?] 今回は初期値を設定して、ラプラス方程式を解く逐次プログラムを使用しましたが、 プログラムによっては、質問?のような結果にならない場合もあるのでしょうか? もしあるなら、どのようなタイプのプログラムなら、1台で4ノード、4台で4ノードの演算性能がほとんど同じ程度になるのでしょうか? できれば、?も?も上記した環境を踏まえて回答していただけると幸いです。 申し訳ありませんが、初心者ということを分かって回答していただけると助かります。 面倒だとは思いますが、回答よろしくおねがいします。 [以下プログラム] この逐次プログラムをMPI関数によって並列処理可能にしたものが実際使用したプログラムです。 (文字数が足りなかったので、並列化する前の逐次プログラムをせめて載せておきます。) #include<math.h> #include<stdio.h> #include<sys/time.h> #define SIZE (1024*3 - 2) #define EPS 1.0e-1 double u[SIZE+2] [SIZE+2], uu[SIZE+2][SIZE+2]; double second() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec / 1000000.0; } void init(double u[SIZE+2][SIZE+2]) { int i,j; memset (u,0,sizeof(double)*(SIZE+2)*(SIZE+2)); for (i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) u[i][j]=sin((j-1)/(SIZE*M_PI))+cos((j-1)/(SIZE*M_PI)); } int main() { double start,time,err; int i,j,iter=0; init(u); init(uu); start=second(); do{ {iter ++;} for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) uu[i][j]=u[i][j]; for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) u[i][j]=(uu[i-1][j]+uu[i+1][j]+uu[i][j-1]+uu[i][j+1])/4.0; {err=0.0;} for(i=1;i<=SIZE;i++) for(j=1;j<=SIZE;j++) err+=(uu[i][j]-u[i][j])*(uu[i][j]-u[i][j]); }while (err>EPS); time = second()-start; printf("time=%f seconds, iteration=%d,performance=%f MFLOPS\n", time,iter,(8.0*SIZE*SIZE*iter)/time/1.0e6); return 0; }

  • 割り込みのカウントの仕方

    c言語、PICともに素人です。 あるサイトのプログラムで、割り込みを使いLEDを点滅させるというものがありました。 割り込み時毎にLEDへの出力を反転させているだけです。 しかし、これだとLEDの点滅が速いのでもう少し遅くしようと、割り込み10回で出力を反転させるようなプログラムを組みました。 #include "pic.h" #include "delay.h" __CONFIG(FOSC_HS & WDTE_OFF & PWRTE_ON & CP_OFF); int a; void main(void) {  GIE = 1;  T0IE = 0;  T0CS = 0;  PSA = 0;  OPTION_REG |= 0x07;  TMR0 = 0x00;  TRISA = 0x00;  TRISB = 0x00;  a = 0;  T0IE = 1;  while(1); } void interrupt peko(void) {  if(T0IF)  {   if(a==10)   {    T0IF = 0;    PORTA ^= 0xff;    PORTB ^= 0xff;    a=0;   }   else   {    a++;   }   return;  } } aという変数をおいて、最初a=0にしておきます。 割り込みが発生するたびにaに+1していき、aが10に達した時処理をし、aを0に戻す。 これで点滅速度が1/10ぐらいになるだろうと思ったのですが、全く変わりません。 点滅はします。 一体何が違うのでしょうか。 ご教授お願いします。

  • for文

    整数を読み込んで、その値を0までカウントダウンしながら表示するプログラム作りたいのですが、 while文ではできたのですが、for文ではうまくいきません。 どこが間違っているのでしょうか? OS:Windows XP C++Builder X パーソナル #include <stdio.h> int main(void) { int i; int num; printf("整数を入力してください:"); scanf("%d", &num); for(i = num; i <= 0; --i) { printf("%d", i); } return 0; } 宜しくお願いします。

  • Tera Termを使ったマイコンとの通信

    H8/3048Fと通信をしようと思い、「Tera Term」を使ってみたのですが、 下のプログラムを実行してもTera Termに何も表示されません(COMの番号はしっかり確認しました) while( 1 ){ ITU0.TCNT = 0; while( ITU0.TCNT < 40000 ); counter++; if( counter > 100 ){ if( P4DR == 0x00 ){ //LEDを点滅させる(確認用) P4DR = 0x10; } else{ P4DR = 0x00; } while( ( SCI0.SSR.BYTE & 0x80 ) == 0 ); SCI0.TDR = 'A'; //Aを送信する SCI0.SSR.BYTE &= ~0x80; counter = 0; } } SCI0の設定は int i; SCI0.SCR.BYTE = 0x00; SCI0.SMR.BYTE = 0x00; SCI0.BRR = 51; for( i = 0 ; i < 1000 ; i++); i = SCI0.SSR.BYTE; SCI0.SSR.BYTE = 0x80; SCI0.SCR.BYTE = 0x30; となっております。 このプログラムを実行すると確認用のLEDは点滅しますが、Tera Termには何も表示されません。 どこか間違っているところなどがあれば教えていただけないでしょうか? ちなみに、使用しているOSはWindows7です。 よろしくお願いします。

  • unsigned型のビット構成を表示するプログラムが理解できません。

    unsigned型ビット構成の表示プログラム #include<stdio.h> int count_bits(unsigned x) { int count=0; while(x){ if(x&1U)count++; x>>=1; } return(count); } int int_bits(void) { return(count_bits(~0U)); } void print_bits(unsigned x) { int i; for(i=int_bits()-1;i>=0;i--) putchar(((x>>i)&1U)?'1':'0'); } int main(void) { unsigned nx; printf("非負の整数を入植してください。:"); scanf("%u",&nx); print_bits(nx); putchar('\n'); return(0); } このプログラムで10を入力したら、00000000000000000000000000000001010と表示され。 18だと00000000000000000000000000000010010と表示される原理が理解できません。 自分なりにプログラムを追ってこういう考えてます。 まず、10を入力したらcount_bitsの関数の処理からスタート。 while(x){ if(x&1U)count++; x>>=1; if(x&1U)の処理を行い。x=10はbit単位表示で、1010として考え。一番右側の101「0」とunsigned型の1との論理比較を行う。0と1なので偽で何もせずにif文を抜けて、x>>=1;を行いx=0101となり。while(x)から再びif(x&1U)行う。x=0101の一番右側のunsigned型の1との論理比較を行い0と1なので真なのでcount++を行いcount=1としてif文を抜け、x>>=1;を行いX=0010になり。三度目のif(x&1U)の処理を行う。0010の一番左側のunsigned型の1との論理比較を行い0と1なので偽でif文を終了。x>>=1;を行い0001となり、再びif(x&1U)行う。 00 01の一番左側のunsigned型の1との論理比較を行い0と1なので真なのでcount++を行いcount=2となり、x>>=1;を行い0000なのでwhile(x)を抜けて返り値2をint_bitsへ返して関数は終了 int_bitsではunsinged型の2が戻り値としてprint_bitsへ返し、int_bitsの関数は終了。 print_bitsの処理が始まり。for(i=int_bits()-1;i>=0;i--)の処理がスタート。 i=int_bits()-1の処理でiは2-1でi=1からスタート。 putchar(((x>>i)&1U)?'1':'0');の処理。 (x>>i)でx=10,i=1なので1010>>1だから0101。 0101の一番右側の1とunsigned型の1と論理比較を行う 真なのでputcharは'1'を一度表示。 for文に戻りiをデクリメントとしてi=0なのi>=0から 一度、putchar(((x>>i)&1U)?'1':'0');処理。 (x>>i)は0101>>0の0右シフト行い0101。 unsignedと1を0101の一番右側の1と論理比較を行う 真なのでputcharは'1'を一度表示。 for文に戻りiをデクリメントとしてi=-1なのでi>=0からfor文を終了してprint_bitsの処理を終了。mainの関数処理に戻り。putchar('\n');を出力して関数処理は終了。表示として「11」が表示される。18も同様に考えているので、「11」が表示されてしまうのでは?という考えに陥ってます。実際は、両方とも正しくunsigned型ビット構成の表示されるので、自分の考え方が間違えている。なのですが、どう間違えているかがわかりません。 多少説明文の省略しているためわかりにくいかもしれませんが、間違えを指摘していただけないでしょうか?

専門家に質問してみよう