Access (VBA)

Access VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 10 Home : Access 2007)
タイマイベントについて
投稿日時: 19/09/13 16:07:12
投稿者: のりまろん

CONTECのデジタル入出力ドライバ(USB用)で外部接続機器からのbiTデータを取得し そのbitデータをACCESSに取り込んで カウントするVBAです
フォームのタイマイベントに下記のVBAを書き込み タイマ間隔は200としました
外部接続機器からのbitデータの発信間隔は不定期で ACCESS側でbitデータを受ける時と受けない時があります(デバイスマネージャーの検査ではちゃんと受信しています)のでACCESS側の問題かと思います
50回以上連続で受け続けて 急に1〜2回受けなかったり 最初から1〜2回受けなかったりします
タイマ間隔を調整したりしましたが うまくいきません
タイマイベントだから イベントが発生する隙間で bitデータが入っているのかもしれません
原因がわかりません 
フォームのイベントで常に接続する方法とかあるのでしょうか? 
 
Private Sub Form_Timer()
 
'Idはデバイスドライバのハンドルを取得します。これは他の関数を実行するときに必要ですので、グローバル変数として宣言します。
 
Dim ID As Integer ' デバイスID(グローバル変数で宣言)
Dim Ret As Long ' 戻り値
Dim ChNo(0) As Integer 'スタートするチャネル番号を格納
Dim InpBitData As Byte
'初期化
 
DeviceName = "DIO000"
 
Ret = DioInit(DeviceName, ID) 'この関数が正常終了するとIdにハンドル値が設定されます
 
 
 ChNo(0) = 0
 
Ret = DioInpBit(ID, ChNo(0), InpBitData) 'DioInitで取得したIdを指定します
 
 If InpBitData = 1 Then
  
   Call BeepAPI(1000, 80)
    
    Dim db As dao.Database
    Dim rs1 As dao.Recordset
    Dim rs2 As dao.Recordset
    Dim rs3 As dao.Recordset
    Dim cnn As dao.Recordset
    Dim i As Long, k As Long
    Dim q As Long, m As Long
    Dim b As Long, t As Long
    Dim y As Long
             
    Set db = CurrentDb
    Set rs1 = db.OpenRecordset("縞割元", dbOpenDynaset)
    Set rs2 = db.OpenRecordset("畦取計算", dbOpenDynaset)
    Set rs3 = db.OpenRecordset("縞割配色", dbOpenDynaset)
    k = Nz(DMax("トータルカウント", "縞割元"))
    q = Nz(DMax("カウント", "縞割元"))
    t = rs2!カラーNo
      
    rs3.Filter = "[カラーNo] = " & t
    Set cnn = rs3.OpenRecordset
    b = Nz(DMax("カウンター", "縞割配色", "[カラーNo] = " & t))
     
    rs1.Edit
    i = k + 1
    m = q + 1
    rs1!トータルカウント = i
    rs1!カウント = m
    rs1.Update
     
   If rs2!反復 = True Then
    
    cnn.Edit
    y = b + 1
    cnn!カウンター = y
    cnn.Update
     
   End If
      
    rs1.Close: Set rs1 = Nothing
    rs2.Close: Set rs2 = Nothing
    rs3.Close: Set rs3 = Nothing
    cnn.Close: Set cnn = Nothing
    db.Close: Set db = Nothing
       
   End If
 
End Sub
 
よろしくお願いいたします
 

回答
投稿日時: 19/09/13 18:25:15
投稿者: sk

引用:
CONTECのデジタル入出力ドライバ(USB用)で外部接続機器からのbiTデータを取得し
そのbitデータをACCESSに取り込んで カウントするVBAです

引用:
Ret = DioInit(DeviceName, ID) 'この関数が正常終了するとIdにハンドル値が設定されます

引用:
Ret = DioInpBit(ID, ChNo(0), InpBitData) 'DioInitで取得したIdを指定します

上記のプロシージャの内部処理が具体的にどうなっているのかが不明
( API を使ってるのか、COM コンポーネントを使ってるのか等)
なので、今のところは具体的な解決策を挙げられません。
 
引用:
フォームのタイマイベントに下記のVBAを書き込み タイマ間隔は200としました
外部接続機器からのbitデータの発信間隔は不定期で ACCESS側でbitデータを
受ける時と受けない時があります(デバイスマネージャーの検査では
ちゃんと受信しています)のでACCESS側の問題かと思います

