Interface 2015年4月号 第1部 第5章および第6章のプログラム
Information
FilterTest - Interface 2015年4月号 第1部 第5章 第6章 のソフトウェア
Program for Section 5 and 6 in April 2015 issue of Interface
(Japanese electronics magazine)
概要
このプログラムは、
- ハイパスフィルタ、ローパスフィルタ、ノッチフィルタ
を行うFilterTestクラスと、波形をUSBシリアル通信でホストへ送信するmain関数で構成されています。
FilterTest.h, FilterTest.cpp
- A-Dサンプリング - 1 kSPS
- ハイパスフィルタ(遮断周波数 0.5 Hz、1次バターワース)
- ローパスフィルタ(遮断周波数 30 Hz、2次バターワース)
- ノッチフィルタ(中心周波数 50 Hz、2次)
main.cpp
- データ送信レート - 1 kSPS
- FilterTestクラスのインスタンスを生成
- 処理開始メソッドを実行
- メインループ - ポーリングにより、サンプリング、フィルタ処理完了フラグがセットされたら、
USBシリアル通信経由で、ホストへ送信する
シリアル通信フォーマット
(※)誌面ではパケットサイズ 64 byteとなっていますが、
64 byteでは、PCのUSBドライバが 4096 byteまで保持し、波形が滑らかに描画できないため、
Ver.1.0.2で、32 byteに変更しています。
- 34byte固定長パケット方式
- 波形データパケット1種類
波形データパケット | |
0x00 | パケットヘッダ(固定値0xAA) |
0x01 | データ種別ID(0x01: 波形データ) |
0x02 | パケット番号(0 - 99繰り返し) |
0x03 | ペイロードサイズ(固定値30) |
0x04 - 0x21 | 波形データ(short, big endian) |
Description
This contains FilterTest class and main function.
FilterTest class:
- High pass filter, Low pass, Notch filter
Main function:
- Send waveform to host via USB serial class.
FilterTest.h, FilterTest.cpp
- A-D sampling - 1 kSPS
- High pass filter - Cut off frequency 0.5 Hz, first order butterworth
- Low pass filter - Cut off frequency 30 Hz, second order butterworth
- Notch filter - Center frequency 50 Hz, second order
main.cpp
- Data sending rate - 1 kSPS
- Executing start procedure method
- Main loop - sending waveform data via USB serial interface when detecting ready flag.
Packet format for USB serial interface
- Packet size: 34 bytes(fixed)
- One type of packet waveform packet
Waveform packet | |
0x00 | Packet header (0xAA (fixed)) |
0x01 | Data type ID (0x01: Waveform ID) |
0x02 | Packet number (0 - 99) |
0x03 | Payload size (30 (fixed)) |
0x04 - 0x21 | Waveform data (short, big endian) |
main.cpp@2:c9471599e9eb, 2015-07-30 (annotated)
- Committer:
- t_tatsuoka
- Date:
- Thu Jul 30 10:23:54 2015 +0000
- Revision:
- 2:c9471599e9eb
- Parent:
- 1:4172c4324c2d
Notch filter 60 Hz version
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
t_tatsuoka | 0:7a4d80e7ea81 | 1 | /** |
t_tatsuoka | 0:7a4d80e7ea81 | 2 | * @file Main.cpp |
t_tatsuoka | 0:7a4d80e7ea81 | 3 | * @brief Send 1ch waveform data to PC via USB serial |
t_tatsuoka | 0:7a4d80e7ea81 | 4 | * @date 2015.02.22 |
t_tatsuoka | 1:4172c4324c2d | 5 | * @version 1.0.2 |
t_tatsuoka | 0:7a4d80e7ea81 | 6 | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 7 | #include "mbed.h" |
t_tatsuoka | 0:7a4d80e7ea81 | 8 | #include "USBSerial.h" |
t_tatsuoka | 0:7a4d80e7ea81 | 9 | #include "FilterTest.h" |
t_tatsuoka | 0:7a4d80e7ea81 | 10 | |
t_tatsuoka | 0:7a4d80e7ea81 | 11 | #define ON (1) |
t_tatsuoka | 0:7a4d80e7ea81 | 12 | #define OFF (0) |
t_tatsuoka | 0:7a4d80e7ea81 | 13 | |
t_tatsuoka | 0:7a4d80e7ea81 | 14 | #define LED_ON (0) |
t_tatsuoka | 0:7a4d80e7ea81 | 15 | #define LED_OFF (1) |
t_tatsuoka | 0:7a4d80e7ea81 | 16 | |
t_tatsuoka | 0:7a4d80e7ea81 | 17 | #define BYTE_MASK (0xFF) |
t_tatsuoka | 0:7a4d80e7ea81 | 18 | #define INT16_MAX (32767) |
t_tatsuoka | 0:7a4d80e7ea81 | 19 | #define INT16_MIN (-32768) |
t_tatsuoka | 0:7a4d80e7ea81 | 20 | |
t_tatsuoka | 0:7a4d80e7ea81 | 21 | #define SAMPLING_RATE (0.001) /* A/D sampling rate (1ms) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 22 | |
t_tatsuoka | 0:7a4d80e7ea81 | 23 | #define PACKET_HEADER (0xAA) |
t_tatsuoka | 0:7a4d80e7ea81 | 24 | #define WAVEFORM_ID (0x01) |
t_tatsuoka | 1:4172c4324c2d | 25 | #define PACKET_SIZE (34) |
t_tatsuoka | 1:4172c4324c2d | 26 | #define DATA_NUM (30) |
t_tatsuoka | 0:7a4d80e7ea81 | 27 | #define BUF_NUM (2) |
t_tatsuoka | 0:7a4d80e7ea81 | 28 | #define CNTR_SIZE (100) |
t_tatsuoka | 0:7a4d80e7ea81 | 29 | /* [ Packet format ] */ |
t_tatsuoka | 0:7a4d80e7ea81 | 30 | /* ---------------- */ |
t_tatsuoka | 0:7a4d80e7ea81 | 31 | /* 0x00 | Header byte | Fixed value (PACKET_HEADER:0xAA) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 32 | /* 0x01 | Data type | ID value (0x01:Waveform) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 33 | /* 0x02 | Packet counter | Count value (0to99 < CNTR_SIZE:100) */ |
t_tatsuoka | 1:4172c4324c2d | 34 | /* 0x03 | Payload size | Fixed value (DATA_NUM:30) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 35 | /* 0x04 | Data0 (MSBside)| Short type (signed, big endian) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 36 | /* ... | ... | */ |
t_tatsuoka | 1:4172c4324c2d | 37 | /* 0x21 | Data29(LSBside)| */ |
t_tatsuoka | 0:7a4d80e7ea81 | 38 | /* ---------------- */ |
t_tatsuoka | 0:7a4d80e7ea81 | 39 | |
t_tatsuoka | 0:7a4d80e7ea81 | 40 | Ticker sampling; /* Interval timer for A/D sampling */ |
t_tatsuoka | 0:7a4d80e7ea81 | 41 | AnalogIn wave_in(p20); /* A/D port */ |
t_tatsuoka | 0:7a4d80e7ea81 | 42 | USBSerial serial; |
t_tatsuoka | 0:7a4d80e7ea81 | 43 | FilterTest filter; |
t_tatsuoka | 0:7a4d80e7ea81 | 44 | |
t_tatsuoka | 0:7a4d80e7ea81 | 45 | DigitalIn hpf_on(p28); /* Hiph pass filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 46 | DigitalIn lpf_on(p27); /* Low pass filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 47 | DigitalIn brf_on(p26); /* Notch (Band reject) filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 48 | /* [ DIP switch ] */ |
t_tatsuoka | 0:7a4d80e7ea81 | 49 | /* TG-LPC11U35-501 +3.3V */ |
t_tatsuoka | 0:7a4d80e7ea81 | 50 | /* | CN1 CN2 | --- */ |
t_tatsuoka | 0:7a4d80e7ea81 | 51 | /* | mbed BD | | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 52 | /* | 13 | p28 -/ -+ Hiph pass filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 53 | /* | 14 | p27 -/ -+ Low pass filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 54 | /* | 15 | p26 -/ -+ Notch filter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 55 | /* | | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 56 | /* pull-down is default as below. */ |
t_tatsuoka | 0:7a4d80e7ea81 | 57 | /* http://developer.mbed.org/handbook/DigitalIn */ |
t_tatsuoka | 0:7a4d80e7ea81 | 58 | /* It says "By default, the DigitalIn is setup */ |
t_tatsuoka | 0:7a4d80e7ea81 | 59 | /* with an internal pull-down resistor." */ |
t_tatsuoka | 0:7a4d80e7ea81 | 60 | /* Better to set the pins to pull-up mode and the */ |
t_tatsuoka | 0:7a4d80e7ea81 | 61 | /* switch connected to GND. */ |
t_tatsuoka | 0:7a4d80e7ea81 | 62 | |
t_tatsuoka | 0:7a4d80e7ea81 | 63 | DigitalOut dbg_pin1(p21); /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 64 | DigitalOut dbg_pin2(p22); /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 65 | DigitalOut dbg_led1(LED1); /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 66 | DigitalOut dbg_led2(LED2); /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 67 | |
t_tatsuoka | 0:7a4d80e7ea81 | 68 | int32_t idx, toggle, send_flag; |
t_tatsuoka | 0:7a4d80e7ea81 | 69 | uint8_t cntr; |
t_tatsuoka | 0:7a4d80e7ea81 | 70 | uint8_t buf[BUF_NUM][PACKET_SIZE]; |
t_tatsuoka | 0:7a4d80e7ea81 | 71 | |
t_tatsuoka | 0:7a4d80e7ea81 | 72 | |
t_tatsuoka | 0:7a4d80e7ea81 | 73 | /** Initialize buffer |
t_tatsuoka | 0:7a4d80e7ea81 | 74 | * @param tgl buffer toggle index |
t_tatsuoka | 0:7a4d80e7ea81 | 75 | * @param ctr packet counter |
t_tatsuoka | 0:7a4d80e7ea81 | 76 | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 77 | void init_buf(int32_t tgl, uint8_t ctr) |
t_tatsuoka | 0:7a4d80e7ea81 | 78 | { |
t_tatsuoka | 0:7a4d80e7ea81 | 79 | int i; |
t_tatsuoka | 0:7a4d80e7ea81 | 80 | if(tgl>BUF_NUM) { |
t_tatsuoka | 0:7a4d80e7ea81 | 81 | return; |
t_tatsuoka | 0:7a4d80e7ea81 | 82 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 83 | buf[tgl][0] = PACKET_HEADER; |
t_tatsuoka | 0:7a4d80e7ea81 | 84 | buf[tgl][1] = WAVEFORM_ID; |
t_tatsuoka | 0:7a4d80e7ea81 | 85 | buf[tgl][2] = ctr; /* Packet counter */ |
t_tatsuoka | 0:7a4d80e7ea81 | 86 | buf[tgl][3] = DATA_NUM; /* Payload size */ |
t_tatsuoka | 0:7a4d80e7ea81 | 87 | idx = 4; /* Start index of waveform */ |
t_tatsuoka | 0:7a4d80e7ea81 | 88 | for(i=4; i<PACKET_SIZE; i++) { /* Initialize array just in case */ |
t_tatsuoka | 0:7a4d80e7ea81 | 89 | buf[tgl][i] = 0; |
t_tatsuoka | 0:7a4d80e7ea81 | 90 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 91 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 92 | |
t_tatsuoka | 0:7a4d80e7ea81 | 93 | /** Interval timer for read A/D value |
t_tatsuoka | 0:7a4d80e7ea81 | 94 | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 95 | void ad_sampling() |
t_tatsuoka | 0:7a4d80e7ea81 | 96 | { |
t_tatsuoka | 0:7a4d80e7ea81 | 97 | int32_t wav_temp; |
t_tatsuoka | 0:7a4d80e7ea81 | 98 | dbg_pin1 = ON; /* Calculation time for filter for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 99 | dbg_led1 = hpf_on; /* High pass filter enable status for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 100 | dbg_led2 = lpf_on; /* Low pass filter enable status for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 101 | |
t_tatsuoka | 0:7a4d80e7ea81 | 102 | /* Read and filter data */ |
t_tatsuoka | 0:7a4d80e7ea81 | 103 | wav_temp = (int32_t)filter.calc( (double)(wave_in.read_u16() - INT16_MAX), hpf_on, lpf_on, brf_on ); |
t_tatsuoka | 0:7a4d80e7ea81 | 104 | wav_temp = (wav_temp > INT16_MAX) ? INT16_MAX : wav_temp; /* Clip ceiling */ |
t_tatsuoka | 0:7a4d80e7ea81 | 105 | wav_temp = (wav_temp < INT16_MIN) ? INT16_MIN : wav_temp; /* Clip floor */ |
t_tatsuoka | 0:7a4d80e7ea81 | 106 | buf[toggle][idx] = (uint8_t)((wav_temp >> 8 ) & BYTE_MASK); /* MSB side (big endian) */ |
t_tatsuoka | 0:7a4d80e7ea81 | 107 | idx++; |
t_tatsuoka | 0:7a4d80e7ea81 | 108 | buf[toggle][idx] = (uint8_t)(wav_temp & BYTE_MASK); /* LSB side */ |
t_tatsuoka | 0:7a4d80e7ea81 | 109 | idx++; |
t_tatsuoka | 0:7a4d80e7ea81 | 110 | |
t_tatsuoka | 0:7a4d80e7ea81 | 111 | dbg_pin1 = OFF; /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 112 | |
t_tatsuoka | 0:7a4d80e7ea81 | 113 | /* Switch buffer */ |
t_tatsuoka | 0:7a4d80e7ea81 | 114 | if(idx >= PACKET_SIZE) { /* Counter reached */ |
t_tatsuoka | 0:7a4d80e7ea81 | 115 | toggle = !toggle; |
t_tatsuoka | 0:7a4d80e7ea81 | 116 | cntr = (cntr + 1 ) % CNTR_SIZE; |
t_tatsuoka | 0:7a4d80e7ea81 | 117 | init_buf(toggle, cntr); |
t_tatsuoka | 0:7a4d80e7ea81 | 118 | send_flag = ON; /* Set flag */ |
t_tatsuoka | 0:7a4d80e7ea81 | 119 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 120 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 121 | |
t_tatsuoka | 0:7a4d80e7ea81 | 122 | /** Send data packet |
t_tatsuoka | 0:7a4d80e7ea81 | 123 | * @param p_buf Data array |
t_tatsuoka | 0:7a4d80e7ea81 | 124 | * @param size Data length |
t_tatsuoka | 0:7a4d80e7ea81 | 125 | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 126 | bool send_packet(uint8_t *p_buf, uint16_t size) |
t_tatsuoka | 0:7a4d80e7ea81 | 127 | { |
t_tatsuoka | 0:7a4d80e7ea81 | 128 | if(serial.writeable()) { |
t_tatsuoka | 0:7a4d80e7ea81 | 129 | dbg_pin2 = ON; /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 130 | serial.writeBlock (p_buf, size); /* Send data via USB */ |
t_tatsuoka | 0:7a4d80e7ea81 | 131 | dbg_pin2 = OFF; /* for debug */ |
t_tatsuoka | 0:7a4d80e7ea81 | 132 | return true; |
t_tatsuoka | 0:7a4d80e7ea81 | 133 | } else { |
t_tatsuoka | 0:7a4d80e7ea81 | 134 | return false; |
t_tatsuoka | 0:7a4d80e7ea81 | 135 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 136 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 137 | |
t_tatsuoka | 0:7a4d80e7ea81 | 138 | /** Main function |
t_tatsuoka | 0:7a4d80e7ea81 | 139 | */ |
t_tatsuoka | 0:7a4d80e7ea81 | 140 | int main() |
t_tatsuoka | 0:7a4d80e7ea81 | 141 | { |
t_tatsuoka | 0:7a4d80e7ea81 | 142 | /* Initialization */ |
t_tatsuoka | 0:7a4d80e7ea81 | 143 | idx = 0; |
t_tatsuoka | 0:7a4d80e7ea81 | 144 | toggle = 0; |
t_tatsuoka | 0:7a4d80e7ea81 | 145 | cntr = 0; |
t_tatsuoka | 0:7a4d80e7ea81 | 146 | send_flag = 0; |
t_tatsuoka | 0:7a4d80e7ea81 | 147 | init_buf(toggle, cntr); |
t_tatsuoka | 0:7a4d80e7ea81 | 148 | init_buf(!toggle, cntr); |
t_tatsuoka | 0:7a4d80e7ea81 | 149 | |
t_tatsuoka | 0:7a4d80e7ea81 | 150 | dbg_pin1 = OFF; |
t_tatsuoka | 0:7a4d80e7ea81 | 151 | dbg_pin2 = OFF; |
t_tatsuoka | 0:7a4d80e7ea81 | 152 | dbg_led1 = LED_OFF; |
t_tatsuoka | 0:7a4d80e7ea81 | 153 | dbg_led2 = LED_OFF; |
t_tatsuoka | 0:7a4d80e7ea81 | 154 | |
t_tatsuoka | 0:7a4d80e7ea81 | 155 | /* Start interval timer */ |
t_tatsuoka | 0:7a4d80e7ea81 | 156 | sampling.attach(&ad_sampling, SAMPLING_RATE); |
t_tatsuoka | 0:7a4d80e7ea81 | 157 | |
t_tatsuoka | 0:7a4d80e7ea81 | 158 | /* Main loop */ |
t_tatsuoka | 0:7a4d80e7ea81 | 159 | while(1) { |
t_tatsuoka | 0:7a4d80e7ea81 | 160 | if(send_flag != OFF) { |
t_tatsuoka | 0:7a4d80e7ea81 | 161 | /* Send data */ |
t_tatsuoka | 0:7a4d80e7ea81 | 162 | send_packet(buf[!toggle], (uint16_t)PACKET_SIZE); |
t_tatsuoka | 0:7a4d80e7ea81 | 163 | |
t_tatsuoka | 0:7a4d80e7ea81 | 164 | /* Disable interrupt */ |
t_tatsuoka | 0:7a4d80e7ea81 | 165 | __disable_irq(); |
t_tatsuoka | 0:7a4d80e7ea81 | 166 | send_flag = OFF; /* Clear flag */ |
t_tatsuoka | 0:7a4d80e7ea81 | 167 | __enable_irq(); |
t_tatsuoka | 0:7a4d80e7ea81 | 168 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 169 | } |
t_tatsuoka | 0:7a4d80e7ea81 | 170 | } |