PICマイコンを使って測定ツールを作ってみよう(6) ―― PIC12F1822を搭載したRS-485ネットワーク対応のセンサ基板を作成

中西 紫朗

tag: 組み込み 電子回路

エレキ系DIY 2011年12月 7日

●PIC12F1822のファームウェアはPIC18F2550向けを転用

 センサ基板に搭載しているPIC12F1822用のファームウェアについては,前述したように,PIC18F2550のコードをそのまま転用し,USB関連のルーチンを削除しています.PIC18F2550はプログラム領域が16Kワードもありますが,PIC12F1822は2Kワードしかありません.当然実現可能な処理が限られます.また,一番の問題はメモリが少ないことです.

 最初,UARTのバッファは32バイトとしていましたが,メモリ不足の嵐になり,泣く泣く10バイトまで削りました.当然,これからの出てくるであろう長尺パケットは処理できません.データをためて一気に送る方式のときも,それほど長いパケットは送れません.

 リスト3にソース・コードを示します.

 

リスト3 PIC12F1822のファームウェアのソース・コード(CQMMACP.c)

/**************************************************************
 Multi Interface PIC board
  for PIC12F1822
 **************************************************************
 author Shiroh Nakanishi

 version 1.00
 Tools:
 MPLAB v8.76
 Hitech PIC C pro9.82
---------------------------------------------------------------
Date :Time Version Build Note
20111026:0053 1.00 ---  Begin the program for 12F1822
---------------------------------------------------------------
Project folder(default)
 C:\PIC\CQMM
Source Files
 CQMMACP.c
Header Files
 
---------------------------------------------------------------
Pin assignment(PIC12F1822,8P)
 7:RA0:O: TXD
 6:RA1:I: RXD
 5:RA2:A: SEnsor INPUT (ADC)
 4:RA3:O:
 3:RA4:O:
 2:RA5:O: TXRX zelection
 8:VSS:P:
 1:VDD:P:
---------------------------------------------------------------
*/
#include <htc.h>
typedef unsigned char   byte;           // 8-bit

//__CONFIG(UNPROTECT & BORDIS & MCLREN & PWRTEN & WDTDIS & INTIO);
__CONFIG( CP_OFF & WDTE_OFF  & MCLRE_OFF & WRT_OFF & FOSC_INTOSC & CLKOUTEN_OFF );

void InitializeUSART(void);
void InitializeI2C(void);

// PROTYPE DECLARATION
void COMM_RS485(void);
void WR_EEPROM(byte address, byte data);
byte RD_EEPROM(byte address);
void put_UART(byte data);
void Send_RS485(byte CMND, byte ID, byte LEN);
int get_UART(void);
int Rcv_RS485(void);
void waitmsec(byte wait);
void waitusec(byte wait);
// Definition
#define uart_ptr_max 10
#define Reset_RS485 0
#define Ping 1
#define Read 2
#define Write 3
#define ACK 0x41
#define NAK 0x4E
#define myID 1  //  ***スレーブを変更するときのこのIDも変更してください****

//unsigned char input_buffer[16];  // USB command buffer
//unsigned char output_buffer[16];  // USB reply buffer
unsigned char UART_rd_buffer[uart_ptr_max]; // UART receive buffer (MASTER --> SLAVE)
unsigned char UART_wr_buffer[uart_ptr_max]; // UART send buffer (SLAVE --> MASTER)
unsigned char uart_wr_ptr,uart_rd_ptr,uart_buf_bytes,n_uart_wrbuf,uart_rcv_complete;
unsigned char ctstart,REGC7,COM_stage,SW[3];
static unsigned char  message_state = 0;

unsigned short a,cnt,tick_count,I2C_state,I2C_DA,I2C_RA,I2C_MDATA,I2C_SDATA,RCVFLG,cnt1;
unsigned char uart_rd_ptr,LEN;
int TMR0L,TMR0H,TMR0L1,TMR0H1,cnt01,cnt0;
unsigned char CMND,SID,ID,msg[8],FF_mode;

