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

Если ваш вопрос не влез ни в одну из вышеперечисленных тем, вам сюда.
Ответить
Родился
Сообщения: 6
Зарегистрирован: Вс ноя 23, 2014 11:23:03

Сообщение Ехан »

Друзья, я столкнулся с таким вопросом. Написал програму на с++ для атмеги88, после запуска как и положено попадаю в 0x0000, но вот вся трудность заключается в том, что там находится далеко не функция main(), как я понимаю нужно всего лишь определить прерывание ресет, но вот найти как на с++ определить вектор этого прерывания мне найти не удалось. :\
Реклама
Мудрый кот
Аватара пользователя
Сообщения: 1812
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали. :)
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Реклама
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

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

Кстати, если программа весьма примитивна(вроде помигать светодиодом), не использует стек и прерываний, то вполне возможно для AVR расположить main() по адресу 0x0000.
Родился
Сообщения: 6
Зарегистрирован: Вс ноя 23, 2014 11:23:03

Сообщение Ехан »

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

А есть чем дизассемблировать и прогнать на эмуляторе? Интересно посмотреть процедуры инициализации.
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение 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 
Реклама
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение 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;
Реклама
Мудрый кот
Аватара пользователя
Сообщения: 1812
Зарегистрирован: Чт июн 10, 2010 08:55:35
Откуда: Сибирские Афины

Сообщение Kavka »

Деление на 256 хорошо делается сдвигом вправо на 8. Тут всё правильно.
Дальше должен работать компилятор.
В случае с
design_value=(design_value>>8)
По хорошему, думаю, что это должно свестись к операции сдвига с помощью цикла или barrel shifter (устройство быстрого сдвига), или пересылкой 3-х байт и занулением четвёртого. Это зависит от архитектуры ядра микроконтроллера и возможностей оптимизации компилятора. К стати, а оптимизация в компиляторе включена? 100 машинных циклов - это похоже на простой цикл сдвига без оптимизации.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Вымогатель припоя
Сообщения: 574
Зарегистрирован: Вт ноя 02, 2010 17:46:37

Сообщение 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х байт из адреса первого параметра во второй.
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение 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 там совсем другая математика выходит.
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение 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;
если не поддерживает, тодобавится имя поля структуры в юнионе...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...

Мой уютный бложик... заходите!
Контактная информация:
Друг Кота
Сообщения: 4583
Зарегистрирован: Вс дек 05, 2010 06:10:34
Откуда: ЮВ

Сообщение 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
Правда это в Студии... как в КодэНедоВижене не знаю...
"Я не даю готовых решений, я заставляю думать!"(С)
Прорезались зубы
Аватара пользователя
Сообщения: 247
Зарегистрирован: Чт янв 08, 2015 22:31:15

Сообщение Элект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 для МК на всякий случай.
Вложения
Termometer_2x7.zip
(19.28 КБ) 138 скачиваний
ARV
Ум, честь и совесть. И скромность.
Аватара пользователя
Сообщения: 18788
Зарегистрирован: Чт дек 28, 2006 08:19:56
Откуда: Новочеркасск

Сообщение ARV »

1. при чтении температуры из датчика вы обязаны считывать 8 байт + CRC, среди которых только первые 2 будут значением температуры, а остальные - всякие внутренние регистры. так вот, регистры датчиков разные для разных семейств, в частности, есть биты, которые всегда установлены в 1 и по ним можно отличить семейства - читайте даташиты. то есть переделки вашей программы должны быть минимальными.

2. листинг не смотрел, ответить не могу - подождите кого-либо, кто на это решится.

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

Мой уютный бложик... заходите!
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

Есть же специальная тема по этому датчику.
1. Чтобы считать ROM CODE, нужно отправить соотвествующую команду

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

            if( ow_reset() == OW_PRESENCE_FAILURE)
                    return;
            ow_write_byte( DS_READ_ROM );
            for( i=0; i<8; i++ )
                    ds_code[ i ] = ow_read_byte();

            if( ow_crc(ds_code, 8) != 0 )
                    return;
3. Для этого после пуска преобразования надо ждать 750мс вместо 120 мкс.
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Заблудился в трех соснах... что не так?????

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

