반응형

#include <EEPROM.h>

void setup() {
  Serial.begin(9600);

  int value;

  EEPROM.get(0, value);
  Serial.print("변경 전 0번 메모리 값 : ");
  Serial.println(value);

  EEPROM.put(0, 111);

  EEPROM.get(0, value);
  Serial.print("변경 후 0번 메모리 값 : ");
  Serial.println(value);

  EEPROM.get(1, value);
  Serial.print("변경 전 1번 메모리 값 : ");
  Serial.println(value);

  EEPROM.put(1, 222);

  EEPROM.get(1, value);
  Serial.print("변경 후 1번 메모리 값 : ");
  Serial.println(value);
}

void loop() {
}

0번 메모리와 1번 메모리를 EEPROM.get 함수로 메모리를 읽어 value 변수에 저장하고 value 변수의 값을 EEPROM.put 함수로 메모리에 써 메모리 변경 전과 후의 결과를 출력하는 간단한 예제 소스코드이다.

 

EEPROM은 1KB의 용량을 가지며 수명이 있다.

읽기는 수명에 영향을 주지 않지만 쓰기는 약 10만 번의 수명이 있고 한번 쓰는데 약 3.3ms의 딜레이가 있다.

 

반응형
반응형

https://gun-ny.tistory.com/59

글을 시작하기에 앞서 Servo 라이브러리를 이용한 서보모터 제어 예제를 먼저 보고 오면 좋을 거 같다.

 


회로는 아두이노와 다이렉트로 구성하고 PWM 파형을 관측할 수 있게 중간에 오실로스코프 핀을 연결해 놓았다.

 


#include <PWM.h>

void setup() {
  Serial.begin(9600);
  InitTimersSafe();
  SetPinFrequencySafe(9, 50);  // 50Hz = 20ms
}

void loop() {
  Serial.println("pwmWrite 7 anglne 0");
  pwmWrite(9, 7);
  delay(2000);

  Serial.println("pwmWrite 18 anglne 90");
  pwmWrite(9, 18);
  delay(2000);

  Serial.println("pwmWrite 30 anglne 180");
  pwmWrite(9, 30);
  delay(2000);
}

SG90 서보모터 데이터시트의 PWM 설명과 예제 소스코드이다.

 

전에 작성했던 Servo 라이브러리를 이용한 서보모터 제어와 똑같이 동작을 하게 작성 하였다.

 

PWM 라이브러리를 사용하려면 주파수를 설정해 주어야 한다.

SG90 서보모터의 PWM 주기는 20ms이다. 1000ms(1초) / 20ms = 50Hz가 나온다.

이렇게 나온 결과 50을 인자로 넘기면 20ms의 주기 설정은 끝났다. 이제 듀티 사이클을 설정할 차례이다.

 

Servo 라이브러리 기준 544us에서 2400us의 듀티 사이클로 서보모터를 제어할 수 있다.

544us = 0도 / 1472us = 90도 / 2400us = 180도 이렇게 말이다.

 

하지만 pwmWrite 함수는 0부터 255의 값을 인자로 받는다.

주기가 20ms로 설정되어 있는 기준 64 = 5ms / 128 = 10ms / 255 = 20ms 이렇게 말이다.

그래서 약간의 계산이 필요하다.

 

0도 출력 기준

20000us(20ms) / 544us = 36.76us

255 / 36.76us = 7(6.93)

 

180도 출력 기준

20000us(20ms) / 2400us = 8.33us

255 / 8.33us = 30(30.61)

 

순간 어떻게 계산해서 결과가 나왔는지 헷갈려서 헤멨다.. (이거 맞나.....?)

 

아무튼.. 이렇게 pwmWrite를 하게 되면 전에 예제로 만들었던 서보모터 제어와 똑같이 동작을 하게 된다.

 


위 예제에 대한 결과이다.

 

반응형
반응형

가장 심플한 서보모터 회로도이다.

 


#include <Servo.h>

Servo servo;

void setup() {
  Serial.begin(9600);
  servo.attach(9);
}

void loop() {
  Serial.println("write angle 0");
  servo.write(0);
  delay(2000);

  Serial.println("writeMicroseconds angle 0");
  servo.writeMicroseconds(544);
  delay(2000);

  Serial.println("write angle 90");
  servo.write(90);
  delay(2000);

  Serial.println("writeMicroseconds angle 90");
  servo.writeMicroseconds(1472);
  delay(2000);

  Serial.println("write angle 180");
  servo.write(180);
  delay(2000);

  Serial.println("writeMicroseconds angle 180");
  servo.writeMicroseconds(2400);
  delay(2000);
}

서보모터 라이브러리를 사용하여 만든 위 회로도에 대한 예제 소스코드이다.

 

2초마다 서보모터 각도에 대한 상태변화를 하며 write 함수와 writeMicroseconds 함수로 교차하며 상태변화를 줄 것이다.

 

각 상태변화마다 현재 상태를 시리얼 모니터로 출력한다.

 


MG90 서보모터 데이터시트의 PWM에 대한 설명이다.

 

MG90 서보모터는 0도에서 180도까지만 회전한다.

 

write 함수는 0에서 180까지의 값을 넣으면 바로 그 각도로 상태변화를 하지만 writeMicroseconds 함수는 20ms의 PWM 주기에서 얼마 동안의 milliseconds(microseconds 아님) 동안 HIGH 값을 출력할 건지 정할 수 있다. PWM 라이브러리를 까보면 write 함수도 사용자의 편의를 위해 만들어진 것이지 최종적으로는 writeMicroseconds로 동작을 한다.

 

즉 소스코드를 다시 보면

servo.write(90);

servo.writeMicroseconds(1472);

