Projects for geeks

Control Unit

05 Dec 2006
Control Unit board

Device was designed to be used as control unit for ROV or any other remotely controlled robot. As primary communication interface is used RS485. It allows controlling robot using 1200m long cable.
Several other interfaces allows reading data like temperature, depth and heading.

Normally ROV receives commands from the surface and sends back data read from sensors. Special software has to be written to perform this task.

Main features

  • Atmel Atmega16 or Atmega32 microcontroller
  • 1×RS485 for communication with surface
  • 2×RS232 to control devices with serial interface, for example Roboteq motor controllers.
  • 5×I²C header to connect any I²C device like CMPS03 digital compass, temperature sensors.
  • 3×multi purpose header to be used as:
    • ADC input for sensors with voltage output, or
    • ADC input for sensors with current output like pressure sensor, or
    • digital input, or
    • digital output, or
    • servo controller
  • 1-Wire bus
  • LANC or IR interface to control camera
  • 2×leak sensor
  • ISP header to program microcontroller
  • 15 pin header to connect Motor Controller
  • Power voltage sensor
  • JTAG support

How to build

All files needed to create own PCB are located at the end of the article. You can use PDF files or create gerber files from Eagle project.


Atmel Atmega16 in typical configuration. 14.7456Mhz crystal gives 0% error for serial communication. Device is powered by 7805 regulator. RS232 interface uses popular MAX232 chip. RS485 is handled by MAX485.



Solder all small elements first, than middle size elements, at the end solder headers and sockets. Note that C12 capacitor is located under Atmega16 socket.

First you need to create PCB. Use attached PDF files for wire artwork. It is very important that you check all wires carefully. 95% of problems is caused by short circuits.

When you finish with elements, connect the power (6-12V). Check how much power device uses, up to 100mA is ok. If you connect ISP programmer or JTAG that is powered from PCB, power consumption will be greater. If you note values greater than 150mA or 7805 chip is very hot turn the power off and check connections.

Connect AVR programmer using ISP socket. If your programmer software is able to read chip signature and fuse bits you can open champagne and celebrate your first success. 50% of work is done.

The next step is to set appropriate fuse bits. We need to change 2 of them: disable JTAG and force chip to use external crystal. All brand new Atmega16 chips uses 1Mhz internal RC oscillator and have JTAG support enabled. If you do not use RS232 you can leave JTAG bit as it is.

Note that if you use JTAG interface to set fuses do not disable JTAG support! If you set XTAL fuse bits and microcontroller stops responding — check crystal connections.

Now you can test all the interfaces using attached test programs. Remember: if something does not work it is probably because of short circuits.

Here are screen shots of popular programmers with proper settings of external XTAL.

Recommended sensors

Here is a list of devices that are recommended to use. Of course any device that has interface supported by control unit can be used.

  • DS18B20 1-Wire digital thermometer
  • CMPS03 I²C digital compass



The device was designed to be powered by 12V accumulator. But can be powered from 6V to 12V (see 7805 spec for more details). Note that pin 1 of SL1, SL2 and SL3 are directly connected to main power supply, so if you power board e.g. with 7.2V expect 7.2V on that pin not 12V! 5V is taken from 7805 chip, it is independent of main power voltage. If you need to power board with voltage >12V I recommend to use DC/DC converter instead of 7805. Too high input voltage combined with 7805 will result in large power dissipation = high temperature. If you really want to use 7805 mount a radiator.

If you have source of regulated 5V you do not need to mount voltage regulator parts: IC4, C8, C9, C10 and C11. Remember to connect 5V in place of pin 2 and 3 of 7805 chip (IC4).

Properly connected power is indicated by LED, I use red one. If you plan to replace it with other color you can try other values of R14 resistor to regulate brightness.


I²C is simple bidirectional 2 wire bus. In Atmel documentation it is called Two-wire Serial Interface (TWI). I²C has become a de facto world standard that is implemented in many different chips and devices like: flash memory, ADC/DAC converters, sensors, clocks, LCD displays, etc.

