第八章 おまけ PICをサブCPUにする(C言語編)


PICをサブCPUにする

PIC16F690のCPUにコマンドを送り、動作させます。
タクトスイッチ、LEDフラッシュ、A/Dコンバータ、デジタルin/outなどのコントロールを一気に受け持ちます。

まず1つのPICと接続してテストしてみる


scl(11)とsda(13)は2.2kΩでプルアップしています。それ以外はチェックのため10kΩを繋げています。実際に使うときにこの値を用いるという意味ではありません。
タクトスイッチの上部から伸びている黄色の線はA/Dコンバーターのチェック用です。繋ぐとVdd/2が供給されます。繋がないと当たり前ですがプルアップしているからVddの電圧になります。


main.c
#include "vs-wrc003.h"

void main(void);

unsigned char write_data[50];   // write buffer
unsigned int read_data[20];     // read buffer

void startInit(char* str)
{
  const BYTE MainCycle = 100;
  Init((BYTE)MainCycle);  //CPUの初期設定
  InitSci3(CBR_115200,non,1);
  Mtr_Run(0,0,0,0);
  LED(1);                 // 緑
  while(!getSW() );
  printf(str);
  LED(0);
}

void setPushSW()
{
  PIC_getData(0x01, 0, read_data, 3); // set to 0xff
  Wait(100);
  PIC_getData(0x01, 0, read_data, 3); // set to 0xff
}

int waitPushSW()
{
  while(read_data[0]!=0)
    PIC_getData(0x02, 0, read_data, 3); // status read
  PIC_getData(0x01, 0, read_data, 3); // set to 0xff
  Wait(100);
  PIC_getData(0x01, 0, read_data, 3); // set to 0xff
}

char LEDflush()
{
  unsigned Led;
  char ch; 
  
  printf("\n************ LED flushのテスト ****************\n"); 
  Led=1;
  PIC_ColorLED(Led);    // ColorLED mode 
    while(!(ch=getch())) {
    Wait(2000);
    if(Led++ >=7) Led=1 ;
    PIC_LED(Led);
  }
  PIC_LEDstop();  
  return ch;
}

char DigitalOutput()
{
  unsigned char x; 
  char ch; 
  printf("\nDigital outputテスト ***\n");
  PIC_SetDirecrion(0x00);   // 全ビット出力
  while(!(ch=getch()))
  {
     LED(2);
     PIC_Output(0x00);
     Wait(100);
     LED(0);
     PIC_Output(0xff);
     Wait(100);
  } 
  return ch;
}

char DigitalInput()
{
  unsigned char x; 
  char ch; 
  printf("\nDigital inputテスト ***\n");
  PIC_SetDirecrion(0xff);   // 全ビット入力
  while(!(ch=getch()))
  {
     x = PIC_Input();
     printf("%x\n", x);
  } 
  return ch;
}

char ADinput()
{
  char ch;
  int i;
  printf("ADのテスト\n");
  PIC_getData(0x10, 0, &ch, 1);   // A/D converter初期設定
  while(!(ch=getch()))
  { 
    PIC_getAD(read_data);
    for(i=1; i<7; i++) printf("%X ", read_data[i]);
    printf("\n");    
  }  
  LED(2);
  Wait(100);
  LED(0);
  return ch;
}

char ADoneTest()
{
  char ch;
  int x, i;
  printf("単発ADのテスト\n");
  PIC_getData(0x13, 2, &ch, 1);   // A/Dポート設定
  while(!(ch=getch()))
  { 
    x = PIC_getADone(2, read_data);
    printf("%X\n", x);    
  }  
  LED(2);
  Wait(100);
  LED(0);
  return ch;
}

void main(void)
{
  int x=0, i, n;

  startInit("\n************ PIC通信のテスト ****************\n");
  PIC_init(0xA0);  
  printf("Init start\n");
  setPushSW();
  while(1) {   
    LED(2);
    waitPushSW();
    LED(0);
    setPushSW();
    Wait(200);
    LEDflush();
    DigitalOutput();
    DigitalInput();
    ADinput();
    ADoneTest();
    printf("\n*** Next task ***\n");
  }
}
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101
102
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 PICのアドレスと一致させる
126 
127 
128 
129 
130 
131 
132 
133 
134 必要な項目のみのチェックにした方がよい
135 
136 
137 
138 
139 
140 
141 


