Aus RN-Wissen.de
Wechseln zu: Navigation, Suche
Rasenmaehroboter Test

K (Servo-Library)
K (Multi IO Projekt Library)
Zeile 3.323: Zeile 3.323:
 
         Funktionen natürlich nicht funktionsfähig und können nicht benutzt
 
         Funktionen natürlich nicht funktionsfähig und können nicht benutzt
 
         werden.
 
         werden.
  Zu (2): Siehe [[RP6 Multi IO Projekt|Hardware-Teil]]!
+
  Zu (2): Siehe [[RP6_Multi_IO_Projekt_-_Software#Multi_IO_Projekt_Library|hier]]!
  
 
Die Library (Software-Bibliothek) besteht aus drei Teilen:
 
Die Library (Software-Bibliothek) besteht aus drei Teilen:

Version vom 10. März 2013, 22:29 Uhr

RP6 Multi IO Erweiterungsmodul

Das RP6-Multi-IO Erweiterungsmodul besteht aus fünf Platinen. Eine Hauptplatine, im üblichen RP6-Layout, enthält eine Vielzahl möglicher Sensoren und Aktoren wie Temperatursensor, Stromsensor, Berührungssensor, Servo-Ansteuerung, LEDs, Buzzer etc. An sie können die vier weiteren Platinen angesteckt werden. Diese sind eine Bumper-Platine zum Anbringen am Heck des RP6, eine Radio-Platine, eine Platine mit vier Tastern und eine mit einem Liniensensor-Array von fünf CNY70-Reflexoptokopplern.

Diese fünf Platinen können bei fabqu ( http://www.roboternetz.de/community/members/47148-fabqu oder fabqu@web.de ) bestellt werden. Sie sind mit Lötstopplack (schwarz) sowie beidseitig mit einem Bestückungsdruck (in weiß) versehen. Sie sind nicht aufgebaut, aber fabqu bietet an, die schwer einzulötenden SMD-ICs (und bei Bedarf auch alle anderen SMD-Bauteile) in einer einmaligen Sammelbestellung zu bestellen und einzulöten.

Hardware

Der Artikel für die Hardware befindet sich HIER.

Software

In diesem Artikel, der die Software für die tolle von Fabian designte Multi IO Projekt Platine vorstellt, darf ich (Dirk) mich austoben. Die vorgestellten Bibliotheken sind natürlich nur ein Vorschlag und sollen nur zur Anregung eigener Projekte und eigener Bibliotheken dienen. Es ist geplant, eine Bibliothek mit allen fest installierten Sensoren und Aktoren aufzubauen. Darüber hinaus soll sich eine weitere Bibliothek mit Umwelt-Fragen beschäftigen (Luftdruck, Luftfeuchtigkeit, Temperatur) sowie eine mit den Sensoren für Lageerkennung (GPS, 2D- oder 9D-Kompass). Diese Bibliotheken liegen – wie das gesamte Projekt – als Open Source vor und werden den Usern zugänglich gemacht.

RP6 M256 WIFI

Die M256-WiFi-Platine (= "M256") kann über den I2C-Bus alle I2C-Sensoren und I2C-Aktoren ansteuern und hat mit ihren vielen freien Ressourcen (Portpins) natürlich optimale Voraussetzungen, um die weiteren Funktionen der Multi IO Platine zu nutzen. Dazu wird sie (wenn alle Funktionen gleichzeitig genutzt werden sollen) mit drei Steckverbindungen angeschlossen:

  • IO-Mxxx <-> IO_PWM/T2/T3
  • ADC-Mxxx <-> ADC_IO2/CMP
  • ADC-M256 <-> ADC_IO1

Dadurch ergeben sich umfangreiche Möglichkeiten, die Sensoren der Multi IO Platine auszulesen und Aktoren zu schalten. Die folgenden 3 Tabellen zeigen die Verbindungen:

Stecker IO-Mxxx:

Stecker-Pin M256-Port M256-Funktion Multi IO-Funktion I/O
1 PE7 ICP3 DCF77 I
2 GND
3 PE6 T3 SHARPS_PWR O
4 PE5 OC3C SNAKE_SWITCH O
5 PB4 OC2A BUZZER O
6 PK7 ADC15 (TX *)
7 PH6 OC2B SNAKE_KEY / (TX *) I
8 PK6 ADC14 (RX *)
9 PE4 OC3B LFS_PWR O
10 VDD

Zu *) UART nicht am IO_PWM/Tx/Ty Stecker der M256 vorhanden!

Stecker ADC-Mxxx:

Stecker-Pin M256-Port M256-Funktion Multi IO-Funktion I/O
1 PK0 ADC8 TOUCH / LFS_L I
2 GND
3 PK1 ADC9 3V3 / LFS_M I
4 PE3 OC3A/AIN1 BUMPER_L I/O *
5 PK2 ADC10 LFS_R I
6 GND
7 PK3 ADC11 BUTTONS I
8 PE2 XCK0/AIN0 BUMPER_R I/O *
9 PK4 ADC12 3V3 alt.1 I
10 VDD

Zu *) Eingang für Bumper-Taster, Ausgang für Bumper-LED!

Stecker ADC-M256:

Stecker-Pin M256-Port M256-Funktion Multi IO-Funktion I/O
1 PF1 ADC1 LDR1 I
2 GND GND
3 PF0 ADC0 LDR2 I
4 VDD
5 PF2 ADC2 LFS_R1 I
6 GND GND
7 PF3 ADC3 LFS_L1 I
8 GND GND
9 PF4 ADC4 SHARP_L I
10 GND GND
11 PF5 ADC5 SHARP_R I
12 PF6 ADC6 SNAKE_R I
13 PF7 ADC7 SNAKE_L I
14 GND GND

Multi IO Projekt Library

Diese Avr-gcc Library für das Multi IO Projekt Board (= "MultiIO") geht von folgenden Voraussetzungen aus:

  • Die RP6v2 M256 WiFi Platine (= "M256") wird für die Ansteuerung der MultiIO benutzt (1).
  • Die M256 ist der I2C-Bus Master.
  • Die I2C-Bus Geschwindigkeit beträgt 100 kHz.
  • Alle Hardware-Komponenten der MultiIO sind aufgebaut (2).
  • Alle Jumper auf der MultiIO sind in ihrer Standardstellung (3).
  • Die MultiIO und die M256 sind mit dem XBUS des RP6-Systems 1:1 verbunden.
  • Der Wannenstecker IO_Mxxx der MultiIO ist mit dem Wannenstecker IO_PWM/T2/T3 der M256 1:1 verbunden.
  • Der Wannenstecker ADC_Mxxx der MultiIO ist mit dem Wannenstecker ADC_IO2/CMP der M256 1:1 verbunden.
  • Der Wannenstecker ADC_M256 der MultiIO ist mit dem Wannenstecker ADC_IO1 der M256 1:1 verbunden.
Zu (1): Dies soll nur der 1. Schritt sein. Natürlich ist die MultiIO auch
        an die RP6 BASE, die M32 und die M128 des RP6-Systems und an
        praktisch alle anderen Microcontroller-Plattformen anschließbar!
Zu (2): Wenn nicht alle Komponenten aufgebaut sind, sind die zugehörigen
        Funktionen natürlich nicht funktionsfähig und können nicht benutzt
        werden.
Zu (3): Siehe folgende Abbildung!

Multi IO Projekt Library - Standardstellung der Jumper

Jumper Standardstellung Hinweis: Die Jumper sind orange eingezeichnet! Die Jumper der Stromversorgung wurden nicht berücksichtigt!


Die Library (Software-Bibliothek) besteht aus drei Teilen:

  • Dem Configuration Header -> Hier stehen alle Definitionen und Festlegungen, die der grundlegenden Konfiguration der MultiIO dienen. Diese Datei kann auf die eigenen Hardware-Voraussetzungen angepaßt werden, ohne dass die eigentliche Library (Header und Source) verändert werden muss.
  • Dem Library Header -> Hier gibt es Definitionen, Variablen- und Funktionsdeklarationen für die Library.
  • Der Library Source -> Das ist die eigentliche Library.
Configuration Header

Datei RP6M256_MultiIO.h:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * Configuration header file for new MultiIO Project Board library.
 *
 * ****************************************************************************
 */

#ifndef RP6M256_MULTIIO_H
#define RP6M256_MULTIIO_H


/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):
#define I2C_MULTIIO_VCS_ADR				0x98	// ADR1/0 = 0/0
//#define I2C_MULTIIO_VCS_ADR				0x9a	// ADR1/0 = 0/1
//#define I2C_MULTIIO_VCS_ADR				0x9c	// ADR1/0 = 1/0
//#define I2C_MULTIIO_VCS_ADR				0x9e	// ADR1/0 = 1/1
//#define I2C_MULTIIO_VCS_ADR				0xee	// Global sync address

// (Voltage divider and shunt resistor!)
#define SHUNT_R							0.051		// 0.051 Ohm
#define V1_ADJUST						2.0			// (10+10)/10 kOhm
#define V2_ADJUST						2.0			// (10+10)/10 kOhm
#define VBAT_ADJUST						3.2			// (22+10)/10 kOhm
#define VSERVO_ADJUST					2.5			// (15+10)/10 kOhm

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):
#define I2C_MULTIIO_RTC_ADR				0xD0	// Default

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):
// (A1 always 0!)
#define I2C_MULTIIO_TEMP_ADR			0x90	// A2/0 = 0/0
//#define I2C_MULTIIO_TEMP_ADR			0x92	// A2/0 = 0/1
//#define I2C_MULTIIO_TEMP_ADR			0x98	// A2/0 = 1/0
//#define I2C_MULTIIO_TEMP_ADR			0x9a	// A2/0 = 1/1

/*****************************************************************************/
// I2C Servo Controller (PCA9685):
// (A5, A4, A3, A2 always 0!)
#define I2C_MULTIIO_SERVO_ADR			0x80	// A1/0 = 0/0
//#define I2C_MULTIIO_SERVO_ADR			0x82	// A1/0 = 0/1
//#define I2C_MULTIIO_SERVO_ADR			0x84	// A1/0 = 1/0
//#define I2C_MULTIIO_SERVO_ADR			0x86	// A1/0 = 1/1
//#define I2C_MULTIIO_SERVO_ADR			0xe0	// ALLCALLADR

// (Servo power is connected to LED8 of the PCA9685!)
#define CHSERVOPWR						9

// Servo left touch (LT), right touch (RT), middle position (MP) constants:
// (Hints: - Servo impulse length [ms] = Servo position value / 204.8
//           (Formula only valid for a PWM of 50 Hz!)
//         - Min. servo impulse (0,7 ms) = Servo position 143
//         - Mid. servo impulse (1,5 ms) = Servo position 307
//         - Max. servo impulse (2,3 ms) = Servo position 471
//         - !!! You should NOT use servo position values < 143 or > 471 !!!)
#define SERVO1_LT						205		// Servo impulse ~1ms
#define SERVO1_RT						410		// Servo impulse ~2ms
#define SERVO1_MP						((SERVO1_RT - SERVO1_LT) / 2 + SERVO1_LT)
#define SERVO2_LT						205
#define SERVO2_RT						410
#define SERVO2_MP						((SERVO2_RT - SERVO2_LT) / 2 + SERVO2_LT)
#define SERVO3_LT						205
#define SERVO3_RT						410
#define SERVO3_MP						((SERVO3_RT - SERVO3_LT) / 2 + SERVO3_LT)
#define SERVO4_LT						205
#define SERVO4_RT						410
#define SERVO4_MP						((SERVO4_RT - SERVO4_LT) / 2 + SERVO4_LT)
#define SERVO5_LT						205
#define SERVO5_RT						410
#define SERVO5_MP						((SERVO5_RT - SERVO5_LT) / 2 + SERVO5_LT)
#define SERVO6_LT						205
#define SERVO6_RT						410
#define SERVO6_MP						((SERVO6_RT - SERVO6_LT) / 2 + SERVO6_LT)
#define SERVO7_LT						205
#define SERVO7_RT						410
#define SERVO7_MP						((SERVO7_RT - SERVO7_LT) / 2 + SERVO7_LT)
#define SERVO8_LT						205
#define SERVO8_RT						410
#define SERVO8_MP						((SERVO8_RT - SERVO8_LT) / 2 + SERVO8_LT)

/*****************************************************************************/
// I2C EEPROM (24LCXXX):
// (A2=1 not usable with 24LC1024-P!)
#define I2C_MULTIIO_EEPROM_ADR			0xA0	// A2/1/0 = 0/0/0
//#define I2C_MULTIIO_EEPROM_ADR			0xA2	// A2/1/0 = 0/0/1
//#define I2C_MULTIIO_EEPROM_ADR			0xA4	// A2/1/0 = 0/1/0
//#define I2C_MULTIIO_EEPROM_ADR			0xA6	// A2/1/0 = 0/1/1
//#define I2C_MULTIIO_EEPROM_ADR			0xA8	// A2/1/0 = 1/0/0
//#define I2C_MULTIIO_EEPROM_ADR			0xAA	// A2/1/0 = 1/0/1
//#define I2C_MULTIIO_EEPROM_ADR			0xAC	// A2/1/0 = 1/1/0
//#define I2C_MULTIIO_EEPROM_ADR			0xAE	// A2/1/0 = 1/1/1

// I2C-EEPROM storage capacity [kbit]:
#define I2C_EEPROM_KBIT					32		// 24LC32-P <== Default
//#define I2C_EEPROM_KBIT					64		// 24LC64-P
//#define I2C_EEPROM_KBIT					128		// 24LC128-P
//#define I2C_EEPROM_KBIT					256		// 24LC256-P
//#define I2C_EEPROM_KBIT					512		// 24LC512-P
//#define I2C_EEPROM_KBIT					1024	// 24LC1024-P

// I2C-EEPROM pagesize [byte]:
// ATTENTION: The pagesize must fit to the EEPROM type defined above!
#define I2C_EEPROM_PAGESIZE				32		// EEPROM 32 or 64 kbit
//#define I2C_EEPROM_PAGESIZE				64		// EEPROM 128 or 256 kbit
//#define I2C_EEPROM_PAGESIZE				128		// EEPROM 512 kbit
//#define I2C_EEPROM_PAGESIZE				256		// EEPROM 1024 kbit

/*****************************************************************************/
// 3V3 Voltage Sensor:
#define ADC_MULTIIO_3V3					ADC_9	// At ADC-Mxxx
//#define ADC_MULTIIO_3V3					ADC_12	// At ADC-Mxxx
//#define ADC_MULTIIO_3V3					ADC_4	// At ADC-M256

/*****************************************************************************/
// Touch Sensor (with NE555):
#define ADC_MULTIIO_TOUCH				ADC_8	// At ADC-Mxxx
//#define ADC_MULTIIO_TOUCH				ADC_5	// At ADC-M256

#define ADCVAL_NOTOUCH					14
#define ADCVAL_TOUCH					1022
#define ADCVAL_LIMIT_T					((ADCVAL_TOUCH - ADCVAL_NOTOUCH) / 2 + ADCVAL_NOTOUCH)

/*****************************************************************************/
// Buttons:
#define ADC_MULTIIO_BUTTONS				ADC_11	// At ADC-Mxxx

#define ADCVAL_BUTTON1					13
#define ADCVAL_BUTTON2					581
#define ADCVAL_BUTTON3					743
#define ADCVAL_BUTTON4					820
#define ADCVAL_LIMIT12					((ADCVAL_BUTTON2 - ADCVAL_BUTTON1) / 2 + ADCVAL_BUTTON1)
#define ADCVAL_LIMIT23					((ADCVAL_BUTTON3 - ADCVAL_BUTTON2) / 2 + ADCVAL_BUTTON2)
#define ADCVAL_LIMIT34					((ADCVAL_BUTTON4 - ADCVAL_BUTTON3) / 2 + ADCVAL_BUTTON3)
#define ADCVAL_LIMIT40					((1023 - ADCVAL_BUTTON4) / 2 + ADCVAL_BUTTON4)

/*****************************************************************************/
// LEDs:
// (Status LED1..LED4 are connected to LED15..LED12 of the PCA9685!)
#define CHLED1							16
#define CHLED2							15
#define CHLED3							14
#define CHLED4							13

/*****************************************************************************/
// Buzzer:
// (This library assumes that the buzzer is connected to OC2A_PI4 (PB4).
//  This is the case, if you connect IO-Mxxx with IO_PWM/T2/T3 of the M256.
//
//  Possible connections of the buzzer on the MultiIO Project Board:
//
//   M256 plug:    Portpin name:  Portpin:
//   IO_PWM/T2/T3  OC2A_PI4       PB4       <== Default of THIS library!
//   IO_PWM/T0/T1  IO_OC0B        PG5
//   UART_SPI1/T5  IO_PL3_OC5A    PL3
//   UART_SPI2/T4  IO_PH5_OC4C    PH5
//
//  You may of course use one of the other portpins (PG5, PL3, PH5) for the
//  buzzer, but then you will have to write your own buzzer functions!!!
//  Attention: Timer/Counter0 is used by the RP6M256 library, so you may NOT
//             use IO_OC0B (PG5) with hardware PWM!)

/*****************************************************************************/
// Other ADC channel definitions:
// (Depending on jumper settings on the MultiIO Project Board!)
#define ADC_MULTIIO_LDR2				ADC_0	// At ADC-M256
#define ADC_MULTIIO_LDR1				ADC_1	// At ADC-M256
#define ADC_MULTIIO_LFS_R1				ADC_2	// At ADC-M256
#define ADC_MULTIIO_LFS_L1				ADC_3	// At ADC-M256
#define ADC_MULTIIO_SHARP_L				ADC_4	// At ADC-M256
#define ADC_MULTIIO_SHARP_R				ADC_5	// At ADC-M256
#define ADC_MULTIIO_SNAKE_R				ADC_6	// At ADC-M256
#define ADC_MULTIIO_SNAKE_L				ADC_7	// At ADC-M256
#define ADC_MULTIIO_LFS_L				ADC_8	// At ADC-Mxxx
#define ADC_MULTIIO_LFS_M				ADC_9	// At ADC-Mxxx
#define ADC_MULTIIO_LFS_R				ADC_10	// At ADC-Mxxx

// Other IO portpin definitions:
// (Bumper/LEDs in-/outputs at the ADC-Mxxx plug!)
#define IO_MULTIIO_BUMPER_R_IN			IO_PE2_XCK0_AIN0 // At ADC-Mxxx
#define IO_MULTIIO_BUMPER_R_DDR			DDRE
#define IO_MULTIIO_BUMPER_R_PIN			PINE
#define IO_MULTIIO_BUMPER_R_PORT		PORTE

#define IO_MULTIIO_BUMPER_L_IN			IO_PE3_OC3A_AIN1 // At ADC-Mxxx
#define IO_MULTIIO_BUMPER_L_DDR			DDRE
#define IO_MULTIIO_BUMPER_L_PIN			PINE
#define IO_MULTIIO_BUMPER_L_PORT		PORTE

// Other IO portpin definitions:
// (Depending on the IO-Mxxx plug connection. Default: IO_PWM/T2/T3!)
#define IO_MULTIIO_LFS_PWR_IN			IO_PE4_OC3B_I4 // IO-Mxxx: IO_PWM/T2/T3
#define IO_MULTIIO_LFS_PWR_DDR			DDRE
#define IO_MULTIIO_LFS_PWR_PORT			PORTE
//#define IO_MULTIIO_LFS_PWR_IN			OC1B_PI6 // IO-Mxxx: IO_PWM/T0/T1
//#define IO_MULTIIO_LFS_PWR_DDR			DDRB
//#define IO_MULTIIO_LFS_PWR_PORT			PORTB
//#define IO_MULTIIO_LFS_PWR_IN			IO_PL4_OC5B // IO-Mxxx: UART_SPI1/T5
//#define IO_MULTIIO_LFS_PWR_DDR			DDRL
//#define IO_MULTIIO_LFS_PWR_PORT			PORTL
//#define IO_MULTIIO_LFS_PWR_IN			IO_PH3_OC4A // IO-Mxxx: UART_SPI2/T4
//#define IO_MULTIIO_LFS_PWR_DDR			DDRH
//#define IO_MULTIIO_LFS_PWR_PORT			PORTH

#define IO_MULTIIO_SHARPS_PWR_IN		IO_PE6_T3_I6 // IO-Mxxx: IO_PWM/T2/T3
#define IO_MULTIIO_SHARPS_PWR_DDR		DDRE
#define IO_MULTIIO_SHARPS_PWR_PORT		PORTE
//#define IO_MULTIIO_SHARPS_PWR_IN		IO_PD6_T1 // IO-Mxxx: IO_PWM/T0/T1
//#define IO_MULTIIO_SHARPS_PWR_DDR		DDRD
//#define IO_MULTIIO_SHARPS_PWR_PORT		PORTD
//#define IO_MULTIIO_SHARPS_PWR_IN		IO_PL2_T5 // IO-Mxxx: UART_SPI1/T5
//#define IO_MULTIIO_SHARPS_PWR_DDR		DDRL
//#define IO_MULTIIO_SHARPS_PWR_PORT		PORTL
//#define IO_MULTIIO_SHARPS_PWR_IN		IO_PH7_T4 // IO-Mxxx: UART_SPI2/T4
//#define IO_MULTIIO_SHARPS_PWR_DDR		DDRH
//#define IO_MULTIIO_SHARPS_PWR_PORT		PORTH

#define IO_MULTIIO_SNAKE_SWITCH_IN		IO_PE5_OC3C_I5 // IO-Mxxx: IO_PWM/T2/T3
#define IO_MULTIIO_SNAKE_SWITCH_DDR		DDRE
#define IO_MULTIIO_SNAKE_SWITCH_PORT	PORTE
//#define IO_MULTIIO_SNAKE_SWITCH_IN		OC0A_OCM_PI7 // IO-Mxxx: IO_PWM/T0/T1
//#define IO_MULTIIO_SNAKE_SWITCH_DDR		DDRB
//#define IO_MULTIIO_SNAKE_SWITCH_PORT		PORTB
//#define IO_MULTIIO_SNAKE_SWITCH_IN		IO_PD5_XCK1 // IO-Mxxx: UART_SPI1/T5
//#define IO_MULTIIO_SNAKE_SWITCH_DDR		DDRD
//#define IO_MULTIIO_SNAKE_SWITCH_PORT		PORTD
//#define IO_MULTIIO_SNAKE_SWITCH_IN		IO_PH2_XCK2 // IO-Mxxx: UART_SPI2/T4
//#define IO_MULTIIO_SNAKE_SWITCH_DDR		DDRH
//#define IO_MULTIIO_SNAKE_SWITCH_PORT		PORTH

