Vol.924 8.Aug.2025

モノクロ写真をカラー化 PIC(3.3V)とSPIデバイスまとめ

C モノクロ写真をカラー化

by fjk

 AIによる画像処理が当たり前になりましたが、サーバーに個人情報が入ったモノを送信するのが不安になることがあります。そこで、サーバーを利用しないAI画像処理ソフトを使ってみました。無料版では透かしが入るなど、使用に制限がありますが、使ってみて良ければ購入しても良いのかな、と思います。
 多くのソフトでは動画対応やカラー化以外の機能もありますが、今回は、カラー化に特化した「着彩!モノクロ写真」(ソースネクスト、@3,960)です。
 カラー化はワンクリックで、人物は結構綺麗ですが、樹木等があると緑色がかぶるところがあります


「着彩!モノクロ写真」カラー化作業中画面

元 画 像       カラー化画像

元 画 像

カラー化画像(背景の緑の影響が若干・・)

【その他のカラー化可能ソフト例】 (Photopshopでもできますが・・)

@ AVCLabs Photo Enhancer AI
A HitPaw FotorPea
B PhotoPad
C WinxvideoAI
D 4DDig (データ回復ソフト)


P PICミニBBシリーズ(24)  〜PIC(3.3V)とSPIデバイスのまとめ

by fjk

 abc923で、PICの3.3V動作を確認したので、SPI接続のOLED+EEP-ROM+SD-cardをまとめてみた。
 各デバイス用のライブラリは各関数をなるべく独立で使用できるようにした。これらに伴い、これまでのプログラムは大幅な変更を行った。

【ハード】
   PIC:PIC16F18326、  Display:QT095B、  Memory:M95M02、  SDcardSlot:BOB-00544
   USBif:FT234X、    3.3V_DC-DC:AMS1117-3.3、  ICSP:PicKit4


回 路 図(PIC16F18326、LEDは抵抗入、WP使用はA5端子を利用可)

ブレッドボード配線状況(黒いピンはスペーサー)

【ソフト】 (MCC)


Pin Module

System Module
 

TMR0 Module
 
EUSART Module            MSSP1 Module
  

========== プログラムリスト ==========
    (全てのケースのデバッグが終わっていないのでバグがあるかもしれません)

@オリジナル  <abc924-18326.zip
abc924-18326.c
mainプログラム
my_conf.h
機能選択・宣言
myProject.h
プロジェクトの環境宣言
myFunction.c/h
EUSART等の汎用関数
AOLED表示  <QT095B_2.zip
QT095B_2.c/h
グラフィックOLED表示
Font_5x7.h
5x7ドットフォントデータ
Bspiメモリ  <spi_mem_2.zip>  <spi_mem_2R.zip('R'コマンド付き)
spi_mem_2.c/h
spi接続EEPROM
kanji.c/h
漢字フォントROM
CSDカード  <sd_card_2.zip
sd_card_2.c/h
SDカード用読み書き関数
diskio.c/h
SDカードアクセス
pff.c/h
プチFAT(dirで修正が必要なので添付ファイルを使うこと)
pffconf.h
プチFAT用環境ファイル
★ EUSARTの設定はabc917を参照のこと。
'R'コマンド付きspi_mem_2R.zipは、解凍すると spi_mem_2c/h とファイル名は同じなので、置き換えること。
 そして、main()関数の switch(cmd) 内に case 'R': sM_cmd_R(RBuf); break; // メモリ読込 を1行追加。
★ DIR+BMP+KANJIは 'R'コマンド追加後も同時に使えるが、漢字フォントデータをROM書込後に確認したい場合、
  KAN_TESTを宣言し main()内で、以下のようにJコマンドをコメント(不使用)にするとメモリ内に収まり、Kコマンドが使える。
// case 'J': sK_cmd_J(RBuf); break; // 漢字表示(JISコード)
★ 'J'、'K'コマンドを同時に使いたいときは、DIR+KANJI+KAN_TEST を宣言し(BMPは不使用)、 main()関数内で
case 'J': sK_cmd_J(RBuf); break; // 漢字表示(JISコード) とJコマンドを有効にし、
// case 'A': Bf_cmd_A(RBuf); break; // バッファー書込(文字)
// case 'R': sM_cmd_R(RBuf); break; // メモリ読込
  と、'A'、'R'コマンドをコメント(不使用)にするとメモリ内に収まる。
★ S-jis漢字を表示するには、(コンパイル時に警告が出るが、問題なく使えます)
gOLED_ZchrX(0,0,'漢',255,0,0);    // S-jis漢字単文字:ed=0
gOLED_ZstrX(0,20,"漢字",255,0,1);  // S-jis漢字文字列:ed=1
★ フォントデータROMのMAP2は、FontRom_Map2.xlsx(zip)を参考に。
★ フォントデータROMへのデータ書込には、BDF_Edita3X_PC.xlsm(zip)(機種依存文字を含む)等を使用。
  BDFフォントエディッタ使い方は abc909abc905 等を参照。

========== ターミナルコマンド ==========
  [ ]はオプション、斜文字はパラメータ。
 ※'A'コマンドを追加(8/12)'R'コマンドを追加(8/16)バグ修正(8/17)文字表示コマンドを追加(8/20)

