[戻る]
過去ログ [ 0001 ]
過去ログ:     ワード検索: 条件: 表示:

タイトル
記事No
投稿日
投稿者
参照先
switch分岐処理
110
: 15/01/30-11:14
PICはじめました

PIC18F2320 + C18環境でプログラムのテストをしています。
switch文を使用して、分岐処理を行っていますが、ある処理に入ってしまうと、他の処理に移行できない問題が発生し、困っています。

switch分を使用して、外部SWによる分岐処理をテストしています。
まず、LEDを2つ点灯させるプログラムで動作確認を行いました。
case0 ,1, 2, 3と、外部SW切り替えに対応してLEDの点灯パターンを変更できることが確認できました。
-> この時のプログラムが、次のプログラムです。

/////////////////////////////SW切り替えて動作確認OK/////////////////////////////
while(1)
{ 
sw = PORTA & 0x03;
switch(sw){
case 0: a_ope();
break;
case 1: b_ope();
break;
case 2: LATCbits.LATC4 = 1;
LATCbits.LATC5 = 0;
break;
case 3: break;
default:break;
}
}
return 0;
}

/*a_ope*/
int a_ope(void)
{
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 0;
return 0;
}


/*b_ope*/
int b_ope(void)
{
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 1;
return 0;
}
////////////////////////////////////////////////////////////////////////////////

次に、case 1(b_ope)の動作を変更しました。
AD変換して、LCDにその値を表示させるというプログラムです。(A/D変換プログラム単体での動作は確認済)

case 1に一度入ってしまうと、外部SWを切り替えても、他のcaseに入れません。
なぜでしょうか。


/////////////////////////////SW切り替えて動作確認NG/////////////////////////////
while(1)
{ 
sw = PORTA & 0x03;
switch(sw){
case 0: a_ope();
break;
case 1: b_ope();
break;
case 2: LATCbits.LATC4 = 1;
LATCbits.LATC5 = 0;
break;
case 3: break;
default:break;
}
}
return 0;
}

/*a_ope*/
int a_ope(void)
{
LATCbits.LATC4 = 0;
LATCbits.LATC5 = 0;
return 0;
}


/*b_ope*/
int b_ope(void)
{
//A/Dコンバータ初期設定
OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
ADC_1ANA);

lcd_init(); //LCD初期化
lcd_clear(); //LCD全消去

while(1)
{
SetChanADC(ADC_CH4); //チャネル4
ConvertADC(); //A/D変換開始
while(BusyADC()); //A/D変換終了待ち
Result = ReadADC(); //データ読み出し

Volt = (Result * 49)/10; //電圧値変換

itostring(4, Result, NUMMSG1+9); //数値を文字に変換
lcd_cmd(0x80); //1行目へ移動
lcd_str(NUMMSG1); //Numberの表示
delay_ms(100); //0.1秒待ち
itostring(4, Volt, NUMMSG2+9); //数値を文字に変換
lcd_cmd(0xC0); //2行目へ移動
lcd_str(NUMMSG2); //Numberの表示
delay_ms(100); //0.1秒待ち
}
return 0;
}
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: switch分岐処理
113
: 15/01/30-13:57
MOT

