Страница 211 из 386

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 10:10:22
COKPOWEHEU
Можно использовать указатель.

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 10:25:48
ARV
greenled писал(а):Доброго всем дня! Пишу тут прогу для МК с архитектурой 8051 на Си в Keil, увы, уровень владения языком невысок, но интересует такой вопрос: как ассоциировать с переменной какую-либо ячейку памяти данных? Делать ассемблерную вставку или можно как-то стандартными средствами кейловского си обойтись?
для MCS51 характерно "сопоставлять" переменные с определенными адресами в ОЗУ. по-моему, в кейле для этого есть расширение в виде "оператора" at или @ - точно не знаю, но вы можете посмотреть в любом хидере на периферию конкретного МК как там определены SFR-регистры, они точно привязаны к адресам...

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 10:45:25
greenled
Gudd-Head, нужно чтобы МК изредка принимал коэффициенты для ацп и хранил у себя во флеше
ARV, адреса SFR регистров есть, но как организовать к ним обращение? постоянно ссылаться на адрес или можно как-то организовать указатель на него?

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 10:52:29
ARV
вы не поняли: вам надо посмотреть в хидере, как определены переменные-SFR, и аналогично определить свои переменные. тогда никаких указателей не потребуется, и кейл сумеет использовать архитектурные особенности ассемблера для работы с вашими переменными, если таковые вдруг будут.

в хидере будет что-то типа такого:
unsigned char PCON at 0xF0;
вот и вам вашу переменную надо будет определить аналогично, например, если ее адрес 0x1A:
unsigned char my_var at 0x1A;
только имейте ввиду, что адрес PCON я просто от фонаря написал - не помню я настоящий.

в конце-концов хелп у вас в кейле есть или нет?! прочтите его...

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 10:53:47
Gudd-Head
greenled писал(а):как ассоциировать с переменной какую-либо ячейку памяти данных?
...
МК изредка принимал коэффициенты для ацп и хранил у себя во флеше
О как. Была память данных, стала память программ.

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 11:29:33
greenled
ARV, ок, большущее Спасибо)
Gudd-Head, нет, речь все еще о памяти данных) В даташите она фигурирует как Flash/EE, просто примелькалось

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 11:45:01
COKPOWEHEU
На уровне языка Си можно так

Код: Выделить всё

TYPE *b=0x????; // TYPE заменить на желаемый тип данных
#define A (*b) // обращение будет именно через А
#define B (*(TYPE*)0x????) // или так, если нет желания отъедать память лишней переменной
В С++ вроде есть штатный способ расположения переменной по определенному адресу

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 08, 2014 12:22:05
greenled
COKPOWEHEU, премного благодарен) заработало)

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 23, 2014 11:54:03
Ехан
Друзья, я столкнулся с таким вопросом. Написал програму на с++ для атмеги88, после запуска как и положено попадаю в 0x0000, но вот вся трудность заключается в том, что там находится далеко не функция main(), как я понимаю нужно всего лишь определить прерывание ресет, но вот найти как на с++ определить вектор этого прерывания мне найти не удалось. :\

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 23, 2014 15:38:59
Kavka
Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали. :)

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 23, 2014 16:19:14
uk8amk
Ехан писал(а):как на с++ определить вектор этого прерывания мне найти не удалось. :\
Эта "кухня" происходит в стартап коде, который пишется на асме. Из него и происходит вызов main().
Обычно нужный стартап подключается компилятором автоматически.

Кстати, если программа весьма примитивна(вроде помигать светодиодом), не использует стек и прерываний, то вполне возможно для AVR расположить main() по адресу 0x0000.

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 23, 2014 22:08:23
Ехан
Kavka писал(а):Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали. :)
Не навыкрутасничил, не знаю как. А стек боюсь использовать, как бы не послал куда не надо ;) Реализовал очередь прерываний с помощью динамической памяти, вычитал где-то: дабы не тратить время и не пропустить другое прерывание - зашел, отметился, вышел.

А есть чем дизассемблировать и прогнать на эмуляторе? Интересно посмотреть процедуры инициализации.

Re: Вопросы по С/С++ (СИ)

