thunderbolt!

thunderbolt!

PR

×

カレンダー

キーワードサーチ

▼キーワード検索

2019.12.19
XML
テーマ: 私のPC生活(7577)
カテゴリ: 家電
​​​​​​​​​​​​​​​​​​昨日の続き。

USB制御できる0-10V電圧源を格安に制作しています。
USB-IO2.0(AKI)を使ってUSBからデジタルI/Oを作り、MCP4922で0-5Vの直流電圧を生成し、LM358Nで0-10Vに昇圧することにしました。

Microchip 12ビットDAコンバーター SPIインターフェース 【MCP4922-E/P】



Kaito7823(5個) STMicroelectronics LM358N オペアンプ(DIP)



昨日の日記で考えた仕様をモトに作った、USB-IO2.0を使ってMCP4922をドライブするプログラムです。
VisualStudio community 2015で作ってます。

コマンドラインから動かす仕様なので、formには何もコントロールを貼り付ける必要はありません。


'MCP4922drive コマンドラインver
'LM358をつけて0-10Vで動作するようにする  実行ファイル名をMCP4922drive.exeとすると
'
' コマンドライン引数は二つ
'(例)  c:> MCP4922drive A 3.5
''DACのAに3.5Vを出力
'
'(例)  c:> MCP4922drive B 2.1
''DACのBに2.1Vを出力
'
'10以上の引数の場合は10Vに固定
'

Imports System.Runtime.InteropServices

Public Class Form1

    '******************************************************
    '定数や構造体の定義  USB-IO2.0用 (サンプルプログラムそのままコピペ)