#define IO_MULTIIO_SNAKE_KEY_IN			IO_PH6_OC2B // IO-Mxxx: IO_PWM/T2/T3
#define IO_MULTIIO_SNAKE_KEY_DDR		DDRH
#define IO_MULTIIO_SNAKE_KEY_PIN		PINH
//#define IO_MULTIIO_SNAKE_KEY_IN			OC1A_PI5 // IO-Mxxx: IO_PWM/T0/T1
//#define IO_MULTIIO_SNAKE_KEY_DDR		DDRB
//#define IO_MULTIIO_SNAKE_KEY_PIN		PINB
//#define IO_MULTIIO_SNAKE_KEY_IN			IO_PL5_OC5C // IO-Mxxx: UART_SPI1/T5
//#define IO_MULTIIO_SNAKE_KEY_DDR		DDRL
//#define IO_MULTIIO_SNAKE_KEY_PIN		PINL
//#define IO_MULTIIO_SNAKE_KEY_IN			IO_PH4_OC4B // IO-Mxxx: UART_SPI2/T4
//#define IO_MULTIIO_SNAKE_KEY_DDR		DDRH
//#define IO_MULTIIO_SNAKE_KEY_PIN		PINH

#define IO_MULTIIO_DCF77_IN				IO_PE7_ICP3_I7 // IO-Mxxx: IO_PWM/T2/T3
#define IO_MULTIIO_DCF77_DDR			DDRE
#define IO_MULTIIO_DCF77_PIN			PINE
//#define IO_MULTIIO_DCF77_IN				IO_PD4_ICP1 // IO-Mxxx: IO_PWM/T0/T1
//#define IO_MULTIIO_DCF77_DDR			DDRD
//#define IO_MULTIIO_DCF77_PIN			PIND
//#define IO_MULTIIO_DCF77_IN				IO_PL1_ICP5 // IO-Mxxx: UART_SPI1/T5
//#define IO_MULTIIO_DCF77_DDR			DDRL
//#define IO_MULTIIO_DCF77_PIN			PINL
//#define IO_MULTIIO_DCF77_IN				IO_PL0_ICP4 // IO-Mxxx: UART_SPI2/T4
//#define IO_MULTIIO_DCF77_DDR			DDRL
//#define IO_MULTIIO_DCF77_PIN			PINL

/*****************************************************************************/

#endif

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * 
 *  ---> changes are documented in the file "RP6M256_MultiIOLib.c"
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Library Header

Datei RP6M256_MultiIOLib.h:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * Header file for new MultiIO Project Board library.
 *
 * ****************************************************************************
 */

#ifndef RP6M256_MULTIIOLIB_H
#define RP6M256_MULTIIOLIB_H


/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// Includes:

#include "RP6M256Lib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6M256_MultiIO.h"

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):

// Registers:
#define LTC2990_STATUS					0
#define LTC2990_CONTROL					1
#define LTC2990_TRIGGER					2
#define LTC2990_TINT_MSB				4
#define LTC2990_TINT_LSB				5
#define LTC2990_V1_MSB					6
#define LTC2990_V1_LSB					7
#define LTC2990_V2_MSB					8
#define LTC2990_V2_LSB					9
#define LTC2990_V3_MSB					10
#define LTC2990_V3_LSB					11
#define LTC2990_V4_MSB					12
#define LTC2990_V4_LSB					13
#define LTC2990_VCC_MSB					14
#define LTC2990_VCC_LSB					15

// Status register bitmasks:
#define LTC2990_STATUS_DEFAULT			0
#define LTC2990_STATUS_BUSY				1
#define LTC2990_STATUS_TINT_READY		2
#define LTC2990_STATUS_V1V2_READY		4
#define LTC2990_STATUS_V2_READY			8
#define LTC2990_STATUS_V3V4_READY		16
#define LTC2990_STATUS_V4_READY			32
#define LTC2990_STATUS_VCC_READY		64

// Control register bitmasks:
#define LTC2990_CONTROL_DEFAULT			0
#define LTC2990_CONTROL_MULTIIO			0b01011010 // Mode V1-V2, V3, V4
												   // All measurements per mode
												   // Single acquisition
#define LTC2990_CONTROL_MODE02_DEFAULT	0
#define LTC2990_CONTROL_MODE34_DEFAULT	0
#define LTC2990_CONTROL_REPEAT_SINGLE	64
#define LTC2990_CONTROL_TEMP_FORMAT		128

extern double tint;
extern double cbat;
extern double vbat;
extern double vservo;
extern double vcc;

void LTC2990_write_cfg(uint8_t);
#define LTC2990_init() {LTC2990_write_cfg(LTC2990_CONTROL_MULTIIO);}
void LTC2990_run(void);
void LTC2990_read(void);
void LTC2990_calculate(void);
void LTC2990_measure(void);

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):

// Registers:
#define DS1307_SECONDS					0
#define DS1307_MINUTES					1
#define DS1307_HOURS					2
#define DS1307_DAY						3
#define DS1307_DATE						4
#define DS1307_MONTH					5
#define DS1307_YEAR						6
#define DS1307_CONTROL					7
#define DS1307_RAM						8

// Control register bitmasks:
#define DS1307_CONTROL_DEFAULT			0
#define DS1307_CONTROL_RS0				1
#define DS1307_CONTROL_RS1				2
#define DS1307_CONTROL_SQWE				16
#define DS1307_CONTROL_OUT				128

enum RTCWEEKDAYS {
	R_MO = 1, R_TU, R_WE, R_TH, R_FR, R_SA, R_SU
};

typedef struct {
	uint16_t         year;				// Year
	uint8_t          month;				// Month   [1..12]
	enum RTCWEEKDAYS weekday;			// Weekday [1..7 = R_MO..R_SU]
	uint8_t          day;				// Day     [1..31]
} rtcdate_t;
rtcdate_t rtc_date;

typedef struct {
	uint8_t dst;						// Daylight-saving-time (time zone)
	uint8_t hour;						// Hour    [0..23]
	uint8_t minute;						// Minute  [0..59]
	uint8_t second;						// Second  [0..59]
} rtctime_t;
rtctime_t rtc_time;

uint8_t BCD2DEC(uint8_t);
uint8_t DEC2BCD(uint8_t);
void DS1307_write_cfg(uint8_t);
void DS1307_init(void);
#define CALC_DST						// Time zone will be calculated
void DS1307_read(void);
void DS1307_write(void);
uint8_t DS1307_readRAM(uint8_t);
void DS1307_writeRAM(uint8_t, uint8_t);

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):

// Registers:
#define TCN75_TEMP						0
#define TCN75_CONFIG					1
#define TCN75_HYST						2
#define TCN75_LIMIT						3

// Config register bitmasks:
#define TCN75_CONFIG_RUN				0		// Default
#define TCN75_CONFIG_SHUTDOWN			1
#define TCN75_CONFIG_COMP				0		// Default
#define TCN75_CONFIG_INT				2
#define TCN75_CONFIG_ALERT_LOW			0		// Default
#define TCN75_CONFIG_ALERT_HIGH			4
#define TCN75_CONFIG_FAULT_1			0		// Default
#define TCN75_CONFIG_FAULT_2			8
#define TCN75_CONFIG_FAULT_4			16
#define TCN75_CONFIG_FAULT_6			24

// Only for the TCN75A - high resolution and OneShot mode:
#define TCN75A_CONFIG_RES_9				0		// Default
#define TCN75A_CONFIG_RES_10			32		// 0b00100000
#define TCN75A_CONFIG_RES_11			64		// 0b01000000
#define TCN75A_CONFIG_RES_12			96		// 0b01100000
#define TCN75A_CONFIG_ONESHOT_DISABLED	0		// Default
#define TCN75A_CONFIG_ONESHOT			128		// 0b10000000

extern double temperature;

void TCN75_write_cfg(uint8_t);
#define TCN75_shutdown() {TCN75_write_cfg(TCN75_CONFIG_SHUTDOWN);}
#define TCN75_run(__CONFIG__) {TCN75_write_cfg(__CONFIG__);}
extern uint8_t temperature_low;
extern uint8_t temperature_high;
#define getTemperatureHigh() (temperature_high)
#define getTemperatureLow() (temperature_low)
void TCN75_read(void);
double TCN75_calculate(void);
double TCN75_measure(void);

/*****************************************************************************/
// I2C Servo Controller (PCA9685):

// Registers:
#define PCA9685_MODE1					0
#define PCA9685_MODE2					1
#define PCA9685_SUBADR1					2
#define PCA9685_SUBADR2					3
#define PCA9685_SUBADR3					4
#define PCA9685_ALLCALLADR				5
#define PCA9685_LED0_ON_L				6
#define PCA9685_LED0_ON_H				7
#define PCA9685_LED0_OFF_L				8
#define PCA9685_LED0_OFF_H				9
#define PCA9685_LED1_ON_L				10
#define PCA9685_LED1_ON_H				11
#define PCA9685_LED1_OFF_L				12
#define PCA9685_LED1_OFF_H				13
#define PCA9685_LED2_ON_L				14
#define PCA9685_LED2_ON_H				15
#define PCA9685_LED2_OFF_L				16
#define PCA9685_LED2_OFF_H				17
#define PCA9685_LED3_ON_L				18
#define PCA9685_LED3_ON_H				19
#define PCA9685_LED3_OFF_L				20
#define PCA9685_LED3_OFF_H				21
#define PCA9685_LED4_ON_L				22
#define PCA9685_LED4_ON_H				23
#define PCA9685_LED4_OFF_L				24
#define PCA9685_LED4_OFF_H				25
#define PCA9685_LED5_ON_L				26
#define PCA9685_LED5_ON_H				27
#define PCA9685_LED5_OFF_L				28
#define PCA9685_LED5_OFF_H				29
#define PCA9685_LED6_ON_L				30
#define PCA9685_LED6_ON_H				31
#define PCA9685_LED6_OFF_L				32
#define PCA9685_LED6_OFF_H				33
#define PCA9685_LED7_ON_L				34
#define PCA9685_LED7_ON_H				35
#define PCA9685_LED7_OFF_L				36
#define PCA9685_LED7_OFF_H				37
#define PCA9685_LED8_ON_L				38
#define PCA9685_LED8_ON_H				39
#define PCA9685_LED8_OFF_L				40
#define PCA9685_LED8_OFF_H				41
#define PCA9685_LED9_ON_L				42
#define PCA9685_LED9_ON_H				43
#define PCA9685_LED9_OFF_L				44
#define PCA9685_LED9_OFF_H				45
#define PCA9685_LED10_ON_L				46
#define PCA9685_LED10_ON_H				47
#define PCA9685_LED10_OFF_L				48
#define PCA9685_LED10_OFF_H				49
#define PCA9685_LED11_ON_L				50
#define PCA9685_LED11_ON_H				51
#define PCA9685_LED11_OFF_L				52
#define PCA9685_LED11_OFF_H				53
#define PCA9685_LED12_ON_L				54
#define PCA9685_LED12_ON_H				55
#define PCA9685_LED12_OFF_L				56
#define PCA9685_LED12_OFF_H				57
#define PCA9685_LED13_ON_L				58
#define PCA9685_LED13_ON_H				59
#define PCA9685_LED13_OFF_L				60
#define PCA9685_LED13_OFF_H				61
#define PCA9685_LED14_ON_L				62
#define PCA9685_LED14_ON_H				63
#define PCA9685_LED14_OFF_L				64
#define PCA9685_LED14_OFF_H				65
#define PCA9685_LED15_ON_L				66
#define PCA9685_LED15_ON_H				67
#define PCA9685_LED15_OFF_L				68
#define PCA9685_LED15_OFF_H				69
#define PCA9685_ALL_LED_ON_L			250
#define PCA9685_ALL_LED_ON_H			251
#define PCA9685_ALL_LED_OFF_L			252
#define PCA9685_ALL_LED_OFF_H			253
#define PCA9685_PRE_SCALE				254
#define PCA9685_TESTMODE				255

// Mode1 register bitmasks:
#define PCA9685_MODE1_ALLCALL			1
#define PCA9685_MODE1_SUB3				2
#define PCA9685_MODE1_SUB2				4
#define PCA9685_MODE1_SUB1				8
#define PCA9685_MODE1_SLEEP				16
#define PCA9685_MODE1_AI				32
#define PCA9685_MODE1_EXTCLK			64
#define PCA9685_MODE1_RESTART			128

// Mode2 register bitmasks:
#define PCA9685_MODE2_OUTNE01_DEFAULT	0
#define PCA9685_MODE2_OUTDRV			4
#define PCA9685_MODE2_OCH				8
#define PCA9685_MODE2_INVRT				16

#define F_PCA9685						25000000.0	// Int. Clock: 25 MHz

void PCA9685_init(uint16_t);
#define initServo(__FREQ__) {PCA9685_init(__FREQ__);}
void PCA9685_set(uint8_t, uint16_t);
#define setServo(__SERVO__,__POS__) {PCA9685_set(__SERVO__,__POS__);}
void PCA9685_shutdown(void);
void PCA9685_restart(void);
void setServoPower(uint8_t);

/*****************************************************************************/
// I2C EEPROM (24LCXXX):

uint8_t I2C_EEPROM_readByte(uint16_t memAddr);
void I2C_EEPROM_writeByte(uint16_t memAddr, uint8_t data);
void I2C_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length);
void I2C_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length);

/*****************************************************************************/
// 3V3 Voltage Sensor:

extern uint16_t adc3v3;
extern double v3v3;

uint16_t get3V3Sensor(void);
double calculate3V3(void);
double measure3V3(void);

/*****************************************************************************/
// Touch Sensor (with NE555):

extern uint16_t adcTouch;
extern uint8_t touch;

uint8_t getTouch(void);

/*****************************************************************************/
// Buttons:

extern uint16_t adcButtons;
extern uint8_t releasedButtonNumber;
extern uint8_t pressedButtonNumber;

uint8_t getPressedButtonNumber(void);
uint8_t checkPressedButtonEvent(void);
uint8_t checkReleasedButtonEvent(void);

/*****************************************************************************/
// LEDs:

void setMultiIOLEDs(uint8_t leds);

void dimMultiIOLED(uint8_t led, uint16_t duty);
void setMultiIOLED1(uint8_t led);
void setMultiIOLED2(uint8_t led);
void setMultiIOLED3(uint8_t led);
void setMultiIOLED4(uint8_t led);

/*****************************************************************************/
// Buzzer:

// Define tone frequencies (well temperament):
// Great Octave
#define Tone_H      2       // 123Hz
// Small Octave
#define Tone_c      16      // 131Hz
#define Tone_cis    30      // 139Hz
#define Tone_d      42      // 147Hz
#define Tone_dis    54      // 156Hz
#define Tone_e      65      // 165Hz
#define Tone_f      76      // 175Hz
#define Tone_fis    86      // 185Hz
#define Tone_g      96      // 196Hz
#define Tone_gis    105     // 208Hz
#define Tone_a      113     // 220Hz
#define Tone_ais    121     // 233Hz
#define Tone_h      128     // 247Hz
// ' Octave
#define Tone_C1     136     // 262Hz
#define Tone_Cis1   142     // 277Hz
#define Tone_D1     149     // 294Hz
#define Tone_Dis1   155     // 311Hz
#define Tone_E1     160     // 330Hz
#define Tone_F1     166     // 349Hz
#define Tone_Fis1   171     // 370Hz
#define Tone_G1     175     // 392Hz
#define Tone_Gis1   180     // 415Hz
#define Tone_A1     184     // 440Hz
#define Tone_Ais1   188     // 466Hz
#define Tone_H1     192     // 494Hz
// '' Octave
#define Tone_C2     195     // 523Hz
#define Tone_Cis2   199     // 554Hz
#define Tone_D2     202     // 587Hz
#define Tone_Dis2   205     // 622Hz
#define Tone_E2     208     // 659Hz
#define Tone_F2     210     // 698Hz
#define Tone_Fis2   213     // 740Hz
#define Tone_G2     215     // 784Hz
#define Tone_Gis2   217     // 831Hz
#define Tone_A2     219     // 880Hz
#define Tone_Ais2   221     // 932Hz
#define Tone_H2     223     // 988Hz
// ''' Octave
#define Tone_C3     225     // 1047Hz
#define Tone_Cis3   227     // 1109Hz
#define Tone_D3     228     // 1175Hz
#define Tone_Dis3   230     // 1245Hz
#define Tone_E3     231     // 1319Hz
#define Tone_F3     233     // 1397Hz
#define Tone_Fis3   234     // 1480Hz
#define Tone_G3     235     // 1568Hz
#define Tone_Gis3   236     // 1661Hz
#define Tone_A3     237     // 1760Hz
#define Tone_Ais3   238     // 1865Hz
#define Tone_H3     239     // 1976Hz
// '''' Octave
#define Tone_C4     240     // 2093Hz
#define Tone_Cis4   241     // 2217Hz
#define Tone_D4     242     // 2349Hz
#define Tone_Dis4   242     // 2489Hz
#define Tone_E4     243     // 2637Hz
#define Tone_F4     244     // 2794Hz
#define Tone_Fis4   244     // 2960Hz
#define Tone_G4     245     // 3136Hz
#define Tone_Gis4   246     // 3322Hz
#define Tone_A4     246     // 3520Hz
#define Tone_Ais4   247     // 3729Hz
#define Tone_H4     247     // 3951Hz
// ''''' Octave
#define Tone_C5     248     // 4186Hz

void Buzzer_init(void);
void setBuzzerPitch(uint8_t);
void soundBuzzer(uint8_t, uint16_t, uint16_t);
#define buzzer(__PITCH__,__TIME__) {soundBuzzer(__PITCH__,__TIME__,0);}

/*****************************************************************************/
// MultiIO Project Board initialisation:

void multiio_init(void);

/*****************************************************************************/

#endif

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * 
 *  ---> changes are documented in the file "RP6M256_MultiIOLib.c"
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Library Source

Datei RP6M256_MultiIOLib.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * 
 * This is our new Library that contains basic routines and functions for
 * accessing the hardwired components of the MultiIO Project Board.
 *
 * There are much more sensors, that may be connected to the MultiIO Project
 * Board: Line following sensors (5x CNY70), bumpers, "Snake Vision board",
 *        LDRs, I2C air pressure sensor, I2C humidity sensor, DCF77 module,
 *        I2C IMU, I2C ultrasonic distance sensors, GPS module and more
 *        sensors connected to free ADCs and IOs and to the I2C bus.
 * This library doesn't contain functions for these sensors, because they are
 * not HARDWIRED to the MultiIO Project Board and may be connected OPTIONALLY.
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// Includes:

#include "RP6M256_MultiIOLib.h" 		

/*****************************************************************************/
// Variables:

uint8_t registerBuf[13]; 

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):

/**
 * Sends the configuration byte to a LTC2990.
 *
 * Input: Config byte for control register
 *
 * There is also a macro LTC2990_init(), which
 * initializes the sensor to work in V1-V2, V3,
 * V4 and Single Acquisition mode.
 *
 * Example:
 *   LTC2990_init();
 *
 */
void LTC2990_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_VCS_ADR, LTC2990_CONTROL, config);
}

uint8_t vcs_tint_low;
uint8_t vcs_tint_high;
uint8_t vcs_v1_low;
uint8_t vcs_v1_high;
uint8_t vcs_v2_low;
uint8_t vcs_v2_high;
uint8_t vcs_v3_low;
uint8_t vcs_v3_high;
uint8_t vcs_v4_low;
uint8_t vcs_v4_high;
uint8_t vcs_vcc_low;
uint8_t vcs_vcc_high;

/**
 * Starts a Single Acquisition measurement.
 */
void LTC2990_run(void)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_VCS_ADR, LTC2990_TRIGGER, 0);
}

/**
 * Reads all data registers of the voltage & current
 * sensor (VCS).
 * They are stored in the variables defined above.
 */
void LTC2990_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_VCS_ADR, LTC2990_TINT_MSB);
	I2CTWI_readBytes(I2C_MULTIIO_VCS_ADR, registerBuf, 12);
	vcs_tint_high = registerBuf[0];
	vcs_tint_low = registerBuf[1];
	vcs_v1_high = registerBuf[2];
	vcs_v1_low = registerBuf[3];
	vcs_v2_high = registerBuf[4];
	vcs_v2_low = registerBuf[5];
	vcs_v3_high = registerBuf[6];
	vcs_v3_low = registerBuf[7];
	vcs_v4_high = registerBuf[8];
	vcs_v4_low = registerBuf[9];
	vcs_vcc_high = registerBuf[10];
	vcs_vcc_low = registerBuf[11];
}

double tint;							// Internal temperature
double cbat;							// Current at 9V
double vbat;							// Battery voltage 9V (BAT)
double vservo;							// Servo voltage 5 .. 7.5V
double vcc;								// Voltage 5V (VCC)

/**
 * Calculates the temperature, voltage and current
 * values by using the data read from the LTC2990
 * with the function LTC2990_read(). The sensor is
 * configured to work in V1-V2, V3, V4 and Single
 * Acquisition mode.
 * The result is stored in the double variables
 * defined above.
 */
void LTC2990_calculate(void)
{
	int16_t tmp, tmp2;
	double v1, v2;

	tmp = (((vcs_tint_high & 0x1f) << 8) + vcs_tint_low) << 3;
	tmp = tmp / 8;
	tint = tmp / 16.0;							// Internal temperature [°C]

	tmp = (((vcs_v1_high & 0x7f) << 8) + vcs_v1_low) << 1;
	tmp = tmp / 2;
	v1 = tmp * 0.01942;
	v1 *= V1_ADJUST;							// Voltage divider factor
	tmp2 = (((vcs_v2_high & 0x7f) << 8) + vcs_v2_low) << 1;
	tmp2 = tmp2 / 2;
	v2 = tmp * 0.01942;
	v2 *= V2_ADJUST;							// Voltage divider factor
	cbat = (v1 - v2) / SHUNT_R;				// Battery current [mA]

	tmp = ((vcs_v3_high & 0x3f) << 8) + vcs_v3_low;
	vbat = tmp * 0.00030518;					// Battery voltage [V]
	vbat *= VBAT_ADJUST;						// Voltage divider factor

	tmp = ((vcs_v4_high & 0x3f) << 8) + vcs_v4_low;
	vservo = tmp * 0.00030518;					// Servo voltage [V]
	vservo *= VSERVO_ADJUST;					// Voltage divider factor

	tmp = ((vcs_vcc_high & 0x3f) << 8) + vcs_vcc_low;
	vcc = 2.5 + tmp * 0.00030518;				// VCC [V]
}

/**
 * Performs a complete measurement with the sensor
 * configured to work in V1-V2, V3, V4 and Single
 * Acquisition mode.
 * The result is stored in the double variables
 * defined above.
 * This function is BLOCKING for about 200 ms!
 * If you don't want a blocking measurement, you
 * have to write your own function with a non
 * blocking pause between starting measurement
 * and reading the result or with another mode
 * of operation (Repeated Acquisitions).
 */