現時点で提示されている情報を元に考えた限り、理論上
「外部接続機器がbitデータを発信したイベント」と
「フォームの Timer イベント」が全く同時に発生
しない限りは
どれだけタイマ間隔を縮めようがズレる時はズレますし、
またタイマ間隔を縮め過ぎれば連鎖イベントの危険性が増すことになるでしょう。

投稿日時: 19/09/13 19:05:35
投稿者: のりまろん

ご回答ありがとうございます
プロシージャーは CONTECより提供されたものです(下記)
  
    Declare Function DioInit Lib "CDIO.DLL" (ByVal DeviceName As String, ByRef ID As Integer) As Integer
    Declare Function DioExit Lib "CDIO.DLL" (ByVal ID As Long) As Integer
    Declare Function DioInpBit Lib "CDIO.DLL" (ByVal ID As Integer, ByVal BitNo As Integer, ByRef Data As Byte) As Integer
  
標準モジュールに書き込んで これで接続しております
 
タイマー間隔を 一桁 例えば 5 とかに設定すれば bitデータが1に対して 3回カウントしてしまい
だめでした
  
またタイマーイベントでは イベント発生が 入力と同時期でなければ bitデータが取得できないのはわかりました
 
どうすれば bitデータを もれなく取得できるのか考えが行き詰まっております
  
この場合 タイマーイベントではなく 常時監視?する 方法はないのでしょうか?
  
お知恵を拝借いたしたく 宜しくお願いいたします

回答
投稿日時: 19/09/13 22:11:15
投稿者: MMYS

ハードウエア制御の経験はありますか。
RS-232C等の経験は?
パソコンではなくマイコン(PIC、Arduino)などの経験はありますか。
 
まず、メーカーがC#やVB.Net等でサンプルプログラムを公開していると思います。
そちらで確認と動作原理は理解してますか。
あと、VBAの動作はメーカー保証されてますか
 
 
コマンドの詳細が不明なので確実なことは言えませんが。
http://www.contec-kb.com/wp/wp-content/uploads/2017/08/9dbefd32075a347db676829e93e6513c.pdf
一部抜粋

引用:

書式 Ret = DioInpBit(hDrv,InBit,Buf)
戻り値
 Ret: 終了情報(戻り値)→正常終了:0、エラー終了 : 0以外(詳細はヘルプの「戻り値一覧」参照)。

※ 本書では、戻り値の確認(エラー処理)は、誌面の都合上、割愛しております。
実システムにおいては、関数を実行した後にエラー処理のコードを記述します。
エラー処理の方法は、各サンプルプログラムを参照してください。


Ret = DioInpBit(ID, ChNo(0), InpBitData) 'DioInitで取得したIdを指定します
 
 If InpBitData = 1 Then
  
   Call BeepAPI(1000, 80)

掲示されたコードでは変数 Ret の値を確認していません。
なぜですか。
通信失敗したとき、掲示されたコードはどんな動きをしますか。
(InpBitData に正常な値は保証されてないと思うが)
 

投稿日時: 19/09/17 12:54:46
投稿者: のりまろん

MMYSさま ご回答ありがとうございます。
 
ハードウエア制御は今回が初めてです。
 
DeviceName = "DIO000"
  
Ret = DioInit(DeviceName, ID) 'この関数が正常終了するとIdにハンドル値が設定されます
  
  
 ChNo(0) = 0
  
Ret = DioInpBit(ID, ChNo(0), InpBitData) 'DioInitで取得したIdを指定します
 
このコードもCONTECの説明書やビギナーズガイドブックをみて 初期接続のためのコードと思い
書き込みました。
サンプルプログラムでも どのタイミングで値を取得するのか書いてありませんでした。
常時データが入ってくるのを監視する みたいなコードはありませんでした
私が わからなかったのかもですが。
CONTECにもいろいろと問い合わせしましたが
VBAでの接続はサポートしていないとのことで 何も教えてもらえませんでした。
 
あとは 試行錯誤で 常時接続ができなかったので タイマイベントに
 If InpBitData = 1 Then   で bitデータが取得できたような状態です
でも 何回かに1回とか2回とか データが取得できないので タイマ間隔での接続エラーかな?と思ったり
しました。
 
 掲示されたコードでは変数 Ret の値を確認していません。
 なぜですか。
 
  If Ret = 1 Then ?
 
