langJapanese
HOME > RT-C Language Controller > Sample "Analog Input Control""
> Sample for RT-C Language Controller <

 Analog Output Control
Here we describe how to output data to analog output board using PCI board control function of RT-C Language Controller standard library "RTC-APILib"
■Equipments
T-C Language Controller
Analog Output Board:CONTEC DA12-16(PCI)

1. Flow
Let me introduce as an example of "CONTEC DA12-16(PCI)".
Board Settings (※ Execute once when program boots))
(1) Search Board
Get IO port to be used by PciFindDevice() of pcibus class.
UInt16 VenID = 0x1221;    // Vendor ID
UInt16 DevID = 0x8163;    // Device ID
UInt16 DevIndex = 0;      // Board ID
UInt32 BaseAddr;

// Search Board
//
// PciFindDevice
//    UInt16 VendorID        :Vendor ID
//    UInt16 DeviceID        :Device ID
//    UInt16 DeviceIndex     :Board ID
//    UInt16 AddrIndex       :Top of acquired base address
//    UInt16 AddrCount       :Numbers of acquired base address
//    ref UInt32 BaseAddr    :Variable where base address is stored
//
pcibus.PciFindDevice(VenID, DevID, DevIndex, 0, 1, ref BaseAddr);    // Get top of base address

// Get IO port address
IOPort = (UInt16)(BaseAddr & 0xFFFC);
(2) Initialize board
Output "Initialize process command" to IO port to initialize board
// ssue board initialize command
pcibus.OutBYTE((ushort)(IOPort + 0x0008), 0);
(3) Set Sampling temrs
After outputing "setting command of sampling terms" to IO port, output setting data ([input mode][channel mode][clock source to be used][sampling mode]).
Byte bAOMode = 0;       // Output Mode                 0:Transparent Output  1:Synchronous Output
Byte bIntClk = 0;       // Internal Sampling Blcok    0:Disabled                1:Enabled
Byte bExtClk = 0;       // External Sampling Blcok   0:Disabled                    1:Enabled

// +----+----+----+----+----+------------------------+------------------------+-----------+
// | D7 | D6 | D5 | D4 | D3 |           D2           |           D1           |    D0     |
// +----+----+----+----+----+------------------------+------------------------+-----------+
// | -- | -- | -- | -- | -- |External Sampling Blcok |Internal Sampling Blcok |Output Mode|
// +----+----+----+----+----+------------------------+------------------------+-----------+
Byte byDATA = (Byte)((bExtClk << 0x02) | (Board.bIntClk << 0x01) | Board.bAOMode);

// Issue command of Sampling temrs reset
pcibus.OutBYTE((ushort)(IOPort + 0x0008), 1);
// Write Sampling temrs
pcibus.OutBYTE((ushort)(IOPort + 0x000C), byDATA);
(4) Set Range Width
After outputting "Setting command of Output Range" to IO port, output settings of Output Range per each channel.
// 0x00:0-10[V]、0x01:±5[V]、0x02:±10[V]
Byte bRange = 0x02;

// Issue command of Range setting
pcibus.OutBYTE((ushort)(IOPort + 0x0008), 2);

// process of Range setting
for (Byte i = 0; i < bUseCh; i++)
{
    // Set CH to be set
    pcibus.OutBYTE((ushort)(IOPort + 0x000C), i);
    // Set range width
    pcibus.OutBYTE((ushort)(IOPort + 0x000D), bRange);
}
(5) Set interrupt mask
After outputting "Setting command of Interrupt factor" to IO port, output settings of factor for interrupt signal occurrance.
※ All must be prohibited.
Byte bFcr0 = 0xFF;        // Interrupt mask0    ※Bit Unit (0:Occur 1:Prohibit)
Byte bFcr1 = 0xFF;        // Interrupt mask1    ※Bit Unit (0:Occur 1:Prohibit)

// Issue setting command of Interrupt mask
pcibus.OutBYTE((ushort)(IOPort + 0x0008), 7);

// Set Interrupt mask
pcibus.OutBYTE((ushort)(IOPort + 0x000C), bFcr0);
pcibus.OutBYTE((ushort)(IOPort + 0x000D), bFcr1);

Data Sampling (※ Always executing in operation)
(6) Output data setting
After setting output channel to "Output channel setting register" of IO port, set output data.
Byte bUseCh = 16;        //CH numbers to be used  1~16
UInt16 wData = 10;        //Output data

for (bChNo = 0; bChNo < bUseCh; bChNo++)
{
    // Set CH to output
    pcibus.OutBYTE((ushort)(IOPort + 0x0004), bChNo);
    // Output data
    pcibus.OutHWORD((ushort)(IOPort + 0x0000), wData);
}
※ Repeat (6)

