質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

Q&A

解決済

1回答

388閲覧

H8/3067を使用したパケット送受信処理について

TOMO6181

総合スコア39

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

マイコン

マイクロコンピュータの略で、CPUにマイクロプロセッサを用いたコンピュータのこと。家電製品、電磁機器などの制御に用いられています。単体でコンピュータとしての機能を一通り備えています。 現代のパーソナルコンピュータに近く、同時期のメインフレームやミニコンピュータと比べ、小さいことが特徴です。

0グッド

0クリップ

投稿2017/11/15 15:34

「H8マイコンによるネットワーク・プログラミング」(技術評論社)に記載してある
「4.4 ARP」のリストex4_2.cのコードについての質問です。

前提条件として、使用しているマイコンはH8/3067、パケット送受信のインターフェースはRTL8019AS、
使用している言語はC言語です。

今回動作させようとしているプログラムは、マイコンからPCにARPリクエストを送信し、
PCからARPリプライが返って来た時に、ARPリプライからPCのMACアドレスを取得し、
マイコン基板のLCDに表示させるものです。
本に記載されているコードは、ex4_2.cのように、global_vabiables.hに定義されたグローバル変数packetを、
ARPリクエストを行う関数(ARP_request)、パケットの受信を行う関数(packet_receive)に渡しています。
ここで、ARP_request、packet_receive関数に渡す引数を、main関数内でローカルに定義したsend_ch、rcv_chを
引数として渡すようコードを変更すると、ARPリプライが返ってこなくなります。
ARP_requestでは、引数にパケット送信のデータを格納、packet_receive内では引数に受信データを格納しているだけ
なので、引数をグローバル変数にする必要はなさそうに見えますが、ローカル変数に変えると予想通りの動作をしなくなる
理由が分からず困っています。
分かる方おられましたら、御回答お願い致します。

C言語

1/* global_variables.h */ 2unsigned char src_IP[4]; /* 送信元IPアドレス */ 3unsigned char src_MAC[6]; /* 送信元MACアドレス */ 4unsigned char dst_IP[4]; /* 宛先IPアドレス */ 5unsigned char dst_MAC[6]; /* 宛先MACアドレス */ 6unsigned char packet[256]; /* 受信パケットのデータ */

C言語

1/* ex4_2.c(本に記載してあるコード) */ 2#include "H8_register.h" /* H8/3067のレジスタ */ 3#include "RTL8019AS_register.h" /* RTL8019ASのレジスタ */ 4#include "packet_definition.h" /* パケットの定義 */ 5#include "global_variables.h" /* グローバル変数の定義 */ 6#include "H8_register_function.h" /* H8/3067のレジスタの設定 */ 7#include "delay_function.h" /* 時間待ちの関数 */ 8#include "LCD_function.h" /* SC1602Bの関数 */ 9#include "NIC_function.h" /* RTL8019ASの関数 */ 10#include "matrix_key_function.h" /* マトリクス・キーの関数 */ 11#include "utility_function.h" /* そのほかの関数 */ 12#include "ARP_function.h" /* ARPの関数 */ 13 14void main(void) 15{ 16 unsigned short i; 17 unsigned char packet_type; 18 char str_IP[16]; 19 char str_MAC[13]; 20 ARP_PACKET *arp_packet; 21 22 H8_register_init(); /* H8/3067のレジスタの設定 */ 23 LCD_init(); /* SC1602Bの初期化 */ 24 NIC_init(); /* RTL8019ASの初期化 */ 25 26 /* 送信元IPアドレスの設定 */ 27 src_IP[0] = 192; 28 src_IP[1] = 168; 29 src_IP[2] = 0; 30 src_IP[3] = 100 + (P2DR & 0x07); /* ディップ・スイッチによって送信元IPアドレスを設定する */ 31 32 /* 宛先IPアドレスの設定 */ 33 dst_IP[0] = 192; 34 dst_IP[1] = 168; 35 dst_IP[2] = 0; 36 dst_IP[3] = 2; 37 38 LCD_clear(); /* 表示クリア */ 39 40 LCD_control(0x80); /* カーソルを0行目の先頭に移動する */ 41 IP_to_str(dst_IP, str_IP); /* dst_IPをstr_IP(文字列)に変換する */ 42 LCD_print(str_IP); /* 液晶ディスプレイにstr_IPを表示する */ 43 44 delay_ms(2000); /* 2000ms(2秒)の時間待ち */ 45 46 ARP_request(packet); /* ARPリクエスト */ 47 48 packet_type = 0; /* packet_typeを0にする */ 49 do 50 { 51 if (packet_receive(packet) != 1) /* パケットを受信したとき */ 52 { 53 arp_packet = (ARP_PACKET *)packet; /* packetをARP_PACKET構造体に当てはめる */ 54 if ((arp_packet -> eth_ethernet_type == 0x0806) && 55 /* ARPのパケットのとき */ 56 (IP_compare(arp_packet -> arp_dst_IP, src_IP) == 0) && 57 /* パケットに記述されている宛先IPアドレスが送信元IPアドレスに一致したとき */ 58 (arp_packet -> arp_operation == 2) 59 /* ARPリプライのとき */ 60 ) 61 { 62 for (i = 0; i < 6; i++) 63 { 64 dst_MAC[i] = arp_packet -> arp_src_MAC[i]; 65 /* パケットに記述されている送信元MACアドレスをdst_MACに格納する */ 66 } 67 packet_type = 'a'; /* packet_typeを'a'にする */ 68 } 69 } 70 } while (packet_type != 'a'); /* packet_typeが'a'になるまで待つ */ 71 72 LCD_control(0xC0); /* カーソルを1行目の先頭に移動する */ 73 MAC_to_str(dst_MAC, str_MAC); /* dst_MACをstr_MAC(文字列)に変換する */ 74 LCD_print(str_MAC); /* 液晶ディスプレイにstr_MACを表示する */ 75 76 while (1) /* 無限ループ */ 77 { 78 /* 何もしない */ 79 } 80}