デバッカ使いましたか? b_ope()のwhile(1)内にbreak;ないように見えますが。
> PIC18F2320 + C18環境でプログラムのテストをしています。
> switch文を使用して、分岐処理を行っていますが、ある処理に入ってしまうと、他の処理に移行できない問題が発生し、困っています。
>
> switch分を使用して、外部SWによる分岐処理をテストしています。
> まず、LEDを2つ点灯させるプログラムで動作確認を行いました。
> case0 ,1, 2, 3と、外部SW切り替えに対応してLEDの点灯パターンを変更できることが確認できました。
> -> この時のプログラムが、次のプログラムです。
>
> /////////////////////////////SW切り替えて動作確認OK/////////////////////////////
> while(1)
> { 
> sw = PORTA & 0x03;
> switch(sw){
> case 0: a_ope();
> break;
> case 1: b_ope();
> break;
> case 2: LATCbits.LATC4 = 1;
> LATCbits.LATC5 = 0;
> break;
> case 3: break;
> default:break;
> }
> }
> return 0;
> }
>
> /*a_ope*/
> int a_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 0;
> return 0;
> }
>
>
> /*b_ope*/
> int b_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 1;
> return 0;
> }
> ////////////////////////////////////////////////////////////////////////////////
>
> 次に、case 1(b_ope)の動作を変更しました。
> AD変換して、LCDにその値を表示させるというプログラムです。(A/D変換プログラム単体での動作は確認済)
>
> case 1に一度入ってしまうと、外部SWを切り替えても、他のcaseに入れません。
> なぜでしょうか。
>
>
> /////////////////////////////SW切り替えて動作確認NG/////////////////////////////
> while(1)
> { 
> sw = PORTA & 0x03;
> switch(sw){
> case 0: a_ope();
> break;
> case 1: b_ope();
> break;
> case 2: LATCbits.LATC4 = 1;
> LATCbits.LATC5 = 0;
> break;
> case 3: break;
> default:break;
> }
> }
> return 0;
> }
>
> /*a_ope*/
> int a_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 0;
> return 0;
> }
>
>
> /*b_ope*/
> int b_ope(void)
> {
> //A/Dコンバータ初期設定
> OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
> ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
> ADC_1ANA);
>
> lcd_init(); //LCD初期化
> lcd_clear(); //LCD全消去
>
> while(1)
> {
> SetChanADC(ADC_CH4); //チャネル4
> ConvertADC(); //A/D変換開始
> while(BusyADC()); //A/D変換終了待ち
> Result = ReadADC(); //データ読み出し
>
> Volt = (Result * 49)/10; //電圧値変換
>
> itostring(4, Result, NUMMSG1+9); //数値を文字に変換
> lcd_cmd(0x80); //1行目へ移動
> lcd_str(NUMMSG1); //Numberの表示
> delay_ms(100); //0.1秒待ち
> itostring(4, Volt, NUMMSG2+9); //数値を文字に変換
> lcd_cmd(0xC0); //2行目へ移動
> lcd_str(NUMMSG2); //Numberの表示
> delay_ms(100); //0.1秒待ち
> }
> return 0;
> }
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re2: switch分岐処理
114
: 15/01/30-16:07
PICはじめました

MOTさん
返答ありがとうございます。

> delay_ms(100); //0.1秒待ち
> }
> return 0;
> }
のところを、

delay_ms(100); //0.1秒待ち

if (!(sw == 1))
break;
}
return 0;
}
に変更してみましたが、b_opeの処理に入ると、他の処理に移行できません。
初歩的な質問で申し訳ありませんが、解決策を教えていただけると助かります。
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: Re2: switch分岐処理
115
: 15/01/30-19:01
MOT

書き込みツール(PICKit3など)を使ってデバッグしてみるといいですよ。
ブレークポイントで止めて,ステップで一行ずつ実行すると原因がわかります。

> MOTさん
> 返答ありがとうございます。
>
> > delay_ms(100); //0.1秒待ち
> > }
> > return 0;
> > }
> のところを、
>
> delay_ms(100); //0.1秒待ち
>
> if (!(sw == 1))
> break;
> }
> return 0;
> }
> に変更してみましたが、b_opeの処理に入ると、他の処理に移行できません。
> 初歩的な質問で申し訳ありませんが、解決策を教えていただけると助かります。
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: Re2: switch分岐処理
117
: 15/01/31-15:02
ハマ

初めまして。プログラムを拝見し1つ疑問に思ったのですが、int b_ope(void)関数内のwhile(1)ですが、これは無限ループ関数です。これが抜け出せなくて切り替わらないでしょうか?
while(1)をwhile(真値の条件式)を記述すればどうでしょうか。
確かwhile文は、if文とbreak文で組み合わせた式では、前に自分で確認したところ抜け出せなかったと思います。

今回の場合、b_ope()を読み出しているswitch文swが1である時を考えると、while(1)→while(sw==1)とすれば、swが1であるときのみwhile文を実行することになります(swの後は、イコールが2つ入ります)。
違う可能性もありますが試してみてはいかがでしょうか?
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: Re2: switch分岐処理
118
: 15/01/31-18:51
MOT

breakで抜けられますよ。
while(条件)は変数swがhile()内で代入されるようにコーディングされていると正しく動作しません。
この場合,

do{
}while(条件);

がいいでしょう。

if(){break;}は条件によりさまざま処理がてきるので便利です。

> 初めまして。プログラムを拝見し1つ疑問に思ったのですが、int b_ope(void)関数内のwhile(1)ですが、これは無限ループ関数です。これが抜け出せなくて切り替わらないでしょうか?
> while(1)をwhile(真値の条件式)を記述すればどうでしょうか。
> 確かwhile文は、if文とbreak文で組み合わせた式では、前に自分で確認したところ抜け出せなかったと思います。
>
> 今回の場合、b_ope()を読み出しているswitch文swが1である時を考えると、while(1)→while(sw==1)とすれば、swが1であるときのみwhile文を実行することになります(swの後は、イコールが2つ入ります)。
> 違う可能性もありますが試してみてはいかがでしょうか?
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re2: switch分岐処理
124
: 15/02/02-09:34
PICはじめました