/********* OLED・バッファー ************/
C
グラフィック画面消去
B[bofs][,n]
バッファデータ表示
S[bofs],h0[,h1[,・・]]
バッファに16進数データを書込
A[bofs,]str
バッファに文字列を書込(コンマの位置に注意!
/********** メモリ ***********/
BR/BW[adr][,n]
メモリ ⇔ バッファー
W[adr],h0[,h1[,・・]]
メモリに16進数データを直接書込む
R[adr][,n]
メモリから16進数データを直接読み込む (8/16 追加)
ERadr
**メモリ消去(フラッシュメモリ使用時)
K[H][adr]
*漢字テスト表示(アドレス)
[code]
*漢字テスト表示(JISコード)
/********** SDカード ***********/
BL/BS[sofs][,n]
SDカード ⇔ バッファー
F[FileName]
ファイル名を設定
D[dirName]
*ディレクトリーデータ表示
I
*現在ファイル情報を表示
V
*BMPファイルを読込表示

bofsn (共に最大512)は10進数、adrsofsは最大5桁の16進数、hxは1バイトの16進数(16進数には0xを付けない)。
★ 注*) K、J、D、I、V、ER コマンドはメモリが不足するので、全てを同時に使えない(my_conf.hで使用するコマンドを選択可能)。
★ 注**) ERコマンドはIS25LP040E等のフラッシュメモリ使用時に有効(my_conf.h で #define USE_FLASH を宣言すること)


メモリ読込例(BRコマンド)

BMPファイル表示例(Vコマンド)

メモリアクセス例(BRコマンド)

ファイルアクセス例(BLコマンド)

バッファーの一部表示例(Bコマンド)

ディレクトリー表示例(Dコマンド)


【バグ報告】(8/17)

  1. SD読み書きで、Sofsではなく、Rofs/Wofsを使っていた => Sofsに修正(8/17修正、sd_card_2sd.zip、abc924_18326sd.zipに含む)
  2. SD読出し時にOLEDに読出し範囲が表示されない => OLED表示ルーチンを追加(8/17修正、sd_card_2.c (sd_card_2sd.zip) )
  3. ダンプ表示時、16の倍数でないデータ数を指定するとasc文字列が表示されない => 表示するよう修正(8/17修正、abc924_18326.c (abc924_18326sd.zip) )
    ・修正ファイルを使う場合、my_conf.hでUSE_INFOをコメント化し、USE_KAN_TESTを有効にして下さい(Jコマンドはコメント化済み)


【おまけ】  新たに、以下のコマンドを追加した。(8/20追加)
 ただし、KANJI_TEST(K、J)、A、R、I コマンドは不使用にすること。abc924_18326.c (abc924_18326_Z.zip )

/********* OLEDに文字表示 ************/
Xx,y
表示開始位置(x,y)を指定
Pstr
指定位置からOLEDに5x7ドット文字列を表示(次指定位置は文字末に)
Hstr
指定位置からOLEDに半角文字列を表示(次指定位置は文字末に)
Zzstr
指定位置からOLEDに全角文字列zstrを表示(次指定位置は文字末に)
これに伴い、Cコマンドも仕様変更した
C!
全画面消去 ・・(色指定時に間違えないよう'!'を加え2文字にした)
C[Fcol[,Bcol]]
色(ForeColor,BackColor)の指定(256色)
 
<参考> 標準色(8色+1)のカラー値
    赤:224 (Red)、   緑:28 (Green)、  青:3 (Blue)、
    黄:252 (Yellow)、 紫:227 (Violet)、  水色:31 (Cyan)
    白:255 (White)、 *黒:0/1 (Kuro)、  **透明:0 (Trans)
  注*1) 表示色(Fcol)で黒は 0、背景色(Bcol)で黒は 1、
  注*2) 背景色(Bcol)で透明は 0
  注*3) 標準色はアルファベットでも指定可(最初の1文字で判断。大小文字をとわない)
     (XC8のstrchr()関数の動作が不安定なので、一致位置を返すmy_strchr()関数を作成)
テラタームから、デフォルト状態で漢字をPICに送信すると、文字化けを起こすことがある。
これは、送信時に文字コードがUTF-8に変換されるためで、テラタームの「設定」で送受信漢字を「S-JIS」にすることで、文字化けを防止出来る。

テラタームの「設定」画面

文字表示例


【my_conf.h】


/**************************(my_conf.h)***********
 *   <使用する機能を設定>                     *
 *   ・メモリが少ないので全ての機能が同時には   *
 *     使えません。                             *
 *   ・使いたい機能をdefineで宣言すること       *
 ************************************************/

//---- OLED ----------------(OLEDは必須)
//#define USE_OLED_TEST         // OLEDのテスト使用

//---- SD-CARD -------------
#define USE_SDCARD            // SDカードを使用
  #define USE_DIR             // デレクトリー管理を使用
  #define USE_BMP             // BMP画像表示コマンド有効
  #define USE_INFO            // ファイル情報表示有効
//  #define USE_SD_TEST         // SD_CARDのテスト使用

//---- MEMORY -------------(ほぼ必須)
//  #define USE_FLASH           // FLASH-ROMを使用
  #define USE_KANJI           // 漢字フォントを利用
    #define KAN_MAP2          // フォントマップ2使用 
//    #define KAN_MAP3          // フォントマップ3使用
//    #define USE_KAN_TEST      // 漢字フォントテスト使用

/***********  end of file ***********************/
【myProject.h】

/*********************************(myProject.h)**
 *  プロジェクト個別条件指定ファイル【再編成版】*
 *   (main.cと同じフォルダーに作成)           *
 ************************************************/

#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "QT095B_2.h"
#include "spi_Mem_2.h"
#include "kanji.h"
#include "pff.h"
#include "pffconf.h"
#include "sd_card_2.h"
#include "my_conf.h"
#include "myFunction.h"

#ifndef PF_INTDEF                       // defined in pff.h
    typedef unsigned int  UINT;         // int must be 16-bit or 32-bit
    typedef unsigned char BYTE;         // char must be 8-bit 
    typedef uint16_t      WORD;	        // 16-bit unsigned integer
    typedef uint16_t      WCHAR;        // 16-bit unsigned integer
    typedef uint32_t      DWORD;        // 32-bit unsigned integer
#endif
typedef int16_t     INT;                // 16-bit signed integer
typedef int32_t     LONG;               // 32-bit signed integer

#define DBF_SIZE    512                 // File/Memory用BFサイズ
#define MBF_SIZE    64                  // メッセージ用BFサイズ

#define CMD_LINE    0                   // OLEDコマンド表示Y位置
#define DATA_LINE   10                  // OLEDデータ表示Y位置
#define LIST_LINE   20                  // OLEDリスト表示Y位置

#define CMD_COLOR   0x1C                // コマンド表示カラー
#define MSG_COLOR   0xFC                // メッセージカラー
#define DATA_COLOR  0xFF                // データ表示カラー
#define LIST_COLOR  0x1F                // リスト表示カラー
#define LIST_COLOR2 0xE3                // リスト表示カラー2

