

PICとpySerialを利用してシリアル通信を行うプログラムを作成しています。  
以下のようなプログラムを実行したところ、”IndexError: index out of range”というエラーが発生しています。  
解決方法を教えていただきたいです。

[code]

    #import sys
    import serial
    from serial import SerialException
    import datetime
    
    # 秒数を時分秒に分解
    def get_hms(td):
        m,s = divmod(td.seconds, 60)
        h,m = divmod(m,60)
        return (h,m,s)
    
    # datetimeの英語フォーマット変換
    def get_endate(dt):
        weekList = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat' 'Sun']
        monthList = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
        weekNo = dt.weekday()
        monthNo = dt.month
    
        s = '{0} {1} {2}\n'.format(
                    weekList[weekNo],
                    monthList[monthNo - 1],
                    dt.strftime("%d %H:%M:%S %Y"))
        return s
    
    
    # プログラム開始
    N_Smpl = 10000
    N_data = 20000
    
    #argv = sys.argv;
    #######exit()
    
    fname_out = "data1.txt"     # 保存先ファイル
    portName = "COM3    "   # COMポートの番号を保存する変数
    BaudRate = int(115200) # baud rateを保存する変数
    flowcontrol = "CTSRTS"  # フロー制御の種類を保存する変数
    
    if(flowcontrol != "CTSRTS" and flowcontrol != "none"):
        print("フロー制御の種類が不正です．CTSRTS,noneのいずれかを指定してください")
        print("\n\n")
        #print("%s max min step blk fname1  fname2 comN baud flow\n\n", argv[0])
        print("     max   Eb/Noの最大値\n")
        print("     min   Eb/Noの最小値\n")
        print("     step  Eb/Noのステップ値\n")
        print("     blk   送信ブロック数\n")
        print("     fname1 出力ファイル名\n")
        print("     fname2 出力ファイル名(PICから)\n")
        print("     comN   使用するCOMポートの番号 例:COM1\n")
        print("     baud   ボーレートの値\n")
        print("     flow   使用するフロー制御の種類 CTSRTS,noneのいずれか\n")
        exit()
    
    ByteSize = serial.EIGHTBITS     # ストップビット長
    Parity = serial.PARITY_NONE     # パリティ
    StopBits = serial.STOPBITS_ONE  # ストップビット
    RtsCts = False                  # RTSCTS 有効/無効
    if(flowcontrol == "CTSRTS"):
        RtsCts = True
    
    #COMポート設定を適用
    ser = serial.Serial("COM3",baudrate = 115200,parity = serial.PARITY_NONE,timeout=None)
    
    #バッファのクリア
    ser.reset_input_buffer()
    
    # 追記モードでファイルオープン
    fp = open(fname_out, 'a')
    #現在時刻の取得
    starttime = datetime.datetime.now()
    s = '# プログラム開始時刻: {0}\n'.format(get_endate(starttime))
    fp.write(s)
    #s = '# 実行コマンド：{0} {1} {2} {3} {4}\n'.format(argv[0], argv[1], argv[2], argv[3], argv[4])
    fp.write(s)
    
    # ポートのオープン処理
    if(ser.is_open == False):
    
        try:
            ser.open()
        except SerialException:
            print("output file open error !!")
            exit()
    
    print("PICと通信開始")
    
    TXstarttime = datetime.datetime.now()
    
    j = 0
    
    while(True):
        #if (j%1000) == 0: print("{}").format(j)
        # データ受信開始
        toReadBytes = N_data
        D_PIC = ser.read(toReadBytes)
    
        #ファイル追加処理
    
        for k in range(1,N_Smpl):
            flag = 0
            if ((D_PIC[2*k] & 128)==128):
                flag = 1
                d = (3 & D_PIC[2*k]) * 256 + D_PIC[2*k+1]
                c = j * N_Smpl + k
                s = '{0} {1}\n'.format(d, c)
                fp.write(s)
    
        #経過時間を表示
        td = datetime.datetime.now() - TXstarttime
        s = '#{0} 経過時間:{1:d}[sec]\n'.format(j, td.seconds)
        fp.write(s)
    
        if(flag == 1): 
            break
            j += 1
    
    
    # COMポートをクローズ
    ser.close()
    
    # 終了時刻を表示
    endtime = datetime.datetime.now()
    s = '# プログラム終了時刻: {0}\n'.format(get_endate(endtime))
    fp.write(s)
    
    # 経過時間を表示
    day = td.days
    (hour, min , sec) = get_hms(td)
    
    s = '# 処理時間: {0}日{1}時間{2}分{3}秒\n'.format(day, hour, min, sec)
    fp.write(s)
    s = '= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = =\n'
    fp.write(s)
    fp.close()
    
    print("データ取得を終了します：（リターンキーで終了）")
    input()
    
[/code]

#### エラーメッセージ

[code]

    C:\python>python LogPIC32Py2.py
    PICと通信開始
    Traceback (most recent call last):
    File "C:\python\LogPIC32Py2.py", line 103, in <module>
        if ((D_PIC[2*k] & 128)==128):
    IndexError: index out of range
    
[/code]

プログラム上のファイル追加処理を以下の通り変更しました。

##### ファイル追加処理

[code]

    for k in range(1,N_Smpl):
        flag = 0
        try:
            if ((D_PIC[2*k] & 128)==128):
                flag = 1
                d = (3 & D_PIC[2*k]) * 256 + D_PIC[2*k+1]
                c = j * N_Smpl + k
                s = '{0} {1}\n'.format(d, c)
                fp.write(s)
        except IndexError:
            print('Error')
            print(len(D_PIC))
            print(2*k)
            os.system('PAUSE')
    
[/code]

#### 結果

[code]

    C:\python>python LogPIC32Py2.py
    PICと通信開始
    Error
    0
    2
    続行するには何かキーを押してください . . .
    Error
    0
    4
    続行するには何かキーを押してください . . .
    Error
    0
    6
    続行するには何かキーを押してください . . .
    
[/code]


CC BY-SA 4.0
2022-02-15T03:55:43.413
86350
2023-05-30T10:01:15.137
2022-02-15T06:47:48.217
3060
51433
question
python シリアル通信
pySerial を用いたシリアル通信プログラムのエラー解決


そのエラーは配列やリストの要素の個数を超えてアクセスしようとしたときに出ます  
そのエラーが出たところで実行を止め、リストの要素数とアクセスするインデックスの数値をチェックしてみよう


CC BY-SA 4.0
2022-02-15T04:54:31.400
86355
2022-02-15T04:54:31.400
27481
86350
answer


その調査結果では、`len(D_PIC)`が 0 なのでシリアルポートからのデータ読み込み結果が 0 バイトという状態になります。  
データの存在しないbytesオブジェクトということなので、何処を読み取ろうとしてもエラーでしょう。

`D_PIC =
ser.read(toReadBytes)`の結果で正常にデータが読み込まれているか、あるいはその前に[in_waiting](https://pyserial.readthedocs.io/en/latest/pyserial_api.html#serial.Serial.in_waiting)で十分なデータがバッファに入っているか、等をチェックした方が良いでしょう。

他の装置で動作した実績のあるプログラムならば、その動作した装置との違いを調べてみてください。

初めてプログラムして初めて発生した現象であるならば、そもそもPICと通信出来ているか等、Pythonでは無いツールなどで確かめてみるとかしてみてください。


CC BY-SA 4.0
2022-02-15T06:56:14.960
86360
2022-02-15T06:56:14.960
26370
86350
answer