上級
データフォーマット:22byteの配列が必要です。
Data     0      1    2    3    4    5    6    7    8    9   10   11   12   13
    status status AN0H AN0L AN1H AN1L AN2H AN2L AN4H AN4L AN5H AN5L AN6H AN6L
                       X         Y         Z      距離L     距離R      温度
     14      15      16     17     18    19     20     21
   RedH  RedL  GreenH  GreenL  BlueH  BlueL   IntH   IntL



PICi2c.c
#include "iodefine.h"

unsigned char PIC_WRITE= 0xA0;
unsigned char PIC_READ = 0xA1;

/* ----------------------------------------------------------------------
    PIC_sendByte
    PIC のレジスタに1バイト送信する
---------------------------------------------------------------------- */
void PIC_sendByte(unsigned  reg, unsigned  dt) {

    unsigned char rdt;

    i2c_waitBusFree();                      // i2c バス空き待ち
    do {
        i2c_setTransmitMode(3);             // マスタ送信モード
        i2c_sendStartCondition();           // i2c バスを開始条件にする
        rdt = i2c_sendByte(PIC_WRITE);  // スレーブアドレスを送信
    } while(rdt == 1);                      // デバイスからACKが返るまでガンバル
    i2c_sendByte(reg);                      // レジスタ番号を送信
    i2c_sendByte(dt);                       // データを送信
    IIC2.ICSR.BIT.TEND = 0;
    i2c_sendStopCondition();                // i2c バスを停止条件にする。
    i2c_setTransmitMode(0);                 // スレーブ受信モードにする
}

/* ----------------------------------------------------------------------
    PIC_readByte
    PIC のレジスタから1バイト受信する
---------------------------------------------------------------------- */
unsigned char PIC_readByte(unsigned  reg) {

    unsigned char rdt;

    i2c_waitBusFree();                      // i2c バス空き待ち
    do {
        i2c_setTransmitMode(3);             // マスタ送信モード
        i2c_sendStartCondition();           // i2c バスを開始条件にする
        rdt = i2c_sendByte(PIC_WRITE);  // スレーブアドレスを送信
    } while(rdt == 1);                      // デバイスからACKが返るまでガンバル
    i2c_sendByte(reg);                      // レジスタ番号を送信
    i2c_setTransmitMode(3);                 // マスタ送信モード
    i2c_sendStartCondition();               // i2c バスを開始条件にする
    i2c_sendByte(PIC_READ);             // スレーブアドレスを送信
    i2c_setTransmitMode(2);                 // マスタ受信モード
    IIC2.ICSR.BIT.TDRE = 0;
    rdt = i2c_receiveByte(1, 1);            // ACK=1, RCVD = 1で受信する。
    i2c_sendStopCondition();                // i2c バスを停止条件にする。
    IIC2.ICCR1.BIT.RCVD = 0;
    i2c_setTransmitMode(0);                 // スレーブ受信モードにする

    return(rdt);
}

/* ----------------------------------------------------------------------
    PIC_getData
    PIC からデータをnバイト受信する
---------------------------------------------------------------------- */
int PIC_getData(unsigned func, unsigned param, unsigned char Data[], unsigned n)
{
  int i, n1;
  unsigned char rdt;
  n1 = n-1;
  i2c_waitBusFree();                    // i2c バス空き待ち
  i=0;
  do {
    i2c_setTransmitMode(3);             // マスタ送信モード
    i2c_sendStartCondition();           // i2c バスを開始条件にする
    rdt = i2c_sendByte(PIC_WRITE);      // スレーブアドレスを送信
    if(i++ == 100) {                   // 返事が無かったらあきらめる
      i2c_sendStopCondition();          // i2c バスを停止条件にする。
      i2c_setTransmitMode(0);           // スレーブ受信モードにする
      return 1;
    }
  } while(rdt == 1);                    // デバイスからACKが返るまでガンバル
  i2c_sendByte(func);                   // レジスタ番号を送信
  i2c_sendByte(param);
  i2c_sendStartCondition();             // i2c バスを開始条件にする
  i2c_sendByte(PIC_READ);               // スレーブアドレスを送信
  i2c_setTransmitMode(2);               // マスタ受信モード
  for(i=0; i< n; i++) {
    IIC2.ICSR.BIT.TDRE = 0;
    if(i==n1) Data[i] = i2c_receiveByte(1, 1);            // ACK=1, RCVD = 1で受信する。
    else Data[i]  = i2c_receiveByte(0, 0); 
    IIC2.ICCR1.BIT.RCVD = 0;
  }
  i2c_sendStopCondition();                // i2c バスを停止条件にする。
  i2c_setTransmitMode(0);                 // スレーブ受信モードにする
  return 0;
}

