• ベストアンサー
※ ChatGPTを利用し、要約された質問です(原文:ある関数を通過すると、IOポートが勝手にLOWになってしまう)

ある関数を通過すると、IOポートが勝手にLOWになってしまう

このQ&Aのポイント
  • H8S_2368マイコンを使用してテンキーパネルの値に基づいてDTMF信号を出力する関数を実行すると、常に特定のIOポートがLOWになる問題が発生します。
  • 関数内でOSSemPend(KeyWait,100, &err)関数を実行すると、IOポートがLOWになる原因が不明です。
  • 解決策や原因をご存知の方がいらっしゃれば、教えていただけないでしょうか?

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

  • ベストアンサー
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.2

場所が特定できたのなら、原因も追跡できるはずです。 err!=0がfalseになる条件、つまりerr==0となるのは何が起こったときでしょう? なお、ソース全体を見ないことにはなんとも言い難いですが、最初のコードのOSSemPend()は直接の原因ではなくて「たまたま時期が一致しているだけ」ではないかと。

techhouse
質問者

お礼

回答頂きありがとうございました。 ”err!=0がfalseになる条件、つまりerr==0となるのは何が起こったときでしょう?” このことについて調べてみたところ、次のことがわかりました。 ・テンキーパネルを何も押さない状態の時には、pb_select_dial02_kj(void)関数のwhile(1)ルーチン中の”OSSemPend(KeyWait,100, &err);”は100の値のカウントでタイムアウトするときは、errに0x0Aという値を返していて、次のif文でcontinueに行きそれをずっとループしている。 ・テンキーパネルのどれかのボタンを押すと、”OSSemPend(KeyWait,100, &err);”は0x00という値をerrに入れて、switch(stKey.key)文でキーのコードのところで条件に合うところに行く。 ・OSSemPend(KeyWait,100, &err);関数をググってみたら、http://www.scribd.com/doc/7046520/Ucos-II-Refmanこのサイトにデータシートがあり、 errにはif the semaphore is availableこれなら、”OS_NO_ERR = 0x00”を返して、 タイムアウトしていたら、”OS_TIMEOUT = 0x0a”を返していることが書かれていました。 ・それで、”OS_NO_ERR = 0x00”を返す時というのは下記のテンキーのキースキャンプログラムで、ボタンを押して、離した際に”OSSemPost(KeyWait);”が実行されて、次の瞬間に”pb_select_dial02_kj(void)関数”のOSSemPend(KeyWait,100, &err)がerr=0x00を入れて、動作していることがわかりました。 DECLARE_TASK_FUNC(Key) { u16 cur,old; u8 status; KeyWait = OSSemCreate(0); parg = parg; cur = old = 0x00; stKey.key = 0; stKey.time = 0; status = KEY_ST_NONE; while(1) { cur = key_scan(); if(cur != old) { if(status == KEY_ST_NONE) { status = KEY_ST_PRESS; stKey.key = cur; stKey.time = 0; } else if(cur == KEY_NONE) { OSSemPost(KeyWait); status = KEY_ST_NONE; //debug("key %s\n\r",key_def[key_get_index(stKey.key)].name); } } else { if(status == KEY_ST_PRESS){ stKey.time++; } } old = cur; OSTimeDly(40); } }

全文を見る
すると、全ての回答が全文表示されます。

その他の回答 (3)

  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.4

ああ違う。#1補足コードで取ろうとしてるのはセマフォじゃなくてキューですね。 おそらくキー入力がトリガになってキューに何かが入るんじゃないかと。

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.3

んー、惜しい! たしかにKeyWaitに関してはそれで正しいですが、errを見ているセマフォはそっちではなく#1補足についてるAudioMsg、つまり > AudioMsg = OSQCreate((void **)&AudioMsgQ[0],3); で作られている方のセマフォです。 こっちを追いかければおそらくキー入力時に何があってこっちのセマフォが取れるようになるのか、というところまで追えるのではないかと。

techhouse
質問者

お礼

