Vol.850 5.Aug.2022

運転状態をLCD表示 読取り革命16

N Nゲージ列車のデジタル運転(7) 〜運転状態をLCD表示

by fjk

 前報(abc849)までに列車の走行制御と列車センサの動作を確認できたが、列車の常点灯を行うには、走行を開始しないPWM条件を知る必要がある。そこで、列車の走行状態やPWM出力値を表示するために、I2C接続LCD(AQM0802A)を追加した。なお、i2cのプルアップはピン設定のWPUで行った。バックライトを使う場合、変換基板の制限抵抗R3は20Ωと小さく明るすぎるので、別途100Ωの抵抗を使用した。
 併せて、センサー入力を最大4チャンネルに拡張できるよう、試作回路も変更した。なお、RA0,1にセンサを接続する時はICSP接続を外すこと(1kΩ程度の抵抗を介して入力することも出来るが)また、誤動作を防ぐため、使用しないセンサ入力ポートは入力に設定しないか、GNDに接続すること。
 回路設計の変更に伴い、センサ入力を全てRAポートに割り当てるため、VR入力はRC5に変更した。今回はRA0、RA1、RA2のセンサー入力を使用していない。また、進行方向指示スイッチは省略し、RA3のリセットスイッチを汎用入力とし、方向スイッチ(Ps_A3)を押すたびに進行方向を変える仕様に変更した(Ps_A3スイッチは緊急停止スイッチとしても使える)。なお、RA3(MCLR)を汎用ポートとして使うにはLow-VoltageProguramingのチェックをつけないこと。
 LCD表示ライブラリはabc840のi2cLCD_AQM0802A.cおよびヘッダーファイルで。I2C_..をI2C1_..に変更し、これをライブラリとして用いた(詳細および使い方はabc840を参照)。

【LCD表示付きパワーパックの使い方】
@ 電源を投入すると、LCDに"NoPwr"と表示。
A PWM出力は0となり,現在のVR値を表示
B VR=0でないなら赤LEDも点灯。
C VR=0とすると赤LEDは消灯。
D LCDに進行(前/後)方向も表示。
E Vrを回すと、PWM出力、VR値表示。
F 方向スイッチを押すと@に戻る。
G 走行中にセンサ入力があると@に戻る(センサを使わない場合はRA4をGNDに接続)。
H 出力電流がオーバーになると@に戻る
 

LCD表示機能付きパワーパック回路
(PIC16F18325)

MCC PinModule
(ここで状態変化割り込みを設定)

★MCCの設定 (その他の設定はdefaultのまま)

【SyatemModule】
Oscilater Select = HFINTOSC
HF internal Clock = 32_MHz
Clock Divider = 1
【TMR2】
Check "Enable Timer"
<Timer Clock>
  Postcaler = 1:1
  Prescaler = 1:1
<Timer Period>
  Timer Period = 32us
【ADC】
Check “Enable ADC"
<ADC Clock>
  Clock Source = FOSC/64
Result Alignment = right
Positiv Reference = VDD
Negative Reference = VSS
Auto-conversion Trigger = no_auto_trigger
Check “Enable ADC interrupt"
【PWM5】
Check “Enable PWM"
Select a Timer = Timer2
<Duty Cycle>
  Duty Cycle = 0.0%
<PWM Parameters>
  PWM Polarity = active_hi
【FVR】
Check “Enable FVR"”
FVR_buffer1 Gain = off
FVR_buffer2 Gain=1x
【DAC1】
Check “Enable DAC"”
Positiv Reference = FVR_buf2
Negativ Reference = VSS
【CMP1】
Chek “Enable Comparator"
Positiv Input =DAC
Negativ Input =CIN2-
Output Polarity = not inverted
【CWG1】
Check “Enable CWG"
Input Source = PWM5_OUT
Output Mode = Stearing mode
Clock Source = FOSC
<Events>
  Rasing Counts = 0
  Falling Counts = 0
