Изменения в библиотеке DigitalPins
- Войдите на сайт для отправки комментариев
Сб, 30/03/2019 - 19:18
Я тут недавно с удивлением обнаружил, что разработанной когда-то по моей просьбе библиотекой DigitalPins пользуюсь не я один. Потому решил выложить сделанные сегодня изменения.
Изменение позволяет использовать пины XTAL1, XTAL2 и RESET как обычные GPIO в ATmega328 (раньше они не поддерживались).
Только прошу правильно понять. Выкладываю исключительно потому, что увидел её в «Проектах». Факт выкладывания не означает, что она стала «поставляться». Она по-прежнему является внутренней поделкой для внутреннего пользования. Использовать или не использовать её Вы можете только на собственный страх и риск.
/////////////////////////////////////////////////////////////////////////////////
//
// Только ATmega328P и ATtiny25/45/85
//
// 1. Не является универсальной библиотекой и не предназначена для распространения
//
// 2. Групповые операции доступны только если оперелить #define GROUP_OPERATIONS
// 2.1 РИСК групповых операций - они НЕ ПРОВЕРЯЮТ, что все пины от одного и того
// же порта, просто берут порт первого пина и сичтают, что остальные пины там же
// 2.2 БЕНЕФИТ групповых операций. Они сделаны так, что все пины изменяются
// точно одновременно - ОДНОЙ командой процессора. Иногда это важно, например,
// если нужно, чтобы два сигнала шли точно в одинаковой фазе. В этих
// случаях лучше воспользоваться digitalWrite на два пина, чем двумя по пину,
// хотя последнее и эффективнее. Потому, кстати, нет никакого смысла в
// мультипортовых групповых операциях - два порта одной командой не изменишь.
//
// 3. Если этот текст как-то попал к Вам, это Ваши проблемы. Автор не несёт никаких
// обязательств ни перед кем, ни в каком случае.
// Текст исключительно для внутреннего использования.
//
// Используем операции с одним подчерком. Операции с большим количество подчерков - внутренняя кухня
//
// Перечень операций
//
// _pinMode(pin,state)
// _digitalWrite(pin,val)
// _digitalRead(pin)
// _pinInvert(pin) // Инвертирование пина
// _pinPulse(pin) // Инвертируется на 1 такт
// _pulseHigh(pin) // Высокий импульс в 1 такт
// _pulseLow(pin) // Низкий импульс в 1 такт
//
// Групповые операции N - 2-8
// _digitalWriteN(p1,...,pN,val)
// _pulseHighN(p1,...,pN)
// _pulseLowN(p1,...,pN)
// _pinInvertN(p1,...,pN)
// _pinPulseN(p1,...,pN)
// _digitalReadN(p1,...,pN) // выдаёт байт, пины можно снимать битовой маской
//
/////////////////////////////////////////
#ifndef DigitalPins_h
#define DigitalPins_h
#define USE_XTAL_PINS
#define USE_RESET_PIN
#define lowByte(w) ((uint8_t) ((w) & 0xff))
#define highByte(w) ((uint8_t) ((w) >> 8))
#define bit(b) (1UL << (b))
#ifndef INPUT
#define INPUT 0x0
#endif // !INPUT
#ifndef OUTPUT
#define OUTPUT 0x1
#endif // !OUTPUT
#ifndef INPUT_PULLUP
#define INPUT_PULLUP 0x2
#endif // !INPUT_PULLUP
#ifndef HIGH
#define HIGH 0x1
#endif // !HIGH
#ifndef LOW
#define LOW 0x0
#endif // !LOW
#define __AVR_ATtinyDetected__ (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__))
#if (!__AVR_ATtinyDetected__) && (!defined(__AVR_ATmega328P__))
#ifndef IGNORE_CPU_CHECK
#error The library has been well tested for ATmega328P and ATtiny25/45/85 only. Define IGNORE_CPU_CHECK option to ignore this check.
#endif // !IGNORE_CPU_CHECK
#endif // (!__AVR_ATtinyDetected__) && (!defined(__AVR_ATmega328P__))
//////////////////////////////////////////////////////////////
//
// Маски для битов групповых операций
//
#define __orMask2(m1,m2) ((unsigned char)((m1) | (m2)))
#define __orMask3(m1,m2,m3) ((unsigned char)(__orMask2(m1,m2) | (m3)))
#define __orMask4(m1,m2,m3,m4) ((unsigned char)(__orMask3(m1,m2,m3) | (m4)))
#define __orMask5(m1,m2,m3,m4,m5) ((unsigned char)(__orMask4(m1,m2,m3,m4) | (m5)))
#define __orMask6(m1,m2,m3,m4,m5,m6) ((unsigned char)(__orMask5(m1,m2,m3,m4,m5) | (m6)))
#define __orMask7(m1,m2,m3,m4,m5,m6,m7) ((unsigned char)(__orMask6(m1,m2,m3,m4,m5,m6) | (m7)))
#define __orMask8(m1,m2,m3,m4,m5,m6,m7,m8) ((unsigned char)(__orMask7(m1,m2,m3,m4,m5,m6,m7) | (m8)))
#define ERROR_BIT 255
#if __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// У ATtiny есть единственный порт B,
// а номера пинов совпадают с номерами битов
//
#define __pin2Port(pin) (PORTB)
#define __pin2DirectionPort(pin) (DDRB)
#define __pin2InputPort(pin) (PINB)
#define __pin2PortBit(pin) (pin)
#else // Не __AVR_ATtinyDetected__
#define A0 14
#define A1 15
#define A2 16
#define A3 17
#define A4 18
#define A5 19
#ifdef USE_XTAL_PINS
// (PCINT6/XTAL1/TOSC1) PB6
// (PCINT7/XTAL2/TOSC2) PB7
#define XTAL1_PIN 20
#define XTAL2_PIN 21
#define EXT_PORTB_PINN(pin) (((pin) == XTAL1_PIN || (pin) == XTAL2_PIN) ? ((pin)-(XTAL1_PIN-6)) :
#define EXT_PORTB_PINS(pin) || ((pin) == XTAL1_PIN) || ((pin) == XTAL2_PIN)
#else
#define EXT_PORTB_PINS(pin)
#define EXT_PORTB_PINN(pin) (
#endif
#ifdef USE_RESET_PIN
// (PCINT14/RESET) PC6
#define RESET_PIN 22
#define EXT_PORTC_PIN(pin) || ((pin) == RESET_PIN)
#define EXT_PORTC_PINN(pin) (((pin) == RESET_PIN) ? 6 :
#else
#define EXT_PORTC_PIN(pin)
#define EXT_PORTC_PINN(pin) (
#endif
//////////////////////////////////////////////////////////////
//
// Выбор порта и бита по пину для ATmega328
//
#define ERROR_PORT _SFR_IO8(255)
#define ___pin2Port(pin, portD, portB, portC) \
(((pin) < 8) ? (portD) : \
(((pin) >= 8 && (pin) < 14) EXT_PORTB_PINS(pin) ? (portB) : \
(((pin) >= A0 && (pin) <= A5) EXT_PORTC_PIN(pin) ? (portC) : ERROR_PORT)))
#define __pin2Port(pin) ___pin2Port(pin, PORTD, PORTB, PORTC)
#define __pin2DirectionPort(pin) ___pin2Port(pin, DDRD, DDRB, DDRC)
#define __pin2InputPort(pin) ___pin2Port(pin,PIND,PINB,PINC)
#define __pin2PortBit(pin) \
(((pin) < 8) ? (pin) : \
(((pin) >= 8 && (pin) < 14) ? ((pin)-8) : \
EXT_PORTB_PINN(pin) \
EXT_PORTC_PINN(pin) \
(((pin) >= A0 && (pin) <= A5) ? ((pin)-A0) : ERROR_BIT)))))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Битовые маски из номеров пинов
//
#define __pin2Mask(pin) (1 << __pin2PortBit(pin))
#define __orPin2(p1,p2) __orMask2(__pin2Mask(p1),__pin2Mask(p2))
#define __orPin3(p1,p2,p3) __orMask3(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3))
#define __orPin4(p1,p2,p3,p4) __orMask4(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4))
#define __orPin5(p1,p2,p3,p4,p5) __orMask5(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5))
#define __orPin6(p1,p2,p3,p4,p5,p6) __orMask6(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6))
#define __orPin7(p1,p2,p3,p4,p5,p6,p7) __orMask7(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6),__pin2Mask(p7))
#define __orPin8(p1,p2,p3,p4,p5,p6,p7,p8) __orMask8(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6),__pin2Mask(p7),__pin2Mask(p8))
//////////////////////////////////////////////////////////////
//
// Внутренняя реализация основных операций
//
#define __pinHigh(port,mask) ((port) |= (mask))
#define __pinLow(port,mask) ((port) &= ~(mask))
#define __digitalWrite(port,mask,val) (((val)!=LOW) ? (__pinHigh(port,mask)) : (__pinLow(port,mask)))
#define __pinInvert(port,mask) ((port) |= (mask))
#define __pinModeOutput(dirport,mask) ((dirport) |= (mask))
#define __pinModeInput(dirport, mask) ((dirport) &= ~(mask))
#define __pinModeInputPullUp(port,dirport,mask) { unsigned char oldSREG = SREG; cli(); (dirport) &= ~(mask); (port) |= (mask); SREG = oldSREG; }
#define __pinMode(pin,state,mask) ((state) == INPUT) ? (__pinModeInput(__pin2DirectionPort(pin), mask)) : \
((state) == INPUT_PULLUP) ? (__pinModeInputPullUp(__pin2Port(pin), __pin2DirectionPort(pin), mask)) : \
((state) == OUTPUT) ? (__pinModeOutput(__pin2DirectionPort(pin), mask)) : (__pinModeOutput(__pin2DirectionPort(pin),0))
//////////////////////////////////////////////////////////////
//
// Основные операции с единичным пином
//
#define _pinMode(pin,state) __pinMode(pin,state,__pin2Mask(pin))
#define _digitalWrite(pin,val) __digitalWrite(__pin2Port(pin),__pin2Mask(pin),val)
#define _digitalRead(pin) (((__pin2InputPort(pin)) & (__pin2Mask(pin))) ? HIGH : LOW)
#define _pulseHigh(pin) do { unsigned char oldSREG = SREG; cli(); _digitalWrite(pin,HIGH); _digitalWrite(pin,LOW); SREG = oldSREG; } while(false)
#define _pulseLow(pin) do { unsigned char oldSREG = SREG; cli(); _digitalWrite(pin,LOW); _digitalWrite(pin,HIGH); SREG = oldSREG; } while(false)
#define _pinPulse(pin) do { unsigned char oldSREG = SREG; cli(); _pinInvert(pin); _pinInvert(pin); SREG = oldSREG; } while(false)
#define _pinInvert(pin) __pinInvert(__pin2InputPort(pin),__pin2Mask(pin))
#if defined(GROUP_OPERATIONS)
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// ГРУППОВЫЕ ОРПЕРАЦИИ
//
//
// Групповой pulseLow по маске (внутренняя операция)
//
#define __pulseLow(port,mask) \
asm volatile ( \
"in __tmp_reg__,__SREG__ \n\t" \
"cli \n\t" \
"in r24,%0 \n\t" \
"mov r23,r24 \n\t" \
"or r24,%1 \n\t" \
"com %1 \n\t" \
"and r23,%1 \n\t" \
"out %0,r23 \n\t" \
"out %0,r24 \n\t" \
"out __SREG__,__tmp_reg__ \n\t" \
: : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24", "r23" \
)
//////////////////////////////////////////////////////////////
//
// Групповой pulseHigh по маске (внутренняя операция)
//
#define __pulseHigh(port,mask) \
asm volatile ( \
"in __tmp_reg__,__SREG__ \n\t" \
"cli \n\t" \
"in r24,%0 \n\t" \
"mov r23,r24 \n\t" \
"or r24,%1 \n\t" \
"com %1 \n\t" \
"and r23,%1 \n\t" \
"out %0,r24 \n\t" \
"out %0,r23 \n\t" \
"out __SREG__,__tmp_reg__ \n\t" \
: : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24", "r23" \
)
//////////////////////////////////////////////////////////////
//
// Групповой Invert по маске (внутренняя операция)
//
#define __Invert(port,mask) \
asm volatile ( \
"in __tmp_reg__,__SREG__ \n\t" \
"cli \n\t" \
"in r24,%0 \n\t" \
"or r24,%1 \n\t" \
"out %0,r24 \n\t" \
"out __SREG__,__tmp_reg__ \n\t" \
: : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24" \
)
//////////////////////////////////////////////////////////////
//
// Групповой двойной Invert по маске (внутренняя операция)
//
#define __2Invert(port,mask) \
asm volatile ( \
"in __tmp_reg__,__SREG__ \n\t" \
"cli \n\t" \
"in r24,%0 \n\t" \
"or r24,%1 \n\t" \
"out %0,r24 \n\t" \
"out %0,r24 \n\t" \
"out __SREG__,__tmp_reg__ \n\t" \
: : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24" \
)
//////////////////////////////////////////////////////////////
//
// Групповой _digitalWrite
//
#define _digitalWrite2(p1,p2,val) __digitalWrite(__pin2Port(p1),__orPin2(p1,p2),val)
#define _digitalWrite3(p1,p2,p3,val) __digitalWrite(__pin2Port(p1),__orPin3(p1,p2,p3),val)
#define _digitalWrite4(p1,p2,p3,p4,val) __digitalWrite(__pin2Port(p1),__orPin4(p1,p2,p3,p4),val)
#define _digitalWrite5(p1,p2,p3,p4,p5,val) __digitalWrite(__pin2Port(p1),__orPin5(p1,p2,p3,p4,p5),val)
#define _digitalWrite6(p1,p2,p3,p4,p5,p6,val) __digitalWrite(__pin2Port(p1),__orPin6(p1,p2,p3,p4,p5,p6),val)
#if !__AVR_ATtinyDetected__
#define _digitalWrite7(p1,p2,p3,p4,p5,p6,p7,val) __digitalWrite(__pin2Port(p1),__orPin7(p1,p2,p3,p4,p5,p6,p7),val)
#define _digitalWrite8(p1,p2,p3,p4,p5,p6,p7,p8,val) __digitalWrite(__pin2Port(p1),__orPin8(p1,p2,p3,p4,p5,p6,p7,p8),val)
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Групповой _pulseHigh
//
#define _pulseHigh2(p1,p2) __pulseHigh(__pin2Port(p1),__orPin2(p1,p2))
#define _pulseHigh3(p1,p2,p3) __pulseHigh(__pin2Port(p1),__orPin3(p1,p2,p3))
#define _pulseHigh4(p1,p2,p3,p4) __pulseHigh(__pin2Port(p1),__orPin4(p1,p2,p3,p4))
#define _pulseHigh5(p1,p2,p3,p4,p5) __pulseHigh(__pin2Port(p1),__orPin5(p1,p2,p3, p4, p5))
#define _pulseHigh6(p1,p2,p3,p4,p5,p6) __pulseHigh(__pin2Port(p1),__orPin6(p1,p2, p3, p4, p5, p6))
#if !__AVR_ATtinyDetected__
#define _pulseHigh7(p1,p2,p3,p4,p5,p6,p7) __pulseHigh(__pin2Port(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7))
#define _pulseHigh8(p1,p2,p3,p4,p5,p6,p7,p8) __pulseHigh(__pin2Port(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Групповой _pulseLow
//
#define _pulseLow2(p1,p2) __pulseLow(__pin2Port(p1),__orPin2(p1,p2))
#define _pulseLow3(p1,p2,p3) __pulseLow(__pin2Port(p1),__orPin3(p1,p2,p3))
#define _pulseLow4(p1,p2,p3,p4) __pulseLow(__pin2Port(p1),__orPin4(p1,p2,p3,p4))
#define _pulseLow5(p1,p2,p3,p4,p5) __pulseLow(__pin2Port(p1),__orPin5(p1,p2,p3, p4, p5))
#define _pulseLow6(p1,p2,p3,p4,p5,p6) __pulseLow(__pin2Port(p1),__orPin6(p1,p2, p3, p4, p5, p6))
#if !__AVR_ATtinyDetected__
#define _pulseLow7(p1,p2,p3,p4,p5,p6,p7) __pulseLow(__pin2Port(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7))
#define _pulseLow8(p1,p2,p3,p4,p5,p6,p7,p8) __pulseLow(__pin2Port(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Групповой _pinInvert
//
#define _pinInvert2(p1,p2) __Invert(__pin2InputPort(p1),__orPin2(p1,p2))
#define _pinInvert3(p1,p2,p3) __Invert(__pin2InputPort(p1),__orPin3(p1,p2,p3))
#define _pinInvert4(p1,p2,p3,p4) __Invert(__pin2InputPort(p1),__orPin4(p1,p2,p3, p4))
#define _pinInvert5(p1,p2,p3,p4,p5) __Invert(__pin2InputPort(p1),__orPin5(p1,p2, p3, p4, p5))
#define _pinInvert6(p1,p2,p3,p4,p5,p6) __Invert(__pin2InputPort(p1),__orPin6(p1, p2, p3, p4, p5, p6))
#if !__AVR_ATtinyDetected__
#define _pinInvert7(p1,p2,p3,p4,p5,p6,p7) __Invert(__pin2InputPort(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7))
#define _pinInvert8(p1,p2,p3,p4,p5,p6,p7,p8) __Invert(__pin2InputPort(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Групповой _pinPulse
//
#define _pinPulse2(p1,p2) __2Invert(__pin2InputPort(p1),__orPin2(p1,p2))
#define _pinPulse3(p1,p2,p3) __2Invert(__pin2InputPort(p1),__orPin3(p1,p2,p3))
#define _pinPulse4(p1,p2,p3,p4) __2Invert(__pin2InputPort(p1),__orPin4(p1,p2,p3, p4))
#define _pinPulse5(p1,p2,p3,p4,p5) __2Invert(__pin2InputPort(p1),__orPin5(p1,p2, p3, p4, p5))
#define _pinPulse6(p1,p2,p3,p4,p5,p6) __2Invert(__pin2InputPort(p1),__orPin6(p1, p2, p3, p4, p5, p6))
#if !__AVR_ATtinyDetected__
#define _pinPulse7(p1,p2,p3,p4,p5,p6,p7) __2Invert(__pin2InputPort(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7))
#define _pinPulse8(p1,p2,p3,p4,p5,p6,p7,p8) __2Invert(__pin2InputPort(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Групповой _digitalRead
//
#define __read(port, mask) ((port) & (mask))
#define _digitalRead2(p1,p2) __read(__pin2InputPort(p1),__orPin2(p1,p2))
#define _digitalRead3(p1,p2,p3) __read(__pin2InputPort(p1),__orPin3(p1,p2,p3))
#define _digitalRead4(p1,p2,p3,p4) __read(__pin2InputPort(p1),__orPin4(p1,p2,p3,p4))
#define _digitalRead5(p1,p2,p3,p4,p5) __read(__pin2InputPort(p1),__orPin5(p1,p2,p3,p4,p5))
#define _digitalRead6(p1,p2,p3,p4,p5,p6) __read(__pin2InputPort(p1),__orPin6(p1,p2,p3,p4,p5,p6))
#if !__AVR_ATtinyDetected__
#define _digitalRead7(p1,p2,p3,p4,p5,p6,p7) __read(__pin2InputPort(p1),__orPin7(p1,p2,p3,p4,p5,p6,p7))
#define _digitalRead8(p1,p2,p3,p4,p5,p6,p7,p8) __read(__pin2InputPort(p1),__orPin8(p1,p2,p3,p4,p5,p6,p7,p8))
#endif // __AVR_ATtinyDetected__
//////////////////////////////////////////////////////////////
//
// Маски для проверки отдельных битов после группового _digitalRead
//
#define _pin0 __pin2Mask(0)
#define _pin1 __pin2Mask(1)
#define _pin2 __pin2Mask(2)
#define _pin3 __pin2Mask(3)
#define _pin4 __pin2Mask(4)
#define _pin5 __pin2Mask(5)
#if !__AVR_ATtinyDetected__
#define _pin6 __pin2Mask(6)
#define _pin7 __pin2Mask(7)
#define _pin8 __pin2Mask(8)
#define _pin9 __pin2Mask(9)
#define _pin10 __pin2Mask(10)
#define _pin11 __pin2Mask(11)
#define _pin12 __pin2Mask(12)
#define _pin13 __pin2Mask(13)
#define _pinA0 __pin2Mask(A0)
#define _pinA1 __pin2Mask(A1)
#define _pinA2 __pin2Mask(A2)
#define _pinA3 __pin2Mask(A3)
#define _pinA4 __pin2Mask(A4)
#define _pinA5 __pin2Mask(A5)
#endif // !__AVR_ATtinyDetected__
#endif // defined(GROUP_OPERATIONS)
#endif // DigitalPins_h
А маски для трёх новых пинов? Те, что в строках 378-399? Забыл? Или не посчитал нужным?
А ещё бы инверсию одной командой.
А маски для трёх новых пинов? Те, что в строках 378-399? Забыл? Или не посчитал нужным?
Забыл.
Вставьте, если не в лом, а то мне не до сук сегодня.
А ещё бы инверсию одной командой.
Это есть (и было давно, с самого начала) - _pinInvert(pin)
Вставьте, если не в лом
Не вопрос
///////////////////////////////////////////////////////////////////////////////// // // Только ATmega328P и ATtiny25/45/85 // // 1. Не является универсальной библиотекой и не предназначена для распространения // // 2. Групповые операции доступны только если оперелить #define GROUP_OPERATIONS // 2.1 РИСК групповых операций - они НЕ ПРОВЕРЯЮТ, что все пины от одного и того // же порта, просто берут порт первого пина и сичтают, что остальные пины там же // 2.2 БЕНЕФИТ групповых операций. Они сделаны так, что все пины изменяются // точно одновременно - ОДНОЙ командой процессора. Иногда это важно, например, // если нужно, чтобы два сигнала шли точно в одинаковой фазе. В этих // случаях лучше воспользоваться digitalWrite на два пина, чем двумя по пину, // хотя последнее и эффективнее. Потому, кстати, нет никакого смысла в // мультипортовых групповых операциях - два порта одной командой не изменишь. // // 3. Если этот текст как-то попал к Вам, это Ваши проблемы. Автор не несёт никаких // обязательств ни перед кем, ни в каком случае. // Текст исключительно для внутреннего использования. // // Используем операции с одним подчерком. Операции с большим количество подчерков - внутренняя кухня // // Перечень операций // // _pinMode(pin,state) // _digitalWrite(pin,val) // _digitalRead(pin) // _pinInvert(pin) // Инвертирование пина // _pinPulse(pin) // Инвертируется на 1 такт // _pulseHigh(pin) // Высокий импульс в 1 такт // _pulseLow(pin) // Низкий импульс в 1 такт // // Групповые операции N - 2-8 // _digitalWriteN(p1,...,pN,val) // _pulseHighN(p1,...,pN) // _pulseLowN(p1,...,pN) // _pinInvertN(p1,...,pN) // _pinPulseN(p1,...,pN) // _digitalReadN(p1,...,pN) // выдаёт байт, пины можно снимать битовой маской // ///////////////////////////////////////// #ifndef DigitalPins_h #define DigitalPins_h #define USE_XTAL_PINS #define USE_RESET_PIN #define lowByte(w) ((uint8_t) ((w) & 0xff)) #define highByte(w) ((uint8_t) ((w) >> 8)) #define bit(b) (1UL << (b)) #ifndef INPUT #define INPUT 0x0 #endif // !INPUT #ifndef OUTPUT #define OUTPUT 0x1 #endif // !OUTPUT #ifndef INPUT_PULLUP #define INPUT_PULLUP 0x2 #endif // !INPUT_PULLUP #ifndef HIGH #define HIGH 0x1 #endif // !HIGH #ifndef LOW #define LOW 0x0 #endif // !LOW #define __AVR_ATtinyDetected__ (defined(__AVR_ATtiny25__) || defined(__AVR_ATtiny45__) || defined(__AVR_ATtiny85__)) #if (!__AVR_ATtinyDetected__) && (!defined(__AVR_ATmega328P__)) #ifndef IGNORE_CPU_CHECK #error The library has been well tested for ATmega328P and ATtiny25/45/85 only. Define IGNORE_CPU_CHECK option to ignore this check. #endif // !IGNORE_CPU_CHECK #endif // (!__AVR_ATtinyDetected__) && (!defined(__AVR_ATmega328P__)) ////////////////////////////////////////////////////////////// // // Маски для битов групповых операций // #define __orMask2(m1,m2) ((unsigned char)((m1) | (m2))) #define __orMask3(m1,m2,m3) ((unsigned char)(__orMask2(m1,m2) | (m3))) #define __orMask4(m1,m2,m3,m4) ((unsigned char)(__orMask3(m1,m2,m3) | (m4))) #define __orMask5(m1,m2,m3,m4,m5) ((unsigned char)(__orMask4(m1,m2,m3,m4) | (m5))) #define __orMask6(m1,m2,m3,m4,m5,m6) ((unsigned char)(__orMask5(m1,m2,m3,m4,m5) | (m6))) #define __orMask7(m1,m2,m3,m4,m5,m6,m7) ((unsigned char)(__orMask6(m1,m2,m3,m4,m5,m6) | (m7))) #define __orMask8(m1,m2,m3,m4,m5,m6,m7,m8) ((unsigned char)(__orMask7(m1,m2,m3,m4,m5,m6,m7) | (m8))) #define ERROR_BIT 255 #if __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // У ATtiny есть единственный порт B, // а номера пинов совпадают с номерами битов // #define __pin2Port(pin) (PORTB) #define __pin2DirectionPort(pin) (DDRB) #define __pin2InputPort(pin) (PINB) #define __pin2PortBit(pin) (pin) #else // Не __AVR_ATtinyDetected__ #define A0 14 #define A1 15 #define A2 16 #define A3 17 #define A4 18 #define A5 19 #ifdef USE_XTAL_PINS // (PCINT6/XTAL1/TOSC1) PB6 // (PCINT7/XTAL2/TOSC2) PB7 #define XTAL1_PIN 20 #define XTAL2_PIN 21 #define EXT_PORTB_PINN(pin) (((pin) == XTAL1_PIN || (pin) == XTAL2_PIN) ? ((pin)-(XTAL1_PIN-6)) : #define EXT_PORTB_PINS(pin) || ((pin) == XTAL1_PIN) || ((pin) == XTAL2_PIN) #else #define EXT_PORTB_PINS(pin) #define EXT_PORTB_PINN(pin) ( #endif #ifdef USE_RESET_PIN // (PCINT14/RESET) PC6 #define RESET_PIN 22 #define EXT_PORTC_PIN(pin) || ((pin) == RESET_PIN) #define EXT_PORTC_PINN(pin) (((pin) == RESET_PIN) ? 6 : #else #define EXT_PORTC_PIN(pin) #define EXT_PORTC_PINN(pin) ( #endif ////////////////////////////////////////////////////////////// // // Выбор порта и бита по пину для ATmega328 // #define ERROR_PORT _SFR_IO8(255) #define ___pin2Port(pin, portD, portB, portC) \ (((pin) < 8) ? (portD) : \ (((pin) >= 8 && (pin) < 14) EXT_PORTB_PINS(pin) ? (portB) : \ (((pin) >= A0 && (pin) <= A5) EXT_PORTC_PIN(pin) ? (portC) : ERROR_PORT))) #define __pin2Port(pin) ___pin2Port(pin, PORTD, PORTB, PORTC) #define __pin2DirectionPort(pin) ___pin2Port(pin, DDRD, DDRB, DDRC) #define __pin2InputPort(pin) ___pin2Port(pin,PIND,PINB,PINC) #define __pin2PortBit(pin) \ (((pin) < 8) ? (pin) : \ (((pin) >= 8 && (pin) < 14) ? ((pin)-8) : \ EXT_PORTB_PINN(pin) \ EXT_PORTC_PINN(pin) \ (((pin) >= A0 && (pin) <= A5) ? ((pin)-A0) : ERROR_BIT))))) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Битовые маски из номеров пинов // #define __pin2Mask(pin) (1 << __pin2PortBit(pin)) #define __orPin2(p1,p2) __orMask2(__pin2Mask(p1),__pin2Mask(p2)) #define __orPin3(p1,p2,p3) __orMask3(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3)) #define __orPin4(p1,p2,p3,p4) __orMask4(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4)) #define __orPin5(p1,p2,p3,p4,p5) __orMask5(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5)) #define __orPin6(p1,p2,p3,p4,p5,p6) __orMask6(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6)) #define __orPin7(p1,p2,p3,p4,p5,p6,p7) __orMask7(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6),__pin2Mask(p7)) #define __orPin8(p1,p2,p3,p4,p5,p6,p7,p8) __orMask8(__pin2Mask(p1),__pin2Mask(p2),__pin2Mask(p3),__pin2Mask(p4),__pin2Mask(p5),__pin2Mask(p6),__pin2Mask(p7),__pin2Mask(p8)) ////////////////////////////////////////////////////////////// // // Внутренняя реализация основных операций // #define __pinHigh(port,mask) ((port) |= (mask)) #define __pinLow(port,mask) ((port) &= ~(mask)) #define __digitalWrite(port,mask,val) (((val)!=LOW) ? (__pinHigh(port,mask)) : (__pinLow(port,mask))) #define __pinInvert(port,mask) ((port) |= (mask)) #define __pinModeOutput(dirport,mask) ((dirport) |= (mask)) #define __pinModeInput(dirport, mask) ((dirport) &= ~(mask)) #define __pinModeInputPullUp(port,dirport,mask) { unsigned char oldSREG = SREG; cli(); (dirport) &= ~(mask); (port) |= (mask); SREG = oldSREG; } #define __pinMode(pin,state,mask) ((state) == INPUT) ? (__pinModeInput(__pin2DirectionPort(pin), mask)) : \ ((state) == INPUT_PULLUP) ? (__pinModeInputPullUp(__pin2Port(pin), __pin2DirectionPort(pin), mask)) : \ ((state) == OUTPUT) ? (__pinModeOutput(__pin2DirectionPort(pin), mask)) : (__pinModeOutput(__pin2DirectionPort(pin),0)) ////////////////////////////////////////////////////////////// // // Основные операции с единичным пином // #define _pinMode(pin,state) __pinMode(pin,state,__pin2Mask(pin)) #define _digitalWrite(pin,val) __digitalWrite(__pin2Port(pin),__pin2Mask(pin),val) #define _digitalRead(pin) (((__pin2InputPort(pin)) & (__pin2Mask(pin))) ? HIGH : LOW) #define _pulseHigh(pin) do { unsigned char oldSREG = SREG; cli(); _digitalWrite(pin,HIGH); _digitalWrite(pin,LOW); SREG = oldSREG; } while(false) #define _pulseLow(pin) do { unsigned char oldSREG = SREG; cli(); _digitalWrite(pin,LOW); _digitalWrite(pin,HIGH); SREG = oldSREG; } while(false) #define _pinPulse(pin) do { unsigned char oldSREG = SREG; cli(); _pinInvert(pin); _pinInvert(pin); SREG = oldSREG; } while(false) #define _pinInvert(pin) __pinInvert(__pin2InputPort(pin),__pin2Mask(pin)) #if defined(GROUP_OPERATIONS) //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// // // ГРУППОВЫЕ ОРПЕРАЦИИ // // // Групповой pulseLow по маске (внутренняя операция) // #define __pulseLow(port,mask) \ asm volatile ( \ "in __tmp_reg__,__SREG__ \n\t" \ "cli \n\t" \ "in r24,%0 \n\t" \ "mov r23,r24 \n\t" \ "or r24,%1 \n\t" \ "com %1 \n\t" \ "and r23,%1 \n\t" \ "out %0,r23 \n\t" \ "out %0,r24 \n\t" \ "out __SREG__,__tmp_reg__ \n\t" \ : : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24", "r23" \ ) ////////////////////////////////////////////////////////////// // // Групповой pulseHigh по маске (внутренняя операция) // #define __pulseHigh(port,mask) \ asm volatile ( \ "in __tmp_reg__,__SREG__ \n\t" \ "cli \n\t" \ "in r24,%0 \n\t" \ "mov r23,r24 \n\t" \ "or r24,%1 \n\t" \ "com %1 \n\t" \ "and r23,%1 \n\t" \ "out %0,r24 \n\t" \ "out %0,r23 \n\t" \ "out __SREG__,__tmp_reg__ \n\t" \ : : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24", "r23" \ ) ////////////////////////////////////////////////////////////// // // Групповой Invert по маске (внутренняя операция) // #define __Invert(port,mask) \ asm volatile ( \ "in __tmp_reg__,__SREG__ \n\t" \ "cli \n\t" \ "in r24,%0 \n\t" \ "or r24,%1 \n\t" \ "out %0,r24 \n\t" \ "out __SREG__,__tmp_reg__ \n\t" \ : : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24" \ ) ////////////////////////////////////////////////////////////// // // Групповой двойной Invert по маске (внутренняя операция) // #define __2Invert(port,mask) \ asm volatile ( \ "in __tmp_reg__,__SREG__ \n\t" \ "cli \n\t" \ "in r24,%0 \n\t" \ "or r24,%1 \n\t" \ "out %0,r24 \n\t" \ "out %0,r24 \n\t" \ "out __SREG__,__tmp_reg__ \n\t" \ : : "I" (_SFR_IO_ADDR(port)), "r" ((mask)) : "r24" \ ) ////////////////////////////////////////////////////////////// // // Групповой _digitalWrite // #define _digitalWrite2(p1,p2,val) __digitalWrite(__pin2Port(p1),__orPin2(p1,p2),val) #define _digitalWrite3(p1,p2,p3,val) __digitalWrite(__pin2Port(p1),__orPin3(p1,p2,p3),val) #define _digitalWrite4(p1,p2,p3,p4,val) __digitalWrite(__pin2Port(p1),__orPin4(p1,p2,p3,p4),val) #define _digitalWrite5(p1,p2,p3,p4,p5,val) __digitalWrite(__pin2Port(p1),__orPin5(p1,p2,p3,p4,p5),val) #define _digitalWrite6(p1,p2,p3,p4,p5,p6,val) __digitalWrite(__pin2Port(p1),__orPin6(p1,p2,p3,p4,p5,p6),val) #if !__AVR_ATtinyDetected__ #define _digitalWrite7(p1,p2,p3,p4,p5,p6,p7,val) __digitalWrite(__pin2Port(p1),__orPin7(p1,p2,p3,p4,p5,p6,p7),val) #define _digitalWrite8(p1,p2,p3,p4,p5,p6,p7,p8,val) __digitalWrite(__pin2Port(p1),__orPin8(p1,p2,p3,p4,p5,p6,p7,p8),val) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Групповой _pulseHigh // #define _pulseHigh2(p1,p2) __pulseHigh(__pin2Port(p1),__orPin2(p1,p2)) #define _pulseHigh3(p1,p2,p3) __pulseHigh(__pin2Port(p1),__orPin3(p1,p2,p3)) #define _pulseHigh4(p1,p2,p3,p4) __pulseHigh(__pin2Port(p1),__orPin4(p1,p2,p3,p4)) #define _pulseHigh5(p1,p2,p3,p4,p5) __pulseHigh(__pin2Port(p1),__orPin5(p1,p2,p3, p4, p5)) #define _pulseHigh6(p1,p2,p3,p4,p5,p6) __pulseHigh(__pin2Port(p1),__orPin6(p1,p2, p3, p4, p5, p6)) #if !__AVR_ATtinyDetected__ #define _pulseHigh7(p1,p2,p3,p4,p5,p6,p7) __pulseHigh(__pin2Port(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7)) #define _pulseHigh8(p1,p2,p3,p4,p5,p6,p7,p8) __pulseHigh(__pin2Port(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8)) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Групповой _pulseLow // #define _pulseLow2(p1,p2) __pulseLow(__pin2Port(p1),__orPin2(p1,p2)) #define _pulseLow3(p1,p2,p3) __pulseLow(__pin2Port(p1),__orPin3(p1,p2,p3)) #define _pulseLow4(p1,p2,p3,p4) __pulseLow(__pin2Port(p1),__orPin4(p1,p2,p3,p4)) #define _pulseLow5(p1,p2,p3,p4,p5) __pulseLow(__pin2Port(p1),__orPin5(p1,p2,p3, p4, p5)) #define _pulseLow6(p1,p2,p3,p4,p5,p6) __pulseLow(__pin2Port(p1),__orPin6(p1,p2, p3, p4, p5, p6)) #if !__AVR_ATtinyDetected__ #define _pulseLow7(p1,p2,p3,p4,p5,p6,p7) __pulseLow(__pin2Port(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7)) #define _pulseLow8(p1,p2,p3,p4,p5,p6,p7,p8) __pulseLow(__pin2Port(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8)) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Групповой _pinInvert // #define _pinInvert2(p1,p2) __Invert(__pin2InputPort(p1),__orPin2(p1,p2)) #define _pinInvert3(p1,p2,p3) __Invert(__pin2InputPort(p1),__orPin3(p1,p2,p3)) #define _pinInvert4(p1,p2,p3,p4) __Invert(__pin2InputPort(p1),__orPin4(p1,p2,p3, p4)) #define _pinInvert5(p1,p2,p3,p4,p5) __Invert(__pin2InputPort(p1),__orPin5(p1,p2, p3, p4, p5)) #define _pinInvert6(p1,p2,p3,p4,p5,p6) __Invert(__pin2InputPort(p1),__orPin6(p1, p2, p3, p4, p5, p6)) #if !__AVR_ATtinyDetected__ #define _pinInvert7(p1,p2,p3,p4,p5,p6,p7) __Invert(__pin2InputPort(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7)) #define _pinInvert8(p1,p2,p3,p4,p5,p6,p7,p8) __Invert(__pin2InputPort(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8)) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Групповой _pinPulse // #define _pinPulse2(p1,p2) __2Invert(__pin2InputPort(p1),__orPin2(p1,p2)) #define _pinPulse3(p1,p2,p3) __2Invert(__pin2InputPort(p1),__orPin3(p1,p2,p3)) #define _pinPulse4(p1,p2,p3,p4) __2Invert(__pin2InputPort(p1),__orPin4(p1,p2,p3, p4)) #define _pinPulse5(p1,p2,p3,p4,p5) __2Invert(__pin2InputPort(p1),__orPin5(p1,p2, p3, p4, p5)) #define _pinPulse6(p1,p2,p3,p4,p5,p6) __2Invert(__pin2InputPort(p1),__orPin6(p1, p2, p3, p4, p5, p6)) #if !__AVR_ATtinyDetected__ #define _pinPulse7(p1,p2,p3,p4,p5,p6,p7) __2Invert(__pin2InputPort(p1),__orPin7(p1, p2, p3, p4, p5, p6, p7)) #define _pinPulse8(p1,p2,p3,p4,p5,p6,p7,p8) __2Invert(__pin2InputPort(p1),__orPin8(p1, p2, p3, p4, p5, p6, p7, p8)) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Групповой _digitalRead // #define __read(port, mask) ((port) & (mask)) #define _digitalRead2(p1,p2) __read(__pin2InputPort(p1),__orPin2(p1,p2)) #define _digitalRead3(p1,p2,p3) __read(__pin2InputPort(p1),__orPin3(p1,p2,p3)) #define _digitalRead4(p1,p2,p3,p4) __read(__pin2InputPort(p1),__orPin4(p1,p2,p3,p4)) #define _digitalRead5(p1,p2,p3,p4,p5) __read(__pin2InputPort(p1),__orPin5(p1,p2,p3,p4,p5)) #define _digitalRead6(p1,p2,p3,p4,p5,p6) __read(__pin2InputPort(p1),__orPin6(p1,p2,p3,p4,p5,p6)) #if !__AVR_ATtinyDetected__ #define _digitalRead7(p1,p2,p3,p4,p5,p6,p7) __read(__pin2InputPort(p1),__orPin7(p1,p2,p3,p4,p5,p6,p7)) #define _digitalRead8(p1,p2,p3,p4,p5,p6,p7,p8) __read(__pin2InputPort(p1),__orPin8(p1,p2,p3,p4,p5,p6,p7,p8)) #endif // __AVR_ATtinyDetected__ ////////////////////////////////////////////////////////////// // // Маски для проверки отдельных битов после группового _digitalRead // #define _pin0 __pin2Mask(0) #define _pin1 __pin2Mask(1) #define _pin2 __pin2Mask(2) #define _pin3 __pin2Mask(3) #define _pin4 __pin2Mask(4) #define _pin5 __pin2Mask(5) #if !__AVR_ATtinyDetected__ #define _pin6 __pin2Mask(6) #define _pin7 __pin2Mask(7) #define _pin8 __pin2Mask(8) #define _pin9 __pin2Mask(9) #define _pin10 __pin2Mask(10) #define _pin11 __pin2Mask(11) #define _pin12 __pin2Mask(12) #define _pin13 __pin2Mask(13) #define _pinA0 __pin2Mask(A0) #define _pinA1 __pin2Mask(A1) #define _pinA2 __pin2Mask(A2) #define _pinA3 __pin2Mask(A3) #define _pinA4 __pin2Mask(A4) #define _pinA5 __pin2Mask(A5) #ifdef USE_XTAL_PINS #define _pinXTAL1 __pin2Mask(XTAL1_PIN) #define _pinXTAL2 __pin2Mask(XTAL2_PIN) #endif #ifdef USE_RESET_PIN #define _pinRESET __pin2Mask(RESET_PIN) #endif #endif // !__AVR_ATtinyDetected__ #endif // defined(GROUP_OPERATIONS) #endif // DigitalPins_hМеня смущает
#define __pinInvert(port,mask) ((port) |= (mask))
так же как и
#define __Invert(port,mask) \
...сичтают...
У меня тоже, когда выпью, одна рука опережает другую.)
Не, извиняюсь, это не тот случай - тут одна рука.)
Меня смущает
Читайте строки №№ 17-19. Этот текст НЕ является универсальной библиотекой, НЕ поддерживается и НЕ сопровожадется. Это домашняя вещь для домашнего использования. Я просто увидел, что она как-то расползлась и даже появилась у нас в одном из проектов в соответсвующем разделе. Потому и решил выложить изменения, о чём уже жалею.
В любом случае, я не консультирую по этому коду и не помогаю решать связанные с ним вопросы. Сейчас сделаю исключение, но впредь, имейте в виду.
Что до Вашего смущения, Вы полезли в групповые операции. Они не делаются одной командой по определению. Однокомандное инвертирование возможно для одиночного пина - _pinInvert(pin). Видимо, Ваш вопрос связан с тем, почему групповое инвертирование не сделано записью в PINx, как это сделано для единичного пина. Так при такой записи, туда (в PINx) полезут не только единицы "куда надо", но и нули "во все остальные биты". Вы уверены. что это будет нормально восприниматься?
Да, я уверен (хотя верить нельзя никому), потому что только запись 1-цы влияет на инверсию порта, не более. 0 не влияет ни на что. Ни на PIN, ни на PORT.
Writing a logic one to PINxn toggles the value of PORTxn, independent on the value of DDRxn.
Плюс этого варианта ещё в том, что операция атомарна.
Да, я уверен ... только запись 1-цы влияет на инверсию порта, не более. 0 не влияет ни на что.
Ну, в даташите этого не написано, а вопросы веры мы тут обсуждать точно не будем. Мне жаль что тот кусок оскорбил Ваши чувства верующего, но обсуждение прекращаем. Как я уже сказал, библиотека не поддерживается а тот мой ответ был исключением.
Да ради бога. Я не пытался вам что то доказать, я просто обратил ваше внимание.)
ЕвгенийП, на самом деле классная библиотека.) Может Вам копирайт какой то следовало поставить? Пусть даже чисто символически.)
Если позволите - тоже влезу. Я такое вот у себя пользую для того, чтобы значения на "защищаемых" пинах не портить (во всяком случае так полагаю):
#include <util/atomic.h> uint8_t writeToPort(const uint8_t _port, const uint8_t _value, const uint8_t _protectMask = B00000000) { volatile uint8_t *portRegister; portRegister = portOutputRegister(_port); if (NOT_A_PORT == portRegister) return false; // Port write transaction // Use protection mask when write to port to save some pins state ATOMIC_BLOCK(ATOMIC_RESTORESTATE) { *portRegister = (*portRegister & _protectMask) | (_value & ~_protectMask); } return true; }В _protectMask '1' препятствует изменению пина, '0' - разрешает изменение.
может и мне когда-нибудь пригодится!
Я такое вот у себя пользую...
С виду норм. Только тип возвращаемого значения желательно bool, по красивому.)