C言語

1/* ex4_2.c(ARP_request、packet_receiveの引数をローカル変数に変えたもの。ヘッダーは本と同一。このコードでは動かない。) */ 2 3void main(void) 4{ 5 unsigned char send_ch[256]; 6 unsigned char rcv_ch[256]; 7 unsigned short i; 8 unsigned char packet_type; 9 char str_IP[16]; 10 char str_MAC[13]; 11 ARP_PACKET *arp_packet; 12 13 H8_register_init(); /* H8/3067のレジスタの設定 */ 14 LCD_init(); /* SC1602Bの初期化 */ 15 NIC_init(); /* RTL8019ASの初期化 */ 16 17 /* 送信元IPアドレスの設定 */ 18 src_IP[0] = 192; 19 src_IP[1] = 168; 20 src_IP[2] = 0; 21 src_IP[3] = 100 + (P2DR & 0x07); /* ディップ・スイッチによって送信元IPアドレスを設定する */ 22 23 /* 宛先IPアドレスの設定 */ 24 dst_IP[0] = 192; 25 dst_IP[1] = 168; 26 dst_IP[2] = 0; 27 dst_IP[3] = 2; 28 29 LCD_clear(); /* 表示クリア */ 30 31 LCD_control(0x80); /* カーソルを0行目の先頭に移動する */ 32 IP_to_str(dst_IP, str_IP); /* dst_IPをstr_IP(文字列)に変換する */ 33 LCD_print(str_IP); /* 液晶ディスプレイにstr_IPを表示する */ 34 35 delay_ms(2000); /* 2000ms(2秒)の時間待ち */ 36 37 ARP_request(send_ch); /* ARPリクエスト(引数をローカル変数に変更) */ 38 39 packet_type = 0; /* packet_typeを0にする */ 40 do 41 { 42 if (packet_receive(rcv_ch) != 1) /* パケットを受信したとき(引数をローカル変数に変更) */ 43 { 44 arp_packet = (ARP_PACKET *)rcv_ch; /* rcv_chをARP_PACKET構造体に当てはめる(ローカル変数に変更) */ 45 if ((arp_packet -> eth_ethernet_type == 0x0806) && 46 /* ARPのパケットのとき */ 47 (IP_compare(arp_packet -> arp_dst_IP, src_IP) == 0) && 48 /* パケットに記述されている宛先IPアドレスが送信元IPアドレスに一致したとき */ 49 (arp_packet -> arp_operation == 2) 50 /* ARPリプライのとき */ 51 ) 52 { 53 for (i = 0; i < 6; i++) 54 { 55 dst_MAC[i] = arp_packet -> arp_src_MAC[i]; 56 /* パケットに記述されている送信元MACアドレスをdst_MACに格納する */ 57 } 58 packet_type = 'a'; /* packet_typeを'a'にする */ 59 } 60 } 61 } while (packet_type != 'a'); /* packet_typeが'a'になるまで待つ */ 62 63 LCD_control(0xC0); /* カーソルを1行目の先頭に移動する */ 64 MAC_to_str(dst_MAC, str_MAC); /* dst_MACをstr_MAC(文字列)に変換する */ 65 LCD_print(str_MAC); /* 液晶ディスプレイにstr_MACを表示する */ 66 67 while (1) /* 無限ループ */ 68 { 69 /* 何もしない */ 70 } 71}

