Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Вопрос по пикам и HITECH PICC
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Все остальные микроконтроллеры
DukeXar
Хочу простого. Есть функция, которая в зависимости от состояния автомата, реализует те или иные действия и переводит автомат в другое состояние.
На MPASM сделал так:
Код
ReadUserInput:
       movlw high ReadUserInput_gotos
       movwf PCLATH
       movf a1_state, W      ; W <- a1_state
       andlw b'00000011'     ; clip to [0..3]
       addwf PCL, F          ; jump
ReadUserInput_gotos:
       goto read_user_input_0
       goto read_user_input_1
       goto read_user_input_2
       goto read_user_input_3
      ; ^^^ 8 Tcy

read_user_input_0:
       jbc b_tst, rui_00
       bsf a1_state, 0
       goto read_user_input_end
rui_00:
       jbc b_dwn, rui_01
       bsf a1_state, 1
       goto read_user_input_end
rui_01:
 clb b_ui_mc
       jbs b_mc, read_user_input_end
       seb b_ui_mc
       bsf a1_state, 0
       bsf a1_state, 1
       goto read_user_input_end

read_user_input_1:
       jbs b_tst, read_user_input_end
       bcf a1_state, 0
       seb b_ui_tst
       goto read_user_input_end

read_user_input_2:
       jbs b_dwn, read_user_input_end
       bcf a1_state, 1
       seb b_ui_dwn
       goto read_user_input_end

read_user_input_3:
       jbs b_mc, read_user_input_end
       bcf a1_state, 0
       bsf a1_state, 1
      ;seb b_ui_mc
      ;goto read_user_input_end
read_user_input_end:
       return


А теперь вопрос: как на C осуществить табличный переход? А то при использовании switch (a1_state) {case0: break; case 1: break; ...} или при использовании if (a1_state == 0) ... компилятор генерит код, который осуществляет проверку значения переменной a1_state на равенство сначала 0, потом 1, потом ... долго в общем. Пробовал еще так:
Код
typedef void (* StatePtr ) ( void );

void state0( void ) {}
void state1( void ) {}
...

const StatePtr states[] = {state0, state1, state2, state3};

char a1_state = 0;

void main()
{
 while (1)
 {
   // some stuff
   states[a1_state] ();
 }
}

Но перед вызовом функции states[a1_state]() компилятор загружает полный адрес функции, после чего вызывает cranky.gif . А если у меня все в одной странице помещается? Зачем тогда полный адрес?

Как лечить, что читать?

Извиняюсь за возможные ошибки, но с пиками знаком лишь один месяц biggrin.gif

Samrat
Значит так, про страницы памяти можно позабыть и просто писать код, он сам всё сделает. чем проще пишешь тем легче компилируется, для интереса там есть опция компиляции в ассемблер. Можешь посмотреть код на асме.
Samrat
И вообще красивый баннерок моей лисичке тоже понравилось, я заставил её прикинутся Осликом и вижу что получилось. Извини за OFFTOPIC.
DukeXar
Вот нашел http://www.microchipc.com/Hi-Tech_C_speed_optimization.htm

Цитата
In switch - case, change constants to be sequental numbers, without gaps.

Цитата
Optimization Tip 5: Case statements

Slow and Inefficient

CODE

c=getch();
switch©
{
  case 'A':
  {
    do something;
    break;
  }

  case 'H':
  {
    do something;
    break;
  }

  case 'Z':
  {
    do something;
    break;
  }
}


Fast and Efficient

CODE

c=getch();
switch©
{
  case 0:
  {
    do something;
    break;
  }

  case 1:
  {
    do something;
    break;
  }

  case 2:
  {
    do something;
    break;
  }
}

The Hi-Tech C optimizer turns the switch statement into a computed goto if possible.

Пробовал я такой switch. Нифига он его в computed goto не компилит angry.gif
Делает как в первом, так и во втором случае следующее:
Код
movf c, W
btfsc STATUS, Z
goto case_0
xorlw 1
btfsc STATUS, Z
goto case_1
xorlw 2
btfsc STATUS, Z
goto case_2

Ну и в чем же разница между "Slow and Inefficient" и "Fast and Efficient"? Где грабли?
Samrat
Проще пишите, ещё проще поставьте ряд IF, и самое главное не поднимайте степень оптимизации выше 1-2 эффекта это даёт мало, а ошибок много. структуру switch - case использовать не желательно. лучше if- elseif - else.
Samrat
"Особенность" данного чудо - компилятора состоит в том что он проглатывает все стандартные Сишные обороты включая очень круто - завёрнутые, но не все их поддерживает. НО то что работает- работает очень хорошо.
Samrat
Рекомендую попробовать такой вариант:
if(A > 10)
{

}
else if((A <10) && (A > 0))
{

}
else
{

}
До сего дня у меня работал, думаю должен работать и у Вас.
DukeXar
Шаблонов не хватает, AKA C++ a14.gif
Спасибо, попробую и так.
DukeXar
Да, с X86 проще - знаешь какой код сгенерит компилятор. Да и время реакции не то.

И вот еще вопрос назрел. Я пока пишу на асме, но планирую перейти на C. Так вот, мне надо генерить пачку из 10 импульсов по 10мкс (скважность 50%) для управления тиристором в начале каждой фазы. Что я делал на асме: каждую миллисекунду проверял наличие фазы с датчика и, соответственно, генерил пачку. Если ее генерить не надо было - выполнял другие действия (считал, обновлял дисплейчик, проверял кнопочки итд.) К услугам таймера прибегал только для того, чтобы выдержать это время в 1мс с начала выполнения задачи. Задач было несколько и, поскольку у меня асм, я мог легко определить время выполнения каждой из них и соответственно перемешать так, чтобы суммарное время выполнения не превышало эту 1мс. Частота камня 4МГц. Прерывания не использовал. При использовании С, черт его знает, что он там состряпает. Я так понимаю, что выход один - использовать прерывание от таймера и в нем выполнять обработку? Наверняка с проблемой генерации таких коротких последовательностей сталкивались, где бы посмотреть примерчик, а то я еще студент blush.gif, в смысле не волшебник rolleyes.gif И еще: если вместо кварца на 4МГц поставить на 8МГц или больше - будет ли устройство более чувствительно к помехам, особенно, если монтаж пока выполнен на макетке проводом?
katarsis
мне кажется имеет смысл все переписать для работы с прерываниями. в этом нет ничего сложного. я вот делаю примерно так:
1. в файле picxxxx.lkr вносим изменения:
CODEPAGE NAME=resvectors START=0x0 END=0x3 PROTECTED
CODEPAGE NAME=intvectors START=0x4 END=0xff PROTECTED
CODEPAGE NAME=page START=0x100 END=0x3FE


SECTION NAME=RESET_VECTOR ROM=resvectors // Reset and interrupt vectors
SECTION NAME=INT_VECTOR ROM=intvectors // Reset and interrupt vectors
SECTION NAME=PROG ROM=page // ROM code space

теперь у нас разделен вектор ресета (начальной загрузки) и прерывания. числа обязательно проверяются по мануалу. да бы не париться с банками я обычно откаменцичаваю
//SHAREBANK NAME=gpr0 START=0xA0 END=0xDF
так что переменные созданые через res выбираются тока в нулевом банке. wink.gif
Теперь в .asm. Начало кода будет как
RESET_VECTOR CODE ; processor reset vector
goto main ; go to beginning of program
с ресета идем на меин wink.gif

INT_VECTOR CODE ;interrupt vector location
movwf w_temp ;save off current W register contents
movf STATUS,w ; move status register into W register
movwf status_temp ; save off contents of STATUS register
bcf PORTC,0
goto but
сохранили регистры w, STATUS далее проверили от чего прерывание. в данном случае проверялась ножка по порту. далее так же можно проверить по завершенности работы таймера и т д.
хочется заметить, что в процессе работы с 16ыми пиками нашелся интересный глючек. как известно у 16го пика 8ми уровневый стек, но при этом нет флажка в флайловых регистрах сообщающих о его переполнении. при таком раскладе вроде бы можно отрываться на прерывание и не возвращаться из него по retfie. ну в общем это не так )) в дебаггере все работает на ура, а в реальной плате пик либо просто не шьется, либо сходит сума. ...мы разменяли с пяток адамов пока поняли в чем дело ))) (с).
а потом совсем все просто. запускаешь таймер разрешаешь прерывания, пускаешь вечный цыкл время от времени его будет отдергивать по таймеру. вот так.
кстати в си ты всегда можешь подсунуть асемблерный год при помощи
#asm
blabla
#endasm
Samrat
Вообще, конечно придётся делать от прерываний таймера. Конечно можно просто поднять частоту, это криминал, но не великий, просто поднимется ток потребления. Лучше при этом ещё и перейти на серию контроллеров в маркировке которой стоит цифра 10, а лучше 20 это позволит поднять частоту до указанных цифр. И конечно воспользоваться опцией : компиляции в асм для контроля длин ходов программы.
Epikur
Могу подсказать точно работающий способ создания табличных функций, которые работают лучше.
Предположим, что функция берёт в качестве параметра unsigned char и возвращает параметр unsigned short согласно таблице.
Тогда где-нибудь в заголовочном файле или отдельно создаём постоянный массив, по порядку вписываем туда все значения, а в теле функции просто делаем выбор из массива.
Код
const unsigned short TableOne[128] = {0x0EDA, 0x0000, ....};

unsigned short MyFunction (unsigned char Param)
{
   Param &= 0x007F;
   return TableOne[Param];
}

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

А вот делать функции так, чтобы компилятор создавал код навроде этого:
Код
CLRF PCLATH;
BSF PCLATH, 2;
ANDLW 0x07;
ADDWF PCL, F;

GOTO Branch_01;
GOTO Branch_02;
GOTO Branch_03;
GOTO Branch_04;
GOTO Branch_05;
GOTO Branch_06;
GOTO Branch_07;
GOTO Branch_08;

Branch_01:
....
Branch_02:
.....

Такого я ещё не умею.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.