void PIC_init(unsigned char adr)
{
  i2c_init();
  PIC_WRITE= adr;
  PIC_READ = adr+1;
}

void PIC_SetDirecrion(unsigned char dir)
{
  unsigned char x;
  PIC_getData(0x20, dir, &x, 1);
}

void PIC_Output(unsigned char data)
{
  unsigned char x;
  PIC_getData(0x21, data, &x, 1);
}

unsigned char PIC_Input()
{
  unsigned char x, data;
  PIC_getData(0x22, data, &x, 1);
  return x;
}

void PIC_ColorLED()
{
  unsigned char x;
  PIC_getData(0x70, 0x00, &x, 1);
}

void PIC_LED(unsigned char color)
{
  unsigned char x;
  PIC_getData(0x71, color, &x, 1);
}

void PIC_LEDstop()
{
  unsigned char x;
  PIC_getData(0x72, 0, &x, 1);
  PIC_getData(0x73, 0, &x, 1);
}
void PIC_getAD(int read_data[])
{
  // 何故か転送エラーがあるのでエラーの時は再送要求する
  do {
    PIC_getData(0x11, 0, (unsigned char*)read_data, 16);   // A/D converter  
  }
  while(read_data[7]!=0x1234);
}

int PIC_getADone(int chan, int read_data[])
{
  // 何故か転送エラーがあるのでエラーの時は再送要求する
  PIC_getData(0x14, chan, (unsigned char*)read_data, 1);
  do {
    PIC_getData(0x02, chan, (unsigned char*)read_data, 8); // status read   
  } while(read_data[0]!=0 || read_data[2]!=0x1234);
  return read_data[1];
}
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101
102
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 
133 
134 
135 
136 
137 
138 
139 
140 
141 
142 
143 
144 
145 
146 
147 
148 
149 
150 
151 
152 
153 

ある意味手を抜いて作っており、たまたま動いているという可能性があるので十分プロトコルを理解してから使用してください。
i2c.c
#include "iodefine.h"
void i2c_init(void);

/* ----------------------------------------------------------------------
    i2c_checkBusCondition
    i2c バスが空くまで待つ
---------------------------------------------------------------------- */
void i2c_waitBusFree() {
    while (IIC2.ICCR2.BIT.BBSY == 1);
}

/* ----------------------------------------------------------------------
    i2c_sendStartCondition
    i2c バスに開始要求を送る
---------------------------------------------------------------------- */
void i2c_sendStartCondition() 
{
    IIC2.ICCR2.BYTE = 0xbd;
}

/* ----------------------------------------------------------------------
    i2c_sendStopCondition
    i2c バスに停止要求を送る
---------------------------------------------------------------------- */
void i2c_sendStopCondition() 
{
    IIC2.ICSR.BIT.STOP = 0; /* STOP をクリアする*/
    IIC2.ICCR2.BYTE = 0x3D; /* 停止条件を発行する(BBSY=0, SCP=0) */
    while (IIC2.ICSR.BIT.STOP != 1) ;
}