<Output Pin Config>
 (CWGA)
  Check “Enable Stearing"
  Stearing data = high
  Polarity = inverted
 (CWGC)
  Check “Enable Stearing"
  Stearing data = high
  Polarity = inverted
<AutoShutdown>
  CWGA&CWGC Shutdown State =logic1
  Check “Comparator1 Output”
【MSSP】
Check “Interupt Driven"
<Hardware Setting>
  SerialProtocol = I2C
  Mode = “Master"
  I2C Clock Frequency = 100000
<Interupt Setting>”
  Check "Enable I2C Interrupt"
【Pin Module】
RA0(Ir_A0):reserved)
RA1(Ir_A1):(reserved)
RA2(Ir_A2):(reserved)
RA3(Ps_A3):input ・・・スイッチ
RA4(Ir_A4):input、IOC = positive
RA5(Led_A5):output ・・・赤LED
RC0(MCL1):(I2C clock)
RC1(MDA1):(I2C data)
RC2(CIN2-):input
RC3(CWG1C):output
RC4(CWG1A):output
RC5(Vr_C5):input

System_Module
 

TMR2
 

ADC
 

PWM5
 

FVR
 

DAC1
 

CMP1
 

CWG1
 

CWG1(shutdown)
 

MSSP
/*-------  pin_module.c ---------*/

#include "pin_manager.h"
extern uint8_t IrFlg;
void (*IOCAF4_InterruptHandler)(void);

      ・・・

void IOCAF4_ISR(void) {
    IrFlg = 1;
    if(IOCAF4_InterruptHandler)
    {
        IOCAF4_InterruptHandler();
    }
    IOCAFbits.IOCAF4 = 0;
}

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

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

uint16_t aVal;
uint16_t pwmV;
uint8_t  trDrc = 1;
uint8_t  inDrc = 0;
uint8_t  IrFlg;

void dsp_sts(uint8_t a){
    LCD_cursor(0,0);
    switch(a){
        case 0:
            LCD_str("NoPwr");
            break;
        case 1:
            LCD_str("Ready");
            break; 
        case 2:
            LCD_str("Forwd");
            break; 
        case 3:
            LCD_str("Revrs");
            break; 
    }
}

void dsp_num(uint8_t x, uint16_t n){
    char sBuf[10];
    sprintf(sBuf,"%4d",n);
    LCD_cursor(x,1);
    LCD_str(sBuf);    
}

void stop_wait_Vr_Zero(void){
    Led_A5_SetHigh();
    PWM5_LoadDutyValue(0);
    CWG1STR = 0xF5;
    pwmV = 0;
    dsp_sts(0);
    dsp_num(0, pwmV);
    do{
        aVal = ADC_GetConversion(Vr_C5);
        dsp_num(4, aVal);
    }while(aVal > 0);
    Led_A5_SetLow();
    dsp_sts(trDrc + 2);
}

/* ====   Main application ==== */

void main(void){
    SYSTEM_Initialize();
    INTERRUPT_GlobalInterruptEnable();
    INTERRUPT_PeripheralInterruptEnable();
    
    DACCON1 = 0x03;
    LCD_init();
    stop_wait_Vr_Zero();
    
    while (1)
    {
        if(CWG1AS0bits.CWG1SHUTDOWN || IrFlg){
            stop_wait_Vr_Zero();
            CWG1_AutoShutdownEventClear();
            trDrc ^= 0x01;
            IrFlg = 0;
        }    
        if(Ps_A3_PORT == 0){
            inDrc ^= 0x01;
        }
        if(trDrc != inDrc){
            stop_wait_Vr_Zero();
            trDrc = inDrc;
            if(trDrc == 0){
                CWG1STR = 0xF1;
            }else{
                CWG1STR = 0xF4;
            }
        }
        aVal = ADC_GetConversion(Vr_C5);
        pwmV = aVal;
        PWM5_LoadDutyValue(pwmV);
        dsp_num(0,pwmV);
        dsp_num(4,aVal);
    }
}
 