#define ON          1
#define OFF         0

/************************************************
 *  PICハード条件                               *
 ************************************************/
//===== PIC電源電圧 ============================
//--- VCC宣言無しは5V(VCC=50と同じ)
//#define VCC     50                    // 電源電圧は5V
#define VCC     33                      // 電源電圧は3.3V

//===== SPIモジュール ==========================
#define MASTER 1
#define SRAVE  2

#define SPIMODE MASTER                  // マスターとして使用
//#define SPIMODE SRAVE                 // スレーブとして使用

#define SSPEN_ON()       SSP1CON1bits.SSPEN = 1
#define SSPEN_OFF()      SSP1CON1bits.SSPEN = 0

#define SPI_EXCHG(b)    (SPI1_ExchangeByte(b))
#define SPI_RBLK(a,c)   (SPI1_ReadBlock(a,c))
#define SPI_WBLK(a,c)   (SPI1_WriteBlock(a,c))

/************************************************
 *  EUSARTモジュール関係                        *
 ************************************************/
//--- シリアル受信バッファーサイズ
#define EU_BFSIZE  120

//--- ECHO宣言無しはエコー有り(ECHO ONと同じ)
#define ECHO  ON                        // エコー有り
//#define ECHO  OFF                     // エコー無し

/*=== Eusart受信割り込みハンドラー =============*
 *    eusrt.cのEUSART_Recive_ISRに追加すること  *
 *----------------------------------------------*/
void myEusart(void);

/************************************************
 *  文字列シリアル出力関数                      *
 ************************************************/
/*=== Eusartへ文字列送信 =======================*
 *      *str: 出力する文字列                   *
 *----------------------------------------------*/
void EU_Write(char *str);

/*=== Eusartへ改行を送信 =======================*/
void EU_Write_CR(void);

/*=== Eusartへ文字列送信(改行付)==============*
 *      *str: 出力する文字列                   *
 *----------------------------------------------*/
void EU_Puts(char *str);

/*=== EusartでYes/Noを確認する =================*
 *      *str:   表示するメッサージ              *
 *----------------------------------------------*/
char EU_Yes_No(char *str);

/******  Delay Macros  **************************
 *      NOTE:  C99 requires macro declarations  *
 ************************************************/
#define __delay_us(x) _delay((uint32_t)((x)*(_XTAL_FREQ/4000000.0)))
#define __delay_ms(x) _delay((uint32_t)((x)*(_XTAL_FREQ/4000.0)))

/************************************************
 *   バッファー操作関数 (main.cで記述)          *
 ************************************************/
/*=====  バッファーのダンプリスト表示 ==========*
 *    ofs:  バッファーの表示開始オフセット      *
 *    sz:   表示データ数                        *
 *----------------------------------------------*/
void dmp_Buf(uint16_t ofs, uint16_t sz);

/*====  S/Wコマンド  ========================*
 *  メモリ/バッファーへデータを書き込む
 *     S(et)コマンド      S[ofs],hx0[,hx1,・・]]
 *      (バッファーへデータを書き込む)
 *     W(rite)コマンド    W[aaa],hx0[,hx1,・・]]
 *      (EEPROMへデータを書き込む)
 *    ofs:      バッファーオフセット(10進数)
 *    aaa:      メモリアドレス      (0x無し16進数)
 *    hx0[,hx1,・・]:書込データ     (0x無し16進数)
 *----------------------------------------------*/
uint16_t Mn_cmd_SW(char *str);

/*====   B(uffer)コマンド   B[L/S/R/W][ofs][,sz]
 *  バッファー操作コマンド
 *
 *  B(第2コマンド無し): バッファーデータをダンプ表示
 *  BL:  SD  -> Buf     (バッファは先頭から・・)
 *  BS:  Buf -> SD      (バッファは先頭から・・)
 *  BR:  Mem -> Buf     (バッファは先頭から・・)
 *  BW:  Buf -> Mem     (バッファは先頭から・・)
 *
 *    ofs:      SD/Memの読書き開始オフセット
 *    sz:       読み書きデータ数
 *----------------------------------------------*/
void Bf_cmd_B(char *str);

//====  A(scii)コマンド    A[ofs,]str ==========
/*  バッファーへASCII文字列を書込む
 *  (ascii文字以外を書き込むにはSコマンドを使用)
 *  (文字列のみを指定する場合はコンマを付けないこと!)
 *    ofs:      Bufの書込オフセット
 *    str:      書き込む文字列
 *----------------------------------------------*/
void Bf_cmd_A(char *str);

/******* End of File ********/

【myFunction.h】


/********************(myFunction.h)**************
 *  自作汎用関数                                *
 ************************************************/

#include "my_conf.h"

/*****  グローバル変数  *************************/
extern char Msg[];                      // メッセージ用

//-----  EUSARTシリアル用 
extern char    RBuf[];                  // 受信文字Buffer
extern uint8_t SFlg;                    // 受信フラグ

/***  文字列変換関数  ***************************/
/*---- 16進文字列を10進数に変換[=xtoi()/C90]----
 *  char *str:変換したい16進数文字列(0x無し)
 *  RETURN:変換された32ビット符号無し整数
 *----------------------------------------------*/
uint32_t my_xtol(char *str);

/*---  文字列を逆順に入替 -----------------------
 *  char *str:文字順を入れ替えたい文字列
 *  CHANG: 文字列 str
 *-----------------------------------------------*/
void reverseString(char *str);

/*---  10進数文字列に変換 -----------------------
 *  char *str:変換結果を格納する文字列
 *  uint_ wd/Ld:変換したい符号無し16/32bitデータ
 *-----------------------------------------------*/
void my_utoa(char *str, uint16_t wd);

void my_uLtoa(char *str, uint32_t Ld);

/*********** 数値を16進文字列に変換 ******/
/*--- 1ワード(16ビット)を16進文字に変換 -------
 *  char *str:変換結果を格納する文字列
 *  uint16_t wd :変換したい符号無し16ビットデータ
 *  uint8_t dg :16進数文字列の桁数
 *----------------------------------------------*/
