From 99eda357457ffcb45a2fc721a4eb0f86b84dc87f Mon Sep 17 00:00:00 2001 From: Steffen Vogel Date: Thu, 15 Nov 2012 22:04:14 +0100 Subject: [PATCH] added controller firmware --- controller/Makefile | 80 ++++++ controller/adc.c | 57 ++++ controller/adc.h | 25 ++ controller/init.o | Bin 0 -> 4216 bytes controller/lcd.c | 236 ++++++++++++++++ controller/lcd.h | 154 +++++++++++ controller/main.c | 548 +++++++++++++++++++++++++++++++++++++ controller/pid.c | 112 ++++++++ controller/pid.h | 54 ++++ controller/rotary.c | 125 +++++++++ controller/rotary.h | 44 +++ controller/uart.c | 651 ++++++++++++++++++++++++++++++++++++++++++++ controller/uart.h | 194 +++++++++++++ 13 files changed, 2280 insertions(+) create mode 100644 controller/Makefile create mode 100644 controller/adc.c create mode 100644 controller/adc.h create mode 100644 controller/init.o create mode 100644 controller/lcd.c create mode 100644 controller/lcd.h create mode 100644 controller/main.c create mode 100644 controller/pid.c create mode 100644 controller/pid.h create mode 100644 controller/rotary.c create mode 100644 controller/rotary.h create mode 100644 controller/uart.c create mode 100644 controller/uart.h diff --git a/controller/Makefile b/controller/Makefile new file mode 100644 index 0000000..1495e32 --- /dev/null +++ b/controller/Makefile @@ -0,0 +1,80 @@ +############################################################################### +# Makefile für das Viertsemester-Projekt am ACS +############################################################################### + +## General Flags +TARGET = auto +MCU = atmega32 +CC = avr-gcc + +## Options common to compile, link and assembly rules +COMMON = -mmcu=$(MCU) + +## Compile options common for all C compilation units. +CFLAGS = $(COMMON) +CFLAGS += -Wall -g -std=gnu99 -DF_CPU=16000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums +CFLAGS += -MD -MP -MT $(*F).o -MF dep/$(@F).d + +## Assembly specific flags +ASMFLAGS = $(COMMON) +ASMFLAGS += $(CFLAGS) + +## Linker flags +LDFLAGS = $(COMMON) +LDFLAGS += -Wl,-Map=$(TARGET).map + +## Intel Hex file production flags +HEX_FLASH_FLAGS = -R .eeprom -R .fuse -R .lock -R .signature +HEX_EEPROM_FLAGS = -j .eeprom +HEX_EEPROM_FLAGS += --set-section-flags=.eeprom="alloc,load" +HEX_EEPROM_FLAGS += --change-section-lma .eeprom=0 --no-change-warnings + +## Include Directories +INCLUDES = + +## Objects that must be built in order to link +OBJECTS = rotary.o lcd.o main.o pid.o adc.o uart.o + +## Objects explicitly added by the user +LINKONLYOBJECTS = + +## Build +all: $(TARGET).elf $(TARGET).hex $(TARGET).eep $(TARGET).lss size + +## Link +$(TARGET).elf: $(OBJECTS) + $(CC) $(LDFLAGS) $(OBJECTS) $(LINKONLYOBJECTS) $(LIBDIRS) $(LIBS) -o $(TARGET).elf + +%.hex: $(TARGET).elf + avr-objcopy -O ihex $(HEX_FLASH_FLAGS) $< $@ + +%.eep: $(TARGET).elf + avr-objcopy $(HEX_EEPROM_FLAGS) -O ihex $< $@ || exit 0 + +%.lss: $(TARGET).elf + avr-objdump -h -S $< > $@ + +size: $(TARGET).elf + @echo + @avr-size -C --mcu=${MCU} ${TARGET}.elf + +flash: $(TARGET).hex + avrdude -p m32 -c avrisp2 -P usb \ + -U flash:w:$(TARGET).hex + +eeprom: $(TARGET).hex + avrdude -p m32 -c avrisp2 -P usb \ + -U eeprom:w:$(TARGET).eep + +## Clean target +.PHONY: clean +clean: + rm -rf $(OBJECTS) dep/* + for suf in elf hex eep lss map ; do \ + rm -f $(TARGET).$$suf ; \ + done + + +## Other dependencies +-include $(shell mkdir dep 2>/dev/null) $(wildcard dep/*) + diff --git a/controller/adc.c b/controller/adc.c new file mode 100644 index 0000000..f4748ba --- /dev/null +++ b/controller/adc.c @@ -0,0 +1,57 @@ +/** + * Analog to Digital converter routines + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Steffen Vogel + */ + +#include + +#include "adc.h" + +/** + * Initialisierung Analog to digital Converter (ADC) + */ +void adc_init() { + uint16_t result; + + ADC_DDR = 0x00; // Pins als Eingänge + ADC_PORT = 0x00; // Pullups deaktivieren + + ADMUX = (1< + */ + +#ifndef _ADC_H_ +#define _ADC_H_ + +// Konfiguration +#define ADC_PORT PORTA +#define ADC_DDR DDRA +#define ADC_PIN_STERING_LEFT 0 +#define ADC_PIN_STERING_RIGHT 1 +#define ADC_PIN_BATT_LOGIC 2 +#define ADC_PIN_BATT_DRIVE 3 +#define ADMUX_MASK 0x1F + +void adc_init(); +uint16_t adc_read(uint8_t channel); +uint16_t adc_read_avg(uint8_t channel, uint8_t average); + +#endif /* _ADC_H_ */ diff --git a/controller/init.o b/controller/init.o new file mode 100644 index 0000000000000000000000000000000000000000..62de3c515820a70ee1e6b0707ae982b1b984022d GIT binary patch literal 4216 zcmb7{O>9(E6o5}@1^kzvpaC@)Fm!O3nfKCBtX;B;Pn@3j>C zVL(s|1Y!ufF)=Z^FeYp;sfIQ+aRGaE!$L4t6I@8T(1k(kIp_Y&Z7Y!8v~$0Ee(pWz z+3ieKh{=_^Pp$V<&$*Hok0ZWVBfxnOJ;Q ztg#37E(X9qD8m9?q1)g*@{=qDj0&JBIWYJGgD)BUhrw%bu_lhGg$93P@D+pa#!#AU z4UjhYRfC5OK4b8CgD)ZEr4@j( z{}ttGt(6@ue#zjI27hJnHRL87;5q+gKFGZM4wApY9ASQwc@y(n%r7#(&AgAf$$W_U zF!NdFQ_Np7pJD!v`4i@!m_K9woB0do6$>ebbIeKR^UTjNf6ZKH{+9WD=8MdqGylju z!F-wdGV>MYKba?)mn@>St}#cM=@bF%VE&7_#QYEQA?78#cONpZn6r;$sP^a_+lYO< z#QZ$ZW7?Sf3)<*C#Y@tJ8@IIYL7TPkfVPQg0>~TkJS@?gJS>F{Im*K_z;bZQ!-II& z6+Z;`X?_Gfl>AXxp?M8Fta&Z0*8DieBw8NU!FtV|U~7&+MspmxG$-`^&w~X|OF7M# zm;9{ksVgh4HELn31o5iZ@5Y00DA5TWrP(y%M+Ohm0nx6hrkA!%nbIfs6;4wR}zpAGCt_vRqy zkdYm65{{itJ5cu;eXG?JNwP@VY?4G1JE5DCu(G;2FxUuceGRv)T~lK96iqBm<>Yfr z)5a=kwomGrFnMpzkg$fP)|3_4gkDifSUYZimd3Fm~8HD=Blp&R~;4g^)t4|TRV zk!>zAtJcD5&N3T?`9@;}oKX}|Z;zFrV8s3)I~y!J=U6sYM9UmT~Isd7AOsy&NQx=iokwKT?#QZ zKIc%b4Y9~#I}1;BcaVC0&x%p_QRAo`;qnmZH%FZbQngZA(y3sSW!Hl>#@VLR1tB_r#f6I@8;F{-;$D3Q1J^`uV9|8c-6xL z1MV%{jQv34c}|a;Eu8Q-$5qP8O~fM&gN9V@q7|VBn3a*Xv?25;V^b}~4MHg%12j$A z(o~$rq%hS|+zd3uBZ{V(lr+VyL19LiYAIe~lxEpJpl z>TWS;TU13Q zH&Z8yB6A~^j@}kEQK`+;iIRxS`isNzRM<1BVaR6{!dIst%}2Ra_)5`GiHtC``QHA@ zVBq2{D-;Mgv>dOK`(eS!kntXbzfhPe&^bM7Rh4qxes(S^{4^ci@25Ai1*3BC9nK z;RjUEcb{r%EqW_8?Na#dxmg)uuk5H_V8}b}2e^vkJMkY~cwKr6rm;ESB-%ZLGS$?4 zYOH!w-T_n7N=|*djzUP=XGB8!cFup3cAA=|yq+?~E0O6tSG1|=H3;JSnj}-xPY8wl zotmclwPKnbkGTW1{z835^60meJmouWq0sZf*6oD?UW1<9g&hiZGHlthoBObTpy0cG k%m-cHlLMN90$NV7$l|Xycn=m@$*TtM#PCQ?vAkmNe~P~_6951J literal 0 HcmV?d00001 diff --git a/controller/lcd.c b/controller/lcd.c new file mode 100644 index 0000000..0bc52d9 --- /dev/null +++ b/controller/lcd.c @@ -0,0 +1,236 @@ +/** + * Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus + * + * Die Pinbelegung ist über defines in lcd.h einstellbar + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @link http://www.mikrocontroller.net/articles/HD44780 + * @link http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung + */ + +#include +#include + +#include + +#include "lcd.h" + +/** + * Erzeugt einen Enable-Puls + */ +static void lcd_enable() { + LCD_PORT |= (1<>(4-LCD_DB)); // Maske löschen + LCD_PORT |= (data>>(4-LCD_DB)); // Bits setzen + lcd_enable(); +} + +/** + * Initialisierung: muss ganz am Anfang des Programms aufgerufen werden + */ +void lcd_init() { + // verwendete Pins auf Ausgang schalten + uint8_t pins = (0x0F << LCD_DB) | // 4 Datenleitungen + (1< 100) return; + + lcd_setcursor(startx, starty); + lcd_data(0b00111100); // < + + for (i=0; i < length-2; i++) { + lcd_setcursor( startx+1+i , starty ); + + if (percent*(length-2)/100 <= i ) { + lcd_data('-'); + } + else { + lcd_data(0b11111111); + } + } + + lcd_setcursor(startx+length-1, starty ); + lcd_data(0b00111110); // > +} + +/** + * Ausgabe einer Ganzzahl mit führenden Leerzeichen + */ +void lcd_int(int16_t number, uint8_t length) { + char buffer[length+1]; + bool vz = true; + bool zf = true; + bool neg = (number < 0); + + buffer[length] = '\0'; + + for (int8_t counter = length-1; counter >= 0; counter--) { + if (zf) { + buffer[counter] = '0' + (abs(number) % 10); + number /= 10; + zf = (bool) number; + } + else if (vz && neg) { + buffer[counter] = '-'; + vz = false; + } + else { + buffer[counter] = ' '; + } + } + + lcd_string(buffer); +} + diff --git a/controller/lcd.h b/controller/lcd.h new file mode 100644 index 0000000..2b67526 --- /dev/null +++ b/controller/lcd.h @@ -0,0 +1,154 @@ +/** + * Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus + * + * Die Pinbelegung ist über #defines in lcd.h konfigurierbar + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @link http://www.mikrocontroller.net/articles/HD44780 + * @link http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung + */ + +#ifndef _LCD_H_ +#define _LCD_H_ + +#include +#include + +#include +#include + +#include "rotary.h" + +// Pinbelegung für das LCD, an verwendete Pins anpassen +// Alle LCD Pins müssen an einem Port angeschlossen sein und die 4 +// Datenleitungen müssen auf aufeinanderfolgenden Pins liegen + +// LCD DB4-DB7 <--> PORTD Bit PD0-PD3 +#define LCD_PORT PORTC +#define LCD_DDR DDRC +#define LCD_DB PC4 + +// LCD RS <--> PORTD Bit PD4 (RS: 0=Data, 1=Command) +#define LCD_RS PC3 + +// LCD EN <--> PORTD Bit PD5 (EN: 1-Impuls für Daten) +#define LCD_EN PC2 + +// LCD Ausführungszeiten (MS=Millisekunden, US=Mikrosekunden) +#define LCD_BOOTUP_MS 15 +#define LCD_ENABLE_US 1 +#define LCD_WRITEDATA_US 46 +#define LCD_COMMAND_US 42 + +#define LCD_SOFT_RESET_MS1 5 +#define LCD_SOFT_RESET_MS2 1 +#define LCD_SOFT_RESET_MS3 1 +#define LCD_SET_4BITMODE_MS 5 + +#define LCD_CLEAR_DISPLAY_MS 2 +#define LCD_CURSOR_HOME_MS 2 + +// Zeilendefinitionen des verwendeten LCD +// Die Einträge hier sollten für ein LCD mit einer Zeilenlänge von 16 Zeichen passen +// Bei anderen Zeilenlängen müssen diese Einträge angepasst werden +#define LCD_DDADR_LINE1 0x00 +#define LCD_DDADR_LINE2 0x40 +#define LCD_DDADR_LINE3 0x10 +#define LCD_DDADR_LINE4 0x50 + +// Initialisierung: muss ganz am Anfang des Programms aufgerufen werden. +void lcd_init( void ); + +// LCD löschen +void lcd_clear( void ); + +// Cursor in die 1. Zeile, 0-te Spalte +void lcd_home( void ); + +// Cursor an eine beliebige Position +void lcd_setcursor( uint8_t spalte, uint8_t zeile ); + +// Ausgabe eines einzelnen Zeichens an der aktuellen Cursorposition +void lcd_data( uint8_t data ); + +// Ausgabe eines Strings an der aktuellen Cursorposition +void lcd_string( const char *data ); + +// Definition eines benutzerdefinierten Sonderzeichens. +// data muss auf ein Array[5] mit den Spaltencodes des zu definierenden Zeichens +// zeigen +void lcd_generatechar( uint8_t code, const uint8_t *data ); + +// Ausgabe eines Kommandos an das LCD. +void lcd_command( uint8_t data ); + +// Ausgabe Balkenanzeige +void lcd_bar(uint8_t startx, uint8_t starty, uint8_t length, uint8_t percent); + +// Ausgabe einer ganzen Zahl +void lcd_int(int16_t number, uint8_t length); + +// LCD Befehle und Argumente. +// Zur Verwendung in lcd_command + +// Clear Display -------------- 0b00000001 +#define LCD_CLEAR_DISPLAY 0x01 + +// Cursor Home ---------------- 0b0000001x +#define LCD_CURSOR_HOME 0x02 + +// Set Entry Mode ------------- 0b000001xx +#define LCD_SET_ENTRY 0x04 + +#define LCD_ENTRY_DECREASE 0x00 +#define LCD_ENTRY_INCREASE 0x02 +#define LCD_ENTRY_NOSHIFT 0x00 +#define LCD_ENTRY_SHIFT 0x01 + +// Set Display ---------------- 0b00001xxx +#define LCD_SET_DISPLAY 0x08 + +#define LCD_DISPLAY_OFF 0x00 +#define LCD_DISPLAY_ON 0x04 +#define LCD_CURSOR_OFF 0x00 +#define LCD_CURSOR_ON 0x02 +#define LCD_BLINKING_OFF 0x00 +#define LCD_BLINKING_ON 0x01 + +// Set Shift ------------------ 0b0001xxxx +#define LCD_SET_SHIFT 0x10 + +#define LCD_CURSOR_MOVE 0x00 +#define LCD_DISPLAY_SHIFT 0x08 +#define LCD_SHIFT_LEFT 0x00 +#define LCD_SHIFT_RIGHT 0x04 + +// Set Function --------------- 0b001xxxxx +#define LCD_SET_FUNCTION 0x20 + +#define LCD_FUNCTION_4BIT 0x00 +#define LCD_FUNCTION_8BIT 0x10 +#define LCD_FUNCTION_1LINE 0x00 +#define LCD_FUNCTION_2LINE 0x08 +#define LCD_FUNCTION_5X7 0x00 +#define LCD_FUNCTION_5X10 0x04 + +#define LCD_SOFT_RESET 0x30 + +// Set CG RAM Address --------- 0b01xxxxxx (Character Generator RAM) +#define LCD_SET_CGADR 0x40 + +#define LCD_GC_CHAR0 0 +#define LCD_GC_CHAR1 1 +#define LCD_GC_CHAR2 2 +#define LCD_GC_CHAR3 3 +#define LCD_GC_CHAR4 4 +#define LCD_GC_CHAR5 5 +#define LCD_GC_CHAR6 6 +#define LCD_GC_CHAR7 7 + +// Set DD RAM Address --------- 0b1xxxxxxx (Display Data RAM) +#define LCD_SET_DDADR 0x80 + +#endif /* _LCD_H_ */ diff --git a/controller/main.c b/controller/main.c new file mode 100644 index 0000000..bfb5b1b --- /dev/null +++ b/controller/main.c @@ -0,0 +1,548 @@ +/** + * Main loop + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Steffen Vogel + */ + +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "lcd.h" +#include "rotary.h" +#include "adc.h" +#include "pid.h" +#include "uart.h" + +#define DISPLAY_MODI 11 +#define BAUDRATE 57600 + +#define MAGIC_BYTE 0xca +#define MAGIC_LEN 16 + +const char *mode_str[] = { + "Stop ", + "Auto ", + "Manual", + "UART " +}; + +const char *display_str[] = { + NULL, + "PWM Motor", + "PWM Servo", + "PID Drive: P", + "PID Drive: I", + "PID Stering: P", + "PID Stering: I", + "ADC Inductor: L", + "ADC Inductor: R", + "ADC Batt: Logic", + "ADC Batt: Drive" +}; + +enum channel { + STERING_LEFT, + STERING_RIGHT, + BATT_LOGIC, + BATT_DRIVE +}; + +enum state { + HALT, + AUTO, + MANUAL +}; + +enum menu { + OVERVIEW, + PWM_DRIVE, + PWM_STERING, + PID_DRIVE_P, + PID_DRIVE_I, + PID_STERING_P, + PID_STERING_I, + ADC_STERING_LEFT, + ADC_STERING_RIGHT, + ADC_BATT_LOGIC, + ADC_BATT_DRIVE, +}; + +enum cmd { + SET_STATUS, /* Mode, Display */ + SET_PWM, /* Drive & Stering */ + SET_PID, /* Controller state */ + GET_PID /* Controller state */ +}; + +// EEPROM +int16_t pid_drive_p_ee EEMEM = 0; +int16_t pid_drive_i_ee EEMEM = 0; +int16_t pid_stering_p_ee EEMEM = 39; +int16_t pid_stering_i_ee EEMEM = 0; + +int16_t pwm_drive_ee EEMEM = 0; +int16_t pwm_stering_ee EEMEM = 0; + +// Globale Daten +int16_t pwm_stering; +int16_t pwm_drive; + +int8_t out_stering; +uint8_t out_drive; + +int16_t adc_stering_left; +int16_t adc_stering_right; +int16_t adc_batt_logic; +int16_t adc_batt_drive; + +uint8_t speed; +uint16_t speed_cnt; +bool speed_ovf = true; + +struct pid pid_drive; +struct pid pid_stering; + +enum state mode; +enum menu display; + +bool edit = false; +bool redraw = true; + +/** + * Parameter editieren + */ +void parameter_edit(int16_t *parameter, int16_t *parameter_ee, enum taster input) { + switch (input) { + case DGB_SW: // Editier-Modus togglen + edit = !edit; + break; + + case DGB_CW: // Wert ändern + if (edit) *parameter = *parameter + 1; + break; + + case DGB_CCW: // Wert ändern + if (edit) *parameter = *parameter - 1; + break; + + case SW_GRUEN: // Laden aus EEPROM + *parameter = eeprom_read_word((uint16_t *) parameter_ee); + break; + + case SW_BLAU: // Speichern im EEPROM + eeprom_write_word((uint16_t *) parameter_ee, *parameter); + break; + } +} + +/** + * Startsequenz + */ +void greeter() { + // UART + uart_puts("Donaudampfschiff\r\n"); + + // LCD + lcd_clear(); + lcd_string("Donaudampfschiff"); + lcd_setcursor(0, 1); + lcd_string(" 4.Sem.Proj. "); + _delay_ms(1500); + lcd_clear(); +} + +/** + * Initialize Timers and IO Ports + */ +void init() { + DDRB = 0xff; + DDRC = 0xff; + DDRD = 0b11111011; + + // Geschwindigkeitssensor + // Falling Edge on INT0 triggers Interrupt + MCUCR = (1<>1) + (( pwm_drive * (128 - abs(out_stering))) >> 8); + } + break; + + case HALT: + default: + out_drive = 0; + out_stering = 0; + } + + /** + * Servo Tastgrad + * Links 2.1ms => 4200 + * Mitte 1.5ms => 3000 + * Rechts 0.9ms => 1800 + */ + OCR1A = 3000 + (out_stering * 9); + OCR2 = out_drive; +} + + +/** + * Interupt Subroutine für ADC + */ +ISR(ADC_vect) { + enum channel ch = ADMUX & ADMUX_MASK; + + switch (ch) { + case STERING_LEFT: + adc_stering_left = ADC; + break; + + case STERING_RIGHT: + adc_stering_right = ADC; + break; + + case BATT_LOGIC: + + adc_batt_logic = ADC; + break; + + case BATT_DRIVE: + adc_batt_drive = ADC; + break; + } + + ADMUX = (ADMUX & ~ADMUX_MASK); + ADMUX |= (ch >= 1) ? 0 : ++ch; + + ADCSRA |= (1< + * @link http://www.atmel.com + * @revision 456 + * @date 2006-02-16 12:46:13 + */ + +#include +#include + +#include "pid.h" + +/** + * Initialisation of PID controller parameters + * + * Initialise the variables used by the PID algorithm + * + * @param p_factor Proportional term + * @param i_factor Integral term + * @param d_factor Derivate term + * @param pid Struct with PID status + */ +void pid_init(int16_t pFactor, int16_t iFactor, int16_t dFactor, struct pid *pid) { + // Start values for PID controller + pid->sumError = 0; + pid->lastProcessValue = 0; + + // Tuning constants for PID loop + pid->pFactor = pFactor; + pid->iFactor = iFactor; + pid->dFactor = dFactor; + + // Limits to avoid overflow + pid->maxError = MAX_INT / (pid->pFactor + 1); + pid->maxSumError = MAX_I_TERM / (pid->iFactor + 1); +} + +/** + * PID control algorithm + * + * Calculates output from setpoint, process value and PID status + * + * @param setPoint Desired value + * @param processValue Measured value + * @param pid PID status struct + */ +int16_t pid_controller(int16_t setPoint, int16_t processValue, struct pid *pid) { + int16_t error, pTerm, dTerm; + int32_t iTerm, ret, temp; + + error = setPoint - processValue; + + // Calculate pTerm and limit error overflow + if (error > pid->maxError){ + pTerm = MAX_INT; + } + else if (error < -pid->maxError){ + pTerm = -MAX_INT; + } + else { + pTerm = pid->pFactor * error; + } + + // Calculate iTerm and limit integral runaway + temp = pid->sumError + error; + if (temp > pid->maxSumError){ + iTerm = MAX_I_TERM; + pid->sumError = pid->maxSumError; + } + else if (temp < -pid->maxSumError){ + iTerm = -MAX_I_TERM; + pid->sumError = -pid->maxSumError; + } + else { + pid->sumError = temp; + iTerm = pid->iFactor * pid->sumError; + } + + // Calculate Dterm + dTerm = pid->dFactor * (pid->lastProcessValue - processValue); + + pid->lastProcessValue = processValue; + + ret = (pTerm + iTerm + dTerm) >> SCALING_SHIFT; + + if (ret > MAX_INT){ + ret = MAX_INT; + } + else if (ret < -MAX_INT){ + ret = -MAX_INT; + } + + return (int16_t) ret; +} + +/** + * Resets the integrator + * + * Calling this function will reset the integrator in the PID regulator + */ +void pid_reset_integrator(struct pid *pid) { + pid->sumError = 0; +} diff --git a/controller/pid.h b/controller/pid.h new file mode 100644 index 0000000..19c9326 --- /dev/null +++ b/controller/pid.h @@ -0,0 +1,54 @@ +/** + * General PID implementation for AVR + * + * Discrete PID controller implementation. Set up by giving P/I/D terms + * to pid_init(), and uses a struct pid to store internal values. + * + * Based on ATMEL AppNote: AVR221 - Discrete PID controller + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Atmel Corporation + * @link http://www.atmel.com + * @revision 456 + * @date 2006-02-16 12:46:13 + */ + +#ifndef _PID_H_ +#define _PID_H_ + +#include +#include + +#define SCALING_FACTOR 128 +#define SCALING_SHIFT 7 + +/** + * PID Status + * + * Setpoints and data used by the PID control algorithm + */ +struct pid { + int16_t lastProcessValue; // Last process value, used to find derivative of process value. + int32_t sumError; // Summation of errors, used for integrate calculations + int16_t pFactor; // The Proportional tuning constant, multiplied with SCALING_FACTOR + int16_t iFactor; // The Integral tuning constant, multiplied with SCALING_FACTOR + int16_t dFactor; // The Derivative tuning constant, multiplied with SCALING_FACTOR + int16_t maxError; // Maximum allowed error, avoid overflow + int32_t maxSumError; // Maximum allowed sumerror, avoid overflow +}; + +/** + * Maximum values + * + * Needed to avoid sign/overflow problems + */ +#define MAX_INT INT16_MAX +#define MAX_LONG INT32_MAX +#define MAX_I_TERM (MAX_LONG / 2) + +void pid_init(int16_t pFactor, int16_t iFactor, int16_t dFactor, struct pid *pid); +int16_t pid_controller(int16_t setPoint, int16_t processValue, struct pid *pid); +void pid_reset_integrator(struct pid *pid); + +#endif /* _PID_H_ */ diff --git a/controller/rotary.c b/controller/rotary.c new file mode 100644 index 0000000..b050a3f --- /dev/null +++ b/controller/rotary.c @@ -0,0 +1,125 @@ +/** + * Rotary encoder routines + * + * @copyright 2012 Institute Automation of Complex Power Systems (ACS), RWTH Aachen University + * @license http://www.gnu.org/licenses/gpl.txt GNU Public License + * @author Steffen Vogel + */ + +#include "rotary.h" + +/** + * Drehgeber initialisieren + */ +void dgb_init() { + // DDR auf input setzen + SW_DDR &= ~(1< + */ + +#ifndef _ROTARY_H_ +#define _ROTARY_H_ + +#include +#include +#include + +#include +#include + +#define DGB_PORT PORTB +#define DGB_DDR DDRB +#define DGB_PIN_A PB0 +#define DGB_PIN_B PB1 +#define DGB_PIN_SW PB2 +#define DGB_PIN PINB + +// Definitionen für zusätzliche Schalter +#define SW_PORT PORTB +#define SW_DDR DDRB +#define SW_PIN PINB +#define SW_PIN_BLAU PB3 +#define SW_PIN_GRUEN PB4 + +enum taster { + DGB_CCW = 1, + DGB_CW, + DGB_SW, + SW_GRUEN, + SW_BLAU +}; + +void dgb_init(); +enum taster dgb_read(); + +#endif /* _ROTARY_H_ */ diff --git a/controller/uart.c b/controller/uart.c new file mode 100644 index 0000000..6034070 --- /dev/null +++ b/controller/uart.c @@ -0,0 +1,651 @@ +/************************************************************************* +Title: Interrupt UART library with receive/transmit circular buffers +Author: Peter Fleury http://jump.to/fleury +File: $Id: uart.c,v 1.6.2.2 2009/11/29 08:56:12 Peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4.6 or higher +Hardware: any AVR with built-in UART, +License: GNU General Public License + +DESCRIPTION: + An interrupt is generated when the UART has finished transmitting or + receiving a byte. The interrupt handling routines use circular buffers + for buffering received and transmitted data. + + The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE variables define + the buffer size in bytes. Note that these variables must be a + power of 2. + +USAGE: + Refere to the header file uart.h for a description of the routines. + See also example test_uart.c. + +NOTES: + Based on Atmel Application Note AVR306 + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + 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. + +*************************************************************************/ +#include +#include +#include +#include "uart.h" + + +/* + * constants and macros + */ + +/* size of RX/TX buffers */ +#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1) +#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1) + +#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK ) +#error RX buffer size is not a power of 2 +#endif +#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK ) +#error TX buffer size is not a power of 2 +#endif + +#if defined(__AVR_AT90S2313__) \ + || defined(__AVR_AT90S4414__) || defined(__AVR_AT90S4434__) \ + || defined(__AVR_AT90S8515__) || defined(__AVR_AT90S8535__) \ + || defined(__AVR_ATmega103__) + /* old AVR classic or ATmega103 with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS USR + #define UART0_CONTROL UCR + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_AT90S2333__) || defined(__AVR_AT90S4433__) + /* old AVR classic with one UART */ + #define AT90_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega8__) || defined(__AVR_ATmega16__) || defined(__AVR_ATmega32__) \ + || defined(__AVR_ATmega8515__) || defined(__AVR_ATmega8535__) \ + || defined(__AVR_ATmega323__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega163__) + /* ATmega163 with one UART */ + #define ATMEGA_UART + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega162__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega64__) || defined(__AVR_ATmega128__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_UART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_UART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_UART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega161__) + /* ATmega with UART */ + #error "AVR ATmega161 currently not supported by this libaray !" +#elif defined(__AVR_ATmega169__) + /* ATmega with one USART */ + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega48__) ||defined(__AVR_ATmega88__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega48P__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328P__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATtiny2313__) + #define ATMEGA_USART + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RX + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_UDRE + #define UART0_STATUS UCSRA + #define UART0_CONTROL UCSRB + #define UART0_DATA UDR + #define UART0_UDRIE UDRIE +#elif defined(__AVR_ATmega329__) ||defined(__AVR_ATmega3290__) ||\ + defined(__AVR_ATmega649__) ||defined(__AVR_ATmega6490__) ||\ + defined(__AVR_ATmega325__) ||defined(__AVR_ATmega3250__) ||\ + defined(__AVR_ATmega645__) ||defined(__AVR_ATmega6450__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_UART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_UART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega640__) +/* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART0_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART0_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#elif defined(__AVR_ATmega644__) + /* ATmega with one USART */ + #define ATMEGA_USART0 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 +#elif defined(__AVR_ATmega164P__) || defined(__AVR_ATmega324P__) || defined(__AVR_ATmega644P__) + /* ATmega with two USART */ + #define ATMEGA_USART0 + #define ATMEGA_USART1 + #define UART0_RECEIVE_INTERRUPT SIG_USART_RECV + #define UART1_RECEIVE_INTERRUPT SIG_USART1_RECV + #define UART0_TRANSMIT_INTERRUPT SIG_USART_DATA + #define UART1_TRANSMIT_INTERRUPT SIG_USART1_DATA + #define UART0_STATUS UCSR0A + #define UART0_CONTROL UCSR0B + #define UART0_DATA UDR0 + #define UART0_UDRIE UDRIE0 + #define UART1_STATUS UCSR1A + #define UART1_CONTROL UCSR1B + #define UART1_DATA UDR1 + #define UART1_UDRIE UDRIE1 +#else + #error "no UART definition for MCU available" +#endif + + +/* + * module global variables + */ +static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART_TxHead; +static volatile unsigned char UART_TxTail; +static volatile unsigned char UART_RxHead; +static volatile unsigned char UART_RxTail; +static volatile unsigned char UART_LastRxError; + +#if defined( ATMEGA_USART1 ) +static volatile unsigned char UART1_TxBuf[UART_TX_BUFFER_SIZE]; +static volatile unsigned char UART1_RxBuf[UART_RX_BUFFER_SIZE]; +static volatile unsigned char UART1_TxHead; +static volatile unsigned char UART1_TxTail; +static volatile unsigned char UART1_RxHead; +static volatile unsigned char UART1_RxTail; +static volatile unsigned char UART1_LastRxError; +#endif + + + +SIGNAL(UART0_RECEIVE_INTERRUPT) +/************************************************************************* +Function: UART Receive Complete interrupt +Purpose: called when the UART has received a character +**************************************************************************/ +{ + unsigned char tmphead; + unsigned char data; + unsigned char usr; + unsigned char lastRxError; + + + /* read UART status register and UART data register */ + usr = UART0_STATUS; + data = UART0_DATA; + + /* */ +#if defined( AT90_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#elif defined( ATMEGA_USART0 ) + lastRxError = (usr & (_BV(FE0)|_BV(DOR0)) ); +#elif defined ( ATMEGA_UART ) + lastRxError = (usr & (_BV(FE)|_BV(DOR)) ); +#endif + + /* calculate buffer index */ + tmphead = ( UART_RxHead + 1) & UART_RX_BUFFER_MASK; + + if ( tmphead == UART_RxTail ) { + /* error: receive buffer overflow */ + lastRxError = UART_BUFFER_OVERFLOW >> 8; + }else{ + /* store new index */ + UART_RxHead = tmphead; + /* store received data in buffer */ + UART_RxBuf[tmphead] = data; + } + UART_LastRxError = lastRxError; +} + + +SIGNAL(UART0_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART Data Register Empty interrupt +Purpose: called when the UART is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART_TxHead != UART_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK; + UART_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART0_CONTROL &= ~_BV(UART0_UDRIE); + } +} + + +/************************************************************************* +Function: uart_init() +Purpose: initialize UART and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart_init(unsigned int baudrate) +{ + UART_TxHead = 0; + UART_TxTail = 0; + UART_RxHead = 0; + UART_RxTail = 0; + +#if defined( AT90_UART ) + /* set baud rate */ + UBRR = (unsigned char)baudrate; + + /* enable UART receiver and transmmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|_BV(RXEN)|_BV(TXEN); + +#elif defined (ATMEGA_USART) + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART0_STATUS = (1<>8); + UBRRL = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<>8); + UBRR0L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE0)|(1<>8); + UBRR = (unsigned char) baudrate; + + /* Enable UART receiver and transmitter and receive complete interrupt */ + UART0_CONTROL = _BV(RXCIE)|(1<> 8; + }else{ + /* store new index */ + UART1_RxHead = tmphead; + /* store received data in buffer */ + UART1_RxBuf[tmphead] = data; + } + UART1_LastRxError = lastRxError; +} + + +SIGNAL(UART1_TRANSMIT_INTERRUPT) +/************************************************************************* +Function: UART1 Data Register Empty interrupt +Purpose: called when the UART1 is ready to transmit the next byte +**************************************************************************/ +{ + unsigned char tmptail; + + + if ( UART1_TxHead != UART1_TxTail) { + /* calculate and store new buffer index */ + tmptail = (UART1_TxTail + 1) & UART_TX_BUFFER_MASK; + UART1_TxTail = tmptail; + /* get one byte from buffer and write it to UART */ + UART1_DATA = UART1_TxBuf[tmptail]; /* start transmission */ + }else{ + /* tx buffer empty, disable UDRE interrupt */ + UART1_CONTROL &= ~_BV(UART1_UDRIE); + } +} + + +/************************************************************************* +Function: uart1_init() +Purpose: initialize UART1 and set baudrate +Input: baudrate using macro UART_BAUD_SELECT() +Returns: none +**************************************************************************/ +void uart1_init(unsigned int baudrate) +{ + UART1_TxHead = 0; + UART1_TxTail = 0; + UART1_RxHead = 0; + UART1_RxTail = 0; + + + /* Set baud rate */ + if ( baudrate & 0x8000 ) + { + UART1_STATUS = (1<>8); + UBRR1L = (unsigned char) baudrate; + + /* Enable USART receiver and transmitter and receive complete interrupt */ + UART1_CONTROL = _BV(RXCIE1)|(1< http://jump.to/fleury +File: $Id: uart.h,v 1.8.2.1 2007/07/01 11:14:38 peter Exp $ +Software: AVR-GCC 4.1, AVR Libc 1.4 +Hardware: any AVR with built-in UART, tested on AT90S8515 & ATmega8 at 4 Mhz +License: GNU General Public License +Usage: see Doxygen manual + +LICENSE: + Copyright (C) 2006 Peter Fleury + + 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 + 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. + +************************************************************************/ + +/** + * @defgroup pfleury_uart UART Library + * @code #include @endcode + * + * @brief Interrupt UART library using the built-in UART with transmit and receive circular buffers. + * + * This library can be used to transmit and receive data through the built in UART. + * + * An interrupt is generated when the UART has finished transmitting or + * receiving a byte. The interrupt handling routines use circular buffers + * for buffering received and transmitted data. + * + * The UART_RX_BUFFER_SIZE and UART_TX_BUFFER_SIZE constants define + * the size of the circular buffers in bytes. Note that these constants must be a power of 2. + * You may need to adapt this constants to your target and your application by adding + * CDEFS += -DUART_RX_BUFFER_SIZE=nn -DUART_RX_BUFFER_SIZE=nn to your Makefile. + * + * @note Based on Atmel Application Note AVR306 + * @author Peter Fleury pfleury@gmx.ch http://jump.to/fleury + */ + +/**@{*/ + + +#if (__GNUC__ * 100 + __GNUC_MINOR__) < 304 +#error "This library requires AVR-GCC 3.4 or later, update to newer AVR-GCC compiler !" +#endif + + +/* +** constants and macros +*/ + +/** @brief UART Baudrate Expression + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT(baudRate,xtalCpu) ((xtalCpu)/((baudRate)*16l)-1) + +/** @brief UART Baudrate Expression for ATmega double speed mode + * @param xtalcpu system clock in Mhz, e.g. 4000000L for 4Mhz + * @param baudrate baudrate in bps, e.g. 1200, 2400, 9600 + */ +#define UART_BAUD_SELECT_DOUBLE_SPEED(baudRate,xtalCpu) (((xtalCpu)/((baudRate)*8l)-1)|0x8000) + + +/** Size of the circular receive buffer, must be power of 2 */ +#ifndef UART_RX_BUFFER_SIZE +#define UART_RX_BUFFER_SIZE 64 +#endif +/** Size of the circular transmit buffer, must be power of 2 */ +#ifndef UART_TX_BUFFER_SIZE +#define UART_TX_BUFFER_SIZE 32 +#endif + +/* test if the size of the circular buffers fits into SRAM */ +#if ( (UART_RX_BUFFER_SIZE+UART_TX_BUFFER_SIZE) >= (RAMEND-0x60 ) ) +#error "size of UART_RX_BUFFER_SIZE + UART_TX_BUFFER_SIZE larger than size of SRAM" +#endif + +/* +** high byte error return code of uart_getc() +*/ +#define UART_FRAME_ERROR 0x0800 /* Framing Error by UART */ +#define UART_OVERRUN_ERROR 0x0400 /* Overrun condition by UART */ +#define UART_BUFFER_OVERFLOW 0x0200 /* receive ringbuffer overflow */ +#define UART_NO_DATA 0x0100 /* no receive data available */ + + +/* +** function prototypes +*/ + +/** + @brief Initialize UART and set baudrate + @param baudrate Specify baudrate using macro UART_BAUD_SELECT() + @return none +*/ +extern void uart_init(unsigned int baudrate); + + +/** + * @brief Get received byte from ringbuffer + * + * Returns in the lower byte the received character and in the + * higher byte the last receive error. + * UART_NO_DATA is returned when no data is available. + * + * @param void + * @return lower byte: received byte from ringbuffer + * @return higher byte: last receive status + * - \b 0 successfully received data from UART + * - \b UART_NO_DATA + *
no receive data available + * - \b UART_BUFFER_OVERFLOW + *
Receive ringbuffer overflow. + * We are not reading the receive buffer fast enough, + * one or more received character have been dropped + * - \b UART_OVERRUN_ERROR + *
Overrun condition by UART. + * A character already present in the UART UDR register was + * not read by the interrupt handler before the next character arrived, + * one or more received characters have been dropped. + * - \b UART_FRAME_ERROR + *
Framing Error by UART + */ +extern unsigned int uart_getc(void); + + +/** + * @brief Put byte to ringbuffer for transmitting via UART + * @param data byte to be transmitted + * @return none + */ +extern void uart_putc(unsigned char data); + + +/** + * @brief Put string to ringbuffer for transmitting via UART + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s string to be transmitted + * @return none + */ +extern void uart_puts(const char *s ); + + +/** + * @brief Put string from program memory to ringbuffer for transmitting via UART. + * + * The string is buffered by the uart library in a circular buffer + * and one character at a time is transmitted to the UART using interrupts. + * Blocks if it can not write the whole string into the circular buffer. + * + * @param s program memory string to be transmitted + * @return none + * @see uart_puts_P + */ +extern void uart_puts_p(const char *s ); + +/** + * @brief Macro to automatically put a string constant into program memory + */ +#define uart_puts_P(__s) uart_puts_p(PSTR(__s)) + + + +/** @brief Initialize USART1 (only available on selected ATmegas) @see uart_init */ +extern void uart1_init(unsigned int baudrate); +/** @brief Get received byte of USART1 from ringbuffer. (only available on selected ATmega) @see uart_getc */ +extern unsigned int uart1_getc(void); +/** @brief Put byte to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_putc */ +extern void uart1_putc(unsigned char data); +/** @brief Put string to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts */ +extern void uart1_puts(const char *s ); +/** @brief Put string from program memory to ringbuffer for transmitting via USART1 (only available on selected ATmega) @see uart_puts_p */ +extern void uart1_puts_p(const char *s ); +/** @brief Macro to automatically put a string constant into program memory */ +#define uart1_puts_P(__s) uart1_puts_p(PSTR(__s)) + +/**@}*/ + + +#endif // UART_H +