Добавлено: Ср дек 24, 2014 04:30:47
pokk
Ехан, AVR Studio

Подскажите, почему дефайн не вставляется ? У меня есть некий кусок кода для отладки и всё работало который я выключаю дефайном __DEBUG__ соответственен непременные который он используют тоже выключаются.

А вот в данном месте начинается на то что нету переменной current_type_eeprom оно и правильно я её раньше выключил. Но почему он вообще компилируется ? если заменить #ifdef DEBUG_MENU1 на #ifdef 0 то ошибок большее не появляется.
Вынос DEBUG_MENU1 из файла тоже не помогает. :dont_know:

Код: Выделить всё

//--------файл DEBUGER_SET--------------- 
#ifndef DEBUGER_SET_H
#define DEBUGER_SET_H
          #define __DEBUG__ 0  // 0-Отладка выкл  1-отладка вкл
           #define DEBUG_MENU 0
           #define DEBUG_MENU1 0
#define __DEBUG_1WIRE__ 0 //
#endif

//--------MAIN-----------------------
#ifdef DEBUG_MENU1
        case BUTT_OK:{
            add_queue_write(0,(unsigned int)&current_type_eeprom);
            add_queue_write(0,(unsigned int)&current_type_eeprom+1);
            add_queue_write(0,(unsigned int)&current_type_eeprom+2);
            add_queue_write(0,(unsigned int)&current_type_eeprom+3);                                    
            DEBUGER("RESIAVER=COMPLEATED",0,0,MESSENGER,TYPE_ADC);
            break;        
        }   
        
        case BUTT_UP:{ 
                   //adc_main=adc_main+1;
            break;
        }
        case BUTT_DW:{ 
                  /// adc_main=adc_main-1;
            break;
        }  
#endif 

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 29, 2014 04:11:09
pokk
Подскажите как правильнее оптимизировать деление на 256 (отбрасыванием байта ).
Сделал сдвиг на 8 codevision это выполнят в 100 тактов. А при самом делении так в вообще за 600 тактов.
В итоге сделал так вот,но этот вариант не сильно нравится боюсь наложение какие-нибудь произойдут.

Код: Выделить всё

unsigned long int design_value @0x0100;
unsigned long int design_result @0x0101;

design_value=345;
design_value=(unsigned long int)design_value*10;
//design_value=(design_value>>8); // design_value=U_power/K; K=256
design_result=design_result;

Re: Вопросы по С/С++ (СИ)

Добавлено: Пн дек 29, 2014 06:41:47
Kavka
Деление на 256 хорошо делается сдвигом вправо на 8. Тут всё правильно.
Дальше должен работать компилятор.
В случае с
design_value=(design_value>>8)
По хорошему, думаю, что это должно свестись к операции сдвига с помощью цикла или barrel shifter (устройство быстрого сдвига), или пересылкой 3-х байт и занулением четвёртого. Это зависит от архитектуры ядра микроконтроллера и возможностей оптимизации компилятора. К стати, а оптимизация в компиляторе включена? 100 машинных циклов - это похоже на простой цикл сдвига без оптимизации.

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 30, 2014 03:57:39
pokk
Процессор ATmega128. Компилятор codevisionavr 2.05 в настройках проекта стоит оптимизация по скорости и уровень максимальный.(только компилятор всё равно любитель в подпрограмму всё заворачивать )
Вот такой ассемблерный код он выдаёт
Спойлер

Код: Выделить всё

         // design_value1=(design_value1>>9);
LDS  R26,_design_value1
LDS  R27,_design_value1+1
LDS  R24,_design_value1+2
LDS  R25,_design_value1+3
LDI  R30,LOW(9)
CALL __LSRD12
STS  _design_value1,R30
STS  _design_value1+1,R31
STS  _design_value1+2,R22
STS  _design_value1+3,R23

__LSRD12:
	TST  R30
	MOV  R0,R30
	MOVW R30,R26
	MOVW R22,R24
	BREQ __LSRD12R
__LSRD12L:
	LSR  R23
	ROR  R22
	ROR  R31
	ROR  R30
	DEC  R0
	BRNE __LSRD12L
__LSRD12R:
	RET
