2021年5月31日月曜日

Delphi を使ってCO2濃度を表示してみる。

こんにちは

 

やましょうです。

 

CO2濃度が見たい

これからエアコンの季節

例の流行り病でCO2濃度の表示が欲しいところですね。

 

マイコン化する前に

Delphi を使ってWindows上でCO2濃度を表示してみます。

 

必要な物

CO2センサーモジュール MH-Z19C

https://akizukidenshi.com/catalog/g/gM-16142/

 USB UART変換  AE-UM232R( Arduinoでもよいと思う)

https://akizukidenshi.com/catalog/g/gK-06693/


配線

接続 こんな感じに接続
(AE-UM232RのDIP SWの位置が重要 TXを3.3Vにするため)

★秋月のページにI/F電圧3.3Vって書いてあるので念のため3.3V設定にしています。

 

赤:+5v(vbus) 

黒:GND

青:CO2センサーTX=>変換IC RX

白:CO2センサーRX=>変換IC TX

 

必要なコンポーネント

COMポート番号を割り出して、DELPHIで以下のソフトを書く

WUni232cのコードはGetitから10.4以降では削除されたので、

https://www.csd.co.jp/product/

より取得 してください。


コード

 /////////////////////コード //////////////////////////////////////////////

unit Unit20;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, WUni232c, Vcl.ExtCtrls, Vcl.StdCtrls;

type
  TForm20 = class(TForm)
    WUni232c1: TWUni232c;
    Timer1: TTimer;
    Label1: TLabel;
    Label2: TLabel;
    Label3: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure Timer1Timer(Sender: TObject);
  private
    { Private 宣言 }
    ReadData: array [0..9] of byte;
  public
    { Public 宣言 }
  end;

var
  Form20: TForm20;

                                    {   0   1   2   3   4   5   6   7   8  }
const CMD_SensorON  : array [0..8] of BYTE = ( $ff,$01,$79,$A0,$00,$00,$00,$00,$E6 );
const CMD_SensorOFF : array [0..8] of BYTE = ( $ff,$01,$79,$00,$00,$00,$00,$00,$86 );
const CMD_SensorRead: array [0..8] of BYTE = ( $ff,$01,$86,$00,$00,$00,$00,$00,$79 );



implementation

{$R *.dfm}

procedure TForm20.FormCreate(Sender: TObject);
begin
    if WUni232c1.Open < 0 then
    begin
        Self.Caption := 'Comポートエラー';
        exit;
    end;
    Wuni232c1.Write(sizeof(CMD_SensorON),@CMD_SensorOn);
    Timer1.Enabled := True;
end;


procedure TForm20.Timer1Timer(Sender: TObject);
var
ReadCount : Byte;
Sum : Byte;
  i: Integer;
begin
    ReadCount :=   Wuni232c1.Read(10,@ReadData);
    Label3.Caption := IntToStr(ReadCount)+'/'+IntToStr(ReadData[2])+'/'+IntToStr(ReadData[3]);
    if(ReadCount = 9) then
    begin
      // sum Check
      sum := 0;
      for i := 0 to 7 do
          Sum := Sum+ ReadData[i];
      sum := $ff-Sum;
      if(Sum = ReadData[8] ) then
      begin
        Label2.Caption := IntToStr(ReadData[2]*256+ReadData[3])+'ppm';

      end;
    end
    else
    begin
        // あまりの受信データをすべて捨てる
      while(Wuni232c1.Read(10,@ReadData) <> 0) do;
    end;
    Wuni232c1.Write(sizeof(CMD_SensorRead),@CMD_SensorRead);

end;
////////////////////////////////////////////////////////////////////////////////////////



end.


動作確認


こんな感じで表示される。

 

そしてコードはここに

https://github.com/qa65000/Co2SensorForDelphi

 

以上

やましょうでした。

 




2021年4月28日水曜日

HAL STM32 GPIO EDGE検出 を割込みを使わずに行う方法。

 こんにちは

やましょうです。

 

なんかなんでも割り込みって風潮はよくない。

割込みは最小限度の処理であとはメインで処理すべきと思っているやましょうです。 


STM32に限らず、ポートの変化でSPIで取込みとかよくある話なんですけど。

そのポートの変化検出で割込みにする必要ないんですよね。。。

通知だけですからね。。。ってことで割込みにせずSTM32で検知する方法で。

STM32 CUBE MXでのNVICでポートの割込みのチェックボックスをオフします。

その後code gane!

あとはメインで、 EXTI ペンディングレジスタ(EXTI_PR)を見るだけですね。


