Added lot's of code-files used during work
This commit is contained in:
parent
644121b478
commit
56d9bdd39e
155 changed files with 23423 additions and 0 deletions
194
source/ct-Bot/mcu/TWI_driver.c
Normal file
194
source/ct-Bot/mcu/TWI_driver.c
Normal file
|
@ -0,0 +1,194 @@
|
|||
/*
|
||||
* c't-Sim - Robotersimulator fuer den c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file TWI_driver.c
|
||||
* @brief TWI-Treiber (I2C)
|
||||
* @author Chris efstathiou hendrix@otenet.gr & Carsten Giesen (info@cnau.de)
|
||||
* @date 08.04.06
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
#include <avr/io.h>
|
||||
#include "TWI_driver.h"
|
||||
#include "global.h"
|
||||
|
||||
|
||||
/*!
|
||||
* TWI Bus initialsieren
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
int8 Init_TWI(void){
|
||||
TWAR = OWN_ADR; /*!< Eigenen Slave Adresse setzen */
|
||||
TWBR = 12; /*!< Setze Baudrate auf 100 KHz */
|
||||
/*!< 4 MHz xtal */
|
||||
TWCR = (1<<TWEN); /*!< TWI-Interface einschalten */
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
* TWI Buss schliesen
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
int8 Close_TWI(void){
|
||||
TWCR = (0<<TWEN); /*!< TWI-Interface ausschalten */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Warte auf TWI interrupt
|
||||
*/
|
||||
|
||||
void Wait_TWI_int(void){
|
||||
while (!(TWCR & (1<<TWINT)))
|
||||
;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sende Start Sequence
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
uint8 Send_start(void){
|
||||
TWCR = ((1<<TWINT)+(1<<TWSTA)+(1<<TWEN)); /*!< Sende START */
|
||||
|
||||
Wait_TWI_int(); /*!< Warte auf TWI interrupt */
|
||||
|
||||
if((TWSR != START)&&(TWSR != REP_START)) /*!< Ist der Status ein Anderer als Start (0x08) oder wiederholter Start (0x10) */
|
||||
return TWSR; /*!< -> error und Rueckgabe TWSR. */
|
||||
return SUCCESS; /*!< wenn OK Rueckgabe SUCCESS */
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sende Stop Sequence
|
||||
*/
|
||||
|
||||
void Send_stop(void){
|
||||
TWCR = ((1<<TWEN)+(1<<TWINT)+(1<<TWSTO));
|
||||
}
|
||||
|
||||
/*!
|
||||
* Hier wird der eigentliche TWI-Treiber angesprochen
|
||||
* @param *data_pack Container mit den Daten fuer den Treiber
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
uint8 Send_to_TWI(tx_type *data_pack){
|
||||
uint8 state,i,j;
|
||||
|
||||
state = SUCCESS;
|
||||
|
||||
for(i=0;(data_pack[i].slave_adr != OWN_ADR)&&(state == SUCCESS);i++) {
|
||||
state = Send_start();
|
||||
if (state == SUCCESS)
|
||||
state = Send_adr(data_pack[i].slave_adr);
|
||||
|
||||
/*!
|
||||
* Abhaengig von W/R senden oder empfangen
|
||||
*/
|
||||
if(!(data_pack[i].slave_adr & R)) {
|
||||
if (state == SUCCESS){
|
||||
/*!
|
||||
* Wenn W bis alle Daten gesendet sind
|
||||
*/
|
||||
for(j=0;((j<data_pack[i].size)&&(state == SUCCESS));j++)
|
||||
state = Send_byte(data_pack[i].data_ptr[j]);
|
||||
}
|
||||
}
|
||||
else{
|
||||
if (state == MRX_ADR_NACK) {
|
||||
state = Send_start();
|
||||
}
|
||||
|
||||
if (state == SUCCESS){
|
||||
/*!
|
||||
* Wenn R bis alle Daten empfangen sind
|
||||
*/
|
||||
for(j=0;((j<data_pack[i].size)&&(state == SUCCESS));j++){
|
||||
/*!
|
||||
* Wenn wir keine Daten mehr erwarten NACK senden
|
||||
*/
|
||||
if(j == data_pack[i].size-1)
|
||||
state = Get_byte(data_pack[i].data_ptr++,0);
|
||||
else
|
||||
state = Get_byte(data_pack[i].data_ptr++,1);
|
||||
}
|
||||
}
|
||||
}
|
||||
Send_stop();
|
||||
}
|
||||
Close_TWI();
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sende ein Byte
|
||||
* @param data das zu uebertragende Byte
|
||||
*/
|
||||
|
||||
uint8 Send_byte(uint8 data){
|
||||
Wait_TWI_int();
|
||||
TWDR = data;
|
||||
TWCR = ((1<<TWINT)+(1<<TWEN));
|
||||
Wait_TWI_int();
|
||||
if(TWSR != MTX_DATA_ACK)
|
||||
return TWSR;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sende Slave Adresse
|
||||
* @param adr die gewuenschte Adresse
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
uint8 Send_adr(uint8 adr){
|
||||
Wait_TWI_int();
|
||||
TWDR = adr;
|
||||
TWCR = ((1<<TWINT)+(1<<TWEN));
|
||||
Wait_TWI_int();
|
||||
if((TWSR != MTX_ADR_ACK)&&(TWSR != MRX_ADR_ACK))
|
||||
return TWSR;
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Empfange ein Byte
|
||||
* @param *rx_ptr Container fuer die Daten
|
||||
* @param last_byte Flag ob noch Daten erwartet werden
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
uint8 Get_byte(uint8 *rx_ptr,uint8 last_byte){
|
||||
Wait_TWI_int();
|
||||
if(last_byte)
|
||||
TWCR = ((1<<TWINT)+(1<<TWEA)+(1<<TWEN));
|
||||
else
|
||||
TWCR = ((1<<TWINT)+(1<<TWEN));
|
||||
Wait_TWI_int();
|
||||
*rx_ptr = TWDR;
|
||||
if(((TWSR == MRX_DATA_NACK)&&(last_byte == 0))||(TWSR == MRX_DATA_ACK))
|
||||
return SUCCESS;
|
||||
return TWSR;
|
||||
}
|
||||
|
||||
#endif
|
70
source/ct-Bot/mcu/adc.c
Normal file
70
source/ct-Bot/mcu/adc.c
Normal file
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file adc.c
|
||||
* @brief Routinen zum Einlesen der AnalogeingÄnge
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
//#include <avr/signal.h>
|
||||
|
||||
#include "adc.h"
|
||||
|
||||
/*!
|
||||
* Initialisert den AD-Umsetzer.
|
||||
* @param channel Für jeden Kanal, den man nutzen möchte,
|
||||
* muss das entsprechende Bit in channel gesetzt sein
|
||||
* Bit0 = Kanal 0 usw.
|
||||
*/
|
||||
void adc_init(uint8 channel){
|
||||
DDRA &= ~ channel; // Pin als input
|
||||
PORTA &= ~ channel; // Alle Pullups aus.
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liest einen analogen Kanal aus
|
||||
* @param channel Kanal - hex-Wertigkeit des Pins (0x01 fuer PA0; 0x02 fuer PA1, ..)
|
||||
*/
|
||||
uint16 adc_read(uint8 channel){
|
||||
uint16 result = 0x00;
|
||||
|
||||
// interne Refernzspannung AVCC, rechts Ausrichtung
|
||||
ADMUX= _BV(REFS0) ;//| _BV(REFS1); //|(0<<ADLAR);
|
||||
|
||||
ADMUX |= (channel & 0x07); // Und jetzt Kanal waehlen, nur single ended
|
||||
|
||||
ADCSRA= (1<<ADPS2) | (1<<ADPS1)| // prescale faktor= 128 ADC laeuft
|
||||
(1 <<ADPS0) | // mit 14,7456MHz/ 128 = 115,2kHz
|
||||
(1 << ADEN)| // ADC an
|
||||
(1 << ADSC); // Beginne mit der Konvertierung
|
||||
|
||||
while ( (ADCSRA & (1<<ADSC)) != 0){asm volatile("nop");} //Warten bis konvertierung beendet
|
||||
// Das sollte 25 ADC-Zyklen dauern!
|
||||
// also 1/4608 s
|
||||
result= ADCL;
|
||||
result+=(ADCH <<8); // Ergebnis zusammenbauen
|
||||
|
||||
return result;
|
||||
}
|
||||
#endif
|
111
source/ct-Bot/mcu/bot-2-pc.c
Normal file
111
source/ct-Bot/mcu/bot-2-pc.c
Normal file
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
* c't-Sim - Robotersimulator fuer den c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file bot-2-pc.c
|
||||
* @brief Verbindung zwischen c't-Bot und PC
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 28.2.06
|
||||
*/
|
||||
|
||||
#include "ct-Bot.h"
|
||||
#include "command.h"
|
||||
#include "uart.h"
|
||||
#include "bot-2-pc.h"
|
||||
#include "sensor.h"
|
||||
#include "motor.h"
|
||||
#include "led.h"
|
||||
#include "mouse.h"
|
||||
#include "log.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#ifdef MCU
|
||||
#ifdef BOT_2_PC_AVAILABLE
|
||||
|
||||
/*!
|
||||
* Diese Funktion nimmt die Daten vom PC entgegen
|
||||
* und wertet sie aus. dazu nutzt er die Funktion command_evaluate()
|
||||
*/
|
||||
void bot_2_pc_listen(void){
|
||||
// LOG_DEBUG(("%d bytes recvd",uart_data_available()));
|
||||
if (uart_data_available() >= sizeof(command_t)){
|
||||
// LOG_DEBUG(("%d bytes recvd",uart_data_available()));
|
||||
if (command_read() ==0){
|
||||
LOG_DEBUG(("command received"));
|
||||
command_evaluate();
|
||||
}else {
|
||||
// TODO Fehlerbehandlung
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Diese Funktion informiert den PC ueber alle Sensor und Aktuator-Werte
|
||||
*/
|
||||
void bot_2_pc_inform(void){
|
||||
int16 value1, value2;
|
||||
|
||||
command_write(CMD_AKT_MOT, SUB_CMD_NORM ,(int16*)&speed_l,(int16*)&speed_r,0);
|
||||
value1=(int16)led;
|
||||
command_write(CMD_AKT_LED, SUB_CMD_NORM ,&value1,&value1,0);
|
||||
|
||||
command_write(CMD_SENS_IR, SUB_CMD_NORM ,(int16*)&sensDistL,(int16*)&sensDistR,0);
|
||||
command_write(CMD_SENS_ENC, SUB_CMD_NORM ,(int16*)&sensEncL,(int16*)&sensEncR,0);
|
||||
command_write(CMD_SENS_BORDER, SUB_CMD_NORM ,(int16*)&sensBorderL,(int16*)&sensBorderR,0);
|
||||
command_write(CMD_SENS_LINE, SUB_CMD_NORM ,(int16*)&sensLineL,(int16*)&sensLineR,0);
|
||||
|
||||
command_write(CMD_SENS_LDR, SUB_CMD_NORM ,(int16*)&sensLDRL,(int16*)&sensLDRR,0);
|
||||
|
||||
value1= (int16) sensTrans; value2=0;
|
||||
command_write(CMD_SENS_TRANS, SUB_CMD_NORM ,&value1,&value2,0);
|
||||
|
||||
value1= (int16) sensDoor;
|
||||
command_write(CMD_SENS_DOOR, SUB_CMD_NORM ,&value1,&value2,0);
|
||||
|
||||
#ifdef MAUS_AVAILABLE
|
||||
value1=(int16)sensMouseDX;
|
||||
value2=(int16)sensMouseDY;
|
||||
command_write(CMD_SENS_MOUSE, SUB_CMD_NORM ,&value1,&value2,0);
|
||||
#endif
|
||||
|
||||
value1=(int16)sensError; value2=0;
|
||||
command_write(CMD_SENS_ERROR, SUB_CMD_NORM ,&value1,&value2,0);
|
||||
// command_write(CMD_SENS_RC5, SUB_CMD_NORM ,(int16*)&RC5_Code,&value2,0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
/*!
|
||||
* Meldet den Bot am c't-Sim an
|
||||
*/
|
||||
void bot_2_pc_init(void){
|
||||
int16 null =0;
|
||||
uint8 j;
|
||||
|
||||
uart_init();
|
||||
|
||||
for(j=0;j<5;j++)
|
||||
command_write(CMD_WELCOME, SUB_WELCOME_REAL ,&null,&null,0);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
69
source/ct-Bot/mcu/delay.c
Normal file
69
source/ct-Bot/mcu/delay.c
Normal file
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file delay.c
|
||||
* @brief Hilfsroutinen
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 20.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#ifdef NEW_AVR_LIB
|
||||
#include <util/delay.h>
|
||||
#else
|
||||
#include <avr/delay.h>
|
||||
#endif
|
||||
|
||||
#include "timer.h"
|
||||
|
||||
/*!
|
||||
* Warte 100 ms
|
||||
*/
|
||||
void delay_100ms(void){
|
||||
char counter;
|
||||
//wait (10 * 120000) cycles = wait 1200000 cycles
|
||||
counter = 0;
|
||||
while (counter != 5)
|
||||
{
|
||||
//wait (30000 x 4) cycles = wait 120000 cycles
|
||||
_delay_loop_2(30000);
|
||||
counter++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Delays for ms milliseconds
|
||||
* @param ms Anzahl der Millisekunden
|
||||
*/
|
||||
void delay(uint16 ms){
|
||||
uint32 start = TIMER_GET_TICKCOUNT_32;
|
||||
if ((uint8)start != TIMER_GET_TICKCOUNT_8) start = TIMER_GET_TICKCOUNT_32;
|
||||
uint32 ticksToWait = MS_TO_TICKS((uint32)ms);
|
||||
uint32 now;
|
||||
do {
|
||||
now = TIMER_GET_TICKCOUNT_32;
|
||||
if ((uint8)now != TIMER_GET_TICKCOUNT_8) now = TIMER_GET_TICKCOUNT_32;
|
||||
} while (now-start < ticksToWait);
|
||||
|
||||
}
|
||||
#endif
|
272
source/ct-Bot/mcu/display.c
Normal file
272
source/ct-Bot/mcu/display.c
Normal file
|
@ -0,0 +1,272 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file display.c
|
||||
* @brief Routinen zur Displaysteuerung
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 20.12.05
|
||||
*/
|
||||
#include "global.h"
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#ifdef MCU
|
||||
#ifdef DISPLAY_AVAILABLE
|
||||
|
||||
#include <avr/io.h>
|
||||
#ifdef NEW_AVR_LIB
|
||||
#include <util/delay.h>
|
||||
#else
|
||||
#include <avr/delay.h>
|
||||
#endif
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include "command.h"
|
||||
|
||||
#include "display.h"
|
||||
#include "led.h"
|
||||
#include "delay.h"
|
||||
#include "shift.h"
|
||||
#include "display.h"
|
||||
|
||||
/*! Puffergroesse fuer eine Zeile in bytes */
|
||||
#define DISPLAY_BUFFER_SIZE (DISPLAY_LENGTH + 1)
|
||||
|
||||
uint8 display_update=0; /*!< Muss das Display aktualisiert werden? */
|
||||
#ifdef DISPLAY_SCREENS_AVAILABLE
|
||||
#ifdef LOG_DISPLAY_AVAILABLE
|
||||
uint8 display_screen=4; /*!< Muss das Display aktualisiert werden? */
|
||||
#else
|
||||
uint8 display_screen=0; /*!< Muss das Display aktualisiert werden? */
|
||||
#endif
|
||||
#endif
|
||||
static char display_buf[DISPLAY_BUFFER_SIZE]; /*!< Pufferstring fuer Displayausgaben */
|
||||
|
||||
#define DISPLAY_CLEAR 0x01 /*!< Kommando zum Löschen */
|
||||
#define DISPLAY_CURSORHOME 0x02 /*!< Kommando für den Cursor */
|
||||
|
||||
#define DISPLAY_OUT 0x07 /*!< Output-Pins Display */
|
||||
#define DISPLAY_IN (1<<5) /*!< Input-Pins Display */
|
||||
|
||||
#define DISPLAY_PORT PORTC /*!< Port an dem das Display hängt */
|
||||
#define DISPLAY_DDR DDRC /*!< Port an dem das Display hängt */
|
||||
#define DPC (DISPLAY_PORT & ~DISPLAY_OUT) /*!< Port des Displays */
|
||||
//#define DRC (DDRC & ~DISPLAY_PINS)
|
||||
|
||||
//#define DISPLAY_READY_PINR PINC /*!< Port an dem das Ready-Flag des Display hängt */
|
||||
#define DISPLAY_READY_DDR DDRC /*!< Port an dem das Ready-Flag des Display hängt */
|
||||
#define DISPLAY_READY_PIN (1<<5) /*!< Pin an dem das Ready-Flag des Display hängt */
|
||||
|
||||
/*! RS-Leitung
|
||||
* legt fest, ob die Daten an das Display in den Textpuffer (RS=1) kommen
|
||||
* oder als Steuercode interpretiert werden (RS=0)
|
||||
*/
|
||||
#define DISPLAY_RS (1<<0) /*!< Pin an dem die RS-Leitung des Displays hängt */
|
||||
|
||||
/*! RW-Leitung
|
||||
* legt fest, ob zum Display geschrieben wird (RW=0)
|
||||
* oder davon gelesen wird (RW=1)
|
||||
*/
|
||||
#define DISPLAY_RW (1<<1) /*!< Pin an dem die RW-Leitung des Displays hängt */
|
||||
|
||||
/*! Enable Leitung
|
||||
* schaltet das Interface ein (E=1).
|
||||
* Nur wenn Enable auf High-Pegel liegt, läßt sich das Display ansprechen
|
||||
*/
|
||||
#define DISPLAY_EN (1<<2) /*!< Pin an dem die EN-Leitung des Displays hängt */
|
||||
|
||||
/*
|
||||
* Im Moment der Low-High-Flanke von ENABLE liest das Dislplay
|
||||
* die Werte von RS und R/W ein. Ist zu diesem Zeitpunkt R/W=0,
|
||||
* dann liest das Display mit der folgenden High-Low-Flanke von ENABLE
|
||||
* den Datenbus ein (Schreibzyklus).
|
||||
* War aber R/W=1, dann legt das Display ein Datenword auf den
|
||||
* Datenbus (Lese-Zyklus), solange bis die High-Low-Flanke von ENABLE
|
||||
* das Interface wieder deaktiviert.
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Übertrage Kommando an das Display
|
||||
* @param cmd Kommando
|
||||
*/
|
||||
void display_cmd(uint8 cmd){ //ein Kommando cmd an das Display senden
|
||||
uint8 i;
|
||||
shift_data_out(cmd,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
|
||||
// Enable muss für mind. 450 ns High bleiben, bevor es fallen darf!
|
||||
// ==> Also mind. 8 Zyklen warten
|
||||
for (i=0; i<150; i++){
|
||||
asm volatile("nop");
|
||||
}
|
||||
DISPLAY_PORT=DPC; // Alles zurück setzen ==> Fallende Flanke von Enable
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Ein Zeichen auf das Display schreiben
|
||||
* @param data Das Zeichen
|
||||
*/
|
||||
void display_data(char data){ //ein Zeichen aus data in den Displayspeicher schreiben
|
||||
uint8 i;
|
||||
shift_data_out(data,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY|DISPLAY_RS);
|
||||
|
||||
// Enable muss für mind. 450 ns High bleiben, bevor es fallen darf!
|
||||
// ==> Also mind. 8 Zyklen warten
|
||||
for (i=0; i<150; i++){
|
||||
asm volatile("nop");
|
||||
}
|
||||
DISPLAY_PORT=DPC; // Alles zurück setzen ==> Fallende Flanke von Enable
|
||||
}
|
||||
|
||||
/*!
|
||||
* Löscht das ganze Display
|
||||
*/
|
||||
void display_clear(void){
|
||||
display_cmd(DISPLAY_CLEAR); // Display loeschen, Cursor Home
|
||||
#ifdef DISPLAY_REMOTE_AVAILABLE
|
||||
command_write(CMD_AKT_LCD, SUB_LCD_CLEAR, NULL, NULL,0);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Positioniert den Cursor
|
||||
* @param row Zeile
|
||||
* @param column Spalte
|
||||
*/
|
||||
void display_cursor (uint8 row, uint8 column) {
|
||||
switch (row) {
|
||||
case 1:
|
||||
display_cmd (0x80 + column - 1);
|
||||
break;
|
||||
case 2:
|
||||
display_cmd (0xc0 + column - 1);
|
||||
break;
|
||||
case 3:
|
||||
display_cmd (0x94 + column - 1);
|
||||
break;
|
||||
case 4:
|
||||
display_cmd (0xd4 + column - 1);
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_REMOTE_AVAILABLE
|
||||
int16 r=row-1;
|
||||
int16 c=column-1;
|
||||
command_write(CMD_AKT_LCD, SUB_LCD_CURSOR, &c,&r,0);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* Init Display
|
||||
*/
|
||||
void display_init(void){
|
||||
shift_init();
|
||||
|
||||
DISPLAY_DDR |= DISPLAY_OUT; // Ausgänge
|
||||
DISPLAY_DDR &= ~DISPLAY_IN; // Eingänge
|
||||
|
||||
delay(12); // Display steht erst 10ms nach dem Booten bereit
|
||||
|
||||
// Register in 8-Bit-Modus 3x Übertragen, dazwischen warten
|
||||
shift_data_out(0x38,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
|
||||
DISPLAY_PORT= DPC;
|
||||
delay(5);
|
||||
shift_data_out(0x38,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
|
||||
DISPLAY_PORT= DPC;
|
||||
delay(5);
|
||||
shift_data_out(0x38,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
|
||||
DISPLAY_PORT= DPC;
|
||||
delay(5);
|
||||
|
||||
display_cmd(0x0f); //Display On, Cursor On, Cursor Blink
|
||||
|
||||
display_cmd(DISPLAY_CLEAR); // Display loeschen, Cursor Home
|
||||
|
||||
display_data('i');
|
||||
}
|
||||
|
||||
/*!
|
||||
* Zeigt einen String an
|
||||
* @return -1 falls string zuende 0 falls Zeile (20 zeichen) zuende
|
||||
*/
|
||||
/*int display_string(char data[20]){
|
||||
int i=0;
|
||||
|
||||
while ((i<20) && (data[i] != 0x00)){ // Abbruch, sobald ein Nullstring erreicht wird
|
||||
// oder 20 Zeichen gesendet sind
|
||||
display_data(data[i++]); // einzelnes Zeichen schicken
|
||||
}
|
||||
|
||||
// return -1 falls string zuende, 0 falls zeile (20 zeichen) zuende
|
||||
if (data[i]==0x00) return -1; else return 0;
|
||||
}
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Schreibt einen String auf das Display.
|
||||
* @param format Format, wie beim printf
|
||||
* @param ... Variable Argumentenliste, wie beim printf
|
||||
*/
|
||||
void display_printf(char *format, ...) {
|
||||
|
||||
unsigned int run = 0;
|
||||
va_list args;
|
||||
|
||||
/* Sicher gehen, das der zur Verfuegung stehende Puffer nicht
|
||||
* ueberschrieben wird.
|
||||
*/
|
||||
va_start(args, format);
|
||||
vsnprintf(display_buf, DISPLAY_BUFFER_SIZE, format, args);
|
||||
va_end(args);
|
||||
|
||||
/* Ausgeben bis Puffer leer ist */
|
||||
while(display_buf[run] != '\0') {
|
||||
display_data(display_buf[run]);
|
||||
run++;
|
||||
}
|
||||
|
||||
#ifdef DISPLAY_REMOTE_AVAILABLE
|
||||
command_write_data(CMD_AKT_LCD, SUB_LCD_DATA, NULL, NULL, display_buf);
|
||||
#endif
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
void display_test(){
|
||||
shift_init();
|
||||
|
||||
// shift_data_out(0xAA,SHIFT_LATCH,SHIFT_REGISTER_DISPLAY);
|
||||
|
||||
display_cmd(0x38); //Display auf 8 Bit Betrieb
|
||||
for(;;){}
|
||||
display_cmd(0x0f); //Display On, Cursor On, Cursor Blink
|
||||
|
||||
display_cmd(DISPLAY_CLEAR); // Display l<>schen, Cursor Home
|
||||
display_cursor(2,2);
|
||||
|
||||
display_string("Hallo");
|
||||
for(;;){
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
||||
|
||||
#endif
|
128
source/ct-Bot/mcu/ena.c
Normal file
128
source/ct-Bot/mcu/ena.c
Normal file
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file ena.c
|
||||
* @brief Routinen zur Steuerung der Enable-Leitungen
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "ena.h"
|
||||
#include "ct-Bot.h"
|
||||
#include "shift.h"
|
||||
#include "mouse.h"
|
||||
|
||||
#ifdef ENA_AVAILABLE
|
||||
|
||||
|
||||
uint8 ena =0; /*!< Sichert den Zustand der Enable-Leitungen */
|
||||
|
||||
/*!
|
||||
* Initialisiert die Enable-Leitungen
|
||||
*/
|
||||
void ENA_init(){
|
||||
DDRD |= 4;
|
||||
shift_init();
|
||||
ENA_set(0x00);
|
||||
}
|
||||
|
||||
|
||||
//void maus_sens_write(int8 adr, uint8 data);
|
||||
/*!
|
||||
* Schaltet einzelne Enable-Transistoren an
|
||||
* andere werden nicht beeinflusst
|
||||
* Achtung, die Treiber-Transistoren sind Low-Aktiv!!!
|
||||
* ENA_on schaltet einen Transistor durch
|
||||
* Daher zieht es die entsprechende ENA_XXX-Leitung (mit Transistor) auf Low und NICHT auf High
|
||||
* @param enable Bitmaske der anzuschaltenden LEDs
|
||||
*/
|
||||
void ENA_on(uint8 enable){
|
||||
// uint8 i;
|
||||
// Maussensor und MMC-Karte haengen zusammen
|
||||
if (enable == ENA_MOUSE_SENSOR){ // Maus sensor an, MMC aus
|
||||
|
||||
// if ((ena & ENA_MMC) ==0){ // War die MMC-Karte an?
|
||||
ena |= ENA_MMC; // MMC aus
|
||||
|
||||
// PORTD |= 4; // Fliplops takten
|
||||
// PORTD &= ~4;
|
||||
//
|
||||
// for (i=0; i<200; i++){ // Ein paar flanken schocken, damit auch sicher danach ruhe ist
|
||||
// PORTB &= ~(1<<7);
|
||||
// PORTB |= (1<<7);
|
||||
// }
|
||||
// }
|
||||
|
||||
// Und dann den Maussensor an
|
||||
ena &= ~ENA_MOUSE_SENSOR;
|
||||
} else if (enable == ENA_MMC) { // Maus sensor aus, MMC aan
|
||||
#ifdef MAUS_AVAILABLE
|
||||
if ((ena & ENA_MOUSE_SENSOR) ==0){ // War der Maussensor an?
|
||||
maus_sens_highZ(); // Der Maussensor muss die Datenleitung freigeben
|
||||
ena |= ENA_MOUSE_SENSOR; // Maus aus
|
||||
}
|
||||
#endif
|
||||
ena &= ~enable;
|
||||
} else {
|
||||
ena |= enable;
|
||||
}
|
||||
|
||||
ENA_set(ena);
|
||||
|
||||
if ( (enable & (ENA_MOUSE_SENSOR | ENA_MMC)) != 0 ){
|
||||
PORTD |= 4; // Fliplops takten
|
||||
PORTD &= ~4;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schaltet einzelne Enable-Transistoren aus
|
||||
* andere werden nicht beeinflusst
|
||||
* Achtung, die Treiber-Transistoren sind Low-Aktiv!!!
|
||||
* ENA_off schaltet einen Transistor ab
|
||||
* Daher zieht es die entsprechende ENA_XXX-Leitung (mit Transistor) auf High und NICHT auf Low
|
||||
* @param enable Bitmaske der anzuschaltenden LEDs
|
||||
*/
|
||||
void ENA_off(uint8 enable){
|
||||
ena &= ~enable;
|
||||
ENA_set(ena);
|
||||
|
||||
if ( (enable & (ENA_MOUSE_SENSOR | ENA_MMC)) != 0 ){
|
||||
PORTD |= 4; // Fliplops takten
|
||||
PORTD &= ~4;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schaltet die Enable-Transistoren
|
||||
* Achtung, die Treiber-Transistoren sind Low-Aktiv!!!
|
||||
* ENA_set bezieht sich auf die Transistor
|
||||
* Daher zieht es die entsprechende ENA_XXX-Leitung auf ~enable
|
||||
* @param LED Wert der gezeigt werden soll
|
||||
*/
|
||||
void ENA_set(uint8 enable){
|
||||
ena=enable;
|
||||
shift_data(~enable,SHIFT_REGISTER_ENA);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
163
source/ct-Bot/mcu/ir-rc5.c
Normal file
163
source/ct-Bot/mcu/ir-rc5.c
Normal file
|
@ -0,0 +1,163 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file ir-rc5.c
|
||||
* @brief Routinen für die Dekodierung von RC5-Fernbedienungs-Codes
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 20.12.05
|
||||
*/
|
||||
|
||||
// Infos ueber RC6: http://www.xs4all.nl/~sbp/knowledge/ir/rc6.htm
|
||||
// http://www.xs4all.nl/~sbp/knowledge/ir/ir.htm
|
||||
|
||||
// ========================================================================
|
||||
// RC5 Infrarot-Empf<70>nger
|
||||
// ========================================================================
|
||||
#include "ct-Bot.h"
|
||||
#ifdef MCU
|
||||
#ifdef IR_AVAILABLE
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "ir-rc5.h"
|
||||
#include "timer.h"
|
||||
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
// Timing
|
||||
// -----------------------------------------------------------------------------
|
||||
#define IR_SAMPLES_PER_BIT 10 /*!< 10 Samples per Bit */
|
||||
#define IR_SAMPLES_PER_BIT_EARLY 8 /*!< Flanke fr<66>hestens nach 8 Samples */
|
||||
#define IR_SAMPLES_PER_BIT_LATE 12 /*!< Flanke sp<73>testens nach 12 Samples */
|
||||
#define IR_SAMPLES_PER_BIT_MIN 3 /*!< Flanke vor 3 Samples -> paket verwerfen */
|
||||
#define IR_PAUSE_SAMPLES 250 /*!< Startbit ist erst nach 250 Samples ohne */
|
||||
// Pegel<65>nderung g<>ltig -- eigentlich m<>sste
|
||||
// man rund 500 Samples abwarten (50 x
|
||||
// Bitzeit), doch weil der Samplez<65>hler ein
|
||||
// Byte ist, beschr<68>nken wir uns hier auf ein
|
||||
// Minimum von 250 Samples
|
||||
|
||||
#define IR_PORT PORTB /*!< Port B */
|
||||
#define IR_DDR DDRB /*!< DDR of Port B */
|
||||
#define IR_PINR PINB /*!< Port B input */
|
||||
#define IR_PIN 1 /*!< Pin 1 */
|
||||
|
||||
|
||||
|
||||
static byte ir_lastsample = 0; /*!< zuletzt gelesenes Sample */
|
||||
static byte ir_bittimer = 0; /*!< zählt die Aufrufe von ir_isr() */
|
||||
|
||||
static uint16 ir_data_tmp = 0; /*!< RC5-Bitstream */
|
||||
static byte ir_bitcount = 0; /*!< anzahl gelesener bits */
|
||||
|
||||
volatile uint16 ir_data = 0; /*!< letztes komplett gelesenes RC5-paket */
|
||||
|
||||
/*!
|
||||
* Interrupt Serviceroutine
|
||||
* wird ca alle 177.8us aufgerufen
|
||||
*/
|
||||
void ir_isr(void) {
|
||||
// sample lesen
|
||||
byte sample = 1;
|
||||
|
||||
if ((IR_PINR & (1<<IR_PIN)) != 0) {
|
||||
sample = 0;
|
||||
}
|
||||
|
||||
// bittimer erhoehen (bleibt bei 255 stehen)
|
||||
if (ir_bittimer<255) {
|
||||
ir_bittimer++;
|
||||
}
|
||||
|
||||
// flankenerkennung
|
||||
if ( ir_lastsample != sample) {
|
||||
if (ir_bittimer<=IR_SAMPLES_PER_BIT_MIN) {
|
||||
// flanke kommt zu frueh: paket verwerfen
|
||||
ir_bitcount=0;
|
||||
} else {
|
||||
// Startbit
|
||||
if (ir_bitcount==0) {
|
||||
if ( (sample==1) && (ir_bittimer>IR_PAUSE_SAMPLES) ) {
|
||||
// Startbit speichern
|
||||
ir_data_tmp = 1;
|
||||
ir_bitcount++;
|
||||
} else {
|
||||
// error
|
||||
ir_data_tmp = 0;
|
||||
}
|
||||
|
||||
// bittimer-reset
|
||||
ir_bittimer = 0;
|
||||
|
||||
// Bits 2..14: nur Flanken innerhalb des Bits beruecksichtigen
|
||||
} else {
|
||||
if (ir_bittimer >= IR_SAMPLES_PER_BIT_EARLY) {
|
||||
if(ir_bittimer<=IR_SAMPLES_PER_BIT_LATE){
|
||||
// Bit speichern
|
||||
ir_data_tmp = (ir_data_tmp<<1) | sample;
|
||||
ir_bitcount++;
|
||||
} else {
|
||||
// zu sp<73>t: paket verwerfen
|
||||
ir_bitcount = 0;
|
||||
}
|
||||
|
||||
// bittimer-reset
|
||||
ir_bittimer = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
// keine flanke innerhalb bitzeit?
|
||||
if (ir_bittimer > IR_SAMPLES_PER_BIT_LATE) {
|
||||
// 14 bits gelesen?
|
||||
if (ir_bitcount==14) {
|
||||
ir_data = ir_data_tmp;
|
||||
}
|
||||
// paket verwerfen
|
||||
ir_bitcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// sample im samplepuffer ablegen
|
||||
ir_lastsample = sample;
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* IR-Daten lesen
|
||||
* @return wert von ir_data, löscht anschliessend ir_data
|
||||
*/
|
||||
uint16 ir_read(void) {
|
||||
uint16 retvalue = ir_data;
|
||||
ir_data = 0;
|
||||
return retvalue;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Init IR-System
|
||||
*/
|
||||
void ir_init(void) {
|
||||
IR_DDR &= ~IR_PIN; // Pin auf Input
|
||||
IR_PORT |= IR_PIN; // Pullup an
|
||||
timer_2_init(); // Für IR-Krams
|
||||
}
|
||||
#endif
|
||||
#endif
|
74
source/ct-Bot/mcu/led.c
Normal file
74
source/ct-Bot/mcu/led.c
Normal file
|
@ -0,0 +1,74 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file led.c
|
||||
* @brief Routinen zur LED-Steuerung
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "led.h"
|
||||
#include "ct-Bot.h"
|
||||
#include "shift.h"
|
||||
|
||||
#ifdef LED_AVAILABLE
|
||||
|
||||
uint8 led=0;
|
||||
/*!
|
||||
* Initialisiert die LEDs
|
||||
*/
|
||||
void LED_init(){
|
||||
shift_init();
|
||||
LED_off(LED_ALL);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schaltet einzelne LEDs an
|
||||
* andere werden nicht beeinflusst
|
||||
* @param LED Bitmaske der anzuschaltenden LEDs
|
||||
*/
|
||||
void LED_on(uint8 LED){
|
||||
led |= LED;
|
||||
LED_set(led);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schaltet einzelne LEDs aus
|
||||
* andere werden nicht beeinflusst
|
||||
* @param LED Bitmaske der anzuschaltenden LEDs
|
||||
*/
|
||||
void LED_off(uint8 LED){
|
||||
led &= ~LED;
|
||||
LED_set(led);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Zeigt eine 8-Bit Variable mit den LEDs an
|
||||
* @param LED Wert der gezeigt werden soll
|
||||
*/
|
||||
void LED_set(uint8 LED){
|
||||
led=LED;
|
||||
shift_data(led,SHIFT_REGISTER_LED);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
93
source/ct-Bot/mcu/mini-fat.c
Normal file
93
source/ct-Bot/mcu/mini-fat.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file mini-fat.c
|
||||
* @brief Routinen zum Auffinden von markierten Files auf einer MMC-Karte.
|
||||
* Dies ist keine vollstaendige FAT-Unterstuetzung, sondern sucht nur eien Datei, die mit einer 3-Zeichen Sequenz beginnt.
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @author Ulrich Radig (mail@ulrichradig.de) www.ulrichradig.de
|
||||
* @date 07.11.06
|
||||
*/
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#ifdef MCU
|
||||
#ifdef MINI_FAT_AVAILABLE
|
||||
|
||||
#include "mmc.h"
|
||||
#include "display.h"
|
||||
#include "mini-fat.h"
|
||||
|
||||
/*!
|
||||
* Sucht einen Block auf der MMC-Karte, dessen erste drei Bytes dem key entsprechen
|
||||
* liefert dann den folgenden Block zurueck.
|
||||
* Achtung das prinzip geht nur, wenn die Dateien nicht fragmentiert sind
|
||||
* @param key 3 Byte zur Identifikation
|
||||
* @param buffer Zeiger auf 512 Byte Puffer im SRAM
|
||||
*/
|
||||
uint32 mini_fat_find_block(const char* filename, uint8* buffer){
|
||||
|
||||
// Suche nach der Datei fuer die Katrte
|
||||
int8 found = False;
|
||||
|
||||
uint32 card_size= mmc_get_size() >> 9; // groesse der Karte in Bloecken
|
||||
|
||||
#ifdef DISPLAY_AVAILABLE
|
||||
display_cursor(2,1);
|
||||
display_printf("Find %s: 0x",filename);
|
||||
uint16 i=0, j=0;
|
||||
#endif
|
||||
|
||||
uint32 block=0;
|
||||
while(found == False && block < card_size){
|
||||
#ifdef DISPLAY_AVAILABLE
|
||||
display_cursor(2,13);
|
||||
display_printf("%02x%04x",j,i );
|
||||
if (i==65535)
|
||||
j++;
|
||||
i++;
|
||||
#endif
|
||||
mmc_read_sector(block++,buffer);
|
||||
uint8 i;
|
||||
for (i=0; i<MMC_FILENAME_MAX; i++)
|
||||
if (filename[i] == '\0'){
|
||||
found = True;
|
||||
break;
|
||||
} else if (filename[i] != buffer[i]) break;
|
||||
}
|
||||
|
||||
if (found == False)
|
||||
return 0xFFFFFFFF;
|
||||
|
||||
#ifdef DISPLAY_AVAILABLE
|
||||
i= block & 0xFFFF;
|
||||
j= (block >> 16) & 0xFFFF;
|
||||
display_cursor(2,1);
|
||||
display_printf("Found %s: 0x%02x%04x",filename,j,i);
|
||||
#endif
|
||||
|
||||
// auf der Karte markieren, dass wir sie in der Hand hatten
|
||||
// buffer[3]++;
|
||||
// mmc_write_sector(block-1,buffer,0);
|
||||
|
||||
return block;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
482
source/ct-Bot/mcu/mmc-low.S
Normal file
482
source/ct-Bot/mcu/mmc-low.S
Normal file
|
@ -0,0 +1,482 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
; Hinweis:
|
||||
; Sollte der Build-Prozess an dieser Datei scheitern, bitte auch die
|
||||
; Datei ".settings/org.eclipse.core.runtime.prefs" aus dem CVS laden, oder
|
||||
; selbst veranlassen, dass .S-Dateien ebenfalls vom gcc verarbeitet werden
|
||||
; (und nicht direkt vom Assembler).
|
||||
|
||||
/*!
|
||||
* @file mmc-low.s
|
||||
* @brief Low-Level-Routinen zum Lesen/Schreiben einer MMC / SD-Card
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 14.11.2006
|
||||
*/
|
||||
|
||||
#include "mmc-low.h"
|
||||
#include "ct-Bot.h"
|
||||
#include "ena.h"
|
||||
#ifdef MMC_AVAILABLE
|
||||
#include <avr/io.h>
|
||||
|
||||
; Portkonfiguration umrechnen
|
||||
.equ PORT_OUT, _SFR_IO_ADDR(MMC_PORT_OUT)
|
||||
.equ PORT_IN, _SFR_IO_ADDR(MMC_PORT_IN)
|
||||
.equ DDR, _SFR_IO_ADDR(MMC_DDR)
|
||||
.equ SPI_CLK_MASK, _BV(SPI_CLK) ; 1<<SPI_CLK
|
||||
|
||||
/*!
|
||||
* Schreibt ein Byte an die Karte
|
||||
* @param data Das zu sendende Byte
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 14.11.2006
|
||||
*/
|
||||
.global mmc_write_byte
|
||||
.type mmc_write_byte, @function
|
||||
mmc_write_byte:
|
||||
in r25, PORT_OUT ; MMC_PORT_OUT einlesen
|
||||
cbr r25, SPI_CLK_MASK ; CLK auf low
|
||||
bst r24, 7 ; Bit 7 der Daten
|
||||
bld r25, SPI_DO ; Daten nach DO
|
||||
out PORT_OUT, r25 ; Daten senden
|
||||
sbi PORT_OUT, SPI_CLK ; CLK auf high
|
||||
bst r24, 6 ; Bit 6 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 5 ; Bit 5 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 4 ; Bit 4 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 3 ; Bit 3 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 2 ; Bit 2 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 1 ; Bit 1 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r24, 0 ; Bit 0 der Daten
|
||||
bld r25, SPI_DO
|
||||
out PORT_OUT, r25
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
sbi PORT_OUT, SPI_DO ; DO auf high
|
||||
ret
|
||||
|
||||
/*!
|
||||
* Liest ein Byte von der Karte
|
||||
* @return Das gelesene Byte
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 14.11.2006
|
||||
*/
|
||||
.global mmc_read_byte
|
||||
.type mmc_read_byte, @function
|
||||
mmc_read_byte:
|
||||
in r19, PORT_OUT ; MMC_PORT_OUT einlesen
|
||||
cbr r19, SPI_CLK_MASK ; CLK low
|
||||
out PORT_OUT, r19 ; CLK auf low
|
||||
mov r18, r19 ; CLK high
|
||||
sbr r18, SPI_CLK_MASK
|
||||
in r25, PORT_IN ; Bit 7 lesen
|
||||
out PORT_OUT, r18 ; CLK Flanke
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI ; Bit 7 speichern
|
||||
bld r24, 7
|
||||
in r25, PORT_IN ; Bit 6
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 6
|
||||
in r25, PORT_IN ; Bit 5
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 5
|
||||
in r25, PORT_IN ; Bit 4
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 4
|
||||
in r25, PORT_IN ; Bit 3
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 3
|
||||
in r25, PORT_IN ; Bit 2
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 2
|
||||
in r25, PORT_IN ; Bit 1
|
||||
out PORT_OUT, r18
|
||||
out PORT_OUT, r19
|
||||
bst r25, SPI_DI
|
||||
bld r24, 1
|
||||
in r25, PORT_IN ; Bit 0
|
||||
out PORT_OUT, r18
|
||||
bst r25, SPI_DI
|
||||
bld r24, 0
|
||||
clr r25 ; return ist in 8 Bit und wir sind ordentlich ;)
|
||||
ret
|
||||
|
||||
/*!
|
||||
* Schaltet die Karte aktiv und checkt dabei die Initialisierung
|
||||
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 09.12.2006
|
||||
*/
|
||||
.global mmc_enable
|
||||
.type mmc_enable, @function
|
||||
mmc_enable:
|
||||
lds r24, mmc_init_state ; Initialisierung der Karte checken
|
||||
tst r24
|
||||
breq 1f
|
||||
call mmc_init ; neu initialisieren
|
||||
tst r24
|
||||
breq 1f
|
||||
ret ; kein Init moeglich => Fehler
|
||||
1:
|
||||
ldi r24, lo8(ENA_MMC) ; Karte aktiv schalten
|
||||
call ENA_on
|
||||
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
|
||||
call ENA_off
|
||||
cbi DDR, SPI_DI ; DI auf input
|
||||
sbi DDR, SPI_DO ; DO auf output
|
||||
ldi r24, lo8(-1)
|
||||
call mmc_write_byte ; sendet 8 CLK-Flanken
|
||||
ldi r24, lo8(ENA_MMC) ; Karte aktiv schalten
|
||||
call ENA_on
|
||||
ldi r24, 0
|
||||
ret ; alles ok
|
||||
|
||||
/*!
|
||||
* Schreibt einen 512-Byte Sektor auf die Karte
|
||||
* @param addr Nummer des 512-Byte Blocks
|
||||
* @param Buffer Zeiger auf den Puffer
|
||||
* @param async 0: synchroner, 1: asynchroner Aufruf, siehe MMC_ASYNC_WRITE in mmc-low.h
|
||||
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich oder Timeout vor / nach Kommando 24, 2 wenn Timeout bei busy
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 16.11.2006
|
||||
*/
|
||||
.global mmc_write_sector
|
||||
.type mmc_write_sector, @function
|
||||
mmc_write_sector:
|
||||
push r13 ; allgemeine Register retten
|
||||
push r14
|
||||
push r15
|
||||
push r16
|
||||
push r28
|
||||
push r29
|
||||
movw r14, r22 ; Byte 1 und 2 von Parameter addr sichern
|
||||
mov r16, r24 ; Byte 3 von Parameter addr sichern
|
||||
movw r28, r20 ; Parameter Buffer sichern
|
||||
mov r13, r18 ; Parameter async sichern
|
||||
call mmc_enable ; Karte aktiv schalten
|
||||
tst r24
|
||||
breq 1f
|
||||
rjmp 4f ; Karte kann nicht initialisiert werden => Fehler
|
||||
1:
|
||||
lsl r14 ; Block in Bytes umrechnen
|
||||
rol r15
|
||||
rol r16
|
||||
#if MMC_ASYNC_WRITE == 1
|
||||
clr r27 ; r27 = 0
|
||||
1:
|
||||
clr r26 ; r26 = 0
|
||||
2:
|
||||
call mmc_read_byte ; warten, ob Karte noch busy
|
||||
cpi r24, lo8(-1)
|
||||
breq 3f ; == 0xff?
|
||||
dec r26 ; r26--
|
||||
brne 2b ; r26 == 0?
|
||||
dec r27 ; r27--
|
||||
brne 1b ; r27 == 0?
|
||||
rjmp 4f ; Timeout :(
|
||||
3:
|
||||
#endif
|
||||
ldi r24, 88 ; Kommando 24 zum Schreiben eines Blocks senden, Byte 0
|
||||
call mmc_write_byte
|
||||
mov r24, r16 ; Byte 1
|
||||
call mmc_write_byte
|
||||
mov r24, r15 ; Byte 2
|
||||
call mmc_write_byte
|
||||
mov r24, r14 ; Byte 3
|
||||
call mmc_write_byte
|
||||
ldi r24, 0 ; Byte 4
|
||||
call mmc_write_byte
|
||||
ldi r24, lo8(-1) ; Byte 5 (CRC)
|
||||
call mmc_write_byte
|
||||
ldi r26, lo8(-1) ; Timeout nach 256 Versuchen
|
||||
1:
|
||||
call mmc_read_byte
|
||||
cpi r24, lo8(-1) ; !0xff = Antwort
|
||||
brne 3f
|
||||
dec r26 ; r26--
|
||||
brne 1b
|
||||
3:
|
||||
tst r24 ; Fehler oder Abbruch durch Timeout?
|
||||
breq 1f
|
||||
rjmp 4f ; Return-Code 1
|
||||
1:
|
||||
ldi r24, lo8(-2) ; Start-Byte an Karte senden
|
||||
call mmc_write_byte
|
||||
in r26, PORT_OUT ; MMC_PORT_OUT einlesen
|
||||
cbr r26, SPI_CLK_MASK ; CLK auf low
|
||||
ldi r18, 2 ; r18 = 2
|
||||
clr r27 ; r27 = 0
|
||||
1:
|
||||
ld r25, Y+ ; Byte aus SRAM lesen
|
||||
bst r25, 7 ; Bit 7
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26 ; Daten senden
|
||||
sbi PORT_OUT, SPI_CLK ; CLK auf high
|
||||
bst r25, 6 ; Bit 6
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 5 ; Bit 5
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 4 ; Bit 4
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 3 ; Bit 3
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 2 ; Bit 2
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 1 ; Bit 1
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
bst r25, 0 ; Bit 0
|
||||
bld r26, SPI_DO
|
||||
out PORT_OUT, r26
|
||||
sbi PORT_OUT, SPI_CLK
|
||||
inc r27 ; r27++
|
||||
breq 2f ; r27 == 0?
|
||||
rjmp 1b
|
||||
2:
|
||||
dec r18 ; r18--
|
||||
breq 3f ; r18 == 0?
|
||||
rjmp 1b
|
||||
3:
|
||||
sbi PORT_OUT, SPI_DO ; DO auf high
|
||||
call mmc_write_byte ; crc-Dummy schreiben
|
||||
call mmc_write_byte
|
||||
#if MMC_ASYNC_WRITE == 1
|
||||
tst r13 ; wollten wir asynchron schreiben?
|
||||
brne 3f ; wenn ja, nicht auf busy warten
|
||||
#endif
|
||||
1:
|
||||
clr r28 ; r28 = 0
|
||||
2:
|
||||
call mmc_read_byte ; warten, ob Karte noch busy
|
||||
cpi r24, lo8(-1)
|
||||
breq 3f ; == 0xff?
|
||||
dec r28 ; r28--
|
||||
brne 2b ; r28 == 0?
|
||||
dec r27 ; r27--
|
||||
brne 1b ; r27 == 0?
|
||||
rjmp 5f ; Timeout :(
|
||||
3:
|
||||
ldi r16, 0 ; Alles ok, also Return-Code 0 laden :)
|
||||
rjmp 6f
|
||||
4:
|
||||
ldi r16, 1 ; Fehler, Return-Code 1 laden
|
||||
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
|
||||
rjmp 6f
|
||||
5:
|
||||
ldi r16, 2 ; Fehler, Return-Code 2 laden
|
||||
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
|
||||
6:
|
||||
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
|
||||
call ENA_off
|
||||
mov r24, r16 ; Return-Code laden
|
||||
ldi r25, 0
|
||||
pop r29 ; allgemeine Register wiederherstellen
|
||||
pop r28
|
||||
pop r16
|
||||
pop r15
|
||||
pop r14
|
||||
pop r13
|
||||
ret
|
||||
|
||||
/*!
|
||||
* Liest einen Block von der Karte
|
||||
* @param addr Nummer des 512-Byte Blocks
|
||||
* @param Buffer Puffer von mindestens 512 Byte
|
||||
* @return 0 wenn alles ok ist, 1 wenn Init nicht moeglich oder Timeout vor / nach Kommando 17
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 17.11.2006
|
||||
*/
|
||||
.global mmc_read_sector
|
||||
.type mmc_read_sector, @function
|
||||
mmc_read_sector:
|
||||
push r14 ; allgemeine Register retten
|
||||
push r15
|
||||
push r16
|
||||
push r28
|
||||
push r29
|
||||
movw r14, r22 ; Byte 1 und 2 von Parameter addr sichern
|
||||
mov r16, r24 ; Byte 3 von Parameter addr sichern
|
||||
movw r28, r20 ; Parameter Buffer sichern
|
||||
call mmc_enable ; Karte aktiv schalten
|
||||
tst r24
|
||||
breq 1f
|
||||
rjmp 5f ; Karte kann nicht initialisiert werden => Fehler
|
||||
1:
|
||||
lsl r14 ; Block in Bytes umrechnen
|
||||
rol r15
|
||||
rol r16
|
||||
#if MMC_ASYNC_WRITE == 1
|
||||
clr r27 ; r27 = 0
|
||||
1:
|
||||
clr r26 ; r26 = 0
|
||||
2:
|
||||
call mmc_read_byte ; warten, ob Karte noch busy
|
||||
cpi r24, lo8(-1)
|
||||
breq 3f ; == 0xff?
|
||||
dec r26 ; r26--
|
||||
brne 2b ; r26 == 0?
|
||||
dec r27 ; r27--
|
||||
brne 1b ; r27 == 0?
|
||||
rjmp 5f ; Timeout :(
|
||||
3:
|
||||
#endif
|
||||
ldi r24, 81 ; Kommando 17 zum Lesen eines Blocks senden, Byte 0
|
||||
call mmc_write_byte
|
||||
mov r24, r16 ; Byte 1
|
||||
call mmc_write_byte
|
||||
mov r24, r15 ; Byte 2
|
||||
call mmc_write_byte
|
||||
mov r24, r14 ; Byte 3
|
||||
call mmc_write_byte
|
||||
ldi r24, 0 ; Byte 4
|
||||
call mmc_write_byte
|
||||
ldi r24,lo8(-1) ; Byte 5 (CRC)
|
||||
call mmc_write_byte
|
||||
ldi r16, lo8(-1) ; Timeout bei 256
|
||||
1:
|
||||
call mmc_read_byte
|
||||
cpi r24, lo8(-2) ; 0xfe = Startbyte
|
||||
breq 2f
|
||||
call mmc_read_byte ; Noch ein Versuch
|
||||
cpi r24, lo8(-2)
|
||||
breq 2f
|
||||
dec r16
|
||||
brne 1b
|
||||
rjmp 4f ; Timeout, also abbrechen :(
|
||||
2:
|
||||
in r20, PORT_OUT ; MMC_PORT_OUT einlesen
|
||||
cbr r20, SPI_CLK_MASK ; CLK low
|
||||
out PORT_OUT, r20 ; CLK auf low
|
||||
mov r19, r20 ; CLK high
|
||||
sbr r19, SPI_CLK_MASK
|
||||
ldi r18, 2 ; Schleifenzaehler laden
|
||||
clr r24
|
||||
1:
|
||||
in r26, PORT_IN ; Bit 7 lesen
|
||||
out PORT_OUT, r19 ; CLK Flanke
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI ; Bit 7 speichern
|
||||
bld r25, 7
|
||||
in r26, PORT_IN ; Bit 6
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 6
|
||||
in r26, PORT_IN ; Bit 5
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT ,r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 5
|
||||
in r26, PORT_IN ; Bit 4
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 4
|
||||
in r26, PORT_IN ; Bit 3
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 3
|
||||
in r26, PORT_IN ; Bit 2
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 2
|
||||
in r26, PORT_IN ; Bit 1
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 1
|
||||
in r26, PORT_IN ; Bit 0
|
||||
out PORT_OUT, r19
|
||||
out PORT_OUT, r20
|
||||
bst r26, SPI_DI
|
||||
bld r25, 0
|
||||
st Y+, r25 ; Byte ins SRAM kopieren
|
||||
inc r24 ; r24++
|
||||
breq 2f ; r24 == 0?
|
||||
rjmp 1b
|
||||
2:
|
||||
dec r18 ; r18--
|
||||
breq 3f ; r18 == 0?
|
||||
rjmp 1b
|
||||
3:
|
||||
out PORT_OUT, r19 ; CLK auf high
|
||||
call mmc_read_byte ; crc-Dummy lesen
|
||||
call mmc_read_byte
|
||||
4:
|
||||
tst r16 ; Abbruch durch Timeout?
|
||||
breq 5f ; r27 == 0?
|
||||
ldi r16, 0 ; Alles ok, also Return-Code 0 laden :)
|
||||
rjmp 6f
|
||||
5:
|
||||
ldi r16, 1 ; Fehler, also Return-Code 1 laden
|
||||
sts mmc_init_state, r16 ; Initstatus auf Fehler setzen
|
||||
6:
|
||||
ldi r24, lo8(ENA_MMC) ; Karte inaktiv schalten
|
||||
call ENA_off
|
||||
mov r24, r16 ; Return-Code laden
|
||||
ldi r25, 0
|
||||
pop r29 ; allgemeine Register wiederherstellen
|
||||
pop r28
|
||||
pop r16
|
||||
pop r15
|
||||
pop r14
|
||||
ret
|
||||
#endif // MMC_AVAILABLE
|
||||
#endif // MCU
|
420
source/ct-Bot/mcu/mmc.c
Normal file
420
source/ct-Bot/mcu/mmc.c
Normal file
|
@ -0,0 +1,420 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file mmc.c
|
||||
* @brief Routinen zum Auslesen/Schreiben einer MMC-Karte
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @author Ulrich Radig (mail@ulrichradig.de) www.ulrichradig.de
|
||||
* @date 07.11.06
|
||||
*/
|
||||
|
||||
|
||||
/* Die (zeitkritischen) Low-Level-Funktionen read_ und write_byte bzw. _sector liegen jetzt
|
||||
* in mmc-low.S. Der Assembler-Code ist a) wesentlich schneller und macht b) das Timing
|
||||
* unabhaengig vom verwendeten Compiler.
|
||||
* Die Portkonfiguration findet sich in mmc-low.h.
|
||||
*/
|
||||
|
||||
//TODO: * kleine Doku machen
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#ifdef MCU
|
||||
#ifdef MMC_AVAILABLE
|
||||
|
||||
#include "mmc.h"
|
||||
#include <avr/io.h>
|
||||
#include "ena.h"
|
||||
#include "timer.h"
|
||||
#include "display.h"
|
||||
|
||||
#include <avr/interrupt.h>
|
||||
#ifndef NEW_AVR_LIB
|
||||
#include <avr/signal.h>
|
||||
#endif
|
||||
|
||||
#include "mmc-low.h"
|
||||
#include "mmc-vm.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#define MMC_Disable() ENA_off(ENA_MMC);
|
||||
#define MMC_Enable() ENA_on(ENA_MMC);
|
||||
|
||||
#define MMC_prepare() { MMC_DDR &=~(1<<SPI_DI); MMC_DDR |= (1<<SPI_DO); }
|
||||
|
||||
volatile uint8 mmc_init_state=1; /*!< Initialierungsstatus der Karte, 0: ok, 1: Fehler */
|
||||
|
||||
/*!
|
||||
* Checkt die Initialisierung der Karte
|
||||
* @return 0, wenn initialisiert
|
||||
*/
|
||||
inline uint8 mmc_get_init_state(void){
|
||||
return mmc_init_state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schreibt ein Byte an die Karte
|
||||
* @param data Das zu sendende Byte
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 14.11.2006
|
||||
* @see mmc-low.s
|
||||
*/
|
||||
void mmc_write_byte(uint8 data);
|
||||
|
||||
|
||||
/*!
|
||||
* Liest ein Byte von der Karte
|
||||
* @return Das gelesene Byte
|
||||
* @author Timo Sandmann (mail@timosandmann.de)
|
||||
* @date 14.11.2006
|
||||
* @see mmc-low.s
|
||||
*/
|
||||
uint8 mmc_read_byte(void);
|
||||
|
||||
|
||||
/*!
|
||||
* Schickt ein Kommando an die Karte
|
||||
* @param cmd Ein Zeiger auf das Kommando
|
||||
* @return Die Antwort der Karte oder 0xFF im Fehlerfall
|
||||
*/
|
||||
uint8 mmc_write_command(uint8 *cmd){
|
||||
uint8 result = 0xff;
|
||||
uint16 timeout = 0;
|
||||
|
||||
mmc_enable(); // MMC / SD-Card aktiv schalten
|
||||
|
||||
// sendet 6 Byte Kommando
|
||||
uint8 i;
|
||||
for (i=0; i<6; i++) // sendet 6 Byte Kommando zur MMC/SD-Karte
|
||||
mmc_write_byte(*cmd++);
|
||||
|
||||
// Wartet auf eine gueltige Antwort von der MMC/SD-Karte
|
||||
while (result == 0xff){
|
||||
result = mmc_read_byte();
|
||||
if (timeout++ > MMC_TIMEOUT)
|
||||
break; // Abbruch da die MMC/SD-Karte nicht antwortet
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Initialisiere die SD/MMC-Karte
|
||||
* @return 0 wenn allles ok, sonst Nummer des Kommandos bei dem abgebrochen wurde
|
||||
*/
|
||||
uint8 mmc_init(void){
|
||||
uint16 timeout = 0;
|
||||
uint8 i;
|
||||
mmc_init_state = 0;
|
||||
|
||||
// Konfiguration des Ports an der die MMC/SD-Karte angeschlossen wurde
|
||||
MMC_CLK_DDR |= _BV(SPI_CLK); // Setzen von Pin MMC_Clock auf Output
|
||||
|
||||
MMC_prepare();
|
||||
|
||||
MMC_Enable();
|
||||
MMC_Disable();
|
||||
|
||||
// Initialisiere MMC/SD-Karte in den SPI-Mode
|
||||
for (i=0; i<0x0f; i++) // Sendet min 74+ Clocks an die MMC/SD-Karte
|
||||
mmc_write_byte(0xff);
|
||||
|
||||
// Sendet Kommando CMD0 an MMC/SD-Karte
|
||||
uint8 cmd[] = {0x40,0x00,0x00,0x00,0x00,0x95};
|
||||
while (mmc_write_command(cmd) != 1){
|
||||
if (timeout++ > MMC_TIMEOUT){
|
||||
MMC_Disable();
|
||||
mmc_init_state = 1;
|
||||
return 1; // Abbruch bei Kommando 1 (Return Code 1)
|
||||
}
|
||||
}
|
||||
|
||||
// Sendet Kommando CMD1 an MMC/SD-Karte
|
||||
timeout = 0;
|
||||
cmd[0] = 0x41; // Kommando 1
|
||||
cmd[5] = 0xFF;
|
||||
while (mmc_write_command (cmd) !=0){
|
||||
if (timeout++ > 3*MMC_TIMEOUT){
|
||||
MMC_Disable();
|
||||
mmc_init_state = 1;
|
||||
return 2; // Abbruch bei Kommando 2 (Return Code 2)
|
||||
}
|
||||
}
|
||||
|
||||
// set MMC_Chip_Select to high (MMC/SD-Karte Inaktiv)
|
||||
MMC_Disable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Liest einen Block von der Karte
|
||||
* @param cmd Zeiger auf das Kommando, das erstmal an die Karte geht
|
||||
* @param Buffer Ein Puffer mit mindestens count Bytes
|
||||
* @param count Anzahl der zu lesenden Bytes
|
||||
*/
|
||||
uint8 mmc_read_block(uint8 *cmd, uint8 *buffer, uint16 count){
|
||||
/* Initialisierung checken */
|
||||
if (mmc_init_state != 0)
|
||||
if (mmc_init() != 0) return 1;
|
||||
|
||||
// Sendet Kommando cmd an MMC/SD-Karte
|
||||
if (mmc_write_command(cmd) != 0) {
|
||||
mmc_init_state = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Wartet auf Start Byte von der MMC/SD-Karte (FEh/Start Byte)
|
||||
uint8 timeout=1;
|
||||
while (mmc_read_byte() != 0xfe){
|
||||
if (timeout++ == 0) break;
|
||||
};
|
||||
|
||||
uint16 i;
|
||||
// Lesen des Blocks (max 512 Bytes) von MMC/SD-Karte
|
||||
for (i=0; i<count; i++)
|
||||
*buffer++ = mmc_read_byte();
|
||||
|
||||
// CRC-Byte auslesen
|
||||
mmc_read_byte(); //CRC - Byte wird nicht ausgewertet
|
||||
mmc_read_byte(); //CRC - Byte wird nicht ausgewertet
|
||||
|
||||
// set MMC_Chip_Select to high (MMC/SD-Karte inaktiv)
|
||||
MMC_Disable();
|
||||
if (timeout == 0) {
|
||||
mmc_init_state = 1;
|
||||
return 1; // Abbruch durch Timeout
|
||||
}
|
||||
return 0; // alles ok
|
||||
}
|
||||
|
||||
#ifdef MMC_INFO_AVAILABLE
|
||||
/*!
|
||||
* Liest das CID-Register (16 Byte) von der Karte
|
||||
* @param Buffer Puffer von mindestens 16 Byte
|
||||
*/
|
||||
void mmc_read_cid (uint8 *buffer){
|
||||
// Kommando zum Lesen des CID Registers
|
||||
uint8 cmd[] = {0x4A,0x00,0x00,0x00,0x00,0xFF};
|
||||
mmc_read_block(cmd, buffer, 16);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liest das CSD-Register (16 Byte) von der Karte
|
||||
* @param Buffer Puffer von mindestens 16 Byte
|
||||
*/
|
||||
void mmc_read_csd (uint8 *buffer){
|
||||
// Kommando zum lesen des CSD Registers
|
||||
uint8 cmd[] = {0x49,0x00,0x00,0x00,0x00,0xFF};
|
||||
mmc_read_block(cmd, buffer, 16);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liefert die Groesse der Karte zurueck
|
||||
* @return Groesse der Karte in Byte. Bei einer 4 GByte-Karte kommt 0xFFFFFFFF zurueck
|
||||
*/
|
||||
uint32 mmc_get_size(void){
|
||||
uint8 csd[16];
|
||||
|
||||
mmc_read_csd(csd);
|
||||
|
||||
uint32 size = (csd[8]>>6) + (csd[7] << 2) + ((csd[6] & 0x03) << 10); // c_size
|
||||
size +=1; // Fest in der Formel drin
|
||||
|
||||
uint8 shift = 2; // eine 2 ist fest in der Formel drin
|
||||
shift += (csd[10]>>7) + ((csd[9] & 0x03) <<1); // c_size_mult beruecksichtigen
|
||||
shift += csd[5] & 0x0f; // Blockgroesse beruecksichtigen
|
||||
|
||||
size = size << shift;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
|
||||
#endif //MMC_INFO_AVAILABLE
|
||||
|
||||
#ifdef MMC_WRITE_TEST_AVAILABLE
|
||||
/*! Testet die MMC-Karte. Schreibt nacheinander 2 Sektoren a 512 Byte mit Testdaten voll und liest sie wieder aus
|
||||
* !!! Achtung loescht die Karte
|
||||
* @return 0, wenn alles ok
|
||||
*/
|
||||
uint8 mmc_test(void){
|
||||
static uint32 sector = 0xf000;
|
||||
/* Initialisierung checken */
|
||||
if (mmc_init_state != 0)
|
||||
if (mmc_init() != 0){
|
||||
sector = 0;
|
||||
return 1;
|
||||
}
|
||||
#ifdef MMC_VM_AVAILABLE // Version mit virtuellen Aressen
|
||||
uint16 i;
|
||||
static uint16 pagefaults = 0;
|
||||
static uint16 old_pf;
|
||||
/* virtuelle Adressen holen */
|
||||
static uint32 v_addr1 = 0;
|
||||
static uint32 v_addr2 = 0;
|
||||
static uint32 v_addr3 = 0;
|
||||
static uint32 v_addr4 = 0;
|
||||
if (v_addr1 == 0) v_addr1 = mmcalloc(512, 1); // Testdaten 1
|
||||
if (v_addr2 == 0) v_addr2 = mmcalloc(512, 1); // Testdaten 2
|
||||
if (v_addr3 == 0) v_addr3 = mmcalloc(512, 1); // Dummy 1
|
||||
if (v_addr4 == 0) v_addr4 = mmcalloc(512, 1); // Dummy 2
|
||||
/* Zeitmessung starten */
|
||||
uint16 start_ticks=TIMER_GET_TICKCOUNT_16;
|
||||
uint8 start_reg=TCNT2;
|
||||
/* Pointer auf Puffer holen */
|
||||
uint8* p_addr = mmc_get_data(v_addr1); // Cache-Hit, CB 0
|
||||
if (p_addr == NULL) return 2;
|
||||
/* Testdaten schreiben */
|
||||
for (i=0; i<512; i++)
|
||||
p_addr[i] = (i & 0xff);
|
||||
/* Pointer auf zweiten Speicherbereich holen */
|
||||
p_addr = mmc_get_data(v_addr2); // Cache-Hit, CB 1
|
||||
if (p_addr == NULL) return 3;
|
||||
/* Testdaten Teil 2 schreiben */
|
||||
for (i=0; i<512; i++)
|
||||
p_addr[i] = 255 - (i & 0xff);
|
||||
/* kleiner LRU-Test */
|
||||
// p_addr = mmc_get_data(v_addr1); // Cache-Hit, CB 0
|
||||
// p_addr = mmc_get_data(v_addr4); // Cache-Miss, => CB 1
|
||||
// p_addr = mmc_get_data(v_addr1); // Cache-Hit, CB 0
|
||||
// p_addr = mmc_get_data(v_addr3); // Cache-Miss, => CB 1
|
||||
// p_addr = mmc_get_data(v_addr1); // Cache-Hit, CB 0
|
||||
// p_addr = mmc_get_data(v_addr4); // Cache-Miss, => CB 1
|
||||
/* Pointer auf Testdaten Teil 1 holen */
|
||||
p_addr = mmc_get_data(v_addr1); // Cache-Hit, CB 0
|
||||
if (p_addr == NULL) return 4;
|
||||
/* Testdaten 1 vergleichen */
|
||||
for (i=0; i<512; i++)
|
||||
if (p_addr[i] != (i & 0xff)) return 5;
|
||||
/* Pointer auf Testdaten Teil 2 holen */
|
||||
p_addr = mmc_get_data(v_addr2); // Cache-Miss, => CB 1
|
||||
if (p_addr == NULL) return 6;
|
||||
/* Testdaten 2 vergleichen */
|
||||
for (i=0; i<512; i++)
|
||||
if (p_addr[i] != (255 - (i & 0xff))) return 7;
|
||||
|
||||
p_addr = mmc_get_data(v_addr4);
|
||||
/* Zeitmessung beenden */
|
||||
int8 timer_reg=TCNT2;
|
||||
uint16 end_ticks=TIMER_GET_TICKCOUNT_16;
|
||||
timer_reg -= start_reg;
|
||||
#ifdef VM_STATS_AVAILABLE
|
||||
/* Pagefaults merken */
|
||||
old_pf = pagefaults;
|
||||
pagefaults = mmc_get_pagefaults();
|
||||
#endif
|
||||
/* kleine Statistik ausgeben */
|
||||
display_cursor(3,1);
|
||||
display_printf("Pagefaults: %5u ", pagefaults);
|
||||
display_cursor(4,1);
|
||||
display_printf("Bei %3u PF: %5u us", pagefaults - old_pf, (end_ticks-start_ticks)*176 + timer_reg*4);
|
||||
#else // alte Version
|
||||
uint8 buffer[512];
|
||||
uint16 i;
|
||||
uint8 result=0;
|
||||
|
||||
/* Zeitmessung starten */
|
||||
uint16 start_ticks=TIMER_GET_TICKCOUNT_16;
|
||||
uint8 start_reg=TCNT2;
|
||||
|
||||
#if MMC_ASYNC_WRITE == 1
|
||||
/* async-Test (wurde im letzten Durchlauf korrekt geschrieben?) */
|
||||
if (sector > 0xf){
|
||||
result= mmc_read_sector(sector-1, buffer);
|
||||
if (result != 0){
|
||||
return result*10 + 9;
|
||||
}
|
||||
for (i=0; i<512; i++)
|
||||
if (buffer[i] != (i & 0xFF)){
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
#endif // MMC_ASYNC_WRITE
|
||||
|
||||
// Puffer vorbereiten
|
||||
for (i=0; i< 512; i++) buffer[i]= (i & 0xFF);
|
||||
// und schreiben
|
||||
result= mmc_write_sector(sector, buffer, 0);
|
||||
if (result != 0){
|
||||
return result*10 + 2;
|
||||
}
|
||||
|
||||
// Puffer vorbereiten
|
||||
for (i=0; i< 512; i++) buffer[i]= 255 - (i & 0xFF);
|
||||
// und schreiben
|
||||
result= mmc_write_sector(sector+1, buffer, 0);
|
||||
if (result != 0){
|
||||
return result*10 + 3;
|
||||
}
|
||||
|
||||
// Puffer lesen
|
||||
result= mmc_read_sector(sector++, buffer);
|
||||
if (result != 0){
|
||||
sector--;
|
||||
return result*10 + 4;
|
||||
}
|
||||
|
||||
// und vergleichen
|
||||
for (i=0; i<512; i++)
|
||||
if (buffer[i] != (i & 0xFF)){
|
||||
return 5;
|
||||
}
|
||||
|
||||
// sector++;
|
||||
// Puffer lesen
|
||||
result= mmc_read_sector(sector++, buffer);
|
||||
if (result != 0){
|
||||
sector--;
|
||||
return result*10 + 6;
|
||||
}
|
||||
// und vergleichen
|
||||
for (i=0; i<512; i++)
|
||||
if (buffer[i] != (255- (i & 0xFF))){
|
||||
return 7;
|
||||
}
|
||||
|
||||
#if MMC_ASYNC_WRITE == 1
|
||||
for (i=0; i< 512; i++)
|
||||
buffer[i]= (i & 0xFF);
|
||||
result= mmc_write_sector(sector-1, buffer, MMC_ASYNC_WRITE);
|
||||
if (result != 0){
|
||||
return result*10 + 8;
|
||||
}
|
||||
#endif // MMC_ASYNC_WRITE
|
||||
|
||||
/* Zeitmessung beenden */
|
||||
int8 timer_reg=TCNT2;
|
||||
uint16 end_ticks=TIMER_GET_TICKCOUNT_16;
|
||||
timer_reg -= start_reg;
|
||||
/* kleine Statistik ausgeben */
|
||||
display_cursor(3,1);
|
||||
display_printf("Dauer: %5u us ", (end_ticks-start_ticks)*176 + timer_reg*4);
|
||||
display_cursor(4,1);
|
||||
display_printf("Sektor:%6u/", sector-2);
|
||||
display_printf("%6u", sector-1);
|
||||
#endif // MMC_VM_AVAILABLE
|
||||
// hierher kommen wir nur, wenn alles ok ist
|
||||
return 0;
|
||||
}
|
||||
#endif //MMC_WRITE_TEST_AVAILABLE
|
||||
|
||||
#endif
|
||||
#endif
|
242
source/ct-Bot/mcu/motor-low.c
Normal file
242
source/ct-Bot/mcu/motor-low.c
Normal file
|
@ -0,0 +1,242 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file motor-low.c
|
||||
* @brief Low-Level Routinen fuer die Motorsteuerung des c't-Bots
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 01.12.05
|
||||
*/
|
||||
#ifdef MCU
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#ifndef NEW_AVR_LIB
|
||||
#include <avr/signal.h>
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "global.h"
|
||||
#include "motor.h"
|
||||
#include "timer.h"
|
||||
#include "sensor.h"
|
||||
#include "display.h"
|
||||
#include "motor-low.h"
|
||||
|
||||
//Drehrichtung der Motoren
|
||||
#define BOT_DIR_L_PIN (1<<6) // PC7
|
||||
#define BOT_DIR_L_PORT PORTC
|
||||
#define BOT_DIR_L_DDR DDRC
|
||||
|
||||
#define BOT_DIR_R_PIN (1<<7) // PC6
|
||||
#define BOT_DIR_R_PORT PORTC
|
||||
#define BOT_DIR_R_DDR DDRC
|
||||
|
||||
#define PWM_L OCR1A
|
||||
#define PWM_R OCR1B
|
||||
|
||||
#define PWM_CLK_0 (_BV(CS02) | _BV(CS00)) /*!< Prescaler fuer PWM 0 = 1024*/
|
||||
//#define PWM_CLK_2 (_BV(CS22) | _BV(CS21) |_BV(CS20)) /*!< Prescaler fuer PWM 2 =1024 */
|
||||
|
||||
int16 motor_left; /*!< zuletzt gestellter Wert linker Motor */
|
||||
int16 motor_right; /*!< zuletzt gestellter Wert rechter Motor */
|
||||
|
||||
|
||||
void pwm_0_init(void);
|
||||
void pwm_1_init(void);
|
||||
// void pwm_2_init(void); // Kollidiert mit Timer2 fuer IR-Fernbedienung
|
||||
|
||||
/*!
|
||||
* Initialisiert alles fuer die Motosteuerung
|
||||
*/
|
||||
void motor_low_init(){
|
||||
BOT_DIR_L_DDR|=BOT_DIR_L_PIN;
|
||||
BOT_DIR_R_DDR|=BOT_DIR_R_PIN;
|
||||
|
||||
pwm_0_init();
|
||||
pwm_1_init();
|
||||
// pwm_2_init(); // Kollidiert mit Timer2 fuer IR-Fernbedienung
|
||||
bot_motor(0,0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* unmittelbarere Zugriff auf die beiden Motoren
|
||||
* normalerweise NICHT verwenden!!!!!
|
||||
* @param left Speed links
|
||||
* @param right Speed rechts
|
||||
*/
|
||||
void bot_motor(int16 left, int16 right){
|
||||
// Vorzeichenbehaftete PWM-Werte sichern
|
||||
motor_left=left;
|
||||
motor_right=right;
|
||||
|
||||
PWM_L = 255-abs(left);
|
||||
PWM_R = 255-abs(right);
|
||||
|
||||
if (left > 0 ){
|
||||
BOT_DIR_L_PORT |= BOT_DIR_L_PIN;
|
||||
direction.left= DIRECTION_FORWARD;
|
||||
} else
|
||||
BOT_DIR_L_PORT &= ~BOT_DIR_L_PIN;
|
||||
|
||||
if (left < 0 )
|
||||
direction.left= DIRECTION_BACKWARD;
|
||||
|
||||
|
||||
if (right <= 0 ) // Einer der Motoren ist invertiert, da er ja in die andere Richtung schaut
|
||||
BOT_DIR_R_PORT |= BOT_DIR_R_PIN;
|
||||
else {
|
||||
BOT_DIR_R_PORT &= ~BOT_DIR_R_PIN;
|
||||
direction.right= DIRECTION_FORWARD;
|
||||
}
|
||||
if (right < 0 )
|
||||
direction.right= DIRECTION_BACKWARD;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Stellt die Servos
|
||||
* Sinnvolle Werte liegen zwischen 8 und 16
|
||||
*/
|
||||
void servo_low(uint8 servo, uint8 pos){
|
||||
if (servo== SERVO1) {
|
||||
if (pos == SERVO_OFF) {
|
||||
#ifdef __AVR_ATmega644__
|
||||
TCCR0B &= ~PWM_CLK_0 ; // PWM aus
|
||||
#else
|
||||
TCCR0 &= ~PWM_CLK_0 ; // PWM aus
|
||||
#endif
|
||||
} else {
|
||||
#ifdef __AVR_ATmega644__
|
||||
TCCR0B |= PWM_CLK_0; // PWM an
|
||||
OCR0A=pos;
|
||||
#else
|
||||
TCCR0 |= PWM_CLK_0; // PWM an
|
||||
OCR0=pos;
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// if (servo== SERVO2) {
|
||||
// if (pos == 0) {
|
||||
// TCCR2 &= ~ (_BV(CS22) | _BV(CS21) | _BV(CS20)); // PWM an
|
||||
// } else {
|
||||
// TCCR2 |= PWM_CLK_2; // PWM an
|
||||
// OCR2=pos;
|
||||
// }
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
* Interrupt Handler for Timer/Counter 0
|
||||
*/
|
||||
#ifdef __AVR_ATmega644__
|
||||
SIGNAL (TIMER0_COMPA_vect){
|
||||
#else
|
||||
SIGNAL (SIG_OUTPUT_COMPARE0){
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Timer 0: Kontrolliert den Servo per PWM
|
||||
* PWM loescht bei erreichen. daher steht in OCR0 255-Speed!!!
|
||||
* initilaisiert Timer 0 und startet ihn
|
||||
*/
|
||||
void pwm_0_init(void){
|
||||
|
||||
DDRB |= (1<<3); // PWM-Pin als Output
|
||||
TCNT0 = 0x00; // TIMER0 vorladen
|
||||
|
||||
#ifdef __AVR_ATmega644__
|
||||
TCCR0A = _BV(WGM00) | // Normal PWM
|
||||
_BV(COM0A1); // Clear on Compare , Set on Top
|
||||
//PWM_CLK_0;
|
||||
|
||||
OCR0A = 8;
|
||||
#else
|
||||
TCCR0 = _BV(WGM00) | // Normal PWM
|
||||
_BV(COM01) ; // Clear on Compare , Set on Top
|
||||
|
||||
OCR0 = 8; // PWM loescht bei erreichen. daher steht in OCR0 255-Speed!!!
|
||||
#endif
|
||||
// TIMSK |= _BV(OCIE0); // enable Output Compare 0 overflow interrupt
|
||||
//sei(); // enable interrupts
|
||||
}
|
||||
|
||||
// ---- Timer 1 ------
|
||||
|
||||
/*!
|
||||
* Interrupt Handler for Timer/Counter 1A
|
||||
*/
|
||||
SIGNAL (SIG_OUTPUT_COMPARE1A){
|
||||
}
|
||||
|
||||
/*!
|
||||
* Interrupt Handler for Timer/Counter 1B
|
||||
*/
|
||||
SIGNAL (SIG_OUTPUT_COMPARE1B){
|
||||
}
|
||||
|
||||
/*!
|
||||
* Timer 1: Kontrolliert die Motoren per PWM
|
||||
* PWM loescht bei erreichen. daher steht in OCR1A/OCR1B 255-Speed!!!
|
||||
* initilaisiert Timer 0 und startet ihn
|
||||
*/
|
||||
void pwm_1_init(void){
|
||||
DDRD |= 0x30 ; // PWM-Pins als Output
|
||||
TCNT1 = 0x0000; // TIMER1 vorladen
|
||||
|
||||
TCCR1A = _BV(WGM10) | // Fast PWM 8 Bit
|
||||
_BV(COM1A1) |_BV(COM1A0) | // Clear on Top, Set on Compare
|
||||
_BV(COM1B1) |_BV(COM1B0); // Clear on Top, Set on Compare
|
||||
|
||||
TCCR1B = _BV(WGM12) |
|
||||
_BV(CS12) | _BV(CS10); // Prescaler = 1024
|
||||
// _BV(CS10); // Prescaler = 1
|
||||
|
||||
OCR1A = 255; // PWM loescht bei erreichen. daher steht in OCR1A 255-Speed!!!
|
||||
OCR1B = 255; // PWM loescht bei erreichen. daher steht in OCR1B 255-Speed!!!
|
||||
|
||||
// TIMSK|= _BV(OCIE1A) | _BV(OCIE1B); // enable Output Compare 1 overflow interrupt
|
||||
// sei(); // enable interrupts
|
||||
}
|
||||
|
||||
/*!
|
||||
* Timer 0: Kontrolliert den Servo per PWM
|
||||
* PWM loescht bei erreichen. daher steht in OCR0 255-Speed!!!
|
||||
* initilaisiert Timer 0 und startet ihn
|
||||
*/
|
||||
/* Kollidiert derzeit mit Timer2 fuer IR
|
||||
void pwm_2_init(void){
|
||||
DDRD |= 0x80; // PWM-Pin als Output
|
||||
TCNT2 = 0x00; // TIMER0 vorladen
|
||||
|
||||
TCCR2 = _BV(WGM20) | // Normal PWM
|
||||
_BV(COM21); // Clear on Top, Set on Compare
|
||||
// _BV(CS22) | _BV(CS21) |_BV(CS20); // Prescaler = 1024
|
||||
|
||||
OCR2 = 8; // PWM löscht bei erreichen. daher steht in OCR0 255-Speed!!!
|
||||
// TIMSK |= _BV(OCIE0); // enable Output Compare 0 overflow interrupt
|
||||
//sei(); // enable interrupts
|
||||
}
|
||||
*/
|
||||
|
||||
#endif
|
183
source/ct-Bot/mcu/mouse.c
Normal file
183
source/ct-Bot/mcu/mouse.c
Normal file
|
@ -0,0 +1,183 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file mouse.c
|
||||
* @brief Routinen fuer die Ansteuerung eines opt. Maussensors
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
#include "global.h"
|
||||
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "ct-Bot.h"
|
||||
#include "mouse.h"
|
||||
#include "delay.h"
|
||||
#include "ena.h"
|
||||
|
||||
#ifdef MAUS_AVAILABLE
|
||||
|
||||
#define MAUS_DDR DDRB /*!< DDR fuer Maus-SCLK */
|
||||
#define MAUS_PORT PORTB /*!< PORT fuer Maus-SCLK */
|
||||
#define MAUS_SCK_PIN (1<<7) /*!< PIN fuer Maus-SCLK */
|
||||
|
||||
#define MAUS_SDA_NR 6 /*!< Pin an dem die SDA-Leitung haengt */
|
||||
#define MAUS_SDA_PINR PINB /*!< Leseregister */
|
||||
#define MAUS_SDA_PIN (1<<MAUS_SDA_NR) /*!< Bit-Wert der SDA-Leitung */
|
||||
|
||||
#define MOUSE_Enable() ENA_on(ENA_MOUSE_SENSOR)
|
||||
|
||||
/*!
|
||||
* Uebertraegt ein Byte an den Sensor
|
||||
* @param data das Byte
|
||||
*/
|
||||
void maus_sens_writeByte(uint8 data){
|
||||
int8 i;
|
||||
MAUS_DDR |= MAUS_SDA_PIN; // SDA auf Output
|
||||
|
||||
for (i=7; i>=0; i--){
|
||||
MAUS_PORT &= ~MAUS_SCK_PIN; // SCK auf Low, vorbereiten
|
||||
|
||||
//Daten rausschreiben
|
||||
MAUS_PORT = (MAUS_PORT & (~MAUS_SDA_PINR)) | ((data >> (7 - MAUS_SDA_NR)) & MAUS_SDA_PIN);
|
||||
data = data <<1; // naechstes Bit vorbereiten
|
||||
asm volatile("nop"); // Etwas warten
|
||||
|
||||
MAUS_PORT |= MAUS_SCK_PIN; // SCK =1 Sensor uebernimmt auf steigender Flanke
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liest ein Byte vom Sensor
|
||||
* @return das Byte
|
||||
*/
|
||||
uint8 maus_sens_readByte(void){
|
||||
int i;
|
||||
char data=0;
|
||||
|
||||
MAUS_DDR &= ~MAUS_SDA_PIN; // SDA auf Input
|
||||
|
||||
for (i=7; i>-1; i--){
|
||||
MAUS_PORT &= ~MAUS_SCK_PIN; // SCK =0 Sensor bereitet Daten auf fallender Flanke vor !
|
||||
data=data<<1; // Platz schaffen
|
||||
|
||||
asm volatile("nop"); // Etwas warten
|
||||
MAUS_PORT |= MAUS_SCK_PIN; // SCK =1 Daten lesen auf steigender Flanke
|
||||
|
||||
data |= (MAUS_SDA_PINR >> MAUS_SDA_NR) & 0x01; //Daten lesen
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Uebertraegt ein write-Kommando an den Sensor
|
||||
* @param adr Adresse
|
||||
* @param data Datum
|
||||
*/
|
||||
void maus_sens_write(int8 adr, uint8 data){
|
||||
int16 i;
|
||||
|
||||
MOUSE_Enable();
|
||||
|
||||
maus_sens_writeByte(adr|=0x80); //rl MSB muss 1 sein Datenblatt S.12 Write Operation
|
||||
maus_sens_writeByte(data);
|
||||
for (i=0; i<300; i++){ asm volatile("nop"); } // mindestens 100 Mikrosekunden Pause!!!
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schickt ein Lesekommando an den Sensor
|
||||
* und liest ein Byte zurueck
|
||||
* @param adr die Adresse
|
||||
* @return das Datum
|
||||
*/
|
||||
uint8 maus_sens_read(uint8 adr){
|
||||
MOUSE_Enable();
|
||||
int16 i;
|
||||
maus_sens_writeByte(adr);
|
||||
for (i=0; i<300; i++){asm volatile("nop");} // mindestens 100 Mikrosekunden Pause!!!
|
||||
|
||||
return maus_sens_readByte();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Initialisiere Maussensor
|
||||
*/
|
||||
void maus_sens_init(void){
|
||||
delay(100);
|
||||
|
||||
MAUS_DDR |= MAUS_SCK_PIN; // SCK auf Output
|
||||
MAUS_PORT &= ~MAUS_SCK_PIN; // SCK auf 0
|
||||
|
||||
delay(10);
|
||||
|
||||
maus_sens_write(MOUSE_CONFIG_REG,MOUSE_CFG_RESET); //Reset sensor
|
||||
maus_sens_write(MOUSE_CONFIG_REG,MOUSE_CFG_FORCEAWAKE); //Always on
|
||||
}
|
||||
|
||||
/*! muessen wir nach dem ersten Pixel suchen?*/
|
||||
static uint8 firstRead;
|
||||
/*!
|
||||
* Bereitet das auslesen eines ganzen Bildes vor
|
||||
*/
|
||||
void maus_image_prepare(void){
|
||||
maus_sens_write(MOUSE_CONFIG_REG,MOUSE_CFG_FORCEAWAKE); //Always on
|
||||
|
||||
maus_sens_write(MOUSE_PIXEL_DATA_REG,0x00); // Frame grabben anstossen
|
||||
firstRead=1; //suche erstes Pixel
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liefert bei jedem Aufruf das naechste Pixel des Bildes
|
||||
* Insgesamt gibt es 324 Pixel
|
||||
* <pre>
|
||||
* 18 36 ... 324
|
||||
* .. .. ... ..
|
||||
* 2 20 ... ..
|
||||
* 1 19 ... 307
|
||||
* </pre>
|
||||
* Bevor diese Funktion aufgerufen wird, muss maus_image_prepare() aufgerufen werden!
|
||||
* @return Die Pixeldaten (Bit 0 bis Bit5), Pruefbit, ob Daten gueltig (Bit6), Markierung fuer den Anfang eines Frames (Bit7)
|
||||
*/
|
||||
int8 maus_image_read(void){
|
||||
int8 pixel=maus_sens_read(MOUSE_PIXEL_DATA_REG);
|
||||
if ( firstRead ==1){
|
||||
while ( (pixel & 0x80) != 0x80){
|
||||
pixel=maus_sens_read(MOUSE_PIXEL_DATA_REG);
|
||||
// if ((pixel & 0x70) != 0x70)
|
||||
// return 0;
|
||||
}
|
||||
firstRead=0;
|
||||
}
|
||||
|
||||
return pixel;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Gibt den SQUAL-Wert zurueck. Dieser gibt an, wieviele Merkmale der Sensor
|
||||
* im aktuell aufgenommenen Bild des Untergrunds wahrnimmt
|
||||
*/
|
||||
uint8 maus_get_squal(void) {
|
||||
return maus_sens_read(MOUSE_SQUAL_REG);
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
229
source/ct-Bot/mcu/sensor-low.c
Normal file
229
source/ct-Bot/mcu/sensor-low.c
Normal file
|
@ -0,0 +1,229 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file sensor-low.c
|
||||
* @brief Low-Level Routinen für die Sensor Steuerung des c't-Bots
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 01.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include <avr/io.h>
|
||||
#include "adc.h"
|
||||
#include "global.h"
|
||||
|
||||
#include "ena.h"
|
||||
#include "sensor.h"
|
||||
#include "mouse.h"
|
||||
#include "motor.h"
|
||||
#include "timer.h"
|
||||
#include "sensor_correction.h"
|
||||
#include "bot-logic/available_behaviours.h"
|
||||
#ifdef BEHAVIOUR_SERVO_AVAILABLE
|
||||
#include "bot-logic/behaviour_servo.h"
|
||||
#endif
|
||||
|
||||
// ADC-PINS
|
||||
#define SENS_ABST_L 0 /*!< ADC-PIN Abstandssensor Links */
|
||||
#define SENS_ABST_R 1 /*!< ADC-PIN Abstandssensor Rechts */
|
||||
#define SENS_M_L 2 /*!< ADC-PIN Liniensensor Links */
|
||||
#define SENS_M_R 3 /*!< ADC-PIN Liniensensor Rechts */
|
||||
#define SENS_LDR_L 4 /*!< ADC-PIN Lichtsensor Links */
|
||||
#define SENS_LDR_R 5 /*!< ADC-PIN Lichtsensor Rechts */
|
||||
#define SENS_KANTE_L 6 /*!< ADC-PIN Kantensensor Links */
|
||||
#define SENS_KANTE_R 7 /*!< ADC-PIN Kantensensor Rechts */
|
||||
|
||||
// Sonstige Sensoren
|
||||
#define SENS_DOOR_PINR PIND /*!< Port an dem der Klappensensor hängt */
|
||||
#define SENS_DOOR_DDR DDRD /*!< DDR für den Klappensensor */
|
||||
#define SENS_DOOR 6 /*!< Pin an dem der Klappensensor hängt */
|
||||
|
||||
#define SENS_ENCL_PINR PINB /*!< Port an dem der linke Encoder hängt */
|
||||
#define SENS_ENCL_DDR DDRB /*!< DDR für den linken Encoder */
|
||||
#define SENS_ENCL 4 /*!< Pin an dem der linke Encoder hängt */
|
||||
|
||||
#define SENS_ENCR_PINR PIND /*!< Port an dem der rechte Encoder hängt */
|
||||
#define SENS_ENCR_DDR DDRD /*!< DDR für den rechten Encoder */
|
||||
#define SENS_ENCR 3 /*!< Pin an dem der rechte Encoder hängt */
|
||||
|
||||
#define SENS_ERROR_PINR PINB /*!< Port an dem die Fehlerüberwachung hängt */
|
||||
#define SENS_ERROR_DDR DDRB /*!< DDR für die Fehlerüberwachung */
|
||||
#define SENS_ERROR 2 /*!< Pin an dem die Fehlerüberwachung hängt */
|
||||
|
||||
#define SENS_TRANS_PINR PINB /*!< Port an dem die Transportfachueberwachung haengt */
|
||||
#define SENS_TRANS_PORT PORTB /*!< Port an dem die Transportfachueberwachung haengt */
|
||||
#define SENS_TRANS_DDR DDRB /*!< DDR für die Transportfachueberwachung */
|
||||
#define SENS_TRANS 0 /*!< Pin an dem die Transportfachueberwachung haengt */
|
||||
|
||||
#define ENC_L ((SENS_ENCL_PINR >> SENS_ENCL) & 0x01) /*!< Abkuerzung zum Zugriff auf Encoder */
|
||||
#define ENC_R ((SENS_ENCR_PINR >> SENS_ENCR) & 0x01) /*!< Abkuerzung zum Zugriff auf Encoder */
|
||||
|
||||
#define ENC_ENTPRELL 12 /*!< Nur wenn der Encoder ein paar mal den gleichen wert gibt uebernehmen */
|
||||
|
||||
|
||||
/*!
|
||||
* Initialisiere alle Sensoren
|
||||
*/
|
||||
void bot_sens_init(void){
|
||||
ENA_init();
|
||||
adc_init(0xFF); // Alle ADC-Ports aktivieren
|
||||
|
||||
ENA_set(ENA_RADLED); // Alle Sensoren bis auf die Radencoder deaktivieren
|
||||
ENA_on(ENA_ABSTAND); // Die Abstandssensoren ebenfalls dauerhaft an, da sie fast 50 ms zum booten brauchen
|
||||
|
||||
SENS_DOOR_DDR &= ~ (1<<SENS_DOOR); // Input
|
||||
|
||||
SENS_ENCL_DDR &= ~ (1<<SENS_ENCL); // Input
|
||||
SENS_ENCR_DDR &= ~(1<<SENS_ENCR); // Input
|
||||
|
||||
SENS_ERROR_DDR &= ~(1<<SENS_ERROR); // Input
|
||||
|
||||
SENS_TRANS_DDR &= ~(1<<SENS_TRANS); // Input
|
||||
SENS_TRANS_PORT |= (1<<SENS_TRANS); // Pullup an
|
||||
|
||||
SENS_ENCL_DDR &= ~(1<<SENS_ENCL); // Input
|
||||
SENS_ENCR_DDR &= ~(1<<SENS_ENCR); // Input
|
||||
|
||||
timer_2_init();
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Alle Sensoren aktualisieren
|
||||
* Derzeit pollt diese Routine alle Sensoren. Insbesondere bei den
|
||||
* analogen dauert das eine Weile. Daher kann man hier einiges
|
||||
* an Performance gewinnen, wenn man die Routine aufspaltet und
|
||||
* zumindest die analogen Sensoren per Interrupt bearbeitet,
|
||||
* denn im Moment blockiert adc_read so lange, bis ein Sensorwert ausgelesen ist.
|
||||
* Die digitalen Sensoren liefern ihre Werte dagegen unmittelbar
|
||||
* Aber Achtung es lohnt auch nicht, immer alles so schnell als moeglich
|
||||
* zu aktualiseren, der Bot braucht auch Zeit zum nachdenken ueber Verhalten
|
||||
*/
|
||||
void bot_sens_isr(void){
|
||||
|
||||
ENA_on(ENA_KANTLED|ENA_MAUS|ENA_SCHRANKE|ENA_KLAPPLED);
|
||||
|
||||
#ifdef MAUS_AVAILABLE
|
||||
// Aktualisiere die Position des Maussensors
|
||||
sensMouseDX = maus_sens_read(MOUSE_DELTA_X_REG);
|
||||
sensMouseDY = maus_sens_read(MOUSE_DELTA_Y_REG);
|
||||
|
||||
#endif
|
||||
|
||||
// ---------- analoge Sensoren -------------------
|
||||
sensLDRL = adc_read(SENS_LDR_L);
|
||||
sensLDRR = adc_read(SENS_LDR_R);
|
||||
|
||||
sensBorderL = adc_read(SENS_KANTE_L);
|
||||
sensBorderR = adc_read(SENS_KANTE_R);
|
||||
ENA_off(ENA_KANTLED);
|
||||
|
||||
sensLineL = adc_read(SENS_M_L);
|
||||
sensLineR = adc_read(SENS_M_R);
|
||||
ENA_off(ENA_MAUS);
|
||||
|
||||
// Aktualisiere Distanz-Sensoren
|
||||
// Die Distanzsensoren sind im Normalfall an, da sie 50 ms zum booten brauchen
|
||||
// Abfrage nur alle 100ms
|
||||
static uint16 old_dist; // Zeit der letzten Messung der Distanzsensoren
|
||||
static uint8 measure_count;
|
||||
static int16 distLeft[3];
|
||||
static int16 distRight[3];
|
||||
|
||||
register uint16 dist_ticks = TIMER_GET_TICKCOUNT_16;
|
||||
if (dist_ticks-old_dist > MS_TO_TICKS(100)){
|
||||
// Zeit fuer naechste Messung merken
|
||||
old_dist=dist_ticks;
|
||||
|
||||
// wenn Kalibrierung gewuenscht, den Part Messen und Korrigieren kommentieren
|
||||
// und Kalibrieren auskommentieren
|
||||
// Kalibirieren
|
||||
//distL=adc_read(SENS_ABST_L);
|
||||
//distR=adc_read(SENS_ABST_R);
|
||||
|
||||
// Messwert merken
|
||||
distLeft[measure_count]=adc_read(SENS_ABST_L);
|
||||
#ifdef BEHAVIOUR_SERVO_AVAILABLE
|
||||
if ((servo_active & SERVO1) == 0) // Wenn die Transportfachklappe bewegt wird, stimmt der Messwert des rechten Sensor nicht
|
||||
#endif
|
||||
distRight[measure_count]=adc_read(SENS_ABST_R);
|
||||
|
||||
measure_count++;
|
||||
if (measure_count==3) measure_count=0;
|
||||
|
||||
// Schnittwert bilden
|
||||
sensor_abstand((distLeft[0]+distLeft[1]+distLeft[2])/3,(distRight[0]+distRight[1]+distRight[2])/3);
|
||||
}
|
||||
|
||||
|
||||
// ------- digitale Sensoren ------------------
|
||||
sensDoor = (SENS_DOOR_PINR >> SENS_DOOR) & 0x01;
|
||||
sensTrans = (SENS_TRANS_PINR >> SENS_TRANS) & 0x01;
|
||||
ENA_off(ENA_SCHRANKE|ENA_KLAPPLED);
|
||||
|
||||
sensError = (SENS_ERROR_PINR >> SENS_ERROR) & 0x01;
|
||||
|
||||
sensor_update(); // Weiterverarbeitung der rohen Sensordaten
|
||||
}
|
||||
|
||||
/*!
|
||||
* Kuemmert sich um die Radencoder
|
||||
* Das muss schneller gehen als die anderen Sensoren,
|
||||
* daher Update per Timer-Interrupt und nicht per Polling
|
||||
*/
|
||||
void bot_encoder_isr(void){
|
||||
static uint8 enc_l=0; /*!< Puffer fuer die letzten Encoder-Staende */
|
||||
static uint8 enc_r=0; /*!< Puffer fuer die letzten Encoder-Staende */
|
||||
static uint8 enc_l_cnt=0; /*!< Entprell-Counter fuer L-Encoder */
|
||||
static uint8 enc_r_cnt=0; /*!< Entprell-Counter fuer R-Encoder */
|
||||
// --------------------- links ----------------------------
|
||||
//Rad-Encoder auswerten
|
||||
if ( ENC_L != enc_l){ // uns interesieren nur Veraenderungen
|
||||
enc_l=ENC_L; // neuen wert sichern
|
||||
enc_l_cnt=0; // Counter zuruecksetzen
|
||||
} else { // Zaehlen, wie lange Pegel bleibt
|
||||
if (enc_l_cnt <= ENC_ENTPRELL) // Nur bis zur Entprell-Marke
|
||||
enc_l_cnt++;
|
||||
}
|
||||
|
||||
if (enc_l_cnt == ENC_ENTPRELL){// wenn lange genug konst
|
||||
if (direction.left == DIRECTION_FORWARD) // Drehrichtung beachten
|
||||
sensEncL++; //vorwaerts
|
||||
else
|
||||
sensEncL--; //rueckwaerts
|
||||
}
|
||||
|
||||
// --------------------- rechts ----------------------------
|
||||
if (ENC_R != enc_r){ // uns interesieren nur Veraenderungen
|
||||
enc_r=ENC_R; // neuen wert sichern
|
||||
enc_r_cnt=0;
|
||||
} else{ // Zaehlen, wie lange Pegel bleibt
|
||||
if (enc_r_cnt <= ENC_ENTPRELL) // Nur bis zur Entprell-Marke
|
||||
enc_r_cnt++;
|
||||
}
|
||||
|
||||
if (enc_r_cnt == ENC_ENTPRELL){// wenn lange genug konst
|
||||
if (direction.right == DIRECTION_FORWARD) // Drehrichtung beachten
|
||||
sensEncR++; //vorwaerts
|
||||
else
|
||||
sensEncR--; //rueckwaerts
|
||||
}
|
||||
}
|
||||
#endif
|
93
source/ct-Bot/mcu/shift.c
Normal file
93
source/ct-Bot/mcu/shift.c
Normal file
|
@ -0,0 +1,93 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file shift.c
|
||||
* @brief Routinen zur Ansteuerung der Shift-Register
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 20.12.05
|
||||
*/
|
||||
#include "global.h"
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#include "shift.h"
|
||||
|
||||
#ifdef MCU
|
||||
#ifdef SHIFT_AVAILABLE
|
||||
|
||||
#include <avr/io.h>
|
||||
#ifdef NEW_AVR_LIB
|
||||
#include <util/delay.h>
|
||||
#else
|
||||
#include <avr/delay.h>
|
||||
#endif
|
||||
|
||||
|
||||
#define SHIFT_OUT 0x1F /*!< Alle Pins die Ausgänge sind */
|
||||
#define SHIFT_PORT PORTC /*!< Port an dem die Register haengen */
|
||||
#define SHIFT_DDR DDRC /*!< DDR des Ports an dem die Register haengen */
|
||||
|
||||
/*!
|
||||
* Initialisert die Shift-Register
|
||||
*/
|
||||
void shift_init(){
|
||||
SHIFT_DDR |= SHIFT_OUT; // Ausgänge Schalten
|
||||
SHIFT_PORT &= ~SHIFT_OUT; // Und auf Null
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schiebt Daten durch eines der drei 74HC595 Schieberegister
|
||||
* Achtung den Port sollte man danach noch per shift_clear() zurücksetzen
|
||||
* @param data Das Datenbyte
|
||||
* @param latch_data der Pin an dem der Daten-latch-Pin des Registers (PIN 11) hängt
|
||||
* @param latch_store der Pin an dem der latch-Pin zum transfer des Registers (PIN 12) hängt
|
||||
*/
|
||||
void shift_data_out(uint8 data, uint8 latch_data, uint8 latch_store){
|
||||
int8 i;
|
||||
|
||||
SHIFT_PORT &= ~SHIFT_OUT; // und wieder clear
|
||||
for (i=8; i>0; i--){
|
||||
SHIFT_PORT |= ((data >> 7)& 0x01); // Das oberste Bit von data auf PC0.0 (Datenleitung Schieberegister)
|
||||
SHIFT_PORT |= latch_data ; // und ins jeweilige Storageregister latchen
|
||||
data= data << 1; // data links schieben
|
||||
SHIFT_PORT &= ~SHIFT_OUT; // und wieder clear
|
||||
}
|
||||
|
||||
SHIFT_PORT |= latch_store; // alles vom Storage ins Output register latchen
|
||||
}
|
||||
|
||||
/*!
|
||||
* Schiebt Daten durch eines der drei 74HC595 Schieberegister
|
||||
* vereinfachte Version, braucht kein shift_clear()
|
||||
* geht NICHT für das Shift-register, an dem das Display-hängt!!!
|
||||
* @param data Das Datenbyte
|
||||
* @param latch_data der Pin an dem der Daten-latch-Pin des Registers (PIN 11) hängt
|
||||
*/
|
||||
void shift_data(uint8 data, uint8 latch_data){
|
||||
shift_data_out(data, latch_data, SHIFT_LATCH);
|
||||
shift_clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* Setzt die Shift-Register wieder zurück
|
||||
*/
|
||||
void shift_clear(){
|
||||
SHIFT_PORT &= ~SHIFT_OUT; // und wieder clear
|
||||
}
|
||||
#endif
|
||||
#endif
|
171
source/ct-Bot/mcu/srf10.c
Normal file
171
source/ct-Bot/mcu/srf10.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/*
|
||||
* c't-Sim - Robotersimulator fuer den c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file srf10.c
|
||||
* @brief Ansteuerung des Ultraschall Entfernungssensors SRF10
|
||||
* @author Carsten Giesen (info@cnau.de)
|
||||
* @date 08.04.06
|
||||
*/
|
||||
#ifdef MCU
|
||||
#include <avr/io.h>
|
||||
#include "TWI_driver.h"
|
||||
#include "srf10.h"
|
||||
#include "delay.h"
|
||||
|
||||
static uint8 address=SRF10_UNIT_0;
|
||||
|
||||
/*!
|
||||
* SRF10 initialsieren
|
||||
*/
|
||||
|
||||
void srf10_init(void){
|
||||
srf10_set_range(SRF10_MAX_RANGE);
|
||||
//srf10_set_range(6); //Mit diesem Wert muss man spielen um das Optimum zu ermitteln
|
||||
return;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Verstaerkungsfaktor setzen
|
||||
* @param gain Verstaerkungsfaktor
|
||||
*/
|
||||
|
||||
void srf10_set_gain(unsigned char gain){
|
||||
if(gain>16) { gain=16; }
|
||||
|
||||
uint8 temp[2];
|
||||
uint8 state;
|
||||
tx_type tx_frame[2];
|
||||
|
||||
state = SUCCESS;
|
||||
|
||||
tx_frame[0].slave_adr = address+W;
|
||||
tx_frame[0].size = 2;
|
||||
tx_frame[0].data_ptr = temp;
|
||||
tx_frame[0].data_ptr[0] = 1;
|
||||
tx_frame[0].data_ptr[1] = gain;
|
||||
|
||||
tx_frame[1].slave_adr = OWN_ADR;
|
||||
|
||||
state = Send_to_TWI(tx_frame);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Reichweite setzen, hat auch Einfluss auf die Messdauer
|
||||
* @param millimeters Reichweite in mm
|
||||
*/
|
||||
|
||||
void srf10_set_range(unsigned int millimeters){
|
||||
uint8 temp[2];
|
||||
uint8 state;
|
||||
tx_type tx_frame[2];
|
||||
|
||||
state = SUCCESS;
|
||||
|
||||
millimeters= (millimeters/43);
|
||||
|
||||
tx_frame[0].slave_adr = address+W;
|
||||
tx_frame[0].size = 2;
|
||||
tx_frame[0].data_ptr = temp;
|
||||
tx_frame[0].data_ptr[0] = 2;
|
||||
tx_frame[0].data_ptr[1] = millimeters;
|
||||
|
||||
tx_frame[1].slave_adr = OWN_ADR;
|
||||
|
||||
state = Send_to_TWI(tx_frame);
|
||||
}
|
||||
|
||||
/*!
|
||||
* Messung ausloesen
|
||||
* @param metric_unit 0x50 in Zoll, 0x51 in cm, 0x52 ms
|
||||
* @return Resultat der Aktion
|
||||
*/
|
||||
|
||||
uint8 srf10_ping(uint8 metric_unit){
|
||||
uint8 temp[2];
|
||||
uint8 state;
|
||||
tx_type tx_frame[2];
|
||||
|
||||
state = SUCCESS;
|
||||
|
||||
tx_frame[0].slave_adr = address+W;
|
||||
tx_frame[0].size = 2;
|
||||
tx_frame[0].data_ptr = temp;
|
||||
tx_frame[0].data_ptr[0] = SRF10_COMMAND;
|
||||
tx_frame[0].data_ptr[1] = metric_unit;
|
||||
|
||||
tx_frame[1].slave_adr = OWN_ADR;
|
||||
|
||||
state = Send_to_TWI(tx_frame);
|
||||
|
||||
return state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Register auslesen
|
||||
* @param srf10_register welches Register soll ausgelsen werden
|
||||
* @return Inhalt des Registers
|
||||
*/
|
||||
|
||||
uint8 srf10_read_register(uint8 srf10_register){
|
||||
uint8 temp;
|
||||
uint8 value;
|
||||
uint8 state;
|
||||
tx_type tx_frame[3];
|
||||
|
||||
state = SUCCESS;
|
||||
value = 0;
|
||||
|
||||
tx_frame[0].slave_adr = address+W;
|
||||
tx_frame[0].size = 1;
|
||||
tx_frame[0].data_ptr = &temp;
|
||||
tx_frame[0].data_ptr[0] = srf10_register;
|
||||
|
||||
tx_frame[1].slave_adr = address+R;
|
||||
tx_frame[1].size = 1;
|
||||
tx_frame[1].data_ptr = &value;
|
||||
|
||||
tx_frame[2].slave_adr = OWN_ADR;
|
||||
|
||||
state = Send_to_TWI(tx_frame);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Messung starten Ergebniss aufbereiten und zurueckgeben
|
||||
* @return Messergebniss
|
||||
*/
|
||||
|
||||
uint16 srf10_get_measure(){
|
||||
char hib;
|
||||
char lob;
|
||||
char state;
|
||||
|
||||
state = SUCCESS;
|
||||
|
||||
state = srf10_ping(SRF10_CENTIMETERS);
|
||||
delay(10); //Optimierungs Potential
|
||||
lob=srf10_read_register(SRF10_LOB);
|
||||
delay(10); //Optimierungs Potential
|
||||
hib=srf10_read_register(SRF10_HIB);
|
||||
|
||||
return (hib*256)+lob;
|
||||
}
|
||||
|
||||
#endif
|
87
source/ct-Bot/mcu/timer-low.c
Normal file
87
source/ct-Bot/mcu/timer-low.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file timer-low.c
|
||||
* @brief Timer und counter für den Mikrocontroller
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#ifndef NEW_AVR_LIB
|
||||
#include <avr/signal.h>
|
||||
#endif
|
||||
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#include "timer.h"
|
||||
#include "ir-rc5.h"
|
||||
#include "sensor-low.h"
|
||||
#include "bot-local.h"
|
||||
|
||||
// ---- Timer 2 ------
|
||||
|
||||
/*!
|
||||
Interrupt Handler fuer Timer/Counter 2(A)
|
||||
*/
|
||||
#ifdef __AVR_ATmega644__
|
||||
SIGNAL (TIMER2_COMPA_vect){
|
||||
#else
|
||||
SIGNAL (SIG_OUTPUT_COMPARE2){
|
||||
#endif
|
||||
|
||||
/* - FERNBEDIENUNG - */
|
||||
#ifdef IR_AVAILABLE
|
||||
ir_isr();
|
||||
#endif
|
||||
/* ----- TIMER ----- */
|
||||
tickCount.u32++; // TickCounter [176 us] erhoehen
|
||||
/* --- RADENCODER --- */
|
||||
bot_encoder_isr();
|
||||
}
|
||||
|
||||
/*!
|
||||
* initilaisiert Timer 0 und startet ihn
|
||||
*/
|
||||
void timer_2_init(void){
|
||||
TCNT2 = 0x00; // TIMER vorladen
|
||||
|
||||
// aendert man den Prescaler muss man die Formel fuer OCR2 anpassen !!!
|
||||
// Compare Register nur 8-Bit breit --> evtl. teiler anpassen
|
||||
#ifdef __AVR_ATmega644__
|
||||
TCCR2A = _BV(WGM21); // CTC Mode
|
||||
TCCR2B = _BV(CS22); // Prescaler = CLK/64
|
||||
OCR2A = ((XTAL/64/TIMER_2_CLOCK) - 1); // Timer2A
|
||||
TIMSK2 |= _BV(OCIE2A); // TIMER2 Output Compare Match A Interrupt an
|
||||
#else
|
||||
// use CLK/64 prescale value, clear timer/counter on compare match
|
||||
TCCR2 = _BV(WGM21) | _BV(CS22);
|
||||
OCR2 = ((XTAL/64/TIMER_2_CLOCK) - 1);
|
||||
TIMSK |= _BV(OCIE2); // enable Output Compare 0 overflow interrupt
|
||||
#endif
|
||||
|
||||
sei(); // enable interrupts
|
||||
}
|
||||
#endif
|
206
source/ct-Bot/mcu/uart.c
Normal file
206
source/ct-Bot/mcu/uart.c
Normal file
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
* c't-Bot
|
||||
*
|
||||
* This program is free software; you can redistribute it
|
||||
* and/or modify it under the terms of the GNU General
|
||||
* Public License as published by the Free Software
|
||||
* Foundation; either version 2 of the License, or (at your
|
||||
* option) any later version.
|
||||
* This program is distributed in the hope that it will be
|
||||
* useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
||||
* PURPOSE. See the GNU General Public License for more details.
|
||||
* You should have received a copy of the GNU General Public
|
||||
* License along with this program; if not, write to the Free
|
||||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
|
||||
* MA 02111-1307, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/*! @file uart.c
|
||||
* @brief Routinen zur seriellen Kommunikation
|
||||
* @author Benjamin Benz (bbe@heise.de)
|
||||
* @date 26.12.05
|
||||
*/
|
||||
|
||||
#ifdef MCU
|
||||
|
||||
#include "ct-Bot.h"
|
||||
|
||||
#include <avr/io.h>
|
||||
#include <avr/interrupt.h>
|
||||
#ifndef NEW_AVR_LIB
|
||||
#include <avr/signal.h>
|
||||
#endif
|
||||
#include "ct-Bot.h"
|
||||
#include "uart.h"
|
||||
#include "command.h"
|
||||
#include "log.h"
|
||||
|
||||
#ifdef UART_AVAILABLE
|
||||
|
||||
#define BAUDRATE 57600
|
||||
|
||||
#define UART_RX_BUFFER_SIZE 16 /*!< Größe des UART-Puffers */
|
||||
|
||||
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1 )
|
||||
#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
|
||||
#error RX buffer size is not a power of 2
|
||||
#endif
|
||||
|
||||
//#define UART_TIMEOUT 20000 /*!< Timeout. Wartet UART_TIMEOUT CPU-Takte */
|
||||
|
||||
static uint8 UART_RxBuf[UART_RX_BUFFER_SIZE]; /*!< UART-Puffer */
|
||||
static volatile uint8 UART_RxHead; /*!< Zeiger für UART-Puffer */
|
||||
static volatile uint8 UART_RxTail; /*!< Zeiger für UART-Puffer */
|
||||
|
||||
//char uart_timeout; /*!< 0, wenn uart_read/uart_send erfolgreich 1, wenn timeout erreicht */
|
||||
|
||||
/*!
|
||||
* Initialisiere UART
|
||||
*/
|
||||
void uart_init(void){
|
||||
#ifdef __AVR_ATmega644__
|
||||
/* Senden und Empfangen ermöglichen + RX Interrupt an */
|
||||
UCSR0B= (1<<RXEN0) | (1<<TXEN0)|(1<<RXCIE0);
|
||||
/* 8 Bit, 1 Stop, Keine Parity */
|
||||
UCSR0C=0x86;
|
||||
#else
|
||||
/* Senden und Empfangen ermöglichen + RX Interrupt an */
|
||||
UCSRB= (1<<RXEN) | (1<<TXEN)|(1<<RXCIE);
|
||||
/* 8 Bit, 1 Stop, Keine Parity */
|
||||
UCSRC=0x86;
|
||||
#endif
|
||||
|
||||
/* UART auf 9600 baud */
|
||||
// UBRRH=0;
|
||||
// UBRRL= 103; /* Werte stehen im Datenblatt tabelarisch */
|
||||
#ifdef __AVR_ATmega644__
|
||||
UBRR0L = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) & 0xFF);
|
||||
UBRR0H = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) >> 8);
|
||||
#else
|
||||
UBRRL = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) & 0xFF);
|
||||
UBRRH = (uint8) (( ((uint32)F_CPU) / 16 / ((uint32)BAUDRATE) - 1) >> 8);
|
||||
#endif
|
||||
|
||||
/* Puffer leeren */
|
||||
UART_RxTail = 0;
|
||||
UART_RxHead = 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Interrupt Handler fuer den Datenempfang per UART
|
||||
*/
|
||||
#ifdef __AVR_ATmega644__
|
||||
SIGNAL (USART0_RX_vect){
|
||||
#else
|
||||
SIGNAL (SIG_UART_RECV){
|
||||
#endif
|
||||
|
||||
/* Pufferindex berechnen */
|
||||
UART_RxHead++; /* erhoehen */
|
||||
UART_RxHead %= UART_RX_BUFFER_MASK; /* Und bei Bedarf umklappen, da Ringpuffer */
|
||||
|
||||
if (UART_RxHead == UART_RxTail){
|
||||
/* TODO Fehler behandeln !!
|
||||
* ERROR! Receive buffer overflow */
|
||||
}
|
||||
#ifdef __AVR_ATmega644__
|
||||
UART_RxBuf[UART_RxHead] = UDR0; /* Daten lesen und sichern*/
|
||||
#else
|
||||
UART_RxBuf[UART_RxHead] = UDR; /* Daten lesen und sichern*/
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Prüft, ob daten verfügbar
|
||||
* @return Anzahl der verfuegbaren Bytes
|
||||
*/
|
||||
uint8 uart_data_available(void){
|
||||
if (UART_RxHead == UART_RxTail) /* Puffer leer */
|
||||
return 0;
|
||||
else if (UART_RxHead > UART_RxTail) /* Schreibzeiger vor Lesezeiger */
|
||||
return UART_RxHead - UART_RxTail;
|
||||
else /* Schreibzeiger ist schon umgelaufen */
|
||||
return UART_RxHead - UART_RxTail + UART_RX_BUFFER_SIZE;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* Überträgt ein Zeichen per UART
|
||||
* Achtung ist noch blockierend!!!!
|
||||
* TODO: umstellen auf nicht blockierend und mehr als ein Zeichen
|
||||
* @param data Das Zeichen
|
||||
*/
|
||||
void uart_send_byte(uint8 data){ // Achtung ist noch blockierend!!!!
|
||||
#ifdef __AVR_ATmega644__
|
||||
while ((UCSR0A & _BV(UDRE0)) ==0){asm volatile("nop"); } // warten bis UART sendebereit
|
||||
UDR0= data;
|
||||
#else
|
||||
while ((UCSRA & _BV(UDRE)) ==0){asm volatile("nop"); } // warten bis UART sendebereit
|
||||
UDR= data;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
* Sende Kommando per UART im Little Endian
|
||||
* @param cmd Zeiger auf das Kommando
|
||||
* @return Anzahl der gesendete Bytes
|
||||
*/
|
||||
//#define uart_send_cmd(cmd) uart_write(cmd,sizeof(command_t));
|
||||
|
||||
/*
|
||||
int uart_send_cmd(command_t *cmd){
|
||||
int i;
|
||||
char * ptr = (char*) cmd;
|
||||
for (i=0; i<sizeof(command_t); i++)
|
||||
uart_send_byte(*ptr++);
|
||||
|
||||
return sizeof(command_t);
|
||||
}
|
||||
*/
|
||||
|
||||
/*!
|
||||
* Sende Daten per UART im Little Endian
|
||||
* @param data Datenpuffer
|
||||
* @param length Groesse des Datenpuffers in bytes
|
||||
* @return Anzahl der gesendete Bytes
|
||||
*/
|
||||
int uart_write(uint8 * data, int length){
|
||||
int i;
|
||||
char * ptr = (char*) data;
|
||||
for (i=0; i<length; i++)
|
||||
uart_send_byte(*ptr++);
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Liest Zeichen von der UART
|
||||
* @param data Der Zeiger an die die gelesenen Zeichen kommen
|
||||
* @param length Anzahl der zu lesenden Bytes
|
||||
* @return Anzahl der tatsaechlich gelesenen Zeichen
|
||||
*/
|
||||
int uart_read(void* data, int length){
|
||||
uint8 i;
|
||||
char* ptr = data;
|
||||
|
||||
uint8 count= uart_data_available();
|
||||
|
||||
// LOG_DEBUG(("%d/%d av/sel",count,length));
|
||||
|
||||
if (count > length)
|
||||
count=length;
|
||||
|
||||
for (i=0; i<count; i++){
|
||||
UART_RxTail++;
|
||||
UART_RxTail %= UART_RX_BUFFER_MASK;
|
||||
*ptr++ = UART_RxBuf[UART_RxTail];
|
||||
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
#endif
|
||||
#endif
|
Reference in a new issue