Я уже думаю сделать ассемблерную вставку типа функции которая принимает два параметра 1-делимое 2-результат
а в теле функции происходит просто копирование 3х байт из адреса первого параметра во второй.

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 30, 2014 07:44:29
uk8amk

Код: Выделить всё

static union{ 
	char 	   bytes[4];
	unsigned long int word32;
} data;
И копируйте байты как вам удобно.
Можно ещё через указатель попробовать:

Код: Выделить всё

char data8[5]={0,0,0,0,0}; // 1 байт лишний, он будет занулять старший байт
unsigned long *ptr1;
unsigned long *ptr2;

ptr1=(unsigned long*) &data8[0];
ptr2=(unsigned long*) &data8[1];

*ptr1 = my_data32;
new_data = *ptr2; 
ЗЫ
// design_value1=(design_value1>>9);
При сдвиге на 9 там совсем другая математика выходит.

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 30, 2014 08:50:37
ARV
если компилятор поддерживает безымянные структуры, то можно так

Код: Выделить всё

static union{
   long normal;
   struct{
      uint8_t dummy; // никогда не используется
      long div256;
   }
} my_var;
   
   my_var.normal = 0xFF000000;
   // деленное на 256 получится так
   long x = my_var.div256; // x == 0x00FF0000;
если не поддерживает, тодобавится имя поля структуры в юнионе...

Re: Вопросы по С/С++ (СИ)

Добавлено: Вт дек 30, 2014 10:01:26
HHIMERA
#define LONG_VALUE_DIV256(var) ((*(volatile uint32_t *)((uint16_t)&(var) + 1)) & 0x00FFFFFF)

hh = 0x12345678;
gg = LONG_VALUE_DIV256(hh);

Получаем...

Код: Выделить всё

29:       gg = LONG_VALUE_DIV256(hh);
+00000033:   91800061    LDS       R24,0x0061     Load direct from data space
+00000035:   91900062    LDS       R25,0x0062     Load direct from data space
+00000037:   91A00063    LDS       R26,0x0063     Load direct from data space
+00000039:   91B00064    LDS       R27,0x0064     Load direct from data space
+0000003B:   70B0        ANDI      R27,0x00       Logical AND with immediate
+0000003C:   93800068    STS       0x0068,R24     Store direct to data space
+0000003E:   93900069    STS       0x0069,R25     Store direct to data space
+00000040:   93A0006A    STS       0x006A,R26     Store direct to data space
+00000042:   93B0006B    STS       0x006B,R27     Store direct to data space
Правда это в Студии... как в КодэНедоВижене не знаю...

Re: Вопросы по С/С++ (СИ)

Добавлено: Сб янв 10, 2015 13:55:51
Электpониk
Переделал програмку для термометра DS18x20 на AT89C2051 под свою схему. В Си пока новичек. Нашел программу под этот контроллер с похожей схемой на 4-сегментном индикаторе. Мне нужно только два сегмента и третий для отображения + и -. Переделал програмку под свои нужды. Все получилось. Только вот есть небольшая проблема. Для подключения датчика DS18S20 или DS18B20 нужно в коде поменять лишь одну циферку. Но заново шить контроллер ради замены датчика не очень хорошо. Поэтому пытаюсь дописать код так чтобы семейство датчиков определялось автоматически. Программа написана в mikroC PRO for 8051.
1. Подскажите как считать в программе код семейства датчиков (64-BIT LASERED ROM CODE). В мануале сказано что нужно считать первую цифру серийного номера датчика. В этой цифре и закодирован код семейства датчика (0x10 для DS18S20 и 0x28 для DS18B20).
2. Почему температура округляется не по правилам математики. Она округляется в большую сторону только если десятые перевалят за 0,7 градуса. А должно быть за 0,5. Т.к. пол градуса это еще не 1, но 0,6 уже 1.
3. Как убрать вывод +85 при инициализации датчика.

Листинг программы
Спойлер

Код: Выделить всё

/* DS18x20 Термометр на 2x7-сегментном индикаторе с индикацией полярности на 1х16-сегментном индикаторе

   Дата : Январь 2015

   МК : AT89C2051, XL : 12МГц */