void LTC2990_measure(void)
{
	LTC2990_run();								// Start measurement
	mSleep(200);
	LTC2990_read();								// Read data
	LTC2990_calculate();						// Calculate values
}

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):

/**
 * This function converts a BCD to a DEC value.
 *
 */
uint8_t BCD2DEC(uint8_t bcd)
{
	return ((bcd >> 4) * 10 + (bcd & 0x0f));
}

/**
 * This function converts a DEC to a BCD value.
 *
 */
uint8_t DEC2BCD(uint8_t dec)
{uint8_t units = dec % 10;
	if (dec /= 10) {
		return (units + (DEC2BCD(dec) << 4));
	}
	else {
		return units;
	}
}

/**
 * Sends the configuration byte to a DS1307.
 *
 * Input: Config byte for control register
 *
 */
void DS1307_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_RTC_ADR, DS1307_CONTROL, config);
}

/**
 * Initializes the DS1307 by resetting all registers.
 * Only use this function ONCE for a DS1307 without or
 * with empty backup battery!
 */
void DS1307_init(void)
{
	uint8_t i;

	for (i = 0; i < 8; i++) {
		registerBuf[i] = 0;
	}
	I2CTWI_transmitBytes(I2C_MULTIIO_RTC_ADR, &registerBuf[0], 8);
}

/**
 * Reads all data registers of the Real Time Clock (RTC).
 * They are stored in the time & date variables defined in
 * the library header.
 */
void DS1307_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_RTC_ADR, DS1307_SECONDS);
	I2CTWI_readBytes(I2C_MULTIIO_RTC_ADR, registerBuf, 7);
	rtc_time.second = BCD2DEC(registerBuf[0] & 0x7f);
	rtc_time.minute = BCD2DEC(registerBuf[1]);
	rtc_time.hour = BCD2DEC(registerBuf[2] & 0x3f);
	rtc_date.weekday = registerBuf[3];
	rtc_date.day = BCD2DEC(registerBuf[4]);
	rtc_date.month = BCD2DEC(registerBuf[5]);
	rtc_date.year = BCD2DEC(registerBuf[6]) + 2000;
	rtc_time.dst = 0;
#ifdef CALC_DST
	// Calculate MESZ (DST):
	uint8_t wday = rtc_date.weekday;			// Weekday [1..7 = R_MO..R_SU]
	if(wday == 7) wday = 0;
	if(rtc_date.month < 3 || rtc_date.month > 10) {
		return;
	}
	if((rtc_date.day - wday >= 25)
	 && (wday || rtc_time.hour >= 2)) {
		if(rtc_date.month == 10)
			return;
	}
	else {
		if(rtc_date.month == 3) {
			return;
		}
	}
	rtc_time.dst = 1;
#endif
}

/**
 * Writes the time & date infos in the variables defined in
 * the library header to the Real Time Clock (RTC).
 */
void DS1307_write(void)
{
	registerBuf[0] = DS1307_SECONDS;
	registerBuf[1] = DEC2BCD(rtc_time.second);
	registerBuf[2] = DEC2BCD(rtc_time.minute);
	registerBuf[3] = DEC2BCD(rtc_time.hour);
	registerBuf[4] = rtc_date.weekday;
	registerBuf[5] = DEC2BCD(rtc_date.day);
	registerBuf[6] = DEC2BCD(rtc_date.month);
	registerBuf[7] = DEC2BCD(rtc_date.year - 2000);
	I2CTWI_transmitBytes(I2C_MULTIIO_RTC_ADR, &registerBuf[0], 8);
}

/**
 * Reads and returns a data byte from the DS1307 RAM.
 *
 * Input: adr -> RAM address [0..55]
 *
 * Hints: - The real DS1307 RAM addresses are 8..63!
 *        - The RAM is nonvolatile. That means, that
 *          it keeps the data as long as the backup
 *          battery doesn't become weak!
 *
 */
uint8_t DS1307_readRAM(uint8_t adr)
{
	if (adr > 55) adr = 0;
	I2CTWI_transmitByte(I2C_MULTIIO_RTC_ADR, (DS1307_RAM + adr));
	return (I2CTWI_readByte(I2C_MULTIIO_RTC_ADR));
}

/**
 * Writes a data byte to the DS1307 RAM.
 *
 * Input: adr  -> RAM address [0..55]
 *        data -> Data byte [0..255]
 *
 * Hints: - The real DS1307 RAM addresses are 8..63!
 *        - The RAM is nonvolatile. That means, that
 *          it keeps the data as long as the backup
 *          battery doesn't become weak!
 *
 */
void DS1307_writeRAM(uint8_t adr, uint8_t data)
{
	if (adr > 55) adr = 0;
	I2CTWI_transmit2Bytes(I2C_MULTIIO_RTC_ADR, (DS1307_RAM + adr), data);
}

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):

/**
 * Sends the configuration byte to a TCN75A.
 *
 * Input: Config byte for config register
 *
 */
void TCN75_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_TEMP_ADR, TCN75_CONFIG, config);
}

uint8_t temperature_low;
uint8_t temperature_high;

/**
 * Reads the two data registers of the temperature
 * sensor.
 * They are stored in the variables temperature_low
 * and _high.
 *
 * Hint: Depending on the sensor configuration the
 *       data are located different in the two bytes
 *       - have a look at the datasheet!
 *
 */
void TCN75_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_TEMP_ADR, TCN75_TEMP);
	I2CTWI_readBytes(I2C_MULTIIO_TEMP_ADR, registerBuf, 2);
	temperature_low = registerBuf[0];
	temperature_high = registerBuf[1];
}

double temperature;						// Temperature [°C]

/**
 * Calculates and returns the temperature value
 * by using the data read from the TCN75A with
 * the function TCN75_read(). The sensor is
 * configured to Single Conversion and 12 bit
 * measurement.
 */
double TCN75_calculate(void)
{
	uint8_t templow;
	double temp;

	templow = getTemperatureLow();
	if (templow & 128)							// Calculate temperature
		templow = (templow & 63) - 127;
	else
		templow = templow & 63;
	temp = templow + (0.0625 * (getTemperatureHigh() >> 4));
	return temp;
}

/**
 * Performs a 12 bit measurement and returns the
 * temperature [°C].
 * This function is BLOCKING for about 250 ms!
 * If you don't want a blocking measurement, you
 * have to write your own function with a non
 * blocking pause between starting measurement
 * and reading the result or with another mode
 * of operation (Continuous Conversion).
 */
double TCN75_measure(void)
{
	TCN75_run(TCN75A_CONFIG_RES_12);			// Start measurement
	mSleep(250);
	TCN75_shutdown();							// Stop measurement
	TCN75_read();								// Read data
	return (TCN75_calculate());					// Calculate value
}

/*****************************************************************************/
// I2C Servo Controller (PCA9685):

/**
 * Call this once before using the servo function.
 *
 * Input: PWM frequency [40..1000 Hz]
 *
 * Hints: - Default servo frequency is 50 Hz!
 *        - The servo power is NOT switched on by
 *          this function!
 *
 * There is also a macro initServo(freq), which
 * does exactly the same as this function.
 *
 * Example:
 *   initServo(50);
 *
 */
void PCA9685_init(uint16_t freq)
{
	if ((freq < 40) || (freq > 1000)) freq = 50;
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE2);
	uint8_t last_mode = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	last_mode &= ~PCA9685_MODE2_INVRT;			// Clear INVRT bit
	last_mode |= PCA9685_MODE2_OUTDRV;			// Set OUTDRV bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE2, last_mode);
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	last_mode = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	last_mode |= PCA9685_MODE1_AI;				// Set AI bit
	uint8_t mode1 = last_mode;
	mode1 |= PCA9685_MODE1_SLEEP;				// Set SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
	uint8_t prescale = (uint8_t) (F_PCA9685 / 4096 / freq - 0.5);
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_PRE_SCALE, prescale);
	last_mode &= ~PCA9685_MODE1_SLEEP;			// Clear SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, last_mode);
	mSleep(1);
	last_mode |= PCA9685_MODE1_RESTART;			// Clear RESTART bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, last_mode);
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_ON_H, 0x10);
	return;
}

/**
 * This is the servo position set function.
 *
 * Input: servo -> Servo number [1..8, 10..16]
 *        pos   -> Servo position [SERVOx_LT..SERVOx_RT]
 *
 * Hints: - Servo number 9 cannot be set by this function!
 *          Please use setServoPower() function instead!
 *        - A servo position of 205 means 1 ms servo impulse,
 *          a position of 410 means a 2 ms servo impulse!
 *          You may calculate the servo impulse length by:
 *          ==> Impulse [ms] = servo position / 204.8 <==
 *          (Formula only valid for a PWM of 50 Hz!)
 *
 * There is also a macro setServo(servo, pos), which
 * does exactly the same as this function.
 *
 * Example:
 *   setServo(2,300);
 *
 */
void PCA9685_set(uint8_t servo, uint16_t pos)
{
	if ((servo == 0) || (servo == CHSERVOPWR) || (servo > 16))
		return;
	uint8_t reg = servo * 4 + 4;				// Register LEDx_OFF_L
	I2CTWI_transmit3Bytes(I2C_MULTIIO_SERVO_ADR, reg, (pos & 0x00ff), (pos >> 8));
}

/**
 * If the servos are not moving for a while, the
 * servo function can be stopped with this
 * function (PCA9685 set to sleep mode).
 *
 * Hint: The servo power is NOT switched off by
 *       this function!
 *
 */
void PCA9685_shutdown(void)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_ALL_LED_OFF_H, 0x10);
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	uint8_t mode1 = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	mode1 |= PCA9685_MODE1_SLEEP;				// Set SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
}

/**
 * If the servo function was stopped with the
 * function PCA9685_shutdown() before, it can be
 * (re)started again with this function.
 *
 * Hint: The servo power is NOT switched on by
 *       this function!
 *
 */
void PCA9685_restart(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	uint8_t mode1 = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	if (mode1 & PCA9685_MODE1_RESTART) {		// RESTART bit set?
		mode1 &= ~PCA9685_MODE1_SLEEP;			// Clear SLEEP bit
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
		mSleep(1);
		mode1 |= PCA9685_MODE1_RESTART;			// Clear RESTART bit
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_ALL_LED_OFF_H, 0);
	}
}

/** 
 * With this function you can switch the servo
 * power on or off, if the servo power jumper on
 * the board enables this feature.
 *
 * Input: pwr -> 0 (false) = servo power off
 *               >0 (true) = servo power on
 *
 * Hints: - If connected servos are not used, you
 *          should always switch the servo power off
 *          to save energy!
 *        - The PCA9685 is NOT restarted or put into
 *          shutdown mode by this function!
 *
 */
void setServoPower(uint8_t pwr)
{
	if (pwr > 0)
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_OFF_H, 0);
	else
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_OFF_H, 0x10);
}	

/*****************************************************************************/
// I2C EEPROM (24LCXXX):

// The following EEPROM types may be used:
//  EEPROM Size:  Chip              Pagesize
//  -   32 kbit:  ST24LC32A            32
//  -   64 kbit:  ST24LC64             32
//  -  128 kbit:  ST24LC128            64
//  -  256 kbit:  ST24LC256            64
//  -  512 kbit:  ST24LC512           128
//  - 1024 kbit:  AT24LC1024          256
// ! You may choose the EEPROM type in the I2C EEPROM !
// ! section of the RP6M256_MultiIO.h file!           !

/**
 * Reads a single Byte from the EEPROM.
 */
uint8_t I2C_EEPROM_readByte(uint16_t memAddr)
{
	uint8_t data;
	I2CTWI_transmit2Bytes(I2C_MULTIIO_EEPROM_ADR, (memAddr >> 8), memAddr);
	data = I2CTWI_readByte(I2C_MULTIIO_EEPROM_ADR);
	return data;
}

/**
 * Write a single data byte to the specified EEPROM address.
 */
void I2C_EEPROM_writeByte(uint16_t memAddr, uint8_t data)
{
	I2CTWI_transmit3Bytes(I2C_MULTIIO_EEPROM_ADR, (memAddr >> 8), memAddr, data);
	mSleep(5);
}

/**
 * Reads "length" Bytes into the Buffer "buffer" from startAddr on. 
 * You can read the complete EEPROM into a buffer at once - if it is large enough. 
 * (But you only have 8KB SRAM on a MEGA2560 ;) )
 * If "length" is higher than I2CTWI_BUFFER_REC_SIZE defined in RP6I2CmasterTWI.h,
 * you have to adapt I2CTWI_BUFFER_REC_SIZE to the highest used "length" value!
 */
void I2C_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_EEPROM_ADR, (startAddr >> 8), startAddr);
	I2CTWI_readBytes(I2C_MULTIIO_EEPROM_ADR, &buffer[0], length);
}

/**
 * Write "length" Bytes from the Buffer to the EEPROM. 
 * YOU CAN ONLY WRITE MAXIMAL [I2C_EEPROM_PAGESIZE] BYTES AT ONCE!!!
 * This is the Pagesize!
 * You can NOT cross a page boundary!
 * If (length + 2) is higher than I2CTWI_BUFFER_SIZE defined in RP6I2CmasterTWI.h,
 * you have to adapt I2CTWI_BUFFER_SIZE to the highest used (length + 2) value!
 */
void I2C_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length)
{
	uint8_t i, addrbuffer[length + 2];
	addrbuffer[0] = (startAddr >> 8);
	addrbuffer[1] = startAddr;
	for(i = 0; i < length; i++) {
		addrbuffer[i + 2] = buffer[i];
	}
	I2CTWI_transmitBytes(I2C_MULTIIO_EEPROM_ADR, &addrbuffer[0], (length + 2));
	mSleep(5);
}

/*****************************************************************************/
// 3V3 Voltage Sensor:

uint16_t adc3v3;						// 3V3 voltage sensor ADC value

/**
 * This function reads and returns the ADC value of
 * the 3V3 voltage sensor. The value is also stored
 * in adc3v3.
 *
 */
uint16_t get3V3Sensor(void)
{
	adc3v3 = readADC(ADC_MULTIIO_3V3);
	return adc3v3;
}

double v3v3;							// 3V3 voltage [V]

/**
 * Calculates and returns the 3.3V voltage value
 * by using the data read from the 3V3 voltage
 * sensor with the function get3V3Sensor().
 *
 */
double calculate3V3(void)
{
	return (5.0 / 1024.0 * adc3v3);
}

/**
 * Measures and returns the 3.3V voltage value.
 * The ADC value of the 3V3 voltage sensor is also
 * stored in adc3v3.
 *
 */
double measure3V3(void)
{
	adc3v3 = readADC(ADC_MULTIIO_3V3);
	return (5.0 / 1024.0 * adc3v3);
}

/*****************************************************************************/
// Touch Sensor (with NE555):

uint16_t adcTouch;						// Touch sensor ADC value
uint8_t touch = 0;						// True (1), if touched

/**
 * Checks if the touch sensor antenna is touched - returns 1,
 * if touched or 0, if the antenna is NOT touched.
 *
 */
uint8_t getTouch(void)
{
	adcTouch = readADC(ADC_MULTIIO_TOUCH);
	if (adcTouch > ADCVAL_LIMIT_T) return 1;
	else return 0;
}

/*****************************************************************************/
// Buttons:

uint16_t adcButtons;					// Keypad ADC value
uint8_t releasedButtonNumber;			// Released (last pressed) button
uint8_t pressedButtonNumber;			// Actually pressed button

/**
 * Checks which button is pressed - returns the button number,
 * or 0, if no button is pressed.
 * Maybe the values of ADCVAL_LIMITxx have to change because
 * of variations in the resistors of the keypad! This is done
 * in RP6M256_MultiIO.h, if you define other ADC values for
 * your 4 buttons in ADCVAL_BUTTON1..ADCVAL_BUTTON4.
 *
 */
uint8_t getPressedButtonNumber(void)
{
	adcButtons = readADC(ADC_MULTIIO_BUTTONS);
	if(adcButtons < 1020) {
		nop();
		nop();
		nop();
		adcButtons += readADC(ADC_MULTIIO_BUTTONS);
		adcButtons >>= 1;
	}
	if(adcButtons < ADCVAL_LIMIT12)
		return 1;
	if(adcButtons < ADCVAL_LIMIT23)
		return 2;
	if(adcButtons < ADCVAL_LIMIT34)
		return 3;
	if(adcButtons < ADCVAL_LIMIT40)
		return 4;
	return 0;
}

/**
 * This function has to be called frequently out of the
 * main loop and checks if a button is pressed! It only returns 
 * the button number a single time, DIRECTLY when the button is
 * pressed.
 * 
 * This is useful for non-blocking keyboard check in the
 * main loop. You don't need something like 
 * "while(getPressedButtonNumber());" to wait for the button
 * to be released again!
 */
uint8_t checkPressedButtonEvent(void)
{
	static uint8_t pressed_button = 0;
	if(pressed_button) {
		if(!getPressedButtonNumber()) 
			pressed_button = 0;
	}
	else {
		pressed_button = getPressedButtonNumber();
		if(pressed_button)
			return pressed_button;
	}
	return 0;
}

/**
 * This function has to be called frequently out of
 * the main loop and checks if a button is pressed AND
 * released. It only returns the button number a single
 * time, AFTER the button has been released.
 * 
 * This is useful for non-blocking keyboard check in the
 * main loop. You don't need something like 
 * "while(getPressedButtonNumber());" to wait for the button
 * to be released again!
 */
uint8_t checkReleasedButtonEvent(void)
{
	static uint8_t released_button = 0;
	if(released_button) {
		if(!getPressedButtonNumber()) {
			uint8_t tmp = released_button;
			released_button = 0;
			return tmp;
		}
	}
	else
		released_button = getPressedButtonNumber();
	return 0;
}

/*****************************************************************************/
// LEDs:

/** 
 * Set the 4 status LEDs of the MultiIO.
 *
 * Example:
 *			setMultiIOLEDs(0b1010);
 *			// this clears LEDs 1 and 3
 *          // and sets LEDs 2 and 4!
 *
 */
void setMultiIOLEDs(uint8_t leds)
{
	if (leds & 0b00000001) PCA9685_set(CHLED1, 4095);
	else PCA9685_set(CHLED1, 0);
	if (leds & 0b00000010) PCA9685_set(CHLED2, 4095);
	else PCA9685_set(CHLED2, 0);
	if (leds & 0b00000100) PCA9685_set(CHLED3, 4095);
	else PCA9685_set(CHLED3, 0);
	if (leds & 0b00001000) PCA9685_set(CHLED4, 4095);
	else PCA9685_set(CHLED4, 0);
}

/** 
 * Dim the 4 status LEDs of the MultiIO.
 *
 * Input: led  -> LED number [1..4]
 *        duty -> Duty cycle [0..4095]
 *
 * Example:
 *			dimMultiIOLED(2,2048);
 *			// this dims LED2 with a
 *          // duty cycle of 50% !
 *
 */
void dimMultiIOLED(uint8_t led, uint16_t duty)
{
	if (led == 1) PCA9685_set(CHLED1, duty);
	if (led == 2) PCA9685_set(CHLED2, duty);
	if (led == 3) PCA9685_set(CHLED3, duty);
	if (led == 4) PCA9685_set(CHLED4, duty);
}

/** 
 * Set ONLY LED1, don't change anything for the other LEDs.
 *
 * Input: led -> 0 (false) = LED off
 *               >0 (true) = LED on
 *
 */
void setMultiIOLED1(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED1, 4095); 
	else PCA9685_set(CHLED1, 0);	
}	

/** 
 * Set ONLY LED2, don't change anything for the other LEDs.
 */
void setMultiIOLED2(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED2, 4095); 
	else PCA9685_set(CHLED2, 0);	
}	

/** 
 * Set ONLY LED3, don't change anything for the other LEDs.
 */
void setMultiIOLED3(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED3, 4095); 
	else PCA9685_set(CHLED3, 0);	
}	

/** 
 * Set ONLY LED4, don't change anything for the other LEDs.
 */
void setMultiIOLED4(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED4, 4095); 
	else PCA9685_set(CHLED4, 0);	
}

/*****************************************************************************/
// Buzzer:

/**
 * Call this once before using the buzzer.
 *
 */
void Buzzer_init(void)
{
	DDRB |= OC2A_PI4;							// Portpin: output
 	TCCR2A = 0;									
	TCCR2B = 0;									// Sound off
	PORTB &= ~OC2A_PI4;							// Portpin low
}

/**
 * This function has no timing stuff. It only sets the pitch
 * and this can be used to generate tone sequences which
 * would sound bad if the beeper turns of for a very short time
 * in between - such as alarm tones or special melodies etc.
 * 
 * Input: pitch -> 0 =   sound off
 *                 1 =   lowest frequency
 *                 255 = higest frequency
 *
 */
void setBuzzerPitch(uint8_t pitch)
{
	OCR2A = 255 - pitch;
	if(pitch) {
		TCCR2A = (1 << WGM21) | (1 << COM2A0);
		TCCR2B = (1 << CS21) | (1 << CS22);
	}
	else {
		TCCR2A = 0;
		TCCR2B = 0;								// Normal port operation
		PORTB &= ~OC2A_PI4;						// Portpin low
	}
}

/**
 * You can use this function to make the buzzer beep ;) 
 * This function is BLOCKING and generates a delay for the
 * sound and a delay between two sounds.
 *
 * Input: pitch -> 0 = sound off
 *                 1 = lowest frequency
 *                 255 = higest frequency
 *        time  -> sound length [ms]
 *        delay -> pause after the sound [ms]
 *
 * Example:
 *   soundBuzzer(150,50,25);
 *   soundBuzzer(200,50,25);
 *
 * There is also a macro buzzer(pitch, time). You may use
 * it for sounds without a pause after the sound. The macro
 * is BLOCKING during the sound length.
 *
 * Example:
 *   buzzer(150,50);
 *
 */
void soundBuzzer(uint8_t pitch, uint16_t time, uint16_t delay)
{
	setBuzzerPitch(pitch);
	if (!pitch) return;
	mSleep(time);
	setBuzzerPitch(0);							// Sound off
	if (!delay) return;
	mSleep(delay);
}

/*****************************************************************************/
/*****************************************************************************/
// MultiIO Project Board initialisation:

/**
 * You MUST call this function at the beginning of a
 * main program, that uses the MultiIO Project Board. 
 *
 */
void multiio_init(void)
{
	// Voltage & current sensor:
	LTC2990_init();								// Init VCS
	// Servo Controller:
	PCA9685_init(50);							// Init PWM 50 Hz
	// Servo power:
	setServoPower(0);							// Servo power off
	// Buzzer:
	Buzzer_init();								// Init buzzer
}

