darkchris90
18.09.2012, 14:55
Hallo,
bin jetzt ganz neu hier und schon eine ganze Weile einen Hexapod am bauen.
Anfangs hat auch alles funktioniert. Ich steuer ihn mit einem AtMega16 und habe 18 Servomotoren angeschlossen. Jedoch gab es irgendwann Probleme mit den Signalen. Ich habe jedes Signal mal mit nem Osziloskop geprüft und jedesmal an genau der selben Stelle eines Servos zuckt das Signal wild hin und her und auch die Servos zucken dann.
Ich benutze für die seitlichen Gelenke und die unteren Beingelenke Modelcraft RS-2 und für die oberen Beingelenke towerpro MG 995. Einzeln mit einem Servotester funktionieren alle einwandfrei.
Ich habe das Programm für die Servosteuerung von einem Beispiel welches ich im Internet gefunden habe, abgeleitet, aber auch kommerzielle Servosteuersoftware ausprobiert. Überall tritt der selbe Fehler auf. Das kommerzielle Programm hies webbotlib.
Zudem läuft der Mega16 mit einem 16MHz Quarz.
Nun weiß ich nicht woran das liegt. Ist es irgendein Überlauf, der genau an der Stelle entsteht und das ganze asynchron laufen lässt? Ein Programmfehler? Ein möglicher Hardwarefehler?
Als Datei noch der Schaltplan des Roboters.
Das Problem ist leider dringend, da meine Bachelorarbeit davon abhängt.
Vielen Dank schonmal und ich hoffe ich habe nichts vergessen zu erwähnen.
Das Programm:
/*
Eine 8-kanalige PWM mit intelligentem Lösungsansatz
ATmega16 @ 16 MHz
*/
#define BAUD 56000UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
// Defines an den Controller und die Anwendung anpassen
#define F_CPU 16000000L // Systemtakt in Hz
#define F_PWM 500L // PWM-Frequenz in Hz
#define PWM_PRESCALER 8 // Vorteiler für den Timer
#define PWM_STEPS 256 // PWM-Schritte pro Zyklus(1..256)
#define PWM_PORT PORTD // Port für PWM
#define PWM_DDR DDRD // Datenrichtungsregister für PWM
#define PWM_PORT_2 PORTC // Port für PWM
#define PWM_DDR_2 DDRC // Datenrichtungsregister für PWM
#define PWM_PORT_3 PORTA // Port für PWM
#define PWM_DDR_3 DDRA // Datenrichtungsregister für PWM
#define PWM_CHANNELS 20 // Anzahl der PWM-Kanäle
// ab hier nichts ändern, wird alles berechnet
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
//#define T_PWM 1 //TEST
#if ((T_PWM*PWM_PRESCALER)<(111+5))
#error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
#endif
#if ((T_PWM*PWM_STEPS)>65535)
#error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.
#endif
// includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// globale Variablen
uint32_t pwm_timing[PWM_CHANNELS+1]; // Zeitdifferenzen der PWM Werte
uint32_t pwm_timing_tmp[PWM_CHANNELS+1];
uint32_t pwm_mask[PWM_CHANNELS+1]; // Bitmaske für PWM Bits, welche gelöscht werden sollen
uint32_t pwm_mask_tmp[PWM_CHANNELS+1]; // ändern uint16_t oder uint32_t für mehr Kanäle
uint8_t pwm_setting[PWM_CHANNELS]; // Einstellungen für die einzelnen PWM-Kanäle
uint8_t pwm_setting_tmp[PWM_CHANNELS+1]; // Einstellungen der PWM Werte, sortiert
// ändern auf uint16_t für mehr als 8 Bit Auflösung
volatile uint8_t pwm_cnt_max=1; // Zählergrenze, Initialisierung mit 1 ist wichtig!
volatile uint8_t pwm_sync; // Update jetzt möglich
char s[4];
char buffer[10];
volatile uint8_t uart_str_count=0;
volatile uint8_t servo=0;
volatile uint8_t uart_str_complete = 0;
// Pointer für wechselseitigen Datenzugriff
uint32_t *isr_ptr_time = pwm_timing;
uint32_t *main_ptr_time = pwm_timing_tmp;
uint32_t *isr_ptr_mask = pwm_mask; // Bitmasken fuer PWM-Kanäle
uint32_t *main_ptr_mask = pwm_mask_tmp; // ändern uint16_t oder uint32_t für mehr Kanäle
// Zeiger austauschen
// das muss in einem Unterprogramm erfolgen,
// um eine Zwischenspeicherung durch den Compiler zu verhindern
void geradeausGehen(uint8_t * pos,uint8_t tempo);
void aufAb(uint8_t *pos,uint8_t tempo);
void tausche_zeiger(void) {
uint32_t *tmp_ptr16;
uint32_t *tmp_ptr8; // ändern uint16_t oder uint32_t für mehr Kanäle
tmp_ptr16 = isr_ptr_time;
isr_ptr_time = main_ptr_time;
main_ptr_time = tmp_ptr16;
tmp_ptr8 = isr_ptr_mask;
isr_ptr_mask = main_ptr_mask;
main_ptr_mask = tmp_ptr8;
}
// PWM Update, berechnet aus den PWM Einstellungen
// die neuen Werte für die Interruptroutine
void pwm_update(void) {
uint8_t i, j, k;
uint32_t m1, m2, tmp_mask; // ändern uint16_t oder uint32_t für mehr Kanäle
uint8_t min, tmp_set; // ändern auf uint16_t für mehr als 8 Bit Auflösung
// PWM Maske für Start berechnen
// gleichzeitig die Bitmasken generieren und PWM Werte kopieren
m1 = 1;
m2 = 0;
for(i=1; i<=(PWM_CHANNELS); i++) {
main_ptr_mask[i]=~m1; // Maske zum Löschen der PWM Ausgänge
pwm_setting_tmp[i] = pwm_setting[i-1];
if (pwm_setting_tmp[i]!=0) m2 |= m1; // Maske zum setzen der IOs am PWM Start
m1 <<= 1;
}
main_ptr_mask[0]=m2; // PWM Start Daten
// PWM settings sortieren; Einfügesortieren
for(i=1; i<=PWM_CHANNELS; i++) {
min=PWM_STEPS-1;
k=i;
for(j=i; j<=PWM_CHANNELS; j++) {
if (pwm_setting_tmp[j]<min) {
k=j; // Index und PWM-setting merken
min = pwm_setting_tmp[j];
}
}
if (k!=i) {
// ermitteltes Minimum mit aktueller Sortiertstelle tauschen
tmp_set = pwm_setting_tmp[k];
pwm_setting_tmp[k] = pwm_setting_tmp[i];
pwm_setting_tmp[i] = tmp_set;
tmp_mask = main_ptr_mask[k];
main_ptr_mask[k] = main_ptr_mask[i];
main_ptr_mask[i] = tmp_mask;
}
}
// Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
k=PWM_CHANNELS; // PWM_CHANNELS Datensätze
i=1; // Startindex
while(k>i) {
while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0)) && (k>i) ) {
// aufeinanderfolgende Werte sind gleich und können vereinigt werden
// oder PWM Wert ist Null
if (pwm_setting_tmp[i]!=0)
main_ptr_mask[i+1] &= main_ptr_mask[i]; // Masken vereinigen
// Datensatz entfernen,
// Nachfolger alle eine Stufe hochschieben
for(j=i; j<k; j++) {
pwm_setting_tmp[j] = pwm_setting_tmp[j+1];
main_ptr_mask[j] = main_ptr_mask[j+1];
}
k--;
}
i++;
}
// letzten Datensatz extra behandeln
// Vergleich mit dem Nachfolger nicht möglich, nur löschen
// gilt nur im Sonderfall, wenn alle Kanäle 0 sind
if (pwm_setting_tmp[i]==0) k--;
// Zeitdifferenzen berechnen
if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind
main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2;
main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2;
k=1;
}
else {
i=k;
main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]);
tmp_set=pwm_setting_tmp[i];
i--;
for (; i>0; i--) {
main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]);
tmp_set=pwm_setting_tmp[i];
}
main_ptr_time[0]=1000+(uint16_t)T_PWM*tmp_set;
}
// auf Sync warten
pwm_sync=0; // Sync wird im Interrupt gesetzt
while(pwm_sync==0);
// Zeiger tauschen
cli();
tausche_zeiger();
pwm_cnt_max = k;
sei();
}
// Timer 1 Output COMPARE A Interrupt
ISR(TIMER1_COMPA_vect) {
static uint32_t pwm_cnt; // ändern auf uint16_t für mehr als 8 Bit Auflösung
uint32_t tmp; // ändern uint16_t oder uint32_t für mehr Kanäle
OCR1A += isr_ptr_time[pwm_cnt];
tmp = isr_ptr_mask[pwm_cnt];
if (pwm_cnt == 0) {
PWM_PORT = tmp; // Ports setzen zu Begin der PWM
PWM_PORT_2 = tmp>>8; // zusätzliche PWM-Ports hier setzen
PWM_PORT_3 = tmp>>16;
pwm_cnt++;
}
else {
PWM_PORT &= tmp; // Ports löschen
PWM_PORT_2 &= tmp>>8; // zusätzliche PWM-Ports hier setzen
PWM_PORT_3 &= tmp>>16;
if (pwm_cnt == pwm_cnt_max) {
OCR1A+=36000;
pwm_sync = 1; // Update jetzt möglich
pwm_cnt = 0;
}
else pwm_cnt++;
}
}
void uart_init(void)
{
UBRRH = UBRR_VAL>>8;
UBRRL = UBRR_VAL;
/* evtl. verkuerzt falls Register aufeinanderfolgen (vgl. Datenblatt)
UBRR = UBRR_VALUE;
*/
UCSRB = (1 << RXEN) | (1 << TXEN) |(1<<RXCIE);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
}
void adc_init(void){
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
ADMUX=0 | (0<<REFS1) | (1<<REFS0);
}
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{
}
UDR = c; /* sende Zeichen */
return 0;
}
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) // warten bis Zeichen verfuegbar
;
return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben
}
void uart_puts (char *st)
{
while (*st)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*st);
st++;
}
//uart_putc(' ');
}
int main(void) {
//uart_init();
//adc_init();
// PWM Port einstellen
PWM_DDR = 0xFF; // Port als Ausgang
// zusätzliche PWM-Ports hier setzen
PWM_DDR_2=0xFF;
PWM_DDR_3=0xFF;
// Timer 1 OCRA1, als variablen Timer nutzen
TCCR1B = 2; // Timer läuft mit Prescaler 8
TIMSK |= (1<<OCIE1A); // Interrupt freischalten
sei(); // Interrupts global einschalten
/************************************************** ****************/
// nur zum testen, in der Anwendung entfernen
// Test values
volatile uint8_t tmp;
// Bein 1
// 2 mitte bein 80 -200 links
// 3 mitte fuß 50 -130 links
// 4 hinten gelenk 70 - 120 links
// Bein 2
// 5 hinten fuß 50 -130 links
// 6 hinten bein 200 -80 links
// 7 mitte gelenk 70 -120 links
// Bein 3
// 8 vorne bein 80 -200 links
// 9 vorne fuß 50 -130 links
// 10 vorne gelenk 70 - 120 links
// Bein 4
// 11
// 12
// 13
// Bein 5
// 14
// 15
// 16
// Bein 6
// 17
// 18
// 19
// 0 1 /2 3 4 / 5 6 7 / 8 9 10 /11 12 13 /14 15 16 /17 18 19
const uint8_t t1[20]={100, 100, 30, 80, 140, 90, 30, 120,30, 90,120,230,180,120,230,180,120,180,230,130};
const uint8_t t2[20]={60, 60, 120, 100, 140, 120, 110, 120,110,120,120,110,170,120,120,160,100,150,120,12 0};
const uint8_t t3[8]={27, 40, 3, 17, 3, 99, 3, 0};
const uint8_t t4[8]={0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t t5[8]={9, 1, 1, 1, 1, 1, 1, 1};
const uint8_t t6[8]={33, 33, 33, 33, 33, 33, 33, 33};
const uint8_t t7[8]={0, 0, 0, 0, 0, 0, 0, 88};
// Messung der Interruptdauer
tmp =1;
tmp =2;
tmp =3;
// Debug
memcpy(pwm_setting, t2, 20);
pwm_update();
/************************************************** ****************/
/*
uint8_t tmp1[10];
memcpy(tmp1,t1,10);
while(1){
tmp1[6]-=1;
tmp1[4]-=1;
if(tmp1[6]<=80) tmp1[6]=130;
if(tmp1[4]<=70) tmp1[4]=120;
memcpy(pwm_setting, tmp1, 10);
pwm_update();
_delay_ms(50);
};
*/
uint8_t pos[20];
memcpy(pos,t2,20);
//startPos();
while(1)
{
//
aufAb(pos,20);
//geradeausGehen(pos,20);
}
while(1){
}
return 0;
}
ISR(USART_RXC_vect)
{
uart_putc(UDR);
if (servo==1)servoSteuer();
else{
unsigned char nextChar;
// Daten aus dem Puffer lesen
nextChar = UDR;
if (nextChar=='s'){
servo=1;
}else{
if( uart_str_complete == 0 ) {
// Daten werden erst in uart_string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
if( nextChar != '\n' &&
nextChar != '\r' &&
uart_str_count < 9 ) {
buffer[uart_str_count] = nextChar;
uart_str_count++;
}
else {
buffer[uart_str_count] = '\0';
uart_str_count=0;
uart_str_complete=1;
}
}
}
}
}
void servoSteuer(void){
static uint8_t servo_count;
uint8_t nextChar;
// Daten aus dem Puffer lesen
nextChar = UDR;
uart_putc(nextChar);
if(nextChar !='s'){
if(
nextChar != '\r'){
memcpy(pwm_setting[3],nextChar,8);
servo_count++;
}else{
servo_count=0;
servo=0;
uart_puts("finish");
pwm_update();
}
}
}
void geradeausGehen(uint8_t* pos,uint8_t tempo)
{
pos[8]=120;
pos[6]=120;
pos[14]=120;
pos[2]=140;
pos[18]=100;
pos[11]=100;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
while(pos[10] <= 140){
pos[4]++;
pos[7]--;
pos[10]++;
pos[19]--;
pos[16]++;
pos[13]++;
if((pos[10]-80)%4==0 && (pos[10]-80)<=35){
pos[5]--;
pos[9]--;
pos[15]++;
}
else if((pos[10]-80)%4==0)
{
pos[5]++;
pos[9]++;
pos[15]--;
}
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
//Beine
pos[2]=120;
pos[18]=120;
pos[11]=120;
//Füße
pos[9]=100;
pos[5]=100;
pos[15]=180;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
pos[8]=140;
pos[6]=140;
pos[14]=100;
//Füße
pos[17]=170;
pos[12]=190;
pos[3]=80;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
while(pos[16] >= 80){
pos[4]--;
pos[7]++;
pos[10]--;
pos[19]++;
pos[16]--;
pos[13]--;
if((pos[16]-50)%4==0 && (pos[16]-50)<=75){
pos[17]--;
pos[12]--;
pos[3]++;
}
else if((pos[16]-50)%4==0)
{
pos[17]++;
pos[12]++;
pos[3]--;
}
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
}
void startPos(void){
// 0 1 /2 3 4 /5 6 7 / 8 9 10 /11 12 13 /14 15 16/ 17 18 19
uint8_t startPos[20]={60, 60, 150, 100, 140, 120,140, 120,140,120,120,80,170,120,90,150,100,150,90,120};
memcpy(pwm_setting, startPos, 20);
pwm_update();
_delay_ms(1000);
for(int i=0; i<15;i++){
startPos[2]-=2;
startPos[6]-=2;
startPos[8]-=2;
startPos[9]--;
startPos[5]--;
startPos[3]--;
startPos[18]+=2;
startPos[11]+=2;
startPos[14]+=2;
startPos[17]++;
startPos[12]++;
startPos[15]++;
memcpy(pwm_setting, startPos, 20);
pwm_update();
_delay_ms(50);
}
const uint8_t endStartPos[20]={100, 100,30, 80, 140, 90, 30, 120,30,90,120,230,180,120,230,180,120,180,230,130} ;
//aufAb(endStartPos,50);
}
void aufAb(uint8_t *pos,uint8_t tempo){
uint8_t i=0;
while (i<80){
i++;
pos[8]--;
pos[6]--;
pos[2]--;
pos[18]++;
pos[11]++;
pos[14]++;
pos[9]++;
pos[5]++;
pos[3]++;
pos[17]--;
pos[12]--;
pos[15]--;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
while (i>0){
i--;
pos[8]++;
pos[6]++;
pos[2]++;
pos[18]--;
pos[11]--;
pos[14]--;
pos[9]--;
pos[5]--;
pos[3]--;
pos[17]++;
pos[12]++;
pos[15]++;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
}
bin jetzt ganz neu hier und schon eine ganze Weile einen Hexapod am bauen.
Anfangs hat auch alles funktioniert. Ich steuer ihn mit einem AtMega16 und habe 18 Servomotoren angeschlossen. Jedoch gab es irgendwann Probleme mit den Signalen. Ich habe jedes Signal mal mit nem Osziloskop geprüft und jedesmal an genau der selben Stelle eines Servos zuckt das Signal wild hin und her und auch die Servos zucken dann.
Ich benutze für die seitlichen Gelenke und die unteren Beingelenke Modelcraft RS-2 und für die oberen Beingelenke towerpro MG 995. Einzeln mit einem Servotester funktionieren alle einwandfrei.
Ich habe das Programm für die Servosteuerung von einem Beispiel welches ich im Internet gefunden habe, abgeleitet, aber auch kommerzielle Servosteuersoftware ausprobiert. Überall tritt der selbe Fehler auf. Das kommerzielle Programm hies webbotlib.
Zudem läuft der Mega16 mit einem 16MHz Quarz.
Nun weiß ich nicht woran das liegt. Ist es irgendein Überlauf, der genau an der Stelle entsteht und das ganze asynchron laufen lässt? Ein Programmfehler? Ein möglicher Hardwarefehler?
Als Datei noch der Schaltplan des Roboters.
Das Problem ist leider dringend, da meine Bachelorarbeit davon abhängt.
Vielen Dank schonmal und ich hoffe ich habe nichts vergessen zu erwähnen.
Das Programm:
/*
Eine 8-kanalige PWM mit intelligentem Lösungsansatz
ATmega16 @ 16 MHz
*/
#define BAUD 56000UL
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)
// Defines an den Controller und die Anwendung anpassen
#define F_CPU 16000000L // Systemtakt in Hz
#define F_PWM 500L // PWM-Frequenz in Hz
#define PWM_PRESCALER 8 // Vorteiler für den Timer
#define PWM_STEPS 256 // PWM-Schritte pro Zyklus(1..256)
#define PWM_PORT PORTD // Port für PWM
#define PWM_DDR DDRD // Datenrichtungsregister für PWM
#define PWM_PORT_2 PORTC // Port für PWM
#define PWM_DDR_2 DDRC // Datenrichtungsregister für PWM
#define PWM_PORT_3 PORTA // Port für PWM
#define PWM_DDR_3 DDRA // Datenrichtungsregister für PWM
#define PWM_CHANNELS 20 // Anzahl der PWM-Kanäle
// ab hier nichts ändern, wird alles berechnet
#define T_PWM (F_CPU/(PWM_PRESCALER*F_PWM*PWM_STEPS)) // Systemtakte pro PWM-Takt
//#define T_PWM 1 //TEST
#if ((T_PWM*PWM_PRESCALER)<(111+5))
#error T_PWM zu klein, F_CPU muss vergrössert werden oder F_PWM oder PWM_STEPS verkleinert werden
#endif
#if ((T_PWM*PWM_STEPS)>65535)
#error Periodendauer der PWM zu gross! F_PWM oder PWM_PRESCALER erhöhen.
#endif
// includes
#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
// globale Variablen
uint32_t pwm_timing[PWM_CHANNELS+1]; // Zeitdifferenzen der PWM Werte
uint32_t pwm_timing_tmp[PWM_CHANNELS+1];
uint32_t pwm_mask[PWM_CHANNELS+1]; // Bitmaske für PWM Bits, welche gelöscht werden sollen
uint32_t pwm_mask_tmp[PWM_CHANNELS+1]; // ändern uint16_t oder uint32_t für mehr Kanäle
uint8_t pwm_setting[PWM_CHANNELS]; // Einstellungen für die einzelnen PWM-Kanäle
uint8_t pwm_setting_tmp[PWM_CHANNELS+1]; // Einstellungen der PWM Werte, sortiert
// ändern auf uint16_t für mehr als 8 Bit Auflösung
volatile uint8_t pwm_cnt_max=1; // Zählergrenze, Initialisierung mit 1 ist wichtig!
volatile uint8_t pwm_sync; // Update jetzt möglich
char s[4];
char buffer[10];
volatile uint8_t uart_str_count=0;
volatile uint8_t servo=0;
volatile uint8_t uart_str_complete = 0;
// Pointer für wechselseitigen Datenzugriff
uint32_t *isr_ptr_time = pwm_timing;
uint32_t *main_ptr_time = pwm_timing_tmp;
uint32_t *isr_ptr_mask = pwm_mask; // Bitmasken fuer PWM-Kanäle
uint32_t *main_ptr_mask = pwm_mask_tmp; // ändern uint16_t oder uint32_t für mehr Kanäle
// Zeiger austauschen
// das muss in einem Unterprogramm erfolgen,
// um eine Zwischenspeicherung durch den Compiler zu verhindern
void geradeausGehen(uint8_t * pos,uint8_t tempo);
void aufAb(uint8_t *pos,uint8_t tempo);
void tausche_zeiger(void) {
uint32_t *tmp_ptr16;
uint32_t *tmp_ptr8; // ändern uint16_t oder uint32_t für mehr Kanäle
tmp_ptr16 = isr_ptr_time;
isr_ptr_time = main_ptr_time;
main_ptr_time = tmp_ptr16;
tmp_ptr8 = isr_ptr_mask;
isr_ptr_mask = main_ptr_mask;
main_ptr_mask = tmp_ptr8;
}
// PWM Update, berechnet aus den PWM Einstellungen
// die neuen Werte für die Interruptroutine
void pwm_update(void) {
uint8_t i, j, k;
uint32_t m1, m2, tmp_mask; // ändern uint16_t oder uint32_t für mehr Kanäle
uint8_t min, tmp_set; // ändern auf uint16_t für mehr als 8 Bit Auflösung
// PWM Maske für Start berechnen
// gleichzeitig die Bitmasken generieren und PWM Werte kopieren
m1 = 1;
m2 = 0;
for(i=1; i<=(PWM_CHANNELS); i++) {
main_ptr_mask[i]=~m1; // Maske zum Löschen der PWM Ausgänge
pwm_setting_tmp[i] = pwm_setting[i-1];
if (pwm_setting_tmp[i]!=0) m2 |= m1; // Maske zum setzen der IOs am PWM Start
m1 <<= 1;
}
main_ptr_mask[0]=m2; // PWM Start Daten
// PWM settings sortieren; Einfügesortieren
for(i=1; i<=PWM_CHANNELS; i++) {
min=PWM_STEPS-1;
k=i;
for(j=i; j<=PWM_CHANNELS; j++) {
if (pwm_setting_tmp[j]<min) {
k=j; // Index und PWM-setting merken
min = pwm_setting_tmp[j];
}
}
if (k!=i) {
// ermitteltes Minimum mit aktueller Sortiertstelle tauschen
tmp_set = pwm_setting_tmp[k];
pwm_setting_tmp[k] = pwm_setting_tmp[i];
pwm_setting_tmp[i] = tmp_set;
tmp_mask = main_ptr_mask[k];
main_ptr_mask[k] = main_ptr_mask[i];
main_ptr_mask[i] = tmp_mask;
}
}
// Gleiche PWM-Werte vereinigen, ebenso den PWM-Wert 0 löschen falls vorhanden
k=PWM_CHANNELS; // PWM_CHANNELS Datensätze
i=1; // Startindex
while(k>i) {
while ( ((pwm_setting_tmp[i]==pwm_setting_tmp[i+1]) || (pwm_setting_tmp[i]==0)) && (k>i) ) {
// aufeinanderfolgende Werte sind gleich und können vereinigt werden
// oder PWM Wert ist Null
if (pwm_setting_tmp[i]!=0)
main_ptr_mask[i+1] &= main_ptr_mask[i]; // Masken vereinigen
// Datensatz entfernen,
// Nachfolger alle eine Stufe hochschieben
for(j=i; j<k; j++) {
pwm_setting_tmp[j] = pwm_setting_tmp[j+1];
main_ptr_mask[j] = main_ptr_mask[j+1];
}
k--;
}
i++;
}
// letzten Datensatz extra behandeln
// Vergleich mit dem Nachfolger nicht möglich, nur löschen
// gilt nur im Sonderfall, wenn alle Kanäle 0 sind
if (pwm_setting_tmp[i]==0) k--;
// Zeitdifferenzen berechnen
if (k==0) { // Sonderfall, wenn alle Kanäle 0 sind
main_ptr_time[0]=(uint16_t)T_PWM*PWM_STEPS/2;
main_ptr_time[1]=(uint16_t)T_PWM*PWM_STEPS/2;
k=1;
}
else {
i=k;
main_ptr_time[i]=(uint16_t)T_PWM*(PWM_STEPS-pwm_setting_tmp[i]);
tmp_set=pwm_setting_tmp[i];
i--;
for (; i>0; i--) {
main_ptr_time[i]=(uint16_t)T_PWM*(tmp_set-pwm_setting_tmp[i]);
tmp_set=pwm_setting_tmp[i];
}
main_ptr_time[0]=1000+(uint16_t)T_PWM*tmp_set;
}
// auf Sync warten
pwm_sync=0; // Sync wird im Interrupt gesetzt
while(pwm_sync==0);
// Zeiger tauschen
cli();
tausche_zeiger();
pwm_cnt_max = k;
sei();
}
// Timer 1 Output COMPARE A Interrupt
ISR(TIMER1_COMPA_vect) {
static uint32_t pwm_cnt; // ändern auf uint16_t für mehr als 8 Bit Auflösung
uint32_t tmp; // ändern uint16_t oder uint32_t für mehr Kanäle
OCR1A += isr_ptr_time[pwm_cnt];
tmp = isr_ptr_mask[pwm_cnt];
if (pwm_cnt == 0) {
PWM_PORT = tmp; // Ports setzen zu Begin der PWM
PWM_PORT_2 = tmp>>8; // zusätzliche PWM-Ports hier setzen
PWM_PORT_3 = tmp>>16;
pwm_cnt++;
}
else {
PWM_PORT &= tmp; // Ports löschen
PWM_PORT_2 &= tmp>>8; // zusätzliche PWM-Ports hier setzen
PWM_PORT_3 &= tmp>>16;
if (pwm_cnt == pwm_cnt_max) {
OCR1A+=36000;
pwm_sync = 1; // Update jetzt möglich
pwm_cnt = 0;
}
else pwm_cnt++;
}
}
void uart_init(void)
{
UBRRH = UBRR_VAL>>8;
UBRRL = UBRR_VAL;
/* evtl. verkuerzt falls Register aufeinanderfolgen (vgl. Datenblatt)
UBRR = UBRR_VALUE;
*/
UCSRB = (1 << RXEN) | (1 << TXEN) |(1<<RXCIE);
UCSRC = (1 << URSEL) | (1 << UCSZ1) | (1 << UCSZ0);
}
void adc_init(void){
ADCSRA = (1<<ADEN) | (1<<ADPS2) | (1<<ADPS1);
ADMUX=0 | (0<<REFS1) | (1<<REFS0);
}
int uart_putc(unsigned char c)
{
while (!(UCSRA & (1<<UDRE))) /* warten bis Senden moeglich */
{
}
UDR = c; /* sende Zeichen */
return 0;
}
uint8_t uart_getc(void)
{
while (!(UCSRA & (1<<RXC))) // warten bis Zeichen verfuegbar
;
return UDR; // Zeichen aus UDR an Aufrufer zurueckgeben
}
void uart_puts (char *st)
{
while (*st)
{ /* so lange *s != '\0' also ungleich dem "String-Endezeichen(Terminator)" */
uart_putc(*st);
st++;
}
//uart_putc(' ');
}
int main(void) {
//uart_init();
//adc_init();
// PWM Port einstellen
PWM_DDR = 0xFF; // Port als Ausgang
// zusätzliche PWM-Ports hier setzen
PWM_DDR_2=0xFF;
PWM_DDR_3=0xFF;
// Timer 1 OCRA1, als variablen Timer nutzen
TCCR1B = 2; // Timer läuft mit Prescaler 8
TIMSK |= (1<<OCIE1A); // Interrupt freischalten
sei(); // Interrupts global einschalten
/************************************************** ****************/
// nur zum testen, in der Anwendung entfernen
// Test values
volatile uint8_t tmp;
// Bein 1
// 2 mitte bein 80 -200 links
// 3 mitte fuß 50 -130 links
// 4 hinten gelenk 70 - 120 links
// Bein 2
// 5 hinten fuß 50 -130 links
// 6 hinten bein 200 -80 links
// 7 mitte gelenk 70 -120 links
// Bein 3
// 8 vorne bein 80 -200 links
// 9 vorne fuß 50 -130 links
// 10 vorne gelenk 70 - 120 links
// Bein 4
// 11
// 12
// 13
// Bein 5
// 14
// 15
// 16
// Bein 6
// 17
// 18
// 19
// 0 1 /2 3 4 / 5 6 7 / 8 9 10 /11 12 13 /14 15 16 /17 18 19
const uint8_t t1[20]={100, 100, 30, 80, 140, 90, 30, 120,30, 90,120,230,180,120,230,180,120,180,230,130};
const uint8_t t2[20]={60, 60, 120, 100, 140, 120, 110, 120,110,120,120,110,170,120,120,160,100,150,120,12 0};
const uint8_t t3[8]={27, 40, 3, 17, 3, 99, 3, 0};
const uint8_t t4[8]={0, 0, 0, 0, 0, 0, 0, 0};
const uint8_t t5[8]={9, 1, 1, 1, 1, 1, 1, 1};
const uint8_t t6[8]={33, 33, 33, 33, 33, 33, 33, 33};
const uint8_t t7[8]={0, 0, 0, 0, 0, 0, 0, 88};
// Messung der Interruptdauer
tmp =1;
tmp =2;
tmp =3;
// Debug
memcpy(pwm_setting, t2, 20);
pwm_update();
/************************************************** ****************/
/*
uint8_t tmp1[10];
memcpy(tmp1,t1,10);
while(1){
tmp1[6]-=1;
tmp1[4]-=1;
if(tmp1[6]<=80) tmp1[6]=130;
if(tmp1[4]<=70) tmp1[4]=120;
memcpy(pwm_setting, tmp1, 10);
pwm_update();
_delay_ms(50);
};
*/
uint8_t pos[20];
memcpy(pos,t2,20);
//startPos();
while(1)
{
//
aufAb(pos,20);
//geradeausGehen(pos,20);
}
while(1){
}
return 0;
}
ISR(USART_RXC_vect)
{
uart_putc(UDR);
if (servo==1)servoSteuer();
else{
unsigned char nextChar;
// Daten aus dem Puffer lesen
nextChar = UDR;
if (nextChar=='s'){
servo=1;
}else{
if( uart_str_complete == 0 ) {
// Daten werden erst in uart_string geschrieben, wenn nicht String-Ende/max Zeichenlänge erreicht ist/string gerade verarbeitet wird
if( nextChar != '\n' &&
nextChar != '\r' &&
uart_str_count < 9 ) {
buffer[uart_str_count] = nextChar;
uart_str_count++;
}
else {
buffer[uart_str_count] = '\0';
uart_str_count=0;
uart_str_complete=1;
}
}
}
}
}
void servoSteuer(void){
static uint8_t servo_count;
uint8_t nextChar;
// Daten aus dem Puffer lesen
nextChar = UDR;
uart_putc(nextChar);
if(nextChar !='s'){
if(
nextChar != '\r'){
memcpy(pwm_setting[3],nextChar,8);
servo_count++;
}else{
servo_count=0;
servo=0;
uart_puts("finish");
pwm_update();
}
}
}
void geradeausGehen(uint8_t* pos,uint8_t tempo)
{
pos[8]=120;
pos[6]=120;
pos[14]=120;
pos[2]=140;
pos[18]=100;
pos[11]=100;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
while(pos[10] <= 140){
pos[4]++;
pos[7]--;
pos[10]++;
pos[19]--;
pos[16]++;
pos[13]++;
if((pos[10]-80)%4==0 && (pos[10]-80)<=35){
pos[5]--;
pos[9]--;
pos[15]++;
}
else if((pos[10]-80)%4==0)
{
pos[5]++;
pos[9]++;
pos[15]--;
}
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
//Beine
pos[2]=120;
pos[18]=120;
pos[11]=120;
//Füße
pos[9]=100;
pos[5]=100;
pos[15]=180;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
pos[8]=140;
pos[6]=140;
pos[14]=100;
//Füße
pos[17]=170;
pos[12]=190;
pos[3]=80;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(1000);
while(pos[16] >= 80){
pos[4]--;
pos[7]++;
pos[10]--;
pos[19]++;
pos[16]--;
pos[13]--;
if((pos[16]-50)%4==0 && (pos[16]-50)<=75){
pos[17]--;
pos[12]--;
pos[3]++;
}
else if((pos[16]-50)%4==0)
{
pos[17]++;
pos[12]++;
pos[3]--;
}
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
}
void startPos(void){
// 0 1 /2 3 4 /5 6 7 / 8 9 10 /11 12 13 /14 15 16/ 17 18 19
uint8_t startPos[20]={60, 60, 150, 100, 140, 120,140, 120,140,120,120,80,170,120,90,150,100,150,90,120};
memcpy(pwm_setting, startPos, 20);
pwm_update();
_delay_ms(1000);
for(int i=0; i<15;i++){
startPos[2]-=2;
startPos[6]-=2;
startPos[8]-=2;
startPos[9]--;
startPos[5]--;
startPos[3]--;
startPos[18]+=2;
startPos[11]+=2;
startPos[14]+=2;
startPos[17]++;
startPos[12]++;
startPos[15]++;
memcpy(pwm_setting, startPos, 20);
pwm_update();
_delay_ms(50);
}
const uint8_t endStartPos[20]={100, 100,30, 80, 140, 90, 30, 120,30,90,120,230,180,120,230,180,120,180,230,130} ;
//aufAb(endStartPos,50);
}
void aufAb(uint8_t *pos,uint8_t tempo){
uint8_t i=0;
while (i<80){
i++;
pos[8]--;
pos[6]--;
pos[2]--;
pos[18]++;
pos[11]++;
pos[14]++;
pos[9]++;
pos[5]++;
pos[3]++;
pos[17]--;
pos[12]--;
pos[15]--;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
while (i>0){
i--;
pos[8]++;
pos[6]++;
pos[2]++;
pos[18]--;
pos[11]--;
pos[14]--;
pos[9]--;
pos[5]--;
pos[3]--;
pos[17]++;
pos[12]++;
pos[15]++;
memcpy(pwm_setting, pos, 20);
pwm_update();
_delay_ms(tempo);
}
}