Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Сложная тема.AVR __io область как параметр функции
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
dormouse
После перехода на EC++ естественно
возникло желание передавать в конструктор информацию о порте
ввода/вывода с которым объект будет работать (если надо использовать
несколько устройств одного типа).

Иными словами - надо подключить, скажем 2 LCD.
class cLCD{ public: putchar(); ...};
cLCD LCD_A(PORTA), LCD_B(PORTB); // Можно пожертвовать читаемостью - 0x12, 0x1F
Каждый объект будет независимо работать на своём порту.

Попытки решить задачу (все безуспешные):
1. void foo(unsigned char byte){
unsigned char __io PORT_TO_WORK = @byte;//Имелось в виду @0x12
}
Неудачно, поскольку на стадии компиляции неизвестно значение byte
2. unsigned char __io * ptrPORT_TO_WORK = 0x12;
Неудачно, поскольку в IAR _НЕТ_ указателей на __io область вообще.
3. Пример из документации (стр 117)
Non-type template parameters
It is allowed to have a reference to a memory type as a template parameter, even if
pointers to that memory type are not allowed.
Example
extern int __io x;
template<__io int &y>
void foo()
{
y = 17;
}
void bar()
{
foo<x>();
}

Неудачно, компилятор говорит, что не может сделать экземплят foo,
который подходит к такому вызову...
Error[Pe304]: no instance of function template "foo" matches the argument list C:\DIY\Projects\001-IAR4-printf\main.c 77


Теперь осталось только ждать предложений, пока моя фантазия
истощена...



PS Очень нужен IAR AVR 4.10 A(B) Full (~100mb).
KRS
Цитата(dormouse @ Mar 18 2005, 16:53)
2. unsigned char __io * ptrPORT_TO_WORK = 0x12;
    Неудачно, поскольку в IAR _НЕТ_ указателей на __io область вообще.
*


А может попробовать так
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

укзателей на __io напрямую нет конечно, но если посмотреть архитектуру AVR то можно так описать. только код не очень оптимальный будет.
dormouse
Порты PORTA, DDRA, PINA - это суть макросы в IAR. Мне надо работать,скажем, с 1-wire. Для этого есть класс, конструктору которого надо передать "ногу" MC, с которой работать.

Для работы требуются все три макроса (функциональности). Я хочу работать так:
LCD lcd("A.6");

в конструкторе надо настроить как-то функции обращения к данной "ноге".
dormouse
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

Насколько я понимаю, такой строкой мы будем пытаться присвоить значение типа int самому указателю. На это компилятор ругнётся.
KRS
Цитата(dormouse @ Mar 18 2005, 18:19)
volatile unsigned char* ptrPORT_TO_WORK = 0x12+0x20;

Насколько я понимаю, такой строкой мы будем пытаться присвоить значение типа int самому указателю. На это компилятор ругнётся.
*


Ну надо преобразование типов поставить
((volatile unsigned char*)(0x12+0x20))
ZiB
всем, привет!
я решаю эту проблему вот так:
#define porta 0x3B
#define bit 1
........................
void Set_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) |= BitNumber;
}

void Clr_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) &= ~BitNumber;
}
.........................
Clr_Port(porta, bit);
Delay(1000);
Set_Port(porta, bit);
// можно и так
for(Byte i = 0; i<7; i++)
{
Set_Port(porta, _Bit(i));
}
Serega Doc
Цитата(ZiB @ Feb 20 2006, 14:58) *
всем, привет!
я решаю эту проблему вот так:
#define porta 0x3B
#define bit 1
........................
void Set_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) |= BitNumber;
}

void Clr_Port(Byte PortNumber, Byte BitNumber)
{
*((Byte*)PortNumber) &= ~BitNumber;
}
.........................
Clr_Port(porta, bit);
Delay(1000);
Set_Port(porta, bit);
// можно и так
for(Byte i = 0; i<7; i++)
{
Set_Port(porta, _Bit(i));
}


Попробовал вашу конструкцию вот что вышло в процессе компиляции в IAR 5.5 без оптимизации
Код
void Set_Port(uchar PortNumber, uchar BitNumber)
??Set_Port:
//   36 {
//   37 *((uchar*)PortNumber) |= BitNumber;
        MOV     R30, R16
        LDI     R31, 0
        LD      R18, Z
        OR      R18, R17
        ST      Z, R18
//   38 }
        RET
//   39

        RSEG CODE:CODE:NOROOT(1)
//   40 void Clr_Port(uchar PortNumber, uchar BitNumber)
??Clr_Port:
//   41 {
//   42 *((uchar*)PortNumber) &= ~BitNumber;
        MOV     R18, R17
        COM     R18
        MOV     R30, R16
        LDI     R31, 0
        LD      R19, Z
        AND     R19, R18
        ST      Z, R19
//   43 }
        RET
//   44
//   45

        RSEG CODE:CODE:NOROOT(1)
//   46 int main()
main:
//   47 {
// Пример работы с портом
//   48     PORTB = 10;
        LDI     R16, 10
        OUT     0x18, R16
//   49     PORTB++;
        IN      R16, 0x18
        INC     R16
        OUT     0x18, R16
//   50  // Ваши процедуры
//   51     Clr_Port(porta, bit);
        LDI     R17, 1
        LDI     R16, 24
        RCALL   ??Clr_Port
//   52     
//   53     Set_Port(porta, bit);
        LDI     R17, 1
        LDI     R16, 24
        RCALL   ??Set_Port
//   54     
//   55
//   56   return 0;
        LDI     R16, 0
        LDI     R17, 0
        RET
        REQUIRE _A_PORTB
//   57 }

Что то тут не то sad.gif
MrYuran
Цитата(Serega Doc @ Jun 7 2010, 15:58) *
Попробовал вашу конструкцию вот что вышло в процессе компиляции в IAR 5.5 без оптимизации
Что то тут не то sad.gif

А теперь попробуйте с оптимизацией.
Может быть, получится то самое?
Serega Doc
Цитата(MrYuran @ Jun 7 2010, 15:10) *
А теперь попробуйте с оптимизацией.
Может быть, получится то самое?

Вот что с оптимизацией
Код
13 void Set_Port(uchar PortNumber, uchar BitNumber)
??Set_Port:
//   14 {
//   15 *((uchar*)PortNumber) |= BitNumber;
        MOV     R30, R16
        LDI     R31, 0
        LD      R16, Z
        OR      R16, R17
        REQUIRE ?Subroutine0
       ;               // Fall through to label ?Subroutine0
//   16 }

        RSEG CODE:CODE:NOROOT(1)
?Subroutine0:
        ST      Z, R16
        RET
//   17

Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит. Да и врядли вообще можно написать что то требуемое потому как в ассемблере IN и OUT конструкции используются с константой и в них номер регистра вообще нельзя передать.
Так что нужно писать таблицу типа и делать переходы на эти метки или как то с помощью кейсов описывать. Иначе на мой взгляд никак.
Код
??RD_PORTB
IN 0x18,R16
RET;
??RD_PORTC
IN 0x15,R16;
RET;
SasaVitebsk
Цитата(Serega Doc @ Jun 7 2010, 15:35) *
Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит. Да и врядли вообще можно написать что то требуемое потому как в ассемблере IN и OUT конструкции используются с константой и в них номер регистра вообще нельзя передать.

Никогда не пробовал, если честно, но по-моему вы заблуждаетесь.

Если посмотреть даташит на atmega8, к примеру, то в разделе SRAM Data Memory есть таблица распределения ОЗУ (Figure 8. Data Memory Map). В ней, насколько я понимаю, показано, что область IO отображается на память со смещением в 0x20. Похоже именно это имел ввиду KRS в первом же посте. Таким образом работать с указателями возможно. Хотя, повторюсь ещё раз, сам лично я не пробовал.
Есть ещё проблема с теми портами, которые подлежат обращению ч/з LD/ST, но это тоже можно описать.

Хотя стоит ли всё это потраченных сил? Не проще ли написать это всё более размашисто и менее универсально? Как правило, работа с оборудованием - ничнтожная часть проекта.
ae_
Цитата(Serega Doc @ Jun 7 2010, 21:35) *
...Но операция ST Z, R16 никогда не будет оптимизироваться в OUT 0x18, R16
Первое работа с ОЗУ второе с I/O. Так что описанный выше метод вообще не подходит...

"ST Z,R16" невозможно соптимизировать в "OUT 0x18,R16" потому что это разные типы адресации, косвенная и прямая, и в первом случае Z - не определено.
вот "STS 0x38,R16" уже можно соптимизировать в "OUT 0x18,R16", здесь заранее известно, куда записать R16.
или все эти три инструкции вместе:
LDI ZL,0x18+0x20
LDI ZH,0
ST Z,R16
можно заменить на одну "OUT 0x18,R16", но не как в первом случае.

Вообще, к любому РОН и порту В/В можно обратится, как к ОЗУ, т.к. все они находятся в одном сегменте данных:
0x00-0x1F - R0...R31
0x20-0x5F - порты в/в, к которым можно обращаться инструкциями IN/OUT, но для IN/OUT адреса меньше на 0x20, т.е. 0x00-0x3F
0x60-0xFF - порты в/в, до которых IN/OUT уже не дотягивается и к ним нужно обращаться, как к ОЗУ
0x100-... - ОЗУ
Например: "STS 0x05, R7" = "MOV R5, R7", но первый вариант занимает 2 слова и выполняется 2 цикла, против 1/1, поэтому мало интересен,
точно также, как и "STS 0x38,R16" = "OUT 0x18,R16", те же 2/2 против 1/1

косвенная адресация более применима:
Код
CLR ZL
CLR ZH
clear:       ; обнуление регистров R0...R15
ST  Z+, ZH
CPI ZL, 16
BRLO clear

Если хочется универсальности, косвенное обращение через X, Y, Z-регистры к портам в/в - приемлемое решение.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.