/*****************************************************************************/
/*****************************************************************************/

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * - v. 2.0 (release for board V3) 17.02.2013 by Dirk
 * - v. 1.0 (initial release) 21.01.2013 by Dirk
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Erklärung

... BAUSTELLE ... BAUSTELLE ... BAUSTELLE ...

Demo

makefile:

...
TARGET = RP6M256_MultiIO
...
SRC += RP6M256_MultiIOLib.c
...

Datei RP6M256_MultiIO.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * In this example we show a first test for the MultiIO Project Board.
 * 
 * ############################################################################
 * The Robot does NOT move in this example! You can simply put it on a table
 * next to your PC and you should connect it to the PC via the USB Interface!
 * You should also connect to it via WIFI.
 * ############################################################################
 * ****************************************************************************
 */

/*****************************************************************************/
// Includes:

#include "RP6M256Lib.h" 				// The RP6 M256 Library. 
										// Always needs to be included!
#include "RP6I2CmasterTWI.h"			// Include the I2C-Bus Master Library

/*****************************************************************************/
/*****************************************************************************/
// Include our new "RP6M256 MultiIO library":
// (This is the library for accessing the MultiIO Project Board!)

#include "RP6M256_MultiIOLib.h"

/*****************************************************************************/

/**
 * Write a floating point number to the WIFI.
 *
 * Example:
 *
 *			// Write a floating point number to the WIFI (no exponent):
 *			writeDouble_WIFI(1234567.890, 11, 3);
 *
 * The value of prec (precision) defines the number of decimal places.
 * For 32 bit floating point variables (float, double ...) 6 is
 * the max. value for prec (7 relevant digits).
 * The value of width defines the overall number of characters in the
 * floating point number including the decimal point. The number of
 * pre-decimal positions is: (width - prec - 1).
 */
void writeDouble_WIFI(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
	dtostrf(number, width, prec, &buffer[0]);
	writeString_WIFI(&buffer[0]);
}

/*****************************************************************************/
// I2C Error handler

/**
 * This function gets called automatically if there was an I2C Error like
 * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
 *
 */
void I2C_transmissionError(uint8_t errorState)
{
	writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x");
	writeInteger_WIFI(errorState, HEX);
	writeChar_WIFI('\n');
}

/*****************************************************************************/
// Main function - The program starts here:

int main(void)
{
	initRP6M256();    // Always call this first! The Processor will not work
					  // correctly otherwise. 

	initLCD(); // Initialize the LC-Display (LCD)
			   // Always call this before using the LCD!

	setLEDs(0b1111);
	mSleep(500);
	setLEDs(0b0000);

	writeString_P_WIFI("\n\nRP6M256 Multi IO Selftest 1!\n"); 

	// IMPORTANT:
	I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
							// with 100kHz SCL Frequency


	// Register the event handler:
	I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);

	setLEDs(0b1111);

	// Write a text message to the LCD:
	showScreenLCD("################", "################");
	mSleep(1500);
	showScreenLCD("RP6v2-M256-WIFI ", "Example Program");
	mSleep(2500); 
	showScreenLCD("RP6M256 Multi IO", "   Selftest 1");
	mSleep(2500);
	clearLCD();

	setLEDs(0b0000);

	// ---------------------------------------

	uint8_t onoff = 0;
	uint16_t servopos = SERVO1_LT;

	startStopwatch1();

	// IMPORTANT:
	multiio_init();								// MultiIO init!!!
	//setServoPower(1);							// Servo power ON!

	// ----------------------------------------------
	// Set RTC once (battery empty or not existing:
	rtc_time.second = 0;
	rtc_time.minute = 0;
	rtc_time.hour = 12;				// 12:00
	rtc_date.weekday = R_TH;
	rtc_date.day = 10;
	rtc_date.month = 1;
	rtc_date.year = 2013;			// Do, 10.1.2013
	DS1307_write();
	// Remove this, if RTC is set and running!!!
	// ----------------------------------------------

	// EEPROM test:
	writeString_P_WIFI("\nWriting 128 to EEPROM address 5:\n");
	I2C_EEPROM_writeByte(5, 128);
	mSleep(500);
	writeString_P_WIFI("Done!\n"); 
	writeString_P_WIFI("\nReading EEPROM address 5:\n");
	uint8_t tmp = I2C_EEPROM_readByte(5);
	mSleep(500);
	I2C_EEPROM_writeByte(5, 0);
	writeString_P_WIFI("Done!\n"); 
	writeString_P_WIFI("EEPROM address 5 content: ");
	writeInteger_WIFI(tmp, DEC);
	writeString_P_WIFI("\n"); 

	// Buzzer test:
    soundBuzzer(Tone_Cis2, 300, 200);
    soundBuzzer(Tone_Fis2, 200, 100);
    soundBuzzer(Tone_Ais2, 100, 100);
    soundBuzzer(Tone_Dis3, 50, 100);
	mSleep(1000);
    soundBuzzer(Tone_Dis3, 300, 200);
    soundBuzzer(Tone_Ais2, 200, 100);
    soundBuzzer(Tone_Fis2, 100, 100);
    soundBuzzer(Tone_Cis2, 50, 100);

	while(true) 
	{
		if(getStopwatch1() > 1000) // 1s
		{
			if (onoff) onoff = 0;
			else onoff = 1;

			// Buttons ADC test:
			clearLCD();
			pressedButtonNumber = getPressedButtonNumber();
			setCursorPosLCD(0, 0);
			writeStringLCD("Button: ");
			writeIntegerLCD(pressedButtonNumber, DEC);
			setCursorPosLCD(1, 0);
			writeStringLCD("ADC: ");
			writeIntegerLCD(adcButtons, DEC);

			// 3V3 voltage sensor ADC test:
			v3v3 = measure3V3();
			writeString_WIFI("\n3V3 Voltage: ");
			writeDouble_WIFI(v3v3, 4, 1);
			writeString_WIFI("V\nADC 3V3: ");
			writeInteger_WIFI(adc3v3, DEC);

			// Touch sensor ADC test:
			touch = getTouch();
			if (touch) writeString_WIFI("\nTOUCHED!!!");
			else writeString_WIFI("\nNOT touched.");
			writeString_WIFI("\nADC Touch: ");
			writeInteger_WIFI(adcTouch, DEC);

			// Temperature sensor test:
			temperature = TCN75_measure();		// Measure
			writeString_WIFI("\nTemperature: ");
			writeDouble_WIFI(temperature, 5, 1);
			writeString_WIFI("°\n");

			// Servo controller test:
			//   LEDs:
			if (onoff) {
				setMultiIOLED1(1);
				setMultiIOLED2(0);
				setMultiIOLED3(0);
				setMultiIOLED4(1);
			}
			else
				setMultiIOLEDs(0b0110);
			//   Servo 1:
			setServo(1, servopos);
			servopos += 10;
			if (servopos > SERVO1_RT) servopos = SERVO1_LT;

			// RTC test:
			DS1307_read();
			writeString_WIFI("RTC: ");
			writeIntegerLength_WIFI(rtc_time.hour, DEC, 2);
			writeString_WIFI(":");
			writeIntegerLength_WIFI(rtc_time.minute, DEC, 2);
			writeString_WIFI(":");
			writeIntegerLength_WIFI(rtc_time.second, DEC, 2);
			writeString_WIFI("  ");
			writeIntegerLength_WIFI(rtc_date.day, DEC, 2);
			writeString_WIFI(".");
			writeIntegerLength_WIFI(rtc_date.month, DEC, 2);
			writeString_WIFI(".");
			writeIntegerLength_WIFI(rtc_date.year, DEC, 4);
			writeString_WIFI("\n");

			// Voltage & current sensor test:
			LTC2990_measure();
			writeString_WIFI("Temperature: ");
			writeDouble_WIFI(tint, 5, 1);
			writeString_WIFI("°\n");
			writeString_WIFI("BAT Current: ");
			writeDouble_WIFI(cbat, 6, 1);
			writeString_WIFI("mA\nBAT Voltage: ");
			writeDouble_WIFI(vbat, 4, 1);
			writeString_WIFI( "V\nSERVO Volt.: ");
			writeDouble_WIFI(vservo, 4, 1);
			writeString_WIFI( "V\nVCC Voltage: ");
			writeDouble_WIFI(vcc, 4, 1);
			writeString_WIFI("V\n");

			setStopwatch1(0);
		}

		task_I2CTWI();
	}

	return 0;
}
Erklärung

Linienfolger Board Software

Fast jeder mobile Roboter hat inzwischen Linienfolge-Sensoren (LFS). Der RP6 bekommt sie mit der Multi IO Projekt Platine jetzt auch.

Gegenüber der Standardstellung der Jumper (siehe hier!) müssen Jumper für die LFS-Nutzung umgesteckt werden. Die folgende Abbildung zeigt den Wahl-Jumperblock.

Wahl-Jumper: Stellung der Jumper

LFS Jumper Stellung Hinweis: Die Jumper sind orange eingezeichnet!

Zur Messung der 3,3V-Spannung und zur Auswertung des
Touch-Sensors kann zusätzlich je ein Jumper auf
3V3-PF4 und NE5-PF3 gesetzt werden, wenn keine
analogen Sensoren auf der Bumper-Platine benutzt
werden.
Demo

makefile:

...
TARGET = RP6M256_MultiIO_2
...
SRC += RP6M256_MultiIOLib.c
...

Datei: RP6M256_MultiIO_2.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * In this example we show a second test for the MultiIO Project Board.
 * It tests the Line Following Sensor (LFS) Board with 3 (5) CNY70s.
 * 
 * ############################################################################
 * The Robot does NOT move in this example! You can simply put it on a table
 * next to your PC and you should connect it to the PC via the USB Interface!
 * You should also connect to it via WIFI.
 * ############################################################################
 * ****************************************************************************
 */

/*****************************************************************************/
// Includes:

#include "RP6M256Lib.h" 				// The RP6 M256 Library. 
										// Always needs to be included!
#include "RP6I2CmasterTWI.h"			// Include the I2C-Bus Master Library

/*****************************************************************************/
/*****************************************************************************/
// Include our new "RP6M256 MultiIO library":
// (This is the library for accessing the MultiIO Project Board!)

#include "RP6M256_MultiIOLib.h"

/*****************************************************************************/
// Defines:

//#define FIVE_SENSORS					// Only, if all 5 CNY70s are used!

#define CH_LFS_L						1
#define CH_LFS_M						2
#define CH_LFS_R						3
#define CH_LFS_R1						4
#define CH_LFS_L1						5

/*****************************************************************************/
// LFS:

/**
 * Call this once before using the LFS function.
 *
 */
void LFS_init(void)
{
	IO_MULTIIO_LFS_PWR_DDR |= IO_MULTIIO_LFS_PWR_IN;
	// LFS power ON:
	IO_MULTIIO_LFS_PWR_PORT &= ~IO_MULTIIO_LFS_PWR_IN;
}

/**
 * This function reads the ADC values of the 5
 * CNY70 sensors on the LFS board.
 *
 * Input: channel -> 1 = left LFS sensor (CH_LFS_L)
 *                   2 = middle LFS sensor (CH_LFS_M)
 *                   3 = right LFS sensor (CH_LFS_R)
 *                   4 = outer right LFS sensor (CH_LFS_R1)
 *                   5 = outer left LFS sensor (CH_LFS_L1)
 *
 */
uint16_t getLFS(uint8_t channel)
{
	uint16_t value;

	switch (channel) {
		case CH_LFS_L :
			value = readADC(ADC_MULTIIO_LFS_L); break;
		case CH_LFS_M :
			value = readADC(ADC_MULTIIO_LFS_M); break;
		case CH_LFS_R :
			value = readADC(ADC_MULTIIO_LFS_R); break;
#ifdef FIVE_SENSORS
		case CH_LFS_R1 :
			value = readADC(ADC_MULTIIO_LFS_R1); break;
		case CH_LFS_L1 :
			value = readADC(ADC_MULTIIO_LFS_L1); break;
#endif
		default : value = 0;
	}
	return value;
}

/** 
 * With this function you can switch the LFS
 * power on or off. 
 *
 * Input: pwr -> 0 (false) = LFS power off
 *               >0 (true) = LFS power on
 *
 * Hint: If the LFS is not used, you should
 *       always switch the LFS power off to
 *       save energy!
 *
 */
void setLFSPower(uint8_t pwr)
{
	if (pwr > 0)
		IO_MULTIIO_LFS_PWR_PORT &= ~IO_MULTIIO_LFS_PWR_IN;
	else
		IO_MULTIIO_LFS_PWR_PORT |= IO_MULTIIO_LFS_PWR_IN;
}

/*****************************************************************************/
// I2C Error handler

/**
 * This function gets called automatically if there was an I2C Error like
 * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
 *
 */
void I2C_transmissionError(uint8_t errorState)
{
	writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x");
	writeInteger_WIFI(errorState, HEX);
	writeChar_WIFI('\n');
}

/*****************************************************************************/
// Main function - The program starts here:

int main(void)
{
	initRP6M256();    // Always call this first! The Processor will not work
					  // correctly otherwise. 

	initLCD(); // Initialize the LC-Display (LCD)
			   // Always call this before using the LCD!

	setLEDs(0b1111);
	mSleep(500);
	setLEDs(0b0000);

	writeString_P_WIFI("\n\nRP6M256 Multi IO Selftest 2!\n"); 

	// IMPORTANT:
	I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
							// with 100kHz SCL Frequency


	// Register the event handler:
	I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);

	setLEDs(0b1111);

	// Write a text message to the LCD:
	showScreenLCD("################", "################");
	mSleep(1500);
	showScreenLCD("RP6v2-M256-WIFI ", "Example Program");
	mSleep(2500); 
	showScreenLCD("RP6M256 Multi IO", "   Selftest 2");
	mSleep(2500);
	clearLCD();

	setLEDs(0b0000);

	// ---------------------------------------

	uint16_t lfs_l, lfs_m, lfs_r;
#ifdef FIVE_SENSORS
	uint16_t lfs_l1, lfs_r1;
#endif

	startStopwatch1();

	// IMPORTANT:
	multiio_init();								// MultiIO init!!!
	//setServoPower(1);							// Servo power ON!

	LFS_init();									// LFS init!

	while(true) 
	{
		if(getStopwatch1() > 500) // 0.5s
		{
			// LFS ADC test:
#ifdef FIVE_SENSORS
			lfs_l1 = getLFS(CH_LFS_L1);
			writeString_WIFI("\nADC LFS_L1: ");
			writeInteger_WIFI(lfs_l1, DEC);
#endif
			lfs_l = getLFS(CH_LFS_L);
			writeString_WIFI("\nADC LFS_L:  ");
			writeInteger_WIFI(lfs_l, DEC);
			lfs_m = getLFS(CH_LFS_M);
			writeString_WIFI("\nADC LFS_M:  ");
			writeInteger_WIFI(lfs_m, DEC);
			lfs_r = getLFS(CH_LFS_R);
			writeString_WIFI("\nADC LFS_R:  ");
			writeInteger_WIFI(lfs_r, DEC);
#ifdef FIVE_SENSORS
			lfs_r1 = getLFS(CH_LFS_R1);
			writeString_WIFI("\nADC LFS_R1: ");
			writeInteger_WIFI(lfs_r1, DEC);
#endif
			writeString_WIFI("\n");

			setStopwatch1(0);
		}

//		task_I2CTWI();
	}

	return 0;
}
Erklärung

Bumper Board Software

Fabian hat ein sehr universelles Bumper-Board designt, auf das 2 LEDs, 2 Bumper-Taster, 2 analoge SHARP-IR-Entfernungssensoren (in dieser Demo: GP2Y0A02YK), 2 I2C-Ultraschall-Entfernungssensoren (SRF02) oder 2 Radar-Sensoren (RSM-1650) montiert werden können.

Diese Software demonstriert das Auslesen aller dieser Sensoren bis auf die Radar-Sensoren.

Gegenüber der Standardstellung der Jumper (siehe hier!) müssen Jumper für die Nutzung des Bumper-Boards umgesteckt werden. Die folgenden Abbildungen zeigen den Wahl-Jumperblock.

Wahl-Jumper: Stellung der Jumper für analoge Sensoren (SHARP, Radar)

Bumper analog Jumper Stellung Hinweis: Die Jumper sind orange eingezeichnet!

Diese Jumperstellung entspricht der Standard-Jumperstellung!

Wahl-Jumper: Stellung der Jumper für I2C-Sensoren (SRF02)

Bumper I2C Jumper Stellung Hinweis: Die Jumper sind orange eingezeichnet!

Zur Messung der 3,3V-Spannung und zur Auswertung des
Touch-Sensors kann zusätzlich je ein Jumper auf 3V3-PF4
und NE5-PF3 gesetzt werden.
Alternativ kann diese Messung auch wie bei der Standard-
Jumperstellung mit Jumpern auf 3V3-AD3 und NE5-AD1
erfolgen, wenn man die LFS-Kanäle L und M nicht braucht.
Demo

makefile:

...
TARGET = RP6M256_MultiIO_3
...
SRC += RP6M256_MultiIOLib.c
...

Datei RP6M256_MultiIO_3.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M256 Examples
 * ****************************************************************************
 * Example: RP6M256 MultiIO
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * In this example we show a third test for the MultiIO Project Board.
 * It tests the Bumper Board with 2 LEDs, 2 bumpers, 2 analogue SHARP IR
 * distance sensors (GP2Y0A02YK) and/or 2 I2C ultrasonic distance sensors
 * (SRF02).
 * 
 * ############################################################################
 * The Robot does NOT move in this example! You can simply put it on a table
 * next to your PC and you should connect it to the PC via the USB Interface!
 * You should also connect to it via WIFI.
 * ############################################################################
 * ****************************************************************************
 */

/*****************************************************************************/
// Includes:

#include "RP6M256Lib.h" 				// The RP6 M256 Library. 
										// Always needs to be included!
#include "RP6I2CmasterTWI.h"			// Include the I2C-Bus Master Library

/*****************************************************************************/
/*****************************************************************************/
// Include our new "RP6M256 MultiIO library":
// (This is the library for accessing the MultiIO Project Board!)

#include "RP6M256_MultiIOLib.h"

/*****************************************************************************/
// Defines:

// Define the devices that are built up on the Bumper Board here!
// Make a comment of a line belonging to a sensor that is NOT built
// up on or attached to the Bumper Board!
#define BUMPERS							// Bumpers are used
#define SHARP_SENSORS					// SHARP IR distance sensors are used
#define SRF02_SENSORS					// SRF02 ultrasonic sensors are used

#define LEFT	1
#define RIGHT	2

/*****************************************************************************/
// LEDs (always used):

// Status of the bumper LEDs:
union {
	uint8_t byte;
	struct {
		unsigned LEDL:1;
		unsigned LEDR:1;
		unsigned unused:6;
	};
} bumperLEDs;

/** 
 * Set ONLY LEDL, don't change anything for the
 * right bumper LED.
 *
 * Input: led -> 0 (false) = LEDL off
 *               >0 (true) = LEDL on
 *
 */
void setbumperLEDL(uint8_t led)
{
	IO_MULTIIO_BUMPER_L_DDR |= IO_MULTIIO_BUMPER_L_IN;
	if (led > 0) {
		IO_MULTIIO_BUMPER_L_PORT |= IO_MULTIIO_BUMPER_L_IN;
		bumperLEDs.LEDL = 1;
	}
	else {
		IO_MULTIIO_BUMPER_L_PORT &= ~IO_MULTIIO_BUMPER_L_IN;
		bumperLEDs.LEDL = 0;
	}
}

/** 
 * Set ONLY LEDR, don't change anything for the
 * left bumper LED.
 *
 * Input: led -> 0 (false) = LEDR off
 *               >0 (true) = LEDR on
 *
 */
void setbumperLEDR(uint8_t led)
{
	IO_MULTIIO_BUMPER_R_DDR |= IO_MULTIIO_BUMPER_R_IN;
	if (led > 0) {
		IO_MULTIIO_BUMPER_R_PORT |= IO_MULTIIO_BUMPER_R_IN;
		bumperLEDs.LEDR = 1;
	}
	else {
		IO_MULTIIO_BUMPER_R_PORT &= ~IO_MULTIIO_BUMPER_R_IN;
		bumperLEDs.LEDR = 0;
	}
}

/** 
 * Set the 2 LEDs of the MultiIO Bumper Board.
 *
 * Example:
 *			setbumperLEDs(0b10);
 *			// this clears LEDL
 *          // and sets LEDR!
 *
 */
void setbumperLEDs(uint8_t leds)
{
	if (leds & 0b00000001) {
		setbumperLEDL(1);
	}
	else {
		setbumperLEDL(0);
	}
	if (leds & 0b00000010) {
		setbumperLEDR(1);
	}
	else {
		setbumperLEDR(0);
	}
}

/*****************************************************************************/
// Bumpers:

#ifdef BUMPERS
/**
 * Call this once before using the bumpers.
 *
 * ATTENTION: Stopwatch 8 is used for the bumpers
 *            task! Please do not use this
 *            stopwatch elsewhere in your program!
 *
 */
void BUMPERS_init(void)
{
	IO_MULTIIO_BUMPER_R_DDR |= IO_MULTIIO_BUMPER_R_IN;
	IO_MULTIIO_BUMPER_R_PORT &= ~IO_MULTIIO_BUMPER_R_IN;
	IO_MULTIIO_BUMPER_L_DDR |= IO_MULTIIO_BUMPER_L_IN;
	IO_MULTIIO_BUMPER_L_PORT &= ~IO_MULTIIO_BUMPER_L_IN;
	bumperLEDs.byte = 0;
	startStopwatch8();
}

uint8_t iobumper_l;
uint8_t iobumper_r;

/**
 * This function reads and returns the value of
 * the left or right bumper. The value is also
 * stored in iobumper_l or iobumper_r.
 *
 * Input: side -> 1 (LEFT) =  Left bumper
 *                2 (RIGHT) = Right bumper
 *
 */
