日付7/18
MCP3208をSPIで読んでみた
前置き
久しぶりすぎる進捗日記です。世界大会も終わり、来年の目標ができ始めました。そんな感じで始めたのがAngelLineSensorです。AngelLineSensor作りたいんですけど、アナログポート足りんすぎです。僕個人的にポートは24くらい欲しいです。それに以前作成したF446REを使ったラインセンサがクソということで好評だったので、いっそArduinoをピンヘッダでつけてでも読めばいいじゃんって思ってました。なんかそれも嫌なので、といいますかArduinoが嫌いなので(好きだけど)、STMで使いたいって思いました。前のF446事件があるようにアナログ16ポート対応のくせしてmbedライブラリ書き換えないと使えないとか、そもそも書き換えるっての意味わかんないですし。おすし。だるいし。誰もわかってなさそうだし。なんなら環境依存しないものを作ればいいじゃないかってなって、ADCを使うことになりました。
MCP3208ってなんやねん
僕が秋月電子通商をさまよっていたら、MCP3208が降ってきました。ADC(アナログデジタルコンバータ)です。これのポートが8ポートついていて、SPIで通信でそれぞれの値を読ことが可能です。300円です。
ADCとは
アナログデジタルコンバータの頭文字を取ったものです。
アナログ(電圧)をデジタル(01表現)にコンバート(変換)してくれます。
今日やったこと
NucleoF446REでMCP3208を読みました。
インターネットで調べてみると先客がいました。
そこのサイトからソースコードパクってやったら一発じゃんって思ってやってみると。。。
コンパイル失敗しました。
class SPI : private NonCopyable<SPI> { NonCopyable.h:157:5: note: declared private here NonCopyable(const NonCopyable&);

なんかSPIのライブラリがNonCopyableでどうこう。まずのこNonCopyableがなんなのかわかんないので調べてみました。Privateになるんですね。治し方がmbedライブラリ書き換える以外なさそうなのでやめました。億劫ですがmcp3208のライブラリ書き換えました。
とりあえずはSPIを使って2MHzで8chアナログをよむことに成功しました!!
明日は2つ、3つ同時接続で24個読み込めるかを試したいです。あと高速化したいので、いい感じの周波数も決定したいです。それに8つ読むのに何秒かかっているかも知りたいですね。
書いていて思ったのですが、303k8でSPIで読んでシリアルで送るか、メインで直接SPIで読むか、どっちがいいですか。
303k8でMCP3208を24ch(uint16_t x 24)受信して踏んでいるセンサ情報を24bitでおくるか、
446reでMCP3208直で読むか。SPIなので早いと思います。しかしCSピンのHIGH/LOWに毎回1us使ったり色々どうなのって感じです。MCP3208の使用上、1ポートごとに1回ずつ数字を送らないといけない感じです。一気に8個送ってくれる感じじゃないんですね。それはそれで便利ですが、今回の用途ではあまり嬉しくない仕様です。2Mhzねえ。シリアルだと230400bps。確かbpsは2倍すれば周波数になるみたいなのを聞いています。それで24bit受信した方が早いのか、SPIで(16bit x 24)(受信) + 24byte(送信)を2Mhzでするのか。どっちがいいのでしょうか。
速さがいらないならSPIで直接読む一択です。しかし用途が用途なのでシリアルかなあ。。。
便利さで言うとSPIで直だと思います。というのは閾値調整をメインマイコンできるので良き。それにラインセンサ用マイコン一個分だけ値段が浮くので、おさいふにも、調整のしやすさ的にも最高です。それにシリアルペリフェラルを使わなくて済むので最高です。
それに対してスレーブを用意した場合は送るの早いですがシリアルペリフェラルを使うのと、下から閾値調整をしなければならないかもしれないのがあるのでちょっと考えちゃいます。
ロボットはラインセンサが命なのでそのくらい妥協してもいいと思います。ロボットはラインセンサ命。SPIで通信できない方面で死亡するのはいいけど、送るデータ多すぎで死亡とかいやなのでシリアルかなああと書いていて思い始めました。マイコンの位置は工夫すればいけますしね。
2018のLEGEND機みたいに書き込みやすい位置にラインセンサマイコンを持ってくればいいんじゃないのでしょうか。ああでも今年はMDが下に入ってきて難しいのか。
皆さんはどっちにしますか。
文章を書く癖がなかったので、ブロークンジャパニーズです。久々に書いてみると全く描けないですね。
プログラム載せときます。
(どちみち、mbedSPIに癖があって環境依存ではあった)
Main
#include "mbed.h" #include "mcp3208.h" MCP3208 mcp3208_0(D11,D12,D13,D10); Serial pc(USBTX,USBRX); DigitalOut checkPin(D2);//LED float v0[8]; int main() { pc.baud(230400); mcp3208_0.m_bus.frequency(2000000); while(1) { for (int i = 0; i < 8; i++) { checkPin = 1; v0[i] = mcp3208_0.read_input(i); checkPin = 0; wait_us(1); } pc.printf("Device0\t"); for (int i = 0; i < 8; i++) { pc.printf("%.3f\t", v0[i]); } pc.printf("\r\n"); // wait(0.01); } }
.h
//.h /** * @file mcp3208.h */ #include "mbed.h" #ifndef MCP3208_H #define MCP3208_H #define START_BIT 0x04 #define MODE_SINGLE 0x02 #define MODE_DIFF 0x00 /** Polarity setting for differential inputs. * * POL_EVEN_POSITIVE sets channel [0|2|4|6] as the positive side and channel * [1|3|5|7] as the negative side. POL_EVEN_NEGATIVE sets the opposite. */ enum Polarity { POL_EVEN_POSITIVE, POL_EVEN_NEGATIVE }; /** Class for interfacing to the MCP3208 SPI-based ADC. * * This class will also allow interfacing to the MCP3204, but only four * inputs are provided by that chip, as opposed to the eight of the MCP3208. */ class MCP3208 { public: /** Create an MCP3208 object. * * @param bus An SPI bus object. * @param cs The name of a pin to use as the chip select. */ MCP3208(PinName mosi,PinName miso,PinName sck,PinName cs); ~MCP3208(); /** Read from a single-ended input. * * @param channel The channel number to read from. * * @param returns The sampled value as a float between 0.0 and 1.0. */ float read_input(int channel); /** Read from a pair of differential inputs. * * In differential mode, the channels are referred to as 0 to 3, with * polarity set in a separate parameter. This avoids the user having to set * the polarity as part of the channel number or having channel numbers * increase by two (i.e. the channels being 0, 2, 4, and 6). * * @param channel The channel number to read from. * @param polarity The polarity of the differential signal. * * @param returns The sampled value as a float between 0.0 and 1.0. */ float read_diff_input(int channel, Polarity polarity); SPI m_bus; private: DigitalOut m_cs; void select(); void deselect(); }; #endif
CPP
/** * @file mcp3208.h */ #include "mbed.h" #ifndef MCP3208_H #define MCP3208_H #define START_BIT 0x04 #define MODE_SINGLE 0x02 #define MODE_DIFF 0x00 /** Polarity setting for differential inputs. * * POL_EVEN_POSITIVE sets channel [0|2|4|6] as the positive side and channel * [1|3|5|7] as the negative side. POL_EVEN_NEGATIVE sets the opposite. */ enum Polarity { POL_EVEN_POSITIVE, POL_EVEN_NEGATIVE }; /** Class for interfacing to the MCP3208 SPI-based ADC. * * This class will also allow interfacing to the MCP3204, but only four * inputs are provided by that chip, as opposed to the eight of the MCP3208. */ class MCP3208 { public: /** Create an MCP3208 object. * * @param bus An SPI bus object. * @param cs The name of a pin to use as the chip select. */ MCP3208(PinName mosi,PinName miso,PinName sck,PinName cs); ~MCP3208(); /** Read from a single-ended input. * * @param channel The channel number to read from. * * @param returns The sampled value as a float between 0.0 and 1.0. */ float read_input(int channel); /** Read from a pair of differential inputs. * * In differential mode, the channels are referred to as 0 to 3, with * polarity set in a separate parameter. This avoids the user having to set * the polarity as part of the channel number or having channel numbers * increase by two (i.e. the channels being 0, 2, 4, and 6). * * @param channel The channel number to read from. * @param polarity The polarity of the differential signal. * * @param returns The sampled value as a float between 0.0 and 1.0. */ float read_diff_input(int channel, Polarity polarity); SPI m_bus; private: DigitalOut m_cs; void select(); void deselect(); }; #endif

Loading Comments...