BLOG

PIC24 based DMX Receiver to 5PWM with XC16

すでにPIC24(CCSコンパイラ)用に移植したDMX受信プログラムをXC16コンパイラ用に修正した。回路図(下図をクリックして拡大)は前回の記事とほぼ同じだが、PWM出力のピンが異なる。この回路はバイオメタル制御用に開発したので定電流源IC(TICx)やFET(Qx)なども追加している。

XCコンパイラを使ってみた印象ではCCSよりもわかりやすい。CCSは細かい設定をブラックボックス化してくれるので初心者には使いやすいのかもしれないが、PICを使いこなそうとした場合、結局データシートを見ながらレジスタを設定しなければならないことが多く、PICのレジスタを直接扱うXCコンパイラのほうがデータシートの解説と直結するので理解がしやすい。また、これまでWin7環境でMPLAB IDE v8を使ってきたが、今更ながらMPLAB-X IDE(Mac環境)で開発したところかなり使いやすくなっていた。特に、レジスタ名さえわかればビット名をリストアップしてくれる機能のおかげでコーディングスピードがあがり、記述ミスもなくなる。Configration bitの自動生成機能のほか、Code Configratorを使うことで様々は周辺機能も簡単に設定できる。PICの機種間の違いもつかみやすい。進化しているな〜

なお、私のプログラムの知識は完全に独学なのでコードには必要のない部分もあるかもしれない。とりあえず動作するが、あくまで参考程度に。

//XC16 v1.25コンパイラ
//DMX受信プログラム
//PIC24FJ64GA004用

#include "xc.h"
#define FCY 10000000UL   // PIC24FのデータシートからFCY=FOSC/2
//delayマクロを使うにはlibpic30.hをインクルードする必要があるが、インクルードする前にFCYを宣言する必要がある。
#include <libpic30.h>
#define _XTAL_FREQ 20000000
#pragma config POSCMOD = HS  // 主発振器+10MHz以上の水晶発振子
#pragma config FNOSC = PRI   // 主発振器(水晶発振子(XT, HS)or 水晶発振器(EC))
#pragma config FWDTEN = OFF  // Watchdog Timer Enable (WDT disabled in hardware; SWDTEN bit disabled)

#define MAX_PWMS 512
#define START_CH 0 //Max上は+1ch表記になる

unsigned char Rx_Buffer[MAX_PWMS]; //XC16ではunsigned charが8bit変数

int Check_levels=0;
int i;

int main(void)
{
   U1BRG = 0x09; //ボーレートプリスケーラ 外部主発振子20MHz 250kbps for DMX
   U1MODEbits.BRGH = 1;

   U1MODEbits.STSEL = 1; //ストップビットを2bitに設定
   U1MODEbits.UARTEN = 1;//UARTの開始
   
   //ピン割付 24FJ64GA004
   TRISBbits.TRISB9 = 1; //UART受信 in RP9(RB9)
   TRISCbits.TRISC6 = 0; //RC6 out SMA-1
   TRISCbits.TRISC7 = 0; //RC7 out SMA-2
   TRISCbits.TRISC8 = 0; //RC8 out SMA-3
   TRISCbits.TRISC9 = 0; //RC9 out 先端白色LED
   TRISBbits.TRISB10 = 0; //RB10(RP10) ステータスLED out
   
   //PWM割り当て
   RPOR11bits.RP22R = 18; //OC1(Output Function Number 18) out to RP22(RC6))
   RPOR11bits.RP23R = 19; //OC2(Output Function Number 19) out to RP23(RC7))
   RPOR12bits.RP24R = 20; //OC3(Output Function Number 20) out to RP24(RC8))
   RPOR12bits.RP25R = 21; //OC4(Output Function Number 21) out to RP25(RC9))
   RPOR5bits.RP10R = 22;  //OC5(Output Function Number 22) out to RP10(RB10))

   //PWM用タイマー2
   T2CONbits.TCKPS = 0b00; //Timer2 Prescale 1:1は0b00(初期値)、1:8は0b01、1:64は0b10、1:256は0b11
   PR2 = 0x3ff;//Timer2 Period Value 1023は16進数で0x3FF 0xffは10進数で255
   T2CONbits.TON = 1; //Timer2 ON
  
   //UART設定
   RPINR18bits.U1RXR = 9;// U1RXをRP9(RB9) に割り当てる          
   IPC2bits.U1RXIP = 4; // Rx割込優先度を4に設定 (既定値) _U1RXIP = 4;も同じ意味
   IEC0bits.U1RXIE = 1; // uart1 RX割込み許可 _U1RXIE = 1;も同じ意味

    //PWM設定
    OC1CONbits.OCTSEL = 0; //Timer2(既定値)
    OC1CONbits.OCM = 0b110; //PWM Mode, Fault pin is disabled
    OC2CONbits.OCTSEL = 0; //Timer2(既定値)
    OC2CONbits.OCM = 0b110; //PWM Mode, Fault pin is disabled
    OC3CONbits.OCTSEL = 0; //Timer2(既定値)
    OC3CONbits.OCM = 0b110; //PWM Mode, Fault pin is disabled
    OC4CONbits.OCTSEL = 0; //Timer2(既定値)
    OC4CONbits.OCM = 0b110; //PWM Mode, Fault pin is disabled
    OC5CONbits.OCTSEL = 0; //Timer2(既定値)
    OC5CONbits.OCM = 0b110; //PWM Mode, Fault pin is disabled
    
	//DMX_LevelsとRx_Buffer初期設定
	for (i=0; i<MAX_PWMS; i++) {
		Rx_Buffer[i] = 0;
	}
 
        //LED起動確認
    LATBbits.LATB10 = 1; // LED on (high)
    __delay_ms(300);
    LATBbits.LATB10 = 0; // LED off (low)
 	__delay_ms(300);
    LATBbits.LATB10 = 1; // LED on (high)
    __delay_ms(300);
    LATBbits.LATB10 = 0; // LED off (low)
 	__delay_ms(300);

 	while (1)
   	{
   		if (Check_levels)
      	{
        	Check_levels=0;

            //タイマー2のPR2を1023で設定したので、DMXの256階調を1024階調に変換している
            OC1RS = (1023 + 1) * ((float)Rx_Buffer[START_CH] / 256);
            OC2RS = (1023 + 1) * ((float)(Rx_Buffer[START_CH+1]) / 256);
            OC3RS = (1023 + 1) * ((float)(Rx_Buffer[START_CH+2]) / 256);
            OC4RS = (1023 + 1) * ((float)(Rx_Buffer[START_CH+3]) / 256);
            OC5RS = (1023 + 1) * ((float)(Rx_Buffer[START_CH+4]) / 256);
			
      	} //END if

   } //END_WHILE
    
 
 return (0);
}