2. Sample Program(C# Source Code)
This sample runs 2 tasks such as【Main Process】which does initialization and does arbitrary processes & 【Data Output Process】which outputs data to board.
■Main Process:
It does board settings when program boots.
You can designate output data and do arbitrary processes while program is running
Main Process
■Data output Process:
It completes board settings in main process, then start data output process.
For example, it outputs sine wave while program is running.
データ出力処理
    // *** Constant ***

    /// <summary>
    /// Output Range
    /// </summary>
    public enum RANGE : byte
    {
        U_1000 = 0x0,       // Unipolar:0..10[V]
        B_0500 = 0x1,       // Bipolar:-5..5[V]
        B_1000 = 0x2        // Bipolar:-10..10[V]
    }

    /// <summary>
    /// Define global variables
    /// </summary>
    public unsafe class GlobalVar
    {
        public static Boolean inExe;            // Request Execution
        public static Boolean inBusy;           // Flag for Running
        public static Boolean inErr;            // Fral for In Error
        public static UInt32 inErrCode;         // Error Code
        public static UInt16 IOPort;            // IO port of analaog board
        public static Single fLo;               // Voltage of minimum output
        public static Single fHi;               // Voltage of maximum output
        public static UInt16 wData;             // Output data instantaneous value
        public static Single fData;             // Output data [V]instantaneous value
    }

    /// <summary>
    /// Define board setting value
    /// </summary>
    public unsafe class Board
    {
        // Target Board
        public static UInt16 VenID = 0x1221;            // CONTEC
        public static UInt16 DevID = 0x8163;            // DA12-16(PCI)
        public static UInt16 DevIndex = 0;              // Board ID:0
        public static Byte bMaxCh = 16;                 // Board CH number
        public static UInt16 Resolution = 0x0FFF;       // Resolution
        // Smapling terms Setting value
        public static Byte bAOMode = 0;           // Output Mode                0:Transparent Output  1:Synchronous Output
        public static Byte bIntClk = 0;           // Internal Sampling Blcok    0:Disabled            1:Enabled
        public static Byte bExtClk = 0;           // External Sampling Blcok    0:Disabled            1:Enabled

        public static Byte bUseCh = 1;                  // CH numbers to be used
        // Range Width Setting value
        public static Byte bRange = (Byte)RANGE.B_1000; // Output Range
        // Inerrupt Mask Setting value
        public static Byte bFcr0 = 0xFF;                // Interrupt mask0    ※Bit Unit (0:Occur 1:Prohibit)
        public static Byte bFcr1 = 0xFF;                // Interrupt mask1    ※Bit Unit (0:Occur 1:Prohibit)
    }
    /// <summary>
    /// *****************************************************************************************************
    ///  Main Process Block
    /// *****************************************************************************************************
    /// </summary>
    [FUNCTION_BLOCK]
    public class _main
    {
        // *** Internal Variables ***
        /// <summary>
        /// Search Target board
        /// </summary>
        private Boolean FindBoard()
        {
            UInt32 BaseAddr = 0;

            if (pcibus.PciFindDevice(Board.VenID, Board.DevID, Board.DevIndex, 0, 1, ref BaseAddr) == false)
            {
                GlobalVar.IOPort = 0;
                return false;
            }
            GlobalVar.IOPort = (UInt16)(BaseAddr & 0x0000FFFC);
            return true;
        }

        /// <summary>
        /// Intialize board
        /// </summary>
        private void InitalizeBord()
        {
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x0008), 0);
        }

        /// <summary>
        /// Set Sampling terms
        /// </summary>
        private void SetSampling()
        {
            // +------------------------+------------------------+-----------+
            // |           D2           |           D1           |    D0     |
            // +------------------------+------------------------+-----------+
            // |External Sampling Blcok |Internal Sampling Blcok |Output Mode|
            // +------------------------+------------------------+-----------+
            Byte byDATA = (Byte)(
                        (Board.bExtClk << 0x02)
                      | (Board.bIntClk << 0x01)
                      | Board.bAOMode
                          );

            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x0008), 0x01);      // Issue set command for Sampling terms
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x000C), byDATA);    // Write Sampling terms

        }

        /// <summary>
        /// Set range width
        /// </summary>
        private void SetRange()
        {
            // ssue set command for range
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x0008), 0x02);

            // Process for range setting
            for (Byte i = 0; i < Board.bUseCh; i++)
            {
                pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x000C), i);               // Set CH to be set
                pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x000D), Board.bRange);    // Set range width
            }

            // Set Voltage of minimum output / Voltage of maximum output
            switch (Board.bRange)
            {
                case (Byte)RANGE.U_1000:
                    GlobalVar.fLo = 0.0f;
                    GlobalVar.fHi = 10.0f;
                    break;
                case (Byte)RANGE.B_0500:
                    GlobalVar.fLo = -5.0f;
                    GlobalVar.fHi = 5.0f;
                    break;
                case (Byte)RANGE.B_1000:
                    GlobalVar.fLo = -10.0f;
                    GlobalVar.fHi = 10.0f;
                    break;
            }

        }

        /// <summary>
        /// Set Interrupt mask
        /// </summary>
        private void SetIntrMask()
        {
            // Issue set command for Interrupt mask
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x0008), 0x07);

            // Set Interrupt mask
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x000C), Board.bFcr0);
            pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x000D), Board.bFcr1);

        }



        /// <summary>
        /// PLC Program - Process in download
        /// </summary>
        public unsafe _main()
        {

            // Analog board setting
            if (!FindBoard())      // Search analog board
            {
                GlobalVar.inErr = true;     // Error
                GlobalVar.inErrCode = 1;    // Board
                return;
            }
            InitalizeBord();        // Initialize board
            SetSampling();          // Set Sampling terms
            SetRange();             // Set Range Width
            SetIntrMask();          // Set Interrupt mask


            // Initialize global variables
            GlobalVar.inErr = false;
            GlobalVar.inErrCode = 0;
        }

        /// <summary>
        /// PLC Program - Process in reset
        /// </summary>
        ~_main()
        {
        }

        /// <summary>
        /// PLC Program - Process in start
        /// </summary>
        public void __Init()
        {
            GlobalVar.inExe = false;
        }

        /// <summary>
        /// PLC Program - Process in executes
        /// </summary>
        public unsafe void __Process()
        {
            if (GlobalVar.inErr)
            {
                GlobalVar.inExe = false;            // Execute request OFF
                return;
            }

            if (GlobalVar.inExe != true)            // If Execute request is not issued
            {
                GlobalVar.inExe = true;             // Execute request ON and start sampling
            }

            /* --- Write ToDo here --- */
        }
    }
    /// <summary>
    /// *****************************************************************************************************
    ///  Data Output Process Block
    /// *****************************************************************************************************
    /// </summary>
    [FUNCTION_BLOCK]
    public class _outputdata
    {
        // *** Internal Variables ***
        private UInt32 Rate = 1000;           // Sample Rate
        private Single Lo = -10.0f;           // Min(V)
        private Single Hi = 10.0f;            // Max(V)
        private UInt32 uiStep;

        // *** Internal Variables ***
        /// <summary>
        /// Output range check
        /// </summary>
        private Boolean CheckRange()
        {
            if ((Lo > GlobalVar.fHi) || (Lo < GlobalVar.fLo)) return false;
            if ((Hi > GlobalVar.fHi) || (Hi < GlobalVar.fLo)) return false;

            return true;
        }

        /// <summary>
        /// Calculate output data
        /// </summary>
        private UInt16 CalcOutputData(Single volt)
        {
            //                   (Output Voltage[V] - Min Voltage[V]) * Resolution
            // Output Voltage = ──────────────────────────
            //                    Output Voltage[V] - Min Voltage[V]
            return (UInt16)(((volt - GlobalVar.fLo) * Board.Resolution) / (GlobalVar.fHi - GlobalVar.fLo));
        }

        /// <summary>
        /// Data Output
        /// </summary>
        private void OutData(Single volt)
        {
            Byte bChNo;

            // Convert voltage value to output data
            GlobalVar.wData = CalcOutputData(volt);
            for (bChNo = 0; bChNo < Board.bUseCh; bChNo++)
            {    // Output
                pcibus.OutBYTE((ushort)(GlobalVar.IOPort + 0x0004), bChNo);
                pcibus.OutHWORD((ushort)(GlobalVar.IOPort + 0x0000), GlobalVar.wData);
            }
            return;
        }

        /// <summary>
        /// Create sine wave
        /// </summary>
        private Single SinData(UInt32 step)
        {
            Single gain = (Hi - Lo) / 2.0f;    // Amplitude
            Single ofst = gain + Lo;        // DC offset
            Single sin = (gain * (Single)Math.Sin((double)step * (Math.PI * 2.0) / (double)Rate)) + ofst;
            return sin;
        }


        /// <summary>
        /// PLC Program - Process in download
        /// </summary>
        public _outputdata()
        {

        }

        /// <summary>
        /// PLC Program - Process in reset
        /// </summary>
        ~_outputdata()
        {
        }

        /// <summary>
        /// PLC Program - Process in start
        /// </summary>
        public unsafe void __Init()
        {
            GlobalVar.inBusy = false;    // Execute Flag OFF
            uiStep = 0;                  // Clear sine wave
        }

        /// <summary>
        /// PLC Program - Process in execute
        /// </summary>
        public unsafe void __Process()
        {
            // Output process is not executed when IOPort cannot be got
            if (GlobalVar.IOPort == 0)
            {
                GlobalVar.inBusy = false;
                return;
            }

            // If Max voltage and Min voltage are outside the range, output 0V and end
            if (!CheckRange())
            {
                GlobalVar.fData = 0;
                OutData(GlobalVar.fData);
                return;
            }

            // Refresh Execute Flag according to execution request
            if (GlobalVar.inBusy != GlobalVar.inExe)
            {
                GlobalVar.inBusy = GlobalVar.inExe;
            }


            // If there is an execution request, start output process
            if (GlobalVar.inExe)
            {
                // Create sine wave
                uiStep = (uiStep + 1) % Rate;
                GlobalVar.fData = SinData(uiStep);

                // Write Data
                OutData(GlobalVar.fData);
            }
            return;
        }
    }