1
0
mirror of https://github.com/AlexGyver/GyverCore.git synced 2025-04-19 08:42:16 +03:00
This commit is contained in:
Alex 2019-08-02 19:08:10 +03:00
parent 983b80cb94
commit c52f478bb5
16 changed files with 295 additions and 785 deletions

View File

@ -5,7 +5,7 @@ menu.timers=Timers
######################
nano.name=ATmega328P based
nano.name=ATmega328/168 based
nano.upload.tool=avrdude
nano.upload.protocol=arduino
@ -21,10 +21,10 @@ nano.build.core=arduino
## timer0 OVF ON/OFF
## --------------------------
nano.menu.timers.yes_millis=yes millis
nano.menu.timers.yes_millis=with millis
nano.menu.timers.yes_millis.build.variant=yesmillis
nano.menu.timers.no_millis=no millis
nano.menu.timers.no_millis=without millis
nano.menu.timers.no_millis.build.variant=nomillis
@ -62,7 +62,7 @@ nano.menu.cpu.atmega328old.build.mcu=atmega328p
## ATmega328P - NO bootloader
## --------------------------
nano.menu.cpu.atmega328noBoot=ATmega328P - NO bootloader
nano.menu.cpu.atmega328noBoot=ATmega328P - without bootloader
nano.menu.cpu.atmega328noBoot.upload.maximum_size=32768
nano.menu.cpu.atmega328noBoot.upload.maximum_data_size=2048
@ -107,7 +107,7 @@ nano.menu.cpu.atmega168old.build.mcu=atmega168
## ATmega168 - NO bootloader
## -------------------------
nano.menu.cpu.atmega168noBoot=ATmega168 - NO bootloader
nano.menu.cpu.atmega168noBoot=ATmega168 - without bootloader
nano.menu.cpu.atmega168noBoot.upload.maximum_size=16144
nano.menu.cpu.atmega168noBoot.upload.maximum_data_size=1024

View File

@ -161,62 +161,7 @@ void detachInterrupt(uint8_t);
void setup(void);
void loop(void);
#define analogInPinToBit(P) (P)
extern const uint16_t PROGMEM port_to_mode_PGM[];
extern const uint16_t PROGMEM port_to_input_PGM[];
extern const uint16_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_AN_INTERRUPT -1
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1C 5
#define TIMER2 6
#define TIMER2A 7
#define TIMER2B 8
#define TIMER3A 9
#define TIMER3B 10
#define TIMER3C 11
#define TIMER4A 12
#define TIMER4B 13
#define TIMER4C 14
#define TIMER4D 15
#define TIMER5A 16
#define TIMER5B 17
#define TIMER5C 18
#ifdef __cplusplus
} // extern "C"
@ -239,8 +184,8 @@ uint16_t makeWord(byte h, byte l);
unsigned long pulseIn(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
unsigned long pulseInLong(uint8_t pin, uint8_t state, unsigned long timeout = 1000000L);
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration = 0);
void noTone(uint8_t _pin);
void tone(uint8_t pin , uint16_t freq, uint32_t duration = 0);
void noTone(uint8_t pin);
// WMath prototypes
long random(long);

View File