ハマ様、MOT様

返信ありがとうございます。教えていただいた2つの方法で試してみました。
@ while (sw ==1)
A do~while (sw ==1)

いずれも、b_opeに入ってしまうと、外部swを切り替えても、他のモードに移行できません。
case 0, case 2, case 3からは、他のモードに移行することができるのですが、case 1 (=b_ope)だけ、他のモードに移行できません。

度々すみませんが、教えていただけると助かります。

以下は、Aの方法で試したときのコードです。
/*b_ope*/
int b_ope(void)
{
//A/Dコンバータ初期設定
OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
ADC_1ANA);

lcd_init(); //LCD初期化
lcd_clear(); //LCD全消去

do{
SetChanADC(ADC_CH4); //チャネル0選択
ConvertADC(); //A/D変換開始
while(BusyADC()); //A/D変換終了待ち
Result = ReadADC(); //データ読み出し

Volt = (Result * 49)/10; //電圧値変換

itostring(4, Result, NUMMSG1+9); //数値を文字に変換
lcd_cmd(0x80); //1行目へ移動
lcd_str(NUMMSG1); //Numberの表示
delay_ms(100); //0.1秒待ち
itostring(4, Volt, NUMMSG2+9); //数値を文字に変換
lcd_cmd(0xC0); //2行目へ移動
lcd_str(NUMMSG2); //Numberの表示
delay_ms(100); //0.1秒待ち
} while(sw==1);
return 0;
}
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: Re2: switch分岐処理
125
: 15/02/02-12:23
ハマ

Gokan様が「Re: switch分岐処理 」に書かれた通りのプログラム構造に書き直した方がよろしいかと思います。A/D変換とLCD表示テストプログラムをそのまま関数として貼り付けてしまうと、毎回A/D変換、LCDの初期化することになり、どこでNGになっているか分らないと思います。int b_ope(void)関数の中身は、できるだけスマートの方がよろしいかと思います。

> ハマ様、MOT様
>
> 返信ありがとうございます。教えていただいた2つの方法で試してみました。
> @ while (sw ==1)
> A do~while (sw ==1)
>
> いずれも、b_opeに入ってしまうと、外部swを切り替えても、他のモードに移行できません。
> case 0, case 2, case 3からは、他のモードに移行することができるのですが、case 1 (=b_ope)だけ、他のモードに移行できません。
>
> 度々すみませんが、教えていただけると助かります。
>
> 以下は、Aの方法で試したときのコードです。
> /*b_ope*/
> int b_ope(void)
> {
> //A/Dコンバータ初期設定
> OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
> ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
> ADC_1ANA);
>
> lcd_init(); //LCD初期化
> lcd_clear(); //LCD全消去
>
> do{
> SetChanADC(ADC_CH4); //チャネル0選択
> ConvertADC(); //A/D変換開始
> while(BusyADC()); //A/D変換終了待ち
> Result = ReadADC(); //データ読み出し
>
> Volt = (Result * 49)/10; //電圧値変換
>
> itostring(4, Result, NUMMSG1+9); //数値を文字に変換
> lcd_cmd(0x80); //1行目へ移動
> lcd_str(NUMMSG1); //Numberの表示
> delay_ms(100); //0.1秒待ち
> itostring(4, Volt, NUMMSG2+9); //数値を文字に変換
> lcd_cmd(0xC0); //2行目へ移動
> lcd_str(NUMMSG2); //Numberの表示
> delay_ms(100); //0.1秒待ち
> } while(sw==1);
> return 0;
> }
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re: switch分岐処理
119
: 15/02/01-09:42
Gokan <gokan@picfun.com>

C言語の全体の基本構成は下記のようにする必要があります。

---------------------------
宣言部
  #includeやConfigurationの記述

main関数部{
  初期化部 一度だけ実行すればよい処理 液晶表示器の初期化など
  while(1){
   繰り返し実行する処理
   サブ関数呼び出し
   繰り返し遅延
 }
}

サブ関数群{

}
-------------------------

この条件でリストを見るとwhile(1)が2回出てくるのは基本構造がおかしいことになります。
つまりC言語のプログラムが2つ構成されているようになっています。