例:

    if(EXTI->PR & EXTI_PR_PR1)

    {    /*エッジ検出    */

            EXTI->PR |= EXTI_PR_PR1;      // 検出結果リセット

           /* エッジ時の処理。。。。*

 

 

以上

やましょうでした。

 

HAL STM32 MASTER-SPI使用時 起動後即SCKがHIGHにならない問題の対応

 こんにちは、やましょうです。

 STM32のSPI-MASTERでSPIで通信を行っていないときにCLOCKラインをHIGHにしておきたいのですが、なぜかCUBE MXの吐き出すコードだと1度SPIを使用するまでCLOCKラインがLOWですね。

 まぁ、問題はないんでしょうけど、最初だけ通常時と異なるのはちょっと考えてしまいますよね。

 

波形としてこんな感じです。(上の黄色がCLOCK)

 

この原因を調査すると、

SPI_CR1の SPE BITの設定ですね。

(注意:SPE BITはいろいろな回路に使われている様でON時には設定変更はできない様なことが書いてあります。)

6 SPE:SPI ペリフェラル  イネーブル フラグな様です。

 

対応 SPIの初期化部でフラグオンを追加します。

  /* USER CODE BEGIN SPI1_Init 2 */
   __HAL_SPI_ENABLE(&hspi1);
 
  /* USER CODE END SPI1_Init 2 */

}

 対応後

 最初の時点でHIGHになりました。

 

以上

やましょうでした。

 

 


2020年9月10日木曜日

Delphi Fmx Edit+SpinEditButtonで長押しが効かない問題対応

こんにちは、

おひさしぶり。

やましょうです。

Delphi Fmx Edit+SpinEditButtonで長押しが効かない

 久々にWindowsでDelphiのお仕事があったのですが、

仕様書ちょっとボタンの色 が青だったので、いいやFmxでって作って

SpinEdit痛い目にあったので、対応方法含めまとめてみました。

1.VCLでの動作

まずVclで確認です。 

ってVCLでまぁ長押しで連続UP/DOWNはできているのですが、なぜ、押してすぐに±1しないってバグ?というか仕様といかという部分はありますが、動画のように連続UP/DOWNできます。

2.FMXでの確認

FMXで動かすSpinEditButtonのイベントはOnUpClickかOnDownClickしかありません。
しかも、離した時に動作します。
(これでは外から押されたときに処理を開始、
離されたらやめるということもできません。)
以下動画


 変更のタイミング、この長押し(連続押し)対応言われたの
ほぼユーザーの確認が終わって最後の変更時に言われたので超絶焦りました。
ってかC#だと簡単にできているので、Delphiでもできると思い込んでいた(笑)。
(やっぱ事前確認は必要だね。)

2.対応策の検討

ひとつ前の動画をみればわかりますが、現状離されたら処理になっています。
 
こんな感じで処理がされています。

希望のタイミング
押されたとき+1、500ms以上の長押し時 100ms/stepでup/downする。

対応するとこうなります。

ってことでめでたしめでたしでした。

 

 対応コード

FMX.Edit.pasを以下の赤色の部分を追加もしくは変更してください。

  TSpinEditButton = class(TStyledControl, IEditControl)
  strict private
    FUpButton: TCustomButton;
    FDownButton: TCustomButton;
    { Events }
    FOnUpClick: TNotifyEvent;
    FOnDownClick: TNotifyEvent;
    FLongPushTimer: TTimer;
  protected
    { Style }
    procedure ApplyStyle; override;
    procedure FreeStyle; override;
    function GetDefaultStyleLookupName: string; override;
    function GetDefaultSize: TSizeF; override;
    { Events }
//  procedure DoUpButtonClick(Sender: TObject);
//  procedure DoDownButtonClick(Sender: TObject);
    procedure LongPushTimerFired(Sender: TObject);
    procedure DoUpMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure DoDownMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure DoUpMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
    procedure DoDownMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);

    { IEditControl }
 

{ TSpinEditButton }

procedure TSpinEditButton.ApplyStyle;
begin
  inherited ApplyStyle;

   FLongPushTimer := TTimer.Create(Self);
   FLongPushTimer.Interval := 100;
   FLongPushTimer.OnTimer  := LongPushTimerFired;
   FLongPushTimer.Enabled  := False;
   FLongPushTimer.Tag      := 0;


  if FindStyleResource<TCustomButton>('upbutton', FUpButton) then
  begin
    FUpButton.TouchTargetExpansion.Bottom := 0;
//    FUpButton.OnClick     := DoUpButtonClick;
    FUpButton.OnMouseDown := DoUpMousedown;
    FUpButton.OnMouseUp   := DoUpMouseUp;

  end;
  if FindStyleResource<TCustomButton>('downbutton', FDownButton) then
  begin
    FDownButton.TouchTargetExpansion.Top := 0;