There are 5 headers on the board. They consists standard I²C lines SDA and SCL and power lines 5V and GND. Note that number of I²C devices connected to the board is not limited by the number of headers. You can connect up to 128 different devices. The only limitation is the bus capacitance 400pF. If you encounter communication problems, especially when connecting many devices and long cables you can try to set R4 and R5 resistors. They are pull-up resistors for bus lines. 10kΩ is commonly used value, to compute other values you can look into Atmega16 documentation, chapter “Two-wire Serial Interface Characteristics” (page 297), parameter Value of Pull-up resistor.

I²C interface can be used to expand number of digital I/O ports by connecting PCF8574 expander chip. One chip gives 8 additional lines. You can look at I²C driver project.


SDA and SCL lines are connected to PC0 and PC1 ports of Atmega16 (pin 22 and 23). As you note alternate functions for those pins are SDA and SCL. That means you can use Atmega16 built-in functionality or software implementations to perform I²C communication.

There are many resources on the internet; you can easily find the information how to use I²C bus. Worth to read is “Two-wire Serial Interface” chapter from Atmel atmega16 documentation.

BASCOM has built-in functions for I²C bus, like: Config Scl, I2cstart, I2cstop, I2cwbyte, I2crbyte and others. Read BASCOM documentation for details.

Here is an example written in BASCOM how to read digital compass CMPS03 heading value.

$regfile = "m16def.dat"
$crystal = 14745600
$lib "I2C_TWI.LBX"                                     ‘use hardware TWI
Config Scl = Portc.0
Config Sda = Portc.1
Config Twi = 400000
Dim Hi As Byte
Dim Lo As Byte
Dim Heading As Integer
Dim X As Integer
‘Open debug port
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 output
Print #1 , "CMPS03 COMPASS DEMO"
   I2cwbyte &HC0
   I2cwbyte &HC1
   I2cwbyte &HC1
   I2crbyte Hi , Ack
   I2crbyte Hi , Ack
   I2crbyte Lo , Nack
   Heading = Makeint(lo , Hi)
   ‘Heading is like 3201 for 320.1deg
   Lo = Heading Mod 10
   Heading = Heading / 10
   Print #1 , "Heading: " ; Heading ; "." ; Lo ; " deg"
   Waitms 500


RS232 is handled by the MAX232 chip. Serial interface do not use hardware UART. RX/TX lines are connected to port C lines. DB2 port uses PC2 and PC3 lines, DB1 uses PC4 and PC5 lines. To transmit or receive data from serial port you must use software routines. Serial port has only data transmission lines TX and RX (and GND). If you use Terminal like program, specify handshaking to None, do not use RTS/CTS or XON/XOFF options.

It is important that you disable JTAG support. Serial port will not work with JTAG enabled. You must clear appropriate fuse bit.

If you do not use serial port, the following elements are unnecessary: IC3 (MAX232), C3, C5, C6, C7, DB1 and DB2. I recommend using at least one serial port, it is very handy to write diagnostic messages to serial port and read it in Terminal window.

Using standard serial cable you can connect PC computer. To connect e.g. modem you must cross TX and RX signals or use NULL modem cable. Everything depends on type of device you are connecting: DTE (e.g. computer) or DCE (e.g. modem). You can consider control unit as DCE device. TX line of one device must match RX line of the second device.


As mentioned earlier serial communication must be performed by software routines. Built-in UART is used for RS485 communication. Remember that software implementation can be affected by interrupts. If you encounter communication problems, disabling interrupts can help.

There are freely available libraries for C. To perform serial communication from BASCOM you must use Open or Serout and Serin functions.

The following BASCOM example sends diagnostic messages to DB1 and DB2 ports every 1s. You can use this program to test serial communication. To see the results connect board to desktop PC and run Terminal program and set communication parameters 2400 8N1, handshaking: none.


‘Serial ports works only if JTAG fuse bit is disabled
‘New chips has JTAG enabled by default
‘Make sure you disabled JTAG bit!
$regfile = "m16def.dat"
$crystal = 14745600
Dim L As Long
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 output
Open "comc.3:2400,8,n,1" For Output As #2                   ‘DB2 output
   Print #1 , "THIS IS PORT DB1. LINE " ; L
   Print #2 , "THIS IS PORT DB2. LINE " ; L
   L = L + 1
   Toggle Porta.2                                           ‘SL3
   Toggle Porta.1                                           ‘SL2
   Toggle Porta.0                                           ‘SL1
   Waitms 500


RS485 is half-duplex serial interface. This interface allows communicating using only two wires for long distance. It was intended to use it as connection between ROV and surface.

