PICマイコンとPC間でシリアル通信を試みています。
PIC18F2520 + C18環境です。
PCとPIC間でシリアル通信を行うプログラムについて。
PCより、RGBのデータが#xxyyzzという形式で送信されます。
xx: Redの8bitデータ (00~FF)
yy: Greenの8bitデータ (00~FF)
zz: Blueの8bitデータ (00~FF)
データが正しく送信されていることは確認済です。
このデータをPICマイコンで受信して、それぞれred,green,blueの変数に格納する方法はどうすれば良いのでしょうか?
送られてきたデータを色ごと(red/green/blue)に分割して格納する方法が分かりません。教えてください。
シリアル通信
Re: シリアル通信
@picマイコン さんが書きました:このデータをPICマイコンで受信して、それぞれred,green,blueの変数に格納する方法はどうすれば良いのでしょうか?
- 適切なプログラムを書く
- 書いたプログラムをコンパイルする
- それをマイコンに書き込む
- PCとマイコンを適切に接続する
- マイコンを起動して書き込んだプログラムを実行させる
データを単純に受信するプログラムなどが既にあるのであれば、それを提示してください。@picマイコン さんが書きました:送られてきたデータを色ごと(red/green/blue)に分割して格納する方法が分かりません。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: シリアル通信
処理系のことを知らないので予想ですが、こんな感じでしょうか?
(コンパイル・テストしていません)
(コンパイル・テストしていません)
int getDigit(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
switch(c) {
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
return 0;
}
int getData(const char* d) {
return getDigit(d[0]) * 16 + getDigit(d[1]);
}
/* 何かの関数の中 */
char cmnd[7] = {0};
int i;
int Red, Green, Blue;
for (i = 0; i < 6; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
Red = getData(cmnd + 0);
Green = getData(cmnd + 2);
Blue = getData(cmnd + 4);
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: シリアル通信
みけCAT様
返信ありがとうございます。
教えていただいたコードを自分なりに勉強させていただきました。
[私の理解と質問]
①文字列データ→整数化
PCから送付される、XXYYZZのデータは、16進数の文字列データとして送付されるため、
これを整数に置き換える処理と理解しました。
②16進数→10進数化
①で数値に変換した16進数をここで10進数に置き換えていると理解しました。 ③ここの理解ができておりません。
◆cmnd[7]は、PCから送付されるXXYYZZを格納する配列と解釈しましたが、
送られてくるのは6文字なので、cmnd[6]でも[7]でも同じ結果でした。
◆for分は、1バイトずつデータを受信してくるので、これを6文字分(6バイト)受信するプログラムと理解しました。
◆最後の+0, +2 +4が全く理解できていません。(素人で申し訳ありません。)
教えていただけると助かります。
[確認結果]
PC側からデータを送付して、LCDにRed/Green/Blueの結果を表示させましたが、次の結果になってしまいます。
PC側からのデータ送信 FFFFFFの時、
Red/Green/Blue = 15/255/255
PC側からのデータ送信 00FFFFの時、
Red/Green/Blue = 0/15/255
PC側からのデータ送信 FF00FFの時、
Red/Green/Blue = 15/240/15
PC側からのデータ送信 FFFF00の時、
Red/Green/Blue = 15/255/240
なにか、初歩的なミスをしているのでしょうか。
返信ありがとうございます。
教えていただいたコードを自分なりに勉強させていただきました。
[私の理解と質問]
①文字列データ→整数化
PCから送付される、XXYYZZのデータは、16進数の文字列データとして送付されるため、
これを整数に置き換える処理と理解しました。
int getDigit(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
switch(c) {
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
return 0;
}
①で数値に変換した16進数をここで10進数に置き換えていると理解しました。 ③ここの理解ができておりません。
◆cmnd[7]は、PCから送付されるXXYYZZを格納する配列と解釈しましたが、
送られてくるのは6文字なので、cmnd[6]でも[7]でも同じ結果でした。
◆for分は、1バイトずつデータを受信してくるので、これを6文字分(6バイト)受信するプログラムと理解しました。
◆最後の+0, +2 +4が全く理解できていません。(素人で申し訳ありません。)
教えていただけると助かります。
char cmnd[7] = {0};
int i;
int Red, Green, Blue;
for (i = 0; i < 6; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
Red= getData(cmnd + 0);
Geen = getData(cmnd + 2);
Blue= getData(cmnd + 4);
[確認結果]
PC側からデータを送付して、LCDにRed/Green/Blueの結果を表示させましたが、次の結果になってしまいます。
PC側からのデータ送信 FFFFFFの時、
Red/Green/Blue = 15/255/255
PC側からのデータ送信 00FFFFの時、
Red/Green/Blue = 0/15/255
PC側からのデータ送信 FF00FFの時、
Red/Green/Blue = 15/240/15
PC側からのデータ送信 FFFF00の時、
Red/Green/Blue = 15/255/240
なにか、初歩的なミスをしているのでしょうか。
Re: シリアル通信
文字列(null-terminated string)として利用されるかもしれないと思い念のため最後にヌル文字を置きました。picc さんが書きました:◆cmnd[7]は、PCから送付されるXXYYZZを格納する配列と解釈しましたが、
送られてくるのは6文字なので、cmnd[6]でも[7]でも同じ結果でした。
for分ではなくfor文でしょう。picc さんが書きました:◆for分は、1バイトずつデータを受信してくるので、これを6文字分(6バイト)受信するプログラムと理解しました。
comm + 2は&comm[2]と同じ意味になります。picc さんが書きました:◆最後の+0, +2 +4が全く理解できていません。
読み込んだ文字列の途中から渡しています。
データがずれているようです。picc さんが書きました:[確認結果]
PC側からデータを送付して、LCDにRed/Green/Blueの結果を表示させましたが、次の結果になってしまいます。
PC側からのデータ送信 FFFFFFの時、
Red/Green/Blue = 15/255/255
PC側からのデータ送信 00FFFFの時、
Red/Green/Blue = 0/15/255
PC側からのデータ送信 FF00FFの時、
Red/Green/Blue = 15/240/15
PC側からのデータ送信 FFFF00の時、
Red/Green/Blue = 15/255/240
なにか、初歩的なミスをしているのでしょうか。
本当にFFFFFFのようなデータを入力したのですか?
最初に書いてある#FFFFFFのようなデータではないのですか?
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: シリアル通信
みけCAT様
返信ありがとうございます。
次のコードに書き換えたことで、正しくRGBの値をLCDに表示させることができました。
ご報告と質問がございます。
[ご報告]
cmnd[7]配列にPCからのデータが格納されると思いますが、
次のコードでできたということは、
cmnd[7] = { ??, X1, X2, Y1,Y2, Z1,Z2} というように先頭に何か文字が入ってしまっているのだと思います。
Red=X1X2
Green=Y1Y2
Blue=Z1Z2 となっています。
次のコードの場合は、
cmnd[7] = { ??, X1, X2, Y1,Y2, Z1} となっており、
Red=0X1
Green=X2Y1
Blue=Y2Z1 となってしまっていました。
つまり先頭(??)に0が1文字入ってしまっているようです。(送信側のプログラムを確認してみます。)
[ご質問]
ここまででPCからのデータをLCDに表示させることはできたのですが、データの受信が一度しかできません。
次のコードでプログラムを記述していますが、一度PCからデータを送信すると、次のデータを受け付けてくれません。
期待するのは、PCからデータを送ると、その都度値をLCDに表示させる動作です。
while(1)の中で常にPCからのデータを受信しているつもりなのですが…何か間違えているのでしょうか。
返信ありがとうございます。
次のコードに書き換えたことで、正しくRGBの値をLCDに表示させることができました。
ご報告と質問がございます。
[ご報告]
cmnd[7]配列にPCからのデータが格納されると思いますが、
次のコードでできたということは、
cmnd[7] = { ??, X1, X2, Y1,Y2, Z1,Z2} というように先頭に何か文字が入ってしまっているのだと思います。
Red=X1X2
Green=Y1Y2
Blue=Z1Z2 となっています。
for (i = 0; i < 7; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
Red= getData(cmnd + 1);
Green = getData(cmnd + 3);
Blue= getData(cmnd + 5);
次のコードの場合は、
cmnd[7] = { ??, X1, X2, Y1,Y2, Z1} となっており、
Red=0X1
Green=X2Y1
Blue=Y2Z1 となってしまっていました。
つまり先頭(??)に0が1文字入ってしまっているようです。(送信側のプログラムを確認してみます。)
for (i = 0; i < 6; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
Red= getData(cmnd + 0);
Green = getData(cmnd + 2);
Blue= getData(cmnd + 4);
[ご質問]
ここまででPCからのデータをLCDに表示させることはできたのですが、データの受信が一度しかできません。
次のコードでプログラムを記述していますが、一度PCからデータを送信すると、次のデータを受け付けてくれません。
期待するのは、PCからデータを送ると、その都度値をLCDに表示させる動作です。
while(1)の中で常にPCからのデータを受信しているつもりなのですが…何か間違えているのでしょうか。
while(1){
mode = PORTD & 0x70;
switch(mode){
case 0x50:
manual_mode();
default:
break;
}
}
CloseUSART();
int manual_mode(void)
{
char cmnd[7] = {0};
int i;
int Red, Green, Blue;
for (i = 0; i < 6; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
Red= getData(cmnd + 0);
Green = getData(cmnd + 2);
Blue= getData(cmnd + 4);
}
Re: シリアル通信
みけCAT様に教えていただいたコードでPCからのデータ受信はできるようになりましたが、次の問題があります。
①PC側から送信できるのは、2回まで。
1回目に"FF0000"というデータを送信すると、LCDの表示は、
RED GREEN BLUE
100% 0% 0% と正しく受信できているのですが、
2回目に同じデータ"FF0000"を送信すると、LCDの表示は、
RED GREEN BLUE
0% 100% 0% とデータがずれてしまいます。
3回目以降は、送信しても、何も変化しません。
原因が分からず困っております。
目的の動作は、PC側からデータが送られてくるたびに、LCDの表示が変化することです。
①PC側から送信できるのは、2回まで。
1回目に"FF0000"というデータを送信すると、LCDの表示は、
RED GREEN BLUE
100% 0% 0% と正しく受信できているのですが、
2回目に同じデータ"FF0000"を送信すると、LCDの表示は、
RED GREEN BLUE
0% 100% 0% とデータがずれてしまいます。
3回目以降は、送信しても、何も変化しません。
原因が分からず困っております。
目的の動作は、PC側からデータが送られてくるたびに、LCDの表示が変化することです。
while(1){
for (i = 0; i < 6; i++) {
while (!DataRdyUSART());
cmnd[i] = getcUSART();
}
//cmnd[]からR/G/B各データを取り出し %変換
vol_R= getData(&cmnd[0])*100/255; //vol_R= getData(cmnd + 0);
vol_G= getData(&cmnd[2])*100/255; //vol_G = getData(cmnd + 2);
vol_B= getData(&cmnd[4])*100/255; //vol_B= getData(cmnd + 4);
lcd_cmd(0x80); //1行目へ移動
lcd_printf(RGB);
lcd_cmd(0xC0); //2行目へ移動
sprintf(&str[0],(const far rom char *)"%3d%% %3d%% %3d%%",vol_R,vol_G,vol_B); // %f(浮動少数)は未サポート
lcd_printf(&str[0]); //vol_R vol_G vol_B表示
delay_ms(100); //0.1秒待ち
}
}
int getDigit(char c) {
if ('0' <= c && c <= '9') {
return c - '0';
}
switch(c) {
case 'a': case 'A': return 10;
case 'b': case 'B': return 11;
case 'c': case 'C': return 12;
case 'd': case 'D': return 13;
case 'e': case 'E': return 14;
case 'f': case 'F': return 15;
}
return 0;
}
int getData(const char* d) {
return getDigit(d[0]) * 16 + getDigit(d[1]);
}
Re: シリアル通信
LCDなどできちんとforループを抜けることができているか、できていないな、何文字目で詰まっているかを調べてみてください。
複雑な問題?マシンの性能を上げてOpenMPで殴ればいい!(死亡フラグ)
Re: シリアル通信
みけCAT様、can110様
ありがとうございます。
送信側プログラム(vb)を見直したところ、CR+LFを付加して送信していました。
そのため、受信バイト数を8バイトにしたところ、目的の動作を行うことができました。
本当にありがとうございました。次は、マイコン同士の送受信にチャレンジしてみます。
ありがとうございます。
送信側プログラム(vb)を見直したところ、CR+LFを付加して送信していました。
そのため、受信バイト数を8バイトにしたところ、目的の動作を行うことができました。
本当にありがとうございました。次は、マイコン同士の送受信にチャレンジしてみます。