通信失敗したとき、掲示されたコードはどんな動きをしますか。
 
 2回ほど データが飛びます(音がでない)
 
やはり コードの書き方がおかしいのですね
 
 
 
 

回答
投稿日時: 19/09/18 01:03:26
投稿者: MMYS

電子回路の経験はどの程度ですか。
製品の性質上、ユーザーが電子工作しなければ使えません。
 
未使用端子(Bit7〜Bit1)の配線はどうしてますか。
Bit7〜Bit1は 必ず 0 が帰ってくると
お考えのようですが。
 

のりまろん さんの引用:

サンプルプログラムでも どのタイミングで値を取得するのか書いてありませんでした。
常時データが入ってくるのを監視する みたいなコードはありませんでした

マウスやキーボードも電子回路では単なるスイッチです。
つまり、電気的に、押している/押してないは
ICの入力ピンに5Vまたは0Vの電圧が掛かっているだけです。
マウスをクリックしたらCPUに通知される。といった電子回路ではありません。
 

投稿日時: 19/09/19 15:00:37
投稿者: のりまろん

MMYSさま お返事ありがとうございます
 
 恥ずかしい話ですが 電子回路の経験は全くありません
 工作機械メーカーが作成した機器を USBでつないで 
 パソコン側で信号を受け取ることだけを考えておりました
 
 医療機関の心電図のように ピッ ピッ と不定期にはいってくる信号を パソコンで
 カウント するシステムを組みたいだけでした
 
未使用端子(Bit7〜Bit1)の配線はどうしてますか。
Bit7〜Bit1は 必ず 0 が帰ってくると
お考えのようですが。
 
 
 工作機械メーカーが作成した機器にUSBをつないで 入力信号を受けているかのテストをしました
 デバイスマネージャーのドライバーの診断で 入力ポートの bit0 が反応していましたので
 0 かと思っておりました
 https://qiita.com/yuji_miyano/items/60368766a813ba06bf66
 
 USBで信号を受ければ 値を取得できるものと考えておりました
 ほんとに無知で申し訳ありません
 どのように 書き込めばよいのでしょうか?
 ご教授頂ければありがたいです
 
 

回答
投稿日時: 19/09/21 21:04:16
投稿者: MMYS

デジタル回路の知識が無いとかなり厳しいと思います。
 

のりまろん さんの引用:

 医療機関の心電図のように ピッ ピッ と不定期にはいってくる信号を パソコンで
 カウント するシステムを組みたいだけでした

ご指摘のように値の取得だけなら得られるでしょう。見た目はオンかオフですから
で、その値だけで、かつAccsessVBAのみで処理したい。と。
 
 
時間軸の考えが抜けてます。
 
 
わかりやすく書くと、あなた(人間)は今、デバイスマネージャーで目て見て数えてますね。
1分間に10回点灯したら、人間でも間違いなく10回だと数えられます。
しかし、
1秒間に10回点灯したら、それって正確に数えられますか。人間には無理です。
(コンピュータに比べたら人間は遅い)
 
では人間ではなくAccsessVBAならどうでしょう。
VBAは人間よりも高速ですが、それでも遅いです。
電気信号の変化と比べたら、とてつもなく遅いです。
もちろんC#やVB.Netでも同じです。
 
ちなみに、1分間に2回でも同じです。テーブルにアクセスしているときに
信号が来たら取りこぼしますから。
 
 
工作機械の仕様が不明ですが、
立ち上がり(信号がL→Hに変化)または
立ち下り(信号がH→Lに変化)
をカウントすることを前提にしていると思いす。
 
私なら、カウントICを使って電子回路でカウントします。
一定時間経過後、
電子回路で数えた値を読み取り。そしてカウントICをクリア(カウント値をゼロにする)
あとは定期的に、読み取りとクリアを繰り返します。
 
 
もしもハード制御(マイコン)や電子回路に興味があるなら下記で
ざっくりと理解できるかと
https://dotinstall.com/lessons/basic_arduino
 

投稿日時: 19/09/23 16:44:08
投稿者: のりまろん

MMYSさま ありがとうございます。
 