/* ----------------------------------------------------------------------
    i2c_setTransmitMode
    i2c 送受信モードの設定

    0: スレーブ受信モード
    1: スレーブ送信モード
    2: マスタ受信モード
    3: マスタ送信モード
---------------------------------------------------------------------- */
void i2c_setTransmitMode(unsigned char tmode) {

  switch (tmode){
    case 0: tmode = 0x00;   // MST=0, TRS=0
        break;
    case 1: tmode = 0x10;   // MST=0, TRS=1
        break;
    case 2: tmode = 0x20;   // MST=1, TRS=0
        break;
    case 3: tmode = 0x30;   // MST=1, TRS=1
        break;
  }

  // レジスタに送受信モードを設定する
  IIC2.ICCR1.BYTE = ((IIC2.ICCR1.BYTE & 0xcf) | tmode);
}

/* ----------------------------------------------------------------------
    i2c_sendByte
    i2c バスへ1バイト送信
---------------------------------------------------------------------- */
unsigned char i2c_sendByte(unsigned char ch) 
{
    unsigned char tend;
    int i=30000;
    // データを送信する
    IIC2.ICDRT = ch;
    
    while(i--) {
        tend = IIC2.ICSR.BIT.TEND;
        if(tend == 1) {
          //IIC2.ICSR.BIT.TEND=0;
            break;
        }
        //if(i==1) i2c_init();
    }
    // ACK を返す
    return(IIC2.ICIER.BIT.ACKBR);
}

/* ----------------------------------------------------------------------
    i2c_receiveByte
    i2c バスから1バイト受信
    
    ack: データ受信時相手に返すACKビット
    rcvd: 最終バイトをリードするときは1にするこの後停止条件発行可能になる
          連続してデータ受信する場合は0
---------------------------------------------------------------------- */
unsigned char i2c_receiveByte(unsigned char ack, unsigned char rcvd) 
{
    unsigned char rdt;

    // データ受信後に送信するACKフラグを設定する。
    IIC2.ICIER.BIT.ACKBT = ack;

    // 最終バイト読み込み時は1
    IIC2.ICCR1.BIT.RCVD = rcvd;
    
    // i2c バスから送られるデータの受信開始
    rdt = IIC2.ICDRR;

    // データが8bit転送されるまで待つ
    while(IIC2.ICSR.BIT.RDRF != 1) ;

    // 揃ったデータを取り出す    
    rdt = IIC2.ICDRR;

    return(rdt);
}

/* ----------------------------------------------------------------------
    i2c_init   
    
    i2c初期化
---------------------------------------------------------------------- */
void i2c_init(void) {

    // I2C の転送レートをΦ/40(Φ=14.7456MHz, 368.6kHz)に設定する
    IIC2.ICCR1.BIT.CKS = 0x00;

  // IIC バスモードをMSB ファースト、ウェイト挿入しない、
  // ビット数: 9 ビットに設定する
    IIC2.ICMR.BIT.MLS = 0;  // MSB First
    IIC2.ICMR.BIT.WAIT = 0; // WAIT 無し
    IIC2.ICMR.BIT.BCWP = 0; // ビットカウンタライトプロテクト解除
    IIC2.ICMR.BIT.BC = 0;   // 9ビット
    IIC2.ICMR.BIT.BCWP = 1; // ビットカウンタライトプロテクト

  // IIC2 I/F モジュールの動作状態を転送動作可能状態
  // (SCL/SDA は、バス駆動状態)に設定する
    IIC2.ICCR1.BIT.ICE = 1;
}
 1 
 2 
 3 
 4 
 5 
 6 
 7 
 8 
 9 
10 
11 
12 
13 
14 
15 
16 
17 
18 
19 
20 
21 
22 
23 
24 
25 
26 
27 
28 
29 
30 
31 
32 
33 
34 
35 
36 
37 
38 
39 
40 
41 
42 
43 
44 
45 
46 
47 
48 
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61 
62 
63 
64 
65 
66 
67 
68 
69 
70 
71 
72 
73 
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86 
87 
88 
89 
90 
91 
92 
93 
94 
95 
96 
97 
98 
99 
100 
101
102
103 
104 
105 
106 
107 
108 
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 
123 
124 
125 
126 
127 
128 
129 
130 
131 
132 


取りあえずのHexファイル(右クリックして「対象をファイルを保存」し、ファイル名の拡張子をtxtからhexに変更する)

第九章に行く    ホームに戻る