RS485 is handled by MAX485 chip. It uses 3 pins of Atmega16. Pins PD1 and PD0 are TX and RX. PD6 sets direction of communication (send/receive). PD1 and PD0 are hardware UART pins of ATmega16, so you do not need software routines to send data but you can use built-in functionality of AVR chips. In addition you can use interrupts to handle communication.

Half-duplex interface do not allow transmitting and receiving data in the same time. You must select appropriate transmission mode. To send data you must set PD6 high. To receive data set PD6 low.

RS485 line must be terminated. There is 120Ω (R10) resistor on the PCB. 120Ω is very common value, suits best twisted pair cable. If you encounter communication problems you can try different values of R10.


From the programmer point of view, use of RS485 is the same as any other serial interface. Because RS485 is connected to hardware UART there is no need to use software routines.
Before sending or receiving any data, MAX485 chip have to be configured to receive or send data. Half duplex communication does not allow receiving and sending data simultaneously.
Set PD6 to 1, before sending data. Set PD6 to 0 to receive data.

The following example in BASCOM-AVR sends simple message to RS485. Note that BASCOM-AVR has special command to configure half duplex RS485 communication, see CONFIG PRINT.

DATA FORMAT: 2400bps 8N1

‘RS485 works even with JTAG fuse bit enabled
$regfile = "m16def.dat"
$crystal = 14745600
$baud = 2400
Dim I As Integer
‘RS485 half-duplex mode switch on portd.6
‘portd.6 = 1 – transmit
‘portd.6 = 0 – receive
Config Print0 = Portd.6 , Mode = Set
   Print "MESSAGE #" ; I ; " FROM RS485"
   I = I + 1
   Waitms 500


To use JTAG interface you must disable RS232 interface. It is not possible to use RS232 and JTAG simultaneously. RS232 and JTAG use the same lines PC2, PC3, PC4 and PC5. But you can still use RS485.

If you feel more comfortable with connected RESET line on JTAG header, you have to connect JP6 and JP7 pins.

Note that to take full advantages of JTAG you must have separate JTAG interface. If you do not have JTAG interface, you can consider building simple interface designed by Aquaticus team.

Here are screenshots with JTAG fuse enabled:


1-Wire is communication bus developed by Dallas. It is similar to I²C, but needs only one communication wire. Every device has its own unique ID. It is possible to connect many devices to the bus.

SL12 header is 1-Wire interface. It consist 5V/GND lines and data line connected to PB0 pin of Atmega16. Microcontroller has no built-in functions for 1-Wire interface, but transmission can be performed by software routines.


The following example reads temperature from two DS18B20 sensors and sends message to RS232 (DB1) port at 2400 8N1.

$regfile = "m16def.dat"
$crystal = 14745600
Config 1wire = Portb.0                                      ‘1-wire bus on PB.0
Declare Function Sc2deg(byval Sc(9) As Byte) As Integer
Dim C As Integer
Dim T_msb As Byte
Dim T_lsb As Byte
Dim Conf_reg As Byte
Dim Temp As Integer
Dim Sensor1(8) As Byte
Dim Sensor2(8) As Byte
Dim Sc(9) As Byte
Dim A As Integer
Dim B As Integer
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 output
C = 1wirecount()
Print #1 , "Number of 1-Wire devices: " ; C
‘Read ID of sensors
Sensor1(1) = 1wsearchfirst()
  Sensor2(1) = 1wsearchnext()
Loop Until Err = 1
   ‘covert temp for all sensors
   1wreset                                                  ‘ reset the bus
   1wwrite &HCC                                             ‘ skip rom
   1wwrite &H44                                             ‘ Convert T
   Waitms 750
   1wverify Sensor1(1)                                      ‘select sensor #2
   1wwrite &HBE
   Sc(1) = 1wread(9)                                        ‘read scratchpad
   Temp = Sc2deg(sc(1) )
   A = Temp / 10
   B = Temp Mod 10
   B = Abs(b)
   Print #1 , "Temperature #1: " ; A ; "." ; B ; " ©"
   If C > 1 Then
      1wverify Sensor2(1)                                   ‘select sensor #2
      1wwrite &HBE
      Sc(1) = 1wread(9)                                     ‘read scratchpad
      Temp = Sc2deg(sc(1) )
      A = Temp / 10
      B = Temp Mod 10
      B = Abs(b)
      Print #1 , "Temperature #2: " ; A ; "." ; B ; " ©"
   End If
   Print #1 , ""
