Вопросы настройки, программирования, прошивки микроконтроллеров и микросхем программируемой логики
Тема закрыта

Объединение разных PINов в один PORT

Пн июл 09, 2012 20:54:47

Доброго времени суток.

Возникла небольшая проблема с портами мк, а точнее их расположением ...

Начну с начала, как я к этому пришел ... Решил сделать подарок девушке в виде светодиодного сердечка (идеей был вдохновлен на хабре). Начал кодить на отладочной плате (самопал), на которой стоит ATmega16 в DIP корпусе.
И тут понеслась ... вроде сделал хорошие наброски кода, баловался с портом В, грациозно делал всякие вундервафли и мигалки с помощью сдвига регистра порта В, аля кусочек из цикла for:

Код:
PORTB=0x00000001;
PORTB=PORTB<1;


Решил портировать все это на мегу8 и тут понял что не все так просто
Если взглянутьна мегу8 в TQFP корпусе то видим
Изображение
что если ее визуально поделить на пополам (две половинки сердечка) вертикально то получим по 11 пинов на сторону

Слева: PD0, PD1, PD2, PD3, PD4PB6, PB7, PD5, PD6, PD7, PB0
Cправа: PC5, PC4, PC3, PC2, PC1, PC0, PB5, PB4, PB3, PB2, PB1

И так внимание вопрос !
Можно ли эти пины обьеденить в один так называемый 11 битный "порт" что б можно было левой и правой частью управлять как 8ми битным портом, т.е. к примеру LEFT=0b00000000001 и загорается первый (PD0) диод ?

Или быдлокодить и дергать пины через делей ? что щитаю не спортивным

Жду любых коментов по теме и камней в мою сторону

Re: Объединение разных PINов в один PORT

Пн июл 09, 2012 21:56:14

можно завести переменную, а потом разбрасывать битики переменной по битикам порта.

Re: Объединение разных PINов в один PORT

Пн июл 09, 2012 23:57:48

Еще как вариант, сделать драйвер на таймере, в обработчике прерывания преобразуем переменные в порты, т.е. запихиваем нужные биты переменных в нужные биты портов, тем самым включая и выключая нужные светодиоды, а в основном коде играем только с двумя переменными, как с "реальными" портами.

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 09:40:57

Хм ... Идея Flasher'a довольно интересна. Можно по подробнее как биты переменной запихивать в биты порта ? Я думал както через массив, но потом понял что затея глупая. Можно про Ваш способ по подробней и если не сложно с примерами кода.

zero648 также буду рад увидеть решение с помощью вашего способа, а то если чесно я немного не допонял как это сделать с таймером.

Заранее вам спасибо.

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 09:48:09

Вот Артём тут выкладывал свои мысли по поводу виртуальных портов.

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 09:54:06

На СИ не практикую уже давно, если устроит на ASMe накидаю.

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 12:07:21

Rondo, интересная у Вас запись шестнадцатеричного числа. :)) Впрочем, и "сдвиг" такой же...

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 16:57:44

0b - это двоичные числа, шестнадцатиричные - 0x. А по поводу сдвига - да, пропустил одну стрелочку.

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 17:04:03

Rondo писал(а):0b - это двоичные числа, шестнадцатиричные - 0x


Вот именно. :) Потому и определяйтесь: либо 0b00000000 - 0b11111111, либо 0x0 - 0xFF. Например, запись PORTB = 0x10000000 это совсем не установка 7-го бита порта. :wink:

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 17:53:52

ну не суть :) я быдлокодю в CVAVR (о чем кстати жалею) но продолжаю в нем, а про PORTB = 0x10000000 это ж 8 бит (т.е PORTB.7=1). Ну в кодвижене так :) и вроде работает)
по поводу поста s_black - очень интересно, но я в асме полный ноль =\

Если ктото сможет пару примерчиков привести в Си буду благодарен

Спасибо всем за ответы, надеюсь вы "вдолбите" мне в голову эту фичу с виртуальными портами, а пока буду сам пробовать чтото понять, но надеюсь на примеры Си кода -_-

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 18:03:22

Rondo писал(а):0x10000000 это ж 8 бит


Это не 8 бит а 32. Если перевести в десятичную систему 0x10000000 = (1*16^7)+(0*16^6)+(0*16^5)+(0*16^4)+(0*16^3)+(0*16^2)+(0*16^1)+(0*16^0) = 268 435 456 (или 0b10000000000000000000000000000).

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 18:26:27

Можно создать макрос и "скармливать" ему маску для установки или сброса битов в этом самом "виртуальном порту".

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 19:24:46

поставь табличную подмену текущих данных на требуемые (разновидность табличного декодера) - метод реализации любой из понятных в объёме слово->слово, только при выводе не забудь про "чтение->модификация с данными->модификация с маской(если у портов разное назначение выводов)->запись
:sleep:

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 19:24:59

Можно разделять исходную переменную битовыми операциями (& / |) по маскам, а потом распихивать выковырянное по портам.