20ms의 PWM 주기에서 1472 milliseconds(1.472ms) 동안 HIGH 값을 출력해라

둘 다 같은 동작을 한다는 것이다.

 


 

위 예제에 대한 결과이다.

 

반응형
반응형

PWM.h

/*
Copyright (c) 2012 Sam Knight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

/*
This library is built to support two of the AVR Architecture 'groups' that Arduino uses
a) ATmega48/88/168/328,
b) ATmega640/1280/1281/2560/2561
*/

#ifndef PWM_H_
#define PWM_H_

#include "avr/pgmspace.h"
#include "math.h"

#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
	#include "utility/ATimerDefs.h"
#elif defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)
	#include "utility/BTimerDefs.h"
#endif


#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)
// 16 bit timers
extern uint32_t	GetFrequency_16(const int16_t timerOffset);
extern bool		SetFrequency_16(const int16_t timerOffset, uint32_t f);
extern uint16_t GetPrescaler_16(const int16_t timerOffset);
extern void		SetPrescaler_16(const int16_t timerOffset, prescaler psc);
extern void		SetTop_16(const int16_t timerOffset, uint16_t top);
extern uint16_t GetTop_16(const int16_t timerOffset);
extern void		Initialize_16(const int16_t timerOffset);
extern float	GetResolution_16(const int16_t timerOffset);

// 8 bit timers
extern uint32_t	GetFrequency_8(const int16_t timerOffset);
extern bool		SetFrequency_8(const int16_t timerOffset, uint32_t f);
extern uint16_t GetPrescaler_8(const int16_t timerOffset);
extern void		SetPrescaler_8(const int16_t timerOffset, prescaler psc);
extern void		SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc);
extern void		SetTop_8(const int16_t timerOffset, uint8_t top);
extern uint8_t	GetTop_8(const int16_t timerOffset);
extern void		Initialize_8(const int16_t timerOffset);
extern float	GetResolution_8(const int16_t timerOffset);

#endif

#if defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)

// 16 bit timers
extern uint32_t	GetFrequency_16();
extern bool		SetFrequency_16(uint32_t f);
extern uint16_t GetPrescaler_16();
extern void		SetPrescaler_16(prescaler psc);
extern void		SetTop_16(uint16_t top);
extern uint16_t GetTop_16();
extern void		Initialize_16();
extern float	GetResolution_16();

// 8 bit timers
extern uint32_t	GetFrequency_8(const int16_t timerOffset);
extern bool		SetFrequency_8(const int16_t timerOffset, uint32_t f);
extern uint16_t GetPrescaler_8(const int16_t timerOffset);
extern void		SetPrescaler_8(const int16_t timerOffset, prescaler psc);
extern void		SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc);
extern void		SetTop_8(const int16_t timerOffset, uint8_t top);
extern uint8_t	GetTop_8(const int16_t timerOffset);
extern void		Initialize_8(const int16_t timerOffset);
extern float	GetResolution_8(const int16_t timerOffset);

#endif

//common functions

extern void		InitTimers();
extern void		InitTimersSafe();										//doesn't init timers responsible for time keeping functions
extern void		pwmWrite(uint8_t pin, uint8_t val);
extern void		pwmWriteHR(uint8_t pin, uint16_t val);					//accepts a 16 bit value and maps it down to the timer for maximum resolution
extern bool		SetPinFrequency(int8_t pin, uint32_t frequency);
extern bool		SetPinFrequencySafe(int8_t pin, uint32_t frequency);	//does not set timers responsible for time keeping functions
extern float	GetPinResolution(uint8_t pin);							//gets the PWM resolution of a pin in base 2, 0 is returned if the pin is not connected to a timer

#endif /* PWM_H_ */

 


ATimerDefs.h

 

