Vol.920 13.Jun.2025

BT接続ラジオ リングライト プチFATで画像表示

B Bluetoothイヤホンに接続可能な携帯ラジオ

by fjk

 GemeanのJ-618はあるようで無かった「ブルーツース(BT)イヤホン接続可能ラジオ」で、逆に「BT接続スピーカー」としても使える優れものです(有線のイヤホンジャックもあります)[amzonで3,999円]。
 さらに、TFカードスロットにSDカードを差し込んでMP3プレーヤーとしても使えます。
 主な仕様は、

 屋外作業時に、ワンセグTV音声も聴取できるPanasonicのRF-Nd50TVを使っていたが、有線イヤホンのためコードが引っかかったり、耳を塞いでいるので周囲の音や声かけが聞こえない不満があった。
 そこで、骨伝導BTイヤホン(AfterShokzのOpenMove、abc834参照)とBTトランスミッタ(AukeyのBT-C1)も合わせて使用していたが、デバイスが3つとなり、チョット面倒くさかった。
 J-618は骨伝導BTイヤホンと直接BT接続ができ(FMでBT使用時はアンテナを伸ばす必要がある)、充電・接続の手間も少なく、満足です。欲を言えば、さらに、ワンセグTVも聞けると理想ですが・・。


J-618(左)とOpenMove(右)


L リングライト(2)

by fjk

 abc842でリングライトを入手していたが、リングサイズが小さく、リングの中心にスマホを取付ることができず、単にスタンドライトとして使っていた。そこで、12インチのリングライト(3色、10段階明るさ調整可)をAmazonで1,680円で入手した。
 購入したリングライト付属のフレキケーブルが硬く、スマホを上手くリング内に固定できなかった。しかし、abc842で購入したライトに付属の「ホットシューマウントアダプタダブルナットロック」を利用すると、ほぼ期待する位置にスマホを固定することができた。
 リングライトはUSB給電式なので、モバイルバッテリー(AnkerのA1368等)でも使うことができる。
 なお、スマホのシャッターはabc913で紹介した自撮り棒用のBTリモコンを利用。


スマホをリングライトの中にセット
(電源はUSBバッテリー)


P PICでSDカードを使う(7)  〜プチFATとOLEDで画像表示