​    '******************************************************​
   Public Const DIGCF_PRESENT = &H2
    Public Const DIGCF_DEVICEINTERFACE = &H10

    Public Const FORMAT_MESSAGE_FROM_SYSTEM = &H1000
    Public Const GENERIC_READ = &H80000000
    Public Const GENERIC_WRITE = &H40000000
    Public Const FILE_SHARE_READ = &H1
    Public Const FILE_SHARE_WRITE = &H2
    Public Const OPEN_EXISTING = 3
    Public Const INVALID_HANDLE_VALUE = -1

    Public Const MyVendorID = &H1352        'Km2Net
    Public Const MyProductID = &H120        'USB-IO2.0
    Public Const MyProductID2 = &H121       'USB-IO2.0(AKI)

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)>
    Public Structure GUID
        Dim Data1 As Integer
        Dim Data2 As Short
        Dim Data3 As Short
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=8)> Dim Data4() As Byte
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1)>
    Public Structure HIDD_ATTRIBUTES
        Dim Size As Integer
        Dim VendorID As Short
        Dim ProductID As Short
        Dim VersionNumber As Short
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1)>
    Public Structure HIDP_CAPS
        Dim Usage As Short
        Dim UsagePage As Short
        Dim InputReportByteLength As Short
        Dim OutputReportByteLength As Short
        Dim FeatureReportByteLength As Short
        <MarshalAs(UnmanagedType.ByValArray, SizeConst:=16)> Dim Reserved() As Short
        Dim NumberLinkCollectionNodes As Short
        Dim NumberInputButtonCaps As Short
        Dim NumberInputValueCaps As Short
        Dim NumberInputDataIndices As Short
        Dim NumberOutputButtonCaps As Short
        Dim NumberOutputValueCaps As Short
        Dim NumberOutputDataIndices As Short
        Dim NumberFeatureButtonCaps As Short
        Dim NumberFeatureValueCaps As Short
        Dim NumberFeatureDataIndices As Short
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1)>
    Public Structure SECURITY_ATTRIBUTES
        Dim nLength As Integer
        Dim lpSecurityDescriptor As Integer
        Dim bInheritHandle As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)>
    Public Structure SP_DEVICE_INTERFACE_DATA
        Dim cbSize As Integer
        Dim InterfaceClassGuid As GUID
        Dim Flags As Integer
        Dim Reserved As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1, CharSet:=CharSet.Ansi)>
    Public Structure SP_DEVINFO_DATA
        Dim cbSize As Integer
        Dim ClassGuid As GUID
        Dim DevInst As Integer
        Dim Reserved As Integer
    End Structure

    <StructLayout(LayoutKind.Sequential, Pack:=1)>
    Public Structure SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim cbSize As Integer
        Dim DevicePath As Byte
    End Structure

    '******************************************************
    '関数の定義  USB-IO2.0用 (サンプルプログラムそのままコピペ)
    '******************************************************
   Public Declare Function CloseHandle Lib "kernel32" (ByVal hObject As Integer) As Integer
    Public Declare Sub RtlMoveMemory Lib "kernel32" (ByRef Destination As Byte, ByVal Source As IntPtr, ByVal Length As Short)

    Public Declare Function CreateFile _
        Lib "kernel32" _
        Alias "CreateFileA" _
        (ByVal lpFileName As String,
        ByVal dwDesiredAccess As Integer,
        ByVal dwShareMode As Integer,
        ByRef lpSecurityAttributes As SECURITY_ATTRIBUTES,
        ByVal dwCreationDisposition As Integer,
        ByVal dwFlagsAndAttributes As Integer,
        ByVal hTemplateFile As Integer) _
    As Integer

    Public Declare Function ReadFile _
        Lib "kernel32" _
        (ByVal hFile As Integer,
        ByRef lpBuffer As Byte,
        ByVal nNumberOfBytesToRead As Integer,
        ByRef lpNumberOfBytesRead As Integer,
        ByVal lpOverlapped As Integer) _
    As Integer

    Public Declare Function WriteFile _
        Lib "kernel32" _
        (ByVal hFile As Integer,
        ByRef lpBuffer As Byte,
        ByVal nNumberOfBytesToWrite As Integer,
        ByRef lpNumberOfBytesWritten As Integer,
        ByVal lpOverlapped As Integer) _
    As Integer

    Public Declare Function HidD_GetAttributes Lib "hid.dll" (ByVal HidDeviceObject As Integer, ByRef Attributes As HIDD_ATTRIBUTES) As Integer
    Public Declare Function HidD_GetHidGuid Lib "hid.dll" (ByRef HidGuid As GUID) As Integer
    Public Declare Function HidD_GetPreparsedData Lib "hid.dll" (ByVal HidDeviceObject As Integer, ByRef PreparsedData As Integer) As Integer
    Public Declare Function HidP_GetCaps Lib "hid.dll" (ByVal PreparsedData As Integer, ByRef Capabilities As HIDP_CAPS) As Integer

    Public Declare Function SetupDiEnumDeviceInterfaces _
        Lib "setupapi.dll" _
        (ByVal DeviceInfoSet As Integer,
        ByVal DeviceInfoData As Integer,
        ByRef InterfaceClassGuid As GUID,
        ByVal MemberIndex As Integer,
        ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA) _
    As Integer

    Public Declare Function SetupDiGetClassDevs _
        Lib "setupapi.dll" _
        Alias "SetupDiGetClassDevsA" _
        (ByRef ClassGuid As GUID,
        ByVal Enumerator As String,
        ByVal hwndParent As Integer,
        ByVal Flags As Integer) _
    As Integer

    Public Declare Function SetupDiGetDeviceInterfaceDetail _
       Lib "setupapi.dll" _
       Alias "SetupDiGetDeviceInterfaceDetailA" _
       (ByVal DeviceInfoSet As Integer,
       ByRef DeviceInterfaceData As SP_DEVICE_INTERFACE_DATA,
       ByVal DeviceInterfaceDetailData As Integer,
       ByVal DeviceInterfaceDetailDataSize As Integer,
       ByRef RequiredSize As Integer,
       ByVal DeviceInfoData As Integer) _
    As Integer

    Public HidDevice As Integer = INVALID_HANDLE_VALUE
    Public Capabilities As HIDP_CAPS

    '*****************************************************************
    '    関数いろいろ  USB-IO2.0用 (サンプルプログラムそのままコピペ)
    '*****************************************************************

    '接続する関数
    Private Function openDevice() As Boolean
        Dim HidGuid As GUID
        Dim DeviceInfoSet As Integer
        Dim MyDeviceInterfaceData As SP_DEVICE_INTERFACE_DATA
        Dim MemberIndex As Integer
        Dim MyDeviceInfoData As SP_DEVINFO_DATA
        Dim Needed As Integer
        Dim DetailData As Integer
        Dim MyDeviceInterfaceDetailData As SP_DEVICE_INTERFACE_DETAIL_DATA
        Dim DetailDataBuffer() As Byte
        Dim gch As GCHandle
        Dim address As Integer
        Dim DevicePathName As String
        Dim sa As SECURITY_ATTRIBUTES
        Dim DeviceAttributes As HIDD_ATTRIBUTES
        Dim PreparsedData As Long
        Dim ipt As IntPtr
        Dim Result As Integer

        openDevice = False
        Result = HidD_GetHidGuid(HidGuid)
        DeviceInfoSet = SetupDiGetClassDevs(HidGuid, vbNullString, 0, (DIGCF_PRESENT Or DIGCF_DEVICEINTERFACE))

        MemberIndex = 0

        Do
            MyDeviceInterfaceData.cbSize = Marshal.SizeOf(MyDeviceInterfaceData)
            Result = SetupDiEnumDeviceInterfaces(DeviceInfoSet, 0, HidGuid, MemberIndex, MyDeviceInterfaceData)

            If Result <> 0 Then
                MyDeviceInfoData.cbSize = Marshal.SizeOf(MyDeviceInfoData)
                Result = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, MyDeviceInterfaceData, 0, 0, Needed, 0)

                DetailData = Needed
                MyDeviceInterfaceDetailData.cbSize = Marshal.SizeOf(MyDeviceInterfaceDetailData)
                ReDim DetailDataBuffer(Needed)
                ipt = Marshal.AllocHGlobal(Marshal.SizeOf(MyDeviceInterfaceDetailData))
                Marshal.StructureToPtr(MyDeviceInterfaceDetailData, ipt, False)
                Call RtlMoveMemory(DetailDataBuffer(0), ipt, 4)

                gch = GCHandle.Alloc(DetailDataBuffer, GCHandleType.Pinned)
                address = gch.AddrOfPinnedObject().ToInt32()

                Result = SetupDiGetDeviceInterfaceDetail(DeviceInfoSet, MyDeviceInterfaceData, address, DetailData, Needed, 0)

                gch.Free()

                DevicePathName = System.Text.Encoding.GetEncoding("Shift-JIS").GetString(DetailDataBuffer)
                DevicePathName = DevicePathName.Substring(4)

                sa.nLength = 12
                sa.lpSecurityDescriptor = 0
                sa.bInheritHandle = 0

                HidDevice = CreateFile(DevicePathName, GENERIC_READ Or GENERIC_WRITE, (FILE_SHARE_READ Or FILE_SHARE_WRITE),
                                        sa, OPEN_EXISTING, 0, 0)

                If HidDevice <> INVALID_HANDLE_VALUE Then
                    DeviceAttributes.Size = Marshal.SizeOf(DeviceAttributes)
                    Result = HidD_GetAttributes(HidDevice, DeviceAttributes)

                    If (DeviceAttributes.VendorID = MyVendorID) And (DeviceAttributes.ProductID = MyProductID Or DeviceAttributes.ProductID = MyProductID2) Then

                        HidD_GetPreparsedData(HidDevice, PreparsedData)
                        HidP_GetCaps(PreparsedData, Capabilities)

                        openDevice = True
                        Exit Do
                    Else
                        Result = CloseHandle(HidDevice)
                    End If

                End If
            Else
                Exit Do
            End If
            MemberIndex = MemberIndex + 1
        Loop

    End Function


