Vol.840 11.Mar.2022

BD・DVDレーベルの作成と印刷 「マクロ」と「インライン」 PICでUSB接続とLCD表示をライブラリ化

L BD・DVDレーベルの作成と印刷 〜画像の取得

by fjk

 テレビの番組をブルーレイ(BD)やDVDに書込保存しているが、その内容が分かるように、途中の画像を使ったレーベルを印刷している。この時、番組データから画像をを取得するには、以下の3種類がある。

@ 動画再生ソフトを利用し、画面キャプチャーを利用する。
A 動画再生ソフトを利用し、モニタ画面をカメラで撮影する。
B レコーダで再生し、テレビ画面をカメラで撮影する。

 @は表示画面サイズで綺麗な画像が得られるが、BDはキャプチャーできない(可能なソフトもあるが基本的に違法)。ABはカメラを正しく位置決めしないと画像が歪んだり、周囲の明かりが映り込んだりする。テレビは有機EL画面の方がくっきり映る。
 そこで、@の場合同じ番組を(画質は落ちるが)DVD-Videoでも録画し、キャプチャーする方法がある(DVD-Videoの作成には実時間と同じ時間が必要)。また、ABではabc822で紹介した「ピタリ四角」を使って、画像の歪の修正と切り出しを同時に行うことで、綺麗な画像を得ることができる。
 このようにして得られた画像を使ってレーベルを作成し、EPSONのPrintCDでレーベル印刷を行った。

スタンドを使って画像を撮影 ピタリ四角で歪を補正し切り出し 出来上がったレーベル(印刷トレイ上)


M 「マクロ」と「インライン」

by fjk

 プログラムをコーディング中に、何度も同じコードを記述することがある場合に、自らが定義したコードブロックを宣言し、その部分を同じ定数や式に書き換えることができる。この処理には「マクロ」と「インライン」の2種類がある。
 これらは、”ある機能を果たす処理のまとまり”である「関数」と異なり、コンパイル時に実際のコードに置き換えられるので、関数呼び出しによる負荷が少なくなり、実行速度も早くなる。しかし、ソースファイルに関数が展開されるので、ファイルサイズが大きくなるデメリットもある。
 「マクロ」はプリプロセッサによって展開され、基本的にはコードそのものの置き換えとなる。これに対して、「インライン」はコンパイラによって展開され、型チェックや引数チェックも同時に行われる。これらの違いをまとめると、

マクロ インライン
宣言方法#define funcname() functiom() inline type function(){ };
定義位置プログラムの最初 クラスの内部または外部
終 了 新しい行(セミコロン不要) セミコロン(関数と同じ)
デバッグマクロ内でのエラーは特定しにくいインライン内で
ブレークポイント作成も可
関数評価呼び出される毎に(複数回)評価 1回だけ評価


P PICでUSB接続とLCD表示をライブラリ化

by fjk

 前報abc839ではmain.cに全てのコードを記述したが、プログラムが長くなり見づらい。そこで、汎用で使えるコードブロックをライブラリとして別のファイルにすると、他のプログラムでもそのまま使うことができ便利である。このような分割ファイルを扱うには前報でも少し紹介したが、プロジェクトを右クリック後「New」からファイルを新規に作成(この場合は自動的にプロジェクトに追加される)するか、エディッタなどで別途作成する場合は、

@ ライブラリにするコードブロックを記述したCファイル(○○.c)を作る。
A @のファイルに対応するヘッダーファイル(○○.h)を作る。
B これらのファイルをプロジェクトフォルダーにコピーする。
C MPLAB_Xのプロジェクトに上記のファイルが追加されていることを確認する。
D プロジェクトを右クリックし「Add Existing Item 」を選択する。
E 表示ファルダー内の追加したいファイルを選んで「Select」を押す。

以上で追加したいファイルがプロジェクトに追加され、一緒にコンパイルされることになる。
※ なお、ファイルが不要となった場合は、ファイル選択後「Remove From Project」で削除できる。
※ 作成ライブラリがプロジェクトフォルダー以外の場所にある場合は「Add Existinf Item fron Folder」でプロジェクトに追加できる。

ファイルの追加画面
【前報(abc839)のプログラムを分割した例】
/*----- i2cLCD_AQM0802A.c ------*/

#include "i2cLCD_AQM0802A.h"

#define CONTRAST       0x18    // for 5.0V
//#define  CONTRAST      0x30    // for 3.3V
#define BOOST          0x00    // for 5.0V Bon=off
//#define  BOOST         0x04   // for 3.3V Bon=on

void LCD_dat(char chr){
    I2C_Write1ByteRegister(I2CLCD_AQM0802A, 0x40, chr);
    __delay_us(30); 		// 30us
}

//-------- send command -------------------------
void LCD_cmd(char cmd){
    I2C_Write1ByteRegister(I2CLCD_AQM0802A, 0x00, cmd);
    if(cmd & 0xFC)		// bit6 = 1
        __delay_us(30); 	// 30us
    else
        __delay_ms(2);		// 2ms Clear or Home
}

//-------- clear LCD--------------------------
void LCD_clr(void){
    LCD_cmd(0x01);
}

//--------- Home -----------------------------
void LCD_home(void){
    LCD_cmd(0x02);
}

//--------- Cursor X,Y -----------------------
void LCD_cursor(int x, int y){
    if (y == 0)
        LCD_cmd(0x80 + x);
    else if (y == 1)
        LCD_cmd(0xc0 + x);
}

