Initial Alpha Version

Ignoring Binaries
This commit is contained in:
Michael Rest
2011-05-28 13:16:45 +02:00
commit 9d61c10a50
8 changed files with 536 additions and 0 deletions

2
.gitignore vendored Normal file
View File

@@ -0,0 +1,2 @@
/default

40
floating_avg.c Normal file
View File

@@ -0,0 +1,40 @@
#include "floating_avg.h"
void InitFloatAvg(tFloatAvgFilter * io_pFloatAvgFilter,
tFloatAvgType i_DefaultValue)
{
// Den Buffer mit dem Initialisierungswert fuellen:
for (uint8_t i = 0; i < (1 << SIZE_OF_AVG); ++i)
{
io_pFloatAvgFilter->aData[i] = i_DefaultValue;
}
// Der naechste Wert soll an den Anfang des Buffers geschrieben werden:
io_pFloatAvgFilter->IndexNextValue = 0;
}
void AddToFloatAvg(tFloatAvgFilter * io_pFloatAvgFilter,
tFloatAvgType i_NewValue)
{
// Neuen Wert an die dafuer vorgesehene Position im Buffer schreiben.
io_pFloatAvgFilter->aData[io_pFloatAvgFilter->IndexNextValue] =
i_NewValue;
// Der naechste Wert wird dann an die Position dahinter geschrieben.
io_pFloatAvgFilter->IndexNextValue++;
// Wenn man hinten angekommen ist, vorne wieder anfangen.
io_pFloatAvgFilter->IndexNextValue %= (1 << SIZE_OF_AVG);
}
tFloatAvgType GetOutputValue(tFloatAvgFilter * io_pFloatAvgFilter)
{
tTempSumType TempSum = 0;
// Durchschnitt berechnen
for (uint8_t i = 0; i < (1 << SIZE_OF_AVG); ++i)
{
TempSum += io_pFloatAvgFilter->aData[i];
}
// Der cast is OK, wenn tFloatAvgType und tTempSumType korrekt gewaehlt wurden.
tFloatAvgType o_Result = (tFloatAvgType) (TempSum >> SIZE_OF_AVG);
return o_Result;
}

38
floating_avg.h Normal file
View File

@@ -0,0 +1,38 @@
#ifndef FLOATING_AVERAGE_H
#define FLOATING_AVERAGE_H
#include <inttypes.h>
// Ueber wieviele Werte soll der gleitende Mittelwert berechnet werden?
// 2**n Werte, da die Division als shift implementiert wird
#define SIZE_OF_AVG 3
// Datentyp, ueber den der gleitende Mittelwert berechnet werden soll.
typedef uint16_t tFloatAvgType;
// typedef float tFloatAvgType;
// Wird nur intern fuer die Durchschnittsberechnung benutzt.
// Muss Zahlen fassen koennen, die SIZE_OF_AVG mal groesser als tFloatAvgType sind.
typedef uint32_t tTempSumType;
// typedef float tTempSumType;
// Die Struktur, in der die Daten zwischengespeichert werden
typedef struct
{
tFloatAvgType aData[1 << SIZE_OF_AVG];
uint8_t IndexNextValue;
} tFloatAvgFilter;
// Initialisiert das Filter mit einem Startwert.
void InitFloatAvg(tFloatAvgFilter * io_pFloatAvgFilter,
tFloatAvgType i_DefaultValue);
// Schreibt einen neuen Wert in das Filter.
void AddToFloatAvg(tFloatAvgFilter * io_pFloatAvgFilter,
tFloatAvgType i_ui16NewValue);
// Berechnet den Durchschnitt aus den letzten SIZE_OF_AVG eingetragenen Werten.
tFloatAvgType GetOutputValue(tFloatAvgFilter * io_pFloatAvgFilter);
#endif

149
lcd-routines.c Normal file
View File