//гланый цикл
volatile uint16_t Data;								

int main (void)
{
	UartInit ();

	while(1){ 

		_delay_ms (500);
		uint8_t *pointer = (uint8_t*) 0x70;


		*pointer = 0x11;
		*(pointer+1) = 0xff;


		Data = *pointer; 
		Data |= (*(pointer+1) << 8);	


		UartTransmitHexInt (Data);	
		UartTransmitSymb (0x0D);
	}
}
В и тоге в Data должно получится 0xFF11... а у меня получается 0x0011...
Толи прот моросит... толи на сам деле такой результат будет (значит AVRST моросит)... ну или как обычно я мороСЮ...

Проект для AVRST4.19 и ПРОТЕУСА - внизу...

Изображение
Вложения
new.7z
(19.15 КБ) 150 скачиваний
11.png
(36.29 КБ) 859 скачиваний
Потрогал лапой паяльник
Аватара пользователя
Сообщения: 353
Зарегистрирован: Вс янв 19, 2014 22:41:55

Сообщение Siarzhuk »

shads писал(а):

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

//гланый цикл
[...]
		uint8_t *pointer = (uint8_t*) 0x70;
[...]

		Data |= (*(pointer+1) << 8);	
[...]
}
Всё правильно, всё справедливо. © Разыменование указателя на байт даёт нам байт, задвигаем его на восемь бит влево и остаёмся при 8-ми новеньких свежеобразовавшихся нулевых битах. Приведите результат разыменования к слову (до сдвига!) и всё получится. Либо сдвиньте Data перед OR-еньем его со вторым байтом (условия задачи чисто умозрительны - так что сменой последовательности байтов в результате, полагаю, можно пренебречь ;-)
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! ;-)
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

Делаю так, результат тот же...
Спойлер

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

volatile uint16_t Data;                        

int main (void)
{
   UartInit ();

   while(1){ 

      _delay_ms (500);
      uint8_t *pointer = (uint8_t*) 0x70;

      *pointer = 0x11;
      *(pointer+1) = 0xff;

      Data = *pointer; 
      Data |= (((uint16_t)*(pointer+1)) << 8);   

      UartTransmitHexInt (Data);   
      UartTransmitSymb (0x0D);
   }
}
Хе... если выключаю оптимизацию, то все ОК... но размер становиться в 10 раз больше!!!


Кста... при выключенной оптимизации и без приведения к 16-ти разрядам - дает нормальный результат...

Siarzhuk писал(а):Либо сдвиньте Data перед OR-еньем его со вторым байтом (условия задачи чисто умозрительны - так что сменой последовательности байтов в результате, полагаю, можно пренебречь ;-)
Спасибо... помогло...
Сделал так:

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

      Data = *(pointer+1); 
	  Data <<= 8;
      Data |= *pointer;   
Друг Кота
Аватара пользователя
Сообщения: 3832
Зарегистрирован: Сб сен 10, 2011 17:46:25

Сообщение oleg110592 »

WinAVR 2010 с оптимизацией Os в протеусе все нормально 0xFF11
Опытный кот
Аватара пользователя
Сообщения: 882
Зарегистрирован: Ср фев 22, 2012 01:25:21

Сообщение shads »

oleg110592 писал(а):WinAVR 2010 с оптимизацией Os в протеусе все нормально 0xFF11
Странно... у меня AVRST4.19 и avr-toolchain3.3.0.710 и ведет себя так как я описал...
Друг Кота
Аватара пользователя
Сообщения: 4905
Зарегистрирован: Чт апр 11, 2013 11:19:59
Откуда: Минск

Сообщение WiseLord »

Всё верно.
shads писал(а):

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

Data = *pointer;
Data |= (*(pointer+1) << 8);  
Первая строчка - без вопросов, Data присваивается 0x11.
А во второй строчке *(pointer+1) - восьмибитное число, сдвинув которое 8 раз влево, Вы получаете 0. Вот и итоговое число не меняется. Результат и должен быть 0x0011.
Вот если эта строчка записывалась как-то так:

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

Data |= ((uint16_t)(*(pointer+1)) << 8);
, было бы другое дело.
Контактная информация:
Ответить

Вернуться в «Разные вопросы по МК»