///     FDownButton.OnClick     := DoDownButtonClick;
    FDownButton.OnMouseDown := DoDownMousedown;
    FDownButton.OnMouseUp   := DoDownMouseUp
;
  end;
end;

procedure TSpinEditButton.LongPushTimerFired(Sender: TObject);
begin
  if( FLongPushTimer.tag = $10) then
  begin {up 方向連続押し}
   if Assigned(FOnUpClick) then
      FOnUpClick(Self);
  end
  else
  if( FLongPushTimer.tag = $20) then
  begin {up 方向連続押し}
   if Assigned(FOnDownClick) then
      FOnDownClick(Self);
  end
  else
  if( FLongPushTimer.tag and $0f <> 0) then
  begin
    FLongPushTimer.tag := Round(FLongPushTimer.tag.ToSingle-1);
  end;
end;


procedure TSpinEditButton.DoUpMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
 FLongPushTimer.Enabled  := true;
 FLongPushTimer.Tag      := $15;
 if Assigned(FOnUpClick) then
    FOnUpClick(Self);
end;

procedure TSpinEditButton.DoDownMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  FLongPushTimer.Enabled  := true;
  FLongPushTimer.Tag      := $25;
  if Assigned(FOnDownClick) then
    FOnDownClick(Self);
end;



procedure TSpinEditButton.DoUpMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  FLongPushTimer.Enabled  := false;
  FLongPushTimer.Tag      := $00;
end;

procedure TSpinEditButton.DoDownMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Single);
begin
  FLongPushTimer.Enabled  := false;
  FLongPushTimer.Tag      := $00
end;


procedure TSpinEditButton.FreeStyle;
begin
  if(FUpButton <> nil ) then  FUpButton.OnMouseDown := Nil;
  if(FUpButton <> nil ) then  FUpButton.OnMouseUp   := Nil;
  if(FDownButton <> nil ) then  FDownButton.OnMouseDown := Nil;
  if(FDownButton <> nil ) then  FDownButton.OnMouseUp   := Nil;
  if(FLongPushTimer <> Nil) then FLongPushTimer.DisposeOf();

  if FUpButton <> nil then
    FUpButton.OnClick := nil;
  FUpButton := nil;
  if FDownButton <> nil then
    FDownButton.OnClick := nil;
  FDownButton := nil;

  FOnUpClick  := nil;
  FOnDownClick:= nil;
  inherited FreeStyle;
end;
 

以上

 やましょうでした。


 


2020年7月4日土曜日

Delphiでバイナリーファイルをexe内に内包する方法

こんにちは

やましょうです。

今回は、電子工作+winのexe系のネタです。

Delphiではバイナリーファイルをリソースとして簡単にexe内に内包できます。

 1.プロジェクト=>リソースと画像を選択
追加でファイルを選択
リソースの識別子にuniq名称割り当て(BinData)



 

 2.あとは読むコード追加

var
  RS: TResourceStream;
begin
  RS := TResourceStream.Create(HInstance, 'BinData', RT_RCDATA);
  Rs.Read(Buf,sizeof(Buf));
  RS.DisposeOf;
end;

これだけで、バイナリーデータを読めます。
あとはmbedドライブ見つけてコピーするもよし、
デバッガ起動してロードさせるもよし、
232cでarduinoに送ってもよしです。

以上
やましょうでした。




2020年4月26日日曜日

Kicad 表面/裏面だけ(部品や配線)が見たい。

こんにちは、
やましょうです。

KI-CADで他人の作ったファイルをみるのですが、部品多すぎで、よくわらかんとなったりする。
表面部品だけ、裏面部品だけが知りたいのですが、
画面に表示するときに両面に自動でなる。非常にうざい、本当にうざい。
表面部品(配線込み)、裏面部品(配線込み)をファイル毎に別けるEXEをつくりました。
(塗り潰しは対応していません。)


...のところを押してファイルを指定してください。
 ダウンロードはここから拾ってください。
指定したファイル名の.Kicad_pcbから
例:


表面部品ファイル:指定したファイル名_Front.Kicad_pcb
 

裏面部品ファイル:指定したファイル名_Rear.Kicad_pcb

という2つのファイルに分離します。


ということでやましょうでした。


2020年3月18日水曜日

秋月製 STM32F303K8 使用マイコンボードの使用例

こんにちは、 STM32の本を前書きしか書いていない。
やましょうです。

2020/3/4に突如して秋月電子通商さんから発売された
STM32F303K8使用マイコンボードの使用方法についてレポートしていきたいと思います。

まず、外見みて思うのなんでデバッグポートを14PINにしたの。。。ってことです。


ARM系のマイコンは最近10PIN 5x2の1.27mmピッチですよね。
ってことで右端の2本、と左端の2本を曲げます。


そしてデバッガをつなげて完成です。

これで動きました。