Function Sc2deg(byval Sc(9) As Byte)
   Sc2deg = Makeint(sc(1) , Sc(2))
   Sc2deg = Sc2deg * 10
   Sc2deg = Sc2deg / 16
End Function 

Leak sensors

There are 2 identical leak sensors on the board. First sensor (SL4) is connected to PD3 line (pin 17), second one (SL5) to PD2 (pin 16).

To read sensor state you must configure PD2 and PD3 as inputs (activation of internal pull-up resistors is not necessary). Leak is detected if appropriate bit is set to 1.
Sensor detects any wet between 2 header pins. It should detect leak even if you short sensor pins with wet finger. You can attach 2 cables to SL4/SL5 or small PCB with pattern like one shown on the left.

If you do not need leak sensor you can attach standard switch to SL9/Sl10 and use it as you like.

Here is simple example in BASCOM. It sends a message to DB1 port when leak is detected.

$regfile = "m16def.dat"
$crystal = 14745600
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 output
Print #1 , "LEAK DETECTOR"
Config Portd.2 = Input
Config Portd.3 = Input
Dim I As Integer
   ‘Leak sensor #1
   If Pind.3 = 1 Then
      Print #1 , I ; ") LEAK SENSOR #1 (SL4): WATER DETECTED"
      I = I + 1
   End If
   ‘Leak sensor #2
   If Pind.2 = 1 Then
      Print #1 , I ; ") LEAK SENSOR #2 (SL5): WATER DETECTED"
      I = I + 1
   End If

Power voltage sensor

The sensor uses AD converter to obtain value of voltage. Power supply value is divided by simple voltage divider built from R11 and R12 resistors. Values of those resistors are selected to be used with ADC internal reference voltage 2.56V. Maximum voltage that can be measured is about 14V.

General equation for the voltage divider is: VOUT=(VSUPPLY×R12)/(R11+R12)

For example if power supply voltage is 12V, divider output and ADC input voltage is: (12×2200)/(2200+10000)=2.16V.

The ADC result is: ADC = VOUT×1024/VREF.

Those 2 equation give us general equation:



It is handy to multiply result by 100 to operate only on integer values:


The result for 9.45V is 945.

ADC is the value read from A/D converter, reference voltage 2.56V, R12=2.2kΩ, R11=10kΩ.

The simplest form (and a bit less accurate) of the equation is just VSUPPLY=ADC/72.

Maximum voltage that can be measured by A/D converter using 2.56V reference voltage is 2.56V. This limits the maximum power supply voltage to 14V. If you need to measure greater values than you have to change values of the R11/R11 resistors. It can be helpful to see this online calculator.
The simpler method is to switch from internal reference voltage (2.56V) to VACC (5V). This allows you to measure up to 70V. The only problem is that you must relay on 7805 voltage regulator.


Here is an example that uses float type to compute voltage. It is easier to understand how it works but program size is bigger because for additional library that must be linked.


‘This progam uses internal reference voltage 2.56V.
‘If you notice incorrect values of voltage check
‘pin 32 (AREF) It shoud NOT be connected to VCC or GND.
$regfile = "m16def.dat"
$crystal = 14745600
Dim A As Word
Dim Vout As Single
Dim Vin As Single
Dim Volfmt As String * 5
Const Vref = 2.56
Const Res1 = 10000                                          ‘Value of R11 resistor [ohms]
Const Res2 = 2200                                           ‘Value of R12 resistor [ohms]
Const Factor = Vref / 1024
‘Internal reference voltage 2.56V
Config Adc = Single , Prescaler = Auto , Reference = Internal
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 output
Start Adc
   A = Getadc(3)
   Vin = A * Factor
   Vout = Res1 + Res2
   Vout = Vout * Vin
   Vout = Vout / Res2
   If A < &H3FF Then
      Volfmt = Fusing(vout , "##.##")
      Volfmt = ">14"
   End If
   Print #1 , "POWER VOLTAGE=" ; Volfmt ; "V" ; "  (ADC value:" ; A ;
   Volfmt = Fusing(vin , "##.##" )
   Print #1 , " ,ADC Input:" ; Volfmt ; "V) "
   Waitms 500