void my_xtoa(char *str, uint16_t wd, uint8_t dg);

/*---  24ビット(16k)整数を6桁16進数文字列に----
 *  char *str:変換結果を格納する文字列
 *  uint32_t Ld:変換したい符号無し24bitデータ
 *---------------------------------------------*/
void my_xLtoa(char *str, uint32_t ld);

//---  文字列s1のp1番目からs2文字列のn2バイト分を置き換える
char * my_strNrep(char *s1, uint16_t p1, char *s2, uint16_t n2);

//---- バイト列s1のp1番目からバイト列s2のn2バイト分を置き換える
BYTE * my_strRep(BYTE *s1, UINT n1, UINT p1, BYTE *s2, UINT n2);

//-----空白文字列の追加
char * my_spc(char *str,uint8_t n);

/*****   項目名(item)とデータの表示 ********
 *  CHANGE: char Msg[];
 *******************************************/
//-----  ”項目名 = 符号無し整数”
void EU_it_uW(char *str, uint16_t uW);

//-----  ”項目名 = 符号無し長整数”
void EU_it_uL(char *str, uint32_t uL);

//-----  ”項目名 = 20ビット16進数”
void EU_it_xL(char *str, uint32_t xL);

//-----  ”文字列 + s2 + 文字列”
void EU_it_str(char *s1, char *s2, char *s3);

/*****   16進数+16進数データの表示 ********
 *  CHANGE: char Msg[];
 *******************************************/
//----- 16進数表示  "32bit + str + 32bit"
void EU_xL_xL(uint32_t xL1, char *str, uint32_t xL2);

//----- 16進数表示  "32bit + str + 16bit"
//  (sw != 0 なら32bitと16bitデータを前後入替えて表示)
void EU_xL_xW(uint32_t xL, char *str, uint16_t xW,uint8_t sw);

//----- 16進数表示  "32bit + str + 8bit"
//  (sw != 0 なら32bitと8bitデータを前後入替えて表示)
void EU_xL_xB(uint32_t xL, char *str, uint8_t xB,uint8_t sw);


/*****   10進数+10/16進数の表示 ********
 *  CHANGE: char Msg[];
 *******************************************/
//----- 10進数+16進数表示  "16bit + str + 8bit"
//  (sw != 0 なら10進数と16進数データを前後入替えて表示)
void EU_uW_xB(uint16_t uW, char *str, uint8_t uB,uint8_t sw);

//----- 10進数+10進数表示  "16bit + str + 16bit"
void EU_uW_uW(uint16_t uW1, char *str, uint16_t uW2);

/******* End of File ********/

【QT095B_2.h】


/***********************************(QT095B_2.h)**********
 *	SPI有機ELカラーグラフィックヘッダーファイル
 ********************************************************/

#include "my_conf.h"
#include "Font_5x7.h"

#define  COLOR256   0x20
#define  COLOR64K2  0x60    // 0x42
#define  COLOR64K3  0x82

//---  SSD1331 初期化
void SSD1331_Init(void);

//---  SPI コマンド出力 
void gOLED_Cmd(uint8_t b);

//---  SPI データ出力
void gOLED_Data(uint8_t b);

//----  RGBを1バイト256色に   ( R = 0-7, G = 0-7, B = 0-3 )
uint8_t gRGB256(uint8_t r,uint8_t g, uint8_t b);

//----  RGBを2バイト64k色に   ( R = 0-31, G = 0-63, B = 0-31 )
uint16_t gRGB64k(uint8_t r,uint8_t g, uint8_t b);

//---  色モード指定(アドレス増方向指定付き)
/*		dir: 0/水平方向、1/垂直方向 */
void gSetMode(uint8_t md, uint8_t dir);

//---  表示エリアの設定
/*		(x0,y0)-(x1,y1):エリア指定 */
void gSetArea(uint8_t x0, uint8_t y0, uint8_t x1, uint8_t y1);

//---  表示エリアのリセット
void gRstArea(void);

/******* アクセラレーションコマンド **********/
/*		(x0,y0)-(x1,y1):エリア指定 */
//---  画面クリア
void gOLED_Clr(uint8_t x0,uint8_t y0,uint8_t x1,uint8_t y1);

//---  線描画(256色)
void gOLED_Line(uint8_t x0,uint8_t y0, uint8_t x1,uint8_t y1, uint8_t r, uint8_t g ,uint8_t b);

//---  四角形描画(256色)
void gOLED_Rect(uint8_t x0,uint8_t y0, uint8_t x1,uint8_t y1, uint8_t r, uint8_t g ,uint8_t b);

//---  画像コピー
void gOLED_Copy(uint8_t x0,uint8_t y0, uint8_t x1,uint8_t y1, uint8_t dx, uint8_t dy);

//---  塗りつぶしのOn[1]/Off[0]
void gOLED_Fill(uint8_t fl);

/******* 文字・パターン描画 ******/
//---  1ドット描画(256色)
/*      (x,y)位置にcol色でドット描画 */
void gOLED_Pset256(uint8_t x, uint8_t y,uint8_t col);

//----  5x7ドットASCII文字を1文字表示(256色)
/*      (x,y)位置からASCII文字(dat)をcol色で描画
 *      col:表示色、 bcl:[0]透明;[1]背景黒;[x]背景256色
 *	rtn: 次表示x位置                                 */
uint8_t gOLED_chrX(uint8_t x, uint8_t y, char dat, uint8_t col, uint8_t bcl);

//----  5x7ドットASCII文字列を表示(256色) 
/*      (x,y)位置からASCII文字列(*str)をcol色で描画
 *      col:表示色、 bcl:[0]透明;[1]背景黒;[x]背景256色
 *	rtn: 次表示x位置                                 */
uint8_t gOLED_strX(uint8_t x, uint8_t y, char *str, uint8_t col, uint8_t bcl);