@ -1,619 +1,46 @@
/* Tone.cpp
A Tone Generator Library
Written by Brett Hagman
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
Version Modified By Date Comments
------- ----------- -------- --------
0001 B Hagman 09/08/02 Initial coding
0002 B Hagman 09/08/18 Multiple pins
0003 B Hagman 09/08/18 Moved initialization from constructor to begin()
0004 B Hagman 09/09/26 Fixed problems with ATmega8
0005 B Hagman 09/11/23 Scanned prescalars for best fit on 8 bit timers
09/11/25 Changed pin toggle method to XOR
09/11/25 Fixed timer0 from being excluded
0006 D Mellis 09/12/29 Replaced objects with functions
0007 M Sproul 10/08/29 Changed #ifdefs from cpu to register
0008 S Kanemoto 12/06/22 Fixed for Leonardo by @maris_HY
0009 J Reucker 15/04/10 Issue #292 Fixed problems with ATmega8 (thanks to Pete62)
0010 jipp 15/04/13 added additional define check #2923
*************************************************/
#include <avr/interrupt.h>
#include <avr/pgmspace.h>
#include "Arduino.h"
//#include "pins_arduino.h"
/* оптимизированный вариант реализации tone */
uint8_t tone_pin; // глобальная переменная для пина
uint32_t toggle_counter; // счетчик toggl'ов
uint32_t toggle_top; // предел счета для toggl'ов
bool willStop; // флаг позволяющий генерировать сигнал бесконечно долго
#if defined(__AVR_ATmega8__) || defined(__AVR_ATmega128__)
#define TCCR2A TCCR2
#define TCCR2B TCCR2
#define COM2A1 COM21
#define COM2A0 COM20
#define OCR2A OCR2
#define TIMSK2 TIMSK
#define OCIE2A OCIE2
#define TIMER2_COMPA_vect TIMER2_COMP_vect
#define TIMSK1 TIMSK
#endif
void tone(uint8_t pin , uint16_t freq, uint32_t duration = 0){
tone_pin = pin; // присвоили номер пина для прерывания
willStop = duration;// если введено время генерации - будет ненулевым
toggle_top = (freq * duration)/500; // расчет кол-ва toggl'ов за указанное время генерации
TCCR2A = (1<<WGM21); // вкл CTC
TIMSK2 |= (1<<OCIE2A); //Вкл прерывание
if(freq < 122){ // максимальный делитель
TCCR2B = 0x7; // присвоили делитель
OCR2A = (15625/freq)-1; // рассчитали top для CTC
}
if(freq > 244){ // минимальный делитель
TCCR2B = 0x5; // по аналогии см выше
OCR2A = (62500/freq)-1; // по аналогии см выше
}
else { // средний делитель
TCCR2B = 0x6; // по аналогии см выше
OCR2A = (125000/freq)-1; // по аналогии см выше
}
toggle_counter = 0; // обнулили счетчик toggl'ов
}
// timerx_toggle_count:
// > 0 - duration specified
// = 0 - stopped
// < 0 - infinitely (until stop() method called, or new play() called)
#if !defined(__AVR_ATmega8__)
volatile long timer0_toggle_count;
volatile uint8_t *timer0_pin_port;
volatile uint8_t timer0_pin_mask;
#endif
volatile long timer1_toggle_count;
volatile uint8_t *timer1_pin_port;
volatile uint8_t timer1_pin_mask;
volatile long timer2_toggle_count;
volatile uint8_t *timer2_pin_port;
volatile uint8_t timer2_pin_mask;
#if defined(TIMSK3)
volatile long timer3_toggle_count;
volatile uint8_t *timer3_pin_port;
volatile uint8_t timer3_pin_mask;
#endif
#if defined(TIMSK4)
volatile long timer4_toggle_count;
volatile uint8_t *timer4_pin_port;
volatile uint8_t timer4_pin_mask;
#endif
#if defined(TIMSK5)
volatile long timer5_toggle_count;
volatile uint8_t *timer5_pin_port;
volatile uint8_t timer5_pin_mask;
#endif
#if defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__)
#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 3, 4, 5, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255, 255, 255, 255 */ };
#elif defined(__AVR_ATmega8__)
#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
#elif defined(__AVR_ATmega32U4__)
#define AVAILABLE_TONE_PINS 1
#define USE_TIMER3
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 3 /*, 1 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255 */ };
#else
#define AVAILABLE_TONE_PINS 1
#define USE_TIMER2
// Leave timer 0 to last.
const uint8_t PROGMEM tone_pin_to_timer_PGM[] = { 2 /*, 1, 0 */ };
static uint8_t tone_pins[AVAILABLE_TONE_PINS] = { 255 /*, 255, 255 */ };
#endif
static int8_t toneBegin(uint8_t _pin)
{
int8_t _timer = -1;
// if we're already using the pin, the timer should be configured.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
return pgm_read_byte(tone_pin_to_timer_PGM + i);
}
}
// search for an unused timer.
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == 255) {
tone_pins[i] = _pin;
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
break;
}
}
if (_timer != -1)
{
// Set timer specific stuff
// All timers in CTC mode
// 8 bit timers will require changing prescalar values,
// whereas 16 bit timers are set to either ck/1 or ck/64 prescalar
switch (_timer)
{
#if defined(TCCR0A) && defined(TCCR0B) && defined(WGM01)
case 0:
// 8 bit timer
TCCR0A = 0;
TCCR0B = 0;
bitWrite(TCCR0A, WGM01, 1);
bitWrite(TCCR0B, CS00, 1);
timer0_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer0_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR1A) && defined(TCCR1B) && defined(WGM12)
case 1:
// 16 bit timer
TCCR1A = 0;
TCCR1B = 0;
bitWrite(TCCR1B, WGM12, 1);
bitWrite(TCCR1B, CS10, 1);
timer1_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer1_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR2A) && defined(TCCR2B)
case 2:
// 8 bit timer
TCCR2A = 0;
TCCR2B = 0;
bitWrite(TCCR2A, WGM21, 1);
bitWrite(TCCR2B, CS20, 1);
timer2_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer2_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR3A) && defined(TCCR3B) && defined(TIMSK3)
case 3:
// 16 bit timer
TCCR3A = 0;
TCCR3B = 0;
bitWrite(TCCR3B, WGM32, 1);
bitWrite(TCCR3B, CS30, 1);
timer3_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer3_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR4A) && defined(TCCR4B) && defined(TIMSK4)
case 4:
// 16 bit timer
TCCR4A = 0;
TCCR4B = 0;
#if defined(WGM42)
bitWrite(TCCR4B, WGM42, 1);
#elif defined(CS43)
// TODO this may not be correct
// atmega32u4
bitWrite(TCCR4B, CS43, 1);
#endif
bitWrite(TCCR4B, CS40, 1);
timer4_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer4_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
#if defined(TCCR5A) && defined(TCCR5B) && defined(TIMSK5)
case 5:
// 16 bit timer
TCCR5A = 0;
TCCR5B = 0;
bitWrite(TCCR5B, WGM52, 1);
bitWrite(TCCR5B, CS50, 1);
timer5_pin_port = portOutputRegister(digitalPinToPort(_pin));
timer5_pin_mask = digitalPinToBitMask(_pin);
break;
#endif
}
}
return _timer;
void noTone(uint8_t pin){ // если вызван noTone
digitalWrite(pin,0);// устанавливаем 0 на выходе
TIMSK2 &=~ (1<<OCIE2A); // остановить прерывания
TCCR2A = 0b00000011; // установить стандартные настройки для таймера 2
TCCR2B = 0b00000100;
OCR2A = 0; //обнуляем регистр сравнения
TCCR2A &=~ ((1<<COM2A1)|(1<<COM2B1)); // откл регистры сравнения (подстраховка)
}
// frequency (in hertz) and duration (in milliseconds).
void tone(uint8_t _pin, unsigned int frequency, unsigned long duration)
{
uint8_t prescalarbits = 0b001;
long toggle_count = 0;
uint32_t ocr = 0;
int8_t _timer;
_timer = toneBegin(_pin);
if (_timer >= 0)
{
// Set the pinMode as OUTPUT
pinMode(_pin, OUTPUT);
// if we are using an 8 bit timer, scan through prescalars to find the best fit
if (_timer == 0 || _timer == 2)
{
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001; // ck/1: same for both timers
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 8 - 1;
prescalarbits = 0b010; // ck/8: same for both timers
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 32 - 1;
prescalarbits = 0b011;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = _timer == 0 ? 0b011 : 0b100;
if (_timer == 2 && ocr > 255)
{
ocr = F_CPU / frequency / 2 / 128 - 1;
prescalarbits = 0b101;
}
if (ocr > 255)
{
ocr = F_CPU / frequency / 2 / 256 - 1;
prescalarbits = _timer == 0 ? 0b100 : 0b110;
if (ocr > 255)
{
// can't do any better than /1024
ocr = F_CPU / frequency / 2 / 1024 - 1;
prescalarbits = _timer == 0 ? 0b101 : 0b111;
}
}
}
}
#if defined(TCCR0B)
if (_timer == 0)
{
TCCR0B = (TCCR0B & 0b11111000) | prescalarbits;
}
else
#endif
#if defined(TCCR2B)
{
TCCR2B = (TCCR2B & 0b11111000) | prescalarbits;
}
#else
{
// dummy place holder to make the above ifdefs work
}
#endif
}
else
{
// two choices for the 16 bit timers: ck/1 or ck/64
ocr = F_CPU / frequency / 2 - 1;
prescalarbits = 0b001;
if (ocr > 0xffff)
{
ocr = F_CPU / frequency / 2 / 64 - 1;
prescalarbits = 0b011;
}
if (_timer == 1)
{
#if defined(TCCR1B)
TCCR1B = (TCCR1B & 0b11111000) | prescalarbits;
#endif
}
#if defined(TCCR3B)
else if (_timer == 3)
TCCR3B = (TCCR3B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR4B)
else if (_timer == 4)
TCCR4B = (TCCR4B & 0b11111000) | prescalarbits;
#endif
#if defined(TCCR5B)
else if (_timer == 5)
TCCR5B = (TCCR5B & 0b11111000) | prescalarbits;
#endif
}
// Calculate the toggle count
if (duration > 0)
{
toggle_count = 2 * frequency * duration / 1000;
}
else
{
toggle_count = -1;
}
// Set the OCR for the given timer,
// set the toggle count,
// then turn on the interrupts
switch (_timer)
{
#if defined(OCR0A) && defined(TIMSK0) && defined(OCIE0A)
case 0:
OCR0A = ocr;
timer0_toggle_count = toggle_count;
bitWrite(TIMSK0, OCIE0A, 1);
break;
#endif
case 1:
#if defined(OCR1A) && defined(TIMSK1) && defined(OCIE1A)
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK1, OCIE1A, 1);
#elif defined(OCR1A) && defined(TIMSK) && defined(OCIE1A)
// this combination is for at least the ATmega32
OCR1A = ocr;
timer1_toggle_count = toggle_count;
bitWrite(TIMSK, OCIE1A, 1);
#endif
break;
#if defined(OCR2A) && defined(TIMSK2) && defined(OCIE2A)
case 2:
OCR2A = ocr;
timer2_toggle_count = toggle_count;
bitWrite(TIMSK2, OCIE2A, 1);
break;
#endif
#if defined(OCR3A) && defined(TIMSK3) && defined(OCIE3A)
case 3:
OCR3A = ocr;
timer3_toggle_count = toggle_count;
bitWrite(TIMSK3, OCIE3A, 1);
break;
#endif
#if defined(OCR4A) && defined(TIMSK4) && defined(OCIE4A)
case 4:
OCR4A = ocr;
timer4_toggle_count = toggle_count;
bitWrite(TIMSK4, OCIE4A, 1);
break;
#endif
#if defined(OCR5A) && defined(TIMSK5) && defined(OCIE5A)
case 5:
OCR5A = ocr;
timer5_toggle_count = toggle_count;
bitWrite(TIMSK5, OCIE5A, 1);
break;
#endif
}
}
ISR(TIMER2_COMPA_vect){ // прерывание генерации
if(toggle_counter < toggle_top || !willStop ){ // если количество toggl'ов не достигло предела или процесс бесконечен - генерация
digitalToggle(tone_pin); // иневертируем состоние на ноге
toggle_counter++; // икремент счетчика
}
}
// XXX: this function only works properly for timer 2 (the only one we use
// currently). for the others, it should end the tone, but won't restore
// proper PWM functionality for the timer.
void disableTimer(uint8_t _timer)
{
switch (_timer)
{
case 0:
#if defined(TIMSK0)
TIMSK0 = 0;
#elif defined(TIMSK)
TIMSK = 0; // atmega32
#endif
break;
#if defined(TIMSK1) && defined(OCIE1A)
case 1:
bitWrite(TIMSK1, OCIE1A, 0);
break;
#endif
case 2:
#if defined(TIMSK2) && defined(OCIE2A)
bitWrite(TIMSK2, OCIE2A, 0); // disable interrupt
#endif
#if defined(TCCR2A) && defined(WGM20)
TCCR2A = (1 << WGM20);
#endif
#if defined(TCCR2B) && defined(CS22)
TCCR2B = (TCCR2B & 0b11111000) | (1 << CS22);
#endif
#if defined(OCR2A)
OCR2A = 0;
#endif
break;
#if defined(TIMSK3) && defined(OCIE3A)
case 3:
bitWrite(TIMSK3, OCIE3A, 0);
break;
#endif
#if defined(TIMSK4) && defined(OCIE4A)
case 4:
bitWrite(TIMSK4, OCIE4A, 0);
break;
#endif
#if defined(TIMSK5) && defined(OCIE5A)
case 5:
bitWrite(TIMSK5, OCIE5A, 0);
break;
#endif
}
}
void noTone(uint8_t _pin)
{
int8_t _timer = -1;
for (int i = 0; i < AVAILABLE_TONE_PINS; i++) {
if (tone_pins[i] == _pin) {
_timer = pgm_read_byte(tone_pin_to_timer_PGM + i);
tone_pins[i] = 255;
break;
}
}
disableTimer(_timer);
digitalWrite(_pin, 0);
}
#ifdef USE_TIMER0
ISR(TIMER0_COMPA_vect)
{
if (timer0_toggle_count != 0)
{
// toggle the pin
*timer0_pin_port ^= timer0_pin_mask;
if (timer0_toggle_count > 0)
timer0_toggle_count--;
}
else
{
disableTimer(0);
*timer0_pin_port &= ~(timer0_pin_mask); // keep pin low after stop
}
}
#endif
#ifdef USE_TIMER1
ISR(TIMER1_COMPA_vect)
{
if (timer1_toggle_count != 0)
{
// toggle the pin
*timer1_pin_port ^= timer1_pin_mask;
if (timer1_toggle_count > 0)
timer1_toggle_count--;
}
else
{
disableTimer(1);
*timer1_pin_port &= ~(timer1_pin_mask); // keep pin low after stop
}
}
#endif
#ifdef USE_TIMER2
ISR(TIMER2_COMPA_vect)
{
if (timer2_toggle_count != 0)
{
// toggle the pin
*timer2_pin_port ^= timer2_pin_mask;
if (timer2_toggle_count > 0)
timer2_toggle_count--;
}
else
{
// need to call noTone() so that the tone_pins[] entry is reset, so the
// timer gets initialized next time we call tone().
// XXX: this assumes timer 2 is always the first one used.
noTone(tone_pins[0]);
// disableTimer(2);
// *timer2_pin_port &= ~(timer2_pin_mask); // keep pin low after stop
}
}
#endif
#ifdef USE_TIMER3
ISR(TIMER3_COMPA_vect)
{
if (timer3_toggle_count != 0)
{
// toggle the pin
*timer3_pin_port ^= timer3_pin_mask;
if (timer3_toggle_count > 0)
timer3_toggle_count--;
}
else
{
disableTimer(3);
*timer3_pin_port &= ~(timer3_pin_mask); // keep pin low after stop
}
}
#endif
#ifdef USE_TIMER4
ISR(TIMER4_COMPA_vect)
{
if (timer4_toggle_count != 0)
{
// toggle the pin
*timer4_pin_port ^= timer4_pin_mask;
if (timer4_toggle_count > 0)
timer4_toggle_count--;
}
else
{
disableTimer(4);
*timer4_pin_port &= ~(timer4_pin_mask); // keep pin low after stop
}
}
#endif
#ifdef USE_TIMER5
ISR(TIMER5_COMPA_vect)
{
if (timer5_toggle_count != 0)
{
// toggle the pin
*timer5_pin_port ^= timer5_pin_mask;
if (timer5_toggle_count > 0)
timer5_toggle_count--;
}
else
{
disableTimer(5);
*timer5_pin_port &= ~(timer5_pin_mask); // keep pin low after stop
}
}
#endif