void interrupt isr(void)                      // 割り込み関数
{
/*
  T0IE = 0;  // Timer0割り込み禁止
  TMR1IE = 0;  // Timer1割り込み禁止
    if(TMR1IF){            // タイマ1割り込み25ms=8x37500 @48MHz
        TMR1IF=0;          // タイマ1割り込みフラグを0にする
  TMR1H = 0x6D;
  TMR1L = 0x84+24;
//  TMR1H = 0x0B;
//  TMR1L = 0xDC;
        if(--cnt1==0){              // cnt1を-1して結果が0?
            cnt1=4;                // cnt1にLEDの更新周期を書き戻す
            if(PORTAbits.RA4)  //    100m秒@20MHz
                PORTAbits.RA4=0;    //LED YELLOWを1秒間隔で点滅
            else
                PORTAbits.RA4=1;
   TMR0L1=TMR0L;
   TMR0H1=TMR0H;
   cnt01=cnt0;
   TMR0H=0;
   cnt0=0;
   TMR0L=0;
      GIE=1;          // 割り込みレベル許可
        }
 } else if(SSP1IF){  //I2C割り込み?
  SSP1IF=0;
  switch(I2C_state){
   case 0:
     if(SSP1STATbits.BF){
      I2C_DA=SSPBUF;
      I2C_state=1;
     }
     break;
   case 1:
     if(SSP1STATbits.BF){
      I2C_RA=SSP1BUF;
      I2C_state=2;
     }
     break;
   case 2:
     if(SSP1STATbits.BF){
      if(SSP1STATbits.R_nW==1){
       I2C_state=3;
      } else {
       I2C_MDATA=SSP1BUF;
       I2C_state=0;
      }
     }
     break;
   case 3:
     if(!SSP1STATbits.BF){
      SSP1BUF=I2C_SDATA;
      I2C_state=0;
     }
     break;
   }    
  PIE1bits.SSP1IE=1;
  } else
*/
 if(RCIF){  //USART割り込み?
//   if(RA4) { RA4=0; } else { RA4=1; }
  a=RCSTA;
  a=RCREG;
   UART_rd_buffer[uart_rd_ptr]=a;
  uart_rd_ptr++;
  uart_buf_bytes++;
  if(FF_mode==0) {
   if(a==0xFF) {
    FF_mode=1;
   } else {
    uart_rd_ptr=0;
    uart_buf_bytes=0;
   }
  } else if(FF_mode==1) {
   if(a==0xFF) {
    FF_mode=2;
   } else {
    uart_rd_ptr=1;
    uart_buf_bytes=1;
   }

  } else if(FF_mode==2){
   
   if(uart_rcv_complete==0){
 
    if(uart_buf_bytes==5) LEN=a;
    if(uart_buf_bytes>=LEN+5 ) {
     uart_rcv_complete=1;
     RA4=1;
     uart_rd_ptr=0;
     FF_mode=0;
    }
   }
  }
/*   if(RCIF){
//    if(RA4) { RA4=0; } else { RA4=1; }
    a=RCREG;
     UART_rd_buffer[uart_rd_ptr]=a;
    uart_rd_ptr++;
    uart_buf_bytes++;
    if(uart_buf_bytes==6) {
     LEN=UART_rd_buffer[4];
    }
    if(uart_buf_bytes>=LEN+7 ) {
     uart_rcv_complete=1;
     RA4=1;
     uart_rd_ptr=0;
    }
   }
*/
//   if(!uart_rcv_complete) if(RA4) { RA4=0; } else { RA4=1; }
//   if(OERR) if(RA4) { RA4=0; } else { RA4=1; }
//   if(OERR) if(RA4) { RA4=0; } else { RA4=1; }
   if(OERR) {
    CREN=0;
    CREN=1;
   }
  }
 CREN=1;
 RCIE=1;
 PEIE=1;
    INTCONbits.GIE=1;          // レベル許可
// INTCONbits.T0IE = 1;
// PIE1bits.TMR1IE = 1;

}                                  