@@ -0,0 +1,149 @@
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
//
// Die Pinbelegung ist <20>ber defines in lcd-routines.h einstellbar
#include <avr/io.h>
#include "lcd-routines.h"
#include <util/delay.h>
// sendet ein Datenbyte an das LCD
void lcd_data (unsigned char temp1)
{
unsigned char temp2 = temp1;
LCD_PORT |= (1 << LCD_RS); // RS auf 1 setzen
temp1 = temp1 >> 4;
temp1 = temp1 & 0x0F;
LCD_PORT &= 0xF0;
LCD_PORT |= temp1; // setzen
lcd_enable ();
temp2 = temp2 & 0x0F;
LCD_PORT &= 0xF0;
LCD_PORT |= temp2; // setzen
lcd_enable ();
_delay_us (42);
}
// sendet einen Befehl an das LCD
void lcd_command (unsigned char temp1)
{
unsigned char temp2 = temp1;
LCD_PORT &= ~(1 << LCD_RS); // RS auf 0 setzen
temp1 = temp1 >> 4; // oberes Nibble holen
temp1 = temp1 & 0x0F; // maskieren
LCD_PORT &= 0xF0;
LCD_PORT |= temp1; // setzen
lcd_enable ();
temp2 = temp2 & 0x0F; // unteres Nibble holen und maskieren
LCD_PORT &= 0xF0;
LCD_PORT |= temp2; // setzen
lcd_enable ();
_delay_us (42);
}
// erzeugt den Enable-Puls
void lcd_enable (void)
{
// Bei Problemen ggf. Pause gem<65><6D> Datenblatt des LCD Controllers einf<6E>gen
// http://www.mikrocontroller.net/topic/81974#685882
LCD_PORT |= (1 << LCD_EN);
_delay_us (1); // kurze Pause
// Bei Problemen ggf. Pause gem<65><6D> Datenblatt des LCD Controllers verl<72>ngern
// http://www.mikrocontroller.net/topic/80900
LCD_PORT &= ~(1 << LCD_EN);
}
// Initialisierung:
// Muss ganz am Anfang des Programms aufgerufen werden.
void lcd_init (void)
{
LCD_DDR = LCD_DDR | 0x0F | (1 << LCD_RW) | (1 << LCD_RS) | (1 << LCD_EN); // Port auf Ausgang schalten
// muss 3mal hintereinander gesendet werden zur Initialisierung
_delay_ms (15);
LCD_PORT &= 0xF0;
LCD_PORT |= 0x03;
LCD_PORT &= ~(1 << LCD_RS); // RS auf 0
LCD_PORT &= ~(1 << LCD_RW); // R/W auf 0
lcd_enable ();
_delay_ms (5);
lcd_enable ();
_delay_ms (1);
lcd_enable ();
_delay_ms (1);
// 4 Bit Modus aktivieren
LCD_PORT &= 0xF0;
LCD_PORT |= 0x02;
lcd_enable ();
_delay_ms (1);
// 4Bit / 2 Zeilen / 5x7
lcd_command (0x28);
// Display ein / Cursor aus / kein Blinken
lcd_command (0x0C);
// inkrement / kein Scrollen
lcd_command (0x06);
lcd_clear ();
}
// Sendet den Befehl zur L<>schung des Displays
void lcd_clear (void)
{
lcd_command (CLEAR_DISPLAY);
_delay_ms (5);
}
// Sendet den Befehl: Cursor Home
void lcd_home (void)
{
lcd_command (CURSOR_HOME);
_delay_ms (5);
}
// setzt den Cursor in Zeile y (1..4) Spalte x (0..15)
void set_cursor (uint8_t x, uint8_t y)
{
uint8_t tmp;
switch (y)
{
case 1: tmp=0x80+0x00+x; break; // 1. Zeile
case 2: tmp=0x80+0x40+x; break; // 2. Zeile
case 3: tmp=0x80+0x10+x; break; // 3. Zeile
case 4: tmp=0x80+0x50+x; break; // 4. Zeile
default: return; // f<>r den Fall einer falschen Zeile
}
lcd_command (tmp);
}
// Schreibt einen String auf das LCD
void lcd_string (char *data)
{
while (*data)
{
lcd_data (*data);
data++;
}
}

39
lcd-routines.h Normal file
View File

@@ -0,0 +1,39 @@
// Ansteuerung eines HD44780 kompatiblen LCD im 4-Bit-Interfacemodus
// http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial/LCD-Ansteuerung
//
void lcd_data (unsigned char temp1);
void lcd_string (char *data);
void lcd_command (unsigned char temp1);
void lcd_enable (void);
void lcd_init (void);
void lcd_home (void);
void lcd_clear (void);
void set_cursor (uint8_t x, uint8_t y);
// Hier die verwendete Taktfrequenz in Hz eintragen, wichtig!
#define F_CPU 16000000
//
// LCD Befehle
//
#define CLEAR_DISPLAY 0x01
#define CURSOR_HOME 0x02
//
// Pinbelegung für das LCD, an verwendete Pins anpassen
#ifndef LCD_PORT
#define LCD_PORT PORTC
#endif
#ifndef LCD_DDR
#define LCD_DDR DDRC
#endif
#ifndef LCD_RW
#define LCD_RW PC4
#endif
#ifndef LCD_RS
#define LCD_RS PC5
#endif
#ifndef LCD_EN
#define LCD_EN PC6
#endif
// DB4 bis DB7 des LCD sind mit PC0 bis PC3 des AVR verbunden