uint8_t getBUMPER(uint8_t side)
{
	if (side == LEFT) {
		IO_MULTIIO_BUMPER_L_PORT &= ~IO_MULTIIO_BUMPER_L_IN;
		IO_MULTIIO_BUMPER_L_DDR &= ~IO_MULTIIO_BUMPER_L_IN;
		nop();
		if ((IO_MULTIIO_BUMPER_L_PIN & IO_MULTIIO_BUMPER_L_IN) > 0)
			iobumper_l = 1;
		else iobumper_l = 0;
		IO_MULTIIO_BUMPER_L_DDR |= IO_MULTIIO_BUMPER_L_IN;
		if (bumperLEDs.LEDL) {
			IO_MULTIIO_BUMPER_L_PORT |= IO_MULTIIO_BUMPER_L_IN;
		}
		return iobumper_l;
	}
	if (side == RIGHT) {
		IO_MULTIIO_BUMPER_R_PORT &= ~IO_MULTIIO_BUMPER_R_IN;
		IO_MULTIIO_BUMPER_R_DDR &= ~IO_MULTIIO_BUMPER_R_IN;
		nop();
		if ((IO_MULTIIO_BUMPER_R_PIN & IO_MULTIIO_BUMPER_R_IN) > 0)
			iobumper_r = 1;
		else iobumper_r = 0;
		IO_MULTIIO_BUMPER_R_DDR |= IO_MULTIIO_BUMPER_R_IN;
		if (bumperLEDs.LEDR) {
			IO_MULTIIO_BUMPER_R_PORT |= IO_MULTIIO_BUMPER_R_IN;
		}
		return iobumper_r;
	}
	return 0;
}

// -------------------------------
// Bumpers State changed handler:

void BUMPERS_stateChanged_DUMMY(void){}
static void (*BUMPERS_stateChangedHandler)(void) = BUMPERS_stateChanged_DUMMY;
/**
 * Use this function to set the Bumpers state change handler. 
 * 
 */
void BUMPERS_setStateChangedHandler(void (*bumperHandler)(void)) 
{
	BUMPERS_stateChangedHandler = bumperHandler;
}
// -------------------------------

/**
 * If you call this frequently out of the mainloop,
 * the global iobumper_l and iobumper_r variables
 * are updated automatically every 50ms and can be
 * used everywhere in your program. It can also
 * call an event handler routine, that you need to
 * register with BUMPERS_setStateChangedHandler
 * before.
 *
 */
void task_BUMPERS(void)
{
	if(getStopwatch8() > 50) { // 50ms
		uint8_t left = getBUMPER(LEFT);
		uint8_t right = getBUMPER(RIGHT);
		if(iobumper_l != left || iobumper_r != right) {
			iobumper_l = left;
			iobumper_r = right;
			BUMPERS_stateChangedHandler();
		}
		setStopwatch8(0);
	}
}
#endif

/*****************************************************************************/
// SHARP sensors:

#ifdef SHARP_SENSORS
/**
 * Call this once before using the SHARPS.
 *
 */
void SHARPS_init(void)
{
	IO_MULTIIO_SHARPS_PWR_DDR |= IO_MULTIIO_SHARPS_PWR_IN;
	// SHARPS power on:
	IO_MULTIIO_SHARPS_PWR_PORT &= ~IO_MULTIIO_SHARPS_PWR_IN;
}

uint16_t adcsharp_l;					// Left SHARP sensor ADC value
uint16_t adcsharp_r;					// Right SHARP sensor ADC value

/**
 * This function reads and returns the ADC value
 * of the left or right SHARP sensor. The value is
 * also stored in adcsharp_l or adcsharp_r.
 *
 * Input: side -> 1 (LEFT) =  Left SHARP sensor
 *                2 (RIGHT) = Right SHARP sensor
 *
 */
uint16_t getSHARPSensor(uint8_t side)
{
	if (side == LEFT) {
		adcsharp_l = readADC(ADC_MULTIIO_SHARP_L);
		return adcsharp_l;
	}
	if (side == RIGHT) {
		adcsharp_r = readADC(ADC_MULTIIO_SHARP_R);
		return adcsharp_r;
	}
	return 0;
}

double distsharp_l;						// Left SHARP sensor distance
double distsharp_r;						// Right SHARP sensor distance

/**
 * Calculates and returns the left or right SHARP
 * sensor distance value [mm] by using the data
 * read from the SHARP sensor with the function
 * getSHARPSensor().
 *
 * Input: side -> 1 (LEFT) =  Left SHARP sensor
 *                2 (RIGHT) = Right SHARP sensor
 *
 * Hints: - The linearisation formula is adapted to
 *          the SHARP GP2Y0A02YK sensor ONLY!
 *        - You can calculate your own linearisation
 *          formula by using a table calculation
 *          program!
 *
 */
double calculateSHARP(uint8_t side)
{
	double vside;

	if (side == LEFT) {
		vside = adcsharp_l * 5.0 / 1024.0;
		vside = (0.082712905 + 9395.7652 * vside)
		 / (1 - 3.3978697 * vside + 17.339222 * vside * vside);
		return vside;
	}
	if (side == RIGHT) {
		vside = adcsharp_r * 5.0 / 1024.0;
		vside = (0.082712905 + 9395.7652 * vside)
		 / (1 - 3.3978697 * vside + 17.339222 * vside * vside);
		return vside;
	}
	return 0;
}

/**
 * Measures and returns the left or right SHARP
 * sensor distance value [cm].
 * The ADC value of the SHARP sensor is also
 * stored in adcsharp_l or adcsharp_r.
 *
 * Input: side -> 1 (LEFT) =  Left SHARP sensor
 *                2 (RIGHT) = Right SHARP sensor
 *
 */
double measureSHARP(uint8_t side)
{
	uint16_t tmp;

	tmp = getSHARPSensor(side);
	return (calculateSHARP(side) / 10);			// Result in [cm]
}

/** 
 * With this function you can switch the SHARP
 * sensors power on or off. 
 *
 * Input: pwr -> 0 (false) = SHARPS power off
 *               >0 (true) = SHARPS power on
 *
 * Hint: If the SHARPS are not used, you should
 *       always switch the SHARPS power off to
 *       save energy!
 *
 */
void setSHARPSPower(uint8_t pwr)
{
	if (pwr > 0)
		IO_MULTIIO_SHARPS_PWR_PORT &= ~IO_MULTIIO_SHARPS_PWR_IN;
	else
		IO_MULTIIO_SHARPS_PWR_PORT |= IO_MULTIIO_SHARPS_PWR_IN;
}
#endif

/*****************************************************************************/
// SRF02 sensors:

#ifdef SRF02_SENSORS
// SRF02 sensors (2) on the Bumper Board:
#define I2C_MULTIIO_SRF02_L_ADR			0xe0	// Default
#define I2C_MULTIIO_SRF02_R_ADR			0xe2
// SRF02 sensors (4) connected to the MultiIO mainboard:
#define I2C_MULTIIO_SRF02_1_ADR			0xe4
#define I2C_MULTIIO_SRF02_2_ADR			0xe6
#define I2C_MULTIIO_SRF02_3_ADR			0xe8
#define I2C_MULTIIO_SRF02_4_ADR			0xea
// Other possible SRF02 I2C addresses:
//#define I2C_MULTIIO_SRF02_x_ADR			0xec
//#define I2C_MULTIIO_SRF02_x_ADR			0xee
//#define I2C_MULTIIO_SRF02_x_ADR			0xf0
//#define I2C_MULTIIO_SRF02_x_ADR			0xf2
//#define I2C_MULTIIO_SRF02_x_ADR			0xf4
//#define I2C_MULTIIO_SRF02_x_ADR			0xf6
//#define I2C_MULTIIO_SRF02_x_ADR			0xf8
//#define I2C_MULTIIO_SRF02_x_ADR			0xfa
//#define I2C_MULTIIO_SRF02_x_ADR			0xfc
//#define I2C_MULTIIO_SRF02_x_ADR			0xfe

// Registers:
#define SRF02_COMMAND					0		// Read: Software Revision
#define SRF02_RANGE_MSB					2
#define SRF02_RANGE_LSB					3
#define SRF02_AUTOTUNE_MIN_MSB			4
#define SRF02_AUTOTUNE_MIN_LSB			5

// SRF02 mode constants:
#define MODE_INCH						80		// Result in [inch]
#define MODE_CM							81		// Result in [cm]
#define MODE_US							82		// Result in [us]
#define MODE_SYNC_INCH					86		// Result in [inch] *
#define MODE_SYNC_CM					87		// Result in [cm] *
#define MODE_SYNC_US					88		// Result in [us] *
#define MODE_40KHZ_BURST				92		// Ping. No measurement!
//												*) Fake ranging mode!

// Sonic speed constants in air (default: at 20°C):
//#define SONIC_SPEED						325.4	// [m/s] at -10°C
//#define SONIC_SPEED						328.5	// [m/s] at - 5°C
//#define SONIC_SPEED						331.5	// [m/s] at   0°C
//#define SONIC_SPEED						334.5	// [m/s] at   5°C
//#define SONIC_SPEED						337.5	// [m/s] at  10°C
//#define SONIC_SPEED						340.5	// [m/s] at  15°C
#define SONIC_SPEED						343.4	// [m/s] at  20°C
//#define SONIC_SPEED						346.3	// [m/s] at  25°C
//#define SONIC_SPEED						349.2	// [m/s] at  30°C

#define CH_SRF02_L						1
#define CH_SRF02_R						2
#define CH_SRF02_1						3
#define CH_SRF02_2						4
#define CH_SRF02_3						5
#define CH_SRF02_4						6

uint8_t registerBuf[3];
uint16_t distsrf02;						// SRF02 distance [inch, cm, us]

/** 
 * Returns the I2C slave address belonging to the
 * SRF02 sensor with the channel number [1..6].
 *
 * Input: channel -> 1 = left SRF02 sensor (CH_SRF02_L) *
 *                   2 = right SRF02 sensor (CH_SRF02_R) *
 *                   3 = SRF02 sensor 1 (CH_SRF02_1) "
 *                   4 = SRF02 sensor 2 (CH_SRF02_2) "
 *                   5 = SRF02 sensor 3 (CH_SRF02_3) "
 *                   6 = SRF02 sensor 4 (CH_SRF02_4) "
 *        *) Located on the Bumper Board!
 *        ") Connected to the MultiIO mainboard!
 *
 */
uint8_t SRF02_i2cadr(uint8_t channel)
{
	uint8_t adr;

	switch (channel) {
		case CH_SRF02_L :
			adr = I2C_MULTIIO_SRF02_L_ADR; break;
		case CH_SRF02_R :
			adr = I2C_MULTIIO_SRF02_R_ADR; break;
		case CH_SRF02_1 :
			adr = I2C_MULTIIO_SRF02_1_ADR; break;
		case CH_SRF02_2 :
			adr = I2C_MULTIIO_SRF02_2_ADR; break;
		case CH_SRF02_3 :
			adr = I2C_MULTIIO_SRF02_3_ADR; break;
		case CH_SRF02_4 :
			adr = I2C_MULTIIO_SRF02_4_ADR; break;
		default : adr = I2C_MULTIIO_SRF02_L_ADR;
	}
	return adr;
}

/** 
 * Reads and returns the SRF02 firmware (software)
 * revision number.
 * If this function returns 255 after a "ping" was
 * sent to the sensor (with SRF02_ping()!), the
 * result of the measurement cannot be read yet
 * over the I2C bus.
 *
 * Input: channel -> [1..6] (for details see
 *                   function SRF02_i2cadr()!)
 *
 * Example:
 *   tmp = SRF02_getFirmware(CH_SRF02_L);
 *   // this reads the software revision from
 *   // the left SRF02 on the Bumper Board!
 *
 */
uint8_t SRF02_getFirmware(uint8_t channel)
{
	uint8_t adr = SRF02_i2cadr(channel);
	I2CTWI_transmitByte(adr, SRF02_COMMAND);
	return (I2CTWI_readByte(adr));
}

/** 
 * Sends a "ping" to the SRF02. This command starts
 * a measurement or only sends an ultrasonic burst
 * depending on mode.
 *
 * Input: channel -> [1..6] (for details see
 *                   function SRF02_i2cadr()!)
 *        mode    -> 80: Result in [inch]
 *                   81: Result in [cm]
 *                   82: Result in [us]
 *                   86: Result in [inch] *
 *                   87: Result in [cm] *
 *                   88: Result in [us] *
 *                   92: 40 kHz burst (no measurement)
 *        *) Fake ranging mode!
 *
 */
void SRF02_ping(uint8_t channel, uint8_t mode)
{
	I2CTWI_transmit2Bytes(SRF02_i2cadr(channel), SRF02_COMMAND, mode);
}

/** 
 * Reads and returns the SRF02 measurement result.
 * The result unit [inch, cm, us] depends on the
 * measuring mode (see SRF02_ping()!).
 * The measurement result of the SRF02 sensor is
 * also stored in distsrf02.
 *
 * Input: channel -> [1..6] (for details see
 *                   function SRF02_i2cadr()!)
 *
 */
uint16_t SRF02_read(uint8_t channel)
{
	uint8_t adr = SRF02_i2cadr(channel);
	I2CTWI_transmitByte(adr, SRF02_RANGE_MSB);
	I2CTWI_readBytes(adr, registerBuf, 2);
	distsrf02 = registerBuf[0] * 256 + registerBuf[1];
	return distsrf02;
}

double distsrf02_l;						// Left SRF02 distance [mm]
double distsrf02_r;						// Right SRF02 distance [mm]

/** 
 * Calculates and returns the distance [mm] from
 * a SRF02 result measured in microseconds [us]
 * (modes 82 or 88).
 *
 * Input: us -> SRF02 result [us]
 *
 */
double SRF02_calculate(uint16_t us)
{
	uint16_t time_ms = us / 2000;				// One way [ms]
	return (SONIC_SPEED * time_ms);				// Distance [mm]
}

/** 
 * Performs a SRF02 measurement and returns the
 * result [inch, cm, us] depending on mode.
 * This function is BLOCKING for about 65 ms!
 * If you don't want a blocking measurement, you
 * have to write your own function with a non
 * blocking pause between starting measurement
 * and reading the result.
 *
 * Input: channel -> [1..6] (for details see
 *                   function SRF02_i2cadr()!)
 *        mode    -> 80: Result in [inch]
 *                   81: Result in [cm]
 *                   82: Result in [us]
 *
 */
uint16_t SRF02_measure(uint8_t channel, uint8_t mode)
{
	uint8_t adr = SRF02_i2cadr(channel);
	SRF02_ping(adr, mode);
	mSleep(65);
	return (SRF02_read(adr));
}

/** 
 * Changes the SRF02 I2C slave address.
 *
 * Input: adr    -> Old I2C address [0xe0..0xfe]
 *        newadr -> New I2C address [0xe0..0xfe]
 *
 * Hints: - adr and newadr may not be equal!
 *        - newadr must be even!
 *        - If you use this function, only !!ONE!!
 *          SRF02 (with the I2C address adr) may
 *          be connected to the I2C bus!
 *
 */
void SRF02_changeAdr(uint8_t adr, uint8_t newadr)
{
	if (adr == newadr) return;
	if (newadr < 0xe0) return;
	newadr &= 0xfe;
	I2CTWI_transmit2Bytes(adr, SRF02_COMMAND, 160);
	mSleep(50);
	I2CTWI_transmit2Bytes(adr, SRF02_COMMAND, 170);
	mSleep(50);
	I2CTWI_transmit2Bytes(adr, SRF02_COMMAND, 165);
	mSleep(50);
	I2CTWI_transmit2Bytes(adr, SRF02_COMMAND, newadr);
}
#endif

/*****************************************************************************/
// Bumper board init:

/**
 * Call this once before using the Bumper Board,
 * if you want to use bumpers and/or SHARP IR
 * distance sensors.
 *
 */
void BUMPERBOARD_init(void)
{
#ifdef BUMPERS
	BUMPERS_init();
#endif
#ifdef SHARP_SENSORS
	SHARPS_init();
#endif
}

/*****************************************************************************/

/**
 * Write a floating point number to the WIFI.
 *
 * Example:
 *
 *			// Write a floating point number to the WIFI (no exponent):
 *			writeDouble_WIFI(1234567.890, 11, 3);
 *
 * The value of prec (precision) defines the number of decimal places.
 * For 32 bit floating point variables (float, double ...) 6 is
 * the max. value for prec (7 relevant digits).
 * The value of width defines the overall number of characters in the
 * floating point number including the decimal point. The number of
 * pre-decimal positions is: (width - prec - 1).
 */
void writeDouble_WIFI(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
	dtostrf(number, width, prec, &buffer[0]);
	writeString_WIFI(&buffer[0]);
}

/*****************************************************************************/
// I2C Error handler

/**
 * This function gets called automatically if there was an I2C Error like
 * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
 *
 */
void I2C_transmissionError(uint8_t errorState)
{
	writeString_P_WIFI("\nI2C ERROR - TWI STATE: 0x");
	writeInteger_WIFI(errorState, HEX);
	writeChar_WIFI('\n');
}

/*****************************************************************************/
// Main function - The program starts here:

int main(void)
{
	initRP6M256();    // Always call this first! The Processor will not work
					  // correctly otherwise. 

	initLCD(); // Initialize the LC-Display (LCD)
			   // Always call this before using the LCD!

	setLEDs(0b1111);
	mSleep(500);
	setLEDs(0b0000);

	writeString_P_WIFI("\n\nRP6M256 Multi IO Selftest 3!\n"); 

	// IMPORTANT:
	I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
							// with 100kHz SCL Frequency


	// Register the event handler:
	I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);

	setLEDs(0b1111);

	// Write a text message to the LCD:
	showScreenLCD("################", "################");
	mSleep(1500);
	showScreenLCD("RP6v2-M256-WIFI ", "Example Program");
	mSleep(2500); 
	showScreenLCD("RP6M256 Multi IO", "   Selftest 3");
	mSleep(2500);
	clearLCD();

	setLEDs(0b0000);

	// ---------------------------------------

	uint8_t bump_l, bump_r;
	uint16_t distsrf_l, distsrf_r;

	startStopwatch1();

	// IMPORTANT:
	multiio_init();								// MultiIO init!!!
	//setServoPower(1);							// Servo power ON!

	BUMPERBOARD_init();							// Bumper Board init!

	while(true) 
	{
		if(getStopwatch1() > 1000) // 1s
		{
#ifdef BUMPERS
			// Bumpers test:
			clearLCD();
			bump_l = getBUMPER(LEFT);			// Read bumper
			bump_r = getBUMPER(RIGHT);
			setCursorPosLCD(0, 0);
			writeIntegerLCD(bump_l, DEC);
			setCursorPosLCD(0, 4);
			writeStringLCD("<BUMPER>");
			bump_r = getBUMPER(RIGHT);
			setCursorPosLCD(0, 15);
			writeIntegerLCD(bump_r, DEC);
#endif
#ifdef SHARP_SENSORS
			// SHARP sensors test:
			distsharp_l = measureSHARP(LEFT);	// Measure
			writeString_WIFI("\nSHARP SENSORS ->");
			writeString_WIFI("\nLeft Distance:  ");
			writeDouble_WIFI(distsharp_l, 5, 1);
			distsharp_r = measureSHARP(RIGHT);
			writeString_WIFI("cm\nRight Distance: ");
			writeDouble_WIFI(distsharp_r, 5, 1);
			writeString_WIFI("cm\n");
#endif
#ifdef SRF02_SENSORS
			// SRF02 sensors test:
			distsrf_l = SRF02_measure(CH_SRF02_L, MODE_CM);
			writeString_WIFI("\nSRF02 SENSORS ->");
			writeString_WIFI("\nLeft Distance:  ");
			writeIntegerLCD(distsrf_l, DEC);
			distsrf_r = SRF02_measure(CH_SRF02_R, MODE_CM);
			writeString_WIFI("cm\nRight Distance: ");
			writeIntegerLCD(distsrf_r, DEC);
			writeString_WIFI("cm\n");
#endif
			setStopwatch1(0);
		}

		task_I2CTWI();
	}

	return 0;
}
Erklärung

Radio Board Software

Wird bei Bedarf DEN Usern zur Verfügung gestellt, die die
Radio-Platine bestellt haben und mit ihr arbeiten möchten.

Library für die Messung von Umweltdaten

... BAUSTELLE ... BAUSTELLE ... BAUSTELLE ...

Library Header
Library Source
Erklärung
Demo
Erklärung

Library für die Orientierung im Raum

... BAUSTELLE ... BAUSTELLE ... BAUSTELLE ...

Library Header
Library Source
Erklärung
Demo
Erklärung

DCF77-Library

Die "Funkuhr-Zeit" kann empfangen und ausgewertet werden, wenn ein DCF77-Empfänger (z.B. CONRAD 641138) mit dem dafür vorgesehenen Anschluß auf der Multi IO Platine verbunden ist.

Die RP6 M256 WIFI DCF77 Library findet ihr HIER!

Geändert werden muss der Eingangs-Portpin. Dazu schaut euch die Datei RP6M256_DCFLib.c an.

Die folgenden Zeilen:

// RP6 M256 WIFI DCF Receiver Connection:
#define DCF_PORT	PORTJ
#define DCF_DDR		DDRJ
#define DCF_PIN		PINJ
#define DCF_IN		INT1_PI12			// PINJ3  XBUS Pin 8

... am Anfang der Datei im Abschnitt "Defines" müssen so geändert werden:

// RP6 M256 WIFI DCF Receiver Connection:
#define DCF_PORT	PORTE
#define DCF_DDR		DDRE
#define DCF_PIN		PINE
#define DCF_IN		IO_PE7_ICP3_I7			// PINE7  IO_PWM/T2/T3 Pin 1

RP6 CCPRO M128

Die RP6-CCPRO-M128 (= "M128") kann über den I2C-Bus alle I2C-Sensoren und I2C-Aktoren ansteuern und hat mit ihren freien Ressourcen (Portpins) gute Voraussetzungen, um die weiteren Funktionen der Multi IO Platine zu nutzen. Dazu wird sie (wenn alle Funktionen gleichzeitig genutzt werden sollen) mit zwei Steckverbindungen angeschlossen:

  • IO-Mxxx <-> I/O
  • ADC-Mxxx <-> ADC

Dadurch ergeben sich umfangreiche Möglichkeiten, die Sensoren der Multi IO Platine auszulesen und Aktoren zu schalten. Die folgenden 2 Tabellen zeigen die Verbindungen:

Stecker IO-Mxxx:

Stecker-Pin M128-Port M128-Funktion Port-Bit Multi IO-Funktion I/O
1 PB5 OC1A 13 DCF77 I
2 PD7 T2 31 LFS_PWR O
3 PB6 OC1B 14 SHARPS_PWR O
4 PD6 T1 30 SNAKE_SWITCH O
5 PE3 ** OC3A/AIN1 35 BUZZER O
6 PD4 ICP1 28 (TX *)
7 PD3 TXD1/INT3 27 SNAKE_KEY / TX I/O
8 PD2 RXD1/INT2 26 RX I
9 GND
10 VDD

Zu *) TX nicht an Pin 6 des I/O Steckers der M128 vorhanden!

Zu **) Auf der M128 ist hier ebenfalls der Piezo-Signalgeber (SND) angeschlossen! Es ist nur möglich, den Signalgeber auf der Multi IO Platine zu nutzen, wenn SND auf der M128 deaktiviert wurde (Jumper EN_SND auf der M128 abziehen)!