Digital in/out

There are 3 general purpose headers that can be used as digital input/output or to measure analog value. To read digital value (1 or 0) on specified pin, you must first configure it to work as input; by default all Atmega16 pins are outputs. In addition you can activate internal pull-up resistors.

If you need more digital I/O lines you can consider connecting PCF8574 expander chip to I²C bus. One chip gives 8 extra lines.


Here is an immortal example — flashing LED. Connect LED directly pin ADCx of SL1 or SL2 or SL3 and GND.

$regfile = "m16def.dat"
$crystal = 14745600
Config Porta = Output
Open "comc.5:2400,8,n,1" For Output As #1                   ‘DB1 debug port
‘Debug message
Print #1 , "LED TEST"
‘Flash LED every 0.5s
   Toggle Porta.2                                           ‘SL3
   Toggle Porta.1                                           ‘SL2
   Toggle Porta.0                                           ‘SL1
   Waitms 500

Analog input

SL1, SL2 and SL3 headers can works as analog input. First those pins must be configured as input for internal ADC unit. Then referral voltage for ADC has to be chosen. You have 2 possibilities: 2.56V internal reference voltage or VCC which is equal to 5V. Reference voltage determines maximum value that can be measured. I recommend using 2.56V voltage if possible.

AD converter can directly read only voltage value. Some sensors that give current output, usually 4-20mA. To measure current you need one additional resistor and simply measure voltage drop on that resistor. With every header SL1, SL2, SL3 is associated one 120Ω resistor (R1,R2,R3). To enable resistor short appropriate jumpers JP1, JP2 or JP3. 120Ω allows you to measure max 20mA when using 2.56V reference voltage.

Camera interface

SL13 can be used to control camera functions like zoom, focus etc. For camera with LANC interface it can be directly connected to SL13. For cameras with IR interface a IR diode have to be connected.

To control camera using infrared, just connect IR diode and resistor (220Ω is common value) between GND and the middle pin of SL13. This allows you to communicate on short distance, but it should be enough for ROV. Use appropriate functions to send RC5 codes (or any other your camera accepts).
For BASCOM-AVR users: built-in function rc5send (and similar functions) would not work. It require IR diode to be connected to OC1A pin of micro controller which is not true for control unit PCB.

Camera pan and tilt is controlled by I²C bus using I²C driver.


ISP is standard 10 pin header. It was confirmed that it can be successfully used with all popular AVR programmers.

Relays header

SV1 consists of 14 data lines that are used to control motor controller.

C resources

All the above software examples are written in BASCOM. For more complicated projects it is better to use C language. It is harder to write a program in C but it gives you full control of the micro controller.

Free GCC (avr-gcc) compiler can compile programs for AVR controller. Note that free version of BASCOM can compile programs up to 4kb. avr-gcc has no limits.

Windows users should download WinAVR. It has everything to create C programs for AVR micro controllers: GNU GCC compiler, standard C library, make and other tools.

Linux users have to install appropriate packages (avr-gcc, binutils, avr-libc). Consult documentation of your distribution for more details.

Here is a list of resources useful when writing programs in C for control unit:

  • Atmel AVR Studio 4 – integrated development tool. It contains editor, debugger and simulator. It can compile programs using avr-gcc. Note that current version of AVR Studio has many bugs, but it is still a very good tool.
  • AVRlib – is a library of easy-to-use C functions for a variety of common and uncommon tasks using AVR processors.
  • Peter Fleury software examples. Good I²C master library.
  • General peripheral drivers by Chris Efstathiou. High level functions for various devices, e.g. DS18B20/1-wire.
  • Martin Thomas AVR-Projects, among others a good example for 1-wire DS18B20 thermometer.

Note that depending on avr-gcc version some of the above libraries may need a minor changes to be properly compiled.

Be sure you specify F_CPU=14745600 clock frequency macro and micro controller type to mega16 (or mega32) in your programs.

When writing software, you may need more advanced tools that ISP and RS232 for debugging. ROV control unit has JTAG header that was used with Aquaticus JTAG interface. This interface is one of the simplest interfaces available on the net. It is fully compatible with AVRStudio.

Additional projects

Here is a list of additional units works with Control Unit.