4.1 Bereitstellen grundlegender Funktionalitäten
Im ersten Schritt ging es darum, den Mikrocontroller so zu programmieren, dass dieser die für dieses Projekt grundlegenden Funktionalitäten bereitstellen kann.
Der Mikrocontroller befand sich vorerst auf dem STK500(siehe Kapitel 2.4.1). Um dessen Komponenten im Mikrocontroller nutzen zu können, müssen dafür Register initialisiert werden oder Funktionalitäten wie z.B. Bibliotheken für das LC-Display bereit gestellt werden.
Die folgenden Kapitel beschreiben den Programmcode, der notwendig ist um diese Funktionalitäten bereitzustellen.
4.1.1 Taster
Um die Taster des STK500 im Mikrocontroller nutzen zu können müssen diese mit dem Mikrocontroller verbunden und entprellt55Als Prellen bezeichnet man das ungewollte mehrfache Schalten eines mechanischen Schalters bei einem einzelnen Schaltvorgang. werden.
Dazu muss die Stiftleiste von PortA mit der Stiftleiste für die Taster verbunden werden. Das Entprellen der Taster wird softwareseitig realisiert. Dies bietet sich bei einem Mikrocontroler an. Dazu gibt es vorgefertigte Bibliotheken die genutzt werden können. Im Projekt wurde die Bibliothek Debounce.h(4) von Peter Dannegger genutzt. Sie ist sehr komfortabl und funktionsreich und basiert auf Timer-Interrupts. Um sie zu nutzen wird die Datei Debounce.h in das Projektverzeichnis kopiert und mit Zeile 1 des Codelisting 1 in das Programm eingebunden. Die Zeilen 2-10 spiegeln die Funktion zum Initialisieren der Bibliothek wieder. Diese Zeilen müssen auf den jeweils verwendeten Mikrocontroller angepasst werden.
Durch die Verwendung der Bibliothek ist es möglich Funktionen wie z.B. get_key_press() zu nutzen um den Status der Taster prellfrei auszulesen und diese Information für Entscheidungen im Programmablauf zu verwenden.
| 1 | keywordstyle include "Debounce.h" // Taster entprellen |
| 2 | void debounce_init (void) { // Taster entprellen |
| 3 | KEY_DDR &= ~ALL_KEYS; // configure key port for input |
| 4 | KEY_PORT |= ALL_KEYS; // and turn on pull up resistors |
| 5 | TCCR0B = (1 << CS02) | (1 << CS00); // divide by 1024 |
| 6 | // preload for 10ms |
| 7 | TCNT0 = (uint8_t) (int16_t) -(F_CPU / 1024 * 10 * 10e-3 + 0.5); |
| 8 | TIMSK0 |= 1 << TOIE0; // enable timer interrupt |
| 9 | sei(); // global enable Interrupts |
| 10 | } |
| 11 | if (get_key_press(1 << KEY4)) |
| 12 | menu_select(&menu_context); // Aktuellen Menuepunkt auswaehlen |
4.1.2 LEDs
LEDs sollen im Programmablauf genutzt werden können, um z.B. Fehler zu signalisieren.
Dazu muss zuerst die Stiftleiste von PortB mit der LED Stiftleiste des STK500 verbunden werden. Um LEDs an PortB betreiben zu können müssen die entsprechenden Pins im Register DDRB als Ausgänge definiert werden. Dies geschieht in Zeile 1 des Codelisting 2. Die Bibliothek zum Entprellen der Taster nutzt die Variablen LED_DDR und LED_PORT. Diese Variablen werden auch hier genutzt um auf die Register zuzugreifen. Dies gewährleistet eine bessere Übersicht. Die Werte im 8-Bit Register LED_PORT spiegeln die Spannungen an den Pins des PortB am Mikrocontroller wieder. Da die LEDs auf dem STK500 mit active-low-Logik betrieben werden, muss das jeweilige Bit gelöscht, also auf ’’0’’, gesetzt werden damit die LED leuchtet. Um alle Bits in einem Register zu verändern kann das Register mit einem 2-stelligen Hex-Wert (8-Bit) oder einem 8 stelligen binären Bitmuster beschrieben werden. In Zeile 2 werden alle Bits mit dem Hex-Wert 0xFF auf ’’1’’ gesetzt und somit alle LEDs ausgeschaltet. Um ein einzelnes Bit zu verändern, können die Anweisungen in den Zeilen 3 und 4 verwendet werden. Dabei steht das ’’X’’ in PBX für die x-te Stelle im Register die gesetzt oder gelöscht werden soll.
Es ist damit möglich im Programmablauf einzelne LEDs anzusteuern.
| 1 | LED_DDR = 0xFF; // LED Port Richtung definieren (Ausgang) |
| 2 | LED_PORT = 0xFF; // LEDs ausschalten |
| 3 | LED_PORT &= ~((1 << PBX)); // loescht Bit an PortB - LED an |
| 4 | LED_PORT |= ((1 << PBX)); // setzt Bit an PortB - LED aus |
4.1.3 Ansteuerung des LC-Display
Um den aktuellen Status des Motor komfortabel in Textform anzeigen zu können und die Schrittmotorkarte menübasiert ansteuern zu können wird ein LC-Display verwendet. Das verwendete Display ist alpha numerisch und kann 4x20 Zeichen anzeigen.
Die meisten LC-Displays werden auf die gleiche Weise angesteuert. Hier gibt es fertige Bibliotheken die frei genutzt werden können. Im Projekt wurde die Bibliothek von Peter Fleury (5) verwendet. Die Bibliothek wird heruntergeladen und die Dateien lcd.c und lcd.h in das Projektverzeichnis entpackt. Die Bibliothek wird mit #include ’’lcd.h’’ eingebunden. In der lcd.h müssen dann noch die Daten des Displays eingegeben werden (siehe Codelisting 3 Zeilen 2–10).
Danach kann das Display im Programm mit den Befehlen aus Zeile 12–21 angesteuert werden.
| 1 | /**< Use 0 for HD44780 controller, 1 for KS0073 controller */ |
| 2 | define LCD_CONTROLLER_KS0073 0 |
| 3 | define LCD_LINES 4 /**< number of visible lines of the display */ |
| 4 | define LCD_DISP_LENGTH 19 /**< visibles characters per line of the display */ |
| 5 | define LCD_LINE_LENGTH 0x40 /**< internal line length of the display */ |
| 6 | define LCD_START_LINE1 0x00 /**< DDRAM address of first char of line 1 */ |
| 7 | define LCD_START_LINE2 0x40 /**< DDRAM address of first char of line 2 */ |
| 8 | define LCD_START_LINE3 0x14 /**< DDRAM address of first char of line 3 */ |
| 9 | define LCD_START_LINE4 0x54 /**< DDRAM address of first char of line 4 */ |
| 10 | define LCD_WRAP_LINES 1 /**< 0: no wrap, 1: wrap at end of visibile line */ |
| 11 | // Funktionen zum Ansteuern des Displays: |
| 12 | extern void lcd_init(uint8_t dispAttr); |
| 13 | extern void lcd_clrscr(void); |
| 14 | extern void lcd_home(void); |
| 15 | extern void lcd_gotoxy(uint8_t x, uint8_t y); |
| 16 | extern void lcd_putc(char c); |
| 17 | extern void lcd_puts(const char *s); |
| 18 | extern void lcd_puts_p(const char *progmem_s); |
| 19 | extern void lcd_command(uint8_t cmd); |
| 20 | extern void lcd_data(uint8_t data); |
| 21 | define lcd_puts_P(__s) lcd_puts_p(PSTR(__s)) |
4.1.4 RS-232-Schnittstelle
RS-232 ist der Name der am häufigsten verwendeten seriellen Schnittstelle um Daten zwischen zwei elektronischen Geräten hin und her zu senden. (7)
Auf dem STK500 ist bereits eine serielle Schnittstelle vorbereitet. Um diese nutzen zu können, müssen die Pins 3 und 4 des PortC (erster UART) des Mikrocontrollers mit der Stiftleiste Rx/Tx auf dem STK500 verbunden werden. Eine weitere Schnittstelle wurde auf einem Steckbrett aufgebaut. Diese wurde mit den Pins 1 und 2 des PortC (zweiter UART) des Mikrocontrollers verbunden. Um die Schnittstellen im Mikrocontroller nutzen zu können müssen diese noch durch setzen von Bits in den entsprechenden Registern des Mikrocontrollers aktiviert werden.
Das Codelisting 4 teilt sich in 4 wesentliche Bereiche:
Zeilen 1 – 2: Setzen der Baudrate und einbinden der benötigten Bibliotheken.
Zeilen 3 – 17: Initialisieren der Schnittstellen durch setzen der richtigen Bits in den entsprechenden Registern.
Zeilen 18 – 35: Funktionen zum Senden von Daten
Zeilen 36 – 65: Funktionen zum Empfangen von Daten
| 1 | define BAUD 9600 // BAUD Rate definieren |
| 2 | keywordstyle include <util/setbaud.h> // UART Funktionen |
| 3 | // UART Initialisieren |
| 4 | void uart_init () { |
| 5 | // UART 0 - IN (Rapidform Software/Terminal) |
| 6 | UBRR0H = UBRRH_VALUE; |
| 7 | UBRR0L = UBRRL_VALUE; |
| 8 | UCSR0C = (3 << UCSZ00); |
| 9 | UCSR0B |= (1 << TXEN0); //Transmitter Enabled |
| 10 | UCSR0B |= (1 << RXEN0); // UART RX einschalten |
| 11 | // UART 1 - OUT (Stepper Karte/Drehtisch) |
| 12 | UBRR1H = UBRRH_VALUE; |
| 13 | UBRR1L = UBRRL_VALUE; |
| 14 | UCSR1C = (3 << UCSZ00); |
| 15 | UCSR1B |= (1 << TXEN1); //Transmitter Enabled |
| 16 | UCSR1B |= (1 << RXEN1); // UART RX einschalten |
| 17 | } |
| 18 | // UART Zeichen senden |
| 19 | void uart_put_charater (unsigned char c, int dir) { |
| 20 | if (dir == D_RapidForm) { // To Rapidform |
| 21 | while (!(UCSR0A & (1 << UDRE0))) {}//warten bis Senden moeglich |
| 22 | UDR0 = c; // sende Zeichen |
| 23 | } |
| 24 | else { // To Stepper |
| 25 | while (!(UCSR1A & (1 << UDRE1))) {}//warten bis Senden moeglich |
| 26 | UDR1 = c; // sende Zeichen |
| 27 | } |
| 28 | } |
| 29 | // UART String senden |
| 30 | void uart_put_string (char *s, int dir) { |
| 31 | while (*s){ // so lange *s != ’\0’ Terminierungszeichen |
| 32 | uart_put_charater(*s, dir); // Zeichenweise senden |
| 33 | s++; |
| 34 | } |
| 35 | } |
| 36 | // UART Zeichen empfangen |
| 37 | int uart_get_character (int dir) { |
| 38 | if (dir == D_RapidForm) { // Aus RapidForm Register auslesen |
| 39 | while (!(UCSR0A & (1 << RXC0))) ; // warten bis Zeichen verfuegbar |
| 40 | return UDR0; // Zeichen aus UDR an Aufrufer zurueckgeben |
| 41 | } |
| 42 | if (dir == D_Stepper) { // Aus Schrittmotor Register auslesen |
| 43 | while (!(UCSR1A & (1 << RXC1))) ; // warten bis Zeichen verfuegbar |
| 44 | return UDR1; // Zeichen aus UDR an Aufrufer zurueckgeben |
| 45 | } |
| 46 | return -1; // Wenn nichts ausgelesen wurde -1 zurueckgeben |
| 47 | } |
| 48 | // UART String empfangen |
| 49 | void uart_get_string (char * string_in, int dir) { |
| 50 | char c; // Einzelnes Zeichen |
| 51 | int i = 0; // Zaehlvariable |
| 52 | do { |
| 53 | c = uart_get_character(dir); // Einzelnes Zeichen holen |
| 54 | if (c != ’\r’) { // Wenn keinn \r |
| 55 | *string_in = c; // Zeichen in Empfangsstring schreiben |
| 56 | string_in += 1; // Adresse des Empfangsstring um 1 ink |
| 57 | i++; // Zaehlvariable um 1 erhoehen |
| 58 | } |
| 59 | } while (i < 100 && c != ’\r’ && c != ’\n’); // So lange bis \r \n o. >100 Zeichen |
| 60 | *string_in = ’\0’; // 0 Terminieren |
| 61 | if (dir == D_Stepper) |
| 62 | LED_PORT |= ( 1 << LED3 ); // "Daten Vorhanden" LED ausschalten |
| 63 | else |
| 64 | LED_PORT |= ( 1 << LED2 ); // "Daten Vorhanden" LED ausschalten |
| 65 | } |
Damit stehen die essentiellen Funktionen uart_put_string(dir) und uart_get_string(dir) zur Verfügung. Mit diesen kann der Mikrocontroller über die serielle Schnittstelle Strings senden und empfangen. Der Parameter dir gibt dabei die Schnittstelle an über die gesendet oder empfangen werden soll.