回答頂きありがとうございます。本当に助かります。 ちょっと、この質問の趣旨と離れてきている内容になってきており恐縮です。私のRTOS(今回uCOS)に関しての知識不足で、セマフォとかの理解がほとんどない状態でして、質問している中で、なんとなくどのような動作をするものなのかというものがつかめてきてそのことの質問になりつつあるのをお許し下さい。 ただ、RTOSがどうして必要なのかということが”OSSemPend関数”とか”OSSemPost関数”の使い方でわかってきたような気がしております。この関数の機能を理解してくると他のプログラムもどのような意味なのかというのが少しずつわかってきたような気がしています。 ”IOポートが勝手にLOWになってしまう”この問題でわかったことがありまして、この”void pb_select_dial02_kj(void)”関数を呼び出す直前に、このオーディオの音声をDACで出力するためのプログラムを呼び出していて、それをコメントアウトしたところ、このLOWになる現象は無くなりました。”勝手に”というのは間違いでした。 ただ、そのオーディオの関数呼び出しの動作などでプログラムを追っていくとさらに疑問がたくさん出てきてしまいましたので、 特におっしゃられている AudioMsg = OSQCreate((void **)&AudioMsgQ[0],3); Audio = (SAUDIO_PLAY *)OSQPend(AudioExtMsg, 100, &err); これらの”OSQPend関数”と”OSSemPend関数”の使い方の違いなどです。 これらの問題は別の質問として投稿させていただきます。 一旦この質問を終了させていただきます。 本当にありがとうございます。

全文を見る
すると、全ての回答が全文表示されます。
  • D-Matsu
  • ベストアンサー率45% (1080/2394)
回答No.1

> OSSemPend(KeyWait,100, &err); のところでポートが変化するのであれば、私ならOSSemPend()で発生しているであろうスリープを解除している場所(※)周辺のコードでポート操作していることを疑います。 ※たぶんOSSemPost()かな?

techhouse
質問者

お礼

回答頂きありがとうございました。 この”#define INT_AMP_EN P2.DR.BIT.B1”のIOポートにかかわるテキストを全ソースから検索してみたところ、下記の関数内にあることがわかり、デバッガでブレークをかけてみたところ通過していることがわかりました。コレガ原因ということがわかりました。 いつもは、 if(err != 0) { //m_pFuncAudio(); continue; } この部分でcontinueに引っ掛かるようで、while(1)に戻り、下は実行されないようなのですが、あの関数を通過すると、このif文を通過してしまうようです。 DECLARE_TASK_FUNC(Audio) { u8 err; int i,j; SAUDIO_PLAY *Audio; parg = parg; LockAudioMsg = OSSemCreate(1); AudioEnd = OSSemCreate(0); AudioMsg = OSQCreate((void **)&AudioMsgQ[0],3); while(1){ Audio = (SAUDIO_PLAY *)OSQPend(AudioMsg, 100, &err); if(err != 0) { //m_pFuncAudio(); continue; } RunAudioTask = TRUE; bPlayAudio = TRUE; INT_AMP_EN = ON; if(Audio->Repeat > 0){ for(i=0 ; i < Audio->Repeat ; i++){ if(bPlayAudio == FALSE)break; for(j=0 ; j < MAX_AUDIO_FILE ; j++){ if(bPlayAudio == FALSE)break; if(Audio->Num[j] == 0) break; else audio_play(Audio->Num[j]-1,Audio->Num[j+1] == 0 ? 1 : 0); if(Audio->Num[j+1] == 0 ) break; } if(Audio->Repeat == 255) if(i > 253 ) i = 250; } } INT_AMP_EN = OFF; bPlayAudio = FALSE; RunAudioTask = FALSE; } }

全文を見る
すると、全ての回答が全文表示されます。