//-------- display strings -------------------------
void LCD_str(char *str){
    while(*str)
 	LCD_dat(*str++); 	//pointer increment
}

//-------- write 1 character to LCD ----------------
void putch(char ch){
    LCD_dat(ch);
}

//-------- LCD initialize ---------------------------
void LCD_init(){
    __delay_ms(40);     	//40ms wait
    LCD_cmd(0x38);      	//8bit,2line
    LCD_cmd(0x39);      	//IS=1 : extention mode
    LCD_cmd(0x14);      	//Internal OSC Frequency
    LCD_cmd(0x70+(CONTRAST & 0x0F)); 
    LCD_cmd(0x58+BOOST+(CONTRAST>>4));
    LCD_cmd(0x6C);      	//Follower control
    __delay_ms(200);    	//200ms wait
    LCD_cmd(0x38);      	//IS=0:extention mode cancel
    LCD_cmd(0x0C);      	//Display ON
    LCD_cmd(0x01);      	//Clear Display
    __delay_ms(2);      	//wait more than 1.08ms
}
/********  End of File ******/

*----- i2cLCD_AQM0802A.h ------*/
#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c_master_example.h"
#define I2CLCD_AQM0802A 0x3e

void LCD_dat(char chr);
void LCD_cmd(char cmd);
void LCD_clr(void);
void LCD_home(void);
void LCD_cursor(int x, int y);
void LCD_str(char *str);
void LCD_init();
/********  End of Header File ******/

*----- USB_1459_CDC.c ------*/
#include "mcc_generated_files/mcc.h"
#include "USB_1459_CDC.h"

void SendUSB_char(char c){
    do
        CDCTxService();
    while (!USBUSARTIsTxTrfReady());
    putUSBUSART(&c, 1);
    CDCTxService();
}
 
void SendUSB_str(char *str){
    do
        CDCTxService();
    while (!USBUSARTIsTxTrfReady());
    putsUSBUSART(str);
    CDCTxService();
}

void SendUSB_int(int val){
    char iBuf[10];
    sprintf(iBuf,"%d: ",val);
    SendUSB_str(iBuf);
}

int RecvUSB(char *buf,int bfsize){
    return getsUSBUSART(buf, bfsize);
}
/********  End of File ******/

/*----- USB_1459_CDC.h ---*/
#include "mcc_generated_files/mcc.h"
#include <stdio.h>
void SendUSB_char(char c);
void SendUSB_str(char *str);
void SendUSB_int(int val);
int RecvUSB(char *buf, int bfsize);
/********  End of File ******/

/*----- main.c ------*/

#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#include "USB_1459_CDC.h"
#include "i2cLCD_AQM0802A.h"

#define  BFSIZE 32

char NEWLINE[] = "\r\n";
static char rBuf[BFSIZE];       // USB Read Buffer
static char wBuf[BFSIZE];       // USB Write Buffer

int tmFlg;                      // Timer2 Flag

/*====        Main application  ==== */
void main(void)
{
    SYSTEM_Initialize();		 	// initialize the device

    INTERRUPT_GlobalInterruptEnable();		// Enable the Global Interrupts
    INTERRUPT_PeripheralInterruptEnable();	// Enable the Peripheral Interrupts
 
    int swFlg = 0;              // Switch Flag
    int adFlg = 0;              // ADconvert Flag
    int num, i;
    int aVal;        		// AD Converted data
    
    LCD_init();
    char msg[] = "Hello!";
    LCD_str(msg);
    while(USBGetDeviceState() < CONFIGURED_STATE);
    SendUSB_str(msg);
    SendUSB_str(NEWLINE);

    while (1) {
        num = RecvUSB(rBuf, BFSIZE);
        if(num > 0) {
            for(i=0; i < num; i++) {
                switch (rBuf[i])  {
                    case 0x0A:
                    case 0x0D:
                    	wBuf[i] = 0x00;
                    	break;
                    default:
                        wBuf[i] = rBuf[i];
                        break;
                }
            }
            LCD_clr();
            LCD_str(wBuf); 
            SendUSB_str("PIC> ");
            SendUSB_int(num);
            SendUSB_str(wBuf);
            SendUSB_str(NEWLINE);
            if(( rBuf[0] & 0x01) == 0)
               	LED_SetLow();
            else
               	LED_SetHigh();
        }
        if((SWC3_GetValue() == 0) & (swFlg == 0)){
           swFlg = 1;
           if(adFlg == 0){
             	sprintf(wBuf,"ADC Start");
                SendUSB_str(wBuf);
               	SendUSB_str(NEWLINE);
               	adFlg = 1;
           }else{
               	sprintf(wBuf,"ADC Hold");
                SendUSB_str(wBuf);
               	SendUSB_str(NEWLINE);
               	adFlg = 0;                
           }
        }else if((SWC3_GetValue() > 0) & (swFlg == 1)){
           swFlg = 0;
        }
        aVal = ADC_GetConversion(3);
        if((tmFlg > 0) & (adFlg > 0)){
            sprintf(wBuf,"ADC:%4d",aVal);
            LCD_cursor(0,1);
            LCD_str(wBuf);
            SendUSB_str(wBuf);
            SendUSB_str(NEWLINE);
            tmFlg = 0;
        }
    } 
}
/********  End of File ******/
※USB接続の準備を確認するため、以下のSTATE確認を追加(3/28、でもまだ不安定)
   while(USBGetDeviceState() < CONFIGURED_STATE);


BD・DVDレーベルの作成と印刷 「マクロ」と「インライン」 PICでUSB接続とLCD表示をライブラリ化