// Конфигурируем микроконтроллер

 sbit OW_Bit at P3_7_bit;     // задаем пин для подключения датчика температуры

 sbit dgt_3 at P3.B1;     // контролирующие пины семисегментного индикатора

 sbit dgt_2 at P3.B2;

 sbit dgt_1 at P3.B3;


 unsigned char SG=0;

 int Digit1,Digit2,Digit3;


 // Соответствующие цифры для вывода на семисегментный индикатор
 //                                                               минус  плюс  пусто
 //              0     1    2    3    4   5     6   7     8    9   10   11   12 
 char number[]={0x03,0x9F,0x25,0x0D,0x99,0x49,0x41,0x1F,0x01,0x09,0xFD,0xFC,0xFF};



void MUX() org IVT_ADDR_ET0 // используем прерывание переполнения Timer0

{

    TL0=0x36; // загружаем LSB & MSB значения

    TH0=0xf6;

    P1=0xFF;

    dgt_1 = dgt_2 = dgt_3 = 0;

    SG++;

    SG=SG%3;

    switch(SG){

        case 0: P1=number[Digit1];

                dgt_1 = 1;

                break;

        case 1: P1=number[Digit2];

                dgt_2 = 1;

                break;

        case 2: P1=number[Digit3];

                dgt_3 = 1;

                break;

    }

}


// Выбор датчика DS18B20 или DS18S20
// DS18B20 отличается от DS18S20 смещением значения температуры на 3 разряда

const unsigned short TEMP_RESOLUTION = 9; //Поставьте ’12’ для DS18B20 или ‘9’ для DS18S20




unsigned temp;

void Display_Temperature(unsigned int temp2write) {

  const unsigned short RES_SHIFT = TEMP_RESOLUTION - 8;

  char temp_whole;




  // проверка отрицательной температуры

  if (temp2write & 0x8000) {

    Digit3 = 10;   //если да показать минус

    temp2write = ~temp2write + 1;  // и инвертировать температуру

     }
   else

    Digit3 = 11;  //иначе показать плюс




  // задаем смещение разрядов температуры в зависимости от семейства датчиков

  temp_whole = temp2write >> RES_SHIFT ;




  // разделяем температуру на разряды

  if (temp_whole/100)

     Digit3 = temp_whole/100;              // извлечь сотни градуса

     Digit2 = (temp_whole/10)%10;          // извлечь десятки градуса

     Digit1 =  temp_whole%10;              // извлечь единицы градуса

  if ((Digit1 == 0) & (Digit2 == 0) & (Digit3 != 1))  Digit3 = 12;  //при нуле градусов плюс отключить
  
  if ((Digit2 == 0) & (Digit3 != 1))  { Digit2 = Digit1; Digit1 = 12; } //если температура меньше 10 смещаем разряд влево
  
  if (Ow_Reset())  Digit1=Digit2=Digit3=10; //если датчик не подключен показать все минусы
}




void main() {

  TMOD=0x01;        // Инициализация Timer 0

  TL0=0x36;         // Задаем задержку 2.5мс для Timer 0

  TH0=0xF6;

  IE=0x82;          // Здесь EA=1 & ET0=1

  TR0_bit=1;        // Старт timer0

  //--- Основной цикл программы

  do {

    //--- Извлечение показаний температуры из датчика

    Ow_Reset();                                  // 1wire сигнал сброса

    Ow_Write(0xCC);                              // отправляем команду SKIP_ROM

    Ow_Write(0x44);                              // отправляем команду CONVERT_T

    Delay_us(120);                               // задержка 120мкс

    Ow_Reset();                                  // 1wire сигнал сброса

    Ow_Write(0xCC);                              // отправляем команду SKIP_ROM

    Ow_Write(0xBE);                              // отправляем команду READING_SCRATCHPAD

    temp =  Ow_Read();                           // считываем температуру

    temp = (Ow_Read() << 8) + temp;

    Display_Temperature(temp);                   // отобразить температуру

    Delay_ms(500);                               // задержка 500мс

  } while (1);

}      //конец
Прикрепляю схему в Proteus для моделирования и hex для МК на всякий случай.