液晶の初期化の部分は最初のwhile(1)の前に記述します。
2回目のwhile(1)は必要ないですね。ここでA/D変換と表示を1回だけ実行すればよいはずです。
また最後の100msの待ちはここではなく最初のwhile(1)のループの中に入れるべきですね。


> PIC18F2320 + C18環境でプログラムのテストをしています。
> switch文を使用して、分岐処理を行っていますが、ある処理に入ってしまうと、他の処理に移行できない問題が発生し、困っています。
>
> switch分を使用して、外部SWによる分岐処理をテストしています。
> まず、LEDを2つ点灯させるプログラムで動作確認を行いました。
> case0 ,1, 2, 3と、外部SW切り替えに対応してLEDの点灯パターンを変更できることが確認できました。
> -> この時のプログラムが、次のプログラムです。
>
> /////////////////////////////SW切り替えて動作確認OK/////////////////////////////
> while(1)
> { 
> sw = PORTA & 0x03;
> switch(sw){
> case 0: a_ope();
> break;
> case 1: b_ope();
> break;
> case 2: LATCbits.LATC4 = 1;
> LATCbits.LATC5 = 0;
> break;
> case 3: break;
> default:break;
> }
> }
> return 0;
> }
>
> /*a_ope*/
> int a_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 0;
> return 0;
> }
>
>
> /*b_ope*/
> int b_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 1;
> return 0;
> }
> ////////////////////////////////////////////////////////////////////////////////
>
> 次に、case 1(b_ope)の動作を変更しました。
> AD変換して、LCDにその値を表示させるというプログラムです。(A/D変換プログラム単体での動作は確認済)
>
> case 1に一度入ってしまうと、外部SWを切り替えても、他のcaseに入れません。
> なぜでしょうか。
>
>
> /////////////////////////////SW切り替えて動作確認NG/////////////////////////////
> while(1)
> { 
> sw = PORTA & 0x03;
> switch(sw){
> case 0: a_ope();
> break;
> case 1: b_ope();
> break;
> case 2: LATCbits.LATC4 = 1;
> LATCbits.LATC5 = 0;
> break;
> case 3: break;
> default:break;
> }
> }
> return 0;
> }
>
> /*a_ope*/
> int a_ope(void)
> {
> LATCbits.LATC4 = 0;
> LATCbits.LATC5 = 0;
> return 0;
> }
>
>
> /*b_ope*/
> int b_ope(void)
> {
> //A/Dコンバータ初期設定
> OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
> ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
> ADC_1ANA);
>
> lcd_init(); //LCD初期化
> lcd_clear(); //LCD全消去
>
> while(1)
> {
> SetChanADC(ADC_CH4); //チャネル4
> ConvertADC(); //A/D変換開始
> while(BusyADC()); //A/D変換終了待ち
> Result = ReadADC(); //データ読み出し
>
> Volt = (Result * 49)/10; //電圧値変換
>
> itostring(4, Result, NUMMSG1+9); //数値を文字に変換
> lcd_cmd(0x80); //1行目へ移動
> lcd_str(NUMMSG1); //Numberの表示
> delay_ms(100); //0.1秒待ち
> itostring(4, Volt, NUMMSG2+9); //数値を文字に変換
> lcd_cmd(0xC0); //2行目へ移動
> lcd_str(NUMMSG2); //Numberの表示
> delay_ms(100); //0.1秒待ち
> }
> return 0;
> }
▲pagetop
タイトル
記事No
投稿日
投稿者
参照先
Re2:switch分岐処理 [解決済]
131
: 15/02/03-14:27
PICはじめました

ADCONレジスタの設定不備に気が付きました。

従来は、次の通り矛盾が生じた設定となっておりました。
ADCON1=0x0F (すべてデジタル設定)
//A/Dコンバータ初期設定 (こちらはAN0のみ使用)
OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
ADC_1ANA);

アナログ入力ピンも変更して、プログラムを変更しました。
ADCON1=0x0D (RA0, 1は、アナログ入力、他はデジタル)
//A/Dコンバータ初期設定 (こちらはAN0,1のみ使用)
OpenADC(ADC_FOSC_8 & ADC_RIGHT_JUST & ADC_8_TAD,
ADC_CH0 & ADC_INT_OFF & ADC_REF_VDD_VSS,
ADC_2ANA);

その結果、無事、A/D変換モードに入っても、他のモードに移行することができました。

皆様ありがとうございました。
▲pagetop

- WebForum -