Stecker ADC-Mxxx:

Stecker-Pin M128-Port M128-Funktion Port-Bit Multi IO-Funktion I/O
1 PF1 ADC1 41 TOUCH / LFS_L I
2 PF7 ADC7 47 3V3 alt.2 I
3 PF3 ADC3 43 3V3 / LFS_M I
4 PF0 ADC0 40 BUMPER_L I/O *
5 PF5 ADC5 45 LFS_R I
6 PF2 ADC2 42 n.c.
7 PF6 ADC6 46 BUTTONS I
8 PF4 ADC4 44 BUMPER_R I/O *
9 GND
10 VDD

Zu *) Eingang für Bumper-Taster, Ausgang für Bumper-LED!

Multi IO Projekt Library

Die Multi IO Library für die M128 hat bei mir nicht die erste Priorität.
Wenn jemand die Multi IO Platine unbedingt mit der M128 betreiben will,
bin ich mit Tips für das Umschreiben der Library auf CompactC gern dabei!
Demo

RP6 CONTROL M32

Die RP6-Control-M32 (= "M32") kann über den I2C-Bus alle I2C-Sensoren und I2C-Aktoren ansteuern und hat mit ihren freien Ressourcen (Portpins) gute Voraussetzungen, um die weiteren Funktionen der Multi IO Platine zu nutzen. Dazu wird sie (wenn alle Funktionen gleichzeitig genutzt werden sollen) mit zwei Steckverbindungen angeschlossen:

  • IO-Mxxx <-> I/O
  • ADC-Mxxx <-> ADC

Dadurch ergeben sich umfangreiche Möglichkeiten, die Sensoren der Multi IO Platine auszulesen und Aktoren zu schalten. Die folgenden 2 Tabellen zeigen die Verbindungen:

Stecker IO-Mxxx:

Stecker-Pin M32-Port M32-Funktion Multi IO-Funktion I/O
1 PC7 TOSC2 DCF77 I
2 GND
3 PC5 TDI SHARPS_PWR O
4 PC6 TOSC1 SNAKE_SWITCH O
5 PC3 TMS BUZZER O
6 PC4 TDO (TX *)
7 PC2 TCK SNAKE_KEY / (TX *) I
8 PD6 ICP (RX *)
9 PD5 OC1A LFS_PWR O
10 VDD

Zu *) UART nicht am I/O Stecker der M32 vorhanden!

Stecker ADC-Mxxx:

Stecker-Pin M32-Port M32-Funktion Multi IO-Funktion I/O
1 PA3 ADC3 TOUCH / LFS_L I
2 PA2 ADC2 3V3 alt.2 I
3 PA4 ADC4 3V3 / LFS_M I
4 GND
5 PA5 ADC5 LFS_R I
6 GND
7 PA6 ADC6 BUTTONS I
8 GND
9 PA7 ADC7 3V3 alt.1 I
10 VDD

Multi IO Projekt Library

Diese Avr-gcc Library für das Multi IO Projekt Board (= "MultiIO") geht von folgenden Voraussetzungen aus:

  • Die RP6-Control-M32 (= "M32") wird für die Ansteuerung der MultiIO benutzt.
  • Die M32 ist der I2C-Bus Master.
  • Die I2C-Bus Geschwindigkeit beträgt 100 kHz.
  • Alle Hardware-Komponenten der MultiIO sind aufgebaut (1).
  • Alle Jumper auf der MultiIO sind in ihrer Standardstellung (2).
  • Die MultiIO und die M32 sind mit dem XBUS des RP6-Systems 1:1 verbunden.
  • Der Wannenstecker IO_Mxxx der MultiIO ist mit dem Wannenstecker I/O der M32 1:1 verbunden.
  • Der Wannenstecker ADC_Mxxx der MultiIO ist mit dem Wannenstecker ADC der M32 1:1 verbunden.
Zu (1): Wenn nicht alle Komponenten aufgebaut sind, sind die zugehörigen
        Funktionen natürlich nicht funktionsfähig und können nicht benutzt
        werden.
Zu (2): Siehe hier!

Die Library (Software-Bibliothek) besteht aus drei Teilen:

  • Dem Configuration Header -> Hier stehen alle Definitionen und Festlegungen, die der grundlegenden Konfiguration der MultiIO dienen. Diese Datei kann auf die eigenen Hardware-Voraussetzungen angepaßt werden, ohne dass die eigentliche Library (Header und Source) verändert werden muss.
  • Dem Library Header -> Hier gibt es Definitionen, Variablen- und Funktionsdeklarationen für die Library.
  • Der Library Source -> Das ist die eigentliche Library.
Configuration Header

Datei: RP6Control_MultiIO.h:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
 * ****************************************************************************
 * Example: RP6Control MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * Configuration header file for new MultiIO Project Board library.
 *
 * ****************************************************************************
 */

#ifndef RP6CONTROL_MULTIIO_H
#define RP6CONTROL_MULTIIO_H


/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):
#define I2C_MULTIIO_VCS_ADR				0x98	// ADR1/0 = 0/0
//#define I2C_MULTIIO_VCS_ADR				0x9a	// ADR1/0 = 0/1
//#define I2C_MULTIIO_VCS_ADR				0x9c	// ADR1/0 = 1/0
//#define I2C_MULTIIO_VCS_ADR				0x9e	// ADR1/0 = 1/1
//#define I2C_MULTIIO_VCS_ADR				0xee	// Global sync address

// (Voltage divider and shunt resistor!)
#define SHUNT_R							0.051		// 0.051 Ohm
#define V1_ADJUST						2.0			// (10+10)/10 kOhm
#define V2_ADJUST						2.0			// (10+10)/10 kOhm
#define VBAT_ADJUST						3.2			// (22+10)/10 kOhm
#define VSERVO_ADJUST					2.5			// (15+10)/10 kOhm

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):
#define I2C_MULTIIO_RTC_ADR				0xD0	// Default

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):
// (A1 always 0!)
#define I2C_MULTIIO_TEMP_ADR			0x90	// A2/0 = 0/0
//#define I2C_MULTIIO_TEMP_ADR			0x92	// A2/0 = 0/1
//#define I2C_MULTIIO_TEMP_ADR			0x98	// A2/0 = 1/0
//#define I2C_MULTIIO_TEMP_ADR			0x9a	// A2/0 = 1/1

/*****************************************************************************/
// I2C Servo Controller (PCA9685):
// (A5, A4, A3, A2 always 0!)
#define I2C_MULTIIO_SERVO_ADR			0x80	// A1/0 = 0/0
//#define I2C_MULTIIO_SERVO_ADR			0x82	// A1/0 = 0/1
//#define I2C_MULTIIO_SERVO_ADR			0x84	// A1/0 = 1/0
//#define I2C_MULTIIO_SERVO_ADR			0x86	// A1/0 = 1/1
//#define I2C_MULTIIO_SERVO_ADR			0xe0	// ALLCALLADR

// (Servo power is connected to LED8 of the PCA9685!)
#define CHSERVOPWR						9

// Servo left touch (LT), right touch (RT), middle position (MP) constants:
// (Hints: - Servo impulse length [ms] = Servo position value / 204.8
//           (Formula only valid for a PWM of 50 Hz!)
//         - Min. servo impulse (0,7 ms) = Servo position 143
//         - Mid. servo impulse (1,5 ms) = Servo position 307
//         - Max. servo impulse (2,3 ms) = Servo position 471
//         - !!! You should NOT use servo position values < 143 or > 471 !!!)
#define SERVO1_LT						205		// Servo impulse ~1ms
#define SERVO1_RT						410		// Servo impulse ~2ms
#define SERVO1_MP						((SERVO1_RT - SERVO1_LT) / 2 + SERVO1_LT)
#define SERVO2_LT						205
#define SERVO2_RT						410
#define SERVO2_MP						((SERVO2_RT - SERVO2_LT) / 2 + SERVO2_LT)
#define SERVO3_LT						205
#define SERVO3_RT						410
#define SERVO3_MP						((SERVO3_RT - SERVO3_LT) / 2 + SERVO3_LT)
#define SERVO4_LT						205
#define SERVO4_RT						410
#define SERVO4_MP						((SERVO4_RT - SERVO4_LT) / 2 + SERVO4_LT)
#define SERVO5_LT						205
#define SERVO5_RT						410
#define SERVO5_MP						((SERVO5_RT - SERVO5_LT) / 2 + SERVO5_LT)
#define SERVO6_LT						205
#define SERVO6_RT						410
#define SERVO6_MP						((SERVO6_RT - SERVO6_LT) / 2 + SERVO6_LT)
#define SERVO7_LT						205
#define SERVO7_RT						410
#define SERVO7_MP						((SERVO7_RT - SERVO7_LT) / 2 + SERVO7_LT)
#define SERVO8_LT						205
#define SERVO8_RT						410
#define SERVO8_MP						((SERVO8_RT - SERVO8_LT) / 2 + SERVO8_LT)

/*****************************************************************************/
// I2C EEPROM (24LCXXX):
// (A2=1 not usable with 24LC1024-P!)
#define I2C_MULTIIO_EEPROM_ADR			0xA0	// A2/1/0 = 0/0/0
//#define I2C_MULTIIO_EEPROM_ADR			0xA2	// A2/1/0 = 0/0/1
//#define I2C_MULTIIO_EEPROM_ADR			0xA4	// A2/1/0 = 0/1/0
//#define I2C_MULTIIO_EEPROM_ADR			0xA6	// A2/1/0 = 0/1/1
//#define I2C_MULTIIO_EEPROM_ADR			0xA8	// A2/1/0 = 1/0/0
//#define I2C_MULTIIO_EEPROM_ADR			0xAA	// A2/1/0 = 1/0/1
//#define I2C_MULTIIO_EEPROM_ADR			0xAC	// A2/1/0 = 1/1/0
//#define I2C_MULTIIO_EEPROM_ADR			0xAE	// A2/1/0 = 1/1/1

// I2C-EEPROM storage capacity [kbit]:
#define I2C_EEPROM_KBIT					32		// 24LC32-P <== Default
//#define I2C_EEPROM_KBIT					64		// 24LC64-P
//#define I2C_EEPROM_KBIT					128		// 24LC128-P
//#define I2C_EEPROM_KBIT					256		// 24LC256-P
//#define I2C_EEPROM_KBIT					512		// 24LC512-P
//#define I2C_EEPROM_KBIT					1024	// 24LC1024-P

// I2C-EEPROM pagesize [byte]:
// ATTENTION: The pagesize must fit to the EEPROM type defined above!
#define I2C_EEPROM_PAGESIZE				32		// EEPROM 32 or 64 kbit
//#define I2C_EEPROM_PAGESIZE				64		// EEPROM 128 or 256 kbit
//#define I2C_EEPROM_PAGESIZE				128		// EEPROM 512 kbit
//#define I2C_EEPROM_PAGESIZE				256		// EEPROM 1024 kbit

/*****************************************************************************/
// 3V3 Voltage Sensor:
#define ADC_MULTIIO_3V3					ADC_4	// ADC-Mxxx: ADC
//#define ADC_MULTIIO_3V3					ADC_7	// ADC-Mxxx: ADC
//#define ADC_MULTIIO_3V3					ADC_2	// ADC-Mxxx: ADC

/*****************************************************************************/
// Touch Sensor (with NE555):
#define ADC_MULTIIO_TOUCH				ADC_3	// ADC-Mxxx: ADC

#define ADCVAL_NOTOUCH					14
#define ADCVAL_TOUCH					1022
#define ADCVAL_LIMIT_T					((ADCVAL_TOUCH - ADCVAL_NOTOUCH) / 2 + ADCVAL_NOTOUCH)

/*****************************************************************************/
// Buttons:
#define ADC_MULTIIO_BUTTONS				ADC_6	// ADC-Mxxx: ADC

#define ADCVAL_BUTTON1					13
#define ADCVAL_BUTTON2					581
#define ADCVAL_BUTTON3					743
#define ADCVAL_BUTTON4					820
#define ADCVAL_LIMIT12					((ADCVAL_BUTTON2 - ADCVAL_BUTTON1) / 2 + ADCVAL_BUTTON1)
#define ADCVAL_LIMIT23					((ADCVAL_BUTTON3 - ADCVAL_BUTTON2) / 2 + ADCVAL_BUTTON2)
#define ADCVAL_LIMIT34					((ADCVAL_BUTTON4 - ADCVAL_BUTTON3) / 2 + ADCVAL_BUTTON3)
#define ADCVAL_LIMIT40					((1023 - ADCVAL_BUTTON4) / 2 + ADCVAL_BUTTON4)

/*****************************************************************************/
// LEDs:
// (Status LED1..LED4 are connected to LED15..LED12 of the PCA9685!)
#define CHLED1							16
#define CHLED2							15
#define CHLED3							14
#define CHLED4							13

/*****************************************************************************/
// Buzzer:
// (The IO-Mxxx plug is connected to the M32 I/O plug!)
#define IO_MULTIIO_BUZZER_IN			IO_PC3	// IO-Mxxx: I/O
#define IO_MULTIIO_BUZZER_DDR			DDRC
#define IO_MULTIIO_BUZZER_PORT			PORTC

/*****************************************************************************/
// Other ADC channel definitions:
// (Depending on jumper settings on the MultiIO Project Board!)
// (The ADC-Mxxx plug is connected to the M32 ADC plug!)
#define ADC_MULTIIO_LFS_L				ADC_3	// ADC-Mxxx: ADC
#define ADC_MULTIIO_LFS_M				ADC_4	// ADC-Mxxx: ADC
#define ADC_MULTIIO_LFS_R				ADC_5	// ADC-Mxxx: ADC

// Other IO portpin definitions:
// (The IO-Mxxx plug is connected to the M32 I/O plug!)
#define IO_MULTIIO_LFS_PWR_IN			IO_PD5	// IO-Mxxx: I/O
#define IO_MULTIIO_LFS_PWR_DDR			DDRD
#define IO_MULTIIO_LFS_PWR_PORT			PORTD

#define IO_MULTIIO_SHARPS_PWR_IN		IO_PC5	// IO-Mxxx: I/O
#define IO_MULTIIO_SHARPS_PWR_DDR		DDRC
#define IO_MULTIIO_SHARPS_PWR_PORT		PORTC

#define IO_MULTIIO_SNAKE_SWITCH_IN		IO_PC6	// IO-Mxxx: I/O
#define IO_MULTIIO_SNAKE_SWITCH_DDR		DDRC
#define IO_MULTIIO_SNAKE_SWITCH_PORT	PORTC

#define IO_MULTIIO_SNAKE_KEY_IN			IO_PC2	// IO-Mxxx: I/O
#define IO_MULTIIO_SNAKE_KEY_DDR		DDRC
#define IO_MULTIIO_SNAKE_KEY_PIN		PINC

#define IO_MULTIIO_DCF77_IN				IO_PC7	// IO-Mxxx: I/O
#define IO_MULTIIO_DCF77_DDR			DDRC
#define IO_MULTIIO_DCF77_PIN			PINC

/*****************************************************************************/

#endif

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * 
 *  ---> changes are documented in the file "RP6Control_MultiIOLib.c"
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Library Header

Datei RP6Control_MultiIOLib.h:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
 * ****************************************************************************
 * Example: RP6Control MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * Header file for new MultiIO Project Board library.
 *
 * ****************************************************************************
 */

#ifndef RP6CONTROL_MULTIIOLIB_H
#define RP6CONTROL_MULTIIOLIB_H


/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// Includes:

#include "RP6ControlLib.h"
#include "RP6I2CmasterTWI.h"
#include "RP6Control_MultiIO.h"

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):

// Registers:
#define LTC2990_STATUS					0
#define LTC2990_CONTROL					1
#define LTC2990_TRIGGER					2
#define LTC2990_TINT_MSB				4
#define LTC2990_TINT_LSB				5
#define LTC2990_V1_MSB					6
#define LTC2990_V1_LSB					7
#define LTC2990_V2_MSB					8
#define LTC2990_V2_LSB					9
#define LTC2990_V3_MSB					10
#define LTC2990_V3_LSB					11
#define LTC2990_V4_MSB					12
#define LTC2990_V4_LSB					13
#define LTC2990_VCC_MSB					14
#define LTC2990_VCC_LSB					15

// Status register bitmasks:
#define LTC2990_STATUS_DEFAULT			0
#define LTC2990_STATUS_BUSY				1
#define LTC2990_STATUS_TINT_READY		2
#define LTC2990_STATUS_V1V2_READY		4
#define LTC2990_STATUS_V2_READY			8
#define LTC2990_STATUS_V3V4_READY		16
#define LTC2990_STATUS_V4_READY			32
#define LTC2990_STATUS_VCC_READY		64

// Control register bitmasks:
#define LTC2990_CONTROL_DEFAULT			0
#define LTC2990_CONTROL_MULTIIO			0b01011010 // Mode V1-V2, V3, V4
												   // All measurements per mode
												   // Single acquisition
#define LTC2990_CONTROL_MODE02_DEFAULT	0
#define LTC2990_CONTROL_MODE34_DEFAULT	0
#define LTC2990_CONTROL_REPEAT_SINGLE	64
#define LTC2990_CONTROL_TEMP_FORMAT		128

extern double tint;
extern double cbat;
extern double vbat;
extern double vservo;
extern double vcc;

void LTC2990_write_cfg(uint8_t);
#define LTC2990_init() {LTC2990_write_cfg(LTC2990_CONTROL_MULTIIO);}
void LTC2990_run(void);
void LTC2990_read(void);
void LTC2990_calculate(void);
void LTC2990_measure(void);

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):

// Registers:
#define DS1307_SECONDS					0
#define DS1307_MINUTES					1
#define DS1307_HOURS					2
#define DS1307_DAY						3
#define DS1307_DATE						4
#define DS1307_MONTH					5
#define DS1307_YEAR						6
#define DS1307_CONTROL					7
#define DS1307_RAM						8

// Control register bitmasks:
#define DS1307_CONTROL_DEFAULT			0
#define DS1307_CONTROL_RS0				1
#define DS1307_CONTROL_RS1				2
#define DS1307_CONTROL_SQWE				16
#define DS1307_CONTROL_OUT				128

enum RTCWEEKDAYS {
	R_MO = 1, R_TU, R_WE, R_TH, R_FR, R_SA, R_SU
};

typedef struct {
	uint16_t         year;				// Year
	uint8_t          month;				// Month   [1..12]
	enum RTCWEEKDAYS weekday;			// Weekday [1..7 = R_MO..R_SU]
	uint8_t          day;				// Day     [1..31]
} rtcdate_t;
rtcdate_t rtc_date;

typedef struct {
	uint8_t dst;						// Daylight-saving-time (time zone)
	uint8_t hour;						// Hour    [0..23]
	uint8_t minute;						// Minute  [0..59]
	uint8_t second;						// Second  [0..59]
} rtctime_t;
rtctime_t rtc_time;

uint8_t BCD2DEC(uint8_t);
uint8_t DEC2BCD(uint8_t);
void DS1307_write_cfg(uint8_t);
void DS1307_init(void);
#define CALC_DST						// Time zone will be calculated
void DS1307_read(void);
void DS1307_write(void);
uint8_t DS1307_readRAM(uint8_t);
void DS1307_writeRAM(uint8_t, uint8_t);

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):

// Registers:
#define TCN75_TEMP						0
#define TCN75_CONFIG					1
#define TCN75_HYST						2
#define TCN75_LIMIT						3

// Config register bitmasks:
#define TCN75_CONFIG_RUN				0		// Default
#define TCN75_CONFIG_SHUTDOWN			1
#define TCN75_CONFIG_COMP				0		// Default
#define TCN75_CONFIG_INT				2
#define TCN75_CONFIG_ALERT_LOW			0		// Default
#define TCN75_CONFIG_ALERT_HIGH			4
#define TCN75_CONFIG_FAULT_1			0		// Default
#define TCN75_CONFIG_FAULT_2			8
#define TCN75_CONFIG_FAULT_4			16
#define TCN75_CONFIG_FAULT_6			24

// Only for the TCN75A - high resolution and OneShot mode:
#define TCN75A_CONFIG_RES_9				0		// Default
#define TCN75A_CONFIG_RES_10			32		// 0b00100000
#define TCN75A_CONFIG_RES_11			64		// 0b01000000
#define TCN75A_CONFIG_RES_12			96		// 0b01100000
#define TCN75A_CONFIG_ONESHOT_DISABLED	0		// Default
#define TCN75A_CONFIG_ONESHOT			128		// 0b10000000

extern double temperature;

void TCN75_write_cfg(uint8_t);
#define TCN75_shutdown() {TCN75_write_cfg(TCN75_CONFIG_SHUTDOWN);}
#define TCN75_run(__CONFIG__) {TCN75_write_cfg(__CONFIG__);}
extern uint8_t temperature_low;
extern uint8_t temperature_high;
#define getTemperatureHigh() (temperature_high)
#define getTemperatureLow() (temperature_low)
void TCN75_read(void);
double TCN75_calculate(void);
double TCN75_measure(void);

/*****************************************************************************/
// I2C Servo Controller (PCA9685):