by fjk

 PIC16F18326(@250[秋月電子通商(以下秋月)、#111886])でSDカードからBMPファイルを読み込み、カラーOLED(QT095B、@1,480[秋月、#114435])に表示してみた。

【ハード】
 QT095Bは5Vでも動作するので、カードスロットは5V動作でサイズが小さいSparkFunの「レベルシフト回路搭載 microSDブレークアウト」(@1,226[スイッチサイエンス、SFE-DEV-13743])、SPI接続メモリは5V動作のM95M02(ST、2Mbit、@350[マルツ]) + DIP化変換基板、USBシリアル通信はFT234Xモジュール(@780[秋月、#108461])を用いた。
 なお、ROMには事前にabc913の回路を使って、EXCELで漢字フォント(ROM_MAP2)を書き込んだ

PICによるOLEDで画像表示回路

BB配線例(LEDは抵抗入)
【ソフト】
・グラフィックライブラリのQT095B.c/habc917とほぼ同じ(SSPEN_ON()/SSPEN_OFF()は削除;)。
・SPI接続ROMの利用にはabc918spi_Mem0.c/hをほぼ利用した(spiはSPI1に変更すること)。

MCCのPinModule(ピン名を設定)
System
Osc=HFINTOSC、Clock=32MHz、Divider=1
TMR0
Prescaler=1:128、Postscaler=1:1、Mode=16bit、Source=FOSC/4、Rate=1
(タイマー0は、PICの稼働確認のため、1秒ごとの割り込みでLED点滅を実施)
EUSART
Rate=115200、Interruptにチェック、STDIOはどちらでもOK
( eusart.cにmyEusart()等を追加、 abc917 を参照)
MSSP1
Mode=Master、SPImode=Mode3、Clock=FOSC/4_SSPxADD、Freq=4000000
(SPIを有効にするため SSP1CON1bits.SSPEN = 1; を忘れないこと)

<ターミナルコマンド>  [ ]はオプション
C
画面クリア
G[n]
グラフィック表示テスト
n:テスト番号(1-3)
P[str]
文字表示
str:表示文字(アスキーのみ)
str無し:テスト漢字文字表示
F[filname]
ファイル名指定
filnam:ファイル名(8.3)
filnam無し:現在ファイル名表示
R[filname]
テキストファイルを読出・表示
V[filname]
BMP画像ファイルを読出・表示
U[aaaa]
ROMデータのダンプ表示
aaaa:アドレス(Hex)
K[H][aaaa]
全半角フォントデータ表示
H:半角を指定、
aaaa:アドレス(Hex)
J[jisCode]
文字データ表示
Code:Jis-code(Hex)

SDからBMP画像を読み込み・表示した例

 PIC16F18326でabc918と同じように、SDカードからBMP画像ファイルを読み込み・表示することができた。さらに、SPI接続ROMから漢字フォントを読み出し・表示することもできた。

【abc920-18326.c】 abc920-18326.c + myFunction.c+myProject.h(zip)
    ( Redirect_STDIO_to_USARTにチェックが有ると、EU_Puts()はputs()に変更可 )


/************************(abc920-18326.c)******
 *  SD card test using PetitFs (+OLED)        *
 **********************************************/

#include "mcc_generated_files/mcc.h"
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "pff.h"
#include "myProject.h"
#include "QT095B.h"
#include "spi_Mem0.h"

#define SD_BFSIZE      256              // SDカード用
#define OLED_BF_SIZE    80              // 表示データ用
#define MEM_DATA    0x3C000             // 保存データ開始アドレス

enum { NON = 0, TXT, CSV, BIN = 8, BMP };

//--- タイマー・汎用変数
char     Msg[40];                       // コメント等送信用文字列
uint8_t  TFlg;                          // タイマーフラグ

//---- SDカード用変数
FATFS    Fs;                            // ファイルシステム変数
BYTE     Buf[SD_BFSIZE + 1];            // ファイルデータ用バッファー
UINT     Br;                            // 送受信完了データ数
char     FilNam[13] = "FLOWER.BMP";     // ファイル名(8.3))
uint8_t  F_ext = BMP;                   // 1:TXT, 2:CSV, 8:BIN, 9:BMP

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

//---- OLED用変数
uint8_t  CrtLn = 0;                     // 現在行(ページ)位置
uint8_t  gBf[OLED_BF_SIZE];             // グラフィック表示用
char     msg1[] = "SD & QT095B";
uint8_t  PosX = 20;                     // 表示開始位置x(Pコマンド)
uint8_t  PosY = 54;                     // 表示開始位置y(Pコマンド)
uint8_t  Dcol = 0x1F;                   // 表示色(256色)

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

/***************************************
 *  SDカード用汎用関数
 ***************************************/
//--- SDカードのマウント
FRESULT SD_Mount(void) {
    uint8_t i = 0;
    FRESULT res;
    do{
        res = pf_mount(&Fs);
        i++;
        EUSART_Write('.');
    }while((res != FR_OK) && (i < 10)); // 10回まで試みる
    if(res != FR_OK){                   // マウント失敗なら
        EU_Puts("** SD Not Mounted !!");
    }else{
        EU_Puts("SD Mount OK!");
    }
    return res;	
}

//--- ファイル名セットするコマンド
void SD_cmd_F(char *str) {
    size_t i,n;
    char *p;
    n = strlen(str);
    if(n > 1){
        if(n > 12) n = 12;
        for(i = 0; i < n; i++)
            FilNam[i] = (char)toupper(str[i+1]);
        FilNam[n]=0;
    } 
    p = strchr(FilNam,'.');
    if     (strncmp(p+1,"TXT",3)==0) F_ext = TXT;
    else if(strncmp(p+1,"CSV",3)==0) F_ext = CSV;
    else if(strncmp(p+1,"BIN",3)==0) F_ext = BIN;
    else if(strncmp(p+1,"BMP",3)==0) F_ext = BMP;
    else                             F_ext = NON;
    sprintf(Msg,"NewFileName = %s: %d\n",FilNam,F_ext);
    EU_Puts(Msg);
}

//--- SDカードから読込コマンド(TXTファイルのみ)
void SD_cmd_R(char *str){
    FRESULT res;
    uint16_t sz = 0;
    if(strlen(str)>1)
        SD_cmd_F(str);
    if(F_ext != TXT){
        EU_Puts("Not Text File!");
        return;
    }
    EU_Puts("Start Command R");
    if(SD_Mount() == FR_OK){
        res = pf_open(FilNam);          // ファイルオープン
        if(res == FR_OK){
            sprintf(Msg,"Open %s",FilNam);
            EU_Puts(Msg);
            do{
                pf_read(Buf, 64, &Br);  // SDから読込む
                Buf[Br] = 0;
                EU_Puts((char *)Buf);
                sz += Br;
            }while(Br!=0);
        }else{
            sprintf(Msg,"** Can't open %s !!",FilNam);
            EU_Puts(Msg);
        }
        sprintf(Msg,"Size = %d",sz);
        EU_Puts(Msg);
    }
}

//--- メモリからBMPファイル読込んで画像表示コマンド
void SD_cmd_V(char *str){
    FRESULT res;
    uint8_t  i;
    uint16_t n;
    if(strlen(str)>1)
        SD_cmd_F(str);  
    if(F_ext != BMP){                   // ファイルがBMPで無い?
        sprintf(Msg,"%s is not BMP File!",FilNam);
        EU_Puts(Msg);
        return;
    }
    EU_Puts("Start Command V");
    gSetMode(COLOR64K2,0);              // 64k(16ビット)カラーに
    gRstArea();                         // 全画面を対象に
    if(SD_Mount() == FR_OK){
        res = pf_open(FilNam);          // ファイルopen
        if(res == FR_OK){
            sprintf(Msg,"Open %s",FilNam);
            EU_Puts(Msg);
          //---  SDからヘッダー部を読込む 
            SD_CS_SetLow();
            pf_read(Buf,138, &Br);
            SD_CS_SetHigh();
            n = (uint16_t)Br;
            sprintf(Msg,"W:%d - H:%d\n",Buf[0x12],Buf[0x16]);
            EU_Puts(Msg);
            for(i = 0; i < n; i++){
                sprintf(Msg,"%02X,",Buf[i]);
                EU_Write(Msg);
                if((i % 16)==15) EU_Write_CR();
            }
            EU_Write_CR();
          //--- SDからデータを読み出し、表示
            do{
                SD_CS_SetLow();
                pf_read(Buf,192, &Br);
                SD_CS_SetHigh();
                n = (uint16_t)Br;
                gCS_SetLow();           // Select gCS
                gDC_SetHigh();          // Select Data
                
                for(i = 0; i < n; i+=2){
                    SPI_EXCHG(Buf[i+1]);
                    SPI_EXCHG(Buf[i]);
                    sprintf(Msg,"%02X,%02X,",Buf[i],Buf[i+1]);
                    EU_Write(Msg);
                    if((i % 16)==14) EU_Write_CR();
                }
                gCS_SetHigh();          // DeSelect gCS
            }while(Br != 0);
            EU_Write_CR();
        }else{
            sprintf(Msg,"** Can't open %s !!",FilNam);
            EU_Puts(Msg);           
        }
    }
}

//--- 画面に文字を表示するコマンド
/*   *str:表示する文字列    */
void SD_cmd_P(char *str){
    uint8_t xpos;
    gSetMode(COLOR256,0);               // 256(8ビット)カラーに
    if(strlen(str)==1){
        xpos = gOLED_ZstrX(2,2,"薔薇",gRGB256(7,7,0),1,0);
    }else{
        xpos = gOLED_strX(PosX,PosY,str+1,DCol,0);
    }
    gSetMode(COLOR256,0);               // アドレス増分を横に
    gRstArea();                         // 全画面を対象に
}

//---  画像表示テストコマンド
void QT_cmd_G(char *str){
    if(strlen(str) > 1){
        switch(str[1]){
            case '1': QT095B_Test1(); break;
            case '2': QT095B_Test2(); break;
            case '3': QT095B_Test3(); break;
        }
    }else{
        QT095B_Test1();
    }
}

//---  画面表示消去コマンド
void QT_cmd_C(void){
    gOLED_Clr(0,0,95,63);
}

//---  (全半角)漢字表示コマンド
void sM_cmd_K(char *str){
    gOLED_Clr(0,0,95,63);
    gOLED_strX(0,0,str,gRGB256(7,7,0),0);
    spiMem_cmd_K(str); 
}

//---  Jisコード漢字表示コマンド
void sM_cmd_J(char *str){
    gOLED_Clr(0,0,95,63);
    gOLED_strX(0,0,str,gRGB256(7,7,0),0);
    spiMem_cmd_L(str); 
}

//---  メモリデータダンプ表示コマンド
void sM_cmd_U(char *str){
    gOLED_Clr(0,0,95,63);
    gOLED_strX(0,0,str,gRGB256(7,7,0),0);
    spiMem_cmd_U(str); 
}

/********************************************
 *     Main application
 ********************************************/
void main(void) {
    FRESULT res;
    char   cmd;                         // 受信コマンド文字
    
    SYSTEM_Initialize();
  // タイマ0 Callback関数定義
    TMR0_SetInterruptHandler(TMR0_Process);
    
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    SSP1CON1bits.SSPEN = 1;
    SSD1331_Init();
    EU_Puts("--- test ---");
    LED_SetHigh();
    while (1) {
        // 1秒周期の処理
        if(TFlg == 1){                  // フラグオンの場合
            LED_Toggle();
            TFlg = 0;                   // フラグリセット
        }
      // コマンド処理
        if(SFlg){                       // 受信ありの場合
          cmd = RBuf[0];  
          sprintf(Msg,"Input = %s\n",RBuf);
          EU_Puts(Msg);
          switch(cmd){
            case 'C': QT_cmd_C();     break; // 画面のクリア
            case 'G': QT_cmd_G(RBuf); break; // グラフィックtest 
            case 'R': SD_cmd_R(RBuf); break; // SDからデータ読出
            case 'F': SD_cmd_F(RBuf); break; // ファイル名セット 
            case 'P': SD_cmd_P(RBuf); break; // 文字表示テスト
            case 'V': SD_cmd_V(RBuf); break; // 画像読込・表示
            case 'U': sM_cmd_U(RBuf); break; // 16進数でダンプ
            case 'K': sM_cmd_K(RBuf); break; // 漢字表示(アドレズ)
            case 'J': sM_cmd_J(RBuf); break; // 漢字表示(JISコード)
            case '$': SSD1331_Init(); break; // SSD1331のリセット
            default:  EU_Puts("???"); break; // 無効なコマンド
          }
          SFlg = 0;
        }
    }
}
/******   End of File   *****/

【その他のライブラリー】

・プチFAT:
pff.c/h+pffconf.h(zip)
・diskio:
diskio.c/h(zip)
・ディスプレィ:
QT095B.c/h+Font_5x7.h(zip)
・メモリ:
spi_Mem0.c/h(zip)

※ OLEDの表示動作が不安定になることが時々ある。そこで、ブレッドボードの配線抵抗を測ってみると、数Ωになることがあり不安定。BB端子の接触不良が原因かな?


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


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


BT接続ラジオ リングライト プチFATで画像表示