//----  8x16ドット(半角)文字を1文字表示(256色)
/*      (x,y):表示開始位置、 *hp:フォントデータアドレス、
 *      col:表示色、 bcl:[0]透明;[1]背景黒;[x]背景256色
 *	rtn: 次表示x位置                                 */
 uint8_t gOLED_HptnX(uint8_t x, uint8_t y, char *hp, uint8_t col, uint8_t bcl);

//----  16x16ドット(全角)文字を1文字表示(256色)
/*      (x,y):表示開始位置、 *kp:フォントデータアドレス、
 *      col:表示色、 bcl:[0]透明;[1]背景黒;[x]背景256色
 *	rtn: 次表示x位置                                 */
uint8_t gOLED_KptnX(uint8_t x, uint8_t y, char *kp,uint8_t col, uint8_t bcl);

//--- パターンデータを表示(256色)
/*      (x,y):表示開始位置、*ptn:パターンデータ、xn/yn:水平/垂直ドット数
 *      vh:0/水平方向描画、1/垂直方向描画           */
void gOLED_ptnX(uint8_t x, uint8_t y, uint8_t *ptn, uint8_t xn, uint8_t yn, uint8_t vh);

//--- パターンデータを表示(64k色、モード1)
/*      (x,y):表示開始位置、*ptn:パターンデータ、xn/yn:水平/垂直ドット数
 *      vh:0/水平方向描画、1/垂直方向描画           */
void gOLED_ptnX_FC2(uint8_t x, uint8_t y, uint8_t *ptn, uint8_t xn, uint8_t yn, uint8_t vh);

//--- パターンデータを表示(64k色、モード2)
/*      (x,y):表示開始位置、*ptn:パターンデータ、xn/yn:水平/垂直ドット数
 *      vh:0/水平方向描画、1/垂直方向描画           */
void gOLED_ptnX_FC3(uint8_t x, uint8_t y, uint8_t *ptn, uint8_t xn, uint8_t yn, uint8_t vh);

//--- グラフィック全画面クリアコマンド
void QT_Clr_All(void);

#ifdef USE_OLED_TEST
//--- グラフィック表示テスト
void QT_cmd_Q(char *str);
#endif

/****** end of file *******/

【spi_Mem_2.h】


/*===================(spi_Mem_2.h)=======
 *  SPI接続メモリ読み書き関数
 *====================================*/

#include "my_conf.h"

//---- ROMステータスの読み出し(一部のROMのみ有効)
uint8_t SPI_Rom_RdStat(void);

//-----  アドレスadrから、1バイトを読み出す
uint8_t SPI_Mem_Read(uint32_t adr);

//-----  アドレスadrに、1バイトdtを書き込む
uint8_t SPI_Mem_Write(uint32_t adr, uint8_t dat);

//-----  アドレスadrからnバイトをary[]に読み出す
void SPI_Mem_NRead(uint32_t adr,uint8_t *ary,uint16_t cnt);

//-----  アドレスadrからary[]のnバイトを書き込む
void SPI_Mem_NWrite(uint32_t adr,uint8_t *ary,uint16_t cnt);

//---- メモリーからバッファ-に読み出す
void Rd_Rom2Bf(uint32_t adr, uint16_t sz);

//---- バッファーデータをメモリーに書込む
void Wr_Bf2Rom(uint32_t adr, uint16_t sz);

/**********  メモリ管理・テスト ***********/
#ifdef USE_FLASH
//---- E(rase)コマンド    ER[aaaa]
void    sM_cmd_E(char *str);
#endif

/*******  End of File   ************/

【sd_card_2.h】


/************************(sd_card_2.h)***********
 *  SD card test using PetitFs (+OLED)          *
 ************************************************/
#include "my_conf.h"

#define SEC_SIZE   512                  // セクターサイズ
#define PATH_SIZE   32                  // パス+ファイル名サイズ
#define WR_BFSIZE   32                  // データ書込時ワークサイズ

/************************************************
 *  SDカード用汎用関数                          *
 ************************************************/
//--- SDカードのマウント
FRESULT SD_Mount(void);

//--- ファイルのオープン(SDアクセステスト用)
FRESULT SD_Open(void);


/************************************************
 *  SDカードの読み書き(バッファー使用)        *
 ************************************************/
//--- SDカードからバッファーへ読込  --------
/*  (読出しはセクター単位で512バイト)
 *  DWORD ofs:  SDカードファイルのオフセット(セクター境界)
 *  RETURN:     ファイル処理結果(正常終了なら0)
 *------------------------------------------*/
FRESULT Load_SD2Bf(DWORD ofs);

//--- バッファーデータをSDに書込
/*  (書き出しはセクター単位で512バイト)
 *  DWORD ofs:  SDカードファイルのオフセット(セクター境界)
 *  RETURN:     ファイル処理結果(正常終了なら0)
 *------------------------------------------*/
FRESULT Save_Bf2SD(DWORD ofs);

/**************************************************
 *      SDカードコマンド                          *
 *  (バッファー経由のアクセスはBコマンドを使用)*
 **************************************************/

//--- ファイル名をセットするコマンド  F[filename]
/*     filname:指定するファイル名                *
 *    (filnameが無い場合、現在ファイル名を表示) */
void SD_cmd_F(char *str);

//--- ファイルシステム(FATFS)データの表示
#ifdef USE_INFO
  void SD_cmd_I(void);
#endif

//----  ディレクトリーのオープン・取得・表示
#ifdef USE_DIRM
  void SD_cmd_D(char *str);
#endif

//--- SDからBMPファイル読込んで画像表示
#ifdef USE_BMP
  void SD_cmd_V(char *str);
#endif

//--- SDカードテスト
#ifdef USE_SD_TEST
  void SD_cmd_T(char *str);
#endif

/******   End of File   *****/

【kanji.h】


/***********************************(kanji.h)**********
 *    漢字(全/半角)文字表示
 ******************************************************/

#include "my_conf.h"