// Registers:
#define PCA9685_MODE1					0
#define PCA9685_MODE2					1
#define PCA9685_SUBADR1					2
#define PCA9685_SUBADR2					3
#define PCA9685_SUBADR3					4
#define PCA9685_ALLCALLADR				5
#define PCA9685_LED0_ON_L				6
#define PCA9685_LED0_ON_H				7
#define PCA9685_LED0_OFF_L				8
#define PCA9685_LED0_OFF_H				9
#define PCA9685_LED1_ON_L				10
#define PCA9685_LED1_ON_H				11
#define PCA9685_LED1_OFF_L				12
#define PCA9685_LED1_OFF_H				13
#define PCA9685_LED2_ON_L				14
#define PCA9685_LED2_ON_H				15
#define PCA9685_LED2_OFF_L				16
#define PCA9685_LED2_OFF_H				17
#define PCA9685_LED3_ON_L				18
#define PCA9685_LED3_ON_H				19
#define PCA9685_LED3_OFF_L				20
#define PCA9685_LED3_OFF_H				21
#define PCA9685_LED4_ON_L				22
#define PCA9685_LED4_ON_H				23
#define PCA9685_LED4_OFF_L				24
#define PCA9685_LED4_OFF_H				25
#define PCA9685_LED5_ON_L				26
#define PCA9685_LED5_ON_H				27
#define PCA9685_LED5_OFF_L				28
#define PCA9685_LED5_OFF_H				29
#define PCA9685_LED6_ON_L				30
#define PCA9685_LED6_ON_H				31
#define PCA9685_LED6_OFF_L				32
#define PCA9685_LED6_OFF_H				33
#define PCA9685_LED7_ON_L				34
#define PCA9685_LED7_ON_H				35
#define PCA9685_LED7_OFF_L				36
#define PCA9685_LED7_OFF_H				37
#define PCA9685_LED8_ON_L				38
#define PCA9685_LED8_ON_H				39
#define PCA9685_LED8_OFF_L				40
#define PCA9685_LED8_OFF_H				41
#define PCA9685_LED9_ON_L				42
#define PCA9685_LED9_ON_H				43
#define PCA9685_LED9_OFF_L				44
#define PCA9685_LED9_OFF_H				45
#define PCA9685_LED10_ON_L				46
#define PCA9685_LED10_ON_H				47
#define PCA9685_LED10_OFF_L				48
#define PCA9685_LED10_OFF_H				49
#define PCA9685_LED11_ON_L				50
#define PCA9685_LED11_ON_H				51
#define PCA9685_LED11_OFF_L				52
#define PCA9685_LED11_OFF_H				53
#define PCA9685_LED12_ON_L				54
#define PCA9685_LED12_ON_H				55
#define PCA9685_LED12_OFF_L				56
#define PCA9685_LED12_OFF_H				57
#define PCA9685_LED13_ON_L				58
#define PCA9685_LED13_ON_H				59
#define PCA9685_LED13_OFF_L				60
#define PCA9685_LED13_OFF_H				61
#define PCA9685_LED14_ON_L				62
#define PCA9685_LED14_ON_H				63
#define PCA9685_LED14_OFF_L				64
#define PCA9685_LED14_OFF_H				65
#define PCA9685_LED15_ON_L				66
#define PCA9685_LED15_ON_H				67
#define PCA9685_LED15_OFF_L				68
#define PCA9685_LED15_OFF_H				69
#define PCA9685_ALL_LED_ON_L			250
#define PCA9685_ALL_LED_ON_H			251
#define PCA9685_ALL_LED_OFF_L			252
#define PCA9685_ALL_LED_OFF_H			253
#define PCA9685_PRE_SCALE				254
#define PCA9685_TESTMODE				255

// Mode1 register bitmasks:
#define PCA9685_MODE1_ALLCALL			1
#define PCA9685_MODE1_SUB3				2
#define PCA9685_MODE1_SUB2				4
#define PCA9685_MODE1_SUB1				8
#define PCA9685_MODE1_SLEEP				16
#define PCA9685_MODE1_AI				32
#define PCA9685_MODE1_EXTCLK			64
#define PCA9685_MODE1_RESTART			128

// Mode2 register bitmasks:
#define PCA9685_MODE2_OUTNE01_DEFAULT	0
#define PCA9685_MODE2_OUTDRV			4
#define PCA9685_MODE2_OCH				8
#define PCA9685_MODE2_INVRT				16

#define F_PCA9685						25000000.0	// Int. Clock: 25 MHz

void PCA9685_init(uint16_t);
#define initServo(__FREQ__) {PCA9685_init(__FREQ__);}
void PCA9685_set(uint8_t, uint16_t);
#define setServo(__SERVO__,__POS__) {PCA9685_set(__SERVO__,__POS__);}
void PCA9685_shutdown(void);
void PCA9685_restart(void);
void setServoPower(uint8_t);

/*****************************************************************************/
// I2C EEPROM (24LCXXX):

uint8_t I2C_EEPROM_readByte(uint16_t memAddr);
void I2C_EEPROM_writeByte(uint16_t memAddr, uint8_t data);
void I2C_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length);
void I2C_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length);

/*****************************************************************************/
// 3V3 Voltage Sensor:

extern uint16_t adc3v3;
extern double v3v3;

uint16_t get3V3Sensor(void);
double calculate3V3(void);
double measure3V3(void);

/*****************************************************************************/
// Touch Sensor (with NE555):

extern uint16_t adcTouch;
extern uint8_t touch;

uint8_t getTouch(void);

/*****************************************************************************/
// Buttons:

extern uint16_t adcButtons;
extern uint8_t releasedMultiIOButtonNumber;
extern uint8_t pressedMultiIOButtonNumber;

uint8_t getMultiIOPressedButtonNumber(void);
uint8_t checkMultiIOPressedButtonEvent(void);
uint8_t checkMultiIOReleasedButtonEvent(void);

/*****************************************************************************/
// LEDs:

void setMultiIOLEDs(uint8_t leds);

void dimMultiIOLED(uint8_t led, uint16_t duty);
void setMultiIOLED1(uint8_t led);
void setMultiIOLED2(uint8_t led);
void setMultiIOLED3(uint8_t led);
void setMultiIOLED4(uint8_t led);

/*****************************************************************************/
// Buzzer:

void Buzzer_init(void);
void buzzer(uint16_t);

/*****************************************************************************/
// MultiIO Project Board initialisation:

void multiio_init(void);

/*****************************************************************************/

#endif

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * 
 *  ---> changes are documented in the file "RP6Control_MultiIOLib.c"
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Library Source

Datei RP6Control_MultiIOLib.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
 * ****************************************************************************
 * Example: RP6Control MultiIO Library
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * 
 * This is our new Library that contains basic routines and functions for
 * accessing the hardwired components of the MultiIO Project Board.
 *
 * There are much more sensors, that may be connected to the MultiIO Project
 * Board: Line following sensors (5x CNY70), bumpers, "Snake Vision board",
 *        LDRs, I2C air pressure sensor, I2C humidity sensor, DCF77 module,
 *        I2C IMU, I2C ultrasonic distance sensors, GPS module and more
 *        sensors connected to free ADCs and IOs and to the I2C bus.
 * This library doesn't contain functions for these sensors, because they are
 * not HARDWIRED to the MultiIO Project Board and may be connected OPTIONALLY.
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// MultiIO hardwired components:
// - I2C Voltage & Current Sensor (LTC2990)
// - I2C Real Time Clock (RTC DS1307Z)
// - I2C Temperature Sensor (TCN75A)
// - I2C Servo Controller (PCA9685)
// - I2C EEPROM (24LCXXX)
// - 3V3 Voltage Sensor
// - Touch Sensor (with NE555)
// - Buttons
// - LEDs
// - Buzzer

/*****************************************************************************/
// Includes:

#include "RP6Control_MultiIOLib.h" 		

/*****************************************************************************/
// Variables:

uint8_t registerBuf[13]; 

/*****************************************************************************/
// I2C Voltage & Current Sensor (LTC2990):

/**
 * Sends the configuration byte to a LTC2990.
 *
 * Input: Config byte for control register
 *
 * There is also a macro LTC2990_init(), which
 * initializes the sensor to work in V1-V2, V3,
 * V4 and Single Acquisition mode.
 *
 * Example:
 *   LTC2990_init();
 *
 */
void LTC2990_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_VCS_ADR, LTC2990_CONTROL, config);
}

uint8_t vcs_tint_low;
uint8_t vcs_tint_high;
uint8_t vcs_v1_low;
uint8_t vcs_v1_high;
uint8_t vcs_v2_low;
uint8_t vcs_v2_high;
uint8_t vcs_v3_low;
uint8_t vcs_v3_high;
uint8_t vcs_v4_low;
uint8_t vcs_v4_high;
uint8_t vcs_vcc_low;
uint8_t vcs_vcc_high;

/**
 * Starts a Single Acquisition measurement.
 */
void LTC2990_run(void)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_VCS_ADR, LTC2990_TRIGGER, 0);
}

/**
 * Reads all data registers of the voltage & current
 * sensor (VCS).
 * They are stored in the variables defined above.
 */
void LTC2990_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_VCS_ADR, LTC2990_TINT_MSB);
	I2CTWI_readBytes(I2C_MULTIIO_VCS_ADR, registerBuf, 12);
	vcs_tint_high = registerBuf[0];
	vcs_tint_low = registerBuf[1];
	vcs_v1_high = registerBuf[2];
	vcs_v1_low = registerBuf[3];
	vcs_v2_high = registerBuf[4];
	vcs_v2_low = registerBuf[5];
	vcs_v3_high = registerBuf[6];
	vcs_v3_low = registerBuf[7];
	vcs_v4_high = registerBuf[8];
	vcs_v4_low = registerBuf[9];
	vcs_vcc_high = registerBuf[10];
	vcs_vcc_low = registerBuf[11];
}

double tint;							// Internal temperature
double cbat;							// Current at 9V
double vbat;							// Battery voltage 9V (BAT)
double vservo;							// Servo voltage 5 .. 7.5V
double vcc;								// Voltage 5V (VCC)

/**
 * Calculates the temperature, voltage and current
 * values by using the data read from the LTC2990
 * with the function LTC2990_read(). The sensor is
 * configured to work in V1-V2, V3, V4 and Single
 * Acquisition mode.
 * The result is stored in the double variables
 * defined above.
 */
void LTC2990_calculate(void)
{
	int16_t tmp, tmp2;
	double v1, v2;

	tmp = (((vcs_tint_high & 0x1f) << 8) + vcs_tint_low) << 3;
	tmp = tmp / 8;
	tint = tmp / 16.0;							// Internal temperature [°C]

	tmp = (((vcs_v1_high & 0x7f) << 8) + vcs_v1_low) << 1;
	tmp = tmp / 2;
	v1 = tmp * 0.01942;
	v1 *= V1_ADJUST;							// Voltage divider factor
	tmp2 = (((vcs_v2_high & 0x7f) << 8) + vcs_v2_low) << 1;
	tmp2 = tmp2 / 2;
	v2 = tmp * 0.01942;
	v2 *= V2_ADJUST;							// Voltage divider factor
	cbat = (v1 - v2) / SHUNT_R;				// Battery current [mA]

	tmp = ((vcs_v3_high & 0x3f) << 8) + vcs_v3_low;
	vbat = tmp * 0.00030518;					// Battery voltage [V]
	vbat *= VBAT_ADJUST;						// Voltage divider factor

	tmp = ((vcs_v4_high & 0x3f) << 8) + vcs_v4_low;
	vservo = tmp * 0.00030518;					// Servo voltage [V]
	vservo *= VSERVO_ADJUST;					// Voltage divider factor

	tmp = ((vcs_vcc_high & 0x3f) << 8) + vcs_vcc_low;
	vcc = 2.5 + tmp * 0.00030518;				// VCC [V]
}

/**
 * Performs a complete measurement with the sensor
 * configured to work in V1-V2, V3, V4 and Single
 * Acquisition mode.
 * The result is stored in the double variables
 * defined above.
 * This function is BLOCKING for about 200 ms!
 * If you don't want a blocking measurement, you
 * have to write your own function with a non
 * blocking pause between starting measurement
 * and reading the result or with another mode
 * of operation (Repeated Acquisitions).
 */
void LTC2990_measure(void)
{
	LTC2990_run();								// Start measurement
	mSleep(200);
	LTC2990_read();								// Read data
	LTC2990_calculate();						// Calculate values
}

/*****************************************************************************/
// I2C Real Time Clock (RTC DS1307Z):

/**
 * This function converts a BCD to a DEC value.
 *
 */
uint8_t BCD2DEC(uint8_t bcd)
{
	return ((bcd >> 4) * 10 + (bcd & 0x0f));
}

/**
 * This function converts a DEC to a BCD value.
 *
 */
uint8_t DEC2BCD(uint8_t dec)
{uint8_t units = dec % 10;
	if (dec /= 10) {
		return (units + (DEC2BCD(dec) << 4));
	}
	else {
		return units;
	}
}

/**
 * Sends the configuration byte to a DS1307.
 *
 * Input: Config byte for control register
 *
 */
void DS1307_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_RTC_ADR, DS1307_CONTROL, config);
}

/**
 * Initializes the DS1307 by resetting all registers.
 * Only use this function ONCE for a DS1307 without or
 * with empty backup battery!
 */
void DS1307_init(void)
{
	uint8_t i;

	for (i = 0; i < 8; i++) {
		registerBuf[i] = 0;
	}
	I2CTWI_transmitBytes(I2C_MULTIIO_RTC_ADR, &registerBuf[0], 8);
}

/**
 * Reads all data registers of the Real Time Clock (RTC).
 * They are stored in the time & date variables defined in
 * the library header.
 */
void DS1307_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_RTC_ADR, DS1307_SECONDS);
	I2CTWI_readBytes(I2C_MULTIIO_RTC_ADR, registerBuf, 7);
	rtc_time.second = BCD2DEC(registerBuf[0] & 0x7f);
	rtc_time.minute = BCD2DEC(registerBuf[1]);
	rtc_time.hour = BCD2DEC(registerBuf[2] & 0x3f);
	rtc_date.weekday = registerBuf[3];
	rtc_date.day = BCD2DEC(registerBuf[4]);
	rtc_date.month = BCD2DEC(registerBuf[5]);
	rtc_date.year = BCD2DEC(registerBuf[6]) + 2000;
	rtc_time.dst = 0;
#ifdef CALC_DST
	// Calculate MESZ (DST):
	uint8_t wday = rtc_date.weekday;			// Weekday [1..7 = R_MO..R_SU]
	if(wday == 7) wday = 0;
	if(rtc_date.month < 3 || rtc_date.month > 10) {
		return;
	}
	if((rtc_date.day - wday >= 25)
	 && (wday || rtc_time.hour >= 2)) {
		if(rtc_date.month == 10)
			return;
	}
	else {
		if(rtc_date.month == 3) {
			return;
		}
	}
	rtc_time.dst = 1;
#endif
}

/**
 * Writes the time & date infos in the variables defined in
 * the library header to the Real Time Clock (RTC).
 */
void DS1307_write(void)
{
	registerBuf[0] = DS1307_SECONDS;
	registerBuf[1] = DEC2BCD(rtc_time.second);
	registerBuf[2] = DEC2BCD(rtc_time.minute);
	registerBuf[3] = DEC2BCD(rtc_time.hour);
	registerBuf[4] = rtc_date.weekday;
	registerBuf[5] = DEC2BCD(rtc_date.day);
	registerBuf[6] = DEC2BCD(rtc_date.month);
	registerBuf[7] = DEC2BCD(rtc_date.year - 2000);
	I2CTWI_transmitBytes(I2C_MULTIIO_RTC_ADR, &registerBuf[0], 8);
}

/**
 * Reads and returns a data byte from the DS1307 RAM.
 *
 * Input: adr -> RAM address [0..55]
 *
 * Hints: - The real DS1307 RAM addresses are 8..63!
 *        - The RAM is nonvolatile. That means, that
 *          it keeps the data as long as the backup
 *          battery doesn't become weak!
 *
 */
uint8_t DS1307_readRAM(uint8_t adr)
{
	if (adr > 55) adr = 0;
	I2CTWI_transmitByte(I2C_MULTIIO_RTC_ADR, (DS1307_RAM + adr));
	return (I2CTWI_readByte(I2C_MULTIIO_RTC_ADR));
}

/**
 * Writes a data byte to the DS1307 RAM.
 *
 * Input: adr  -> RAM address [0..55]
 *        data -> Data byte [0..255]
 *
 * Hints: - The real DS1307 RAM addresses are 8..63!
 *        - The RAM is nonvolatile. That means, that
 *          it keeps the data as long as the backup
 *          battery doesn't become weak!
 *
 */
void DS1307_writeRAM(uint8_t adr, uint8_t data)
{
	if (adr > 55) adr = 0;
	I2CTWI_transmit2Bytes(I2C_MULTIIO_RTC_ADR, (DS1307_RAM + adr), data);
}

/*****************************************************************************/
// I2C Temperature Sensor (TCN75A):

/**
 * Sends the configuration byte to a TCN75A.
 *
 * Input: Config byte for config register
 *
 */
void TCN75_write_cfg(uint8_t config)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_TEMP_ADR, TCN75_CONFIG, config);
}

uint8_t temperature_low;
uint8_t temperature_high;

/**
 * Reads the two data registers of the temperature
 * sensor.
 * They are stored in the variables temperature_low
 * and _high.
 *
 * Hint: Depending on the sensor configuration the
 *       data are located different in the two bytes
 *       - have a look at the datasheet!
 *
 */
void TCN75_read(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_TEMP_ADR, TCN75_TEMP);
	I2CTWI_readBytes(I2C_MULTIIO_TEMP_ADR, registerBuf, 2);
	temperature_low = registerBuf[0];
	temperature_high = registerBuf[1];
}

double temperature;						// Temperature [°C]

/**
 * Calculates and returns the temperature value
 * by using the data read from the TCN75A with
 * the function TCN75_read(). The sensor is
 * configured to Single Conversion and 12 bit
 * measurement.
 */
double TCN75_calculate(void)
{
	uint8_t templow;
	double temp;

	templow = getTemperatureLow();
	if (templow & 128)							// Calculate temperature
		templow = (templow & 63) - 127;
	else
		templow = templow & 63;
	temp = templow + (0.0625 * (getTemperatureHigh() >> 4));
	return temp;
}

/**
 * Performs a 12 bit measurement and returns the
 * temperature [°C].
 * This function is BLOCKING for about 250 ms!
 * If you don't want a blocking measurement, you
 * have to write your own function with a non
 * blocking pause between starting measurement
 * and reading the result or with another mode
 * of operation (Continuous Conversion).
 */
double TCN75_measure(void)
{
	TCN75_run(TCN75A_CONFIG_RES_12);			// Start measurement
	mSleep(250);
	TCN75_shutdown();							// Stop measurement
	TCN75_read();								// Read data
	return (TCN75_calculate());					// Calculate value
}

/*****************************************************************************/
// I2C Servo Controller (PCA9685):

/**
 * Call this once before using the servo function.
 *
 * Input: PWM frequency [40..1000 Hz]
 *
 * Hints: - Default servo frequency is 50 Hz!
 *        - The servo power is NOT switched on by
 *          this function!
 *
 * There is also a macro initServo(freq), which
 * does exactly the same as this function.
 *
 * Example:
 *   initServo(50);
 *
 */
void PCA9685_init(uint16_t freq)
{
	if ((freq < 40) || (freq > 1000)) freq = 50;
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE2);
	uint8_t last_mode = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	last_mode &= ~PCA9685_MODE2_INVRT;			// Clear INVRT bit
	last_mode |= PCA9685_MODE2_OUTDRV;			// Set OUTDRV bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE2, last_mode);
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	last_mode = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	last_mode |= PCA9685_MODE1_AI;				// Set AI bit
	uint8_t mode1 = last_mode;
	mode1 |= PCA9685_MODE1_SLEEP;				// Set SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
	uint8_t prescale = (uint8_t) (F_PCA9685 / 4096 / freq - 0.5);
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_PRE_SCALE, prescale);
	last_mode &= ~PCA9685_MODE1_SLEEP;			// Clear SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, last_mode);
	mSleep(1);
	last_mode |= PCA9685_MODE1_RESTART;			// Clear RESTART bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, last_mode);
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_ON_H, 0x10);
	return;
}

/**
 * This is the servo position set function.
 *
 * Input: servo -> Servo number [1..8, 10..16]
 *        pos   -> Servo position [SERVOx_LT..SERVOx_RT]
 *
 * Hints: - Servo number 9 cannot be set by this function!
 *          Please use setServoPower() function instead!
 *        - A servo position of 205 means 1 ms servo impulse,
 *          a position of 410 means a 2 ms servo impulse!
 *          You may calculate the servo impulse length by:
 *          ==> Impulse [ms] = servo position / 204.8 <==
 *          (Formula only valid for a PWM of 50 Hz!)
 *
 * There is also a macro setServo(servo, pos), which
 * does exactly the same as this function.
 *
 * Example:
 *   setServo(2,300);
 *
 */
void PCA9685_set(uint8_t servo, uint16_t pos)
{
	if ((servo == 0) || (servo == CHSERVOPWR) || (servo > 16))
		return;
	uint8_t reg = servo * 4 + 4;				// Register LEDx_OFF_L
	I2CTWI_transmit3Bytes(I2C_MULTIIO_SERVO_ADR, reg, (pos & 0x00ff), (pos >> 8));
}

/**
 * If the servos are not moving for a while, the
 * servo function can be stopped with this
 * function (PCA9685 set to sleep mode).
 *
 * Hint: The servo power is NOT switched off by
 *       this function!
 *
 */
void PCA9685_shutdown(void)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_ALL_LED_OFF_H, 0x10);
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	uint8_t mode1 = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	mode1 |= PCA9685_MODE1_SLEEP;				// Set SLEEP bit
	I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
}

/**
 * If the servo function was stopped with the
 * function PCA9685_shutdown() before, it can be
 * (re)started again with this function.
 *
 * Hint: The servo power is NOT switched on by
 *       this function!
 *
 */
void PCA9685_restart(void)
{
	I2CTWI_transmitByte(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1);
	uint8_t mode1 = I2CTWI_readByte(I2C_MULTIIO_SERVO_ADR);
	if (mode1 & PCA9685_MODE1_RESTART) {		// RESTART bit set?
		mode1 &= ~PCA9685_MODE1_SLEEP;			// Clear SLEEP bit
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
		mSleep(1);
		mode1 |= PCA9685_MODE1_RESTART;			// Clear RESTART bit
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_MODE1, mode1);
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_ALL_LED_OFF_H, 0);
	}
}

/** 
 * With this function you can switch the servo
 * power on or off, if the servo power jumper on
 * the board enables this feature.
 *
 * Input: pwr -> 0 (false) = servo power off
 *               >0 (true) = servo power on
 *
 * Hints: - If connected servos are not used, you
 *          should always switch the servo power off
 *          to save energy!
 *        - The PCA9685 is NOT restarted or put into
 *          shutdown mode by this function!
 *
 */
void setServoPower(uint8_t pwr)
{
	if (pwr > 0)
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_OFF_H, 0);
	else
		I2CTWI_transmit2Bytes(I2C_MULTIIO_SERVO_ADR, PCA9685_LED8_OFF_H, 0x10);
}	

/*****************************************************************************/
// I2C EEPROM (24LCXXX):

// The following EEPROM types may be used:
//  EEPROM Size:  Chip              Pagesize
//  -   32 kbit:  ST24LC32A            32
//  -   64 kbit:  ST24LC64             32
//  -  128 kbit:  ST24LC128            64
//  -  256 kbit:  ST24LC256            64
//  -  512 kbit:  ST24LC512           128
//  - 1024 kbit:  AT24LC1024          256
// ! You may choose the EEPROM type in the I2C EEPROM !
// ! section of the RP6Control_MultiIO.h file!           !

/**
 * Reads a single Byte from the EEPROM.
 */
uint8_t I2C_EEPROM_readByte(uint16_t memAddr)
{
	uint8_t data;
	I2CTWI_transmit2Bytes(I2C_MULTIIO_EEPROM_ADR, (memAddr >> 8), memAddr);
	data = I2CTWI_readByte(I2C_MULTIIO_EEPROM_ADR);
	return data;
}

/**
 * Write a single data byte to the specified EEPROM address.
 */
