Dept. of Medical Physics and Bioengineering Implanted Devices Group Automated data logging and temperature control for thick-film process analysis MSc Radiation Physics: Final Report Author: Alexander James Messenger Supervisors: Dr. Anne Vanhoestenberghe Ms Kylie de Jager Word Count: 9840 11/08/2010 Abstract This report gives an account of how a bespoke data logger was built to monitor manufacturing processes in a clean room. The device was built using a microcontroller unit with inbuilt ADCs and assembled in an enclosure with a modular hardware design, which allows it to be easily repaired and augmented. The modules for the device include an LCD and keypad for user interface; type J/K thermocouple amplifiers for measuring temperature, and a constant current source array for measuring resistance. The device also includes a 16 channel multiplexer, and SD card reader for data storage. The device has been demonstrated to take measurements at regular intervals for up to 24 hours and store the data in a format compatible with most PCs. Although more time needs to be spent fine tuning and verifying the performance of the device, it is clear it is an effective solution for the environment it is designed to work in. Notes are included with this report suitable for someone wishing to build or modify the device. ii Acknowledgements I would firstly like to thank Anne Vanhoestenberghe for her continued help and support throughout the project, and Kylie de Jager for also taking time to help me. I would also like to thank Martin Fry, Joe Evans, Tim Perkins and Nick Donaldson who all helped with solutions to some of the problems that arose during the course of the project. iii Table of Contents 1. 2. Abstract Acknowledgements Abbreviations Introduction Existing Solutions 2.1 2.2 2.3 Data Acquisition Devices Microcontroller Units Available MCUs 3. Hardware Design 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 3.9 3.10 3.11 Thermocouple Amplifiers DC - DC Converter LCD Keypad Enclosure External SD card Grounding Issues and Interference Current Source Array Operational Amplifier Multiplexer Level Changers 4. Software Design 4.1 4.2 4.3 4.4 4.5 4.6 4.7 4.8 4.9 4.10 4.11 Reading from an ADC Taking a Temperature Reading Writing to a File Data Formatting Data Management Parameters Program and Memory Hierarchy LCD Keypad Multiplexer and Current Source Main Data Logging Program 5. Results and Discussion ii iii vi 1 1 2 2 3 4 5 6 8 9 9 11 11 11 13 14 15 17 17 18 18 19 19 20 21 21 22 23 23 24 24 24 26 28 29 30 30 31 31 5.1 Resistance Measurements 5.1.1 Current Source Ramp Time 5.1.2 Measurement Stability 5.1.3 Calculated Resistance 5.2 Temperature Measurements 5.3 Further Discussion 5.3.1 Long Data Runs 5.3.2 AC/DC Power Supply 5.3.3 Battery Power iv 6. Conclusion and Further Work 6.1 Humidity Sensor 6.2 Profilometer 6.3 Real-Time Clock Backup References Appendices 32 33 33 33 34 (I) Calculations (II) User Guide i) Getting Started ii) Setting up an Experiment iii) Calibrating the Thermocouple iv) Running an Experiment v) Plotter Beta vi) Interfacing with a PC vii) Loading Programs viii) Saving to Flash ix) Reloading the Entire Data-logging Program (III) Schematics (IV) Program Code (V) Contact details v 34 35 37 37 37 39 39 41 41 42 43 43 45 50 61 Abbreviations Except for the most commonly used abbreviations, all the following are defined on their first use in the report. ABS – ADC – ASCII – BASIC – CMOS – CPU – CR – DAC – DAQ – DIP – HID – I2C – IC – IDG – LCD – LED – LF – MCU – MOSFET – Op-Amp – PC – PCB – RAM – RH – RS232 – RTC – SD – SIP – SPI – TTL – UART – UCL – USB – Acrylonitrile Butadiene Styrene Analogue to Digital Converter American Standard Code for Information Interchange Beginner's All-purpose Symbolic Instruction Code Complementary metal–oxide–semiconductor Central Processing Unit Carriage Return Digital to Analogue Converter Data Acquisition Device Dual In-Line Package Human Interface Device Inter-Integrated Circuit Integrated Circuit Implanted Devices Group Liquid Crystal Display Light Emitting Diode Line Feed Microcontroller Unit Metal–Oxide–Semiconductor Field-Effect Transistor Operational Amplifier Personal Computer Printed Circuit Board Random Access Memory Relative Humidity Recommended Standard 232 Real Time Clock Secure Digital Single In-Line Package Serial Peripheral Interface Bus Transistor Transistor Logic Universal Asynchronous Receiver/Transmitter University College London Universal Serial Bus vi 1. Introduction The Implanted Devices Group (IDG) operates a clean-room at the Dept. of Medical Physics at UCL, in which a number of manufacturing processes are undertaken. Many of the processes such as the production of thick film resistors are sensitive to the conditions (e.g. temperature or humidity) they are produced under, however this particular manufacturing process takes of the order of days; so to better understand how the conditions affect the final product, a form of automated data-logging and process control is required. Although there is a specific interest in the thick film process, the automated system should ideally be versatile enough, that it can be used with other experiments with minimal alteration. Most of the equipment in the clean room is fitted with sensors that give analogue signals, so the system should be able to accommodate this as well as reading digital signals. Measurements are expected to be made approximately every hour, of course a system that can work at higher frequency may be desirable for other future experiments, but the key concern is making a system that is stable over the period of days, weeks or more. The system will likely be monitoring many items in a process at once; therefore it should be able to accept many inputs. Another key consideration is easy communication with a PC, somebody unfamiliar with the system should easily be able to set it up and interface with any PC. Finally the system would be more effective if it could also give output signals for possible control of the processes that it is monitoring (e.g. temperature control). 2. Existing Solutions Clearly data-acquisition is not a new problem, having laid out what criteria the system should fulfil in the introduction, this chapter aims to explore some solutions that are available to buy off the shelf and discuss their advantages and disadvantages. Most scientists and engineers will be familiar with products marketed as „Data Acquisition Devices‟ (DAQ), typically an array of Analogue to Digital Converters (ADC) connected directly to a PC, listed below are several examples of these. 1 2.1 Data Acquisition Devices PicoLog 1000 Series [1], a DAQ with 12 or 16 ADC inputs at a resolution of 10 or 12 bits respectively, which depends on the model, both have a maximum sampling rate of 1 MSs-1 (Though this is in truth limited by the sample buffer in the DAQ). Connects directly to a PC over USB and is supplied with proprietary data logging software. (£105/£159) National Instruments NI USB-6008 [2], another 12 bit DAQ with 8 ADC inputs and a 10 KSs1 sample rate. Connects directly to a PC. (£99). Has software available similar to the above, but at an additional cost of £600. Both of these DAQs are fairly reasonable solutions for measuring and logging analogue signals, however both are fundamentally dependent on a PC for operation. In a normal laboratory situation this would not normally be a problem, but in the clean-room it is necessary to have a neat self contained solution. Datataker DT80 [3] –A versatile powerful DAQ with 15 ADC inputs suitable for reading voltages, current, resistance and frequency with an effective 18bit resolution. Can store data to USB (max 512MiB) or to FTP after configuration with PC; can be powered from the mains or battery. (£1915.25) This is a fairly impressive DAQ which has an advantage over the two previously mentioned, in that it can function independently from a PC once it has been initially set up. The only real drawback aside from the relatively complex set up is the price. The devices listed so far are all viable solutions but none are ideal; in the context of the cleanroom environment, a system that is completely self-contained would be best. It was decided that it would be useful for the purposes of the project to develop a device in the department. This would allow the project to cover the areas of product and circuit design as well as conducting scientific experiments and finally, creating a system that is truly fit for purpose. By designing a system from the ground up, it can be built to work truly independent from a PC with a suitable form of data storage and all remain contained within a single enclosure. 2.2 Microcontroller Units A device that can be programmed to interpret ADC inputs and do something meaningful with the information is a Microcontroller Unit (MCU). An MCU is a relatively simple CPU with supporting functions such as timers and serial and analogue I/O; it has a small amount of programmable memory that could be used to run a program for reading and storing analogue 2 signals, and digital outputs suitable for process control. Many MCUs have multiple ADCs (and DACs) built-in [4]. The Accuracy of an ADC is described by the number of bits it uses (quantisation), therefore we need to know what accuracy will likely be required of the device when choosing an ADC. Knowing the furnaces operate up to 1000˚C and a typical K-type thermocouple has an accuracy of 1.5˚C (below 300˚C then progressively less accurate) [5,6], a 10bit ADC or better would be suitable to cover this range. Humidity sensors are inherently not very accurate and there is little meaning in accuracy exceeding +/- 1% RH due to the effects of drift [7], so an 8 bit ADC would be sufficient for acquiring data [Appendices: Calculation 1]. An MCU has the advantage of being able to store data permanently to memory; some offering an on-board memory of up to 32KiB and above (though a certain portion of this must be dedicated to program storage). In addition to using the on board memory it is also possible to interface with an SD card module. A typical SD card module works with either a UART or SPI interface and should be compatible with card sizes of up to at least 2GiB of storage (This arises from limitations in the FAT16 filing system) [8][9]. Higher capacity modules are available, but a typical reading with a timestamp is of the order of 20 bytes [Section 4.5] and on a 2GiB card this equates to 105 readings. An obvious advantage to using a SD card for storage is that it can easily be removed from the system and read and analysed on a separate PC. When selecting an appropriate MCU it should be noted that some companies also offer development boards which are PCBs designed specifically for that chip with basic useful features such as power switches, serial ports and DC inputs; and another advantage is the microcontroller pins are much more accessible. 2.3 Available MCUs The Amtel ATMega32 is an MCU with 32KB of memory for program and data storage, and 8 ADC channels at 10bits [10]. It has on-board UART suitable for communication with PC and SD and there is a development board available equipped with RS232 communication, DC regulator, port connectors and various LEDs and DIP switches (£19 from India) [11]. There is also another development board for the same MCU available that is slightly more compact, 3 featuring just the DC regulator and ports but also supplied with C and BASIC compilers (£35.24) [12]. The PIC family of MCUs is another option, an example of which is the PIC18F4550 featuring the same 32KB memory, but also 13 ADC channels at 10bits [13]. The PIC manufacturers conveniently supply USB drivers to allow direct USB communication with a PC including HID and Mass Storage support, which would be advantageous considering most modern PCs are equipped with USB rather than serial ports. A development board is available, the PIC-USB-4550 (£20.88) [14] featuring a USB connection and AC/DC regulator, and ample space for additional components. Another member of the PIC family that would also be suitable is the PIC32MX340-512 [15]; this MCU has a larger 512KiB flash memory, 32KiB RAM and 16 ADC channels at 10bits. It is supplied with a development board [16] that includes USB connection, real-time clock, DC regulator, port connectors and microSD card interface built in. The board is also supplied with a variant of the BASIC programming language (PIC-32-Basic) which is interactive i.e. it allows calculations and functions to be written, executed; and results (interpreted) returned immediately. The DC regulator will accept power via USB or from an auxiliary DC source. This MCU/development board combination has an in built SD card slot and a good amount of available memory and ADC channels available at low cost (£38.55); so it was selected for use in the automated data-logging system. 3. Hardware Design Having selected the ByVac BV513 development board as the basis for the automated datalogging system, this chapter gives an account of the different components that were used to build the system. Although the system is the product of an MSc project, it should be emphasised that it is expected to be used as a bona-fide item of scientific equipment after the project is completed. To facilitate this, the system has been made to be as modular as possible, both in hardware and software; this allows any part that is not needed or faulty, to be isolated, removed and or repaired. All of the individual modules for the system were first tested using breadboard to verify all the components where functioning correctly. After this the modules where fabricated using stripboard, on which all the ICs and components where 4 soldered. 2.54mm pitch header pins and sockets where used to interconnect all of the modules. The following report has been separated into sections that correspond to the various modules of the system. It should also be noted that the majority of the hardware and software was developed concurrently, but for purposes of clarity they have been separated into different chapters. There are some small items of theoretical background included with the account of the practical work, but they haven‟t been separated into distinct chapters as they aid the flow of the report. For more technical details of how the system was developed, the appendices have information suitable for someone wishing to alter or expand the system. 3.1 Thermocouple Amplifiers Many of the processes in the IDG laboratories are conducted in furnaces. Type J or K thermocouples are the best method for measuring temperature inside a furnace, as they are low cost and cover a large temperature range. The basic theory behind a thermocouple is that a junction between two metals produces a voltage related to a temperature differential. There are a few hurdles to overcome when using one to take measurements. VoC-1 is typically very small e.g. a type K generates approx 41μVoC-1 [5,6]. VoC-1 is non-linear, particularly above 375oC [5,6]. A thermocouple does not measure absolute temperature, only a temperature difference, thus a measurement can only be made if the temperature of one of the junctions (the cold junction) is known [6]. To solve these problems an Analogue Devices AD595AQ Thermocouple Amplifier IC was selected, which has in-built cold junction compensation and outputs a linear voltage to temperature response at a more convenient level of 10mVoC-1. The AD595AQ accepts a supply voltage of +5V to +15V. This is useful as the MCU can supply 5V but it limits the temperature range to 300oC for type K, thus for higher readings a higher supply is required. A DC converter was used to supply the +15V, which is described in a later section. The ADCs on the MCU are rated from 0V to a maximum +3.3V; therefore the output from the AD595AQ is stepped down using a resistive divider. 5 Vout 2 1+ 2 Vin (1) The voltage output given by the AD595AQ is a signal, so resistors in the KΩ range should be used to minimise current draw. In this case values of R1 3.9KΩ and Calculation 2] 2 1.1KΩ [Appendices: where chosen. Two AD595AQs where mounted on stripboard, both with resistive dividers to reduce the output voltages. Care must be taken when connecting a thermocouple to the amplifier, as using anything other than thermocouple wiring will change how thermocouple behaves. To connect the AD595AQs to the back-panel, type K thermocouple extension wire was soldered directly to the back-panel terminals, as opposed to copper wire with pins and sockets. fig.1 AD955AQ Thermocouple Amplifier Module 3.2 DC - DC Converter A +15V power supply is required to make the full use of the AD595AQ temperature range, it is also useful for other modules in the system, for example it reduces the internal resistance of the multiplexers used later in the project. The BV513 board has a built-in DC regulator that will supply +5V from either USB or auxiliary power; by powering the DC converter from the board all the components will be functional using either power source. The DC converter selected was the „MAX773 high efficiency DC-DC converter‟, a type of switched-mode power supply (SMPS), specifically a flyback boost converter. The basic theory of operation is that an inductor tends to resist changes in current; when charged it acts as a load and absorbs energy, and when discharged it acts as an energy source. The voltage it produces during the discharge phase is related to the rate of change of current, and not to the 6 original charging voltage, thus allowing different input and output voltages [17]. By adjusting the duty cycle of the charging voltage (the ratio of on/off time), the amount of power transferred can be controlled. There were some initial problems with the set up of the DC converter. Having used the recommended values of resistors, capacitors and inductor [18], the IC was seen to continuously draw an exceptional amount of current (more than 200mA) in an attempt to raise the output voltage to the required +15V, on small load (10KΩ). A large current draw is expected during start up, but this is expected to be for a maximum 20µs, and afterward drop to no more than 110µA [18]. It was found that the Rsense resistor was lower than necessary to give the output current required, by changing it from 100mΩ to 560mΩ the IC could reach the required +15V on an open circuit,; however this took approximately 15s (depending on the current limit of the power supply) and this would immediately drop as soon as even a minor load (10KΩ) was placed across the outputs. Checking the circuit with an oscilloscope revealed that current in the inductor was ramping up to a high level before the current-limit comparator could turn off the ramp; this meant that the recommended inductor value of 22µH was being saturated and not sufficient for use in the circuit. By selecting an inductor such that (2) the current would have sufficient time to ramp up to a high level [18]. By using a 100µH inductor [Appendix: Calculation 3] the DC-DC converter began working as it should. The working circuit was then mounted to stripboard, featuring a single power input and five rows of power outputs to serve multiple modules. Initially the circuit did not function correctly when permanently mounted to stripboard, this was caused by some stray wire sitting underneath the stripboard, making contact with the solder joints. It was also later pointed out that the IC should not be directly soldered to the board, but rather fitted to an IC socket, that makes the IC easier to replace; all subsequent modules where fitted with these sockets. 7 fig.2 MAX773 DC DC Converter Module In the course of the project a need arose for a -15V rail. The MAX773 module was replaced with a similar IC, the „MAX743 Dual Output, Switch-Mode egulator‟ which could supply both the -15V and +15V. This particular IC did not need external N-channel MOSFETs, but otherwise required twice as many external components to drive the two power rails; however, the module was still able to fit in the original space allocated for the first DC converter by carefully planning the component layout, and using a second layer of stripboard mounted to the top of using nylon spacers. There are multiple power output sockets fitted to the second layer of stripboard, and power pins that protrude underneath the first layer that allow power cables to be run underneath the base-plate. fig.3 MAX743 Dual Output DC DC Converter 3.3 LCD When the system was shown to be capable of taking readings from the ADCs and storing to SD, an LCD was selected to enable the user to check the system is working as it should, and allow the user to set up the system as required. A graphical LCD was chosen that would allow large user menus and many readings to be shown simultaneously, compared to for example a typical two line LCD. The LCD selected is a BV4512 which has 128x64 pixels and is fitted with an I2C controller which features line and rectangle drawing functions and 8 ASCII character set allowing eight lines of 21 characters. The I2C interface is useful as it allows multiple devices to be connected to the same bus, and only uses two data wires making connections simpler than serial communication for example. 3.4 Keypad To enable a user to interact with the system a numerical keypad was integrated, allowing navigation of the user menus, and entry of settings for the experimental runs. The keypad is a BV4506, which has 12 keys and also uses the I2C interface. The keypad and LCD where connected together using 4-way ribbon cable, which corresponds to the two data lines, power line and ground line. The connectors on each end of the cable where made with the standard 2.54mm pitch pins, and double row sockets, allowing the cables to be piggy-backed to each other, and thus enabling both devices to be plugged into a single bus. The I2C interface also requires both data lines to be held high, this was achieved by making a small connector with 10KΩ pull-up resistors, to plug in the end of one of the cables. 3.5 Enclosure During the prototyping of the system, the parts where held together using a cardboard shell, this was subsequently replaced with a Hammond Instrument Case, with an ABS plastic body, and aluminium front and rear panels. The LCD and keypad were fitted to the faceplate using a pillar drill make a hole in the middle, manually cutting with a coping saw and finishing with a file. The LCD has mounting holes, so these where marked and drilled into the faceplate, and the LCD secured in place with M3 screws, nuts and nylon washers. The keypad does have mounting holes, but they are extremely close to the protruding part of the keypad, so it was easier to make the cut-out a tight fit, and hold the keypad in place purely by friction. fig.4 LCD and Keypad fitted to the Aluminium Face-plate 9 Most of the modules are made from 2.54mm pitch stripboard. To mount the modules inside the enclosure, a large piece of 2.54mm pitch matrix board is used as a base-plate. This has the advantage that when drilling the mounting holes for modules; they are always perfectly aligned with the base-plate, and the modules can easily be stacked and connected on top each other. The base-plate is secured to the enclosure using M3 screws and Nylon spacers, as are the modules to the base-plate. The MCU development board does not have any mounting holes (or any space for them), so a mounting bracket had to be made to secure it inside the enclosure. The USB port for the MCU must be accessible from the rear of the enclosure; this was again achieved by drilling, cutting and filing. The back-plate can only be installed and removed vertically, and therefore when the USB port of the MCU is fitted to the back-plate, the MCU as a whole can only be installed and removed vertically. Many project boxes are available that have the inside walls lined with grooves designed for slotting PCB and stripboard into; and also have plastic adaptors that allow the board to be mounted horizontally rather than vertically. By taking a small project box and cutting out one of the sides (with part of the base still attached), drilling holes in the base and fitting to the base-plate, a bracket suitable for vertically sliding the MCU was made. fig.5 ABS Case shown fitted with MCU bracket, SD card reader, base-plate, nylon mounting spacers and power sockets To allow the system to be powered from the mains as well as USB, a DC power jack is fitted to the rear panel and connected to the MCU via the usual 2.54mm sockets. To prevent the 10 MCU taking power from USB and an auxiliary source at the same time, a jumper was used to select the source; though this would be problematic to access when the box was sealed, so a power select switch was instead fitted to the rear panel by drilling, cutting, filing and securing with epoxy adhesive. 3.6 External SD card Although the MCU is fitted with a microSD card reader, it was not feasible to mount the MCU to the case in such a way that both the USB port and microSD card where easily accessible. A solution to this was to fit a separate full size SD card reader to the rear panel and connect to the MCU via 8-way ribbon cable. This proved advantageous, as the full size SD cards are easier to handle than their microSD counterparts. fig.6 Back-Panel of the Device, shown with the external SD card, power switch, USB, DC and Multiplexer Terminals 3.7 Grounding Issues and Interference During experiments with the MCU mounted inside the enclosure, the system began to experience some intermittent large drops in the LCD contrast, an indication that a large current was being drawn from one of the circuits. The current drops where absent if the DC converter was disconnected, or by waving a hand near the grounded back panel, so the problem was likely caused by bad wiring. To reduce the interference, all of the inter-module cables where replaced with twisted-pair cables, the connectors where covered in heat-shrink and 0.22µF decoupling capacitors where connected across the power pins of every module. 3.8 Current Source Array To analyse the thick film resistor process, change in resistance needs to be measured. The ADCs on the MCU measure voltage, so one way to read a resistance as a voltage is by using a constant current source. The LM334 is a three terminal current source that can be set 11 between 1µA and 10mA using a resistor, Rset [19]. The value of the resistor being measured is unknown and will depend on the application considered for the data-logger; so a range of constant currents is needed to give an appropriate voltage signal. Using a dual four channel multiplexer, UTC4502, two ranges of current sources could be selected, one for more accurately determining lower resistances, one for covering a broad range of higher resistances. Current (mA) Rset (Ω) Current (µA) Rset (Ω) 10 6.8 2000 33 5 13 200 330 1 63 20 3.3K 0.5 130 2 33K fig.7 Chart showing the required Rset resistors to set the LM334 current sources [Appendices: Calculation 4] Originally it was planned to use the multiplexer to select the resistance over the Rset terminals, however, the values of Rset were expected to range from 6.8Ω to 33KΩ, and the internal resistance of the multiplexer was expected to be approximately 80Ω when running on a +15V power supply [20]. This would significantly affect the majority of the current values, particularly as the internal resistance of the multiplexer cannot be assumed to remain constant. To solve this, separate current sources are used with their respective resistors, and the multiplexer selects which source to supply power to. The outputs of all the current sources on each half of the multiplexer are connected together, and the half of the multiplexer in use is selected using a jumper. To control if the current source is on or off, the inhibit pin on the multiplexer is used. fig.8 UTC4502 Multiplexer and Current Source Array 12 fig. 9 Multiplexer and Current Source array schematic 3.9 Operational Amplifier To measure the voltage across the resistors while only drawing a small amount of current, an operational amplifier (op-amp) is connected to the current source module output. The op-amp (OP97) is set up as a standard non-inverting amplifier with a very low input bias current of 100pA [21], the output gain set by a resistive voltage divider (3) The gain is set to a value of 10, using 9KΩ and 1KΩ resistors; however this is easily adjustable as the resistors are not directly soldered to the stripboard, but mounted using turned pin sockets that allow easy removal. The common-mode range of the OP97 typically extends to within 1V of either of the power rails, and functions most effectively in the middle that range. For most effective operation in the system then, the OP97 requires a power range of -15V and +15V, hence the need for the aforementioned dual output DC-DC converter. To control the input offset, a 5KΩ potentiometer is connected across the two offset null pins. With the gain at 10, the MDU should be able to read resistances in the ranges of 10Ω to 2.8KΩ and 50Ω to 70KΩ [Appendices: Calculation 5]. 13 3.10 Multiplexer For multiple resistors (or other experiments) to be tested at once, a 16 channel multiplexer (HEF4067B) is fitted to the system. The outputs of the multiplexer are connected to the backpanel with eight way screw terminals. The screw terminals used where not supplied with a necessary plug required for making the internal connection to the multiplexer. As the sockets are a 5.08mm pitch, spare round pins were fitted to the sockets and soldered to every other track of 2.54mm pitch stripboard, thereby making a removable connector. fig.10 Rear terminals and fabricated removable connector The terminals are fitted to the back-panel using M2.5 screws, nuts and several washers to ensure the terminals are not obscured by the lip of the ABS case. To measure the voltage drop just across the resistor being tested and second demultiplexer is required. fig.11 Measuring voltage across an unknown resistor using only a mux, and a mux/demux combination The figure above shows how the system was originally set up to measure the voltage drop at the current source before the multiplexer (left). The multiplexer has an approximate ON 14 resistance of 60Ω [22], so in the first set up, the op-amp will measure the voltage drop across both the multiplexer and the resistor; this would be a problem if the unknown resistor is a low value compared to the multiplexer. In the second example (right), the voltage is measured at the unknown resistor through a demultiplexer; the current draw by the op-amp is extremely low (max 100pA) so the 60Ω internal resistance of the demultiplexer does not affect the voltage reading. The demultiplexer is connected to the multiplexer by mounting it directly above, and using long, 2.54mm pitch pin and socket connectors. fig.12 16 Channel Multiplexers shown on separate stripboard and fitted stacked together There was an issue with the multiplexer/demultiplexer module when first used in an experimental run, that when it was turned on it drew far too much current. This was found to be caused by a barely visible hair-thin piece of copper stripboard track still joining the common input and +15V rail together; this shows how much care and attention needs to paid when working with the stripboard. 3.11 Level Changers The PIC32MX340-512 has digital inputs and outputs that work at the 3.3V TTL level. This voltage is sometimes sufficient to control +5V CMOS ICs, but most of the modules in the system use a +15V supply, and as such require a high voltage control signal. The system uses two hex level shifters (CD4504B), one for the current source module and the other for the multiplexer/demultiplexer module; this raises the 3.3V digital outputs to a suitable +15V. 15 fig.13 4504B Level Changers fig.14 The Enclosure showing all of the hardware modules mounted and fitted fig.15 The fully assembled enclosure 16 4. Software Design The BV513 is supplied with PIC32-Basic, which is a variant of interpreted BASIC running on a 32bit microcontroller. It is purpose written for the environment and can take advantage of the available Flash and RAM. The language works via a simple terminal emulator, so no specialist software needs installing, and the software is all contained on the Microcontroller. All that is required to interface with the MCU is the terminal emulator (BV-Com.exe) and the USB FTDI driver. Functions and programs can be typed directly into the console, executed and saved; however this is cumbersome particularly if any mistakes are made or code needs to be rewritten. A more effective method is to write the entire program in a text editor such as PSPad (or notepad), save as a „.bas‟ file, and use the command „tload‟ at the terminal console to copy the program to the MCU memory. The following chapter describes how the code works and was written, built-in commands are written in bold and explicitly called commands; functions that have been written by me are also written in bold and explicitly called functions. Footnotes are also used in this section; they are not directly relevant for this report but would be useful for somebody continuing development on the system. 4.1 Reading from an ADC To function as a data-logging system the MCU needs to be able to read voltage from the ADCs, use and or store the value. To take an ADC reading, the ADC channel needs to be opened, this is achieved using the command „openadc<sample><list of inputs>‟i. The command „adc(<channel>)„ will return the value of the ADC channel entered in the parenthesis. The ADC has a resolution of 10 bits, so the value returned by the function is a number from 0 to 1023 and corresponds to a voltage between 0V and 3.3V. The voltage on the first ADC channel can therefore be displayed to the console by using the following example code:ii i <sample> is between 1 to 31, with 1 being approximately 1.5µs and <list of inputs> is a list of the channels to be opened separated by commas e.g. openadc 10 0,1,2,8 ii Most variables do not need to be defined (with the ‟dim„ statement) prior to use in PIC32-Basic; with the exceptions of arrays, and variables used in branches or loops, e.g. for j=1 to 10 etc. The type of variable may be defined by following with a symbol e.g. „a$‟ is a string, „a#‟ is a floating point ,‟a&‟ is a character, „a%‟ is an unsigned integer and „a‟ is an integer 17 openadc 31 0 a=adc(0)*3.3/1023 print a 4.2 Taking a Temperature Reading The AD595AQ gives a voltage output of 10mVoC-1 and is connected to a voltage divider giving VOUT = 0.22VIN so the actual response will be 2.2mVoC-1. With the AD595AQ connected and using the same code as before with the additional voltage temperature response, a temperature reading can be taken. print adc(0)*3.3/(1023*0.0022) To ensure the readings are accurate, a program to calculate the voltage-temperature response manually from a known temperature source and save the result has also been written [calibrat.bas]. 4.3 Writing to a File The system can make measurements but also needs to store them; this is done by writing a file to the SD card and saving strings inside the file (a string in this case being a collection of ASCII characters). A file is opened for reading or writing using command ‟openfile(<filename><mode>)‟, and has an associated integer file number between 1 and 4 (i.e. four files may be open at once) e.g.iii F openfile(“test.dat”,‟w‟) Strings can be written with command ‟write$ <fn>[;start] <string>‟, and read with command „read$(<fn>,<max>)‟, the following shows how to save and retrieve a string:iv „w‟ indicates the file is to be written to, and could also be „r‟ for read, or „a‟ for amend. „F‟ will contain the file number <fn>. It is also important to close the file once it is no longer needed, particularly when it has been written to otherwise the contents may not be updated and the file corrupted. iv iii. [;start] allows the string to be written at a given offset from the start of the file; <max> is the maximum number of characters to read and can be an integer or the word „max‟. iii 18 fn openfile(“test.dat”,‟w‟) fn openfile(“test.dat”,‟r‟) a$ ”Hello World” a$=read$(fn,max) write$ fn a$ print a$ closefile fn closefile fn 4.4 Data Formatting To work as a data-logger the system needs to take readings at regular intervals and store them in an easily understandable, accessible manner. Using the „write$’ command continues writing one string after another, for example, if three readings like „23.3‟, „27.2‟ and „35.6‟ are stored using „write$’, the result using „read$’ or opening the file on a PC will be „23.327.235.6‟, which is not particularly useful. To make the data file a little easier to digest, the file can be formatted using non-visible ASCII characters and the „write$’ command. ASCII character constants can be assigned to a string using „*‟ e.g. a$ ”ABC”+*0x44+*0x45+*0x46 would make a$ ”ABCDEF”. Horizontal tab (*0x09) is used to separate multiple readings and their respective times, and the combination of „carriage return (CR)‟ (*0x0d) and „line feed (LF)‟ (*0x0a) is used to create a new line in the text file. This allows the data to be arranged in clear columns and rows when it is opened in a text editor, and is suitably formatted for opening in a spreadsheet program such as excel.v 4.5 Data Management The data management program [data.bas] collates the useful functions that have been written that are relevant to writing files, so that they can easily be used with other programs on the device. The „datalogcheck’ function will first look to see if the “data.cfg” file exists, this normally contains an integer detailing what the last data file number was. If the file does not exist, the function proceeds to check through the file names “data<XXXX>.dat” where <XXXX> is an integer up to 1000, to see if any data files exist. If data files do exist an error v PIC32-Basic has some undocumented eccentricities, if a character constant is the first part of a string to be written, it needs to be preceded with “”, i.e. a string of nothing, otherwise it won‟t work. Also the carriage return, line feed constants MUST be entered in that order, or the formatting will not work. Horizontal tabs were used as they make the data easy to read when opened in a text editor; comma separated variables may be used by replacing *0x09 with *0x2C 19 message is given and the user is prompted to check the disk. If no data files exist, the “data.cfg” file is created and set to one. After using the „datalogcheck’ function, the „newfile’ function may be used. The “data.cfg” file is opened, the integer is read, increased by one, and the file closed; the program then creates a file called “data<XXXX>.dat”, leaves it open and uses the command „keep’ to leave the file number available in the RAM. „resetlog’ will set the “data.cfg” file back to one. The MCU is equipped with a real-time clock and date, however if the MCU power supply is turned off, the time and date are lost and reset to spurious values. The main data-logging program uses the real-time clock as a timer, so the function „resetclock‟ sets the clock to 00:00:00, after which the clock continues counting as normal. The st function writes a combination of strings to the currently open data file (e.g. data5.dat); firstly a new line using the CR LF character constants, the number of days into the data run and finally the time. The‟ srTEMP(<temp>)’ function will write to the current data file, a horizontal tab, and a temperature reading to one decimal place. The „srVOLT(<volt>)’ function will write to the current data file, a horizontal tab, and a voltage reading to three decimal places. The „timeconvert(<timestring>)’ function will take a standard time in string format (such as the one given by the system clock e.g. 10:24:41) and return a result in seconds (e.g. 37481), which is useful for long term scheduling. 4.6 Parameters Also included in the data management program are a set of functions written to store and find named „parameters‟ on SD that may be of relevance to one or more programs. „paramopen’ opens the file “config.cfg” where all the parameters are kept. „paramclose’ will write the string “END” and close the “config.cfg” file. „paramstore(<name>,<value>)’ will write the name of the parameter, an „ ‟ character, the parameter value and a horizontal tab. Originally the parameters had to be called in the exact order they were stored, and the function to call them was very sensitive to any unexpected events (e.g. one more named parameter than expected, or one more character than expected). To solve this, a more robust function „callparam(<name>)’ was written, it will open the “config.cfg” file, search for the parameter <name> and return a value of any length. To change a parameter 20 „changeparam(<name>,<value>)‟ will search the “config.cfg” file and alter the stored parameter value without having to call every value and rewrite the filevi. 4.7 Program and Memory Hierarchy Programs on the BV513 are loaded to and executed in the RAM; many programs can be stored on the SD card, but the program memory available in the RAM is limited to approximately 18KiB, as 14KiB is used by the Micro-Bos and system [23]. This means that space can run out quickly, especially considering that the data management program alone takes up almost 6KiB. Fortunately, functions can be permanently saved to the flash memory and each one called only when required, so space in the RAM is not wasted holding the code. All the critical functions are stored in the flash and small individual programs are stored on the SD card; they call each other with the command „run <program filename>‟ which clears the RAM before loading the new program.vii 4.8 LCD The LCD works via the I2C interface, which needs to first be opened using the command „i2copen <speed>‟ where <speed> is in Hz (the BV4512 works at a maximum 400KHz). Commands are sent using the command „i2cwrite <address> <value>‟, where <address> is the device address (0x42), and <value> is a byte. The program to run the LCD and its functions is stored in the flash, and calling it opens the I2C channel and sets the LCD address. Functions written for the LCD include vi The total length of all the parameters is currently limited to 256 bytes, this can be extended, or the code could be redesigned to allow a parameter file of any length vii The MCU can be made to begin running programs without the aid of the PC by including a file in the root directory of the SD card called “auto.bas”. For a program to run immediately when it is called, it must have a function somewhere in it with the same name as the program filename. The hardware chapter explains that a second SD card is included in the system enclosure. The built-in microSD card is mounted as „a:‟ and the external SD as „b:‟. 21 Lcd Open I2C and check device address Lcdcls Clear LCD display and reset cursor lcdc(<char>) Put character to LCD lcdic(<char>) Put inverted character to LCD lcds(<string>) Print string to LCD lcdis(<string>) Print inverted string to LCD lcdlp(<line>,<pos>) Set cursor line and position lcdhline(<x>,<y>,<length>) Draw horizontal line lcdvline(<x>,<y>,<length>) Draw vertical line lcdnbox(<x>,<y>,<xlength>,<ylength>) Draw unfilled rectangle lcdfbox(<x>,<y>,<xlength>,<ylength>) Draw filled rectangle fig.16 Table of composed LCD functions:viii 4.9 Keypad The keypad also works on the I2C interface at a different address to the LCD. The „keypad’ function is similar to the „lcd‟ function, opening the I2C channel and checking the device address (0x62). The keypad must also have commands read from it and this done using the „i2cread <address> <value>‟, where <value> must be a one dimensional array, even if only one byte is expected. The keypad was originally set-up using the scheduling feature of the MCU; however, there were issues with the holding of variables inside scheduled functions, so the following functions are only called when an input is expected. The keypad has a 16 key buffer, so the keypad is first asked how many keys exist in the buffer, if it is more than 0 the keys are read and saved in an array. viii The LCD has 8 lines and 21 positions available for ASCII characters. <line> is a value from 0 to 7, with 0 being the top line. <pos> is a value from 0 to 20, with 0 being the leftmost position. <x> is 0 to 127 and <y> is 0 to 63. 22 keypad Open I2C channel and test device address keycheck Find out how many keys are in the buffer keyread Read those keys from the buffer kget Wait for input and give it as a result (useful for user menus) kgetmul#(<size>) Wait for a number of <size> digits, also accepting a decimal point, give it as a result, and print each character to the LCD (so the user can verify the input) fig.17 Table of keypad functions 4.10 Multiplexer and Current Source The 16 channel multiplexer and the dual four channel multiplexer are controlled via the digital outputs of the MCU. The output ports are set using the „setport <port> as <I/O>‟ command, where <port> is the port name, and <I/0> is either the word „input‟ or „output‟. The channel is then selected by converting the decimal number to the individual digits of a binary number, which are used to set the output port values. 4.11 Main Data Logging Program The main data-logging program [readstar.bas] works as the focal point for all the previously written functions. The program first checks if the settings file [config.cfg] exists, if it doesn‟t, the program displays an error message; if the settings file is present, all the parameters (i.e. the experiment length, measurement interval, number of multiplexer channels and thermocouple calibration) are called and saved to the RAM. The real-time clock is used to schedule the reading interval by converting it to a time in seconds, and checking when the next reading should be (rather than using the built-in scheduling process, which as previously mentioned is a bit buggy). Column titles are written at the beginning of the file, so it is clear what data is being stored. If a reading is taken from one of the ADCs, a conversion to temperature is made for channels 1 and 2, whilst the others are stored as a raw voltage, or as a calculated resistance. The program also checks if the user has pressed the „#‟ key, which will prematurely end the data-logging run, save the data file, and return to the main menu.ix ix There were some initial issues with the main data-logging program consistently running out of memory after eight minutes of a data run. This was due to a ‘dim‟ statement located within a loop, and was found using the ‘adr()’ command to show where all the variables were being kept in the memory. 23 Before data-logging begins, the voltage is read at each multiplexer channel due to be used with the current sources OFF. If the multiplexer channel is properly connected to a resistive load connected to ground, the reading should be 0V. If the connection is not present, the op amp be floating, and in this circuit will tend to rise toward the positive rail. If the ADC reading is significantly more than 0V the LCD displays an error message telling the user to check the appropriate channel connection. After this the current source for each channel is chosen, firstly by selecting the highest current ON and reading the voltage across the channel. If the voltage is near the maximum measurable value (usually within 0.8V of the 15V rail) a lower current source is selected and measured. The process is repeated until the voltage falls within the measurable range and the selection is stored to memory. 5. Results and Discussion Each of the modules made for the system were individually tested both at the breadboard and stripboard stages. However assembling the entire system and getting all the modules to work in unison did prove to be challenging. As such there was limited time to fully verify the performance of the system, but this chapter aims to give some insight into how it behaves. 5.1 Resistance Measurements 5.1.1 Current Source Ramp Time A perfect current source would have a discontinuous jump between the OFF and ON states. Such perfect sources do not exist, so it takes a measurable amount of time for the charge to build; if the charge builds very quickly there may also be some overshoot from the target current. The following charts are taken directly from a digital oscilloscope and show how the voltage ramps up for each of the current sources. The loads for each of the current sources where chosen using a resistance box, such that the voltage would be approximately at the halfway point of the data-loggers measurable voltage range (0V to +1.5V on the 10x Gain setup). 24 5mA source with 155Ω Load 800 1000 600 800 Millivolts Millivolts 10mA Current Source with 62Ω Load 400 200 600 400 200 0 0 0 0.5 1 1.5 2 2.5 0 1 Microseconds 3 Microseconds 1mA Current Source with 620Ω Load 0.5mA Current Source , 1.56KΩ Load 800 1000 600 800 Millivolts Millivolts 2 400 200 600 400 200 0 0 0 1 2 3 4 5 0 Microseconds 2 4 6 Microseconds fig.18 LM334 current source ramp-time graphs At first glance the response looks fairly erratic at the different current levels; however this is consistent with the behaviour documented in the LM334 datasheet [19]. The voltage reaches a stable level in no more than 5µs, so for many data-logging applications almost no allowance needs to be made in the code for the ramp time. The delay between activating the current source and taking a measurement is included in the user options. At the time of writing the second set of current sources (2µA to 2000µA) is not functioning, so their respective ramp time graphs could not also be included. The wiring for these sources is no different from the working sources bar the RSET resistors, so the problem is likely due to stray wire, bad solder joint or faulty IC as they have been observed working within the last few weeks running up to this report. 25 5.1.2 Measurement Stability The device was tested to verify that the measurements made were not subject to drift over an experimental run. This was achieved by using various passive components of fixed value, so the voltage readings on each channel should stay constant over the entire run. Resistors were used that fell below, in the middle of, and above the observable range of the device. A 2.2µF capacitive load was also included, and two RC circuits where the resistor and capacitor were in parallel. The RC circuits where chosen such that the time constant τ would be very small compared to the measurement delay for one circuit (i.e. between the current source switching ON and the ADC readout), and approximately the same as the measurement delay for the other circuit. What is expected is the small τ circuit should rise toward the maximum voltage quickly, and the large τ circuit will only rise to a certain voltage in-between the minimum and maximum given by. (4) (5) The interval between separate measurements is large compared to both time constants, so both RC circuits should discharge to a very low level in between readings. The following test ran overnight for nine hours, with a five minute interval and 2.5 second delay between current switch ON and measurement. Measurement Stability Test over 9 hours Voltage (Volts) 1.6 1.4 1MΩ (10mA) 1.2 1KΩ (1mA) 100Ω (10mA) 1 68Ω (10mA) 0.8 33Ω (10mA) 0.6 10Ω (10mA) 0.4 0.56Ω (10mA) 0.2 2.2µF (10mA) 0 2.2µF + 1MΩ (1mA) 0 1 2 3 4 5 6 7 8 9 2.2µF + 1KΩ (10mA) Time (Hours) fig.19 ADC read-outs for ten passive components connected to constant current sources over 9 hours 26 The chart shows the voltage readings are for the most part fairly stable, with the exception of the voltages at the top of the measurable range. A voltage reading at the top of the measurement range indicates the resistance is too high to read or an open circuit; the value that it will reach is determined by the op amp which swings within approximately 0.5V of the positive rail [21]. The op-amp is not particularly accurate at the limit of its range, so the fluctuations at high voltage seen in the first few hours are not cause for too much concern; though there is a small change in some of the other channels so it was worth investigating further. After replacing the AC/DC adaptor (which is discussed in more detail later) another measurement stability test was taken over a period of 45 hours, with a 15 minute interval and 2.5 second delay. Measurement Stability Test over 45 Hours with new AC/DC adaptor 1.6 1.4 1MΩ (10mA) Voltage (Volts) 1.2 1KΩ (1mA) 100Ω (10mA) 1 68Ω (10mA) 0.8 33Ω (10mA) 0.6 10Ω (10mA) 0.4 0.56Ω (10mA) 0.2 2.2µF (10mA) 2.2µF + 1MΩ (1mA) 0 0 5 10 15 20 25 30 35 40 45 2.2µF + 1KΩ (10mA) Time (Hours) fig.20 ADC read-outs for ten passive components connected to constant current sources over 45 hours This chart shows a significant improvement in the voltage measurement stability, giving confirmation that the original AC/DC adaptor was of inferior quality. The voltages for both charts are consistent with what would be expected for the current source / load combinations. The capacitive load measurements for both charts are also consistent with what was expected, the purely capacitive maintained high voltage as did the low τ, 2.2µF + 1KΩ circuit. The high τ, 2.2µF + 1MΩ circuit was also close to the expected value of +1.02V [Appendix: Calculation 6], and 27 very consistent. Although the data-logger will function with capacitive loads, the automatic current selection is programmed to check for loads that reach the maximum voltage within the delay time; hence the automatic current selection is not ideal for capacitive loads. The automatic current selector could be made more robust by making several voltage measurements over a certain period, and check to see if it is constant or changing. The data logger automatically selected 10mA for the 1MΩ as the resistance was well outside the measurable range, and used it by default as the current source. A feature could be added to the code to alert the user if the preliminary test detects an out of range resistor, or automatically decide not to measure the channel. 5.1.3 Calculated Resistance The device is capable of taking a voltage measurement across a resistor and calculating the resistance by using a saved measurement of the constant current level. The following is a chart to show how much the calculated resistances from the device differ from a set of known resistances of 1% tolerance. Relative Error of Measured Resistance Against True Resistance 3 Relative Error(%) 2 1 0 0 50 100 150 200 250 300 350 -1 -2 -3 True Resistance (Ω) fig.21 Plot to show resistance calculation accuracy for a set of known resistors It should be noted that the multiplexer channels have a ΔRON resistance of up to 5Ω [22], so each multiplexer channel needs to be calibrated independently to give an accurate resistance reading, but there was not sufficient time to do this. This chart does not cover the whole 28 range of measurable resistances for this particular set-up (10Ω to 2.8KΩ), and is only intended to give an approximate indication of the accuracy that may be expected from the device. 5.2 Temperature Measurements The following also shows the thermocouple read out over the same nine hour and 45 hour runs as the measurement stability tests. Temperature Measurement over Nine Hours 25 Temperature (Celsius) 24 23 22 21 20 19 18 17 0 1 2 3 4 5 6 7 8 Time (Hours) fig.22 Chart to show thermocouple temperature measurement over 9 hours 29 9 Temperature Measurement over 45 Hours 27.0 Temperature (Celsius) 26.0 25.0 24.0 23.0 22.0 21.0 20.0 0 5 10 15 20 25 30 35 40 45 Time (Hours) fig.22 Chart to show thermocouple temperature measurement over 9 hours The signal does appear a bit noisy, but it should be appreciated that type K thermocouples are not particularly well suited for accurate room temperature measurements, and the relative error in a measurement is much better at higher temperatures. 5.3 Further Discussion 5.3.1 Long Data Runs The device is expected to be used on experimental runs of the order of days, so several experiments were set to run for 24 hours and over. Two 24 hours experimental runs where set off on the 300mA AC/DC adaptor, however there was noticeable change in the screen contrast when taking readings, and the system froze after 30 minutes and also 5 hours. The device only draws a maximum 210mA so the AC/DC adaptor should have no issue providing this. Yet the issue was repeatable and switching to USB or a laboratory supply alleviated the issues with the screen, and the following two 24 hour runs were a success. The device was then set to run for 48 hours, however after 24 hours the device continued running, but not taking measurements and storing them to the SD card. It was noticed that the LCD day counter was not turning over when passing the 24 hour mark; this was due to a bug 30 in the main data-logging program. The bug was an unsigned integer used to mark when the next reading was due „NEXTTIME%‟, however the part of the code used to count the days used the variable „NEXTTIME‟. This made the program never pass the first day mark and loop continuously for the first 24 hours, not expecting another reading to be taken until that 24 hours had passed. This was fixed by setting all of the variables to the correct unsigned integer format, and adding a new day turnover variable that activates when the clock string is equal to 23:59:59. The program has been verified to work past one day by setting the clock start to 23:59:30, and observing the behaviour of the device. The device was then set to run for up to 3 days and was still successfully running at 45 hours, after which the experimental run was selected to end prematurely so the data could be collected and have time to be analysed. 5.3.2 AC/DC Power Supply The original AC/DC adaptor caused many problems with the screen contrast, interference and system crashes. The rating for the adaptor was a 300mA output at +5V, which should easily meet the requirements of the device (max 210mA). The problem was repeatable with the adaptor; but was completely absent when using either a laboratory power supply current limited to 300mA, or USB power. Another AC/DC adaptor was subsequently found in the lab rated for 1A at +5V; the issues were also absent when using this power source so it can be safely concluded that the original adaptor was faulty, or not built to the stated specifications. 5.3.3 Battery Power Battery power was considered as an option to make the data-logger more portable. The entire system draws between 800mW to 1050mW with a backlit LCD, or between 600mW to 850mW unlit. The relatively large swing in power consumption arises when the current source is in use. A large capacity AA size battery can be expected to deliver up to 2.85Ah of charge at 1.2V [24], so at least four batteries are required to deliver enough voltage. Larger batteries are also available, but to achieve the necessary voltage requires a set of batteries or single battery approaching the size of the data-logger, so this detracts somewhat from the portability argument. So in a situation where the power consumption is at its lowest (Unlit LCD and large reading interval, so the spikes in power draw are negligible), with 600mW of power draw at 5V and 31 four 2.85Ah batteries, we would expect a maximum run time of 22 hours [Appendix: Calculation 7]. This is a reasonable amount of time, but a lot of the data acquisition is expected to be over longer periods than this. The data-logger is expected to be near a mains power socket most of the time, so battery power is not currently a pressing issue. Should battery power later be required it is recommended that either a high voltage (up to 10V, as the MCU has a regulator allowing supplies between 5V to 10V) battery, or a DC converter is used to account for the voltage drop seen when the battery is low on charge. 6. Conclusion and Further Work Although there has not been enough time to fully test and debug the device, I am confident that it is well suited to the original aims of the project, and suitable for other applications in the department. In summary, the device has been verified to take temperature measurements from multiple thermocouples covering a range of 0˚C to 1250˚C, and measure voltages between 0V to +15V with a variable gain to improve accuracy at lower voltage levels. It can also use a selection of constant current sources to measure a range of resistances (currently set up for between 10Ω and 2.8KΩ). The appropriate current level is automatically selected so the voltage across the unknown resistance is within the measurable range, and the resistance value is stored. The device functions correctly when connected to a load with significant capacitance and is also capable of monitoring multiple loads with a 16 channel multiplexer. The measurements are taken at regular intervals, adjustable from 1s to 23h59m59s and the results stored to an SD card in a data format that is compatible with almost any modern PC. The user interface is clear and concise, with a fair amount of error checking; so a user that is unfamiliar with the device should be able set it up and collect data with relative ease. The hardware and software design is very modular so it can easily be adapted to new experiments and interface with other equipment. There are still eight digital input / outputs, 13 ADC channels, I2C interface and serial interface available, so there is plenty of scope for further expansion of the system. The following suggests some future work, more considerable than the fine-tuning of hardware and software mentioned throughout this report. 32 6.1 Humidity Sensor Some processes in the IDG laboratory are dependent on the humidity in the air; the HIH4000-002 is a small SIP IC that gives a linear voltage output against relative humidity. Two of these ICs were ordered but they were not interfaced with MCU as other modules in the project had a higher priority. Interfacing should be a simple case of a connecting to an ADC channel with a resistive divider and minor addition the program code. 6.2 Profilometer The profilometer can communicate over RS232 serial connection with options to set the speed, parity and stop bits. This protocol is compatible with the MCU, but the RS232 interface requires a negative voltage swing of at least -3V so an additional hardware module would need to be made to facilitate this. The PIC32-Basic system also allows for „plug-ins‟ to be written in C and run above the operating system and make the code run more efficiently [26] ; this would be necessary if a large amount of data is expected to be read from the profilometer. 6.3 Real-Time Clock Backup The MCU has a real-time clock and date, but these are reset to spurious values when the power is turned off. A useful feature would be to keep the RTC running when not connected to mains or USB power. This would allow the data files to be correctly time-stamped, and for absolute time readings to be used with each measurement. To do this a BV4236 Real Time Clock & Temperature Sensor could be added to the system. This module works over the I2C interface and uses a cell battery to power its own RTC which is always on [25]. The module also has a programmable alarm, so features such as delayed start from standby could also be implemented or even put the device in standby in between readings, significantly reducing the overall power consumption. 33 References [1] PicoLog 1000 Series - http://www.picotech.com/multi-channel-daq.html [2] National Instruments NI USB-6008 - http://sine.ni.com/nips/cds/view/p/lang/en/nid/14604 [3] Datataker DT80 - http://www.bellflowsystems.co.uk/grant-data-taker-dt80-complete-data-loggingkit.html [4] S. Heath (2003). Embedded systems design. EDN series for design engineers (2nd ed). pg.11-12 Newnes. ISBN 9780750655460. [5] "Technical Notes: Thermocouple Accuracy". IEC 584-2(1982)+A1(1989) http://www.microlink.co.uk/tctable.html [6] Manual on the Use of Thermocouples in Temperature Measurements. ASTM, 1974 [7] K. Bull Catching the Drift. - http://www.veriteq.com/download/whitepaper/catching-the-drift.pdf [8] MicroDrive SD Module - http://www.saelig.com/product/ST001.htm [9] DOSonCHIP FAT16/32 IC http://www.coolcomponents.co.uk/catalog/product_info.php?cPath=27&products_id=101 [10] Amtel ATMega32 - http://www.futurlec.com/Atmel/ATMEGA32.shtml [11] AVR Development Board http://robokits.co.in/shop/index.php?main_page=product_info&products_id=14 [12] ATMega32 Development Board - http://www.active-robots.com/products/controllr/m32db.shtml [13] PIC18F4550 - http://www.microchip.com/wwwproducts/Devices.aspx?dDocName=en010300 [14] PIC-USB-4550 Development Board http://www.coolcomponents.co.uk/catalog/product_info.php?products_id=87 [15] PIC32MX340-512 - http://www.pic32.byvac.com/bv513_specs.php [16] ByVac BV513 PIC32 Development - Board http://www.byvac.co.uk/mi_bv513.php [17] W. Erickson, D. Maksimović. (2001) Fundamentals of power electronics (2nd ed) pg 23-31 Springer ISBN 0471429082 [18] Maxim MAX773 DC DC Converter Datasheet – pg. 2-3,11,16 [19] National Semiconductor LM334 Adjustable Current Source Datasheet – pg. 1,4-5 [20] Motorola 4052 Dual 4 Channel Multiplexer Datasheet – pg. 4 [21] Analog Devices OP97 Operational Amplifier Datasheet – pg.1 [22] Phillips HEF4067 16 Channel Multiplexer Datasheet – pg. 5 [23] ByVac PIC32 Internals - http://www.pic32.byvac.com/pic32_internals.php#speed [24] Farnell AA battery - http://uk.farnell.com/ansmann/5035201/battery-rechargeable-nimhaa/dp/1453781 [25] RTC Backup - http://www.byvac.co.uk/in_rtc.php [26] PIC32-Basic Plug-in Introduction - http://www.pic32.byvac.com/ar_plugin.html.php 34 Appendices (I) Calculations 1.) Accuracy required for thermocouple: 1.5˚C / 1250˚C = 0.12% ln(1 / 1.2E-3) / ln(2) = 9.70 so 10 bits are required Accuracy measurement for RH does not need to exceed 1% ln(1 / 0.01) / ln(2) = 6.64 so 8 bits are required 2.) VOUT = (15V x 1.1KΩ) / (3.9KΩ 1.1KΩ) = 3.3V 3.) Using the time of 2µs, and the current limit trip level of 200mV / RSENSE stipulated in the datasheet, with a 5V input: L ≥ (5V x 2µs) / (200mV / (560mΩ x 2)) = 56µH 4.) Using: so 100µH is sufficient given by the LM334 datasheet ISET RSET E-12 Series 10 mA 6.81 Ω 6.8 Ω 5 mA 13.6 Ω 13 Ω 1 mA 68.1 Ω 68 Ω 0.5 mA 136 Ω 130 Ω 2000 µA 34.0 Ω 33 Ω 200 µA 340 Ω 330 Ω 20 µA 3.40 KΩ 3.3 KΩ 2 µA 34.0 KΩ 33 KΩ The E-12 series is a standardised set of resistor values that allows a resistor within 10% of the specified value to be selected. Accuracy higher than this is not usually required as most resistors are made to a fairly loose tolerance. 35 5.) Using a minimum voltage measurement of 1V and a maximum 14V and a gain of 10, the device should be able to measure a total resistance in the ranges: 1V / (10 x 10mA) = 10Ω to 14V / (10 x 0.1mA) = 2.8KΩ And 1V / (10 x 2000µA) = 50Ω to 14V / (10 x 20µA) = 70KΩ Note: 20µA was used as the lower current limit as it was realised that at 2µA there is likely to be a significant contribution from Johnson noise, and quantisation error. Even 20µA would likely require more thorough grounding of all the modules in the circuit. 6.) (15V / Gain 10) x (1-e^(-2.5s/(2.2µF x 1MΩ))) = 1.019V 7.) 2.85Ah x 1.2V x 4 / 600mW = 22.8h 36 II) User Guide i) Getting Started Setting up the device to take readings is very simple provided it is set up correctly. I will firstly explain how the correctly set up device works; then progressively explain how the hardware and software is structured so the user can understand how the device is set up. For in depth detail on how to develop code to use the MCU, the ByVac PIC32-Basic website (http://www.pic32.byvac.com/downloads.php) has ample detail, with articles on how to use many of the interfaces and features. The device may be run from USB or a DC adaptor; there is a power source select switch on the real panel that also functions as a regular power switch when only one source is connected. The device may take several seconds to power up, after which the splash screen will be displayed and the device will load the main menu. If this does not happen, firstly check the SD card containing the program files is installed in the rear panel. Alternatively sometimes the device does not switch on immediately if it has been powered down for a while; this is likely due to the large initial current draw from the DC converter affecting the MCU start-up. Simply switch the power off then on again, and the device should start normally. ii) Setting up an Experiment The items on the menu are selected with the numerical keypad. The main data-logging program must first have the experimental settings entered before it can be run. If no settings file exists (usually only if the SD card has been erased, or the reset configuration option is used) then the data-logging program will display an error message prompting the settings to 37 be entered; if the file does exist, the main program will use the last settings entered. To enter new experimental settings, select option 3. This program will firstly display the current settings if they exist, the user is then asked whether they wish to keep the current settings or enter new ones. Some of the options have a range of values with a variable amount of digits, so the „#‟ key acts as an enter key if required. The bottom line of the screen displays tips on what values the program is expecting, and if the user enters an invalid setting (e.g. 3 temperature channels, or 18 mux channels) the bottom line explains what valid entries are available. After entering all the new settings, they are displayed for several seconds and the device returns to the main menu. Parameter Description Duration Total experiment length (Maximum 99 days, 23hours, 59 mins and 59secs) Interval Time between measurements (Maximum 23hours, 59 mins and 59secs) Temp Chn How many thermocouple channels to use (Maximum 2) MUX Chn How many multiplexer channels to use (Maximum 16) Volt/Res Save either a voltage reading or calculated resistance from the multiplexer channel (0 for Voltage, 1 for Resistance) Pause Time between the current source switch ON and taking the measurement (Maximum 9999ms) 38 iii) Calibrating the Thermocouple As mentioned in the main report, the thermocouple amplifier gives a linear voltage to temperature response, expected to be 2.2mV/˚C. To be absolutely sure that this is correct, there is the thermocouple calibration program which calculates the true response from a known temperature source (boiling water is usually convenient and accurate). Any existing settings are firstly displayed and the user is asked whether or not to overwrite them. The program then asks for the temperature of the known sources and then proceeds to measure the voltage response 1280 times over a period of about seven seconds, displaying a progress bar on the bottom of the screen (1280 was a convenient number to combine the 128 pixel progress bar with a large number of readings). The results of the calibration are then displayed and the user is asked once more if they want to replace the existing settings, after which the device returns to the main menu. iv) Running an Experiment Once the experimental settings have bet set up and the thermocouples are calibrated, the user may now begin the main data-logging program. Firstly the SD card is checked for the [data.cfg] file, which contains the number of the last data file created. If it does not exist the card is checked for existing data files to make sure nothing is accidently overwritten. If files do exist the user is told to check the card; otherwise the [data.cfg] file is created and set to 1. 39 The program reads the file number in the [data.cfg] file, increases it by one, updates the file and closes it. The new number is then used to create a [dataXXXX.dat] file, where XXXX is the file number, and the file name is held in the RAM. Every time a reading is taken, the program opens the [dataXXXX.dat] file for amendment, saves the time, saves all the relevant readings, starts a new line, then closes the file until the next reading is taken. This reduces the likelihood of the SD card being corrupted if the device should crash for any reason. The experimental set up is then checked. Any multiplexer channels being used should be connected to a resistor which should in turn be connected to ground. This means the ADC reading for that channel should be 0V or at least very close to it. If the channel is not connected properly, the op-amp will naturally rise toward the positive rail, so the ADC reading will be near maximum (+3.3V). The program checks for this, and if any of the active channels are significantly above 0V, the user is told to check the connection of the relevant channel. If the experimental set up is tested as correct, the appropriate current source is selected for each channel. The highest current source is used first; if the voltage reading is too high to be meaningful, a lower current source it selected until the voltage is in the measurable range. The number of the current source used for each channel is saved to memory, and saved at the beginning of the data file. All the preliminary features of the main data-logging program are finished, and the device begins taking and saving readings. The experimental duration and the elapsed time are both displayed at the bottom of the screen, and the most recent temperature readings are displayed 40 if the any of the thermocouples are being used. When a reading is being taken, this is also displayed on the screenx. The program also allows the user to end the experiment prematurely by pressing the „#‟ key twice. v) Plotter Beta This is a program that was written to test and demonstrate the graphic capabilities of the LCD display. It was anticipated that it may be used to create a real time plot of one of the measurements as an option in the main data-logging program, but for the time being, it just displays a variety of mathematical functions to show what a plot may look like. vi) Interfacing with a PC Alterations can be made to the programs on the SD card, but connecting to the PC is useful as any errors that occur in a new piece of code can quickly be identified through the terminal emulator. x The elapsed time does not update on screen whilst a reading is being taken, but the real-time clock is still running and will update as normal once the device has finished measuring and saving. 41 To interface with a PC all that is required is the terminal emulator [BV-Com.exe] and USB FTDI drivers, both available from the ByVac website. After opening the [BV-Com.exe] program, the Baud rate should be set to 115,200 with 8 data bits and 1 stop bit. Once connected, the MCU should respond with a sign on message and if the main program is installed on the MCU, this will execute automatically. If the main program runs automatically, only to 0-9 „#‟ and „.‟ keys will be available on the keyboard. By selecting option „0‟, the program on the MCU will end, and all the keyboard keys and features of the terminal will be available. vii) Loading Programs Code and programs can be directly typed and executed in the console, but if any mistakes are made the whole code must be rewritten and saved code cannot be edited. It is therefore advisable to type the code in a test editor, save as a [.bas] file and load to the MCU. PSPad is 42 a useful text editor, as it can be easily configured with a syntax colours file that indicates if typed commands are recognised (again available from the website) Programs can be loaded directly to the RAM on the MCU using the load command at the terminal, where the user will then be prompted to select a [.bas] file in explorer.. Programs may also directly uploaded to the SD card using the tload <filename> command, where <filename> is the full destination filename (e.g. readstar.bas). Saved programs may then be run using the run <filename> command; in this case it is not necessary to include the extension, as [.bas] is assumed for a program. If a program is run, the MCU looks for a function with same name as the filename in the code and executes it first. To automatically start a program when the MCU powers on, a file called [auto.bas] may be placed in the root directory of the SD card, or saved to flash viii) Saving to Flash Functions or entire programs may be saved to the 512KiB flash memory. This has the advantage that the code does not need to be held in the RAM when it is not in use, but is still accessible to any program currently running. As such the core parts of the data-logging program are held in the flash, which include, the „data management and multiplexer control‟, „lcd control‟, „keypad control‟ and „splash screen‟. To save code to the flash it is first executed in the RAM. Before the program space is cleared the fsave all command is used; this copies and saves everything in the RAM to the flash memory. ix) Reloading the Entire Data-logging Program All the data-logging program parts are kept in the folder [b:\mainprog], which is opened and the main menu executed by the [auto.bas] file in the root directory. Should any code in the flash need to be changed or re-uploaded, back-ups of the core programs are also stored in this folder. Below is an example of clearing the entire flash with fclear all, and uploading all of the core program parts. 43 The error displayed after running [data.bas] is normal; it arises because there is no function in the program called „data‟. Most of the code I have written for the MCU has notes describing what each section does, so I should be fairly clear to a developer how the code all fits together. As always for more detail on the commands available on the MCU and how to make the most the resources it has, consult the ByVac PIC32-Basic website. 44 (III) Schematics (Schematic 1 – AD595AQ Thermocouple Amplifer) The inputs must be connected to the rear screw terminals using type J or K thermocouple extension wire. Two of these ICs are mounted to a single module to allow two thermocouples to be read at once, the outputs are connected to separate ADC inputs. Pin 1 should be grounded, unless the connected thermocouple is grounded. 45 (Schematic 2 – First DC-DC Converter, MAX773) L1 was originally fitted with a 22µH inductor, and 1 at 100mΩ, however these values were not correct for powering the system. 46 (Schematic 3 – Second DC-DC converter, dual voltage regulator MAX743) 47 (Schematic 4 – Multiplexer, Demultiplexer and Level Changer Modules) The numbered outputs are connected to the unknown resistors, which are then connected to ground 48 (Schematic 5 – Current Sources, Dual Multiplexer and Level Changer) 49 (IV) Program Code Auto.bas function auto if currentcard()<0 then lcd lcdcls a3$=" INSERT SD CARD" lcdlp(3,0) lcds(a3$) print " TERMINAL READY" new else cd b:\mainprog run start endif endf // Calibrat.bas //Calibration function //Take reading at high T, the AD595AQ is designed to give linear temp //response //Default Settings constant MAX_V# 3.3 //Maximum ADC voltage constant BITS# 1024 //No of ADC bits function calibrat lcd keypad lcdcls a=fileexists(calib.cfg) if a=1 then callcalib print "Already Calibrated!" print "Channel 1: "+format$("#.######",V_OVER_ C#) print "Channel 2: "+format$("#.######",V_OVER_ C2#) print "Enter new settings? 1.Yes 0.No " a0$=" CALIBRATION " a2$=" Already Calibrated!" a3$="Channel 1: " a4$="Channel 2: " a7$="Overwrite? 1.Yes 0.No" lcdcls lcdlp(0,0) lcdis(a0$) lcdlp(2,0) lcds(a2$) lcdlp(3,0) lcds(a3$) lcds(format$("#.######",V_OVE R_C#)) lcdlp(4,0) lcds(a4$) lcds(format$("#.######",V_OVE R_C2#)) lcdlp(7,0) lcdis(a7$) MENU=kget if MENU<>1 then run mainmenu endif endif openadc 31 0 openadc 31 1 print "Note: This assumes the AD595AQ gives a linear Voltage/Temp Response" print "and that at 0C the voltage is 0V" a0$=" CALIBRATION " a2$="Enter High Temp Value" a3$="Temp CH1: " lcdcls lcdlp(0,0) lcdis(a0$) lcdlp(2,0) lcds(a2$) lcdlp(3,0) lcds(a3$) //Establish Voltage at high T print "Enter high temperature reading " HIGH_T_INPUT#=kgetmul#(5) a4$="Temp CH2: " lcdlp(4,0) lcds(a4$) HIGH_T_INPUT2#=kgetmul#(5) print "Reading..." HIGH_T#=0 HIGH_T2#=0 dim j for j=1 to 1280 HIGH_T#=HIGH_T#+adc(0) 50 HIGH_T2#=HIGH_T2#+adc(1) wait 5 if mod(j,10)=0 then i2cwrite LCDADR 9 j/10 7 255 endif next HIGH_T#=HIGH_T#*(MAX_V#/ BITS#)/1280 HIGH_T2#=HIGH_T2#*(MAX_ V#/BITS#)/1280 //Calculate V/C response VC#=HIGH_T#/HIGH_T_INPUT # VC2#=HIGH_T2#/HIGH_T_INP UT2# screen$=format$("#.######",VC# ) screen2$=format$("#.######",VC 2#) print "Voltage/Temp Response is CH1: "+screen$ print "Voltage/Temp Response is CH2: "+screen2$ print "Save? 1.Yes 0.No " a5$="V/C CH1: " a6$="V/C CH2: " a7$="Save? 1.Yes 0.No" lcdlp(5,0) lcds(a5$) lcds(screen$) lcdlp(6,0) lcds(a6$) lcds(screen2$) lcdlp(7,0) lcdis(a7$) MENU=kget if MENU=1 then fn=openfile("calib.cfg",'w') write$ fn screen$+" "+screen2$ closefile fn endif run mainmenu endf Data.bas //DATA MANAGEMENT and DIGITAL OUTPUT CONTROL // 16 Channel Mutliplexer Ports constant MA0$ "d1" constant MA1$ "d2" constant MA2$ "d3" constant MA3$ "d4" constant ME0$ "d5" // Dual 4 Channel Current Source Multiplexer Ports constant CA0$ "d10" constant CB0$ "d9" constant CE0$ "d8" //Current data file number check //(Will take a few seconds if data.cfg is missing) //Uses "data.cfg" to keep a log of the last file number used //If "data.cfg" is missing, checks for any data files so nothing //is overwritten accidentally function datalogcheck cd b:\data //Check if config file exists a=fileexists("data.cfg") if a=1 then fn=openfile("data.cfg",'r') FILENUM=read$(fn,5) closefile fn else //See if any data files exist dim j,check for j=1 to 99 a=fileexists("data"+j+".dat") if a=1 then check=j endif //Need to wait briefly otherwise file system crashes wait 1 next //If any files exist check>0 if check=0 then print "No Data found, Creating new Log file" fn=openfile("data.cfg",'w') write$ fn "0" closefile fn else print "WARNING Log file Missing but data exists!" print "Creating new Log starting at last data file found" fn=openfile("data.cfg",'w') write$ fn check closefile fn endif endif endf // Create new data file // Note leaves the file OPEN! // Needs to be closed once youre finished to prevent corruption! function newfile cd b:\data fn=openfile("data.cfg",'r') FILENUM=read$(fn,5) closefile fn fn=openfile("data.cfg",'w') FILENUM=FILENUM+1 write$ fn FILENUM closefile fn fn=openfile("data"+FILENUM+". dat",'w') write$ fn "" closefile fn keep endf //Reset Log File function resetlog cd b:\data input "Reset File Number? Data may be overwritten [y/n] " choice$ if choice$=y then fn=openfile("data.cfg",'w') write$ fn "0" closefile fn endif endf //Reset Clock //Clock always sets itself to an arbitaty value //after power outage function resetclock settime "00:00:0" endf //Write time to data file //notes down the time in the data file, includes CR + LF //Note: ensure DAYS$ is also in use function st 51 fn=openfile("data"+FILENUM+". dat",'a') write$ fn ""+*0x0d+*0x0a+DAYS+*0x3a+t ime$() endf //Write reading to data file //File MUST be OPEN first //Closefile fn if last reading taken //Includes preceding horizontal tab function srTEMP(VALUE#) write$ fn ""+*0x09+format$(###.#,VALUE #) endf function srVOLT(VALUE#) write$ fn ""+*0x09+format$(#.###,VALUE #) endf function srRES(VALUE#) write$ fn ""+*0x09+format$(###.#,VALUE #) endf // 30/01/10 // Call stored parameter // Searches the file for the named parameter PAR$, if the name is found the // variable PARVAL$ will contain all following characters until an "@" is found // note, doesnt like files with CR or LF function callparam(PAR$) parfile=openfile("config.cfg",'r') dim FILESTRING$[:256],STAR,PAR VAL$,END FILESTRING$=read$(parfile,256) closefile parfile STAR=instr(FILESTRING$,PAR $) if STAR=0 then PARVAL$="No parameter by that name" else STAR=STAR+len(PAR$)+1 PARVAL$=mid$(FILESTRING$, STAR,256) END=instr(PARVAL$,*0x09) if (END-1)=len(VAL$) then END=instr(PARVAL$,*0x09) parfile=openfile("config.cfg",'a') write$ parfile;STAR-1 VAL$ closefile parfile else print "Parameter length not the same as original!" endif endif endf PARVAL$=left$(PARVAL$,(EN D-1)) endif dim FILESTRING$[:2]=0 keep endf // Store a parameter function paramopen parfile=openfile("config.cfg",'w') write$ parfile ""+*0x09 keep endf function paramstore(NAME$,VAL$) write$ parfile NAME$+"="+VAL$+*0x09 endf function paramclose write$ parfile "END" closefile parfile endf // 02/02/10 // Find and change parameter // MAKE SURE ITS THE RIGHT LENGTH! function changeparam(PAR$,VAL$) parfile=openfile("config.cfg",'r') dim FILESTRING$[:256],STAR,PAR VAL$,END FILESTRING$=read$(parfile,256) closefile parfile STAR=instr(FILESTRING$,PAR $) if STAR=0 then PARVAL$="No parameter by that name" else STAR=STAR+len(PAR$)+1 PARVAL$=mid$(FILESTRING$, STAR,256) // 14/02/10 Copied from main function to keep available in flash // 20/07/10 Updated for new main reading program //New Call function callsettings callparam(DAYSX) DAYS=PARVAL$ callparam(TOTALTIMEX) TOTALTIME$=PARVAL$ callparam(INTERVALX) INTERVAL$=PARVAL$ TOTALSEC=timeconvert(TOTAL TIME$)+(DAYS*24*60*60) callparam(TEMPCHNX) TEMPCHN=PARVAL$ callparam(RESISCHNX) RESISCHN=PARVAL$ callparam(VOLTRESX) VOLTRES=PARVAL$ callparam(PAUSEX) PAUSE=PARVAL$ keep endf // 01/03/10 Edited calibration function so settings are handled seperatly // to the other settings function callcalib fn=openfile("calib.cfg",'r') V_OVER_C#=read$(fn,8) space$=read$(fn,1) V_OVER_C2#=read$(fn,8) closefile fn keep endf //Convert time string (xx:xx:xx) to time in seconds 52 function timeconvert(TIMESTRING$) HOUR=mid$(TIMESTRING$,1,2 ) MIN=mid$(TIMESTRING$,4,2) SEC=mid$(TIMESTRING$,7,2) result (HOUR*60*60)+(MIN*60)+SEC endf // 20/07/10 Select 16ch MUX channel //select multiplexer port, between 0 and 15 function MUXselect(CHNS) port ME0$ 0 port MA3$ int(CHNS/8) CHNS=mod(CHNS,8) port MA2$ int(CHNS/4) CHNS=mod(CHNS,4) port MA1$ int(CHNS/2) CHNS=mod(CHNS,2) port MA0$ CHNS endf //Current source MUX, 0 to 3 function curMUXselect(CURLEV) port CE0$ 0 port CA0$ int(CURLEV/2) CURLEV=mod(CURLEV,2) port CB0$ CURLEV endf //Inhibit both MUXs function MUXkill port ME0$ 1 port CE0$ 1 endf //Set the digital outputs for the MUX and N-Mos function setoutputs setport MA0$ as output setport MA1$ as output setport MA2$ as output setport MA3$ as output setport ME0$ as output setport CA0$ as output setport CB0$ as output setport CE0$ as output port MA0$ 0 port MA1$ 0 port MA2$ 0 port MA3$ 0 port ME0$ 1 port CA0$ 0 port CB0$ 0 port CE0$ 1 endf // ----------------- DATA MANAGEMENT END ------------------ entercon.bas //Check for, show and enter experimental settings function entercon lcd keypad lcdcls a=fileexists(config.cfg) a0$="EXPERIMATAL SETTINGS" a1$="Duration: " a2$="Interval: " a3$="Temp Chn: " a4$=" MUX Chn: " a5$="Volt/Res: " a6$=" Pause: " a7$="Overwrite? 1.Yes 0.No" MENU=1 if a=1 then callsettings lcdcls lcdlp(0,0) lcdis(a0$) lcdlp(1,0) lcds(a1$) lcds(DAYS) lcdc(58) lcds(TOTALTIME$) lcdlp(2,0) lcds(a2$) a$=" " lcds(a$) lcds(INTERVAL$) lcdlp(3,0) lcds(a3$) lcds(TEMPCHN) lcdlp(4,0) lcds(a4$) lcds(RESISCHN) lcdlp(5,0) lcds(a5$) if VOLTRES=0 then lcds(Volt) else lcds(Res) endif lcdlp(6,0) lcds(a6$) lcds(PAUSE) lcds(ms) lcdlp(7,0) lcdis(a7$) MENU=kget endif //Input new settings if MENU=1 then lcdcls lcdlp(0,0) lcdis(a0$) paramopen a7$=" Format: dd:hh:mm:ss " lcdlp(7,0) lcdis(a7$) lcdlp(1,0) lcds(a1$) //[:3] is used to set the string length to save memory dim DAYS$[:3],HOURS$[:3],MINS$[ :3],SECS$[:3] //First get the days of experimental length DAYS$=kget lcds(DAYS$) DAY$=kget lcds(DAY$) DAYS$=DAYS$+DAY$ lcdc(58) dim j TOTALTIME$="" //This gets the time in the 00:00:00 format for j=1 to 8 select j case 3 lcdc(58) TOTALTIME$=TOTALTIME$+" :" case 6 lcdc(58) TOTALTIME$=TOTALTIME$+" :" default TIME$=kget lcds(TIME$) TOTALTIME$=TOTALTIME$+ TIME$ endselect next paramstore(DAYSX,DAYS$) 53 paramstore(TOTALTIMEX,TOT ALTIME$) //Get interval in seconds 'ss' a7$=" Format: hh:mm:ss " lcdlp(7,0) lcdis(a7$) lcdlp(2,0) lcds(a2$) lcds(a$) INTERVAL$="" for j=1 to 8 select j case 3 lcdc(58) INTERVAL$=INTERVAL$+":" case 6 lcdc(58) INTERVAL$=INTERVAL$+":" default TIME$=kget lcds(TIME$) INTERVAL$=INTERVAL$+TIM E$ endselect next paramstore(INTERVALX,INTER VAL$) //No of temp channels a7$=" No of Temp channels " lcdlp(7,0) lcdis(a7$) lcdlp(3,0) lcds(a3$) j=0 while j=0 TEMPCHN$=kget if TEMPCHN$>2 then a7$=" Must be 0, 1, or 2 " lcdlp(7,0) lcdis(a7$) else lcdlp(3,10) lcds(TEMPCHN$) j=1 endif wend paramstore(TEMPCHNX,TEMPC HN$) //No of resistor channels a7$="Multiplexer Channels " lcdlp(7,0) lcdis(a7$) lcdlp(4,0) lcds(a4$) j=0 while j=0 lcdlp(4,10) RESISCHN=kgetmul#(2) if RESISCHN>16 then a7$=" Must be 0 to 16 " lcdlp(7,0) lcdis(a7$) lcdlp(4,10) lcdc(32) lcdc(32) else lcdlp(4,10) lcds(RESISCHN) j=1 endif wend RESISCHN$=RESISCHN paramstore(RESISCHNX,RESISC HN$) //Set Current Level a7$="Voltage / Resistance" lcdlp(7,0) lcdis(a7$) lcdlp(5,0) lcds(a5$) j=0 while j=0 VOLTRES$=kget if VOLTRES$>1 then a7$=" Must be 0 to 1 " lcdlp(7,0) lcdis(a7$) else lcdlp(5,10) if VOLTRES$=0 then lcds(Volt) else lcds(Res) endif j=1 endif wend paramstore(VOLTRESX,VOLTR ES$) //Pause between current on and reading a7$="Pause B4 Reading (ms)" lcdlp(7,0) lcdis(a7$) lcdlp(6,0) lcds(a6$) PAUSE$=kgetmul#(4) paramstore(PAUSEX,PAUSE$) paramclose lcdlp(7,0) a7$=" Done " lcdis(a7$) wait 1500 endif run mainmenu endf keypad.bas //Keypad interface //Multiple value call "kgetmul#()" uses LCD subroutines constant KEYADR 0x62 //Initialisation function keypad i2copen 400000 if i2ctest(KEYADR) = 0 then print "Device not connected at address ";hex$(KEYADR) endif dim keys[16],keychk[1],keyrun,w,v keep endf //Check for keys in buffer function keycheck i2cwrite KEYADR 1 i2cread KEYADR, keychk[1];1 endf //Get keys from buffer function keyread i2cwrite KEYADR 4 i2cread KEYADR, keys[1];keychk[1] keychk[1]=0 endf //Wait for and return number input (or * or #) function kget w=0 while w=0 keycheck keychk=keychk[1] if keychk>0 then keyread keys=keys[1] 54 w=1 endif if key?(2)=1 then keys=key(2) keys=keys-48 if keys=-13 then keys=10 endif if keys=-6 then keys=11 endif w=1 if keys<0 then w=0 endif if keys>11 then w=0 endif endif wend result keys endf //Enter a multiple digit number inc "." with # to complete //Also prints to LCD so must set line and position first! //SIZE sets a limit on digits to be entered //Note "." counts as a digit toward SIZE function kgetmul#(SIZE) v=0 ordmag=1 sign=1 kval=0 kvalt#=0 CSIZE=0 while v=0 kval=kget breakif kval=10 if kval=11 then if sign=-1 then goto goto1 endif sign=-1 CSIZE=CSIZE+1 lcdc(46) goto goto1 endif if sign=1 then kvalt#=kval+kvalt#*10 CSIZE=CSIZE+1 endif if sign=-1 then kvalt#=kvalt#+kval*(10^(ordmag* sign)) ordmag=ordmag+1 CSIZE=CSIZE+1 endif lcds(kval) label goto1 breakif SIZE=CSIZE wend result kvalt# endf lcd.bas // LCD Control constant LCDADR 0x42 function lcdhelp print print "Functions - lcdinit" print " lcdc(char)" print " lcds(string)" print " lcdlp(line,pos)" print " lcdcls" print " lcdhline(x,y,length)" print " lcdvline(x,y,length)" print " x=0 to 127 y=0 to 63" print " lcdnbox(x,y,xlength,ylength" print " lcdfbox(x,y,xlength,ylength" print endf // initialise and check address function lcd i2copen 400000 if i2ctest(LCDADR) = 0 then print "Device not connected at address ";hex$(LCDADR) endif endf // ----------- Text functions --------------------// // put character to display function lcdc(c) i2cwrite LCDADR 0x20 c endf // put inverted colour character to display function lcdic(c) i2cwrite LCDADR 0x21 c endf function lcds(s$) dim j for j = 1 to len(s$) lcdc(asc(s$,j)) next endf // print inverted colour string function lcdis(s$) dim j for j = 1 to len(s$) lcdic(asc(s$,j)) next endf // set line and current position, line is 0 or 7 snd // postion is 0 to 20 function lcdlp(line,pos) i2cwrite LCDADR 0x25 line pos // set line & pos endf // clear screen and home cursor function lcdcls i2cwrite LCDADR 0x05 endf // -------------- Graphic Functions --------------// // Draw horizontal and vertical lines atarting at given // co-ordimates where // x: horixontal 0-127 // y: vertical 0-63 function lcdhline(x,y, length) i2cwrite LCDADR 0x12 x y length endf function lcdvline(x,y, length) i2cwrite LCDADR 0x14 x y length endf // // Draws a box N no fill F filled // x,y are the top left hand corner of the box and // xl, yl are the lengths of the sides function lcdnbox(x,y,xl,yl) i2cwrite LCDADR 0x16 x y xl yl endf function lcdfbox(x,y,xl,yl) i2cwrite LCDADR 0x18 x y xl yl endf // prints string to display 55 mainmenu.bas //Main Program Main Menu function mainmenu lcd keypad lcdcls print print " THERMOCOUPLE READING PROGRAM" print " -------------------------------" print print " 1. Begin temperature logging" print " 2. Calibrate the thermocouple" print " 3. Enter configuration settings" print " 4. Reset configuration" print " 5. Plotter BETA" print " 6. Current Source BETA" print " 9. Run Snake" print a0$=" MAIN MENU " a2$="1.Begin Data-Logging" a3$="2.Calibrate TC" a4$="3.Configure" a5$="4.Reset Configuration" a6$="5.Run Plotter BETA" a7$="6.Current Source BETA" lcdlp(0,0) lcdis(a0$) lcdlp(2,0) lcds(a2$) lcdlp(3,0) lcds(a3$) lcdlp(4,0) lcds(a4$) lcdlp(5,0) lcds(a5$) lcdlp(6,0) lcds(a6$) lcdlp(7,0) lcds(a7$) MENU=kget select MENU case 1 run readstar case 2 run calibrat case 3 run entercon case 4 run resetcon case 5 run plotter case 6 run pulstart case 9 run snake case 0 lcdcls a3$=" Consult PC Terminal" lcdlp(3,0) lcds(a3$) print " EXIT" new default run mainmenu endselect endf lcdlp(0,0) lcdis(a0$) lcdlp(2,0) lcds(a2$) lcdlp(3,0) lcds(a3$) lcdlp(4,0) lcds(a4$) lcdlp(5,0) lcds(a5$) lcdlp(6,0) lcds(a6$) lcdlp(7,0) lcds(a7$) endf // Convert second array of y points to a byte matrix suitable for direct sending // to the LCD and SUM them to the final byte matrix function convertmatrixsum for CP=1 to 128 PLOT=63-MATRIXD&[CP] BYTE=mod(PLOT,8) PLOT=(PLOT-BYTE)/8 BYTE=2^(BYTE) plotterbeta.bas //Fast map of byte matrix to screen ~ 3.55s //Note: The bytes have to be mapped in this unusual order due to unexpected bad // behaviour from LCD, this only affects the mapping time by a few ms function bytemap lcdcls dim i,j,k CP=0 for j=0 to 1 for i=0 to 7 i2cwrite LCDADR 8 i i2cwrite LCDADR 7 64*j for k=0 to 63 i2cwrite LCDADR 3 MATRIXB&[(64*j)+k+1,i+1] CP=CP+1 next next next endf //Compare two arrays of y points, if two points are the same then clear one //to prevent duplication function comparematrix for CP=1 to 128 if MATRIXC&[CP]=MATRIXD&[ CP] then MATRIXD&[CP]=64 endif next endf //Plotter Beta function plotter lcd keypad lcdcls showmenu dim MATRIXC&[128],MATRIXD&[1 28],TIMERES,CP,MATRIXB&[1 28,8] MENU=kget select MENU case 1 tester(1) case 2 tester(2) case 3 tester(3) case 4 test1 case 5 test2 case 6 run mainmenu default run plotter endselect keep endf //LCD Menu function showmenu a0$=" PLOTTER (BETA) " a2$="1.Plot Linear" a3$="2.Plot Exp" a4$="3.Plot Sinusoidal" a5$="4.Plot Exp&Sine" a6$="5.Plot Combination" a7$="6.Return to Main Menu" MATRIXB&[CP,PLOT+1]=BYT E+MATRIXB&[CP,PLOT+1] next endf //Convert array of y points to a byte matrix suitable for direct sending to //the LCD function convertmatrix for CP=1 to 128 PLOT=63-MATRIXC&[CP] BYTE=mod(PLOT,8) PLOT=(PLOT-BYTE)/8 BYTE=2^(BYTE) MATRIXB&[CP,PLOT+1]=BYT E next endf 56 //Clear Bytemap function clearbytemap dim i,j for i=1 to 128 for j=1 to 8 MATRIXB$[i,j]=0 next next endf //TEST: Combine two functions and plot function test1 calc for TIMERES=1 to 128 MATRIXC&[TIMERES]=33+int( 31*sin(2*PI*TIMERES/128)) MATRIXD&[TIMERES]=int(64^ (TIMERES/128)) next comparematrix convertmatrix convertmatrixsum bytemap wait 2500 run plotter endf SECON=kgetmul#(1) calc for TIMERES=1 to 128 MATRIXC&[TIMERES]=choose plot(FIRST,TIMERES) //TEST: Compose a standard array of y points for a plot, convert to //the suitable byte matrix, and send via the FAST mapping function function tester(MEN) calc select MEN case 1 for TIMERES=1 to 128 MATRIXC&[TIMERES]=lin(TI MERES) next case 2 for TIMERES=1 to 128 MATRIXC&[TIMERES]=exp(TI MERES) next case 3 for TIMERES=1 to 128 MATRIXC&[TIMERES]=sine(TI MERES) next endselect convertmatrix bytemap wait 2500 run plotter endf //test any two functions function test2 lcdcls a2$=" First function: " a3$=" Second function: " a5$=" 1.Lin 2.Inv-Lin" a6$=" 3.Exp 4.Inv-Exp" a7$=" 5.Sine 6.Inv-Sine" lcdlp(5,0) lcds(a5$) lcdlp(6,0) lcds(a6$) lcdlp(7,0) lcds(a7$) lcdlp(2,0) lcds(a2$) FIRST=kgetmul#(1) lcdlp(3,0) lcds(a3$) MATRIXD&[TIMERES]=choose plot(SECON,TIMERES) next comparematrix convertmatrix convertmatrixsum bytemap wait 2500 run plotter endf function chooseplot(PL,VA) select PL case 2 PV=ilin(VA) case 3 PV=exp(VA) case 4 PV=iexp(VA) case 5 PV=sine(VA) case 6 PV=isine(VA) default PV=lin(VA) endselect result PV endf function lin(VAL) result int((VAL)/2) endf function ilin(VAL) result 64-int((VAL)/2) endf function exp(VAL) result int(64^(VAL/128)) endf function iexp(VAL) result 64-int(64^(VAL/128)) endf function sine(VAL) result 33+int(31*sin(2*PI*VAL/128)) endf function isine(VAL) 57 result 31int(31*sin(2*PI*VAL/128)) endf function calc lcdcls a3$="CALCULATING" lcdlp(3,5) lcds(a3$) endf readstar.bas //Main Data Logging program //Default Settings constant MAX_V# 3.3 //Maximum ADC voltage constant PUL_V# 15 //Current source voltage constant BITS# 1024 //No of ADC bits constant GAIN# 10 //Op-amp gain constant THRESHOLDMAX# 14.28 //Voltage maximum before droping the current constant OFFSET# 1 //Additonal MUX resistance // Current Levels constant CUR0# 10.23 constant CUR1# 5.350 constant CUR2# 1.014 constant CUR3# 0.515 function readstar //Set up main program dim fn,i,j,k,READING#[2],CURRENT &[16] keep lcd keypad lcdcls a0$=" DATA LOGGING " a3$=" TESTING" a7$=" Press # to Exit " lcdlp(0,0) lcdis(a0$) lcdlp(3,0) lcds(a3$) lcdlp(7,0) lcdis(a7$) a=fileexists("config.cfg") if a=0 then configerror endif a=fileexists("calib.cfg") if a=0 then configerror endif callsettings callcalib setoutputs for k=0 to 2 openadc 30 k next //Check all resisors are grounded for k=1 to RESISCHN m=k-1 MUXselect(m) READINGZ#=readvoltage if READINGZ#>0.1 then a3$=" CHECK CHANNEL: " a4$=" CONNECTION! " lcdlp(3,0) lcds(a3$) lcds(k) lcdlp(4,0) lcds(a4$) wait 3000 cd b:\mainprog run mainmenu endif next //Get data file ready datalogcheck newfile //Find out current level to use fn=openfile("data"+FILENUM+". dat",'a') write$ fn "Current: " if TEMPCHN>0 then for j=1 to TEMPCHN write$ fn ""+*0x09 next endif for k=1 to RESISCHN m=k-1 MUXselect(m) A=testcurrent CURRENT&[k]=A print CURRENT&[k] write$ fn ""+*0x09+A next write$ fn ""+*0x0d+*0x0a+*0x0d+*0x0a closefile fn //-------------resetclock NEXTTIME%=0 DAYSX=0 a3$=" " lcdlp(3,0) lcds(a3$) a2$="Temp1:" a3$="Temp2:" a5$="Elapsed:" a6$=" Total: " if TEMPCHN>0 then lcdlp(2,0) lcds(a2$) endif if TEMPCHN>1 then lcdlp(2,10) lcds(a3$) endif lcdlp(5,0) lcds(a5$) lcdlp(6,0) lcds(a6$) if DAYS<10 then lcdc(48) endif lcds(DAYS) lcdc(58) lcds(TOTALTIME$) //Give titles to the readings in the file fn=openfile("data"+FILENUM+". dat",'a') write$ fn "TIME " if TEMPCHN>0 then for j=1 to TEMPCHN write$ fn ""+*0x09+TEMP+j next endif if RESISCHN>0 then for j=1 to RESISCHN if VOLTRES=0 then write$ fn ""+*0x09+VOLT+j else write$ fn ""+*0x09+RES+j endif next endif closefile fn //Begin data logging TIMESTR$=time$() INTERVAL=timeconvert(INTER VAL$) while (DAYSX*86400)+timeconvert(ti me$())<=TOTALSEC //Print time every second if TIMESTR$<>time$() then 58 lcdlp(5,9) if DAYSX<10 then lcdc(48) lcds(DAYSX) lcdlp(5,11) else lcds(DAYSX) endif lcdc(58) lcds(time$()) TIMESTR$=time$() endif //Take readings if NEXTTIME%<=(DAYSX*86400 )+timeconvert(time$()) then lcdlp(1,7) lcds(READING) print print time$()+" "; st if TEMPCHN>0 then readtemp endif if RESISCHN>0 then for k=1 to RESISCHN m=k-1 A=CURRENT&[k] MUXselect(m) curMUXselect(A) wait PAUSE READINGZ#=readvoltage MUXkill select A case 0 CURL#=CUR0# case 1 CURL#=CUR1# case 2 CURL#=CUR2# case 3 CURL#=CUR3# endselect READINGZ#=READING#[1] READINGZ#=READINGZ#/GAI N# if VOLTRES=0 then print format$(#.###,READINGZ#)+" "; srVOLT(READINGZ#) else READINGZ#=(1000*READING Z#/CURL#)-OFFSET# print format$(###.#,READINGZ#)+" "; srRES(READINGZ#) endif next endif closefile fn lcdlp(1,7) a0$=" " lcds(a0$) NEXTTIME%=NEXTTIME%+IN TERVAL lcdlp(2,20) lcdc(32) lcdlp(3,20) lcdc(32) endif //Loop Break breakif key?(2)=1 keycheck if keychk[1]>1 then keyread endif breakif keys[1]=10 //Increment DAYSX counter at 23:59:59 if timeconvert(time$())=86399 then resetclock DAYSX=DAYSX+1 wait 800 endif wend //Finish closefile fn print "Finished" cd b:\mainprog run mainmenu endf function configerror print "Must set configuration first!" a2$=" Must enter" a3$=" configuration" a4$=" settings first!" lcdlp(2,0) lcds(a2$) lcdlp(3,0) lcds(a3$) lcdlp(4,0) lcds(a4$) wait 1500 run mainmenu endf function readtemp for j=1 to 200 for k=1 to TEMPCHN m=k-1 READING#[k]=READING#[k]+a dc(m) next next j=j-1 for k=1 to TEMPCHN select k case 1 READING#[k]=READING#[k]*( MAX_V#/BITS#)/(j*V_OVER_C #) print format$(###.#,READING#[k])+" "; lcdlp(2,6) lcds(format$(###,READING#[1])) srTEMP(READING#[k]) case 2 READING#[k]=READING#[k]*( MAX_V#/BITS#)/(j*V_OVER_C 2#) print format$(###.#,READING#[k])+" "; lcdlp(2,16) lcds(format$(###,READING#[2])) srTEMP(READING#[k]) endselect READING#[k]=0 next endf function readvoltage for j=1 to 200 READING#[1]=READING#[1]+a dc(2) next j=j-1 READING#[1]=READING#[1]*( PUL_V#/BITS#)/j result READING#[1] 59 endf function testcurrent i=0 CURSET=0 while i<4 curMUXselect(i) wait 50 for j=1 to 10 READING#[1]=READING#[1]+a dc(2) next port CE0$ 1 j=j-1 READING#[1]=READING#[1]*( PUL_V#/BITS#)/j print READING#[1]+" "; if READING#[1] > THRESHOLDMAX# then i=i+1 else CURSET=i i=4 endif wend result CURSET endf // // resetcon.bas //Reset Configuration function resetcon lcd keypad lcdcls a0$=" RESET CONFIGURATION " lcdlp(0,0) lcdis(a0$) a=fileexists(config.cfg) if a=1 then a2$=" Confirm Deletion? " lcdlp(2,0) lcds(a2$) a3$=" CONFIG.CFG" lcdlp(3,0) lcds(a3$) a7$=" 1.Yes 0.No " lcdlp(7.0) lcdis(a7$) MENU=kget if MENU=1 then del config.cfg a7$=" DONE " lcdlp(7,0) lcdis(a7$) wait 1500 endif else a2$="CONFIG.CFG not found!" lcdlp(2,0) lcds(a2$) wait 1500 endif run mainmenu endf splash.bas //Splash screen function splash lcd lcdcls a$=" Implanted " b$=" Devices Group " c$=" Automated " d$=" Data-logger " lcdnbox(0,0,128,64) lcdlp(1,0) lcds(a$) lcdlp(2,0) lcds(b$) lcdhline(6,30,116) lcdhline(8,32,112) lcdlp(5,0) lcds(c$) lcdlp(6,0) lcds(d$) wait 2000 a$=" Designed and Built " b$=" by " c$=" Alex Messenger " Lines: 1482 60 d$=" 2010 " lcdlp(1,0) lcds(a$) lcdlp(2,0) lcds(b$) lcdhline(6,30,116) lcdhline(8,32,112) lcdlp(5,0) lcds(c$) lcdlp(6,0) lcds(d$) wait 1500 lcdfbox(0,0,128,64) i2cwrite LCDADR 0x19 0 0 128 64 lcdcls endf (V) Contact details Alexander James Messenger a.j.messenger@live.com 12 Milton Lane 01732 874159 Kings Hill 07989 363425 West Malling Kent ME19 4HP 61