void COMM_RS485(void)
{

   static unsigned char devaddr, regaddr, i2cdata, i2cdata2 ;
   unsigned char N,i,j,k,ch,I2Cdata2,ASD_type,ASD_num;
 unsigned char RSP,Resp,data;              

// Push button Switch interpreter


// RS485 command interpreter

//
//  Packet format ( RS485 network MASTER <-> SLAVE )
//            aa[0]    aa[1]   aa[2]    aa[3]   aa[4]            aa[2+LEN]
//   | ID  |  LEN   |  CMND   |  PRM0  | PRM1 | ------- | PRMx   |
//             0x00 : RESET
//      0x01 : PING
//             0x02 : READ
//             0x03 : WRITE
//  RS485 Command state machine
//     Send Command PC>MASTER>SLAVE : COM_stage=0
//         Receive Reply SLAVE>MASTER>PC : COM_stage=1
//
// RS485 Ack packet proccessor
 if(uart_buf_bytes>0){
 }
 if(uart_rcv_complete){
  Resp=Rcv_RS485();
  RA4=0;
  for(i=0; i<10; i++){
   for(j=0; j<10; j++);
  }
//  Send_RS485(Resp,ID,LEN);
  if((ID==0xFE)||(ID==myID)){
   switch(CMND){
     case Reset_RS485:
    if(ID==myID){
     if(Resp==0) {
      RSP=0x41;  // ACK
     } else {
      RSP=0x4E;  // NAK
     }
     Send_RS485(RSP,ID,LEN);
    } 
    break;
     case Ping:
    if(ID==myID){
     if(Resp==0) {
      RSP=0x41;  // ACK
     } else {
      RSP=0x4E;  // NAK
     }
     Send_RS485(RSP,ID,LEN);
    }  
    break;
   case Read:
    if(ID==myID){
     if(Resp==0) {
                  ADCON0 = 0x0B;  // ADC=AN2, GODONE, ADC ON
                  while((ADCON0&0x02) == 1);  // ADC Complete?
      UART_rd_buffer[5]=ADRESH;
      UART_rd_buffer[6]=ADRESL;
      RSP=0x41;  // ACK
     } else {
      RSP=0x4E;  // NAK
     }
     Send_RS485(RSP,ID,LEN);
    } 
    break;
   case Write:
    if(ID==myID){
     if(Resp==0) {
      RSP=0x41;  // ACK
     } else {
      RSP=0x4E;  // NAK
     }
     Send_RS485(RSP,ID,LEN);
    } 
    break;
   }    
  }
  
  } // End of COM_stage switch
  for(i=0; i<10; i++){
   for(j=0; j<10; j++);
  }

// UART TX serialization
  if(TXSTAbits.TRMT==1){
   if(n_uart_wrbuf==0) { RA5=0; } else { RA5=1; }
   if(n_uart_wrbuf!=0){
    TXREG=UART_wr_buffer[uart_wr_ptr];
    uart_wr_ptr++;
    if(uart_wr_ptr>uart_ptr_max) uart_wr_ptr=0;
    n_uart_wrbuf--;
    if(n_uart_wrbuf==0) {
     uart_wr_ptr=0;
    }
   }
  }
  // end_of_USB_process:
   i=0;
}        //end of COMM_RS485