​    '閉じる関数​
    Private Sub closeDevice()
        If HidDevice <> INVALID_HANDLE_VALUE Then
            CloseHandle(HidDevice)
        End If
    End Sub

​    '送受信関数​
   Private Sub SendRecv(ByVal sendData() As Byte, ByRef recvData() As Byte)
        Dim i As Integer
        Dim s As String
        Dim NumberOfBytesWritten As Integer
        Dim NumberOfBytesRead As Integer

        Dim wrtData(Capabilities.OutputReportByteLength - 1) As Byte
        Dim readData(Capabilities.InputReportByteLength - 1) As Byte

        On Error GoTo errJump

        wrtData(0) = &H0
        For i = 0 To 63
            wrtData(i + 1) = sendData(i)
        Next
        WriteFile(HidDevice, wrtData(0), Capabilities.OutputReportByteLength, NumberOfBytesWritten, 0)

        Do
            ReadFile(HidDevice, readData(0), Capabilities.InputReportByteLength, NumberOfBytesRead, 0)
            If wrtData(64) = readData(64) Then
                Exit Do
            End If
        Loop

        For i = 0 To 63
            recvData(i) = readData(i + 1)
        Next

        Exit Sub

errJump:
        MsgBox(Err.Description)
    End Sub




    '*****************************************************************
    '    自分で書いたMCP4922制御用コードの始まり
    '*****************************************************************

    'ピンの状態を表す配列
 'J1のpin7~pin0にセットするビット列を表す0と1の文字列 左端がpin7 送るときはConvert.tobyteによってバイト値に変換する
    Dim CommandBinStringsArray() As String   