関連するQ&A

  • 関数の戻り値として文字列を返して、printfで出力させることはできますか?

    いま、引数の数値によって、文字列を返すという関数を作り、それをprintf関数で出力したいと考えているんですが、どうやって作ればいいのかわかりません。 char data_2_dtmfdata(u8 getdata) { switch(getdata) { case 0x01: //tone"1" return "KEY_1"; case 0x02: //tone"2" return "KEY_2"; case 0x03: //tone"3" return "KEY_3"; } } このような感じで関数を作成して、 printf("%s",data_2_dtmfdata(data)); printf関数でこのように設定してあげれば”KEY_1”とか”KEY_3”とかの文字列を出力してあげられるのでしょうか?

  • OSSemCreate関数に引数”1”と入れた場合動作。

    セマフォを作るためのOSSemCreate関数について質問なのですが、 ”OscWait = OSSemCreate(1);”という引数に1を入れた場合は ”OscWait = OSSemCreate(0);”の時と動作にどのような違いがでるのでしょうか? H8S2368マイコンにuCOSというRTOSを組み込んでいるプログラムを見せてもらっているのですが、セマフォを作る場合は ”OscWait = OSSemCreate(0);”というように記述すればよいというのはなんとなくわかったのですが、 所々、”OSSemCreate(1);”という記述もあり、どのように使い分けているのかがわかりません。 どのような意味で、このようにして使っているのでしょうか? DECLARE_TASK_FUNC(Sw) { BYTE err; OscWait = OSSemCreate(1); parg = parg; while(1) { OSSemPend(OscWait, 500, &err); OSSemPost(OscWait); } } DECLARE_TASK_FUNC(Osc) { BYTE err; parg = parg; while(1) { OSSemPend(OscWait, 100, &err); if(err != 0){ continue; } OSC_temp++; printf("OSC_temp %d \n\r",OSC_temp); } } DECLARE_TASK_FUNC(Osc02) { u16 cur,old; u8 OSC_temp02=0; BYTE err; parg = parg; while(1) { OSSemPend(OscWait, 100, &err); if(err != 0){ continue; } OSC_temp02++; printf("OSC_temp02 %d \n\r",OSC_temp02); } }

  • PIC18F15Q40のI2Cスレーブ動作について

    現在、PIC18F15Q40をMicrochip MPLAB X v5.50とMCC v5.0.3で開発しています。 MCCの自動生成コードによってI2Cスレーブ動作(割り込み駆動)をさせ、 マスタからREAD要求 -> 固定長データを送り返すというようなプログラムを書きたいのですが、 データを送信し終わった後に割り込み処理から復帰せず、WDTによるリセットが掛かってしまいます。 以下、割り込み関数内の処理です。単純にデータカウンタをインクリメントし、それに応じたデータをI2C1_Writeしているだけになります。 void I2C_WriteInterrupt(void) { volatile static uint8_t tx_buf; switch(I2C_TxCounter) { case REV: tx_buf = Revision; break; case STAT: tx_buf = Status; break; case VOL_MSB: tx_buf = (uint8_t)((ADC_Result >> 8) & 0x00FF); break; case VOL_LSB: tx_buf = (uint8_t)(ADC_Result & 0x00FF); break; case CYL_MSB: tx_buf = (uint8_t)((CycleCount >> 8) & 0x00FF); break; case CYL_LSB: tx_buf = (uint8_t)(CycleCount & 0x00FF); break; default: tx_buf = 0xFF; } I2C1_Write(tx_buf); // カウンタ操作とタイマ再開 if(I2C_TxCounter < CYL_LSB) I2C_TxCounter++; } 以前PIC16F18877で同様の処理を行わせた際には特に問題は発生しなかったのですが…… MCCの設定はスレーブアドレスとクロックストレッチ有効、Interrupt Driven有効以外に変更していません。 どなたか解決策お持ちの方はいらっしゃいますでしょうか。

  • カーソルを自作の画像に変えようと思い、LoadImage関数を使ってカ

    カーソルを自作の画像に変えようと思い、LoadImage関数を使ってカーソルの画像を読み込もうと思ったのですが、マウスカーソルが表示されませんでした。GetLastError関数は0を返しました。誰か原因がわかる方がいましたら回答お願いします。 HCURSOR hIcon; DWORD i; char szFileName[64]; strcpy( szFileName, "picture/electlic1.cur" ); hIcon =(HCURSOR)LoadImage(NULL,szFileName,IMAGE_CURSOR,0,0,LR_DEFAULTSIZE | LR_LOADFROMFILE); i=999; i=GetLastError(); switch(i) { case 0:texture->vecPosition[0].x=500;break; case 1:texture->vecPosition[0].y=200;break; case 2:texture->vecPosition[0].x=100;break; } SetCursor(hIcon);

  • カーソルを自作の画像に変えようと思い、LoadImage関数を使ってカ

    カーソルを自作の画像に変えようと思い、LoadImage関数を使ってカーソルの画像を読み込もうと思ったのですが、画像は表示されませんでした。GetLastError関数は0を返しました。誰か原因がわかる方がいましたら回答お願いします。 HCURSOR hIcon; DWORD i; char szFileName[64]; strcpy( szFileName, "picture/electlic1.cur" ); hIcon =(HCURSOR)LoadImage(GetModuleHandle(0),szFileName,IMAGE_CURSOR,0,0,LR_DEFAULTSIZE | LR_LOADFROMFILE); i=999; i=GetLastError(); switch(i) { case 0:texture->vecPosition[0].x=500;break; case 1:texture->vecPosition[0].y=200;break; case 2:texture->vecPosition[0].x=100;break; } SetCursor(hIcon);

  • switch文の中でforeach

    switch文の中でforeachをしたいのですが、うまくいきません。 <現状> $x=5; switch( $x ){  case 2:   echo $x="JavaScript";    break;  case 5:   echo $x="PHP";   break;  default:   echo $x="未分類"; } <やりたいこと>判定データを別で用意して、読み込ませたい $x_master = array(  2 => "JavaScript",  5 => "PHP", ); ■テスト1 $x=5; switch( $x ){  foreach( $x_master as $key => $value ){   case $key:    echo $x=$value;   break;  }   default:    echo $x="未分類"; } これを試すと、Parse error: syntax error, unexpected T_FOREACH, expecting T_CASE or T_DEFAULT or '}'となります。これは、switchの中でforeachは使えないということでしょうか? ■テスト2 $x=5; foreach( $x_master as $key => $value ){  switch( $x ){   case $key:    echo $x=$value;    break;   default:    echo $x="未分類";  } } $x=2;だとJavaScript未分類となるのに、$x=5;だと未分類未分類になります。 $x=2と$x=5で挙動が異なる理由が分かりません。 ■テスト3 $x=5; foreach( $x_master as $key => $value ){  switch( $x ){   case $key:    echo $x=$value;   break;  } } これでようやく望んだ結果が得られたのですが、これでo.k.のなのでしょうか? なんでdefault入れてはダメなのでしょうか? foreachでいくら回しても、該当部分が存在する限り、breakして、defaultへはいかないと思うのですが…。それともforeachの一番最後の終了処理で何かが返ってきて、それが該当項目に存在せず、defaultへ流れる結果となるのでしょうか? そもそも、考え方として、foreachで回している以上、この場合、例外というか、switch文のdefaultに該当する部分は必要ないとの認識でよいでしょうか? 質問内容 ■テスト1が、syntax errorとなる理由 ■テスト2で、$x=2なら$x_masterを読み込むのに、$x=5なら$x_masterを読み込まない理由 ■テスト3のケースは、default部分を本当に書かなくてo.k.でしょうか? またその理由は?

    • ベストアンサー
    • PHP
  • 矢印キーの反応が悪くなります

    このコードをmain関数とキーコントロール関数とに分けたところ、 キーのレスポンスがわるくなりました。 このソースコードをどのように分割すれば一つのファイルで書いたように、 動いてくれるのかわかりません。 よろしくお願いします。 /* 分割前のソースコード */ #include <stdio.h> #include <conio.h> int main(int argc, char *argv[]){ int key=0; while(key!='q'){ //終了キー 'q' key=_getch(); //Keyによって分岐 switch((key == 0x00 || key == 0xe0) ? _getch(): key) { case 0x48:printf("上");break;//上 case 0x50:printf("下");break;//下 case 0x4b:printf("左");break;//左 case 0x4d:printf("右");break;//右 default:break; } } return 0; } /*--ここから下が分割してみたソースコード---*/ /* arrowkey.h */ #ifndef ARROWKEY_H #define ARROWKEY_H int arrowkey(void); #endif //ARROWKEY_H /*---------------------------------*/ /* arrowkey.c */ #include <stdio.h> #include <conio.h> #include "arrowkey.h" int arrowkey(void){ int key=_getwch(); //Keyによって分岐 switch((key == 0x00 || key == 0xe0) ? _getch(): key) { case 0x48:printf("上");break;//上 case 0x50:printf("下");break;//下 case 0x4b:printf("左");break;//左 case 0x4d:printf("右");break;//右 case 0x71:break;//終了 default:break; } return key; } /*---------------------------------*/ /* main.c */ #include "arrowkey.h" int main(int argc, char *argv[]){ int key=0; while(key!='q'){ //終了キー 'q' key=arrowkey() } return 0; }

  • 付け値関数の求め方

    まず問題を書かせていただきます。 効用関数が U(z,h)=z^α×h^(1-α) であり、所得制約が y-tx=z+Rh の形をしている。ここでzは消費財、hは住宅の敷地面積、yは所得、xは都心からの距離、tは単位距離あたりの通勤費用である。 このとき、付け値関数R(y-tx,u)と地代勾配R^*'(x)を求めよ。 という問題についてですが、解答を見てみると 【解】 立地点を所与にした効用最大化問題の解は Z=α(y-tx) h={(1-α)(y-tx)}/R であるので付け値関数は R(y-tx,u)=(1-α)×α^(α/(1-α))×u^(-1/(1-α))×(y-tx)^(1/(1-α)) となる。 とありました。正直、最初に出てきた効用最大化問題の解Z,hの求め方すら分かりません...どうしていきなりこんな式が出てきたのか。もちろん付け値関数の指数だらけの式はなおさらさっぱりです。ここまでの求め方を教えていただきたいです。地代勾配についても触れていただければ幸いです。 こちらの都合になってしまうのですが、時間が無くて出来るだけ早い回答を頂ければ助かります。どうぞよろしくお願いしますm(_ _)m

  • ポインター引数の関数でコンパイルエラーが出る。

    現在ATmega88というアトメル社製のマイコンのプログラミングを行っています。コンパイラはwin_avrを使用しています。 現在void tx_test(cc1101_client * client)というcc1101_clientポインターを引数とした関数を作成したのですが、この関数内でu16 tx_fifo_set(txfifo_data * txfifo)という txfifo_dataポインターを引数とする関数を呼び出したいと思っているのですが、これをコンパイルすると error: incompatible type for argument 1 of 'tx_fifo_set'というエラーが出力されコンパイルできない状態になります。なぜこのようなエラーになるのでしょうか? u16 tx_fifo_set(txfifo_data * txfifo) { -------------------(中略)------------------------------------------------------------- } void tx_test(cc1101_client * client) { u8 i=0; u8 new_input_data=0; -------------------(中略)------------------------------------------------------------- while(1) { switch(status) { -------------------(中略)------------------------------------------------------------- case FIFO_SETUP: if(cnt_sent_packet > 100) { status = DATA_WAVEOUT_QUIT; break; } //alert_data_get(&client); cc1100_cmd_flush_tx(); cc1100_cmd_idle(); cc1100_cmd_calibrate(); cc1100_cfg_gdo0(CC1100_GDOx_SYNC_WORD); mdelay(5); client->status.sessionflag = 0x02; //SYN flag set client->status.ivent_flag = 0xa5; //tx_length = tx_fifo_set(client); //tx_fifo_set(&client); tx_fifo_set(client->txfifo); udelay(10); #if 1 cc1100_read_reg_uartout((CC1100_REG_TXBYTES | CC1100_ACCESS_STATUS)); #endif status = DATA_WAVEOUT; break; -------------------(中略)------------------------------------------------------------- }

  • C言語でのカレンダーの表示について質問です

    VisualStudioを使ってC言語でコンソールアプリケーションのカレンダーを作っています。 やりたいことは以下の通りです。 プログラムを起動すると、現在の月を中央に三ヶ月分のカレンダーを表示。 Lキーでカレンダー全体を一ヶ月前に変更 Rキーで一ヶ月後に変更 Dキーで三ヶ月前に変更 Uキーで三ヶ月後に変更 Aキーで一年前に変更 Bキーで一年後に変更 起動時にカレンダー表示するのはできているんですが、Rでカレンダーを進めていくと12月の次が13月、次が0月、その次が1月となってしまい、日付も上手いこと表示されません。 L,D,U,でも同じようになります。 また、A,Bで年を変えると日付が正確に表示されないです。 これらを正しく表示させる方法をご教授いただけますでしょうか。 #include <stdio.h> #include <conio.h> #include <time.h> #define KEY_ESC (0x1b) // エスケープ #define KEY_L (0x6c) // L #define KEY_D (0x64) // D #define KEY_R (0x72) // R #define KEY_U (0x75) // U #define KEY_A (0x61) // A #define KEY_B (0x62) // B time_t timer; // 現在の時刻 struct tm local; // 地方時 int curr_year; // 現在の年 int curr_mon; // 現在の月 int input; // どのキーが入力されたか int calendar[12][6][7]; // 月、最大の週、1週間 int year; // 年 int month; // 月 int day; // 日 int nweek; // その月が何周あるか int nday; // その月が何日まであるか int day_of_week; // その月が何曜日から始まるか void CalendarDisplay(void); void CalendarSet(void); void DayOfWeek(int, int, int); void NumOfDay(int); void KeyOperat(int); int LaepYear(int, int); int Zeller(int, int, int); int main(void) { CalendarDisplay(); while (1) { printf("ESCキーで終了\n\n"); input = _getch(); if(input == KEY_ESC) { break; } else if(input == KEY_L || input == KEY_D || input == KEY_R || input == KEY_U || input == KEY_A || input == KEY_B) { KeyOperat(input); } } return 0; } // カレンダーの表示 void CalendarDisplay(void) { // 現在時刻を取得 timer = time(NULL); // 地方時に変換 localtime_s(&local, &timer); // 現在の年 curr_year = local.tm_year + 1900; // 現在の月 curr_mon = local.tm_mon + 1; CalendarSet(); } // 当月とその±1の月を設定 void CalendarSet(void) { for (month = curr_mon-1; month <= curr_mon+1; month++) { // 12月を超えたら次の年に if(curr_mon > 12) { curr_mon = 1; month = 1; curr_year += 1; } // 1月を超えたら前の年に else if(curr_mon < 1) { curr_mon = 12; month = 12; curr_year -= 1; } // その月が何日まであるか求めて代入 nday = LaepYear(curr_year, month); // その月が何曜日から始まるか day_of_week = Zeller(curr_year, month, 1); nweek = 0; for (day = 1; day <= nday; day++) { calendar[month-1][nweek][day_of_week] = day; //printf("day-> %d ", day); if (++day_of_week == 7) { day_of_week = 0; nweek++; } } } DayOfWeek(month, curr_mon, curr_year); } // 月と曜日の表示 void DayOfWeek(int m, int cur_m, int cur_y) { for (m = cur_m-1; m <= cur_m-1; m++) { printf("%d%6d月%16d%6d月%16d%6d月\n" "日 月 火 水 木 金 土  " "日 月 火 水 木 金 土  " "日 月 火 水 木 金 土\n", cur_y, m, cur_y, m + 1, cur_y, m + 2); NumOfDay(&calendar[m-1]); } } // 日数の表示 void NumOfDay(int calendar[][6][7]) { int max_w = 0, nmon = 0, w = 0; // その月の最大週の間 for (max_w = 0; max_w < 6; max_w++) { // 3ヶ月分表示 for (nmon = 0; nmon < 3; nmon++) { for (w = 0; w < 7; w++) { if (calendar[nmon][max_w][w]) { printf("%2d ", calendar[nmon][max_w][w]); } else { printf(" "); } } printf(" "); } printf("\n"); } } // キー操作でカレンダーの表示を変える void KeyOperat(int input) { do { switch(input) { case KEY_L: curr_mon -= 1; break; case KEY_R: curr_mon += 1; break; case KEY_D: curr_mon -= 3; break; case KEY_U: curr_mon += 3; break; case KEY_A: curr_year -= 1; break; case KEY_B: curr_year += 1; break; default : input = !input; break; } } while(!input); CalendarSet(); } // うるう年の判定 int LaepYear(int y, int m) { const int num_day[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; if (m == 2 && y % 4 == 0 && (y % 100 != 0 || y % 400 == 0)) { return 29; } return num_day[m - 1]; } // ツェラーの公式から曜日を求める int Zeller(int y, int m, int d) { int dow;   // 1月と2月の場合、それぞれ前年の13月、14月とする if(m == 1 || m == 2) { y--; m = m + 12; } dow = (y + y/4 - y/100 + y/400 + (13*m+8)/5 + d) % 7; return dow; }