Zurück
(C) Christof Ermer, Regensburg
30.05.2016
4x-MultiServo
Dokumenation. +
Software.
ATM16_V1.0-2011_MultiSinus_PWM.zip
Eagle
Eagle_4xServo_HighRes.zip
//------------------------------------------------------------------------------
// Programmed by Christof Ermer
//------------------------------------------------------------------------------
/*
C:\AVR_Projekte\AA_AVR_PRJ_2016\ATM8-2x-16BitTimerMultiPWM_Portdirect - 2te_MCU
MCU2 = EXTERN CLOCK
FUSE HIGH = 0xA0
FUSE LOW = 0xDF
_MCU1 =
FUSE HIGH = 0xBF
FUSE LOW = 0xCF
TIMER 0 = TICK
TIMER 1 = 16 BIt PWM
TIMER 2 = Manage TImer 1
Processor 1 = links
#define UART_BAUD_RATE 9600
*/
//#define TICK_USED
#define MULTI_PWM_USED
//#define UART_IS_USED
//http://www.engbedded.com/fusecalc/
// Low Fuse=0xBF High Fuse= 0xCF
//alternate Low Fuse=0x9E High Fuse= 0xEF
#define AUTOR "Christof Ermer"
#define DATUM "29.04.2016"
#define UHRZEIT "12:00"
#define HARDWARE "AVR ATMega8 Board"
#define SOFTWARE "2x16Bit HighResolution PWM"
#define SHOW_BAUDRATE "19200,8,N,1"
#include <ctype.h>
#include <inttypes.h>
#include <avr\io.h>
#include <avr\pgmspace.h> // <--#include <progmem.h>
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <stdarg.h>
#include <string.h>
#include <avr\interrupt.h> // obsolete #include <avr\signal.h>
#include <avr\wdt.h>
//Produziert Fehler...
#include <util\delay.h> //_delay_loop_1 _delay_loop_2 delay_ms
#include "avr_register.h" //with Hardware assigns
#include "main.h" //witdh Hardware assigns
#include "uart.h"
#include "TxtFunc.h"
#include "debug.h"
//CONSTANT ARRAYs IN .TEXT = ROM ARREA .DATA IST SRAM !! .BSS SRAM
//const char MCA_DELIMTERSTR[] PROGMEM = { ',',0 };
volatile uint32_t gu32_Ticks; //T2 timeCounter, only NN_Counter for Keypressings
//uint8_t g16PWM_Compare = 40U;
float gf_PWM_Delay ;
//T_BAUDRATE eBaud = 57600;
uint8_t gu8Mode;
volatile uint8_t gu8Status;
// ****************************************************************
ISR( TIMER2_OVF_vect ) //oder SIGNAL--INTERRUPT(SIG_OVERFLOW2) = mit SEI am Anfang
// *******************************************************************
{ //~1µS
volatile unsigned char u8Sreg = SREG;
volatile static uint8_t u8Periode;
cli();
u8Pede++;
u8Periode %rio= 5;
if( !(u8Periode) ) // 1/5
{
INIT_PWM_DIR();
TCCR1B = 0; //STOP T1
TCCR1A = 0 ;
TCNT1=0;
SET_OC2_HIGH(); // OC1X alle HIGH
SET_PWMS_HIGH(); //PWM ALLES ON
// TCCR1A = (1<<COM1A1) | (1<<COM1B1); //Clear OC1A OC1B on compare
TIFR |= (1<<OCIE1A) | (1<<OCIE1B); // Flag weg !!!!!!!!!!!!!!!!!!!!!
TIMSK |= (1<<TOIE0) | (1<<TOIE2) | (1<<OCIE1A) | (1<<OCIE1B); //INT T2 und INT T1A
TCCR1B = (1<<CS10); // :1 NORMAL
};
SREG = u8Sreg;
};
// *******************************
ISR( TIMER1_COMPA_vect )
// *******************************
{
volatile unsigned char u8Sreg = SREG;
cli();
PWM_PORT &= ~(1<<PWM_A_16BIT_PIN);
TIMSK &= ~(1<<OCIE1A);
SREG = u8Sreg;
};
// *******************************
ISR( TIMER1_COMPB_vect )
// *******************************
{
volatile unsigned char u8Sreg = SREG;
cli();
PWM_PORT &= ~(1<<PWM_B_16BIT_PIN);
TIMSK &= ~(1<<OCIE1B);
SREG = u8Sreg;
};
//TCKcounter ! /1024 = 61/Sekunde
// ****************************************************************
//volatile SIGNAL(TIMER2_OVF_vect) //oder SIGNAL--INTERRUPT(SIG_OVERFLOW2) = mit SEI am Anfang
ISR( TIMER0_OVF_vect ) //TIMER0_COMP_vect oder SIGNAL--INTERRUPT(SIG_OVERFLOW0) = mit SEI am Anfang
// *******************************************************************
{
volatile unsigned char u8Sreg = SREG;
volatile static uint32_t u32Now;
cli();
gu32_Ticks++;
if( (gu32_Ticks - u32Now) > 61)
{
u32Now = gu32_Ticks;
gu8Status |= TICK_EVENT;
}; // Tickcounter
UART_TXRX_Check(); //IMMER VORHANDEN !! IN ALLEN LOOPS DIE ZEIT BRAUCHEN
/*
if( !(gu32_Ticks % 10) )
{
};
*/
SREG = u8Sreg;
};
//TIMER2
// *************************************
void StartTimers(void) //0.1 Seconds interrupt
//Normal MODE OC2 Disconnect Prescale 64
// *************************************
{
volatile unsigned char u8Sreg = SREG;
cli();
CLR_ENABLE();
INIT_ENABLEPIN();
INIT_PWM_DIR();
INIT_OC2DIR();
OCR1A = PWM_MITTE;
OCR1B = PWM_MITTE;
OCR2 = OCR2_MITTE;
TCNT1=0;
TCCR1A = 0;
TCCR1B = 0; // Da ist der Clock drin
// 8 Bit Timer erzeugt 244 HZ Und OC2 CLEARCOmpare
TCNT2=0;
TCCR2 = (1 << CS22) | (1 << CS21); //256
//TCCR2 = (1 << CS22) | (1 << CS21) | (1 << COM21); //256 OC2 CLEAR ON COMPARE //OC2=PB3 Toggle, NORMAL
TIFR |= (1<<TOV2);
TIMSK |= (1<<TOIE2) | (1<<TOIE0); //(1<<OCIE2); //INT T2 und INT T1A
SREG = u8Sreg;
};
// *************************************
void StartTickTimer(void) //244 INT/Sec
// *************************************
{
unsigned char sreg = SREG;
TCCR0 = (1<<CS02) | (1<<CS00); //1024
SREG = sreg; //loakaler Speicher
sei();
};
#ifdef UART_USE_ENABLED
// *******************************************************************
void CheckOrder(char *pcStrOrder) //von gcaRxStr
// *******************************************************************
{
// zerlege UART RX Str inseine Delimitrer Bestandteile
TokensRXStr( pcStrOrder ); //und lege diese in gsCmd.ucaCmd ab
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PWM3") ) )
{
OCR1A = (uint16_t)gsCmd.fCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PWM4") ) )
{
OCR1B = (uint16_t)gsCmd.fCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PON") ) )
{
SET_ENABLE();
gu8Mode |= MODE_ACTIVE;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("POFF") ) )
{
CLR_ENABLE();
gu8Mode &= ~MODE_ACTIVE;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STAT3") ) )
{
PrintULongCR(OCR1A);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("STAT4") ) )
{
PrintULongCR(OCR1B);
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("ENABLE") ) )
{
if( (uint8_t)gsCmd.fCmdVal_1)
{
SET_ENABLE();
gu8Mode |= MODE_ACTIVE;
}
else
{
CLR_ENABLE();
gu8Mode &= ~MODE_ACTIVE;
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("DD") ) )
{
gf_PWM_Delay = gsCmd.fCmdVal_1;
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("SIN") ) )
{
if( (uint8_t)gsCmd.fCmdVal_1)
{
gu8Mode |= MODUS_SINUS;
}
else
{
gu8Mode &= ~MODUS_SINUS;
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("PING2") ) )
{
Print_PStrCR( PSTR("Pong") );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("Device2") ) )
{
Print_PStrCR( PSTR("High-Resolution PWM") );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("TT2") ) )
{
PrintLongCR( gu32_Ticks );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("RR2") ) )
{
gu32_Ticks = 0; //Reset TickCounter
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("EE2") ) )
{
if( (uint8_t)gsCmd.fCmdVal_1)
{
gu8Mode |= TX_TRAFFIC_ON;
}
else
{
gu8Mode &=~ TX_TRAFFIC_ON;
};
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("??2") ) )
{
uart_puts_p( PSTR("x=1,2,3,4,PWMx,PON,POFF,Enable{0,1},DD,SIN{0,1},STAT2\r") );
uart_puts_p( PSTR("??2,Device2,TT2,EE2{0,1},RR2,BAUD2,PING2,DD\r") );
return;
};
if( !strcasecmp_P( gsCmd.ucaCmd, PSTR("BAUD2") ) )
{
uart_init( UART_BAUD_SELECT((uint16_t)gsCmd.fCmdVal_1, F_CPU) );
ResetRxBuff();
return;
};
};
#endif
// **********************************
int main(void)
// **********************************
{
cli();//The global interrupt flag is maintained in the I bit of the status register (SREG).
//INIT HARDWARE
//USing of PORTOUTS 1=OUT, 0=IN
DDRB = 0x00;
DDRC = 0x00;
DDRD = 0x02; //TX
ADCSR |= (1<<ADC); //ADC OFF
INIT_ENABLEPIN();
INIT_OC2DIR(); //| (1<<OC1A) | (1<<OC1B)
INIT_PWM_DIR();
//SFIOR = (1<<PUD); //Pullup Disable
//Pointer and Strings init
wdt_enable(WDTO_1S); //WDTO_500MS
wdt_reset(); //WATCHDOG!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
// Initialize UART library, pass baudrate and avr cpu clock
// with the macro UART_BAUD_SELECT()
//#ifdef UART_IS_USED
uart_init( UART_BAUD_SELECT(UART_BAUD_RATE, F_CPU) );
ResetRxBuff();
sei();
Print_PStrCR( PSTR(HARDWARE) );
Print_PStrCR( PSTR(SOFTWARE) );
Print_PStrCR( PSTR(AUTOR) );
Print_PStrCR( PSTR(DATUM) );
uart_puts_p( PSTR("UART-Baud="));
Print_PStrCR( PSTR(SHOW_BAUDRATE) );
//#endif
OCR1A = PWM_MITTE;
OCR1B = PWM_MITTE;
StartTickTimer(); //8 Bit Timer 2 = MS Tick Counter
StartTimers();
SET_ENABLE();
gu32_Ticks = 0;
//PWM_PORT |= PWM_ENABLE_BIT;
gf_PWM_Delay = 0.1;
//gu8Mode |= MODUS_SINUS;
gu8Mode = 0;
// ************ MAIN LOOP FOR EVER *********************
sei();
for (;;) /* loop forever */ //Aber schnell > 200.000 mal/Sekunde
{
sei();
wdt_reset(); //WATCHDOG!
if( gu8Mode & MODUS_SINUS)
{
uint16_t u16PWMVal;
Toggle_Bit(2);
_delay_ms( gf_PWM_Delay );
u16PWMVal++;
u16PWMVal %= (PWM_1MS-1); //OCR1A = PWM_1MS + u16PWMVal ;
OCR1A = PWM_1MS + round( 8000U + 8000U * sin( 2.0 * M_PI * (u16PWMVal / 16000.0) ) );
OCR1B = OCR1A;
};
if( gu8Status & TICK_EVENT )
{
gu8Status &= ~TICK_EVENT;
Toggle_Bit(1);
if( gu8Mode & TX_TRAFFIC_ON )
{
Toggle_Bit(3);
ULongToNumStr( gu32_Ticks );
uart_puts( gcaNumStr );
uart_puts_p( PSTR(", ") );
ULongToNumStr( OCR1A );
uart_puts( gcaNumStr );
uart_puts_p( PSTR(", ") );
PrintLongCR( OCR1B );
};
//PrintStrCR( ByteToBin (TIMSK) );
}; // Tickcounter
}; //main loop Ende
};
// ******************* MAIN END ********************************************
================================================================
#ifndef MAIN_HEADER //Prevents multiple includes
#define MAIN_HEADER
//#define UART_BAUD_RATE 9600
//#define UART_BAUD_RATE 57600U
#define UART_BAUD_RATE 19200U
#define TIMER_TICK_USED
#define DISABLE_ALL_PULLUP() (SFIOR |= _BV(PUD));
#define ENABLE_ALLUP_SCL() (SFIOR &= ~(_BV(PUD)));
#define WDTO_2S 7 //WatchDog
//========================================================================
//TIMERS
//TIMER2 = is 61 miliseconds Timer ~approx.
// 16MhZ / 1024 / 256 = 61,03515625 Hz
// T= 1/f = 0.016384 ms / Interrupt
//Aufzaehlbezeichner
#define RX_BITNR PD0 //0
#define TX_BITNR PD1 //1
extern volatile uint32_t gu32_Ticks; // T2 timeCounter, only NN_Counter for Keypressings
extern void CheckOrder(char *pcStrOrder); //von gcaRxStr
#ifdef TIMER_TICK_USED
void StartTickTimer(void); //0.1 Seconds interrupt
#endif
// SOFT PWM
#define ENABLE_DDRX DDRC
#define ENABLE_PORT PORTC
#define ENABLE_PIN 2
#define INIT_ENABLEPIN() (ENABLE_DDRX |= (1<<ENABLE_PIN))
#define SET_ENABLE() (ENABLE_PORT |= (1<<ENABLE_PIN))
#define CLR_ENABLE() (ENABLE_PORT &= ~(1<<ENABLE_PIN))
#define CLR_PWM_OC1A_PIN() (PWM_PORT &= ~(1<<PWM_A_16BIT_PIN))
#define CLR_PWM_OC1B_PIN() (PWM_PORT &= ~(1<<PWM_B_16BIT_PIN))
#define PWM_DDRX DDRB
#define PWM_PORT PORTB
#define PWM_A_16BIT_PIN 1
#define PWM_B_16BIT_PIN 2
#define INIT_PWM_DIR() (PWM_DDRX |= (1<< PWM_A_16BIT_PIN) | (1<< PWM_B_16BIT_PIN))
#define SET_PWMS_HIGH() (PWM_PORT |= (1<<PWM_A_16BIT_PIN) | (1<<PWM_B_16BIT_PIN))
#define OC2DDRX DDRB
#define OC2PORT PORTB
#define OC2 3
#define INIT_OC2DIR() ( OC2DDRX |= (1<<OC2) )
#define SET_OC2_HIGH() ( OC2PORT |= (1<<OC2) )
#define SET_OC2_LOW() ( OC2PORT &=~(1<<OC2) )
#define PWM_1MS 16000U
#define PWM_MITTE 24000U
#define PWM_2MS 32000U
#define OCR2_MITTE 127
#define MODUS_SINUS 0x01
#define MODUS_SINGEL_PULSE 0x02
#define MODE_ACTIVE 0x04
#define MODE_FALLBACK 0x08
#define TX_TRAFFIC_ON 0x10
//gu8Mode
#define TICK_EVENT 0x01
//volatile uint8_t gu8Status;
extern float gf_PWM_Delay ; // für sinus
#endif //MAIN_HEADER