/*
Copyright (c) 2012 Sam Knight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/


#ifndef ATIMERDEFS_H_
#define ATIMERDEFS_H_

#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)

//bit offset from timer 1 in the register
#define TIMER1_OFFSET	0x00
#define TIMER3_OFFSET	0x10
#define TIMER4_OFFSET	0x20
#define TIMER5_OFFSET	0xA0

//generic register-accessing macros (eliminates some branching)
#define TCCRA_16(tmr_offset)	_SFR_MEM8(0x80  + tmr_offset)
#define TCCRB_16(tmr_offset)	_SFR_MEM8(0x81  + tmr_offset)
#define TCCRC_16(tmr_offset)	_SFR_MEM8(0x82  + tmr_offset)
#define ICR_16(tmr_offset)		_SFR_MEM16(0x86 + tmr_offset)

//physical memory locations. Used in pwmWrite()
#define OCR1A_MEM	0x88
#define OCR1B_MEM	0x8A
#define OCR1C_MEM	0x8C
#define OCR3A_MEM	0x98
#define OCR3B_MEM	0x9A
#define OCR3C_MEM	0x9C
#define OCR4A_MEM	0xA8
#define OCR4B_MEM	0xAA
#define OCR4C_MEM	0xAC
#define OCR5A_MEM	0x128
#define OCR5B_MEM	0x12A
#define OCR5C_MEM	0x12C

#define OCR0A_MEM	0x47
#define OCR0B_MEM	0x48
#define OCR2A_MEM	0xB3
#define OCR2B_MEM	0xB4

#define TCCR1A_MEM	0x80
#define TCCR1B_MEM	0x81
#define TCCR1C_MEM	0x82
#define TCCR3A_MEM	0x90
#define TCCR3B_MEM	0x91
#define TCCR4A_MEM	0xA0
#define TCCR4B_MEM	0xA1
#define TCCR4C_MEM	0xA2
#define TCCR5A_MEM	0x120
#define TCCR5B_MEM	0x121
#define TCCR5C_MEM	0x122

#define TCCR0A_MEM	0x44
#define TCCR0B_MEM	0x45
#define TCCR2A_MEM	0xB0
#define TCCR2B_MEM	0xB1

#define ICR1_MEM	0x86
#define ICR3_MEM	0x96
#define ICR4_MEM	0xA6
#define ICR5_MEM	0x126

//8 bit timers
#define TIMER0_OFFSET	0x00
#define TIMER2_OFFSET	0x6C

#define TCCRA_8(tmr_offset)		_SFR_MEM8(0x44 + tmr_offset)
#define TCCRB_8(tmr_offset)		_SFR_MEM8(0x45 + tmr_offset)
#define OCRA_8(tmr_offset)		_SFR_MEM8(0x47 + tmr_offset)

static const uint16_t pscLst[] = { 0, 1, 8, 64, 256, 1024};
static const uint16_t pscLst_alt[] = {0, 1, 8, 32, 64, 128, 256, 1024};

struct TimerData //each instance is 4 bytes
{
	uint16_t	TimerTopRegLoc:		9;
	uint16_t	ChannelRegLoc:		9;
	uint16_t	PinConnectRegLoc:	9;
	uint8_t		PinConnectBits:		4;
	bool		Is16Bit:			1;
};

//4 bytes each, 18 elements, 72 Bytes total
const TimerData timer_to_pwm_data[] = {
	{0, 0, 0, 0},										//NOT_ON_TIMER
	{0, 0, 0, 0},										//TIMER0A	disabled when initialized
	{OCR0A_MEM, OCR0B_MEM, TCCR0A_MEM, COM0B1, false},	//TIMER0B
		
	{ICR1_MEM, OCR1A_MEM, TCCR1A_MEM, COM1A1, true},	//TIMER1A
	{ICR1_MEM, OCR1B_MEM, TCCR1A_MEM, COM1B1, true},	//TIMER1B	no C channel on timer 1?

	{0, 0, 0, 0, 0},									//TIMER2	
	{0, 0, 0, 0, 0},									//TIMER2A	disabled when initialized
	{OCR2A_MEM, OCR2B_MEM, TCCR2A_MEM, COM2B1, false},	//TIMER2B
		
	{ICR3_MEM, OCR3A_MEM, TCCR3A_MEM, COM3A1, true},	//TIMER3A
	{ICR3_MEM, OCR3B_MEM, TCCR3A_MEM, COM3B1, true},	//TIMER3B
	{ICR3_MEM, OCR3C_MEM, TCCR3A_MEM, COM3C1, true},	//TIMER3C
		
	{ICR4_MEM, OCR4A_MEM, TCCR4A_MEM, COM4A1, true},	//TIMER4A
	{ICR4_MEM, OCR4B_MEM, TCCR4A_MEM, COM4B1, true},	//TIMER4B
	{ICR4_MEM, OCR4C_MEM, TCCR4A_MEM, COM4C1, true},	//TIMER4C
	{0, 0, 0, 0, 0},									//TIMER4D	
		
	{ICR5_MEM, OCR5A_MEM, TCCR5A_MEM, COM5A1, true},	//TIMER5A
	{ICR5_MEM, OCR5B_MEM, TCCR5A_MEM, COM5B1, true},	//TIMER5B
	{ICR5_MEM, OCR5C_MEM, TCCR5A_MEM, COM5C1, true},	//TIMER5C
};

enum prescaler
{
	ps_1	=	1,
	ps_8	=	2,
	ps_64	=	3,
	ps_256	=	4,
	ps_1024 =	5
};

//certain 8 bit timers read the CSn register differently
enum prescaler_alt
{
	psalt_1		=	1,
	psalt_8		=	2,
	psalt_32	=	3,
	psalt_64	=	4,
	psalt_128	=	5,
	psalt_256	=	6,
	psalt_1024	=	7
};

//macros for each timer 'object'
#define Timer0_GetFrequency()		GetFrequency_8(TIMER0_OFFSET)
#define Timer0_SetFrequency(x)		SetFrequency_8(TIMER0_OFFSET, x)
#define Timer0_GetPrescaler()		GetPrescaler_8(TIMER0_OFFSET)
#define Timer0_SetPrescaler(x)		SetPrescaler_8(TIMER0_OFFSET, x)
#define Timer0_GetTop()				GetTop_8(TIMER0_OFFSET)
#define Timer0_SetTop(x)			SetTop_8(TIMER0_OFFSET, x)
#define Timer0_Initialize()			Initialize_8(TIMER0_OFFSET)
#define Timer0_GetResolution()		GetResolution_8(TIMER0_OFFSET)

#define Timer1_GetFrequency()		GetFrequency_16(TIMER1_OFFSET)
#define Timer1_SetFrequency(x)		SetFrequency_16(TIMER1_OFFSET, x)
#define Timer1_GetPrescaler()		GetPrescaler_16(TIMER1_OFFSET)
#define Timer1_SetPrescaler(x)		SetPrescaler_16(TIMER1_OFFSET, x)
#define Timer1_GetTop()				GetTop_16(TIMER1_OFFSET)
#define Timer1_SetTop(x)			SetTop_16(TIMER1_OFFSET, x)
#define Timer1_Initialize()			Initialize_16(TIMER1_OFFSET)
#define Timer1_GetResolution()		GetResolution_16(TIMER1_OFFSET)

#define Timer2_GetFrequency()		GetFrequency_8(TIMER2_OFFSET)
#define Timer2_SetFrequency(x)		SetFrequency_8(TIMER2_OFFSET, x)
#define Timer2_GetPrescaler()		GetPrescaler_8(TIMER2_OFFSET)
#define Timer2_SetPrescaler(x)		SetPrescalerAlt_8(TIMER2_OFFSET, x)
#define Timer2_GetTop()				GetTop_8(TIMER2_OFFSET)
#define Timer2_SetTop(x)			SetTop_8(TIMER2_OFFSET, x)
#define Timer2_Initialize()			Initialize_8(TIMER2_OFFSET)
#define Timer2_GetResolution()		GetResolution_8(TIMER2_OFFSET)

#define Timer3_GetFrequency()		GetFrequency_16(TIMER3_OFFSET)
#define Timer3_SetFrequency(x)		SetFrequency_16(TIMER3_OFFSET, x)
#define Timer3_GetPrescaler()		GetPrescaler_16(TIMER3_OFFSET)
#define Timer3_SetPrescaler(x)		SetPrescaler_16(TIMER3_OFFSET, x)
#define Timer3_GetTop()				GetTop_16(TIMER3_OFFSET)
#define Timer3_SetTop(x)			SetTop_16(TIMER3_OFFSET, x)
#define Timer3_Initialize()			Initialize_16(TIMER3_OFFSET)
#define Timer3_GetResolution()		GetResolution_16(TIMER3_OFFSET)

#define Timer4_GetFrequency()		GetFrequency_16(TIMER4_OFFSET)
#define Timer4_SetFrequency(x)		SetFrequency_16(TIMER4_OFFSET, x)
#define Timer4_GetPrescaler()		GetPrescaler_16(TIMER4_OFFSET)
#define Timer4_SetPrescaler(x)		SetPrescaler_16(TIMER4_OFFSET, x)
#define Timer4_GetTop()				GetTop_16(TIMER4_OFFSET)
#define Timer4_SetTop(x)			SetTop_16(TIMER4_OFFSET, x)
#define Timer4_Initialize()			Initialize_16(TIMER4_OFFSET)
#define Timer4_GetResolution(x)		GetResolution_16(TIMER4_OFFSET)

#define Timer5_GetFrequency()		GetFrequency_16(TIMER5_OFFSET)
#define Timer5_SetFrequency(x)		SetFrequency_16(TIMER5_OFFSET, x)
#define Timer5_GetPrescaler()		GetPrescaler_16(TIMER5_OFFSET)
#define Timer5_SetPrescaler(x)		SetPrescaler_16(TIMER5_OFFSET, x)
#define Timer5_GetTop()				GetTop_16(TIMER5_OFFSET)
#define Timer5_SetTop(x)			SetTop_16(TIMER5_OFFSET, x)
#define Timer5_Initialize()			Initialize_16(TIMER5_OFFSET)
#define Timer5_GetResolution()		GetResolution_16(TIMER5_OFFSET)

#else
	#error "ATimerDefs.h only supports ATMega640, ATMega1280, ATMega1281, ATMega2560, and ATMega2561"
#endif
#endif /* ATIMERDEFS_H_ */

 