#ifdef USE_KANJI

  #define NO_FONT     0                   // 該当フォント無し

  //---  フォントデータアドレス
  #ifdef KAN_MAP2
    #define F_H_ASC     0x00200           // 半角ASCII
    #define F_SYM1      0x01000           // 記号1(2121-217E)
    #define F_PCDEF     0x06800           // 機種依存文字(2DXX)
    #define F_KAN0      0x08000           // 漢字第1水準(新アドレス)
    #define F_KAN2      0x20000           // 漢字2水準(5021-7426)
  #endif

  #ifdef KAN_MAP3
    #define USE_U_FONT  1                 // ユーザフォント使用宣言
    #define F_H_ASC     0x00200           // 半角ASCII
    #define F_H_KANA    0x00800           // 半角カナ(A1-DF)
    #define F_KAN1_3    0x04D60           // 第1水準漢字格納アドレス?

    //---  フォントマップ構造体とマップ
    struct kfont{
        uint16_t  staCd;                // 開始コード
        uint16_t  endCd;                // 終了コード
        uint32_t  adr;                  // 開始アドレス
    };

    struct kfont KF_Map[] = {
        { 0x2121, 0x217E, 0x01000 },    // 記号
        { 0x2221, 0x222E, 0x01BC0 },
        { 0x223A, 0x2241, 0x01D80 },
        { 0x224A, 0x2250, 0x01E80 },
        { 0x225C, 0x226A, 0x01F60 },
        { 0x2272, 0x2279, 0x02140 },    // 227Eは未登録
        { 0x2330, 0x2339, 0x02240 },    // 数字
        { 0x2341, 0x235A, 0x02380 },    // 英小文字
        { 0x2361, 0x237A, 0x026C0 },    // 英大文字
        { 0x2421, 0x2473, 0x02A00 },    // ひらかな
        { 0x2521, 0x2576, 0x03460 },    // カタカナ
        { 0x2621, 0x2638, 0x03F20 },    // ギリシャ大文字
        { 0x2641, 0x2658, 0x04220 },    //  〃  小文字
        { 0x2721, 0x2741, 0x04520 },    // クリル大文字
        { 0x2751, 0x2771, 0x04940 },    //   〃 小文字
        { 0x3021, 0x4F53, 0x04D60 },    // 漢字(第1水準)
        };
  #endif

  /********************************************************
   *   半角文字表示  (256色、背景:有り/透明)
   ********************************************************/
  //----  半角フォントアドレス取得
  uint32_t HfntAdr(uint8_t chCode);

  //=====  半角(8x16dot)文字表示  =====
  /*      uint8_t  x,y:  x位置[0-95]、y位置[0-63]
   *      uint8_t  chCd: 半角文字列開始ポインタ
   *      uint8_t  col:  フォアカラー[0-255]
   *      uint8_t  bcl:  バックカラー[0-255](0:透明、1:黒)
   *  RTN -> 次表示X位置             ----- */
  uint8_t gOLED_HchrX(uint8_t xpos,uint8_t ypos,uint8_t chCd,uint8_t col,uint8_t bcl);

  //=====  半角(8x16dot)文字列表示  =====
  /*      uint8_t  x,y:  x位置[0-95]、y位置[0-63]
   *      uint8_t  chCd: 半角文字列開始ポインタ
   *      uint8_t  col:  フォアカラー[0-255]
   *      uint8_t  bcl:  バックカラー[0-255](0:透明、1:黒)
   *  RTN -> 次表示X位置             ----- */
  uint8_t gOLED_HstrX(uint8_t xpos,uint8_t ypos,uint8_t *str,uint8_t col,uint8_t bcl);

  /********************************************************
   *   全角文字表示  (256色、背景:有り/透明)
   ********************************************************/
  //=====  漢字フォント格納アドレスを取得  =====
  /*      (マップは3種類(ROM_MAP1-3)から選択)
   *      uint16_t kCode: 漢字(JIS)コード
   * RTN ->   該当フォントがあれば、格納アドレスを返す
   *          該当フォントがなければ、NO_FONT(0)を返す ---- */
  uint32_t KfntAdr(uint16_t kCode);

  //=====  全角(漢字)を1文字表示  =====
  /*      uint8_t  x,y:  x位置[0-95]、y位置[0-63]
   *      uint8_t  kCd:  漢字(全角)文字コード
   *      uint8_t  col:  フォアカラー[0-255]
   *      uint8_t  bcl:  バックカラー[0-255] 
   *      uint8_t  ed:   エンディアン[0-3]
   *  RTN -> 次xpos位置を返す         ----- */
  uint8_t gOLED_ZchrX(uint8_t x,uint8_t y,uint16_t kCd,uint8_t col,uint8_t bcl, uint8_t ed);

  //=====  全角(漢字)文字列表示  =====
  /*      uint8_t  x,y:  x位置[0-95]、y位置[0-63]
   *      uint8_t  *str: 漢字(全角)文字列
   *      uint8_t  col:  フォアカラー[0-255]
   *      uint8_t  bcl:  バックカラー[0-255] 
   *      uint8_t  ed:   エンディアン[0-3]
   *  RTN -> 次xpos位置を返す         ----- */
  uint8_t gOLED_ZstrX(uint8_t x,uint8_t y,uint8_t *str,uint8_t col,uint8_t bcl,uint8_t ed);

  #ifdef USE_KAN_TEST
    //---- K(漢字)表示コマンド  K[H][aaaa]
    int sK_cmd_K(char *str);

    //---- L(文字)表示コマンド  L[code] (文字コード)
    void sK_cmd_J(char *str);
  #endif

#endif

/***********  End of file ********************/

【main.c】  'A'コマンドを追加(8/12)


/************************(abc924-18326.c)********
 *  3.3V動作PIC  + OLED + MEM + SD card         *
 ************************************************/

#include "myProject.h"
#include "my_conf.h"

/***** グローバル変数 ***************************/
//--- タイマー用変数
    uint8_t TFlg;                               // タイマーフラグ

//---- EUSART用変数
    char    RBuf[EU_BFSIZE];                    // シリアル受信バッファー
    uint8_t SFlg;                               // シリアル受信フラグ

//---- 汎用データ処理用関数
    char    Msg[MBF_SIZE];                      // コメント等送信用文字列
    BYTE    Buf[DBF_SIZE];                      // データ(S/M)用バッファー

    char    Dlm[] = ",";                        // 文字列区切りデリミタ
    
    uint16_t Bofs = 0;
    uint16_t Bsiz = 512;
    uint32_t Rofs = 0;
    uint32_t Wofs = 0;
    uint32_t Sofs = 0;
    