ちなみに、1分間に2回でも同じです。テーブルにアクセスしているときに
信号が来たら取りこぼしますから。 
 
  おっしゃる通りだと思いました。
 
  この 工作機械は30年前に制作され
  PC-9800でRS-232Cで接続されフロッピーディスク1枚で動いて(カウント)おりました。
  もちろん今回再制作された機器はUSB対応に変更されています。
 
  CONTECのガイドに このような書き込みがありました。
   Visual Basicのタイマコントロールは、発生した誤差が累積されていくため、短い
   時間間隔では、正確な周期を得ることが難しいと言われています。これを解決する
   方法として、ボード上にタイマを搭載し高速・高精度の周期を得る、または独自の
   タイマコントロールを提供するなどの対策がとられています。
   弊社では、オリジナルのタイマコントロール(ACX-TIMER)を製品添付ドライバソフトウェア
   CD-ROMに収録、または、弊社ホームページから無償ダウンロードにて提供しています。
 
  これかは わかりませんが、 
 
掲示されたコードでは変数 Ret の値を確認していません。
なぜですか。
通信失敗したとき、掲示されたコードはどんな動きをしますか。
(InpBitData に正常な値は保証されてないと思うが)
 
 MMYSさまのご指摘の通り コードの書き方に 問題があると思います。
 
 
 

回答
投稿日時: 19/09/26 00:54:56
投稿者: MMYS

 

のりまろん さんの引用:

  この 工作機械は30年前に制作され
  PC-9800でRS-232Cで接続されフロッピーディスク1枚で動いて(カウント)おりました。

なぜ素直にRS-232Cで接続しないのですか。
 
RS-232C産業機器では今も現役です。
今年発売された「GPD MicroPC」にはRS-232C搭載されてますし。
https://www.gpd-direct.jp/gpd-micropc
 
USB接続のRS-232C変換器は多くのメーカーから今も普通に買えます。
 
 
のりまろん さんの引用:

   Visual Basicのタイマコントロールは、発生した誤差が累積されていくため、短い
   時間間隔では、正確な周期を得ることが難しいと言われています。これを解決する

スマホで容量使い切ると通信速度は128kbpsになります。
この128kbpsはとても遅いですが、これは1秒間に
 
128000回電圧が変化。
つまり、1秒間に12万回。
 
Windowsタイマー割り込みは1/1000秒ですが、1秒間に12万回の変化に使い物になるとお考えですか。
で、のりまろんが今やりたいことに、そんな性能が必要ですか。
 
 
のりまろん さんの引用:

 MMYSさまのご指摘の通り コードの書き方に 問題があると思います。

コードでなんとかなると考える根拠はなんですか。
 
 

投稿日時: 19/09/26 09:27:38
投稿者: のりまろん

MMYSさま ありがとうございます
 
なぜ素直にRS-232Cで接続しないのですか。
 
 メーカーが新しく作成した機器が USBでの接続コードでしか対応していなかった為です。
 また、前の機械の接続がRS-232Cでも、USB接続のように ネットや本で調べなければ、
 私にはそれを接続する知識もありません。
 
128000回電圧が変化。
つまり、1秒間に12万回。
 
 電子回路はまったくの無知で 思いもよりませんでした。
 性能とかにこだわっていませんが
 その 工作機械とゆうのが 人が一つ物を動かすと 1カウントするデータを送る
 とゆう単純なものなんです。
 1秒間に何万回もデータが届くわけではなく 多くて1秒間に1回程度 または 3秒に
 1回のデータが送られてくるだけなんです
 VBAのタイマーイベントでそれを拾うことが出来るとおもってましたが 時々 飛んでしまい
 タイマーイベントが発生する狭間に データが来てるのかと思ってしまいました
 そもそも タイマーイベントで データを取得しようと考えたのが ミスだったのかも
 しれません。
 常に DeviceName = "DIO000" に入ってくるデータを監視できるような コードを
 考えればよかったのですが 今の 私の知識では 限界です。
 1秒に1回程度入ってくるデータを取りこぼしなく拾うコードを知りたかっただけです。
 VBAで無理なら諦めます。
 
 このように考えるのもおかしいですか?
 
 
 

回答
投稿日時: 19/09/28 00:51:09
投稿者: MMYS

VBAだけで処理するサンプルを提示します。
もちろん、限界がありますが、実用上は許容範囲に収まると思います。
 