1
screwer.aps Normal file
View File

@@ -0,0 +1 @@
<AVRStudio><MANAGEMENT><ProjectName>CSAMPLE</ProjectName><Created>21-Feb-2010 12:55:22</Created><LastEdit>02-May-2010 07:21:22</LastEdit><ICON>241</ICON><ProjectType>0</ProjectType><Created>21-Feb-2010 12:55:22</Created><Version>4</Version><Build>4, 18, 0, 685</Build><ProjectTypeName>AVR GCC</ProjectTypeName></MANAGEMENT><CODE_CREATION><ObjectFile>default\screwer.elf</ObjectFile><EntryFile></EntryFile><SaveFolder>E:\AVR\screwer\</SaveFolder></CODE_CREATION><DEBUG_TARGET><CURRENT_TARGET>AVR Simulator</CURRENT_TARGET><CURRENT_PART>AT90S8515.xml</CURRENT_PART><BREAKPOINTS></BREAKPOINTS><IO_EXPAND><HIDE>false</HIDE></IO_EXPAND><REGISTERNAMES><Register>R00</Register><Register>R01</Register><Register>R02</Register><Register>R03</Register><Register>R04</Register><Register>R05</Register><Register>R06</Register><Register>R07</Register><Register>R08</Register><Register>R09</Register><Register>R10</Register><Register>R11</Register><Register>R12</Register><Register>R13</Register><Register>R14</Register><Register>R15</Register><Register>R16</Register><Register>R17</Register><Register>R18</Register><Register>R19</Register><Register>R20</Register><Register>R21</Register><Register>R22</Register><Register>R23</Register><Register>R24</Register><Register>R25</Register><Register>R26</Register><Register>R27</Register><Register>R28</Register><Register>R29</Register><Register>R30</Register><Register>R31</Register></REGISTERNAMES><COM>Auto</COM><COMType>0</COMType><WATCHNUM>0</WATCHNUM><WATCHNAMES><Pane0></Pane0><Pane1></Pane1><Pane2></Pane2><Pane3></Pane3></WATCHNAMES><BreakOnTrcaeFull>0</BreakOnTrcaeFull></DEBUG_TARGET><Debugger><modules><module></module></modules><Triggers></Triggers></Debugger><AVRGCCPLUGIN><FILES><SOURCEFILE>lcd-routines.c</SOURCEFILE><SOURCEFILE>floating_avg.c</SOURCEFILE><SOURCEFILE>screwer.c</SOURCEFILE><HEADERFILE>lcd-routines.h</HEADERFILE><HEADERFILE>floating_avg.h</HEADERFILE></FILES><CONFIGS><CONFIG><NAME>default</NAME><USESEXTERNALMAKEFILE>NO</USESEXTERNALMAKEFILE><EXTERNALMAKEFILE></EXTERNALMAKEFILE><PART>atmega8535</PART><HEX>1</HEX><LIST>1</LIST><MAP>1</MAP><OUTPUTFILENAME>screwer.elf</OUTPUTFILENAME><OUTPUTDIR>default\</OUTPUTDIR><ISDIRTY>1</ISDIRTY><OPTIONS><OPTION><FILE>floating_avg.c</FILE><OPTIONLIST></OPTIONLIST></OPTION><OPTION><FILE>lcd-routines.c</FILE><OPTIONLIST></OPTIONLIST></OPTION><OPTION><FILE>screwer.c</FILE><OPTIONLIST></OPTIONLIST></OPTION></OPTIONS><INCDIRS/><LIBDIRS/><LIBS><LIB>libprintf_flt.a</LIB><LIB>libm.a</LIB></LIBS><LINKOBJECTS/><OPTIONSFORALL>-Wall -gdwarf-2 -std=gnu99 -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums</OPTIONSFORALL><LINKEROPTIONS>-Wl,-u,vfprintf</LINKEROPTIONS><SEGMENTS/></CONFIG></CONFIGS><LASTCONFIG>default</LASTCONFIG><USES_WINAVR>1</USES_WINAVR><GCC_LOC>C:\Programme\WinAVR-20100110\bin\avr-gcc.exe</GCC_LOC><MAKE_LOC>C:\Programme\WinAVR-20100110\utils\bin\make.exe</MAKE_LOC></AVRGCCPLUGIN><IOView><usergroups/><sort sorted="0" column="0" ordername="0" orderaddress="0" ordergroup="0"/></IOView><Files><File00000><FileId>00000</FileId><FileName>screwer.c</FileName><Status>1</Status></File00000><File00001><FileId>00001</FileId><FileName>floating_avg.h</FileName><Status>1</Status></File00001></Files><Events><Bookmarks></Bookmarks></Events><Trace><Filters></Filters></Trace></AVRStudio>

