ページ 1 / 1
シリアル通信から抜けられない
Posted: 2015年12月10日(木) 14:54
by picc
Serial通信から抜けられません。
次に示すコードで、
①USART通信
②A/D変換 のプログラムを実施しています。
①の動作から②の動作
②の動作から①の動作 へ切り替えた際(スイッチによる切替)、切替+USART通信でデータを受信しないとモードを切り替えることができません。
今のプログラムだと、モード(①、②)を切り替えた際、PC側(USART通信の相手)からデータを送ってあげないと、モードが切り替わりません。
なにがいけないのでしょうか。
コード:
while(1){
mode = PORTD & 0x70;
switch(mode){
case 0x50:
manual_mode(); //USART通信
break;
case 0x40:
auto_mode();
break;
default:
alarm_clock();
break;
}
}
//①の動作
int manual_mode(void)
{
getsUSART(cmnd,8);
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
//②の動作
int auto_mode(void)
{
SetChanADC(ADC_CH0); //チャンネルを切り替える場合
ConvertADC();
while( BusyADC()); //AD変換が終わるまで待つ
ADR = ReadADC(); //AD変換値読込み
SetChanADC(ADC_CH1); //チャンネルを切り替える場合
ConvertADC();
while( BusyADC()); //AD変換が終わるまで待つ
ADG = ReadADC(); //AD変換値読込み
SetChanADC(ADC_CH2); //チャンネルを切り替える場合
ConvertADC();
while( BusyADC()); //AD変換が終わるまで待つ
ADB = ReadADC(); //AD変換値読込み
vR = (double)ADreadR / 10.13; //exchange 10bit for %
vG = (double)ADreadG / 10.13; //exchange 10bit for %
vB = (double)ADreadB / 10.13; //exchange 10bit for %
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",vR,vG,vB);
lcd_printf(&str[0]); //vR vG vB表示
delay_ms(100); //0.1秒待ち
}
Re: シリアル通信から抜けられない
Posted: 2015年12月10日(木) 18:24
by みけCAT
定義がわからない関数があるので断定はできませんが、データを受信するまでブロックする処理があるのがいけないと予想できます。
例えば、もしgetsUSART関数が
電子工作室に書かれている
永久に受信完了を待ちタイムアウトは無い。
という仕様であるならば、ここで受信するまでブロックするのでモード切り替えの処理に戻れないのでしょう。
Re: シリアル通信から抜けられない
Posted: 2015年12月11日(金) 08:11
by picc
みけCAT様
いつも回答ありがとうございます。
私も仕様を確認しました。
永久に待ち続けるということは、スイッチにより動作モードを切り替えても、USARTのモードでデータを受信しない限り、他のモードに移行できないということになりますね。
モードの切り替えは断念するしかないでしょうか。
Re: シリアル通信から抜けられない
Posted: 2015年12月11日(金) 09:22
by みけCAT
ブロックするのが問題なので、素直に考えればブロックしないようにすればいいでしょう。
例えばこんな感じかな?(コンパイル・テストしていません)
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
if (cnt < 8) return; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
オフトピック
シリアル通信を使わないモードの時にも入力を読み捨てる処理を置いておかないと、もしかしたらそっちのモードにいる時にデータが来るとバッファが溢れて、戻ってきた時にうまく動作しないかも?
Re: シリアル通信から抜けられない
Posted: 2015年12月11日(金) 13:12
by picc
みけCAT様
返信ありがとうございます。
早速試してみました。
①USART通信
②A/D変換 のプログラムを実施していますが
①の動作ができなくなってしまいました。
しかし、①の状態から②の状態へモードを切り替えることができました。
スイッチで①のモードにしても、PCからのデータがLCDに表示されません。
(おかしなデータになっているとかではなく。LCDの表示が全くされない)
ますます分からなくなってしまいました。
Re: シリアル通信から抜けられない
Posted: 2015年12月11日(金) 22:10
by みけCAT
すいません、戻り値の型がvoidでないのにreturnで戻り値を書くのを忘れていました。
修正版
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
picc さんが書きました:スイッチで①のモードにしても、PCからのデータがLCDに表示されません。
(おかしなデータになっているとかではなく。LCDの表示が全くされない)
自分で原因を調べる努力はしていますか?
例えば、return 0;の前でcmndやcntの値を表示する処理を入れてみるとか。
Re: シリアル通信から抜けられない
Posted: 2015年12月14日(月) 09:00
by picc
みけCAT様
①②③の確認を行ないました。
私としては、②と③は、デバッグのためにLCD表示を追加しただけで、処理内容は①も②も③も同じだと考えています。
しかし、結果は、②だけPCからのデータを受信する(1回きりですが…)という結果になりました。
デバッグ能力が乏しく申し訳ありませんが、この状況から分かることを教えていただけると助かります。
①PCからデータを送信してもLCDに何も表示されない
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
②return 0;の前で、cmndをLCDに表示
PCからFFDDBB+CR+LFを送信すると、LCDにもFFDDBB+CR+LFが表示される
この状態からモードの移行を試しました。
manual mode→auto mode 動作OK
その後、auto mode → manual modeに移行して、PCからデータを送信すると、今度はデータを受け付けない。(LCDの表示も変化しない)
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
lcd_cmd(0x80); //1行目へ移動
lcd_printf(cmnd);
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
③return 0;の前で、cntをLCDに表示
cntを表示させてみたが、LCDには何も表示されない(PCから送付したデータは、FFDDBB+CR+LF)
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
lcd_cmd(0x80); //1行目へ移動
lcd_printf(cnt);
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
Re: シリアル通信から抜けられない
Posted: 2015年12月14日(月) 10:44
by みけCAT
picc さんが書きました:③return 0;の前で、cntをLCDに表示
cntを表示させてみたが、LCDには何も表示されない(PCから送付したデータは、FFDDBB+CR+LF)
ライブラリの仕様を知らないのですが、これは本当にcntをLCDに表示するコードなのですね?
lcd_printfはprintfに近い仕様なのではないのですか?
デタラメな「アドレス」をlcd_printfに渡してデタラメな挙動をさせるコードではないのですね?
Re: シリアル通信から抜けられない
Posted: 2015年12月15日(火) 12:13
by picc
みけCAT様
大変失礼しました。cntのLCD表示について間違えた処理をしていました。すみません。
コードを添付して状況を報告させていただきます。
cntをLCDに表示させてみましたが、cntの値が2と表示されることが多いです。
(多いというのは、まれに0や3や7など、他の値が表示されることがあります。)
(LCDの2行目に受信データを表示させていますが、cntの値と、受信した文字数は一致しています。)
なぜ、受信文字数が毎回変わってしまうのでしょうか。
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
lcd_cmd(0x80); //1行目へ移動
sprintf(&str[0],(const far rom char *)"%4d",cnt); // %f(浮動少数)は未サポート
lcd_printf(&str[0]); //vol_R vol_G vol_B表示
lcd_cmd(0xC0); //2行目へ移動
lcd_printf(cmnd);
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
}
Re: シリアル通信から抜けられない
Posted: 2015年12月15日(火) 13:42
by みけCAT
picc さんが書きました:cntをLCDに表示させてみましたが、cntの値が2と表示されることが多いです。
(多いというのは、まれに0や3や7など、他の値が表示されることがあります。)
(LCDの2行目に受信データを表示させていますが、cntの値と、受信した文字数は一致しています。)
なぜ、受信文字数が毎回変わってしまうのでしょうか。
データが来るのが速すぎて、データを読む前に次のデータに上書きされている可能性が考えられます。
もしそうなら、受信時に割り込みをかける機能があれば割り込みを使ってデータを十分大きいバッファに入れ、そこから読み出すようにすると良いでしょう。
とりあえず、PC側の送信ソフトでデータをゆっくり(例えば、1秒おきに1バイトずつ)送信するようにしてみてください。
Re: シリアル通信から抜けられない
Posted: 2015年12月15日(火) 16:04
by picc
みけCAT様
ありがとうございます。
早速送信側のプログラムを変えてみました。
結果は、
起動後、1回目のデータ受信は成功
しかし、2回目以降はデータ受信できません。(LCDに表示させているcnt, cmndの値も変化なし)
今回私がトライしているプログラムは、
①PCからデータを送信 (R/G/Bのデータ)
②PICマイコンでデータを受信
③受信したデータをLCDに表示
④受信したデータをフルカラーLEDに表示 (ソフトウェアPWMを使用)
④の動作は以前からできていて、今もPCからのデータ受信確認のために、フルカラーLEDの点灯状況を見ています。
今回のプログラム(バイト数リセット)を追加した所、フルカラーLEDが点滅してしまうようになりました。
USARTの割り込みもあるのですが、
ソフトウェアPWMのタイマ割り込み、外部入力の割り込みを併用して使っているため、これ以上割り込みの追加ができるか不明です。(勉強してみます)
今現在はPCからデータを送っていますが、最終的にはPICマイコンからPICマイコンにデータを送りたいと考えています。
何か、良い方法がありましたら、ご教授いただけると幸いです。
送信プログラム(vb)は、次の通りです。
コード:
Dim Red, Green, Blue As Integer
Red = trbRed.Value
Green = trbGreen.Value
Blue = trbBlue.Value
Dim x, y, z As String
x = Red.ToString("X2")
y = Green.ToString("X2")
z = Blue.ToString("X2")
'strSend = "O" + lblCode.Text
'文字列の末尾がChr(13)+Chr(10)と一致しなかったら、文字列にChr(13)とChr(10)を追加する
If Not z.EndsWith(Chr(13) + Chr(10)) Then
z += Chr(13) + Chr(10)
End If
Try
'文字列の送信
Dim sdat1() As Byte = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes(x)
SerialPort1.Write(sdat1, 0, sdat1.GetLength(0))
'1000msec停止
System.Threading.Thread.Sleep(1000)
'文字列の送信
Dim sdat2() As Byte = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes(y)
SerialPort1.Write(sdat2, 0, sdat2.GetLength(0))
'1000msec停止
System.Threading.Thread.Sleep(1000)
'文字列の送信
Dim sdat3() As Byte = System.Text.Encoding.GetEncoding("SHIFT-JIS").GetBytes(z)
SerialPort1.Write(sdat3, 0, sdat3.GetLength(0))
'1000msec停止
System.Threading.Thread.Sleep(1000)
Catch ex As Exception
MessageBox.Show(ex.Message, "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error)
End Try
Re: シリアル通信から抜けられない
Posted: 2015年12月15日(火) 17:11
by picc
みけCAT様
たびたびすみません。
↓に示すコードで解決することができました。
①PC側の送信プログラム修正
CR+LFは不要なので、削除しました。
②フルカラーLEDが点滅…という話をさせていただきましたが、
R,G,Bのデータを取得するコードの位置が間違えておりましたので、↓に示すコードの通り修正しました。
→みけCAT様のコードを良く理解していなかったことが原因です。
送信側の時間の問題もありますが、時間調整は自分で行ってみたいと思います。
次は、PICマイコン同士で同様のプログラムにチャレンジしてみたいと思います。
コード:
int cnt = 0; /* 何文字読み込んだか */
int manual_mode(void)
{
if(DataRdyUSART()) cmnd[cnt++] = ReadUSART(); /* データがあったら1文字読み込む */
//lcd_cmd(0x80); //1行目へ移動
//sprintf(&str[0],(const far rom char *)"%4d",cnt); // %f(浮動少数)は未サポート
//lcd_printf(&str[0]); //vol_R vol_G vol_B表示
//lcd_cmd(0xC0); //2行目へ移動
//lcd_printf(cmnd);
R= getData(&cmnd[0])*100/255;
G= getData(&cmnd[2])*100/255;
B= getData(&cmnd[4])*100/255;
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",R,G,B);
lcd_printf(&str[0]);
delay_ms(100);
if (cnt < 8) return 0; /* まだ読み込み終わっていなければそのデータを使う処理に行かない */
cnt = 0; /* 読み込んだバイト数をリセットする */
}