void InitializeUSART(void)
{
  char c;
//        UART_TRISRx=1;    // RX
//        UART_TRISTx=0;    // TX
        TXSTA = 0x24;        // TX enable BRGH=1
        RCSTA = 0x90;        // SP enable,Single Character RX
        SPBRG = 0x67;
        SPBRGH = 0x00;       // 0x067 for 16MHz -> 19200 baud
        SPBRG = 0xA0;
        SPBRGH = 0x01;       // 0x1A0 for 16MHz -> 9600 baud
        BAUDCON = 0x08;      // BRG16 = 1
//        c = RCREG;    // read
}
void put_UART(byte data)
{
 UART_wr_buffer[uart_wr_ptr]=data;
 uart_wr_ptr++;
 n_uart_wrbuf++;

void Send_RS485(byte CMND,byte ID,byte n)
{
 byte i,j,data,chksum;
    chksum=0;
 
 RA5=1;  // Change LTC485 to TX mode
 RA4=1;

 put_UART(0xFF);
 put_UART(0xFF);
 put_UART(CMND);
 chksum+=CMND;
 put_UART(ID);
    chksum+=ID;
 put_UART(n);

 chksum+=n;

 for (i=0; i<n; i++){
  data=UART_rd_buffer[i+5];
  put_UART(data);
        chksum+=data;
 }
    put_UART(chksum&0xFF);
    uart_wr_ptr=0;
  for(i=0; i<10; i++){
   for(j=0; j<10; j++);
  }
}
int get_UART(void)
{
 byte data;

 if(uart_buf_bytes>0) {
  data=UART_rd_buffer[uart_rd_ptr];
  uart_rd_ptr++;
  uart_buf_bytes--;
  return data;
 } else {
  return -1;
 } 
}
int Rcv_RS485(void)
{
 byte i,ret,data;

 ret=0;

 uart_rd_ptr=0;
 data=get_UART();
 if(data!=0xFF)  { 
  while(data!=0xFF){ data=get_UART(); }
  }
 data=get_UART();
 if(data!=0xFF){ 
  uart_rd_ptr=0;
  uart_buf_bytes=0;
  uart_rcv_complete=0;
  return 1;
  }
 data=get_UART();
 if((data>=0)&&(data<5 )) {
    CMND=data;
   } else {
  uart_rd_ptr=0;
  uart_buf_bytes=0;
  uart_rcv_complete=0;
   return 3;
  }
 

 ID=get_UART();
// LEN=get_UART();
 a=get_UART();
 for( i=0; i<LEN+4; i++){
//  data=get_UART();
  UART_wr_buffer[i]=UART_rd_buffer[i];
  msg[i]=data;
 }
 uart_rd_ptr=0;
 uart_buf_bytes=0;
 uart_rcv_complete=0;

 return 0;

}
void WR_EEPROM(byte addr, byte data)
{
    EEADR = addr;
 EEDATA = data;
 EECON1bits.WREN = 1;
 EECON2 = 0x55;
 EECON2 = 0xAA;
 EECON1bits.WR = 1;
 while (EECON1bits.WR);      
}//end of WR_EEPROM

byte RD_EEPROM(byte address)
{
    EEADR = address;

 EECON2 = 0x55;
 EECON2 = 0xAA;
 return EEDATA;
}      

void main()
{
unsigned short LED;
int i,j,k;
 //OPTION = 0x87; // prescaler 1:256
65.536ms@4MHz
 OPTION_REG = 0x80; // prescaler 1:2
512us@4MHz
 OSCCON=0xFF;  // 16MHz
 APFCON = 0x00;      // TXD(RA0),RXD(RA1)
 ANSELA = 0x04;  // AN2(RA2)
 CCP1CON =0x00;  // Capture/Compare/PWM disabled
 TRISA = 0x06;  // RXD(RA1),AN2(RA2)
 PORTA = 0x00;
 
 TMR0 = 0;
 INTCON = 0x00; // GIE:1,T0IE:1

 ANSELA = 0x04;
 ADCON0=0x09; // ADFM:Left
 ADGO=0;
 InitializeUSART();
 uart_rcv_complete=0;
 RCIE=1;
 PEIE=1;
 GIE=1;
 RA5=1;  // Change LTC485 to TX mode
 RA5=0;  // Change LTC485 to TX mode
 RA4=0;
 LEN=3;
 FF_mode=0;
/*
    while(1){
  for(k=0; k<10; k++){
  if(TRMT==1){
    TXREG=0x30+k;    
  }
  for(i=0; i<10; i++){
   for(j=0; j<100; j++);
  }
//  RA5^=1;  // Change LTC485 to TX mode
  }
 }
*/
 while(1){
  COMM_RS485();
  for(i=0; i<10; i++){
   for(j=0; j<10; j++);
  }
 }
}

 

 

 なお,リスト1リスト3のソース・コードは,こちらからダウンロードできます.

 

               *               *               *

 

 今回は5種類のセンサ基板を紹介し,紫外線センサ基板について動作を確認しました.次回は残りのセンサ基板の動作確認を行って報告したいと思います.

 

なかにし・しろう
(有)NSL

 

 

組み込みキャッチアップ

お知らせ 一覧を見る

電子書籍の最新刊! FPGAマガジン No.12『ARMコアFPGA×Linux初体験』好評発売中

FPGAマガジン No.11『性能UP! アルゴリズム×手仕上げHDL』好評発売中! PDF版もあります

PICK UP用語

EV(電気自動車)

関連記事

EnOcean

関連記事

Android

関連記事

ニュース 一覧を見る
Tech Villageブログ

渡辺のぼるのロボコン・プロモータ日記

2年ぶりのブログ更新w

2016年10月 9日

Hamana Project

Hamana-8最終打ち上げ報告(その2)

2012年6月26日