/*-------  i2c_LCD_AQM0802A.h ---------*/

#include "mcc_generated_files/mcc.h"
#include "mcc_generated_files/examples/i2c1_master_example.h"

#define I2CLCD_AQM0802A 0x3e

/*  LCD library */
void LCD_dat(char chr);         // Send Data
void LCD_cmd(char cmd);         // Send Command
void LCD_clr(void);             // Clera LCD
void LCD_home(void);            // Home
void LCD_cursor(int x, int y);	//Cursol X,Y
void LCD_str(char *str);        // Display Strings
void LCD_init();                // LCD initialize
 
/*------- i2c_LCD_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

/*  LCD library */
void LCD_dat(char chr){
    I2C1_Write1ByteRegister(I2CLCD_AQM0802A, 0x40, chr);
    __delay_us(30);             // 30us
}

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

void LCD_clr(void){
    LCD_cmd(0x01);
}

void LCD_home(void){
    LCD_cmd(0x02);
}

void LCD_cursor(int x, int y){
    if (y == 0)
        LCD_cmd((char)(0x80 + x));
    else if (y == 1)
        LCD_cmd((char)(0xc0 + x));
}

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

void putch(char ch){
    LCD_dat(ch);
}

void LCD_init(){
    __delay_ms(40);         //40ms wait
    LCD_cmd(0x38);          //8bit,2line
    LCD_cmd(0x39);          //IS=1 : extention mode set
    LCD_cmd(0x14);          //Internal OSC Frequency
    LCD_cmd(0x70 + (CONTRAST & 0x0F)); 	//Contrast set
    LCD_cmd(0x58 + BOOST + (CONTRAST >> 4));
                            //Power/ICON/Contrast Control
    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
}


電源投入時の試作回路
(NoPwr、赤LED点灯)

列車走行時の試作回路
(Forwd、黄LED点灯)

列車走行テスト風景
 

 PWMの幅の指定は0〜1023(10ビット)なので、LCD表示される数値はフルパワーのほぼ0.1%単位表示と見なせる。
 ちなみに、走行試験に用いたBトレインでは、約350(0.35×12V=4.2V)を超えると走行を開始し、250〜300(3〜3.6V)まで下げると停止した。


Y 読取り革命16

by fjk

 PICなどのデータシートや機器のマニュアルを、abc841で紹介した「瞬間テキスト」とグーグル翻訳で日本語化しWordファイルとしているが、図や表があると、ページ内のレイアウトが乱れることが多い。
 そこで、レイアウトを維持したままPDFファイルを読み取ることが出来るOCRソフトを利用することにした。今まで、OCRソフトはイロイロ試しており、文字読み取り精度が良くないものが普通と感じていた。ネットで調べていると、英文読取りに優れていると言われる「読取り革命16」(6,980円、DL割引版)が見つかった。さらにグーグル翻訳とも連携している。そこで、あまり期待せずにポチり。
 実際に使ってみると、さすがに英文の読み取りはほぼ完璧だが、領域の認識がイマイチ。領域を設定し直すと、英語だけでなく日本語も含めてほぼ満足できる読取りができた。領域の再設定は意外と手間がかかるので、この部分の改良を期待する(罫線無し表形式が指定できると・・)。
 その後、英文を日本語にグーグル翻訳で翻訳すると、チョットおかしい翻訳をする場合もあるが、専門用語や記号が混じっている場合でも、それなりに変換できているようである。翻訳後の日本語が長くなる場合には、領域をはみ出して見えなくなるので、領域が自動で拡大されるとうれしい。
 ソフトのほとんどの機能はマウス操作なので、キーボードによるショートカットで操作が出来るとありがたいのだが・・。


読取り革命ver.16の画面例(PIC16F1813マニュアル、英文翻訳後)


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


運転状態をLCD表示 読取り革命16