Поклонники продукции Microchip Technology Inc тусуются тут.
Ответить

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:04:45

Siarzhuk писал(а):pos это не переменная, и даже не тип (в С) - а именно что НеизвестнАЯ ИдентификАтыръ. :)

И как тогда мне ее, структуру, объявить, если struct pos {unsigned char x, y;}; объявлено неправильно?

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:08:41

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

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

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:09:39

Zhuk72 писал(а):
Siarzhuk писал(а):pos это не переменная, и даже не тип (в С) - а именно что НеизвестнАЯ ИдентификАтыръ. :)

И как тогда мне ее, структуру, объявить, если struct pos {unsigned char x, y;}; объявлено неправильно?


Вот у КиР написано
Код:
struct point {
                  int x;
                  int у;
                  } ;

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:14:03

Zhuk72 писал(а):И как тогда мне ее, структуру, объявить, если struct pos {unsigned char x, y;}; объявлено неправильно?
лично я в подобных "подозрительных" случаях всегда объявляю пользовательский тип - ни разу сбоев не было!
Код:
typedef struct{
   unsigned char x, y;
} point_t;

pint_t pos;


Добавлено after 1 minute 49 seconds:
КРАМ писал(а):Категоричные заявления о вредности нестандартных типов из-за непереносимости кода не выдерживают никакой критики
категорические утверждения о невыдерживнии критики не выдерживают никакой критики :)))
потому что если есть стандарт, то надо максимально соблюдать его требования все время, пока не попал в безвыходную ситуацию. а уж в безвыходной ситуации все средства хороши.

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:18:01

ARV писал(а):это на самом деле так? не 1 байт?

Третьего дня самолично в RX-GCC наткнулся. :-) Причём директивы упаковки не спасли. Не PIC, конечно - но иметь ввиду вероятность такого сюрприза не помешает, кмк.

Siarzhuk писал(а):скорее всего он задействует для этой цели аппаратные фичи кристалла. про PIC не скажу, а в MCS51 есть особые области ОЗУ с побитовой адресацией

Обнаружил это в PIC16F630 с XC8 когда и сам заталкивал в него побольше функционала на фоне исчерпания .data. XC8, правда, был Free версии - а в этом режиме он имеет привычку оптимизировать с прохладцей, саботажем и лёгким вредительством - и если в PRO версии с глобальными bit по другому работает - ну тогда я не прав. :)
Последний раз редактировалось Siarzhuk Пт ноя 18, 2016 13:38:48, всего редактировалось 1 раз.

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:18:45

Аlex писал(а):Ещё, плюс объединений переменных в структуры - обработка в функциях. Можно передавать указатель, как аргумент, вместо кучи переменных.

Правда это удобство приводит к достаточно громоздкому скомпилированному коду в КАЖДОЙ функции, куда передается указатель на структуру. Потому как до конкретного элемента структуры нужно еще добраться.
ARV писал(а):
КРАМ писал(а):Категоричные заявления о вредности нестандартных типов из-за непереносимости кода не выдерживают никакой критики
категорические утверждения о невыдерживнии критики не выдерживают никакой критики :)))
потому что если есть стандарт, то надо максимально соблюдать его требования все время, пока не попал в безвыходную ситуацию. а уж в безвыходной ситуации все средства хороши.

Есть стандарт языка, но нет стандарта для создаваемого кода. Все средства хороши В ЛЮБОЙ ситуации.
Более того, если программист не применяет эти самые "все средства" всегда, то в "безвыходной ситуации" он оказывается достаточно беспомощным и полученный код действительно не выдержит никакой критики...

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:30:30

ARV писал(а):лично я в подобных "подозрительных" случаях всегда объявляю пользовательский тип - ни разу сбоев не было!

Спасибо, получилось!

ARV писал(а):про PIC не скажу, а в MCS51 есть особые области ОЗУ с побитовой адресацией, и соответствующие однобитовые команды ассемблера. так что и тут речь скорее всего об этом - линкер отдыхает.

Именно в ПИКовом проекте объявлял биты, а потом в отладчике наблюдал, как они все оказывались в одном регистре в области общей памяти.

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 13:37:02