1
screwer.aws Normal file
View File

@@ -0,0 +1 @@
<AVRWorkspace><IOSettings><CurrentRegisters/></IOSettings><part name="AT90S8515"/><Files><File00000 Name="E:\AVR\screwer\screwer.c" Position="613 71 1437 658" LineCol="131 27" State="Maximized"/><File00001 Name="E:\AVR\screwer\floating_avg.h" Position="749 226 1389 610" LineCol="22 25" State="Maximized"/></Files></AVRWorkspace>

266
screwer.c Normal file
View File

@@ -0,0 +1,266 @@
/*********************************************
Blink-Schaltung
Compiler : winavr
Chip type : ATtiny2313
nst, 07.11.2005
*********************************************/
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
#include "lcd-routines.h"
#include "floating_avg.h"
//Constants
#define ADC_CURRENT 0
#define ADC_SETPOINT_SPEED 2
#define ADC_SETPOINT_TORQUE 1
//LCD Settings
#define LCD_PORT PORTC
#define LCD_DDR DDRC
#define LCD_RS PC5
#define LCD_EN PC6
//Devel
//#define CURRENT_RAW
//Prototypes
void pwm_init (void);
void tc0_init (void);
uint16_t ReadADC (uint8_t mux);
//global Vars
volatile uint16_t uiSpeedDelay;
//ISR Timer 0 - Counter for smooth start
ISR (TIMER0_OVF_vect)
{
if (uiSpeedDelay > 0)
{
uiSpeedDelay --;
}
}
//ISR Timer 1 - measure current
ISR (TIMER1_OVF_vect)
{
}
int main (void)
{
char sBuffer [20];
char sState [3];
unsigned char bTorqueReached = 0;
uint16_t uiCurrent, uiSetpointSpeed;
double fTorque, fSetpointTorque;
uint16_t uiCurrentZero = 100;
const double fCurrentStep = 0.03699;
const double fTorqueConstant = 0.630; //MN/A
double fCurrTorqueConst = fCurrentStep * fTorqueConstant;
const double fTorqueSetpointStep = 0.009885;
//Portsetup
//LCD on Port C !!!
lcd_init ();
DDRB = 0x00; // Set Port Read
PORTB = 0xff; //Activate Pullups
//Lock Low Side of H-Bride !!!!
PORTD = (1 << PD6) | (1 << PD7);
DDRD = (1 << PD4) | (1 << PD5) | (1 << PD6) | (1 << PD7) ; //Set PBD5 (OC1A) as Write
//Init PWM
pwm_init ();
//Set Timer 0 and Enable Interrupts
sei ();
tc0_init ();
// Datenstruktur anlegen:
tFloatAvgFilter FilterCurrent;
// initialisieren und mit aktuellem wert fuellen
uiCurrentZero = ReadADC (ADC_CURRENT);
InitFloatAvg (&FilterCurrent, uiCurrentZero);
//Compare
OCR1A = 0x0;
OCR1B = 0x0;
while (1)
{
//Read Analog values
//Read Current Vallue fom IC
uiCurrent = ReadADC (ADC_CURRENT);
if (((PIND & (1 << PD1)) == 0) && ((PIND & (1 << PD2)) == 0))
{
//Motor stopped so recalibrate
uiCurrentZero = uiCurrent;
//Get potis
uiSetpointSpeed = ReadADC (ADC_SETPOINT_SPEED);
fSetpointTorque = ReadADC (ADC_SETPOINT_TORQUE) * fTorqueSetpointStep;
if (fSetpointTorque < 0.5)
fSetpointTorque = 0.5;
}
uiCurrent -= uiCurrentZero;
//Floating Average
AddToFloatAvg (&FilterCurrent, uiCurrent);
uiCurrent = GetOutputValue (&FilterCurrent);
fTorque = (double)(uiCurrent) * fCurrTorqueConst;
//Start Motor left
if ((PIND & (1 << PD1)) && !bTorqueReached)
{
OCR1B = 0;
PORTD |= (1 << PD7);
PORTD &= ~(1 << PD6);
////PORTD |= (1 << PD5);
////PORTD &= ~(1 << PD4);
OCR1A = (uiSetpointSpeed - uiSpeedDelay) >> 2; //TOP = 0xff
// strcpy (sState, "Li");
}
//Start Motor right
else if ((PIND & (1 << PD2)) && !bTorqueReached)
{
OCR1A = 0;
PORTD |= (1 << PD6);
PORTD &= ~(1 << PD7);
//PORTD |= (1 << PD4);
//PORTD &= ~(1 << PD5);
OCR1B = (uiSetpointSpeed - uiSpeedDelay) >> 2; //TOP = 0xff
// strcpy (sState, "Re");
}
else if (((PIND & (1 << PD1)) == 0) && ((PIND & (1 << PD2)) == 0))
{
//Stop - no operation
OCR1A = 0;
OCR1B = 0;
//smooth stop
PORTD |= (1 << PD6) | (1 << PD7);
uiSpeedDelay = uiSetpointSpeed;
bTorqueReached = 0;
strcpy (sState, "St");
}
if ((fTorque > fSetpointTorque) && !uiSpeedDelay)
{
//Torque Stop after start ramp
OCR1A = 0x00;
OCR1B = 0x00;
//Fast Stop
PORTD |= (1 << PD6) | (1 << PD7);
//PORTD &= ~(1 << PD6);
//PORTD &= ~(1 << PD7);
bTorqueReached = 1;
strcpy (sState, "ST");
}
set_cursor (0, 1);
sprintf (sBuffer, "v=%d%% M=%04.2fNm", (uiSetpointSpeed / 10), fSetpointTorque);
lcd_string (sBuffer);
set_cursor (0, 2);
#ifdef CURRENT_RAW
sprintf (sBuffer, "%s I=%dA", sState, (uiCurrent + uiCurrentZero));
#else
//sprintf (sBuffer, "%s I=%8.2fA", sState, );
sprintf (sBuffer, "%s M=%04.2fNm", sState, (fTorque));
#endif
lcd_string (sBuffer);
}
return 1;
}
/*==========================================*/
void pwm_init (void)
{
// Set timer 1
// OC1A/OC1B clear on Match, Set on Top
// 8 bit resolution , Phase Correct PWM
TCCR1A = (1 << COM1A1) | (0 << COM1A0) | \
(1 << COM1B1) | (0 << COM1B1) | \
(0 << WGM13) | (0 << WGM12) | (0 << WGM11) | (1 << WGM10);
// Pre divisor of Timer 1
TCCR1B = (0 << CS12) | (0 << CS11) | (1 << CS10);
//Enable overflow interrupt
//TIMSK |= (1 << TOIE1);
//Set TOP value
ICR1 = 0xFF;
}
/*==========================================*/
void tc0_init (void)
{
// Set timer 0
// normal operation
TCCR0 = (0 << WGM01) | (0 << WGM00) | \
(0 << CS02) | (1 << CS01) | (1 << CS00);
//Enable overflow interrupt
TIMSK |= (1 << TOIE0);
}
/*==========================================*/
uint16_t ReadADC (uint8_t mux)
{
uint8_t i;
uint16_t result;
//Seclect Channel
ADMUX = mux;
//set Reference Voltage to external
ADMUX |= (0 << REFS1) | (0 << REFS0);
//Prescaler 50kHz < CLK / Prescaler < 200 kHz !!!
//also enaable ADC
ADCSRA = (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
//1st Dummy Readout
ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
while ( ADCSRA & (1 << ADSC))
{//wait for convertion
}
result = ADCW;
result = 0;
for (i = 0; i < 4; i ++)
{
ADCSRA |= (1 << ADSC);// eine Wandlung "single conversion"
while (ADCSRA & (1 << ADSC))
{//wait for convertion
}
result += ADCW;
}
ADCSRA &= ~(1 << ADEN);
return (result >> 2);
}