​   'コマンド行インデックスの最大値  (実際のコマンド行数)-1を指定​
    Dim NofCommmandArray As Integer = 36


​    '起動時​
    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        ReDim CommandBinStringsArray(NofCommmandArray)

​        'コマンドライン引数の取得​
        Dim cmds As String() = System.Environment.GetCommandLineArgs()
        Dim selectDAC As Integer
        If cmds(1) = "A" Then selectDAC = 0
        If cmds(1) = "B" Then selectDAC = 1

        Dim SetVoltage As Double = CDbl(cmds(2))
        If SetVoltage > 10 Then SetVoltage = 10
        If SetVoltage < 0 Then SetVoltage = 0


​        '起動時自動接続 J1を全ピンを出力に変える​
        ConnectUSBIO()

​        '電圧印加​
        ReadWritePins(SetVoltage, selectDAC)

​        '終了​
        closeDevice()
        End



    End Sub







​    '接続&出力設定​
    Private Sub ConnectUSBIO()

​        '接続が成功したら​
        If openDevice() = True Then

​            '送受信バッファを用意して​
            Dim sendData(63) As Byte
            Dim recvData(63) As Byte

​           'まずは現状の設定を問い合わせる​
            sendData(0) = &HF8              ​'コマンド :システム設定用フラッシュロム読込み​
            sendData(63) = &H0              ​ 'シーケンス​
            SendRecv(sendData, recvData)   ​  '送受信​


      'J1pinの状態(インデックス5)を見る 上位ビットがpin7、下位ビットがpin0になる 
            'ビットON(=1)になっていれば入力ピン設定されている。全ピンが出力設定(つまりインデックス5の値が0)になっているか確認して、そうなっていなければ0を送る(J1全ピンを出力に設定)
            If recvData(5) And &H0 = False Then

                sendData(0) = &HF9              'コマンド :システム設定用フラッシュロム書き込み
                sendData(1) = 0                 '未使用
                sendData(2) = recvData(2)  'プルアップを設定(今回使わないけど現状をそのまま返す)
                sendData(3) = 0                 '未使用
                sendData(4) = 0                 '未使用
                sendData(5) = &H0        '入力ピン設定 ビットON(=1)が入力ピン設定なので0を送って全部出力ピンにする
                sendData(63) = &H0              'シーケンス

                SendRecv(sendData, recvData)    '送信
            End If



​            '接続が失敗した場合は何もせずそのまま終了することにする​
        End If


    End Sub