/************************************************
 *  タイマ0 Callback関数 (1秒周期割り込み)      *
 ************************************************/
void TMR0_Process(void){
    TFlg = 1;                                   // タイマーフラグセット
}

/************************************************
 *   バッファー操作関数 (main.cで記述)          *
 ************************************************/
/*=====  バッファーのダンプリスト表示 ==========*
 *    ofs:  バッファーの表示開始オフセット      *
 *    sz:   表示データ数                        *
 *----------------------------------------------*/
void dmp_Buf(uint16_t ofs, uint16_t sz){
    uint8_t  x,y;
    uint16_t i,j;
    char   bhx[3];
    char     by;
    char   as[18];
   
    ofs &= 0x1F0;                               // 16バイト単位
    if(ofs+sz>512) sz = 512 - ofs;

    for(i = 0; i < sz; i++){
        by = Buf[ofs+i];
        my_xtoa(bhx,by,2);
        EU_Write(bhx); EU_Write(" ");
        if(i<32){                               // OLED表示
            x = 12 * (uint8_t)(i % 8);
            y = LIST_LINE + 10 * (uint8_t)(i / 8);
            if(i % 2){
                gOLED_strX(x,y,bhx,LIST_COLOR,1);
            }else{
                gOLED_strX(x,y,bhx,LIST_COLOR2,1);
            }
        }
        if(isprint(by)) as[i%16]=by;
         else           as[i%16]='.';
        if((i % 16)==15){
            EU_Write("  ");
            as[16]= 0;
            EU_Puts(as);
        }
    }
}

void mn_cmd_BD(uint16_t ofs, uint16_t sz){
     ofs &= 0x1F0;                               // 16バイト単位
    if(ofs+sz>512) sz = 512 - ofs;
    EU_uW_uW(ofs," - ",ofs+sz-1);
    gOLED_strX(0,DATA_LINE,Msg,MSG_COLOR,1);   
    dmp_Buf(ofs,sz);   
}

//====  S/Wコマンド =================================
/*  メモリ/バッファーへデータを書き込む                *
 *     S(et)コマンド      S[ofs],hx0[,hx1,・・]]       *
 *      (バッファーへデータを書き込む)                *
 *     W(rite)コマンド    W[aaa],hx0[,hx1,・・]]       *
 *      (EEPROMへデータを書き込む)                    *
 *    ofs:      バッファーオフセット(10進数)           *
 *    aaa:      メモリアドレス      (0x無し16進数)     *
 *    hx0[,hx1,・・]:書込データ     (0x無し16進数)     *
 *------------------------------------------------------*/
uint16_t Mn_cmd_SW(char *str){
    char      *pt;                              // 文字列操作用ポインタ
    uint8_t   cmd_W = 0;                        // Sコマンドか?
    uint32_t  res = 0;                          // Hex文字数値変換結果
    uint16_t  cnt = 0;                          // 実際に書き込んだバイト数
    uint8_t   dt;                               // 書き込むバイトデータ
    uint8_t   y;                                // リスト表示行位置

    QT_Clr_All();
    gOLED_strX(0,0,str,CMD_COLOR,1);
    if(str[0] == 'W') cmd_W = 1;                // 現在コマンド
    if(strlen(str)==1){                         // コマンドのみなら
        return 0;                               // データは書き込まない
    }
    if(str[1]!=','){                            // 第2文字がコンマか?
        pt = strtok(str+1,Dlm);                 // コマンドの次文字から
        if(pt != NULL){                         // 第1パラメータ有り?
            if(cmd_W) Wofs = my_xtol(pt);
             else     Bofs = (uint16_t)atoi(pt);
        }
        pt = strtok(NULL,Dlm);                  // 次文字列取込
    }else{                                      // 第1パラメータ無し
        pt = strtok(str+1,Dlm);                 // 文字列取込
    } 
    do{
        if(pt != NULL){                         // データがあるか?
            res = my_xtol(pt);
            dt = (uint8_t)res;
            Bofs &= 0x1FF;                      // Bofsは512以内
            if(cmd_W){
                SPI_Mem_Write(Wofs,dt);         // データをメモリに書込
                EU_xL_xB(Wofs++," < ",dt,0);
            }else{
                Buf[Bofs] = dt;                 // データをBufに書込
                EU_uW_xB(Bofs++," < ",dt,0);
            }
            if(cnt < 5){                        // MsgはEU_関数でセット済み
                y = (uint8_t)(LIST_LINE+cnt*9);
                gOLED_strX(0,y,Msg,LIST_COLOR,1);
            }
            cnt++;          
            pt = strtok(NULL,Dlm);              // 次文字へ
        }
    }while(pt != NULL);                         // データがあるだけ繰り返す
    return cnt;                                 // 書き込んだ文字数を返す
}

/*====   B(uffer)コマンド   B[L/S/R/W][ofs][,sz] ==
 *  バッファー操作コマンド                          *
 *                                                  *
 *  B(のみ):        バッファーデータをダンプ表示    *
 *  BL:  SD  -> Buf (バッファは先頭から・・)       *
 *  BS:  Buf -> SD  (バッファは先頭から・・)       *
 *  BR:  Mem -> Buf (バッファは先頭から・・)       *
 *  BW:  Buf -> Mem (バッファは先頭から・・)       *
 *                                                  *
 *    ofs:  SD/Mem = 読書き開始オフセット(16進数)  *
 *         'B'のみ = バッファーオフセット(10進数)  *
 *          (ofsは16bit単位[最下位は常に0に切捨])  *
 *    sz:       読み書きデータ数                    *
 *--------------------------------------------------*/