Например, есть у нас шестнадцатибитная переменная VPORT - типа виртуальный порт. Пускай первый и третий ниббл надо запихать в PORTA, а второй и четвертый - в PORTB.

Код:

PORTA=(VPORT & 0x000F) | ((VPORT & 0x0F00) >> 4);
PORTB=((VPORT & 0x00F0) >> 4) | ((VPORT & 0xF000) >> 8);



Странное дело... Тот, у кого есть девушка, обычно не знает, как сделать виртуальный порт. А у того, кто знает, обычно нет девушки... :))) Так что Вы это... Аккуратнее. :)))

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 20:19:50

Rondo, если нужно управлять пинами по отдельности, можно сделать примерно так.
Код:
// Массив соответствия виртуальных пинов
unsigned char ptable[11,3]{
    // Порт B      Порт C      Порт D
    {0b00010000, 0b00000000, 0b00000000},   // виртуальный пин 0
    {0b00000000, 0b00100000, 0b00000000},
    {0b00000000, 0b10000000, 0b00000000},
    {0b00001000, 0b00000000, 0b00100000},
    {0b00000000, 0b00000100, 0b00000000},
    {0b00000100, 0b00000000, 0b00000000},
    {0b00000000, 0b00000000, 0b00000000},
    {0b00000000, 0b00000001, 0b00000000},
    {0b00000000, 0b00000000, 0b00001000},
    {0b00000000, 0b00000000, 0b00000010},
    {0b10000000, 0b00000000, 0b00000000}    // виртуальный пин 1
}

// Установка виртульного пина по его номеру
// num от 0 до 10 (в данном случае)
void setBit(unsigned char num)
{
    PORTB|=ptable[num, 0];
    PORTC|=ptable[num, 1];
    PORTD|=ptable[num, 2];
}

// Сброс виртуального пина
void clearBit(unsigned char num)
{
    PORTB&=(~ptable[num, 0]);
    PORTC&=(~ptable[num, 1]);
    PORTD&=(~ptable[num, 2]);
}

Re: Объединение разных PINов в один PORT

Вт июл 10, 2012 21:35:54

Rondo, если есть кто может подружить этот код с СИ, то вот так примерно выглядит драйвер на таймере, индикация здесь у нас получается динамическая, частоту обновления можно изменить, если чё.
В основном цикле MAIN загружаем младшие 8 бит и старшие три бита регистра, в соответствующие переменные для каждой линейки светодиодов, а драйвер нам их конвертирует как мы хотим, старшие пять битов старшего регистра нам побоку,
Как вариант можно задать массив с кучей разных эффектов и тупо прогонять его просто через переменные, должно неплохо получиться.
Код:

            .include "m8def.inc"     ; Используем ATMega8
 
; ROM ===============

            .CSEG                     ; ROM
            .org $000
            rjmp RESET                ;
            .org $009
            rjmp TMR0_OVF             ; TIMER0 OVF Переполнение таймера/счетчика Т0
           
; ---------- R E S E T ----------

            .ORG   INT_VECTORS_SIZE   ; Конец таблицы прерываний
RESET:
            cli
            ldi     r16, high(RAMEND) ; Main program start
            out     SPH, r16          ; Set Stack Pointer to top of RAM
            ldi     r16, low(RAMEND)  ;
            out     SPL, r16          ;

            clr     r16
            out     TCCR0, r16        ; Стоп Timer0
            out     TCNT0, r16        ; Сброс Timer/Counter0
            ldi     r16, 0b00000001   ; Используем вектор переполнения TIMER0 OVF
            out     TIMSK, r16        ;
            sei

            ldi     YL, low(SRAM_START) ; Начало ОЗУ
            ldi     YH, high(SRAM_START);

; При тактовой частоте МК 8 МГц, частота обновления около 30 Гц

            ldi     r16, 0b00000101   ; Запускаем Timer0 предделитель частоты 1:1024
            out     TCCR0, r16        ; 001=1:1,010=1:8,011=1:64,100=1:256,101=1:1024

;передаем регистры в переменные драйвера

            ldi   r16, 0b11001111     ; LEFT low 0bxxxxxxxx
            std   Y+0, r16            ;
            ldi   r16, 0b00000101     ; LEFT high 0b?????xxx
            std   Y+1, r16            ;
            ldi   r16, 0b00011111     ; RIGHT low 0bxxxxxxxx
            std   Y+2, r16            ;
            ldi   r16, 0b00000111     ; RIGHT high 0b?????xxx
            std   Y+3, r16            ;

MAIN:

; Типа бегущие огни для примера

            ldd   r16, Y+0           
            ldd   r17, Y+1           
            lsr   r16
            in    r20, SREG
            lsr   r17
            in    r21, SREG
            sbrc  r21, 0
            sbr   r16, 0x80
            sbrc  r20, 0
            sbr   r17, 0x04
            std   Y+0, r16            ;
            std   Y+1, r17            ;

            ldd   r18, Y+2            ;
            ldd   r19, Y+3            ;
            lsr   r18
            in    r20, SREG
            lsr   r19
            in    r21, SREG
            sbrc  r21, 0
            sbr   r18, 0x80
            sbrc  r20, 0
            sbr   r19, 0x04
            std   Y+2, r18            ;
            std   Y+3, r19            ;
           

            in      r16,MCUCR
            ori     r16, $80
            out     MCUCR, r16
            sleep                     ; Ждем включения драйвера
            rjmp    MAIN              ; Go again               

;----------

TMR0_OVF:
            push    r16
            push    r17
            push    r18
            push    r19
            in      r16, SREG
            push    r16

; Очищаем порты
            ldi   r16, 0b00111111
            out   DDRC, r16
            ser   r16
            out   DDRB, r16
            out   DDRD, r16
            clr   r16
            out   PORTB, r16
            out   PORTC, r16
            out   PORTD, r16

; Читаем переменные
            ldd   r16, Y+0           
            ldd   r17, Y+1           
            ldd   r18, Y+2            ;
            ldd   r19, Y+3            ;

; И запихиваем в нужные биты портов

; Ряд слева
            sbrc  r16, 0
            sbi   PORTD,0             ; PD0
            sbrc  r16, 1
            sbi   PORTD,1             ; PD1
            sbrc  r16, 2
            sbi   PORTD,2             ; PD2
            sbrc  r16, 3
            sbi   PORTD,3             ; PD3
            sbrc  r16, 4
            sbi   PORTD,4             ; PD4
            sbrc  r16, 5
            sbi   PORTB,6             ; PB6
            sbrc  r16, 6
            sbi   PORTB,7             ; PB7
            sbrc  r16, 7
            sbi   PORTD,5             ; PD5
            sbrc  r17, 0
            sbi   PORTD,6             ; PD6
            sbrc  r17, 1
            sbi   PORTD,7             ; PD7
            sbrc  r17, 2
            sbi   PORTB,0             ; PB0

; Ряд справа
            sbrc  r18, 0
            sbi   PORTC,5             ; PC5
            sbrc  r18, 1
            sbi   PORTC,4             ; PC4
            sbrc  r18, 2
            sbi   PORTC,3             ; PC3
            sbrc  r18, 3
            sbi   PORTC,2             ; PC2
            sbrc  r18, 4
            sbi   PORTC,1             ; PC1
            sbrc  r18, 5
            sbi   PORTC,0             ; PC0
            sbrc  r18, 6
            sbi   PORTB,5             ; PB5
            sbrc  r18, 7
            sbi   PORTB,4             ; PB4
            sbrc  r19, 0
            sbi   PORTB,3             ; PB3
            sbrc  r19, 1
            sbi   PORTB,2             ; PB2
            sbrc  r19, 2
            sbi   PORTB,1             ; PB1

            pop     r16
            out     SREG, r16
            pop     r19
            pop     r18
            pop     r17
            pop     r16

            reti

Re: Объединение разных PINов в один PORT

Ср июл 11, 2012 07:00:02

ну Вы zero648 и наворотили... :cry:
кстати, "динамика" даже при регенерации с частотой 50Гц уже не слишком приятно смотрится...
можно конечно для световых эффектов и так "изголяться", но лучше уж табличка, а самый верный способ - правильно кристалл выбрать, тем более , что их сейчас в каждом семействе навалом ... ну, например здесь atmega8515, atmega126 - там простое рядное расположение выводов... :beer:

Re: Объединение разных PINов в один PORT

Ср июл 11, 2012 09:04:10

Ну натворил не натворил, скажем просто накидал для примера, по простому, чтобы читалось проще и понятней для начинающих. Я понимаю, что при частоте 50 Гц это может раздражать, но мы же не выводим информацию, скажем, через один порт на целую матрицу, где частоту для лучшего восприятия делать хотябы не менее 100 Гц, где даже мерцание может быть заметно, а в этом конкретном случае, каждый светодиод подключен к отдельному пину, поэтому, даже при 10 Гц ничего раздражать не должно, у нас просто обновляется состояние портов, тем более, что частоту обновления можно регулировать в том же обработчике прерывания.
А выбирать кристалл у нас нет возможности, как я понял, иначе зачем тогда все эти конвертации понадобились автору темы, т.е. мое решение по условию задачи. :beer:

Re: Объединение разных PINов в один PORT

Ср июл 11, 2012 10:55:31

выбор микрух всегда есть... не avr (mega7tiny) так mcs51 или pic10/12/16/18 :roll:

Re: Объединение разных PINов в один PORT

Ср июл 11, 2012 12:19:21

Бум лепить из того, что есть, тем более задача не такая уж и сложная, и такой камень пойдет. Собственно, Я обычно так и делаю, сначала развожу плату, как мне удобнее, а потом под железо пишу код, а не наоборот. Хоть немного моск напрячь, а когда просто, както скучно даже.
Тема закрыта