Zhuk72 писал(а):И как тогда мне ее, структуру, объявить, если struct pos {unsigned char x, y;}; объявлено неправильно?

Объявлен тип, но не объявлена переменная этого типа. :)

С битовыми полями ещё и на проверке индексов можно экономить:

Код:
#define BIT_SIZE 4
char ringBuffer[1 << SIZE];
struct {
  char headIndex : BIT_SIZE;
  char tailIndex : BIT_SIZE;
};


Добавлено after 1 minute 37 seconds:
Zhuk72 писал(а):а потом в отладчике наблюдал, как они все оказывались в одном регистре в области общей памяти.

В map-файл если ешё не заглядывали - тоже, кмк, будет интересно глянуть.

Re: Програмирование pic на СИ.

Пт ноя 18, 2016 14:34:52

Всем спасибо за очень познавательную дискуссию :)
Удаляюсь для воплощения.

Re: Програмирование pic на СИ.

Сб ноя 19, 2016 08:56:58

В итоге решил делать так:
Код:
typedef struct {unsigned work: 1;
                unsigned btn_start: 1;
                unsigned flash: 1;
                unsigned b3: 1;
                unsigned b4: 1;
                unsigned b5: 1;
                unsigned b6: 1;
                unsigned b7: 1;} bits;
bits flag;

Поскольку использовать в подобных конструкциях более, чем 1 бит, только ухудшит конечный код (в асме добавятся маски и сдвиги, как я предполагаю), указанное выше - это просто удобство помнить только одну переменную с именем flag, в которую по необходимости можно добавлять и другие подобные флаги.

Re: Програмирование pic на СИ.

Сб ноя 19, 2016 10:46:11

Zhuk72 писал(а):Поскольку использовать в подобных конструкциях более, чем 1 бит, только ухудшит конечный код (в асме добавятся маски и сдвиги, как я предполагаю)

На всякое категоричное утверждение найдётся аргу́́мент. :) Если .data уже закончился, а .text ещё полупустой - разменять таким образом RОМ на RAM будет вполне себе выходом.
[pedantic mode on]
Если не затруднит - гляньте sizeof(bits) пожалуйста и нам сообщите для общего развития. И да - unsigned это unsigned int, и, припоминаю, явное указание вместо int восьмибитного типа в конкретном случае оптимизации под PIC16F630 сэкономило мне в своё время, таки парочку байтов. Стоит тоже проверить, кмк. :)
[pedantic mode off]

Re: Програмирование pic на СИ.

Сб ноя 19, 2016 15:31:25

Siarzhuk писал(а):[pedantic mode on]
1. Если не затруднит - гляньте sizeof(bits) пожалуйста и нам сообщите для общего развития.

2. И да - unsigned это unsigned int, и, припоминаю, явное указание вместо int восьмибитного типа в конкретном случае оптимизации под PIC16F630 сэкономило мне в своё время, таки парочку байтов. Стоит тоже проверить, кмк. :)
[pedantic mode off]


1. Я не волшебник, я только учусь (с) :))
Вы только намекните где это можно увидеть, а я сразу же...

2. Вот тут я в сомнениях. Что-то написать там нужно, но что именно, чтоб они все упаковались в один байт - я не знаю. Пока времени не было уточнить.

Re: Програмирование pic на СИ.

Сб ноя 19, 2016 17:00:31

Zhuk72 писал(а):2. Вот тут я в сомнениях. Что-то написать там нужно, но что именно, чтоб они все упаковались в один байт - я не знаю. Пока времени не было уточнить.

Битовые поля по-честному укладываются на соответствующие биты - вопрос лишь в том, сколько займёт структура. Можно глянуть в отладчике. Можно прикинуть по map-файлу. Вот например ваши флаги в моём файле:

Код:
_ep_data_out                       bssBANK2     0131
_flag                              bssBANK0     006A                     <--------- flag (в банке 0)
_hid_rpt01                         stringtext   1500
_i2cProtocol                       dataCOMMON   007B
_idle_rate                         bssBANK2     0143
_inBuffer                          dataCOMMON   0079
_inPipes                           bssBANK2     013D
_main                              cinit        104B
_notifyChunks                      bssBANK0     006B                     <--------- следуюший за flag-ом в банке 0
_outBuffer                         dataBANK0    006E


Т.е. очевидно, что всё уместилось в байт. Добавляем девятое поле:

Код:
_ep_data_out                       bssBANK2     0131
 _flag                              bssBANK2     0133                     <---------
 _hid_rpt01                         stringtext   1500
 _i2cProtocol                       dataCOMMON   007B
 _idle_rate                         bssBANK2     0144
 _inBuffer                          dataCOMMON   0079
 _inPipes                           bssBANK2     013E
 _main                              cinit        1048
 _notifyChunks                      bssBANK0     006A
 _outBuffer                         dataBANK0    006E
 _outPipes                          bssBANK2     0120
 _pBDTEntryEP0OutCurrent            bssBANK1     00EA
 _pBDTEntryEP0OutNext               bssBANK1     00EB
 _pBDTEntryIn                       bssBANK2     0135                     <--------- 134-го в bssBANK2 нету
 _pBDTEntryOut                      bssBANK2     0137

Ага, два байта. И во вторую банку переместилось из нулевой - в которой очевидно место закончилось.

А упаковка относится к структурам, поскольку компилятор порой раскладывает их поля по выровненным (aligned) адресам, для ускорения работы с ними. В итоге размер такой структуры будет больше нежели сумма размеров её элементов. Если вам извне придёт пакет данных без подобных "прорех" - разобрать его простым наложением структуры на указатель будет несколько затруднительно. Поэтому при объявлении нужно явно указывать:

Код:
typedef struct __attribute__ ((packed)) _USB_DEVICE_DESCRIPTOR
{
    uint8_t bLength;               // Length of this descriptor.
[...]


Ну и за компанию про глобальные bit переменные. Добавим горсть малую в тестовый кот с вашим битовым полем:

Код:
bit bit1;
bit bit2;
bit bit3;
bit bit4;

MAIN_RETURN main(void)
{
   SYSTEM_Initialize(SYSTEM_STATE_USB_START);

   flag.b3 = 1;
   bit1 = 0;
   bit2 = 1;
   bit3 = flag.b7;
   bit4 = 0;

   if (flag.b6 == 1 && bit1 == bit3 || bit1 != bit2 || bit2 == bit4)
      USBDeviceInit();


И в мап-файле:

Код:
__size_ofi1_LED_On                 (abs)        0000
_active_protocol                   bssBANK2     0147
_bit1                              bitbssCOMMON 03D0                     <--------- следим
_bit2                              bitnvCOMMON  03C8                     <--------- за
_bit3                              bitnvCOMMON  03C9                     <--------- адреса-
_bit4                              bitbssCOMMON 03D1                     <--------- ми
_configDescriptor1                 stringtext   149C
_controlTransferState              bssBANK1     00E8
[...]
                Name                               Link     Load   Length Selector   Space Scale
[...]
                bssBANK0                             66       66        6       50       1
                dataCOMMON                           7B       7B        1       70       1
                bssCOMMON                            76       76        3       70       1
                bitbssCOMMON                        3D0       7A        2       70       1     8                     <--------- размер 2!
                bitnvCOMMON                         3C8       79        2       70       1     8                     <--------- тоже самое.
                stringtext                         1400     1400       DB       28       0
[...]

Т.е. оно их даже в один байт не упаковало. Вероятно справедливо рассудив, что "места у этого поца покамест ещё хватает". Что самое забавное в режимах PRO Speed и PRO без Speed - картина не меняется. :-)

PS: Других переменных типа bit кроме здесь показанных в программе нету если что.

Re: Програмирование pic на СИ.

Сб ноя 19, 2016 21:51:57

Вот мое объявление переменных на данный момент:
Код:
typedef struct {unsigned work: 1;
                unsigned btn_start: 1;
                unsigned flash: 1;
                unsigned b3: 1;
                unsigned b4: 1;
                unsigned b5: 1;
                unsigned b6: 1;
                unsigned b7: 1;} bits;
bits flag;
unsigned char flash_cnt, flash_pause;

А это в мар-файле:
Код:
_flag                    bssBANK0     0026
_flash_cnt               bssBANK0     0027
_flash_pause             bssBANK0     0028

Стало быть за границы одного байта ничего не вылезло :)

Re: Програмирование pic на СИ.

Чт янв 26, 2017 23:43:46

Доброго времени суток. Взялся попробовать С. Ну так, самую малость, просто чтобы понять что я теряю, колупаясь в асме. Хочу значит установить предделитель Таймера0. Пишу:
Код:
OPTION = 1<<0;

Гляжу в дизассемблер, вижу результат:
Код:
01A    3001     MOVLW 0x1
01B    1683     BSF 0x3, 0x5
01C    0081     MOVWF 0x1

В принципе устраивает (хотя я ручками покороче умею).
Помню, что на асме можно удобно по именам битов устанавливать/сбрасывать. На всякий случай лезу в заголовочный файл на используемый МК, и нахожу там заветные строчки
Код:
/*   OPTION bits   */
volatile   bit   RBPU   @ (unsigned)&OPTION*8+7;
volatile   bit   INTEDG   @ (unsigned)&OPTION*8+6;
volatile   bit   T0CS   @ (unsigned)&OPTION*8+5;
volatile   bit   T0SE   @ (unsigned)&OPTION*8+4;
volatile   bit   PSA   @ (unsigned)&OPTION*8+3;
volatile   bit   PS2   @ (unsigned)&OPTION*8+2;
volatile   bit   PS1   @ (unsigned)&OPTION*8+1;
volatile   bit   PS0   @ (unsigned)&OPTION*8+0;


Отлично, заменяю код на:
Код:
OPTION = 1<<PS0;

получаю в итоге:

Это как понимать ? :shock:

Re: Програмирование pic на СИ.

Пт янв 27, 2017 05:51:40

С чего это так не скажу, а для изменения отдельных бит в регистре всегда пользуюсь маской. Могли бы сделать так:
Код:
  OPTION |= 1;

или для второго случая
Код:
  PS0 = 1;

Но первый лучше.

Re: Програмирование pic на СИ.

Пт янв 27, 2017 07:27:55

Пока_без_кота писал(а):Это как понимать ? :shock:

А понимать это так, что компилятор при нулевом уровне оптимизации:
1. Сгенерировал ДОСЛОВНЫЙ код. То есть сделал ровно то, что было написано на Си, включая промежуточные действия.
2. Обеспечил атомарность, выполняя п.1
Таким образом, сначала произвел действия с константами справа и лишь потом присвоил результат регистру option_reg.
Как Вам передо мной уже сказали, заставить ДАННЫЙ компилятор выполнить битовую операцию при нулевой оптимизации можно макросом PS0=1.

Re: Програмирование pic на СИ.

Пт янв 27, 2017 19:03:27

Спасибо за ответы.

Re: Програмирование pic на СИ.

Ср фев 01, 2017 12:39:27

День добрый!

Подскажите как реализовать такую штуку.
Необходимо создавать "некие таймеры". Их число фиксировано и равно, допустим, 8.
Есть один системный таймер T0. Он считает до 255 и объявляет tick. Дальше по этому tick инкрементируется rtc_timer (может быть long, тут дело не в этом).

Сам "некий таймер" представляет из себя структуру следующих параметров:
-активный
-начало
-продолжительность
-функция окончания

По определенному событию (это не важно) - таймер активируется. "активный" выставляется в 1, в начало записывается текущее значение rtc_timer.

Обработчик таймеров постоянно (каждый цикл) проверяет rtc_timer и начало и продолжительность активных таймеров. как только "начало+продолжительность">=rtc_timer - "активный"=0 и выполняется функция.

Вроде алгоритм понятен, а в структурах я чот туплю.

Re: Програмирование pic на СИ.

Ср фев 01, 2017 12:50:46

Ну, примерно как то так :
Код:
typedef struct{
  unsigned          enabled :1;
  unsigned          start :1;          // Тут не понял, что за "начало" такое и зачем оно нужно...
  unsigned long     time;
  void*             call_back_func;  // Тут, скорее всего будет не так, а указатель на созданный ранее тип каллбека. Это уже тонкости
}Timer;
Ответить