Firmware for a hand-built PTZ (Pan / Tilt / Zoom / Focus) keyboard controller based on the Microchip PIC32MX460F512L running on a Digilent CEREBOT 32MX4 development board.
Camera commands are sent over RS-485 using the Pelco-D protocol.
| GLCD splash screen on the dev board | Custom keypad matrix (hand-wired) | Completed keypad wiring |
|---|---|---|
![]() |
![]() |
![]() |
- Pan / Tilt control via analog joystick (ADC), with three selectable speed presets (Slow / Medium / Fast)
- Zoom control via analog joystick axis, variable speed, DMA-driven UART transmission
- Focus control via rotary encoder, three selectable speed presets
- Preset recall — enter a preset number on the keypad and press RECALL
- Extended queries — query absolute Pan / Tilt / Zoom / Focus position from the camera and display on the GLCD
- 128×64 graphical LCD (Ampire 12864C) with real-time slider visualization for all four axes, speed icons, camera ID display, and Tx/Rx/Standby status icons
- 5×8 keypad matrix (40 keys, scanned at 10 ms)
- Pelco-D frame parser on UART2 interrupt — validates checksum and decodes extended position responses
- DMA-driven UART transmit (channel 1) for non-blocking camera command dispatch
- I²C EEPROM (24LC256) for persistent settings storage
- RS-485 transceiver direction control (Tx arm / Rx listen)
| Item | Detail |
|---|---|
| MCU | PIC32MX460F512L |
| Board | Digilent CEREBOT 32MX4 |
| Clock | 80 MHz (XT oscillator) |
| Display | Ampire 12864C — 128×64 monochrome GLCD |
| Keypad | Custom 5×8 matrix, hand-wired on perfboard |
| Joystick | 3-axis analog (Pan / Tilt / Zoom) — AN4, AN5, AN8 |
| Focus | Rotary encoder with push-button — RB0/RB1/RB2 |
| Communication | RS-485 (Pelco-D, 2400 baud) |
| Storage | Microchip 24LC256 I²C EEPROM |
| Toolchain | mikroBasic PRO for PIC32 |
firmware/
├── Cardinal.mbas # Main program — init, event loop
├── Cardinal.mbp32 # Project file (mikroBasic PRO)
├── Cardinal_PLD.pld # Programmable logic device config
│
├── CEREBOT_KEYPAD_IO_v01.mbas # Board I/O pin declarations
│
├── UART2_PARSER_v17_PelcoD_Axis.mbas # Pelco-D frame parser (UART2 ISR)
├── msg_pelcoD_v02.mbas # Pelco-D message builders (pan/tilt/zoom/focus/preset)
├── dma_uart_v01.mbas # DMA ch0/ch1 UART transmit driver
├── DMA_2_ADC_SCAN_v01.mbas # DMA ch2 ADC scan driver
│
├── ADC_setup_v02.mbas # ADC module initialisation
├── pot_speed_tables_v01.mbas # Joystick ADC → speed mapping tables
│
├── core_timer_v06.mbas # Core timer driver (100 µs tick)
├── Timer3_Handler_v01.mbas # Timer3 ISR
├── Timer4_Handler_v01.mbas # Timer4 ISR — focus speed/direction update
├── Timer5_Handler_v01.mbas # Timer5 ISR — keypad scan, ADC tick
│
├── rotary_encoder_v01.mbas # Rotary encoder & keypad driver
├── keypad_5x8_v01.mbas # 5×8 keypad scan logic
│
├── Ampire_12864C_v05.mbas # Ampire 12864C GLCD driver
├── glcd_fonts_v01.mbas # Font collection (6×5, 8×8, 9×14, 13×16, icons)
├── graphical_elements_v01.mbas # UI elements — sliders, icons, absolute position display
│
└── EEPROM_MX4Ck_24LC256_v02.mbas # I²C EEPROM driver
docs/
├── Schematics_preliminary.pdf
├── Keypad_Connection_v01.pdf
└── components-sources.pdf
img/ # Build photos
| Source | Priority | Sub-priority | Rate / Purpose |
|---|---|---|---|
| Core Timer | 7 | 3 | 100 µs tick |
| CN On-Change | 7 | 0 | Keypad select, encoder direction |
| Timer 4 | 6 | 1 | 4–50 ms — focus speed/direction update |
| Timer 5 | 6 | 0 | 10 ms — keypad matrix scan, ADC tick |
| DMA 0 | 5 | 2 | UART Rx |
| DMA 1 | 5 | 1 | UART Tx |
| ADC | 4 | 0 | Scan complete |
| UART 1 | 4 | 1 | Rx |
| UART 2 | 4 | 0 | Rx — Pelco-D parser |
[FF] [CamID] [Cmd1] [Cmd2] [Data1] [Data2] [Checksum]
Checksum = CamID + Cmd1 + Cmd2 + Data1 + Data2
The controller transmits commands (pan, tilt, zoom, focus, preset recall, extended queries) and parses position response frames returned by the camera (0x59 Pan, 0x5B Tilt, 0x5D Zoom, 0x63 Focus).
Open firmware/Cardinal.mbp32 with mikroBasic PRO for PIC32 and compile. Flash the resulting .hex to the PIC32MX460F512L using a PICkit or compatible programmer.
See LICENSE.
Copyright © 2013 Gabi Mihaila