void Bf_cmd_B(char *str){
    char     *pt;
    char     cmd2;
    uint32_t ofs;
    uint16_t sz;

    QT_Clr_All();
    gOLED_strX(0,0,str,CMD_COLOR,1);
    if(strlen(str)==1){ 
        mn_cmd_BD(Bofs, Bsiz);
    }else{
        cmd2 = str[1];        
        if(strchr("DLSRW",cmd2)){
            pt = str+2;
        }else{
            pt = str + 1; 
            cmd2 = 'D';
        }
        if(*pt != ','){                         // 第1パラメータ有り
            pt = strtok(pt,Dlm);                // 文字列データ新規取得
            if(pt != NULL){                     // 文字列があれば?
                if(cmd2 == 'D'){
                    Bofs = (uint16_t)atoi(pt);
                    if(Bofs>512) Bofs = 512;
                }else{
                    ofs = my_xtol(pt);          // 第1パラメータget
                    switch(cmd2){
                        case 'R': Rofs = ofs; break;
                        case 'W': Wofs = ofs; break;
                    }
                }
                pt = strtok(NULL,Dlm);          // 次文字列データ再取得
            }else{
                switch(cmd2){
                    case 'R': Rofs += Bsiz; break;
//                    case 'W': Wofs += Bsiz; break;
                }                
            }
        }else{
            pt = strtok(pt+1,Dlm);
        }
        if(pt != NULL){                         // 文字列があれば?
                            EU_it_str("Size"," = ", pt);
            Bsiz = (uint16_t)atoi(pt);          // 第2パラメータget
            if((Bsiz>512)||(Bsiz==0)) Bsiz = 512;
        }
        
        switch(cmd2){
            case 'D': mn_cmd_BD(Bofs, Bsiz);  break;
            case 'L': Load_SD2Bf(Sofs);       break;
            case 'S': Save_Bf2SD(Sofs);       break;
            case 'R': Rd_Rom2Bf(Rofs,Bsiz);   break;
            case 'W': Wr_Bf2Rom(Wofs,Bsiz);   break;
        }
    }
}

//====  A(scii)コマンド           A[ofs,]str =======
/*  バッファーへASCII文字列を書込む                  *
 *  (ascii文字以外を書き込むにはSコマンドを使用)   *
 *  (オフセット無し場合はコンマを付けないこと!)   *
 *    ofs:      Bufの書込オフセット                  *
 *    str:      書き込む文字列                       *
 *---------------------------------------------------*/
void Bf_cmd_A(char *str){
    char    *pts;                           // 文字列ポインタ
    UINT    sz ;                            // 書込文字数
    
    QT_Clr_All();
    gOLED_strX(0,0,str,CMD_COLOR,1);
    if(strlen(str)==1)   return;            // 'A'のみなら
    if(strchr(str,',')){                    // コンマがあれば?ofs有り
        pts = strtok(str+1,Dlm);            // コマンドの次文字から
        if(pts != NULL){                    // オフセットデータがある
            Bofs = (UINT)atol(pts);         // オフセット値取得
        }
        pts = strtok(NULL,Dlm);             // 書込文字列指定
    }else{
        pts = str + 1;                      // 書込文字列指定
    }
    if(pts != NULL){                        // 文字列データ有り
        sz = strlen(pts);
        if(Bofs+sz>512) sz = 512 - Bofs;
        my_strRep(Buf,512,Bofs,(BYTE *)pts,sz);
        Bofs += sz;
    }
}

/********************************************
 *     Main application
 ********************************************/
void main(void) {
    char   cmd;                                 // 受信コマンド文字
    char   msg[] = "--- abc924 ---";
    
    SYSTEM_Initialize();
    
    // タイマ0 Callback関数定義
    TMR0_SetInterruptHandler(TMR0_Process);
    
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    
    SSPEN_ON();
    SSD1331_Init();
    SPI_Mem_Read(0);                            // メモリーを空読み
    
    LED_SetHigh();                              // LED点灯
    EU_Puts(msg);
    QT_Clr_All();                               // OLED画面をクリア
    gOLED_strX(0,0,msg,255,1);
    
    while (1) {
      // 1秒周期の処理
        if(TFlg == 1){                          // フラグオンの場合
            LED_Toggle();
            TFlg = 0;                           // フラグリセット
        }
      // コマンド処理
        if(SFlg){                               // 受信ありの場合
          cmd = RBuf[0];
          switch(cmd){          
              case 'C': QT_Clr_All();    break; // 画面の全クリア
              case 'B': Bf_cmd_B(RBuf);  break; // バッファー処理
              case 'A': Bf_cmd_A(RBuf);  break; // バッファーへ書込(文字列)
              case 'S': Mn_cmd_SW(RBuf); break; // バッファーへ書込(16進数)
              case 'W': Mn_cmd_SW(RBuf); break; // メモリへ書込

        #ifdef USE_FLASH
              case 'E': sM_cmd_E(RBuf);  break; // フラッシュメモリ消去
        #endif

        #if defined(USE_OLED_TEST)
              case 'Q': QT_cmd_Q(RBuf);  break; // OLED表示テスト
        #endif
              
        #if defined(USE_SDCARD)
              case 'F': SD_cmd_F(RBuf);  break; // ファイル名セット
          #if defined(USE_INFO)
              case 'I': SD_cmd_I();      break; // ファイル情報
          #endif
          #if defined(USE_DIR)
              case 'D': SD_cmd_D(RBuf);  break; // ディレクトリ
          #endif
          #if defined(USE_BMP)
              case 'V': SD_cmd_V(RBuf);  break; // 画像読込・表示
          #endif
          #if defined(USE_SD_TEST)
              case 'T': SD_cmd_T(RBuf);  break; // SDカードテスト
          #endif
       
        #endif
        
        #if defined(USE_KANJI) && defined(USE_KAN_TEST)
            case 'K': sK_cmd_K(RBuf);    break; // 漢字表示(アドレス)
            case 'J': sK_cmd_J(RBuf);    break; // 漢字表示(JISコード)
        #endif

            default:  EU_Puts("???");    break; // 無効なコマンド
          }
          SFlg = 0;
        }
    }
}

/******   End of File   *****/

※プログラムのリストをハイライト付きのスタイルで見る場合はここをクリック


※ 本レポートの参考・利用は、あくまでも自己責任でお願いします。


モノクロ写真をカラー化 PIC(3.3V)とSPIデバイスまとめ