​    '電圧印加用コマンドを作る​
    Private Sub ReadWritePins(SetVoltage As Double, selectDAC As String)

        Dim iii As Integer

        '設定する12bitのバイナリ値(0~4095)を計算  本来、5V=4095であるが、
        'LM358オペアンプによって0-10Vに増幅するから、ここでは10Vが指定されたときに4095を出すようにする
        Dim SetBinValue As Integer = CInt(SetVoltage / 10 * 4095)

        'config bits部分をセット
        'CS、SCK、SDI、LDACの順でpin7、6、5、4につなぐ  最上位ビット(左端)がpin7 最下位ビット(右端) がpin0
        CommandBinStringsArray(0) = "1001" '始状態

        CommandBinStringsArray(1) = "00" & selectDAC & "1" 'DAC A/Bをセット
        CommandBinStringsArray(2) = "01" & selectDAC & "1"

        CommandBinStringsArray(3) = "0011" 'BUF=1 固定
        CommandBinStringsArray(4) = "0111"

        CommandBinStringsArray(5) = "0011" 'GA=1 固定  ちなみにGA=0(x2倍)にしたからと言って10Vが出るわけではない
        CommandBinStringsArray(6) = "0111"  '確かにVrefの2倍が出るが、上限は5V(VDD)。つまりVrefが2Vのときには4Vが出たりするだけの話

        CommandBinStringsArray(7) = "0011" 'SHDN=1 固定
        CommandBinStringsArray(8) = "0111"

        '12 data bits部分をセット
        'インデックス9~32はバイナリ値をビット列に置き換えたものとなる  上位ビットから12ビット分送信
        Dim tempbit As Integer
        For iii = 0 To 11
            tempbit = Math.Floor(SetBinValue / (2 ^ (11 - iii))) Mod 2
            CommandBinStringsArray(9 + iii * 2) = "00" & tempbit & "1"
            CommandBinStringsArray(10 + iii * 2) = "01" & tempbit & "1"
        Next iii

​        '残りのビットを用意​
        CommandBinStringsArray(33) = "0001" 'クロック終了
        CommandBinStringsArray(34) = "1001" 'CSを上げる

        CommandBinStringsArray(35) = "1000" 'LDACを開ける
        CommandBinStringsArray(36) = "1001" '終状態

        'pin3~0の部分を追記  とりあえず今は0埋め
        'MCP4922を複数台つなぐのであれば、ここにCSとLDACのデータを書く (SCKとSDI線は複数のMCP4922で共有できる) 
        For iii = 0 To NofCommmandArray
            CommandBinStringsArray(iii) = CommandBinStringsArray(iii) & "0000"
        Next iii

​        'コマンド送信​
        SendCommand(CommandBinStringsArray, NofCommmandArray)

    End Sub




​    'コマンド送信​
    Private Sub SendCommand(CommandArray() As String, NofIndex As Integer)

        Dim iii As Integer

​        '入出力バッファを用意して​
        Dim sendData(63) As Byte
        Dim recvData(63) As Byte

        sendData(0) = &H20              ​'コマンド :デジタル入出力​
        sendData(1) = &H1               ​'出力1:J1​
        sendData(63) = &H0              ​'シーケンス​

        For iii = 0 To NofIndex
            sendData(2) = Convert.ToByte(CommandArray(iii), 2)  ​'0と1の文字列だったビット列をバイト値に変換してセット​
            SendRecv(sendData, recvData)    ​'送受信​
​            'System.Threading.Thread.Sleep(1)            ' Wait とりあえず不要​
        Next iii


    End Sub


End Class





明日に続く。

​​ ​​ ​​​​​​​​​​​​​​​​​





お気に入りの記事を「いいね!」で応援しよう

最終更新日  2019.12.27 23:07:16
コメントを書く


【毎日開催】
15記事にいいね!で1ポイント
10秒滞在
いいね! -- / --
おめでとうございます!
ミッションを達成しました。
※「ポイントを獲得する」ボタンを押すと広告が表示されます。
x
X

コメント新着

quanta511 @ Re[1]:柿の種も高級品になるのか(11/20) まーっさんへ コメントありがとうござい…
まーっ@ Re:柿の種も高級品になるのか(11/20) 更新を楽しみに拝見してます。 古い記事へ…
私はイスラム教徒です@ Re:美大あるある 工学部も同じ(05/07) 神神は言った: コーランで 『 (21) 人…
聖書預言@ Re:どんど焼き(01/14) 神の御子イエス・キリストを信じる者は永…
aki@ この様な書き込み大変失礼致します 日本も当事国となる台湾有事を前に反日メ…

© Rakuten Group, Inc.
X

Design a Mobile Website
スマートフォン版を閲覧 | PC版を閲覧
Share by: