Страница 42 из 103
Re: Програмирование pic на СИ.
Добавлено: Пт окт 14, 2016 18:17:33
foton6
Приветствую пиководы)
Подскажите как получить доступ к переменными из СИ кода в ассемблерной вставке?
Код: Выделить всё
uint8_t AAA
asm("BSF AAA, 7"); //__Установить 7 бит в переменной ААА.
Именно такая форма записи не катит, при компиляции пишет: "не определен символ AAA (или както так)".
Когда писал под x86 то использовал подобную форму записи:
Наверняка в XC8 тоже есть нечто подобное, но в мануале на XC8 описано только обычное: asm("_cod_")
Re: Програмирование pic на СИ.
Добавлено: Пт окт 14, 2016 18:33:35
Zhuk72
Код: Выделить всё
uint8_t AAA
asm("BSF _AAA, 7"); //__Установить 7 бит в переменной ААА.
Re: Програмирование pic на СИ.
Добавлено: Пт окт 14, 2016 18:46:55
foton6
Zhuk72 писал(а):Код: Выделить всё
uint8_t AAA
asm("BSF _AAA, 7"); //__Установить 7 бит в переменной ААА.
Спасибо))) Тоже только что об этом вспомнил, как раз на x86(а может еще где, не помню) вроде бы
вызов СИщных функция из АСМа реализован при помощи черточки)
Если кому интересно еще можно так:
Код: Выделить всё
#define asm_BTFSS(mark, adr, bit) asm("BTFSS " #adr "," #bit); \
asm("GOTO " #mark)
в итоге получаем:
Естественно метка вешается где нибудь (mark - меняется на любую надпись.):
Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 11:53:18
Zhuk72
У меня глупый вопрос про ХС8 ))
Берет ли компилятор на себя все связанное с банками, правильным размещением переменных в памяти и прочим?
Дело в том, что у меня в программе происходят странности с кодом, переполнение стека при определенных обстоятельствах и ветвление кода в непредсказуемые места. PIC16F876A.
Итак, имеются 2 массива. Первый из них - одномерный const unsigned char SYM[16] содержит символы 7-сегментника. Второй - двухмерный signed char [11][2]. Нулевой столбец последнего содержит цифры (0...9), а в первом располагаются соответствующие им символы для выдачи на индикатор. В процессе работы программы цифры могут меняться пользователем, каждое изменение цифры в нулевом столбце тут же сопровождается подбором его символа в первом столбце командой
dsp[dig][1] = SYM[dsp[dig][0]];
С этим проблем нет.
При старте программы последние введенные цифры загружаются из ЕЕПРОМ (num_load), преобразовываются в символы (dig2sym) и выводятся на дисплей.
Код: Выделить всё
void num_load (void)
{
static unsigned char a = 0;
EEPGD = 0; // Выбор ЕЕПРОМ области
while (a < 11)
{
EEADR = a;
RD = 1; // Запуск чтения
dsp[a][0] = EEDATA; // Сохранение
a++;
}
}
Код: Выделить всё
void dig2sym (void)
{
static unsigned char a = 0;
while (a < 11)
{
dsp[a][1] = SYM[dsp[a][0]];
a++;
}
}
Так вот совместно они не работают. Чтение из ЕЕПРОМ происходит, а когда дело доходит до преобразования, программа начинает уходить в такие дебри, где ее никто не ждал. Шагал по ассемблерному коду в Протеусе, но он скорее всего не виноват, ибо код такой получается.
Если же я обхожу чтение из ЕЕПРОМ (// num_load), и назначаю цифры вручную, то преобразование (dig2sym) работает нормально. Оно также работает нормально, если комментирую только одну строку:
dsp[a][0] = EEDATA.
Пробовал делать и через указатели с тем же успехом, но эта тема для меня пока малопонятная, так что пока решил в лес не углубляться. Оптимизацию отключал. Не вариант.
Сижу со вчерашнего вечера в ступоре и пытаюсь поумнеть. Поможете?

Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 12:15:21
КРАМ
При объявлении переменной компилятор сам определяет ей место в памяти и в дальнейшем управляет банками при пользовании ей.
Однако.
Существуют СПЕЦИАЛЬНЫЕ квалификаторы переменных, с помощью которых можно ЗАСТАВЛЯТЬ компилятор размещать переменную в определенном банке или области памяти.
Смотрите описание на конкретный компилятор.
Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 14:43:51
Zhuk72
Назначения адресов массивов вручную ничуть не улучшили ситуацию.
Добавлено after 16 minutes 2 seconds:
Добавил еще один массив
unsigned char test[11] = {8,9,1,6,1,2,3,4,5,6,7};
В процедуре загрузки из ЕЕПРОМ заменил строку
dsp[a][0] = EEDATA;
на
dsp[a][0] = test[a];
, и все работает правильно.
Что не так с чтением из ЕЕПРОМ? Почему она коверкает программу?
Привожу ее еще раз для наглядности:
Код: Выделить всё
void num_load (void)
{
static unsigned char a;
a = 0;
EEPGD = 0;
while (a < 11)
{
EEADR = a;
RD = 1;
dsp[a][0] = EEDATA;
a++;
}
}
Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 17:07:31
КРАМ
Неплохо бы привести дизасм этого участка кода.
Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 22:47:05
Zhuk72
Вот:
Спойлер
Код: Выделить всё
Line Address Opcode Label DisAssy
385 0180 01FB num_load CLRF a
386 0181 1683 BSF STATUS, 0x5
387 0182 1703 BSF STATUS, 0x6
388 0183 138C BCF PIR1, 0x7 ; bit 7 PSPIF(1): Parallel Slave Port Read/Write Interrupt Flag bit
389 0184 300B MOVLW 0xB
390 0185 027B SUBWF a, W
391 0186 1803 BTFSC STATUS, 0x0 ; STATUS,C
392 0187 0008 RETURN
393 0188 087B MOVF a, W
394 0189 1283 BCF STATUS, 0x5
395 018A 1703 BSF STATUS, 0x6
396 018B 008D MOVWF PIR2 ; bit 4 EEIF: EEPROM Write Operation Interrupt Flag bit ????
397 018C 0000 NOP
398 018D 0000 NOP
399 018E 0000 NOP
400 018F 0000 NOP
401 0190 1683 BSF STATUS, 0x5
402 0191 1703 BSF STATUS, 0x6
403 0192 140C BSF PIR1, 0x0 ; bit 0 TMR1IF: TMR1 Overflow Interrupt Flag bit
404 0193 087B MOVF a, W
405 0194 3E3C ADDLW 0x3C
406 0195 0084 MOVWF FSR
407 0196 1383 BCF STATUS, 0x7 ; bit 7 IRP: Register Bank Select bit
408 0197 0800 MOVF INDF, W
409 0198 1283 BCF STATUS, 0x5
410 0199 1303 BCF STATUS, 0x6
411 019A 00C7 MOVWF 0x47
412 019B 1003 BCF STATUS, 0x0 ; STATUS,C
413 019C 0D7B RLF a, W
414 019D 3E20 ADDLW 0x20
415 019E 0084 MOVWF FSR
416 019F 0847 MOVF 0x47, W
417 01A0 0080 MOVWF INDF
418 01A1 0AFB INCF a, F
419 01A2 2984 GOTO 0x184
Добавлено after 6 minutes 1 second:
Резюмирую все сказанное ранее: с самой функцией чтения проблем нет, она читает из ЕЕПРОМ и сохраняет считанное по нужным адресам в массиве. Но функции, которые идут за ней начинают сходить с ума. Программа переходит не по тем адресам, иногда хаотично, иногда на вектор сброса.
Но стоит закомментировать вызов num_load, как все начинают ходить куда положено.
Ответ лежит где-то на поверхности, но я его не вижу
Добавлено after 5 hours 19 minutes 57 seconds:
Переписал чтение из ЕЕПРОМ на асм, ничего не глючит, но и чтение не работает
Где-то я накосячил на сонную голову.
Завтра буду разбираться, но это не выход. Не для того я ушел от ассемблера, чтобы им же потом свои сишные прорехи залатывать

Re: Програмирование pic на СИ.
Добавлено: Чт окт 27, 2016 23:22:28
Аlex
а когда дело доходит до преобразования, программа начинает уходить в такие дебри, где ее никто не ждал
А в каком конкретном месте она улетает ? При вызове
dig2sym или где то внутри функции ?
На чём тестируете, только в протезе, или на железе тоже вылезает такой косяк ?
Попробуйте заменить всё, что касается чтения, на компиляторскую библиотечную функцию чтения EEPROM.
Если не поможет. Создайте проект с минимальным кодом, при котором вылезает такая бяка и выложите всё сюда, вместе с файлом протеза. Если будет время, можно будет погонять код.
Добавлено after 27 minutes 41 second:
И ещё.
Вы уверены, что в массив dsp[a][0] читаются значения из EEPROM, не выходящие из диапазона 0..15 ? Ведь по этим значениям потом идёт адресация по массиву
SYM. Мало того, т.к. константы компилятор разместит во флеш, то адресация идёт через PCL, а это значит, что любые отличия от этого диапазона приведут к прыжку в неизвестном направлении. Обязательно сделайте в программе ограничение, не позволяющее выходить этим значениям из диапазона. Компилятор за Вас этого не сделает.
И ещё. Почему массив
dsp знаковый ?
Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 06:43:49
Zhuk72
Программа уходит налево на команде dsp[a][1] = SYM[dsp[a][0]]; В зависимости от видоизменений в программе это может быть 0, а может и основной цикл. Там всего 3 проверки, после чего она возвращается на а++. И так ходит по кругу. Проверяю в Протеусе. Это не для меня, потому я паять ничего не буду ))
Обидно, все готово и работает, а такая мелочь, которая за 5 минут на ходу написалась, всю работу затормозила.
Встроенную EEPROM_READ тоже пробовал с тем же результатом. Попробую выкинуть все лишнее и проверить.
Старшие 6 байтов в SYM - это буквы и они не используются, так что ухода за пределы 10 первых точно не происходит. Я даже пробовал глупость сотворить: как положено сохранил w, status и pclath перед входом в num_load, и восстановил перед выходом из функции

Не помогло.
По поводу знака )) Изначально ( и я опять к этому вернулся) массивов переменных было два, один для цифр (num), другой для соответствующих им символов (dsp). Так вот когда в программе пользователем перебираются цифры, проверка на переполнение выше 9 не вызывало беспокойства компилятора (что резонно), а выражение
if ((--num[a]) < 0) num[a] = 9; вызывала предупреждение о том, что переменная незнаковая. Компиляция проходила, но я на всякий случай сделал массив знаковым.
Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 07:39:57
Аlex
Zhuk72 писал(а):Программа уходит налево на команде dsp[a][1] = SYM[dsp[a][0]];
Значит в массив заполняются значения, отличные от диапазона 0..15. Погоняйте в отладке и посмотрите эти значения.
Zhuk72 писал(а):но я на всякий случай сделал массив знаковым.
А не проще было написать условие, удовлетворяющее беззнаковую переменную ?

Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 08:11:21
Zhuk72
В том-то и дело, что массив заполняется корректно. Если перед этим не читать ЕЕПРОМ ))
Условие для unsigned можно было написать, но, во-первых, лениво, т.к. это вариант для энкодера, а в конечном варианте будет только кнопка для приращения и проверка на убывание будет не нужна. А во-вторых, размерность массива в обоих случаях одинакова, и одна проверка старшего бита программу не испортит

Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 08:39:58
Аlex
Zhuk72 писал(а):Если перед этим не читать ЕЕПРОМ ))
Дак о чём я Вам и говорю, что именно из EEPROM читаются некорректные для индексации массива значения

Если Вы работали с ассемблером, то хорошо должны представлять себе выборку из массива, находящегося во флеши, на МК, не имеющих табличного чтения.
Поставьте ограничение. Ну или, ради эксперимента, разместите массив
SYM в ОЗУ. И всё заработает
Добавлено after 9 minutes 34 seconds:
Нужно всего-то добавить пару строк :
Код: Выделить всё
void dig2sym (void)
{
unsigned char a = 0, i;
while (a < 11)
{
i=dsp[a][0];
if(i>15) i=15;
dsp[a][1] = SYM[i];
a++;
}
}
Добавлено after 16 minutes 42 seconds:
Да, и ещё. static уберите из переменной "a", иначе при втором и последующих вызовах функции, она не будет инициализироваться нулём.
Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 08:45:11
Zhuk72
Alex, я собирался, торжествуюше хихикая, выложить это:
Код: Выделить всё
eeprom unsigned char number[16] = "89161234567\0\0\0\0\0";
а следом это:
и тут я сделал
Получается, что в массив копируется не число, а его аски код. Соответственно PCL уводит программу к черту на кулички.
Я - дубина! А вам - спасибо, в очередной раз, огромное!
Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 09:05:31
Аlex
В любом случае, добавьте проверку на корректность. 2 строки роли не сыграют, а от глюка могут спасти.
Re: Програмирование pic на СИ.
Добавлено: Пт окт 28, 2016 10:22:13
Zhuk72
Да, теперь все работает
Проверку на диапазон 0-9 сделаю, потому как возможна некорректная запись в ЕЕПРОМ и последующее чтение кривых данных из него во время старта вызовет кОтОклизму автору, т.е. мне
Еще раз спасибо!
Добавлено after 47 minutes 22 seconds:
Этого будет достаточно:
Код: Выделить всё
if (EEDATA < 10) num[a] = EEDATA;
else num[a] = 0;
Re: Програмирование pic на СИ.
Добавлено: Чт ноя 03, 2016 16:51:28
Zhuk72
Други, почему не компилится выражение
asm("rlcf _test,f,0"); ?
Компилятор ХС8, test объявлен как unsigned char. Выдает ошибку синтаксиса.
Отвечаю сам себе: потому что надо писать
asm("rlcf _test,f,с");
К тому же это не работает с локальными переменными, только с глобальными.
Спойлер
Newer versions of XC8 generate a "error: (876) syntax error" to the use of the above. It turns out ",1,0" on the end of the addwf and addwfc lines are the issue (even though these numeric values are specified for use in device datasheets).
The '1' needs to change to 'f' for file register.
The '0' needs to change to 'c' for common memory / access ram (the alternative would be 'b' for bank select register.
http://www.electronics-design.net/embedded-programming/microchip-pic/mplab-x/issues/inline-assembly-generates-error-876-syntax-error
Re: Програмирование pic на СИ.
Добавлено: Пн ноя 07, 2016 21:17:11
botchin
Ето не вопрос. Ето особенность компилятора HI-TECH 9.71a - фрагмент кода
Код: Выделить всё
char *s1,*s2,*s3, ss [10];
void main(void)
{
s1 = ss ;
s2 = ss ;
s3 = ss ;
if(s1 == s2)
NOP();
#asm
movlw _s3
#endasm
597. if(s1 == s3)
NOP();
Сам код безсмъсленнъй. Но ... оказъвается (и про ето прочитал где-то) компилятор сам решает (анализируя кода) какая разрядность у указателей. В етом коде он решил что у s1 и s2 разрядность 1 байт, а у s3 - 2 байта - из за участие s3 в #asm директиве . При попътке скомпилировать етот фрагмент въдает
Error [712] C:\Users\botchin......_1829_2.c; 597. can't generate code for this expression
Тот же самъй резултать если попътаемся иницилировать указателей так: s1 = s2 = s3 = ss;
В асемблере двубайтнъй указатель иницилизируется так:
Код: Выделить всё
588: s1 = ss ;
0174 3047 MOVLW 0x47
0175 00D3 MOVWF 0x53 //1 байт
589: s2 = ss ;
0176 00D4 MOVWF 0x54 //1 байт
590: s3 = ss ;
0177 00D1 MOVWF 0x51 //младшая част
0178 01D2 CLRF 0x52 //старшая
Видим для s1,s2 - 1 байт, s3 - 2 байта
и как мне не стъдно самое тупое решение 1- следить за таких указателей и 2-конверсия типов
Код: Выделить всё
if(s1 == (char *)(char)s3) // стъд
NOP();
////////////////////
597: if(s1 == (char *)(char)s3)
017F 0020 MOVLB 0
0180 0853 MOVF 0x53, W
0181 0651 XORWF 0x51, W //работает только "младшая" часть
0182 1903 BTFSC 0x3, 0x2
598: NOP();
0183 0000 NOP
Другая особенность:
имеем функцию
Код: Выделить всё
void test(void)
{ ......
#asm
......
loop_test
decfsz _xxx,f
goto loop_test
#endasm
.....
}
Все нормально если възъваем функцию однократно, но если попътаемся възвать ее более раза то получаем сообщение
Error [845] C:\Users\botchin........_1829_2.c; 525. symbol "loop_test" defined more than once
Я понимаю, что ето в резултате работъ препроцессора, но все таки - .....

Re: Програмирование pic на СИ.
Добавлено: Пн ноя 07, 2016 21:35:18
Аlex
Это может быть зарегистрированный компилятором регистр. Не могут одинаковые указатели иметь разный размер
botchin писал(а):Все нормально если възъваем функцию однократно, но если попътаемся възвать ее более раза то получаем сообщение
Error [845] C:\Users\botchin........_1829_2.c; 525. symbol "loop_test" defined more than once
Скорее всего, компилятор инлайнит эту функцию. Отсюда и сообщение о дублировании метки.
Re: Програмирование pic на СИ.
Добавлено: Пн ноя 07, 2016 21:56:20
botchin
Аlex писал(а):Не могут одинаковые указатели иметь разный размер
И я думал так. Попробую опять найти где описъвали етот момент. А если вас не затрудняет и имеете 9,71 - проиграйте.
Но я, кстати, думал что .h фаил для какой-то камень коректнъй, а пришлось переделъвать файл. точнее для PIC16F1829
pic16f1829.h
Код: Выделить всё
// Config Register: CONFIG2
#define CONFIG2 0x8008
// 4x PLL disabled
#define PLLEN_OFF 0xFEFF //corr old 0xFDFF
// Stack Overflow/Underflow Reset Enable
#define STVREN_OFF 0xFDFF //corr old 0xFBFF
// Brown-out Reset Voltage (VBOR) set to 2.5 V
#define BORV_25 0xFBFF //corr old 0xF7FF
// High-voltage on MCLR/VPP must be used for programming
#define LVP_OFF 0xDFFF //corr old 0xBFFF
Вот - в
HI-TECH C® for PIC10/12/16 User’s Guide
There are several pointer classifications used with the HI-TECH C Compiler for
PIC10/12/16 MCUs, such as those indicated below.
• An 8-bit pointer capable of accessing common memory and two consecutive banks, e.g. banks 0 and 1, or banks 7 and 8, etc.
• A 16-bit pointer capable of accessing the entire data memory space
• An 8-bit pointer capable of accessing up to 256 bytes of program space data
• A 16-bit pointer capable of accessing up to 64 kbytes of program space data
• A 16-bit pointer capable of accessing the entire data space memory and up to 64 kbytes of program space data
Each data pointer will be allocated one of the available classifications after preliminary
scans of the source code. There is no mechanism by which the programmer can specify
the style of pointer required (other than by the assignments to the pointer). If the C
code does not convey the required information to the compiler, then it is not complete
or accurate.