void I2C_EEPROM_writeByte(uint16_t memAddr, uint8_t data)
{
	I2CTWI_transmit3Bytes(I2C_MULTIIO_EEPROM_ADR, (memAddr >> 8), memAddr, data);
	mSleep(5);
}

/**
 * Reads "length" Bytes into the Buffer "buffer" from startAddr on. 
 * You can read the complete EEPROM into a buffer at once - if it is large enough. 
 * (But you only have 2KB SRAM on a MEGA32 ;) )
 * If "length" is higher than I2CTWI_BUFFER_REC_SIZE defined in RP6I2CmasterTWI.h,
 * you have to adapt I2CTWI_BUFFER_REC_SIZE to the highest used "length" value!
 */
void I2C_EEPROM_readBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length)
{
	I2CTWI_transmit2Bytes(I2C_MULTIIO_EEPROM_ADR, (startAddr >> 8), startAddr);
	I2CTWI_readBytes(I2C_MULTIIO_EEPROM_ADR, &buffer[0], length);
}

/**
 * Write "length" Bytes from the Buffer to the EEPROM. 
 * YOU CAN ONLY WRITE MAXIMAL [I2C_EEPROM_PAGESIZE] BYTES AT ONCE!!!
 * This is the Pagesize!
 * You can NOT cross a page boundary!
 * If (length + 2) is higher than I2CTWI_BUFFER_SIZE defined in RP6I2CmasterTWI.h,
 * you have to adapt I2CTWI_BUFFER_SIZE to the highest used (length + 2) value!
 */
void I2C_EEPROM_writeBytes(uint16_t startAddr, uint8_t *buffer, uint8_t length)
{
	uint8_t i, addrbuffer[length + 2];
	addrbuffer[0] = (startAddr >> 8);
	addrbuffer[1] = startAddr;
	for(i = 0; i < length; i++) {
		addrbuffer[i + 2] = buffer[i];
	}
	I2CTWI_transmitBytes(I2C_MULTIIO_EEPROM_ADR, &addrbuffer[0], (length + 2));
	mSleep(5);
}

/*****************************************************************************/
// 3V3 Voltage Sensor:

uint16_t adc3v3;						// 3V3 voltage sensor ADC value

/**
 * This function reads and returns the ADC value of
 * the 3V3 voltage sensor. The value is also stored
 * in adc3v3.
 *
 */
uint16_t get3V3Sensor(void)
{
	adc3v3 = readADC(ADC_MULTIIO_3V3);
	return adc3v3;
}

double v3v3;							// 3V3 voltage [V]

/**
 * Calculates and returns the 3.3V voltage value
 * by using the data read from the 3V3 voltage
 * sensor with the function get3V3Sensor().
 *
 */
double calculate3V3(void)
{
	return (5.0 / 1024.0 * adc3v3);
}

/**
 * Measures and returns the 3.3V voltage value.
 * The ADC value of the 3V3 voltage sensor is also
 * stored in adc3v3.
 *
 */
double measure3V3(void)
{
	adc3v3 = readADC(ADC_MULTIIO_3V3);
	return (5.0 / 1024.0 * adc3v3);
}

/*****************************************************************************/
// Touch Sensor (with NE555):

uint16_t adcTouch;						// Touch sensor ADC value
uint8_t touch = 0;						// True (1), if touched

/**
 * Checks if the touch sensor antenna is touched - returns 1,
 * if touched or 0, if the antenna is NOT touched.
 *
 */
uint8_t getTouch(void)
{
	adcTouch = readADC(ADC_MULTIIO_TOUCH);
	if (adcTouch > ADCVAL_LIMIT_T) return 1;
	else return 0;
}

/*****************************************************************************/
// Buttons:

uint16_t adcButtons;					// Keypad ADC value
uint8_t releasedMultiIOButtonNumber;	// Released (last pressed) button
uint8_t pressedMultiIOButtonNumber;		// Actually pressed button

/**
 * Checks which button is pressed - returns the button number,
 * or 0, if no button is pressed.
 * Maybe the values of ADCVAL_LIMITxx have to change because
 * of variations in the resistors of the keypad! This is done
 * in RP6Control_MultiIO.h, if you define other ADC values for
 * your 4 buttons in ADCVAL_BUTTON1..ADCVAL_BUTTON4.
 *
 */
uint8_t getMultiIOPressedButtonNumber(void)
{
	adcButtons = readADC(ADC_MULTIIO_BUTTONS);
	if(adcButtons < 1020) {
		nop();
		nop();
		nop();
		adcButtons += readADC(ADC_MULTIIO_BUTTONS);
		adcButtons >>= 1;
	}
	if(adcButtons < ADCVAL_LIMIT12)
		return 1;
	if(adcButtons < ADCVAL_LIMIT23)
		return 2;
	if(adcButtons < ADCVAL_LIMIT34)
		return 3;
	if(adcButtons < ADCVAL_LIMIT40)
		return 4;
	return 0;
}

/**
 * This function has to be called frequently out of the
 * main loop and checks if a button is pressed! It only returns 
 * the button number a single time, DIRECTLY when the button is
 * pressed.
 * 
 * This is useful for non-blocking keyboard check in the
 * main loop. You don't need something like 
 * "while(getMultiIOPressedButtonNumber());" to wait for the
 * button to be released again!
 */
uint8_t checkMultiIOPressedButtonEvent(void)
{
	static uint8_t pressed_button = 0;
	if(pressed_button) {
		if(!getMultiIOPressedButtonNumber()) 
			pressed_button = 0;
	}
	else {
		pressed_button = getMultiIOPressedButtonNumber();
		if(pressed_button)
			return pressed_button;
	}
	return 0;
}

/**
 * This function has to be called frequently out of
 * the main loop and checks if a button is pressed AND
 * released. It only returns the button number a single
 * time, AFTER the button has been released.
 * 
 * This is useful for non-blocking keyboard check in the
 * main loop. You don't need something like 
 * "while(getMultiIOPressedButtonNumber());" to wait for the
 * button to be released again!
 */
uint8_t checkMultiIOReleasedButtonEvent(void)
{
	static uint8_t released_button = 0;
	if(released_button) {
		if(!getMultiIOPressedButtonNumber()) {
			uint8_t tmp = released_button;
			released_button = 0;
			return tmp;
		}
	}
	else
		released_button = getMultiIOPressedButtonNumber();
	return 0;
}

/*****************************************************************************/
// LEDs:

/** 
 * Set the 4 status LEDs of the MultiIO.
 *
 * Example:
 *			setMultiIOLEDs(0b1010);
 *			// this clears LEDs 1 and 3
 *          // and sets LEDs 2 and 4!
 *
 */
void setMultiIOLEDs(uint8_t leds)
{
	if (leds & 0b00000001) PCA9685_set(CHLED1, 4095);
	else PCA9685_set(CHLED1, 0);
	if (leds & 0b00000010) PCA9685_set(CHLED2, 4095);
	else PCA9685_set(CHLED2, 0);
	if (leds & 0b00000100) PCA9685_set(CHLED3, 4095);
	else PCA9685_set(CHLED3, 0);
	if (leds & 0b00001000) PCA9685_set(CHLED4, 4095);
	else PCA9685_set(CHLED4, 0);
}

/** 
 * Dim the 4 status LEDs of the MultiIO.
 *
 * Input: led  -> LED number [1..4]
 *        duty -> Duty cycle [0..4095]
 *
 * Example:
 *			dimMultiIOLED(2,2048);
 *			// this dims LED2 with a
 *          // duty cycle of 50% !
 *
 */
void dimMultiIOLED(uint8_t led, uint16_t duty)
{
	if (led == 1) PCA9685_set(CHLED1, duty);
	if (led == 2) PCA9685_set(CHLED2, duty);
	if (led == 3) PCA9685_set(CHLED3, duty);
	if (led == 4) PCA9685_set(CHLED4, duty);
}

/** 
 * Set ONLY LED1, don't change anything for the other LEDs.
 *
 * Input: led -> 0 (false) = LED off
 *               >0 (true) = LED on
 *
 */
void setMultiIOLED1(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED1, 4095); 
	else PCA9685_set(CHLED1, 0);	
}	

/** 
 * Set ONLY LED2, don't change anything for the other LEDs.
 */
void setMultiIOLED2(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED2, 4095); 
	else PCA9685_set(CHLED2, 0);	
}	

/** 
 * Set ONLY LED3, don't change anything for the other LEDs.
 */
void setMultiIOLED3(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED3, 4095); 
	else PCA9685_set(CHLED3, 0);	
}	

/** 
 * Set ONLY LED4, don't change anything for the other LEDs.
 */
void setMultiIOLED4(uint8_t led)
{
	if (led > 0) PCA9685_set(CHLED4, 4095); 
	else PCA9685_set(CHLED4, 0);	
}

/*****************************************************************************/
// Buzzer:

/**
 * Call this once before using the buzzer.
 *
 */
void Buzzer_init(void)
{
	IO_MULTIIO_BUZZER_DDR |= IO_MULTIIO_BUZZER_IN;
	IO_MULTIIO_BUZZER_PORT &= ~IO_MULTIIO_BUZZER_IN;
}

/**
 * You can use this function to make the buzzer beep ;)
 * with a frequency of about 1000 Hz.
 * This function is BLOCKING and generates a delay for the
 * sound.
 *
 * Input: time  -> sound length [ms]
 *
 * Example:
 *   buzzer(150);
 *
 */
void buzzer(uint16_t time)
{
	if (!time) return;
	while (time--) {
		IO_MULTIIO_BUZZER_PORT |= IO_MULTIIO_BUZZER_IN;
		sleep(5);
		IO_MULTIIO_BUZZER_PORT &= ~IO_MULTIIO_BUZZER_IN;
		sleep(5);
	}
}

/*****************************************************************************/
/*****************************************************************************/
// MultiIO Project Board initialisation:

/**
 * You MUST call this function at the beginning of a
 * main program, that uses the MultiIO Project Board. 
 *
 */
void multiio_init(void)
{
	// Voltage & current sensor:
	LTC2990_init();								// Init VCS
	// Servo Controller:
	PCA9685_init(50);							// Init PWM 50 Hz
	// Servo power:
	setServoPower(0);							// Servo power off
	// Buzzer:
	Buzzer_init();								// Init buzzer
}

/*****************************************************************************/
/*****************************************************************************/

/******************************************************************************
 * Additional info
 * ****************************************************************************
 * Changelog:
 * - v. 1.0 (initial release) 23.02.2013 by Dirk
 *
 * ****************************************************************************
 */

/*****************************************************************************/
// EOF
Erklärung
Demo

makefile:

...
TARGET = TARGET = RP6Control_MultiIO
...
SRC += RP6Control_MultiIOLib.c
...

Datei RP6Control_MultiIO.c:

/* 
 * ****************************************************************************
 * RP6 ROBOT SYSTEM - RP6 CONTROL M32 Examples
 * ****************************************************************************
 * Example: RP6Control MultiIO
 * Author(s): Dirk
 * ****************************************************************************
 * Description:
 * In this example we show a first test for the MultiIO Project Board.
 * 
 * ############################################################################
 * The Robot does NOT move in this example! You can simply put it on a table
 * next to your PC and you should connect it to the PC via the USB Interface!
 * ############################################################################
 * ****************************************************************************
 */

/*****************************************************************************/
// Includes:

#include "RP6ControlLib.h" 				// The RP6 Control Library. 
										// Always needs to be included!
#include "RP6I2CmasterTWI.h"			// Include the I2C-Bus Master Library

/*****************************************************************************/
/*****************************************************************************/
// Include our new "RP6Control MultiIO library":
// (This is the library for accessing the MultiIO Project Board!)

#include "RP6Control_MultiIOLib.h"

/*****************************************************************************/

/**
 * Write a floating point number to the UART.
 *
 * Example:
 *
 *			// Write a floating point number to the UART (no exponent):
 *			writeDouble(1234567.890, 11, 3);
 *
 * The value of prec (precision) defines the number of decimal places.
 * For 32 bit floating point variables (float, double ...) 6 is
 * the max. value for prec (7 relevant digits).
 * The value of width defines the overall number of characters in the
 * floating point number including the decimal point. The number of
 * pre-decimal positions is: (width - prec - 1).
 */
void writeDouble(double number, uint8_t width, uint8_t prec)
{char buffer[width + 1];
	dtostrf(number, width, prec, &buffer[0]);
	writeString(&buffer[0]);
}

/*****************************************************************************/
// I2C Error handler

/**
 * This function gets called automatically if there was an I2C Error like
 * the slave sent a "not acknowledge" (NACK, error codes e.g. 0x20 or 0x30).
 * The most common mistakes are: 
 *   - using the wrong address for the slave
 *   - slave not active or not connected to the I2C-Bus
 *   - too fast requests for a slower slave
 * Be sure to check this if you get I2C errors!
 */
void I2C_transmissionError(uint8_t errorState)
{
	writeString_P("\nI2C ERROR --> TWI STATE IS: 0x");
	writeInteger(errorState, HEX);
	writeChar('\n');
}

/*****************************************************************************/
// Main function - The program starts here:

int main(void)
{
	initRP6Control();	// Always call this first! The Processor will not
						// work correctly otherwise. 

	initLCD(); // Initialize the LC-Display (LCD)
			   // Always call this before using the LCD!

	setLEDs(0b1111);
	mSleep(500);
	setLEDs(0b0000);

	writeString_P("\n\nRP6Control Multi IO Selftest 1!\n"); 

	// IMPORTANT:
	I2CTWI_initMaster(100); // Initialize the TWI Module for Master operation
							// with 100kHz SCL Frequency


	// Register the event handler:
	I2CTWI_setTransmissionErrorHandler(I2C_transmissionError);

	setLEDs(0b1111);

	// Write a text message to the LCD:
	showScreenLCD("################", "################");
	mSleep(1500);
	showScreenLCD(" RP6Control M32", "Example Program");
	mSleep(2500); 
	showScreenLCD("  RP6 Multi IO", "   Selftest 1");
	mSleep(2500);
	clearLCD();

	setLEDs(0b0000);

	// ---------------------------------------

	uint8_t onoff = 0;
	uint16_t servopos = SERVO1_LT;

	startStopwatch1();

	// IMPORTANT:
	multiio_init();								// MultiIO init!!!
	//setServoPower(1);							// Servo power ON!

	// ----------------------------------------------
	// Set RTC once (battery empty or not existing:
	rtc_time.second = 0;
	rtc_time.minute = 0;
	rtc_time.hour = 12;				// 12:00
	rtc_date.weekday = R_TH;
	rtc_date.day = 10;
	rtc_date.month = 1;
	rtc_date.year = 2013;			// Do, 10.1.2013
	DS1307_write();
	// Remove this, if RTC is set and running!!!
	// ----------------------------------------------

	// EEPROM test:
	writeString_P("\nWriting 128 to EEPROM address 5:\n");
	I2C_EEPROM_writeByte(5, 128);
	mSleep(500);
	writeString_P("Done!\n"); 
	writeString_P("\nReading EEPROM address 5:\n");
	uint8_t tmp = I2C_EEPROM_readByte(5);
	mSleep(500);
	I2C_EEPROM_writeByte(5, 0);
	writeString_P("Done!\n"); 
	writeString_P("EEPROM address 5 content: ");
	writeInteger(tmp, DEC);
	writeString_P("\n"); 

	// Buzzer test:
    buzzer(330);
	mSleep(200);
    buzzer(330);
	mSleep(200);
    buzzer(330);
	mSleep(1000);
    buzzer(330);
	mSleep(200);
    buzzer(330);
	mSleep(200);
    buzzer(330);

	while(true) 
	{
		if(getStopwatch1() > 1000) // 1s
		{
			if (onoff) onoff = 0;
			else onoff = 1;

			// Buttons ADC test:
			clearLCD();
			pressedMultiIOButtonNumber = getMultiIOPressedButtonNumber();
			setCursorPosLCD(0, 0);
			writeStringLCD("Button: ");
			writeIntegerLCD(pressedMultiIOButtonNumber, DEC);
			setCursorPosLCD(1, 0);
			writeStringLCD("ADC: ");
			writeIntegerLCD(adcButtons, DEC);

			// 3V3 voltage sensor ADC test:
			v3v3 = measure3V3();
			writeString("\n3V3 Voltage: ");
			writeDouble(v3v3, 4, 1);
			writeString("V\nADC 3V3: ");
			writeInteger(adc3v3, DEC);

			// Touch sensor ADC test:
			touch = getTouch();
			if (touch) writeString("\nTOUCHED!!!");
			else writeString("\nNOT touched.");
			writeString("\nADC Touch: ");
			writeInteger(adcTouch, DEC);

			// Temperature sensor test:
			temperature = TCN75_measure();		// Measure
			writeString("\nTemperature: ");
			writeDouble(temperature, 5, 1);
			writeString("°\n");

			// Servo controller test:
			//   LEDs:
			if (onoff) {
				setMultiIOLED1(1);
				setMultiIOLED2(0);
				setMultiIOLED3(0);
				setMultiIOLED4(1);
			}
			else
				setMultiIOLEDs(0b0110);
			//   Servo 1:
			setServo(1, servopos);
			servopos += 10;
			if (servopos > SERVO1_RT) servopos = SERVO1_LT;

			// RTC test:
			DS1307_read();
			writeString("RTC: ");
			writeIntegerLength(rtc_time.hour, DEC, 2);
			writeString(":");
			writeIntegerLength(rtc_time.minute, DEC, 2);
			writeString(":");
			writeIntegerLength(rtc_time.second, DEC, 2);
			writeString("  ");
			writeIntegerLength(rtc_date.day, DEC, 2);
			writeString(".");
			writeIntegerLength(rtc_date.month, DEC, 2);
			writeString(".");
			writeIntegerLength(rtc_date.year, DEC, 4);
			writeString("\n");

			// Voltage & current sensor test:
			LTC2990_measure();
			writeString("Temperature: ");
			writeDouble(tint, 5, 1);
			writeString("°\n");
			writeString("BAT Current: ");
			writeDouble(cbat, 6, 1);
			writeString("mA\nBAT Voltage: ");
			writeDouble(vbat, 4, 1);
			writeString( "V\nSERVO Volt.: ");
			writeDouble(vservo, 4, 1);
			writeString( "V\nVCC Voltage: ");
			writeDouble(vcc, 4, 1);
			writeString("V\n");

			setStopwatch1(0);
		}

		task_I2CTWI();
	}

	return 0;
}
Erklärung

Servo-Library

Auf der MultiIO is ein 10-poliger Wannenstecker "ServosM32" und ein 8x3-poliger Servo-Anschluß-Stecker vorgesehen, um 8 Servos direkt an die RP6Control M32 anschließen zu können. Dazu muss der I/O-Wannenstecker der M32 mit dem o.g. Wannenstecker für die Servos verbunden werden. Man kann dann bis zu 8 Servos an den Servo-Anschluß-Stecker der MultiIO anstecken.

Dieser M32 Servo-Anschluß auf der MultiIO dient also NUR dazu, das Anschließen von Servos zu erleichtern. Die MultiIO steuert diese Servos NICHT! Sie stellt allerdings die Stromversorgung für die Servos zur Verfügung. Das bedeutet, dass die Servo-Spannung auf der MultiIO eingeschaltet werden muss, wenn man diese Steckverbindung nutzen will.

Wenn man die RP6Control M32 Library für 8 Servos nicht verändern will,
muss man man den Jumper J_SERVOS-On auf der MultiIO aufstecken.

Die RP6Control M32 Library für 8 Servos findet ihr HIER!

RP6 BASE

Die RP6(v2) BASE (= "RP6") kann über den I2C-Bus alle I2C-Sensoren und I2C-Aktoren ansteuern. Da der RP6 nur über wenige freie Portpins verfügt, muss man eine Auswahl treffen, welche weiteren Funktionen man nutzen will.

Es gibt auf dem RP6 auch keine passenden Wannenstecker (wie auf der M32, M128 und M256), um auf einfache Weise eine mehrpolige Verbindung zu den IO-Mxxx, ADC-Mxxx oder ADC-M256 Steckern der Multi IO Platine herzustellen. Stattdessen kann man einzelne Portpins des RP6 mit der Multi IO Platine verbinden. Die folgende Tabelle zeigt mögliche Verbindungen:

RP6-Port RP6-Funktion RP6-Stecker:Pin I/O Bemerkungen Z.B. für Multi IO-Funktion
PA0 ADC0 ADC0:3 I/O Freier ADC oder IO BUTTONS, TOUCH, SHARPS_L/R, 3V3 ...
PA1 ADC1 ADC1:3 I/O Freier ADC oder IO LFS_L/M/R, SNAKE_L/R, LDR1/2 ...
PA4 ADC4 XBUS:8 I/O XBUS INT1! Falls nicht für den I2C-Bus benutzt: freier IO * SNAKE_SWITCH, SNAKE_KEY ...
PB1 T1 IO4 *** I Status LED5! Zusätzlich als Input z.B. für Taster nutzbar * BUMPER_L/R ...
PB7 SCK IO3 **, ISP:7 I Status LED4! Zusätzlich als Input z.B. für Taster nutzbar * BUMPER_L/R ...
PC4 TDO IO1 I Status LED1! Zusätzlich als Input z.B. für Taster nutzbar * SNAKE_KEY ...
PC5 TDI IO2 I Status LED2! Zusätzlich als Input z.B. für Taster nutzbar * DCF77 ...
PD0 RXD PRG/U:2 I/O UART RX! Nutzbar NUR, wenn USB-Interface abgezogen, als UART RX oder freier IO RX, SHARPS_PWR ...
PD1 TXD PRG/U:3 I/O UART TX! Nutzbar NUR, wenn USB-Interface abgezogen, als UART TX oder freier IO TX, LFS_PWR ...

Zu *) ACHTUNG: Bestimmte Beschaltung erforderlich! Sollte nur genutzt werden, wenn man sich gut mit dem RP6 auskennt!

Zu **) RP6v2: IO4!

Zu ***) RP6v2: IO5!

Multi IO Projekt Library

Aus den genannten Gründen kann es keine generelle Multi IO
Projekt Library für die RP6 BASE geben! Ich bin gern dabei,
wenn jemand die M32 Library für die RP6 Base umschreiben
möchte!

Siehe auch

Weblinks

Alle wichtigen Daten (Lötanleitung, Anleitung in .pdf-Form, Schaltpläne) findet ihr HIER

Servo-Lib für M32 von Dirk

Orientierungs-Mitmach-Projekt von Dirk

Mitmachprojekt Orientierung

Umbau des Snake Vision für RP6

EEPROM

Autoren

--Dirk 08:48, 09. Mär 2013 (CET)

--fabqu 21:30, 09. Mär 2013 (CET)


LiFePO4 Speicher Test