/************************************************************************
*                          UART割り込み関数                                  *
************************************************************************/

void __attribute__ ((interrupt, no_auto_psv)) _U1RXInterrupt(void)
{
    IFS0bits.U1RXIF = 0; //割り込み関数が動作したら、すぐに割り込みフラグはクリアする

  	#define WAIT_FOR_NEXT_BYTE 0
  	#define WAIT_FOR_BREAK     1
  	#define WAIT_FOR_START     2
  	#define RECEIVE_DATA       3

	static int Rx_State = WAIT_FOR_BREAK;
	char data;

	union //受信ステータスタック用の構造体を含む共用体
	{
  		unsigned int word;
		struct {
			unsigned int URXDA:1;
			unsigned int OERR:1;
			unsigned int FERR:1;
			unsigned int     :13; //これ以降は使わないので省略
 		} bits;
	} naka_u1sta;

	static int Rx_Index = 0;
            
	while(U1STAbits.URXDA)//受信データがあれば1,なければ0
	{
		naka_u1sta.word = U1STA; //OERRとFERRを検出するためのスタック
		data = (char)U1RXREG; //受信データの読み込み

    	if (naka_u1sta.bits.OERR)
    	{
            
	  		U1STAbits.OERR = 0; //UART受信バッファクリア
      		Rx_State = WAIT_FOR_NEXT_BYTE;
      		return;
      	}

    	switch (Rx_State)
    	{
      		case WAIT_FOR_NEXT_BYTE:

        	if (!naka_u1sta.bits.FERR)
          		Rx_State = WAIT_FOR_BREAK;
        	break;

      		case WAIT_FOR_BREAK:

        	if (naka_u1sta.bits.FERR)
        	{
          		if (!data)
            	Rx_State = WAIT_FOR_START;
        	}
        	break;

      		case WAIT_FOR_START:

        	if (naka_u1sta.bits.FERR)
            	Rx_State = WAIT_FOR_NEXT_BYTE;
        	else
        	{
          		if (!data)
          		{
            		Rx_Index = 0;
            		Rx_State = RECEIVE_DATA;
          		}
        	}
        	break;

      		case RECEIVE_DATA:

       		if (naka_u1sta.bits.FERR)
        	{
          		if (!data)
            	Rx_State = WAIT_FOR_START;
          		else
            	Rx_State = WAIT_FOR_NEXT_BYTE;
        	}
        	else
        	{
            	Rx_Buffer[Rx_Index] = data;
            	++Rx_Index;
            	Check_levels=1;
        	}
        	break;

    	} //END switch

  	} //END while

  return;
}  //END