View File

@ -1,12 +1,13 @@
/* Главный цикл программы */
#include <Arduino.h>
int main(void)
{
WDTCSR = 0; // wdt disable
init();
setup();
while (1) {
loop();
if (serialEventRun) serialEventRun();
WDTCSR = 0; // Первым делом отключаем ватчдог
init(); // инициализация таймеров и ацп
setup(); // функция setup
while (1) { // бесконечный цикл
loop(); // функция loop
if (serialEventRun) serialEventRun(); // обслуживание serial
}
return 0;
}

View File

@ -1,6 +1,6 @@
#include "Arduino.h"
#include "timeControl.h"
/* функции времени и инициализация таймеров , АЦП*/
#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) // 1024
#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) // 1
#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) // 3
@ -10,7 +10,7 @@ volatile unsigned long timer0_overflow_count = 0;
volatile unsigned long timer0_millis = 0;
static unsigned char timer0_fract = 0;
#ifdef MILLIS_TMRS
#ifdef MILLIS_TMRS // переключатель, отключающий millis(), освобождающий вектор прерывания
ISR(TIMER0_OVF_vect)
{
timer0_millis++;
@ -24,20 +24,20 @@ ISR(TIMER0_OVF_vect)
#endif
unsigned long millis() {
cli();
unsigned long m = timer0_millis;
sei();
return m;
cli(); // остановить счет
unsigned long m = timer0_millis; // перехватить значение
sei(); // продолжить счет
return m; // вернуть миллисекунды
}
unsigned long micros() {
cli();
unsigned long m = timer0_overflow_count;
uint8_t t = TCNT0;
if ((TIFR0 & _BV(TOV0)) && (t < 255))
cli(); // остановить прерывания
unsigned long m = timer0_overflow_count; // счет переполнений
uint8_t t = TCNT0; // считать содержимое счетного регистра
if ((TIFR0 & _BV(TOV0)) && (t < 255)) //инкремент по переполнению
m++;
sei();
return (long)(((m << 8) + t) * 4);
sei(); // продолжить счет
return (long)(((m << 8) + t) * 4); // вернуть микросекунды
}
/*
@ -77,11 +77,11 @@ void delayMicroseconds(unsigned int us)
*/
void delay(unsigned long ms)
void delay(unsigned long ms)
{
uint32_t start = micros();
uint32_t start = micros(); // запомнили время старта
while (ms > 0) {
while (ms > 0) { // ведем отсчет
yield();
while ( ms > 0 && (micros() - start) >= 1000) {
ms--;
@ -91,15 +91,13 @@ void delay(unsigned long ms)
}
void delayMicroseconds(unsigned int us)
void delayMicroseconds(unsigned int us) // работает на счете тиков
{
#if F_CPU >= 16000000L
if (us <= 1) return; // = 3 cycles, (4 when true)
us <<= 2; // x4 us, = 4 cycles
us -= 5;
#endif
// busy wait
__asm__ __volatile__ (
"1: sbiw %0,1" "\n\t" // 2 cycles
@ -109,24 +107,24 @@ void delayMicroseconds(unsigned int us)
}
void init()
void init() // функция инициализации
{
cli();
cli();
/* timer 0 */
TCCR0A = 0b00000011; // fast pwm 8 bit
TCCR0B = 0b00000011; // prescaler 64
TIMSK0 |= (1<<TOIE0); // ovf interrupt enable
TCCR0B = 0b00000011; // делитель 64
TIMSK0 |= (1<<TOIE0); // ovf interrupt вкл
/* timer 1 */
TCCR1A = 0b00000001; // fast pwm 8 bit
TCCR1B = 0b00001011; // prescaler 64
TCCR1B = 0b00001011; // делитель 64
/* timer 2 */
TCCR2A = 0b00000011; // fast pwm 8 bit
TCCR2B = 0b00000100; // prescaler 64
TCCR2B = 0b00000100; // делитель 64
/* adc */
ADMUX = 0b01001111; // reference - vcc , adc parked to gnd
ADCSRA = 0b10000010; // prescaler - 4 [0,1,2 bits - prescaler]
ADMUX = 0b01001111; // reference - vcc , вход ацп припаркован к gnd
ADCSRA = 0b10000010; // делитель - 4 [0,1,2 bits - делитель]
/* ADC prescalers: 001 >> /2 010 >> /4 011 >> /8 100 >> /16 101 >> /32 110 >> /64 111 >> /128*/
/* UART */
UCSR0B = 0;
UCSR0B = 0; // пока не вызван Serial.begin / uartBegin выводы 0/1 свободны для работы.
sei();
}

View File

@ -1,46 +1,48 @@
#include "uart.h"
/* Реализация облегченного Serial от AlexGyver & Egor 'Nich1con' Zaharov*/
// ===== INIT =====
void uartBegin(uint32_t baudrate){
uint16_t speed = (2000000/baudrate)-1;
UBRR0H = highByte(speed);
void uartBegin(uint32_t baudrate){ // инициализация uart
uint16_t speed = (2000000/baudrate)-1; // расчет baudrate
UBRR0H = highByte(speed); // установка baudrate
UBRR0L = lowByte(speed);
UCSR0A = (1 << U2X0);
UCSR0B = ((1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0));
UCSR0C = ((1<<UCSZ01) | (1<<UCSZ00));
UCSR0A = (1 << U2X0); // вкл удвоенную скорость
UCSR0B = ((1<<TXEN0) | (1<<RXEN0) | (1<<RXCIE0)); // вкл uart
UCSR0C = ((1<<UCSZ01) | (1<<UCSZ00)); // настраиваем формат данных
}
void uartBegin(void) {
void uartBegin(void) { // вызов uartBegin без параметра настроит скорость 9600
uartBegin(9600);
}
void uartEnd(){
void uartEnd(){ // откл uart
UCSR0B = 0;
}
// ===== READ =====
volatile char _UART_RX_BUFFER[64];
volatile int8_t _UART_RX_COUNTER;
ISR(USART_RX_vect) {
_UART_RX_BUFFER[_UART_RX_COUNTER] = UDR0;
_UART_RX_COUNTER++;
ISR(USART_RX_vect) { // чекаем твои байты по прерыванию
_UART_RX_BUFFER[_UART_RX_COUNTER] = UDR0; // пишем в массив "буфер"
_UART_RX_COUNTER++;
}
char uartRead() {
char uartRead() { // чтение данных из буфера
char thisChar = _UART_RX_BUFFER[0];
for (byte i = 0; i < _UART_RX_COUNTER; i++) _UART_RX_BUFFER[i] = _UART_RX_BUFFER[i + 1];
if (--_UART_RX_COUNTER < 0) _UART_RX_COUNTER = 0;
return thisChar;
}
char uartPeek() {
boolean uartAvailable() { // проверка доступности данных в буфере
return _UART_RX_COUNTER;
}
/* Дальше он писал сам, там жесть полная */
char uartPeek() {
return _UART_RX_BUFFER[0];
}
boolean uartAvailable() {
return _UART_RX_COUNTER;
}
void uartClear() {
void uartClear() {
_UART_RX_COUNTER = 0;
}

View File

@ -1,4 +1,6 @@
#ifndef uart_h
/* Облегченный Serial */
#ifndef uart_h
#define uart_h
#include "Arduino.h"

View File

@ -1,29 +1,61 @@
/*
wiring_pulse.c - pulseIn() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
//#include "wiring_private.h"
//#include "pins_arduino.h"
#include "Arduino.h"
#define analogInPinToBit(P) (P)
extern const uint16_t PROGMEM port_to_mode_PGM[];
extern const uint16_t PROGMEM port_to_input_PGM[];
extern const uint16_t PROGMEM port_to_output_PGM[];
extern const uint8_t PROGMEM digital_pin_to_port_PGM[];
// extern const uint8_t PROGMEM digital_pin_to_bit_PGM[];
extern const uint8_t PROGMEM digital_pin_to_bit_mask_PGM[];
extern const uint8_t PROGMEM digital_pin_to_timer_PGM[];
#define digitalPinToPort(P) ( pgm_read_byte( digital_pin_to_port_PGM + (P) ) )
#define digitalPinToBitMask(P) ( pgm_read_byte( digital_pin_to_bit_mask_PGM + (P) ) )
#define digitalPinToTimer(P) ( pgm_read_byte( digital_pin_to_timer_PGM + (P) ) )
#define analogInPinToBit(P) (P)
#define portOutputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_output_PGM + (P))) )
#define portInputRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_input_PGM + (P))) )
#define portModeRegister(P) ( (volatile uint8_t *)( pgm_read_word( port_to_mode_PGM + (P))) )
#define NOT_A_PIN 0
#define NOT_A_PORT 0
#define NOT_AN_INTERRUPT -1
#define PA 1
#define PB 2
#define PC 3
#define PD 4
#define PE 5
#define PF 6
#define PG 7
#define PH 8
#define PJ 10
#define PK 11
#define PL 12
#define NOT_ON_TIMER 0
#define TIMER0A 1
#define TIMER0B 2
#define TIMER1A 3
#define TIMER1B 4
#define TIMER1C 5
#define TIMER2 6
#define TIMER2A 7
#define TIMER2B 8
#define TIMER3A 9
#define TIMER3B 10
#define TIMER3C 11
#define TIMER4A 12
#define TIMER4B 13
#define TIMER4C 14
#define TIMER4D 15
#define TIMER5A 16
#define TIMER5B 17
#define TIMER5C 18
const uint16_t PROGMEM port_to_mode_PGM[] = {
NOT_A_PORT,
NOT_A_PORT,

View File

@ -1,25 +1,4 @@
/*
wiring_shift.c - shiftOut() function
Part of Arduino - http://www.arduino.cc/
Copyright (c) 2005-2006 David A. Mellis
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library 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
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
/* Програмный SPI */
#include "Arduino.h"
uint8_t shiftIn(uint8_t dataPin, uint8_t clockPin, uint8_t bitOrder) {

View File

@ -40,6 +40,12 @@ uartParsePacket KEYWORD2
######################################
# Constants (LITERAL1)
#######################################
PWM_8BIT LITERAL1
PWM_10BIT LITERAL1
PWM_DEFAULT LITERAL1
PWM_8KHZ LITERAL1
PWM_31KHZ LITERAL1
THERMOMETR LITERAL1
A0 LITERAL1
A1 LITERAL1

View File

@ -1,5 +1,5 @@
# GyverCore for ATmega328p/168p
Быстрое ядро для Arduino IDE. **В разработке**
# GyverCore for ATmega328/168
Быстрое и лёгкое ядро для Arduino IDE.
Основано на оригинальном ядре Arduino версии 1.8.9, большинство функций заменены на более быстрые и лёгкие аналоги, убрано всё лишнее и не относящееся к микроконтроллеру ATmega328p, убран почти весь Wiring-мусор, код упрощён и причёсан.
## Установка
@ -14,12 +14,13 @@
- Листай в самый низ, пока не увидишь **GyverCore**
- Жми **Установка**
- Закрой окно
- Выбери плату в **Инструменты > Плата > GyverCore > ATmega328p based**
- Выбери плату в **Инструменты > Плата > GyverCore > ATmega328/168 based**
- Выбери в **CPU & BOOT** нужный вариант загрузчика
- Готово
- Готово!
- *Примечание*: файлы ядра находятся по пути *C:\Users\Username\AppData\Local\Arduino15\packages\GyverCore\hardware\avr\1.0.0\*
# Изменения
## Облегчено и ускорено
## Изменения
### Облегчено и ускорено
Время выполнения функций, мкс
Функция | Arduino | GyverCore | Быстрее в
@ -31,7 +32,8 @@ analogWrite | 4.15 us | 1.13 us | 3.67
analogRead | 112.01 us | 5.41 us | 20.70
analogReference | 0.00 us | 0.69 us | 0.00
attachInterrupt | 1.20 us | 1.18 us | 1.02
detachInterrupt | 0.82 us | 0.57 us | 1.44
detachInterrupt | 0.82 us | 0.57 us | 1.44
tone | 5.63 us | 2.40 us | 2.3
Занимаемое место, Flash, байт
@ -44,18 +46,22 @@ analogWrite | 406 | 48 | 358
analogRead | 32 | 72 | -40
analogReference | 0 | 32 | -32
attachInterrupt | 212 | 180 | 32
detachInterrupt | 198 | 150 | 48
detachInterrupt | 198 | 150 | 48
tone | 1410 | 740 | 670
Serial.begin | 1028 | 166 | 862
print long | 1094 | 326 | 768
print string | 2100 | 1484 | 616
print float | 2021 | 446 | 1575
parseInt | 1030 | 214 | 816
readString | 2334 | 1594 | 740
parseFloat | 1070 | 246 | 824
parseFloat | 1070 | 246 | 824
Примечание: analogRead и analogReference имеют расширенную функциональность и весят чуть больше
Примечание: analogRead и analogReference имеют расширенную функциональность и весят чуть больше
Скетч, состоящий из однократного вызова перечисленных выше функций, занимает
- Ядро Arduino: 3446 байт (11%) Flash / 217 байт (10%) SRAM
- Ядро GyverCore: 1436 байт (4%) Flash / 94 байт (4%) SRAM
## Добавлено
### Добавлено
- Подсветка в коде **A0**, **A1**.. **A7**
- Макрос **bitToggle**(value, bit), инвертирует состояние бита bit в байте value
- Функция **digitalToggle**(pin), инвертирует состояние пина
@ -86,12 +92,16 @@ parseFloat | 1070 | 246 | 824
- **uartParseFloat()** - принять число float
- **uartParsePacket(dataArray)** - принять пакет вида **$50 60 70;** в массив dataArray (смотри пример)
### Убарно
Убраны всякие сервисные файлы и прочий хлам, не относящийся к ATmega328 (wifi, USB). Ядро полностью совместимо с остальными библиотеками, ничего из стандартных функций не вырезано.
## Дополнительно
### Настройки прошивки
- Добавлен вариант прошивки без загрузчика (во всю доступную Flash память) для прошивки через ISP
- Добавлен вариант прошивки с отключенными функциями времени (освобождает вектор **TIMER0_OVF_vect** для личного пользования)
- Смотри примеры в папке examples (в корне этого репозитория!)
- Добавлен вариант прошивки без загрузчика **ATmega 328/168 without bootloader** (во всю доступную Flash память) для прошивки через ISP
- Добавлен вариант прошивки с отключенными функциями времени **with/without millis** (освобождает вектор **TIMER0_OVF_vect** для личного пользования)
### Больше контроля!
## Больше контроля!
Для большего контроля за периферией микроконтроллера рекомендую попробовать следующие наши библиотеки:
- **directTimers** - полный контроль над таймерами/счётчиками ATmega328
- **directADC** - полный контроль над АЦП и компаратором ATmega328

View File

@ -0,0 +1,22 @@
void setup() {
setPWM_20kHz(5); // частота шим на D5 установлена на 20 кГц
// ШИМ на выходе D6 больше не рабоатет!
// функции времени (millis/delay) теперь работают некорректно
analogWrite(5, 30); // запустить ШИМ на D5
setPwmFreqnuency(3, PWM_31KHZ); // частота ШИМ на пинах 3 (и на 11) установлена на 31 кГц
analogWrite(3, 30); // запустить ШИМ на D3
analogWrite(11, 200); // запустить ШИМ на D11
setPWM_20kHz(9); // частота шим на D9 (и автоматичсеки на D10) установлена на 20 кГц
// разрядность по умолчанию 8 бит (0-255)
setPWM_9_10_resolution(PWM_10BIT); // ШИМ на пинах 9 и 10 теперь 10 битный (0-1023)
analogWrite(9, 512); // ШИМ на пине 9 с 50% заполнением
analogWrite(10, 700); // ШИМ на пине 9 с заполнением 700/1023
}
void loop() {
}

View File

@ -0,0 +1,28 @@
// скетч для проверки занимаемой памяти
void setup() {
pinMode(2, 1);
digitalWrite(1, 1);
digitalRead(0);
analogRead(0);
analogReference(DEFAULT);
analogWrite(9, 125);
millis();
micros();
delay(10);
delayMicroseconds(10);
tone(10, 10);
tone(10, 10, 100);
attachInterrupt(0, isr, 0);
detachInterrupt(0);
//uartBegin();
//uartPrintln("kek OK");
Serial.begin(9600);
Serial.println("kek OK");
}
void isr(){}
void loop() {
// put your main code here, to run repeatedly:
}

View File

@ -0,0 +1,21 @@
// пример работы с функцией uartParsePacket
// функция принимает из порта строку вида
// $10 21 458 63 8 45 875 215;
// и запихивает в массив dataArray
int dataArray[8];
void setup() {
uartBegin(); // открыть на 9600
}
void loop() {
// $10 21 458 63 8 45 875 215;
if (uartParsePacket((int*)dataArray)) {
for (byte i = 0; i < 8; i++) {
uartPrint(dataArray[i]);
uartPrint(" ");
}
uartPrintln();
}
}

View File

@ -0,0 +1,37 @@
// тест вывода в порт разных типов данных
int8_t data1 = -50;
uint8_t data2 = 125;
int16_t data3 = -2000;
uint16_t data4 = 30000;
int32_t data5 = -70000;
uint32_t data6 = 4194967295;
float data7 = 3681.65424;
float data8 = -4375.12353;
String data9 = "LOL LOL";
const char *data10[] = {
"LOL",
"KEK",
"CHEBUREK",
};
void setup() {
uartBegin();
uartPrintln(data1);
uartPrintln(data2);
uartPrintln(data3);
uartPrintln(data4);
uartPrintln(data5);
uartPrintln(data6);
uartPrintln(data7);
uartPrintln(data8, 3);
uartPrintln(data9);
uartPrintln("KEK KEK");
uartPrintln(F("KEK KEK MACRO"));
uartPrintln(data10[2]);
}
void loop() {
}

View File

@ -16,10 +16,10 @@
"category": "Contributed",
"url": "https://github.com/AlexGyver/GyverCore/releases/download/GyverCore/GyverCore.zip",
"archiveFileName": "GyverCore.zip",
"checksum": "MD5:758f491c55f177cca874f20eaf1d6e63",
"size": "139848",
"checksum": "MD5:c304d158e055df8911457ed1aa42fae4",
"size": "137283",
"boards": [
{"name": "ATmega328 boards"}
{"name": "ATmega328/168 based boards"}
],
"toolsDependencies": []
}