C言語

1/* NIC_function.h(packet_receive以外の関数は記載を省略) */ 2unsigned char packet_receive(unsigned char *packet) 3{ 4 unsigned short i; 5 unsigned short size; 6 unsigned char data; 7 unsigned char size_H, size_L; 8 unsigned char boundary_page, start_page, current_page; 9 unsigned char header[4]; 10 11 NIC_write(CR, 0x22); /* レジスタ・ページ0 */ 12 boundary_page = NIC_read(BNRY); /* BNRYを読み取る */ 13 NIC_write(CR, 0x62); /* レジスタ・ページ1 */ 14 current_page = NIC_read(CURR); /* CURRを読み取る */ 15 16 if (current_page < boundary_page) 17 { 18 current_page += (0x60 - 0x46); /* 受信バッファがリング・バッファであることを考慮する */ 19 } 20 if (current_page == boundary_page + 1) /* 受信パケットの判定 */ 21 { 22 return 1; /* 受信パケットなし */ 23 } 24 25 start_page = boundary_page + 1; /* 受信パケットの開始ページ */ 26 if (start_page == 0x60) 27 { 28 start_page = 0x46; /* 受信バッファがリング・バッファであることを考慮する */ 29 } 30 31 NIC_write(CR, 0x22); /* レジスタ・ページ0 */ 32 NIC_write(RBCR0, 4); /* フレーム管理ヘッダのサイズ(下位バイト) */ 33 NIC_write(RBCR1, 0); /* フレーム管理ヘッダのサイズ(上位バイト) */ 34 NIC_write(RSAR0, 0x00); /* フレーム管理ヘッダの先頭アドレス(下位バイト) */ 35 NIC_write(RSAR1, start_page); /* フレーム管理ヘッダの先頭アドレス(上位バイト) */ 36 NIC_write(CR, 0x0A); /* リモートDMA読み取りを許可する */ 37 for (i = 0; i < 4; i++) 38 { 39 header[i] = NIC_read(RDMAP); /* フレーム管理ヘッダを読み取る */ 40 } 41 do 42 { 43 data = NIC_read(ISR); /* ISRを読み取る */ 44 } while ((data & 0x40) == 0x00); /* リモートDMAが停止するのを待つ */ 45 46 NIC_write(CR, 0x22); /* レジスタ・ページ0 */ 47 size_L = header[2]; /* 受信パケットのサイズ(下位バイト) */ 48 size_H = header[3]; /* 受信パケットのサイズ(上位バイト) */ 49 size = ((unsigned short)size_H << 8) + (unsigned short)size_L; /* 受信パケットのサイズ */ 50 NIC_write(RBCR0, size_L); /* 受信パケットのサイズ(下位バイト) */ 51 NIC_write(RBCR1, size_H); /* 受信パケットのサイズ(上位バイト) */ 52 NIC_write(RSAR0, 0x00); /* 受信パケットの先頭アドレス(下位バイト) */ 53 NIC_write(RSAR1, start_page); /* 受信パケットの先頭アドレス(上位バイト) */ 54 NIC_write(CR, 0x0A); /* リモートDMA読み取りを許可する */ 55 for (i = 0; i < 4; i++) 56 { 57 NIC_read(RDMAP); /* ダミー・データを読み取る */ 58 } 59 for (i = 0; i < (size - 4); i++) 60 { 61 packet[i] = NIC_read(RDMAP); /* 受信バッファからパケットのデータを読み取る */ 62 63 if (i >= 256) /* パケットのサイズが256byteよりも大きいとき */ 64 { 65 NIC_read(RDMAP); /* ダミー・データを読み取る */ 66 } 67 } 68 do 69 { 70 data = NIC_read(ISR); /* ISRを読み取る */ 71 } while ((data & 0x40) == 0x00); /* リモートDMAが停止するのを待つ */ 72 73 NIC_write(CR, 0x22); /* レジスタ・ページ0 */ 74 boundary_page = current_page - 1; 75 if (boundary_page >= 0x60) 76 { 77 boundary_page -= (0x60 - 0x46); /* 受信バッファがリング・バッファであることを考慮する */ 78 } 79 NIC_write(BNRY, boundary_page); /* BNRYを更新する */ 80 81 return 0; 82}