Sub sample()

  Dim hDrv          As Long
  Dim InPortData    As Byte
  Dim Ret           As Long

  Dim old As Long
  Dim cnt As Long
        
  '/*デバイス設定*/
  Const DeviceName  As String = "DIO000"    'デバイス名
  Const InPort      As Integer = 0          'ポート番号
    
  '/* 開始処理 */
  Ret = DioOpenEx(DeviceName, hDrv)
  Select Case Ret
    Case 0: MsgBox "ポートを開きました。これより測定開始します。"
    Case 1: MsgBox "○○エラー発生が発生しました": End
    Case 2: MsgBox "△△エラー発生が発生しました": End
    Case Else: MsgBox "予期しないエラーが発生しました": End
  End Select
           
  '/* 処理中 */
  old = 0
  Do
    Ret = DioInpByte(hDrv, InPort, InPortData)
    If Ret <> 0 Then
        MsgBox "予期しないエラーが発生しました"
        End     '強制終了
    End If
    
    InPortData = InPortData And 1 'ビットマスク。(bit7〜bit1を0にする)
              
    If (InPortData = 1) And (old = 0) Then
        cnt = cnt + 1   'カウント
        Debug.Print cnt '結果を表示
    End If
    old = InPortData
    
    DoEvents
    Sleep 50
  Loop
  
  '/* 終了処理 */
  Ret = DioClose(hDrv)
  Select Case Ret
    Case 0: MsgBox "正常終了"
    Case 1: MsgBox "○○エラー発生が発生しました": End
    Case 2: MsgBox "△△エラー発生が発生しました": End
    Case Else: MsgBox "予期しないエラーが発生しました": End
  End Select
  
End Sub

解説は後日行いますが、
まず、プログラムを解読して下さい。
 
なお、本コードはサンプルのため無限ループになってます。
ループ終了処理を追加して DioClose 呼び出しが必要です。
 

投稿日時: 19/09/28 19:03:58
投稿者: のりまろん

MMYSさま
 
ありがとうございます
DO LOOPにて処理する方法ですね
無限ループから抜け出すコードは考えてみます
コードの流れを解読いたします
ループを制御するコードを見つけて 実際に 組み込んでみたいと思います
色々とご参考になるお知恵をお貸しいただき ありがとうございました
 
問題なく稼働しましたら 報告いたします

回答
投稿日時: 19/09/28 23:10:28
投稿者: MMYS

パソコンのキーボードは電気部品と見た場合、
ある意味電気信号です。キーボードを工作機械の電気信号とみなして
説明します。
次のコードはCtrl キーを工作機械の電気信号とみなした例です。
イミテーションウインドウを表示して実行して実行中に
 
Ctrlキーを押したり離したりして下さい。
 
おな10秒間で。ループして終了します。
 

    Option Explicit

Private Declare Function GetAsyncKeyState Lib "User32" (ByVal vKey As Long) As Integer
Private Declare Sub Sleep Lib "kernel32" (ByVal dwMilliseconds As Long)

Sub Liset1()
  Dim inp       As Integer
  Dim StopTime  As Date
  
  StopTime = Now + TimeSerial(0, 0, 10)
  Do Until StopTime < Now
    inp = GetAsyncKeyState(vbKeyControl)
    Debug.Print Hex(inp)
    DoEvents
    Sleep 100
  Loop
End Sub

イミテーションウインドウには
Ctrlキーの押す/離すで
  1
  0
  1
  8000
  8001
が表示されましたね。
 
GetKeyState関数はキーホードの状態を返す関数です。
bit15 に押している/押してない。の情報が入っています。
そしてBit14〜Bit0は別の情報が入っています。
つまり、Bit14〜Bit0までは無視しなければなりません。
特定のビットだけを有効にするコードは次になります。
 
Sub Liset2()
  Dim inp       As Integer
  Dim StopTime  As Date
  
  StopTime = Now + TimeSerial(0, 0, 10)
  Do Until StopTime < Now
    inp = GetAsyncKeyState(vbKeyControl)
    inp = inp And &H8000
    Debug.Print Hex(inp)
    DoEvents
    Sleep 100
  Loop
End Sub

今度は
  0
  8000
しか表示されません。つまり、
    0 → 信号なし
  8000 → 信号あり
ですから、あとは押した回数をカウントするだけ。
 