ATimerDefs.cpp

 

/*
Copyright (c) 2012 Sam Knight
Permission is hereby granted, free of charge, to any person obtaining a copy 
of this software and associated documentation files (the "Software"), to deal 
in the Software without restriction, including without limitation the rights to 
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
of the Software, and to permit persons to whom the Software is furnished to do 
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all 
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#if defined(__AVR_ATmega640__) || defined(__AVR_ATmega1280__) || defined(__AVR_ATmega1281__) || defined(__AVR_ATmega2560__) || defined(__AVR_ATmega2561__)

#include "wiring_private.h"
#include "../PWM.h"

#define UINT16_MAX 65535
#define UINT8_MAX 255

//--------------------------------------------------------------------------------
//							Helper Functions
//--------------------------------------------------------------------------------

static float toBaseTwo(double baseTenNum)
{
	return log(baseTenNum + 1)/log(2);
}

//--------------------------------------------------------------------------------
//							16 Bit Timer Functions
//--------------------------------------------------------------------------------

uint32_t GetFrequency_16(const int16_t timerOffset)
{
	return (int32_t)(F_CPU/(2 * (int32_t)GetTop_16(timerOffset) * GetPrescaler_16(timerOffset)));
}

bool SetFrequency_16(const int16_t timerOffset, uint32_t f)
{
	if(f > 2000000 || f < 1)
	return false;
	
	//find the smallest usable multiplier
	uint16_t multiplier = (int16_t)(F_CPU / (2 * f * UINT16_MAX));
	
	uint8_t iterate = 0;
	while(multiplier > pscLst[iterate++]);
	
	multiplier = pscLst[iterate];		//multiplier holds the clock select value, and iterate holds the corresponding CS flag
	
	//getting the timer top using the new multiplier
	uint16_t timerTop = (uint16_t)(F_CPU/(2* f * multiplier));
	
	SetTop_16(timerOffset, timerTop);
	SetPrescaler_16(timerOffset, (prescaler)iterate);
	
	return true;
}

uint16_t GetPrescaler_16(const int16_t timerOffset)
{
	return pscLst[(TCCRB_16(timerOffset) & 7)];
}

void SetPrescaler_16(const int16_t timerOffset, prescaler psc)
{
	TCCRB_16(timerOffset) = (TCCRB_16(timerOffset) & ~7) | (psc & 7);
}

void SetTop_16(const int16_t timerOffset, uint16_t top)
{
	ICR_16(timerOffset) = top;
}

uint16_t GetTop_16(const int16_t timerOffset)
{
	return ICR_16(timerOffset);
}

void Initialize_16(const int16_t timerOffset)
{
	//setting the waveform generation mode
	uint8_t wgm = 8;
	
	TCCRA_16(timerOffset) = (TCCRA_16(timerOffset) & B11111100) | (wgm & 3);
	TCCRB_16(timerOffset) = (TCCRB_16(timerOffset) & B11100111) | ((wgm & 12) << 1);
	
	SetFrequency_16(timerOffset, 500);
}

float GetResolution_16(const int16_t timerOffset)
{
	return toBaseTwo(ICR_16(timerOffset));
}

//--------------------------------------------------------------------------------
//							8 Bit Timer Functions
//--------------------------------------------------------------------------------

uint32_t GetFrequency_8(const int16_t timerOffset)
{
	return (uint32_t)(F_CPU/((uint32_t)2 * GetTop_8(timerOffset) * GetPrescaler_8(timerOffset)));
}

bool SetFrequency_8(const int16_t timerOffset, uint32_t f)
{
	if(f > 2000000 || f < 31)
		return false;
	
	//find the smallest usable multiplier
	uint16_t multiplier = (F_CPU / (2 * (uint32_t)f * UINT8_MAX));
	
	uint8_t iterate = 0;
	uint16_t timerTop; 
	
	do
	{
		if(TIMER2_OFFSET != timerOffset)
		{
			while(multiplier > pscLst[++iterate]);
			multiplier = pscLst[iterate];
		}
		else
		{
			while(multiplier > pscLst_alt[++iterate]);
			multiplier = pscLst_alt[iterate];
		}
		//getting the timer top using the new multiplier
		timerTop = (F_CPU/(2* f * (uint32_t)multiplier));
	} while (timerTop > UINT8_MAX);
	
	SetTop_8(timerOffset, timerTop);
	
	if(timerOffset != TIMER2_OFFSET)
	SetPrescaler_8(timerOffset, (prescaler)iterate);
	else
	SetPrescalerAlt_8(timerOffset, (prescaler_alt)iterate);
	
	return true;
}

uint16_t GetPrescaler_8(const int16_t timerOffset)
{
	if(timerOffset != TIMER2_OFFSET)
		return pscLst[(TCCRB_8(timerOffset) & 7)];
	else
		return pscLst_alt[(TCCRB_8(timerOffset) & 7)];
}

void SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc)
{
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & ~7) | (psc & 7);
}

void SetPrescaler_8(const int16_t timerOffset, prescaler psc)
{
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & ~7) | (psc & 7);
}

void SetTop_8(const int16_t timerOffset, uint8_t top)
{
	OCRA_8(timerOffset) = top;
}

uint8_t	GetTop_8(const int16_t timerOffset)
{
	return OCRA_8(timerOffset);
}

void Initialize_8(const int16_t timerOffset)
{
	//setting the waveform generation mode
	uint8_t wgm = 5;
	
	TCCRA_8(timerOffset) = (TCCRA_8(timerOffset) & B11111100) | (wgm & 3);
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & B11110111) | ((wgm & 12) << 1);
	
	//disable timer0's interrupt when initialization is called, otherwise handler will eat
	//up processor cycles when PWM on timer0 is set to high frequencies. This will effectively disable
	//Arduino's time keeping functions, which the user should be aware of before initializing timer0
	if(timerOffset == 0)
	{
		TIMSK0 &= B11111110;
	}
	
	SetFrequency_8(timerOffset, 500);
}

float GetResolution_8(const int16_t timerOffset)
{
	return toBaseTwo(OCRA_8(timerOffset));
}

//--------------------------------------------------------------------------------
//							Timer Independent Functions
//--------------------------------------------------------------------------------

void pwmWrite(uint8_t pin, uint8_t val)
{
	pinMode(pin, OUTPUT);
	
	uint32_t tmp = val;
	
	if (val == 0)
		digitalWrite(pin, LOW);
	else if (val == 255)
		digitalWrite(pin, HIGH);
	else
	{
		TimerData td = timer_to_pwm_data[digitalPinToTimer(pin)];
		if(td.ChannelRegLoc) //null checking
		{
			if(td.Is16Bit)
			{
				sbi(_SFR_MEM8(td.PinConnectRegLoc), td.PinConnectBits);
				_SFR_MEM16(td.ChannelRegLoc) = (tmp * _SFR_MEM16(td.TimerTopRegLoc)) / 255;
			}
			else
			{
				sbi(_SFR_MEM8(td.PinConnectRegLoc), td.PinConnectBits);
				_SFR_MEM8(td.ChannelRegLoc) = (tmp * _SFR_MEM8(td.TimerTopRegLoc)) / 255;
			}
		}		
	}
}

//takes a 16 bit value instead of an 8 bit value for maximum resolution
void pwmWriteHR(uint8_t pin, uint16_t val)
{
	pinMode(pin, OUTPUT);
	
	uint32_t tmp = val;	
	
	if (val == 0)
	digitalWrite(pin, LOW);
	else if (val == 65535)
	digitalWrite(pin, HIGH);
	else
	{
		TimerData td = timer_to_pwm_data[digitalPinToTimer(pin)];
		if(td.ChannelRegLoc) //null checking
		{
			if(td.Is16Bit)
			{
				sbi(_SFR_MEM8(td.PinConnectRegLoc), td.PinConnectBits);
				_SFR_MEM16(td.ChannelRegLoc) = (tmp * _SFR_MEM16(td.TimerTopRegLoc)) / 65535;
			}
			else
			{
				sbi(_SFR_MEM8(td.PinConnectRegLoc), td.PinConnectBits);
				_SFR_MEM8(td.ChannelRegLoc) = (tmp * _SFR_MEM8(td.TimerTopRegLoc)) / 65535;
			}
		}
	}
}

//Initializes all timer objects, setting them to modes compatible with frequency manipulation. All timers are set to 488 - 500 Hz at the end of initialization.
void InitTimers()
{
	Timer0_Initialize();
	InitTimersSafe();
}

//initializes all timer objects except for timer 0, which is necessary for the Arduino's time keeping functions
void InitTimersSafe()
{
	Timer1_Initialize();
	Timer2_Initialize();
	Timer3_Initialize();
	Timer4_Initialize();
	Timer5_Initialize();
}

bool SetPinFrequency(int8_t pin, uint32_t frequency)
{
	uint8_t timer = digitalPinToTimer(pin);
	
	if(timer == TIMER0B)
	return Timer0_SetFrequency(frequency);
	else if(timer == TIMER1A || timer == TIMER1B)
	return Timer1_SetFrequency(frequency);
	else if(timer == TIMER2B)
	return Timer2_SetFrequency(frequency);
	else if(timer == TIMER3A || timer == TIMER3B || timer == TIMER3C)
	return Timer3_SetFrequency(frequency);
	else if(timer == TIMER4A || timer == TIMER4B || timer == TIMER4C)
	return Timer4_SetFrequency(frequency);
	else if(timer == TIMER5A || timer == TIMER5B || timer == TIMER5C)
	return Timer5_SetFrequency(frequency);
	else
	return false;
}

bool SetPinFrequencySafe(int8_t pin, uint32_t frequency)
{
	uint8_t timer = digitalPinToTimer(pin);
	
	if(timer == TIMER1A || timer == TIMER1B)
	return Timer1_SetFrequency(frequency);
	else if(timer == TIMER2B)
	return Timer2_SetFrequency(frequency);
	else if(timer == TIMER3A || timer == TIMER3B || timer == TIMER3C)
	return Timer3_SetFrequency(frequency);
	else if(timer == TIMER4A || timer == TIMER4B || timer == TIMER4C)
	return Timer4_SetFrequency(frequency);
	else if(timer == TIMER5A || timer == TIMER5B || timer == TIMER5C)
	return Timer5_SetFrequency(frequency);
	else
	return false;
}

float GetPinResolution(uint8_t pin)
{
	TimerData td = timer_to_pwm_data[digitalPinToTimer(pin)];
	double baseTenRes = 0;
	
	if(td.ChannelRegLoc)
	{
		//getting a base 10 resolution
		td.Is16Bit? (baseTenRes = _SFR_MEM16(td.TimerTopRegLoc)) : (baseTenRes = _SFR_MEM8(td.TimerTopRegLoc));
		 
		//change the base and return	
		return toBaseTwo(baseTenRes);
	}
	else
	{
		return 0;
	}
}
#endif

 


BTimerDefs.h

 

/*
Copyright (c) 2012 Sam Knight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/


#ifndef BTIMERDEFS_H_
#define BTIMERDEFS_H_

#if defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)

//physical memory locations used in pwmWrite()
#define OCR1A_MEM	0x88
#define OCR1B_MEM	0x8A
#define OCR1C_MEM	0x8C

#define OCR0A_MEM	0x47
#define OCR0B_MEM	0x48
#define OCR2A_MEM	0xB3
#define OCR2B_MEM	0xB4

#define TCCR1A_MEM	0x80
#define TCCR1B_MEM	0x81
#define TCCR1C_MEM	0x82

#define TCCR0A_MEM	0x44
#define TCCR0B_MEM	0x45
#define TCCR2A_MEM	0xB0
#define TCCR2B_MEM	0xB1

#define ICR1_MEM	0x86

//8 bit timers
#define TIMER0_OFFSET	0x00
#define TIMER2_OFFSET	0x6C

#define TCCRA_8(tmr_offset)		_SFR_MEM8(0x44 + tmr_offset)
#define TCCRB_8(tmr_offset)		_SFR_MEM8(0x45 + tmr_offset)
#define OCRA_8(tmr_offset)		_SFR_MEM8(0x47 + tmr_offset)

static const uint16_t pscLst[] = { 0, 1, 8, 64, 256, 1024};
static const uint16_t pscLst_alt[] = {0, 1, 8, 32, 64, 128, 256, 1024};

enum prescaler
{
	ps_1	=	1,
	ps_8	=	2,
	ps_64	=	3,
	ps_256	=	4,
	ps_1024 =	5
};

//certain 8 bit timers read the CSn register differently
enum prescaler_alt
{
	psalt_1		=	1,
	psalt_8		=	2,
	psalt_32	=	3,
	psalt_64	=	4,
	psalt_128	=	5,
	psalt_256	=	6,
	psalt_1024	=	7
};

//macros for each timer 'object'
#define Timer0_GetFrequency()	GetFrequency_8(TIMER0_OFFSET)
#define Timer0_SetFrequency(x)	SetFrequency_8(TIMER0_OFFSET, x)
#define Timer0_GetPrescaler()	GetPrescaler_8(TIMER0_OFFSET)
#define Timer0_SetPrescaler(x)	SetPrescaler_8(TIMER0_OFFSET, x)
#define Timer0_GetTop()			GetTop_8(TIMER0_OFFSET)
#define Timer0_SetTop(x)		SetTop_8(TIMER0_OFFSET, x)
#define Timer0_Initialize()		Initialize_8(TIMER0_OFFSET)
#define Timer0_GetResolution()	GetResolution_8(TIMER0_OFFSET)

#define Timer1_GetFrequency()	GetFrequency_16()
#define Timer1_SetFrequency(x)	SetFrequency_16(x)
#define Timer1_GetPrescaler()	GetPrescaler_16()
#define Timer1_SetPrescaler(x)	SetPrescaler_16(x)
#define Timer1_GetTop()			GetTop_16()
#define Timer1_SetTop(x)		SetTop_16(x)
#define Timer1_Initialize()		Initialize_16()
#define Timer1_GetResolution()	GetResolution_16()

#define Timer2_GetFrequency()	GetFrequency_8(TIMER2_OFFSET)
#define Timer2_SetFrequency(x)	SetFrequency_8(TIMER2_OFFSET, x)
#define Timer2_GetPrescaler()	GetPrescaler_8(TIMER2_OFFSET)
#define Timer2_SetPrescaler(x)	SetPrescalerAlt_8(TIMER2_OFFSET, x)
#define Timer2_GetTop()			GetTop_8(TIMER2_OFFSET)
#define Timer2_SetTop(x)		SetTop_8(TIMER2_OFFSET, x)
#define Timer2_Initialize()		Initialize_8(TIMER2_OFFSET)
#define Timer2_GetResolution()	GetResolution_8(TIMER2_OFFSET)

#else
	#error "BTimerDefs.h only supports ATMega48, ATMega88, ATMega168, ATMega328"
#endif
#endif /* BTIMERDEFS_H_ */

 


