【PIC】16F18313 I2C通信テスト
最近暑すぎるのでやはりエアコンをネット経由で遠隔操作したいと思い,エアコン遠隔操作の計画が再開しています.現在の計画では
PC,スマホ
↓ (Ethernet)
ラズパイ
↓ (I2C)
PIC 16F18313
↓
赤外線LED点滅回路
で考えています.PC-ラズパイ間の通信はどうとでもなるのでとりあえずI2Cでラズパイから一方通行のデータを送るPICプログラムを作って試してみました.
1.ソースコード
#include < pic.h > /* * RA0:out * RA1:I2C * RA2:I2C * RA3:nc * RA4:nc * RA5:nc */ //コンフィグ1 #pragma config FEXTOSC = OFF #pragma config RSTOSC = HFINT32 #pragma config CLKOUTEN = OFF #pragma config CSWEN = ON #pragma config FCMEN = OFF // 外部クロック監視しない(FCMEN_OFF) // コンフィギュレーション2の設定 #pragma config WDTE = OFF // ウオッチドッグタイマー無し(OFF) #pragma config PWRTE = ON // 電源ONから64ms後にプログラムを開始する(ON) #pragma config MCLRE = OFF // 外部リセット信号は使用せずにデジタル入力(RA3)ピンとする(OFF) #pragma config CP = OFF // プログラムメモリーを保護しない(OFF) #pragma config CPD = OFF // データメモリーを保護しない(OFF) #pragma config BOREN = ON // 電源電圧降下常時監視機能ON(ON) #pragma config CLKOUTEN = OFF // CLKOUTピンをRA6ピンで使用する(OFF) #pragma config PPS1WAY = OFF // PPS設定をロックしない #pragma config STVREN = ON // スタックがオーバフローやアンダーフローしたらリセットをする(ON) #pragma config BORV = HIGH // 電源電圧降下常時監視電圧(2.5V)設定(HI) // コンフィギュレーション3の設定 #pragma config WRT = OFF // Flashメモリーを保護しない(OFF) #pragma config LVP = OFF // 低電圧プログラミング機能使用しない(OFF) #define _XTAL_FREQ 4000000 static unsigned char RData; void __interrupt() InterI2C(void) { char temp; if (SSP1IF == 1 && !((SSP1STAT&0x04)==0x04)){ //I2C割込(受信のみ) if (SSP1STAT & 0x20){ //受信バイトがデータ D/A = 0 RData = SSP1BUF; //データ読込 } else{ //受信バイトがアドレス D/A =1 temp = SSP1BUF; //アドレスデータ空読み } SSP1IF = 0; //割込みフラグリセット SSP1CON1 = SSP1CON1 | 0x10; //SCLライン開放 CKP = 1 } else SSP1IF = 0; //割込みフラグリセット } void main(void) { OSCFRQ = 0xf3; // (HFFRQ = 0b0011)4MHzx2で8MHzの周波数生成 OSCCON1 = 0xf1; // (NDIV = 0b0001)分周比1:2でFOSC=4MHz TRISA = 0x0e; //[RA5:RA0] 0b001110 ANSELA = 0x00; //アナログ入力ナシ RA1PPS = 0x19; //RA1(out)にSDAを指定 SSP1DATPPS = 0x01; //SDA(in)にRA1を指定 SSP1CLKPPS = 0x02; //SCL(in)にRA2を指定 SSP1STAT= 0b10000000 ; // 標準速度モードに設定する(100kHz) SSP1CON1= 0b00100110 ; // SDA/SCLピンはI2Cで使用し、スレーブモードとする SSP1CON2bits.SEN = 1 ; // SCL制御(クロックストレッチ)を行う SSP1ADD = 8 << 1 ; // マイアドレス(8)の設定 SSP1MSK = 0b11111110 ; // アドレス比較用マスクデータ SSP1IE = 1 ; // SSP(I2C)割り込みを許可する BCL1IE = 1 ; // MSSP(I2C)バス衝突割り込みを許可する PEIE = 1 ; // 周辺装置割り込みを許可する GIE = 1 ; // 全割り込み処理を許可する SSP1IF = 0 ; // SSP(I2C)割り込みフラグをクリアする BCL1IF = 0 ; // MSSP(I2C)バス衝突割り込みフラグをクリアする while(1){ if(RData == 0x00) RA0 = 1; else RA0 = 0; } }
2.参考文献
http://zattouka.net/GarageHouse/micon/MPLAB/16F18313/memo.htm
C言語 socket通信でhttp通信
背景
webアプリを作りたくて始めました.普通のアプリならjavascriptやphpでゴニョゴニョすればいいと思うのですが(よくしらない),FPGAチップのZinqシリーズ上で動くFPGA上のデータをウェブブラウザ経由でモニタリングするものを考えていたため,メモリの直叩きが得意なCでサーバー側のプログラムを作る必要がありました.その第一歩としてまずはhttp通信をCで表現するとどうなるのか?そもそもhttpとは?を理解するべくsocket通信でhttp通信を試してみることにしました.
ネットワークの基礎
ネットワークはOSI参照モデルによって階層分けされており,一番上のアプリケーション層は一つ下のプレゼンテーション層に支えられ...というように成り立っています.今自分が使ってるモノがどの層で動いているのかを意識するとわかりやすいです.
OSI参照モデルはあくまで概念なのでイメージ程度に考えます.
表1 OSI参照モデル
図1 ざっくりしたTCP/IP
図1にざっくりした下層の解説図を表しました.
ネットワーク層:クライアントはサーバーのIPアドレスを頼りに通信を始めます.クライアント-サーバー間にどんな機器が存在するか,どんなデータを送っているかを気にすることなく通信します.
データリンク層:ネットワーク機器は宛先IPアドレスをもとに次にどこにデータを送ればよいか判断しデータを中継します.この時,機器に割り振られたアドレスがMACアドレスと呼ばれるものです.ネットワーク機器はMACアドレスで次の中継先にデータを送るので,中継先とどんなインターフェースでつながれているか,最終目標のIPアドレスは何なのかを気にすることなく通信します.
物理層:ネットワーク機器の端子からは何らかの物理現象でデータを表現し送信します.MACアドレス,IPアドレス,データの中身を気にすることなく,単に信号を光に変換したり,Wi-Fi電波で飛ばしたり,電気信号としてケーブルに流します.
以上のようにしてクライアント-サーバー間で通信を行っています.実際にはIPアドレスを変換したりなんやら勘彌ら複雑ですが気にしないことにします.
socket通信の基礎
C言語でsocketを使うと文字の通信ができるようになります.socket通信はセッション層らしいです.TCP通信では図2のように通信を行います.socketはこの一連の処理をなんやかんややってくれて,read(),write()関数だけで文字のやり取りができるようにしてくれます.
図2 TCP通信の概要
httpの基礎
httpはアプリケーション層で動くプロトコルです.クライアント(webブラウザ)はサーバーに対してデータ送信要求を示す文字列を送り,データが返ってくるという形です.(図3)今回の送信文字列は
GET /test.html HTTP/1.1
Host: 192.168.0.41:80
Connection: close
です.
1行目:メソッド(送信要求),要求オブジェクトURI,プロトコル
2行目:IPアドレス,ポート番号
3行目:ヘッダ,上述のように記述すると送信が終わると接続が切れる.
ローカルIPアドレス192.168.0.41(ポート80)にHTTP ver 1.1 で/test.htmlのデータを要求しています.
図3 http通信の概略
取得するhtmlファイルの大きさが大きいと1度のレスポンスで送り切れないので今回の実験では1度で送り切れるような簡単なtest.htmlを用意しました.
読みだしたtest.htmlファイルも載せておきます.サーバー側ではapacheが動いておりこのファイルをindex.htmlと同じディレクトリに保存して実験しました.
test.html
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>test</title> </head> <body> <p>hello world</p> </body> </html>
実行プログラム
インターネット上をあされば数多の同様なプログラムが出てくると思います.しかしながらたいていのプログラムは名前解決が実装されてたりエレガントにエラー処理がされてたりしてわかりにくいので超絶シンプル記述を意識しました.
httpは究極に単純化するとsocket通信のwrite()でGET要求を送ってread()でデータを読めばいいのです.
今回はあらかじめLAN内にサーバーを立ててtest.htmlを用意し,そこにLinuxPCからアクセスする作戦で行きました.サーバーのアドレスは192.168.0.41を設定しました.
クライアントプログラム
#include <stdio.h> #include <sys/types.h> #include <sys/socket.h> #include <netinet/in.h> int main() { struct sockaddr_in server; int sock; char buf[1024]; //バッファ(1kB) int n; char request_messe[]="GET /test.html HTTP/1.1\r\nHost: 192.168.100.41:80\r\nConnection: close\r\n\r\n"; //文字数79 /*ソケットの作成*/ sock = socket(AF_INET, SOCK_STREAM, 0); server.sin_family = AF_INET; //よくわからん server.sin_port = htons(80); //接続先ポート番号 server.sin_addr.s_addr = inet_addr("192.168.0.41"); //接続先IPアドレス /*サーバに接続*/ connect(sock, (struct sockaddr *)&server, sizeof(server)); printf("conected\n"); send(sock, request_messe, 77,0); //(ソケット,送信メッセージ,データ文字数,フラグ?) printf("data send\n"); /*サーバからデータを受信*/ memset(buf, 0, sizeof(buf)); //バッフア初期化 n = read(sock, buf, sizeof(buf)); //受信 printf("read:%d\n\n %s\n", n, buf); //表示 /*ソケットの終了*/ close(sock); return 0; }
実行結果
conected data send read:415 HTTP/1.1 200 OK Date: Tue, 05 Apr 2022 00:05:56 GMT Server: Apache/2.4.38 (Raspbian) Last-Modified: Mon, 04 Apr 2022 15:06:42 GMT ETag: "8f-5dbd579d471ae" Accept-Ranges: bytes Content-Length: 143 Vary: Accept-Encoding Connection: close Content-Type: text/html <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>test</title> </head> <body> <p>hello world</p> </body> </html>
Ciscoルーターでインターネットに接続する最低限の設定
Ciscoルーターを家庭で使って逸般の誤家庭に一歩近づこう!
はじめに
アパートで使っていたBUFFALOのルーターがGigabitEthernet非対応だったため,どうせならと思いヤフオクで購入した中古Ciscoルーターに置き換えることに.アパートの回線は建物全体とインターネットを何らかの形でつなげるルーターが設置されていて,外部からのアクセスは遮断される.ユーザーは部屋のLANコンセントに機器を接続することでアパートルーターからDHCPでIPアドレスを割り振られる.CiscoルーターはDHCPでIPを受け取るので,部屋内からの通信はnatでそのIPに付け替えてあげればよい.
注意!アパートルーターの地点で十分セキュリティが保たれてる前提で設定してます.実際に使うときは外部からのアクセスを遮断とかする必要があると思います.
基本情報技術者試験程度の知識があるとして書いてます.
使用機材
・L2SW(Buffaloルーターをハブモードで使用)
・PC(LANポートのあるもの) x2台以上
手順
0.ルーターの基本操作
1.インターフェースの設定
2.ルーティングの設定
3.NATの設定
4.DNSの設定(オプション,やらないと使い物にならない)
5.DHCPの設定(オプション,やらなくても使える)
0.ルーターの基本操作
CiscoルーターはIOSと呼ばれるCLIのOSが動いているのでコンソール端子にUSBやシリアルケーブルを接続して,TeraTarmなどにより遠隔操作を行う.設定モードが4階層くらいに分かれていて,グローバル設定モード→enableモード→configureモード→interfaceモードという順に詳しい設定ができるようになっている.以降出てくるコマンドで,enable,configure,interface hoge,といった記述が出てきたらこのモード切替を行っている.また,endやexitなどにより上のモードに戻ることができる.
1.インターフェースの設定
アパート側の端子をDHCPでIPを受け取り,内部側の端子をデフォルトゲートウェイっぽいアドレスに設定してあげればよい.今回は
・アパート側
端子:GigabitEhternet 0/0
アドレス:DHCP
・内部側
端子:GigabitEhternet 0/1
アドレス:192.168.10.1(255.255.255.0)
enable
configure
interface Gigabitethernet0/0
ip address DHCP
no shutdown
interface Gigabitethernet0/1
ip address 192.168.10.1 255.255.255.0
no shutdown
end
とりあえずこれでネットワーク機器として立ち上がったのでPCのアドレスを192.168.10.xxに手動で設定して192.168.10.1にpingを打つと帰ってくるはずである.
show ip interface brief
コマンドでインターフェースがONかOFFかなど見れる
2.ルーティングの設定
とりあえずインターネットにつながればいいのでCiscoルーターの設定は受け取ったパケットをすべてアパート側のルーター(192.168.32.1)に送ればいいので,
enable
configure
ip route 0.0.0.0 0.0.0.0 192.168.32.1
end
この地点でルーター内部ではGi0/0とGi0/1がつながってるのでPCからDHCPでciscoルーターに割り振られたIPにpingを打つと帰ってくるはずである.
show ip route
コマンドでルーティングテーブルが確認できる.
3.NATの設定
アパートルーターはDHCPで割り振ったアドレス以外のアクセスは受け付けないので,内部側のパケットをただ中継するだけではインターネットにつながらない.内部のIPをDHCPで割り振られたIPに付け替えて中継する必要がある.
enable
configure
interface gigabitethernet0/0
ip nat outside
interface gigabitethernet0/1
ip nat inside
end
とりあえずこれでどっちのポートが外か内か設定できたので続けて
enable
configure
ip nat inside source list 1 interface gigabitethernet0/0 overload
access-list 1 permit 192.168.10.0 0.0.0.255
end
この地点でインターネットにはつながるのでPC(またはCiscoルーター)から8.8.8.8(googleDNSサーバー)にpingを打つと帰ってくるはずである.また,ブラウザのアドレスバーにウェブサイトのアドレスを入力すれば表示できるはずである.
ip nat debug
コマンドでnatのリアルタイムでの状況が確認できる.
no ip nat debug
コマンドで終了する.
4.DNSの設定
この段階でインターネットはつながるようになるが,DNSの設定をしていないのでブラウザではIPを直接入力しないとページが表示されない.今回のネットワークでは特別DNSサーバーがあるわけではないのでアパートルーター(192.168.32.1)へ名前解決の仕事を全部丸投げする.ちなみに以下の設定法はCisco1800シリーズではできないらしい.
enable
configure
ip dns server
ip domain-lookup
ipdns view default
dns forwarding
dns forwarder 192.168.32.1
end
5.DHCPの設定
もうすでにyoutubeだろうがなんでもできるようになったが,新しい機器を接続したときに手動でIPを設定する必要がある.少しめんどくさいのでCiscoルーターをDHCPサーバ―として動作させる.
enable
configure
service dhcp
ip dhcp excluded-address 192.168.10.2 192.168.10.20
↑DHCPでの自動振り分けから除外するアドレスを指定した
ip dhcp pool SALES
network 192.168.10.0 255.255.255.0
default-router 192.168.10.1
dns-server 192.168.10.1
lease infinite
end
これで動くはずである.
おわりに
今回の設定に当たり以下のサイトにお世話になりました.
初めてのCisco IOSルータの初期セットアップ -Telnetが出来るまで-CCNA – ランスルネット
Cisco NAT/PATの設定と確認 | IPアドレッシング | ネットワークのおべんきょしませんか?
エアコンリモコンの赤外線信号解析
ふと自宅のエアコンをラズパイを使ってLAN経由でスマホ操作できるようにすることを思いついたので第一段階としてエアコンリモコンの赤外線信号を解析してみたものを備忘録としてあげておきます.
1.使用部品
- ラズパイB+
- 赤外線リモコン受信モジュール GP1UXC41QS
- エアコン 日立白くまくん
2.赤外線通信の概要
赤外線通信は36kHz~40kHzのオンオフのバースト信号が続いてる期間を1とし,バースト信号がない時が0とされています.今回使用した受信モジュールは何もない時電源電圧を出力し,38kHzのバースト波があるとき出力が0になるもので,実際の信号とは逆になります.
3.実験
実験1逐次信号とり
バースト波の有無で信号の01を表現するのはすべての規格で同じ(多分)ですが,この01信号でどのようにデータを送るかは規格によって異なります.今回使用したエアコンは最新型で規格がわからないため,受信モジュールをGPIOピンにつなぎ,逐次値を読み取り,その時の時間を記録してみました.
作成したプログラムは上書きしてしまったので残っていませんがこのように断片的なデータしかとることができませんでした.しかし,単純なオンオフによる01信号ではなく,オン期間の長さで01を表していることがわかりました.
実験2エッジ検出での信号とり
実験1の結果どうやら信号が1の時間が長い時と短い時を区別してデータを送っていることがわかったので,信号が1になる「立ち上がりエッジ」と0になる「立下りエッジ」を検出し,その時の時間を記録するプログラムを用意し,データをとってみました.
今回はうまくデータが取れました次はこのデータを用いてデータを解析していきたいと思います.
実験3データの解析
実験2でとれた信号をONの期間が長い時を1,短い時を0として16進数に変換してみました.この時の信号は設定温度27度で停止ボタンを押しました.
8008 0002 FDFF 0033 CC49 B6C8 3736 C900 FF00 FF00 FF00 FF00 FFCA 3587 7800 FF00 FF01 FEC0 3F80 7F11 EE00 FF00 FFFF 00FF 00FF 00FF
26度の時は,
8008 0002 FDFF 0033 CC49 B6C8 3716 E900 FF00 FF00 FF00 FF00 FFCA 3587 7800 FF00 FF01 FEC0 3F80 7F11 EE00 FF00 FFFF 00FF 00FF 00FF
以上より下線部のところで温度を示しているようで,さらに,3を反転するとC,6を反転させると9になることから1バイトごとに反転信号を挿入していることがわかりました.
また,今度は27度で冷房ボタンを押したところ,次のようになりました.
8008 0002 FDFF 0033 CC49 B6C8 3736 C900 FF00 FF00 FF00 FF00 FFCA 358F 7000 FF00 FF01 FEC0 3F80 7F11 EE00 FF00 FFFF 00FF 00FF 00FF
よって,下線部で命令を表していることがわかりました.
さらに冷房状態で27度から26度に変化させてみたところ,次のようになりました.
8008 0002 FDFF 0033 CC49 B6C2 3D16 E900 FF00 FF00 FF00 FF00 FFCA 358F 7000 FF00 FF01 FEC0 3F80 7F11 EE00 FF00 FFFF 00FF 00FF 00FF
このことから,下線部で温度変化信号であることを示していることがわかりました.
以上のことをまとめると,
8008 0002 FDFF 0033 CC49 B6C2 3D16 E900 FF00 FF00 FF00 FF00 FFCA 358F 7000 FF00 FF01 FEC0 3F80 7F11 EE00 FF00 FFFF 00FF 00FF 00FF
_温度変化信号であるか?,_今何度か?,_なんの動作(ONOFF)か?であること,水色部は特にデータがない同期用の信号であることが今のところ分かっています.今後も暖房ボタンや温度上昇ボタンを押してみて信号を解析していきたいと考えています.