Sub Liset3()
  Dim inp       As Integer
  Dim StopTime  As Date
  Dim cnt       As Integer
  
  cnt = 0
  StopTime = Now + TimeSerial(0, 0, 10)
  Do Until StopTime < Now
    inp = GetAsyncKeyState(vbKeyControl)
    inp = inp And &H8000
    If inp = &H8000 Then
        cnt = cnt + 1
    End If
    DoEvents
    Sleep 10
  Loop

  MsgBox cnt & "回数、押しました"
End Sub

 
Ctroキーを10回押してください。
「10回数、押しました」
と表示されるはずです。表示されましたか。
 
のりまろん さんの引用:

50回以上連続で受け続けて 急に1〜2回受けなかったり 最初から1〜2回受けなかったりします
 
タイマー間隔を 一桁 例えば 5 とかに設定すれば bitデータが1に対して 3回カウントしてしまい

まさしく、この現象が発生していませんか。
 

投稿日時: 19/09/30 17:11:02
投稿者: のりまろん

MMYSさま
 
イミテーションウインドウを確認いたしました。
 
そして 本日 教えてもらいましたコードを利用しまして
ACCESSのイベントの フォーム読み込み時 に
 
 Do until rs1.Eof
 
 Ret = DioInpBit(ID, ChNo(0), InpBitData)
 
  If InpBitData = 1 Then
   Call BeepAPI(1000, 80)
   以下 前回と同じ
 
 
   db.Close: Set db = Nothing の下に
 
    DoEvents
    Sleep 150
  Loop
 
 
 Sleepの値を10にすれば 1bitデータに対して 3回ほど Beep音がなりましたので
 150で調整しました。
 
フォームクローズ時に Ret = DioExit(ID) で終了するように設定しました。
 
 これで もれなくデータが取得できるのを確認しました。
 
長きにわたり ご指導いただきまして 本当にありがとうございました。
 
助かりました。 
 
また 間違ってましたら ご指導下さい。
 
 
 
 

回答
投稿日時: 19/10/01 00:26:31
投稿者: MMYS

のりまろん さんの引用:

 Sleepの値を10にすれば 1bitデータに対して 3回ほど Beep音がなりましたので
 150で調整しました。

それは正しいコーディングではありません。
まぁ、どんな不具合が起きようと、困るのはのりまろんさんで
私は困りませんが。
 
タイミングの問題ではありません。これは前回すでに指摘してます。

> Ctroキーを10回押してください。
> 「10回数、押しました」
> と表示されるはずです。表示されましたか。

のりまろん自身が Liset3 を動かしてますか。そして何で誤動作するかを考えましたか。
そして、どこでカウントするかをイミテーションウインドウ確認すれば、すぐに気づくはず。
 
解説すると今回のケースは一定間隔でチェックしますよね。
 
OFF
OFF ←チェック
OFF
OFF ←チェック
ON
ON ←チェック(1回)
ON
OFF ←チェック
OFF
OFF ←チェック
ON
ON ←チェック(2回)
ON
OFF ←チェック
 
チェック間隔とON時間が一致すればたまたま上手くいきます。
しかし、
 
OFF
OFF ←チェック
OFF
ON ←チェック(1回)
ON
ON ←チェック(2回)
OFF
OFF ←チェック
OFF
ON ←チェック(3回)
ON
ON ←チェック(4回)
OFF
OFF ←チェック
 
だと正しいカウントにはなりません。
 
チェックするのはONの時ではありません。
ONが連続してら誤動作します。
チェックするのはOFFからONになる時です。
 
言い換えれば、今回はON かつ 前回はOFF です。
 
    If (今回はON) かつ (前回はOFF) Then
        cnt = cnt + 1 'カウント
        Debug.Print cnt '結果を表示
    End If
 
    If (InPortData = 1) And (old = 0) Then
        cnt = cnt + 1   'カウント
        Debug.Print cnt '結果を表示
    End If
    old = InPortData

投稿日時: 19/10/01 18:49:51
投稿者: のりまろん

MMYSさま
 
ご指導ありがとうございます
 
 Sleepの値ではないのはわかりました
 