BTimerDefs.cpp

 

/*
Copyright (c) 2012 Sam Knight
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/

#if defined(__AVR_ATmega48__) || defined(__AVR_ATmega88__) || defined(__AVR_ATmega88P__) || defined(__AVR_ATmega168__) || defined(__AVR_ATmega168P__) || defined(__AVR_ATmega328__) || defined(__AVR_ATmega328P__)

#include "wiring_private.h"
#include "../PWM.h"

#define UINT16_MAX 65535
#define UINT8_MAX 255

//--------------------------------------------------------------------------------
//							Helper Functions
//--------------------------------------------------------------------------------

static float toBaseTwo(double baseTenNum)
{
	return log(baseTenNum + 1)/log(2);
}

//--------------------------------------------------------------------------------
//							16 Bit Timer Functions
//--------------------------------------------------------------------------------

uint32_t GetFrequency_16()
{
	return (int32_t)(F_CPU/(2 * (int32_t)GetTop_16() * GetPrescaler_16()));
}

bool SetFrequency_16(uint32_t f)
{
	if(f > 2000000 || f < 1)
	return false;
	
	//find the smallest usable multiplier
	uint16_t multiplier = (int16_t)(F_CPU / (2 * f * UINT16_MAX));
	
	uint8_t iterate = 0;
	while(multiplier > pscLst[iterate++]);
	
	multiplier = pscLst[iterate]; //multiplier holds the clock select value, and iterate holds the corresponding CS flag
	
	//getting the timer top using the new multiplier
	uint16_t timerTop = (uint16_t)(F_CPU/(2* f * multiplier));
	
	SetTop_16(timerTop);
	SetPrescaler_16((prescaler)iterate);
	
	return true;
}

uint16_t GetPrescaler_16()
{
	return pscLst[(TCCR1B & 7)];
}

void SetPrescaler_16(prescaler psc)
{
	TCCR1B = (TCCR1B & ~7) | (psc & 7);
}

void SetTop_16(uint16_t top)
{
	ICR1 = top;
}

uint16_t GetTop_16()
{
	return ICR1;
}

void Initialize_16()
{
	//setting the waveform generation mode
	uint8_t wgm = 8;
	
	TCCR1A = (TCCR1A & B11111100) | (wgm & 3);
	TCCR1B = (TCCR1B & B11100111) | ((wgm & 12) << 1);
	
	SetFrequency_16(500);
}

float GetResolution_16()
{
	return toBaseTwo(ICR1);
}

//--------------------------------------------------------------------------------
//							8 Bit Timer Functions
//--------------------------------------------------------------------------------

uint32_t GetFrequency_8(const int16_t timerOffset)
{
	return (uint32_t)(F_CPU/((uint32_t)2 * GetTop_8(timerOffset) * GetPrescaler_8(timerOffset)));
}

bool SetFrequency_8(const int16_t timerOffset, uint32_t f)
{
	if(f > 2000000 || f < 31)
		return false;
	
	//find the smallest usable multiplier
	uint16_t multiplier = (F_CPU / (2 * (uint32_t)f * UINT8_MAX));
	
	uint8_t iterate = 0;
	uint16_t timerTop;
	
	do
	{
		if(TIMER2_OFFSET != timerOffset)
		{
			while(multiplier > pscLst[++iterate]);
			multiplier = pscLst[iterate];
		}
		else
		{
			while(multiplier > pscLst_alt[++iterate]);
			multiplier = pscLst_alt[iterate];
		}
		
		//getting the timer top using the new multiplier
		timerTop = (F_CPU/(2* f * (uint32_t)multiplier));
		
	} while (timerTop > UINT8_MAX);
	
	SetTop_8(timerOffset, timerTop);
	
	if(timerOffset != TIMER2_OFFSET)
	SetPrescaler_8(timerOffset, (prescaler)iterate);
	else
	SetPrescalerAlt_8(timerOffset, (prescaler_alt)iterate);
	
	return true;
}

uint16_t GetPrescaler_8(const int16_t timerOffset)
{
	if(timerOffset != TIMER2_OFFSET)
		return pscLst[(TCCRB_8(timerOffset) & 7)];
	else
		return pscLst_alt[(TCCRB_8(timerOffset) & 7)];
}

void SetPrescaler_8(const int16_t timerOffset, prescaler psc)
{
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & ~7) | (psc & 7);
}

void SetPrescalerAlt_8(const int16_t timerOffset, prescaler_alt psc)
{
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & ~7) | (psc & 7);
}

void SetTop_8(const int16_t timerOffset, uint8_t top)
{
	OCRA_8(timerOffset) = top;
}

uint8_t	GetTop_8(const int16_t timerOffset)
{
	return OCRA_8(timerOffset);
}

void Initialize_8(const int16_t timerOffset)
{
	//setting the waveform generation mode
	uint8_t wgm = 5;
	
	TCCRA_8(timerOffset) = (TCCRA_8(timerOffset) & B11111100) | (wgm & 3);
	TCCRB_8(timerOffset) = (TCCRB_8(timerOffset) & B11110111) | ((wgm & 12) << 1);
	
	//disable timer0's interrupt when initialization is called, otherwise handler will eat
	//up processor cycles when PWM on timer0 is set to high frequencies. This will effectively disable
	//Arduino's time keeping functions, which the user should be aware of before initializing timer0
	if(timerOffset == 0) 
	{
		TIMSK0 &= B11111110;
	}
	
	SetFrequency_8(timerOffset, 500);
}

float GetResolution_8(const int16_t timerOffset)
{
	return toBaseTwo(OCRA_8(timerOffset));
}


//--------------------------------------------------------------------------------
//							Timer Independent Functions
//--------------------------------------------------------------------------------

void pwmWrite(uint8_t pin, uint8_t val)
{
	pinMode(pin, OUTPUT);
	
	//casting "val" to be larger so that the final value (which is the partially
	//the result of multiplying two potentially high value int16s) will not truncate
	uint32_t tmp = val;
	
	if (val == 0)
		digitalWrite(pin, LOW);
	else if (val == 255)
		digitalWrite(pin, HIGH);
	else
	{
		uint16_t regLoc16 = 0;
		uint16_t regLoc8 = 0;
		
		uint16_t top;
		
		switch(digitalPinToTimer(pin))
		{
			case TIMER0B:
			sbi(TCCR0A, COM0B1);
			regLoc8 = OCR0B_MEM;
			top = Timer0_GetTop();
			break;
			case TIMER1A:
			sbi(TCCR1A, COM1A1);
			regLoc16 = OCR1A_MEM;
			top = Timer1_GetTop();
			break;
			case TIMER1B:
			sbi(TCCR1A, COM1B1);
			regLoc16 = OCR1B_MEM;
			top = Timer1_GetTop();
			break;
			case TIMER2B:
			sbi(TCCR2A, COM2B1);
			regLoc8 = OCR2B_MEM;
			top = Timer2_GetTop();
			break;
			case NOT_ON_TIMER:
			default:
			if (val < 128)
			digitalWrite(pin, LOW);
			else
			digitalWrite(pin, HIGH);
			return;
		}
		
		if(regLoc16)
			_SFR_MEM16(regLoc16) = (tmp*top)/255;
		else
			_SFR_MEM8(regLoc8) = (tmp*top)/255;
		
	}		
}

//takes a 16 bit value instead of an 8 bit value for maximum resolution
void pwmWriteHR(uint8_t pin, uint16_t val)
{
	pinMode(pin, OUTPUT);
	
	uint32_t tmp = val;
	
	if (val == 0)
	digitalWrite(pin, LOW);
	else if (val == 65535)
	digitalWrite(pin, HIGH);
	else
	{
		uint16_t regLoc16 = 0;
		uint16_t regLoc8 = 0;
		
		uint16_t top;
		switch(digitalPinToTimer(pin))
		{
			case TIMER0B:
			sbi(TCCR0A, COM0B1);
			regLoc8 = OCR0B_MEM;
			top = Timer0_GetTop();
			break;
			case TIMER1A:
			sbi(TCCR1A, COM1A1);
			regLoc16 = OCR1A_MEM;
			top = Timer1_GetTop();
			break;
			case TIMER1B:
			sbi(TCCR1A, COM1B1);
			regLoc16 = OCR1B_MEM;
			top = Timer1_GetTop();
			break;
			case TIMER2B:
			sbi(TCCR2A, COM2B1);
			regLoc8 = OCR2B_MEM;
			top = Timer2_GetTop();
			break;
			case NOT_ON_TIMER:
			default:
			if (val < 128)
			digitalWrite(pin, LOW);
			else
			digitalWrite(pin, HIGH);
			return;
		}			
		
		if(regLoc16)
			_SFR_MEM16(regLoc16) = (tmp*top)/65535;
		else
			_SFR_MEM8(regLoc8) = (tmp*top)/65535;
	}
}

void InitTimers()
{
	Timer0_Initialize();
	Timer1_Initialize();
	Timer2_Initialize();
}

void InitTimersSafe()
{
	Timer1_Initialize();
	Timer2_Initialize();
}

extern bool SetPinFrequency( int8_t pin, uint32_t frequency )
{
	uint8_t timer = digitalPinToTimer(pin);
	
	if(timer == TIMER0B)
		return Timer0_SetFrequency(frequency);
	else if(timer == TIMER1A || timer == TIMER1B)
		return Timer1_SetFrequency(frequency);
	else if(timer == TIMER2B)
		return Timer2_SetFrequency(frequency);
	else
		return false;
}

bool SetPinFrequencySafe(int8_t pin, uint32_t frequency)
{
	uint8_t timer = digitalPinToTimer(pin);
	
	if(timer == TIMER1A || timer == TIMER1B)
		return Timer1_SetFrequency(frequency);
	else if(timer == TIMER2B)
		return Timer2_SetFrequency(frequency);
	else
		return false;
}

float GetPinResolution(uint8_t pin)
{
	uint8_t timer = digitalPinToTimer(pin);	
	uint16_t top;
	
	switch(timer)
	{
		case TIMER0B:
			top = Timer0_GetTop();
			break;
		case TIMER1A:
			top = Timer1_GetTop();
			break;
		case TIMER1B:
			top = Timer1_GetTop();
			break;
		case TIMER2B:
			top = Timer2_GetTop();
		default:
			return 0;
	}
	
	return toBaseTwo(top);
}

#endif

 

반응형

+ Recent posts