C言語

1/* ARP_function.h(ARP_request以外の関数は記載を省略) */ 2void ARP_request(unsigned char *packet) 3{ 4 unsigned short i; 5 ARP_PACKET *arp_packet; 6 7 arp_packet = (ARP_PACKET *)packet; /* packetをARP_PACKET構造体に当てはめる */ 8 9 for (i = 0; i < 6; i++) 10 { 11 arp_packet -> eth_dst_MAC[i] = 0xFF; /* ブロードキャスト・アドレス */ 12 } 13 for (i = 0; i < 6; i++) 14 { 15 arp_packet -> eth_src_MAC[i] = src_MAC[i]; /* 送信元MACアドレス */ 16 } 17 arp_packet -> eth_ethernet_type = 0x0806; /* 上位プロトコルの種類(ARP) */ 18 arp_packet -> arp_hardware_type = 0x0001; /* ネットワークの物理媒体の種類(イーサネット) */ 19 arp_packet -> arp_protocol_type = 0x0800; /* 上位プロトコルの種類(IP) */ 20 arp_packet -> arp_hardware_length = 6; /* ネットワークの物理媒体のアドレス長(MACアドレス) */ 21 arp_packet -> arp_protocol_length = 4; /* 上位プロトコルのアドレス長(IPv4) */ 22 arp_packet -> arp_operation = 1; /* ARPの動作(ARPリクエスト) */ 23 for (i = 0; i < 6; i++) 24 { 25 arp_packet -> arp_src_MAC[i] = src_MAC[i]; /* 送信元MACアドレス */ 26 } 27 for (i = 0; i < 4; i++) 28 { 29 arp_packet -> arp_src_IP[i] = src_IP[i]; /* 送信元IPアドレス */ 30 } 31 for (i = 0; i < 6; i++) 32 { 33 arp_packet -> arp_dst_MAC[i] = 0x00; /* 宛先MACアドレス */ 34 } 35 for (i = 0; i < 4; i++) 36 { 37 arp_packet -> arp_dst_IP[i] = dst_IP[i]; /* 宛先IPアドレス */ 38 } 39 40 packet_send(packet, 60); /* パケットのサイズを60byteに指定して送信する */ 41}

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

TOMO6181さん、

ローカル変数宣言が main関数内で

void main(void) { unsigned char send_ch[256]; unsigned char rcv_ch[256];

としているので、スタックからメモリを確保しようとしていますが、スタックサイズは足りていますか?

とりあえず、以下のように、staticをつけて、動作するか、確認してみてください。

static unsigned char send_ch[256]; static unsigned char rcv_ch[256];

投稿2017/11/15 18:22

mt08

総合スコア1825

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

TOMO6181

2017/11/16 16:05

仰られるようにローカル変数にstaticを付けたら動作しました。 スタックサイズのことを完全に失念していました。 H8/3067のスタック領域にデータを確保する十分なサイズがなかったようです。 staticを付けたローカル変数はスタック領域ではなく、データ領域にデータが確保されるから 動作したのですね。 御回答ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問