> Ctroキーを10回押してください。
> 「10回数、押しました」
> と表示されるはずです。表示されましたか。
 
 確認いたしました
 Sleep値を 10 で見れば Ctrl を1回押すと 20ぐらいのカウントをするので
 Sieep値を 150 で設定すればいいのかと思い違いしておりました
 うまくいったのも たまたま なのも 今回の ご指摘でわかりました
 
 
 old=0
 Do until rs1.Eof
  
 Ret = DioInpBit(ID, ChNo(0), InpBitData)
  
  If (InpBitData = 1)AND(old=0) Then
   Call BeepAPI(1000, 80)
   以下 前回と同じ
  END If
  old = InpBitData
 
  
   db.Close: Set db = Nothing の下に
  
    DoEvents
    Sleep 150
  Loop
 
このように書き込めば 2重データの取得を回避できるのですね
 
 
    

回答
投稿日時: 19/10/03 00:58:41
投稿者: MMYS

のりまろん さんの引用:

 Sleep値を 10 で見れば Ctrl を1回押すと 20ぐらいのカウントをするので
 Sieep値を 150 で設定すればいいのかと思い違いしておりました
 

前回のコードをタイミングに依存しない
書き方は下記となります。
 
Sub Liset4()
  Dim inp       As Integer
  Dim StopTime  As Date
  Dim cnt       As Integer
  Dim old As Integer
  
  cnt = 0
  StopTime = Now + TimeSerial(0, 0, 10)
  Do Until StopTime < Now
    inp = GetAsyncKeyState(vbKeyControl)
    inp = inp And &H8000
    If (inp = &H8000) And (old = 0) Then
        cnt = cnt + 1
    End If
    old = inp
    DoEvents
    Sleep 100
  Loop

ただし、高速に連打するすると、10回とは表示されません。
これはチェック間隔が長すぎるためです。つまり取りこぼし。
Sleep値を 10 などして高速にチェックすれば連打しても10回と表示されます。
 
 
データベースアクセスは時間のかかる処理です。
その間チェックできませんから取りこぼしのリスクとなります。
 
のりまろんのコードだと信号1回ごとに
更新してますが、取りこぼしリスクを考えると
私なら例えば1分間はカウントのみ。
1分おきにデータベース更新して取りこぼしリスクを低減します。
 

回答
投稿日時: 19/10/04 12:02:12
投稿者: よろずや

イミテーションウインドウ

イミディエイトウィンドウ

投稿日時: 19/10/04 13:30:55
投稿者: のりまろん

MMYSさま
  
 ご指導ご意見ありがとうございます
  
 ひとつ気になる現象が起きたのですが
  
 1サイクル 1000回の作業中 もれなく カウントしたのですが 70回ぐらいで 
  
 DeviceName = "DIO000"
   
 Ret = DioInit(DeviceName, ID) 
  
 この接続が切れたのです
  
 プー とか音がして カウントしなくなったので
  
 しかたなく再接続して 作業再開しましたが 1000回まで もれなくカウントしました
  
 2サイクル目にも 250回ほどで途切れる現象が起きたのですが 何か問題があるのでしょうか?
  
 機器からパソコンまでUSBで接続された DeviceName = "DIO000" までは 問題なくデータが届いています

回答
投稿日時: 19/10/08 00:59:28
投稿者: MMYS

 
どのようにコードを記述しているか知りませんが、
エラー発生時もデバイスを閉じるコードは呼び出してますか。
 
 
あと、RS-232Cは挑戦した上で、できないと判断ですか。
VBAでは、さずかに面倒ですが、VB.Netなら簡単です。
実際に挑戦されればわかりますが、RS-232Cは
テキストファイルの読み書きと、ほとんど変わりません。
 
(面倒な処理はシステムがやってくれます)
 
 

投稿日時: 19/10/09 12:51:41
投稿者: のりまろん

MMYSさま
 
 いつもありがとうございます
 
どのようにコードを記述しているか知りませんが、
エラー発生時もデバイスを閉じるコードは呼び出してますか。
 
 USBデバイスの「電源の管理}が原因であることがわかりました。
 電源の節約をオフ USBセレクティブサスペンドの設定 を無効
 で現象は起きなくなりました。
 すみませんでした。
 
 
あと、RS-232Cは挑戦した上で、できないと判断ですか。
 
 メーカー制作の機器との接続コネクタが USB 2.0 Type B だったもので
 RS-232Cは未確認です
 コネクタの依頼から 機器を発注できるのなら 一度挑戦してみます。
 
 色々とご指導ありがとうございました。