【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

http://zattouka.net/GarageHouse/micon/I2C/I2C_1.htm

C言語 socket通信でhttp通信

背景

 webアプリを作りたくて始めました.普通のアプリならjavascriptphpでゴニョゴニョすればいいと思うのですが(よくしらない),FPGAチップのZinqシリーズ上で動くFPGA上のデータをウェブブラウザ経由でモニタリングするものを考えていたため,メモリの直叩きが得意なCでサーバー側のプログラムを作る必要がありました.その第一歩としてまずはhttp通信をCで表現するとどうなるのか?そもそもhttpとは?を理解するべくsocket通信でhttp通信を試してみることにしました.

 

ネットワークの基礎

 ネットワークはOSI参照モデルによって階層分けされており,一番上のアプリケーション層は一つ下のプレゼンテーション層に支えられ...というように成り立っています.今自分が使ってるモノがどの層で動いているのかを意識するとわかりやすいです.

 OSI参照モデルはあくまで概念なのでイメージ程度に考えます.

 

表1 OSI参照モデル

f:id:mamenicaSPA:20220405174005p:plain

 

f:id:mamenicaSPA:20220405174033p:plain

 図1 ざっくりしたTCP/IP

 

 図1にざっくりした下層の解説図を表しました.

 ネットワーク層:クライアントはサーバーのIPアドレスを頼りに通信を始めます.クライアント-サーバー間にどんな機器が存在するか,どんなデータを送っているかを気にすることなく通信します.

 データリンク層:ネットワーク機器は宛先IPアドレスをもとに次にどこにデータを送ればよいか判断しデータを中継します.この時,機器に割り振られたアドレスがMACアドレスと呼ばれるものです.ネットワーク機器はMACアドレスで次の中継先にデータを送るので,中継先とどんなインターフェースでつながれているか,最終目標のIPアドレスは何なのかを気にすることなく通信します.

 物理層:ネットワーク機器の端子からは何らかの物理現象でデータを表現し送信します.MACアドレスIPアドレス,データの中身を気にすることなく,単に信号を光に変換したり,Wi-Fi電波で飛ばしたり,電気信号としてケーブルに流します.

 

 以上のようにしてクライアント-サーバー間で通信を行っています.実際にはIPアドレスを変換したりなんやら勘彌ら複雑ですが気にしないことにします.

 

socket通信の基礎

 C言語でsocketを使うと文字の通信ができるようになります.socket通信はセッション層らしいです.TCP通信では図2のように通信を行います.socketはこの一連の処理をなんやかんややってくれて,read(),write()関数だけで文字のやり取りができるようにしてくれます.

 

f:id:mamenicaSPA:20220405174300p:plain

図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のデータを要求しています.

 

f:id:mamenicaSPA:20220405174435p:plain

図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ルーターでインターネットに接続する最低限の設定

ルーターwifiが使えるようになる機械 ではないゾ

Ciscoルーターを家庭で使って逸般の誤家庭に一歩近づこう!

はじめに

アパートで使っていたBUFFALOのルーターがGigabitEthernet非対応だったため,どうせならと思いヤフオクで購入した中古Ciscoルーターに置き換えることに.アパートの回線は建物全体とインターネットを何らかの形でつなげるルーターが設置されていて,外部からのアクセスは遮断される.ユーザーは部屋のLANコンセントに機器を接続することでアパートルーターからDHCPIPアドレスを割り振られる.CiscoルーターDHCPでIPを受け取るので,部屋内からの通信はnatでそのIPに付け替えてあげればよい.

注意!アパートルーターの地点で十分セキュリティが保たれてる前提で設定してます.実際に使うときは外部からのアクセスを遮断とかする必要があると思います.

基本情報技術者試験程度の知識があるとして書いてます.

使用機材

Cisco

・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からDHCPciscoルーターに割り振られた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ルータで学ぶネットワーク

Cisco NAT/PATの設定と確認 | IPアドレッシング | ネットワークのおべんきょしませんか?

CISCOルーターでDNSリレー - zan-gyo’s diary

DHCPサーバ - Ciscoコンフィグ設定

エアコンリモコンの赤外線信号解析

 ふと自宅のエアコンをラズパイを使ってLAN経由でスマホ操作できるようにすることを思いついたので第一段階としてエアコンリモコンの赤外線信号を解析してみたものを備忘録としてあげておきます.

1.使用部品

  • ラズパイB+
  • 赤外線リモコン受信モジュール GP1UXC41QS
  • エアコン 日立白くまくん

 

2.赤外線通信の概要

 赤外線通信は36kHz~40kHzのオンオフのバースト信号が続いてる期間を1とし,バースト信号がない時が0とされています.今回使用した受信モジュールは何もない時電源電圧を出力し,38kHzのバースト波があるとき出力が0になるもので,実際の信号とは逆になります.

 

3.実験

実験1逐次信号とり

 バースト波の有無で信号の01を表現するのはすべての規格で同じ(多分)ですが,この01信号でどのようにデータを送るかは規格によって異なります.今回使用したエアコンは最新型で規格がわからないため,受信モジュールをGPIOピンにつなぎ,逐次値を読み取り,その時の時間を記録してみました.

f:id:mamenicaSPA:20200522181354p:plain

作成したプログラムは上書きしてしまったので残っていませんがこのように断片的なデータしかとることができませんでした.しかし,単純なオンオフによる01信号ではなく,オン期間の長さで01を表していることがわかりました.

 

実験2エッジ検出での信号とり

 実験1の結果どうやら信号が1の時間が長い時と短い時を区別してデータを送っていることがわかったので,信号が1になる「立ち上がりエッジ」と0になる「立下りエッジ」を検出し,その時の時間を記録するプログラムを用意し,データをとってみました.

 

f:id:mamenicaSPA:20200522181357p:plain

今回はうまくデータが取れました次はこのデータを用いてデータを解析していきたいと思います.

 

 

実験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)か?であること,水色部は特にデータがない同期用の信号であることが今のところ分かっています.今後も暖房ボタンや温度上昇ボタンを押してみて信号を解析していきたいと考えています.