Вопросы по С/С++ (СИ)
- Сообщения: 6
- Зарегистрирован: Вс ноя 23, 2014 11:23:03
Друзья, я столкнулся с таким вопросом. Написал програму на с++ для атмеги88, после запуска как и положено попадаю в 0x0000, но вот вся трудность заключается в том, что там находится далеко не функция main(), как я понимаю нужно всего лишь определить прерывание ресет, но вот найти как на с++ определить вектор этого прерывания мне найти не удалось. :\
- Реклама
Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали.
Если, конечно, вы сами ничего не навыкрутасничали.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Эта "кухня" происходит в стартап коде, который пишется на асме. Из него и происходит вызов main().Ехан писал(а):как на с++ определить вектор этого прерывания мне найти не удалось. :\
Обычно нужный стартап подключается компилятором автоматически.
Кстати, если программа весьма примитивна(вроде помигать светодиодом), не использует стек и прерываний, то вполне возможно для AVR расположить main() по адресу 0x0000.
- Сообщения: 6
- Зарегистрирован: Вс ноя 23, 2014 11:23:03
Не навыкрутасничил, не знаю как. А стек боюсь использовать, как бы не послал куда не надоKavka писал(а):Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали.
А есть чем дизассемблировать и прогнать на эмуляторе? Интересно посмотреть процедуры инициализации.
- Сообщения: 574
- Зарегистрирован: Вт ноя 02, 2010 17:46:37
Ехан, AVR Studio
Подскажите, почему дефайн не вставляется ? У меня есть некий кусок кода для отладки и всё работало который я выключаю дефайном __DEBUG__ соответственен непременные который он используют тоже выключаются.
А вот в данном месте начинается на то что нету переменной current_type_eeprom оно и правильно я её раньше выключил. Но почему он вообще компилируется ? если заменить #ifdef DEBUG_MENU1 на #ifdef 0 то ошибок большее не появляется.
Вынос DEBUG_MENU1 из файла тоже не помогает.
Подскажите, почему дефайн не вставляется ? У меня есть некий кусок кода для отладки и всё работало который я выключаю дефайном __DEBUG__ соответственен непременные который он используют тоже выключаются.
А вот в данном месте начинается на то что нету переменной current_type_eeprom оно и правильно я её раньше выключил. Но почему он вообще компилируется ? если заменить #ifdef DEBUG_MENU1 на #ifdef 0 то ошибок большее не появляется.
Вынос DEBUG_MENU1 из файла тоже не помогает.
Код: Выделить всё
//--------файл 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)¤t_type_eeprom);
add_queue_write(0,(unsigned int)¤t_type_eeprom+1);
add_queue_write(0,(unsigned int)¤t_type_eeprom+2);
add_queue_write(0,(unsigned int)¤t_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
Подскажите как правильнее оптимизировать деление на 256 (отбрасыванием байта ).
Сделал сдвиг на 8 codevision это выполнят в 100 тактов. А при самом делении так в вообще за 600 тактов.
В итоге сделал так вот,но этот вариант не сильно нравится боюсь наложение какие-нибудь произойдут.
Сделал сдвиг на 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;Деление на 256 хорошо делается сдвигом вправо на 8. Тут всё правильно.
Дальше должен работать компилятор.
В случае с
design_value=(design_value>>8)
По хорошему, думаю, что это должно свестись к операции сдвига с помощью цикла или barrel shifter (устройство быстрого сдвига), или пересылкой 3-х байт и занулением четвёртого. Это зависит от архитектуры ядра микроконтроллера и возможностей оптимизации компилятора. К стати, а оптимизация в компиляторе включена? 100 машинных циклов - это похоже на простой цикл сдвига без оптимизации.
Дальше должен работать компилятор.
В случае с
design_value=(design_value>>8)
По хорошему, думаю, что это должно свестись к операции сдвига с помощью цикла или barrel shifter (устройство быстрого сдвига), или пересылкой 3-х байт и занулением четвёртого. Это зависит от архитектуры ядра микроконтроллера и возможностей оптимизации компилятора. К стати, а оптимизация в компиляторе включена? 100 машинных циклов - это похоже на простой цикл сдвига без оптимизации.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
- Сообщения: 574
- Зарегистрирован: Вт ноя 02, 2010 17:46:37
Процессор ATmega128. Компилятор codevisionavr 2.05 в настройках проекта стоит оптимизация по скорости и уровень максимальный.(только компилятор всё равно любитель в подпрограмму всё заворачивать )
Вот такой ассемблерный код он выдаёт
Я уже думаю сделать ассемблерную вставку типа функции которая принимает два параметра 1-делимое 2-результат
а в теле функции происходит просто копирование 3х байт из адреса первого параметра во второй.
Вот такой ассемблерный код он выдаёт
Спойлер
Код: Выделить всё
// 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а в теле функции происходит просто копирование 3х байт из адреса первого параметра во второй.
Код: Выделить всё
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 там совсем другая математика выходит.
если компилятор поддерживает безымянные структуры, то можно так
если не поддерживает, тодобавится имя поля структуры в юнионе...
Код: Выделить всё
static union{
long normal;
struct{
uint8_t dummy; // никогда не используется
long div256;
}
} my_var;
my_var.normal = 0xFF000000;
// деленное на 256 получится так
long x = my_var.div256; // x == 0x00FF0000;
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
#define LONG_VALUE_DIV256(var) ((*(volatile uint32_t *)((uint16_t)&(var) + 1)) & 0x00FFFFFF)
hh = 0x12345678;
gg = LONG_VALUE_DIV256(hh);
Получаем...
Правда это в Студии... как в КодэНедоВижене не знаю...
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
Переделал програмку для термометра 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 при инициализации датчика.
Листинг программы
Прикрепляю схему в Proteus для моделирования и hex для МК на всякий случай.
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);
} //конец- Вложения
-
- Termometer_2x7.zip
- (19.28 КБ) 138 скачиваний
1. при чтении температуры из датчика вы обязаны считывать 8 байт + CRC, среди которых только первые 2 будут значением температуры, а остальные - всякие внутренние регистры. так вот, регистры датчиков разные для разных семейств, в частности, есть биты, которые всегда установлены в 1 и по ним можно отличить семейства - читайте даташиты. то есть переделки вашей программы должны быть минимальными.
2. листинг не смотрел, ответить не могу - подождите кого-либо, кто на это решится.
3. запустите первое преобразование до входа в главный цикл и дождитесь, пока преобразование кончится. в этом случае ваш главный цикл отработает уже с корректными показаниями температуры.
2. листинг не смотрел, ответить не могу - подождите кого-либо, кто на это решится.
3. запустите первое преобразование до входа в главный цикл и дождитесь, пока преобразование кончится. в этом случае ваш главный цикл отработает уже с корректными показаниями температуры.
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Есть же специальная тема по этому датчику.
1. Чтобы считать ROM CODE, нужно отправить соотвествующую команду
3. Для этого после пуска преобразования надо ждать 750мс вместо 120 мкс.
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;- Сообщения: 882
- Зарегистрирован: Ср фев 22, 2012 01:25:21
Заблудился в трех соснах... что не так?????
В и тоге в Data должно получится 0xFF11... а у меня получается 0x0011...
Толи прот моросит... толи на сам деле такой результат будет (значит AVRST моросит)... ну или как обычно я мороСЮ...
Проект для AVRST4.19 и ПРОТЕУСА - внизу...

Код: Выделить всё
//гланый цикл
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);
}
}Толи прот моросит... толи на сам деле такой результат будет (значит AVRST моросит)... ну или как обычно я мороСЮ...
Проект для AVRST4.19 и ПРОТЕУСА - внизу...
- Сообщения: 353
- Зарегистрирован: Вс янв 19, 2014 22:41:55
Всё правильно, всё справедливо. © Разыменование указателя на байт даёт нам байт, задвигаем его на восемь бит влево и остаёмся при 8-ми новеньких свежеобразовавшихся нулевых битах. Приведите результат разыменования к слову (до сдвига!) и всё получится. Либо сдвиньте Data перед OR-еньем его со вторым байтом (условия задачи чисто умозрительны - так что сменой последовательности байтов в результате, полагаю, можно пренебречьshads писал(а):Код: Выделить всё
//гланый цикл [...] uint8_t *pointer = (uint8_t*) 0x70; [...] Data |= (*(pointer+1) << 8); [...] }
Одновременным нажатием LIGHT и POWER, РП Sangean ATS-909X (ver 1.29) превращается в ATS-909XR! 
- Сообщения: 882
- Зарегистрирован: Ср фев 22, 2012 01:25:21
Делаю так, результат тот же...
Хе... если выключаю оптимизацию, то все ОК... но размер становиться в 10 раз больше!!!
Кста... при выключенной оптимизации и без приведения к 16-ти разрядам - дает нормальный результат...
Сделал так:
Спойлер
Код: Выделить всё
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);
}
}
Кста... при выключенной оптимизации и без приведения к 16-ти разрядам - дает нормальный результат...
Спасибо... помогло...Siarzhuk писал(а):Либо сдвиньте Data перед OR-еньем его со вторым байтом (условия задачи чисто умозрительны - так что сменой последовательности байтов в результате, полагаю, можно пренебречь
Сделал так:
Код: Выделить всё
Data = *(pointer+1);
Data <<= 8;
Data |= *pointer;
- Сообщения: 3832
- Зарегистрирован: Сб сен 10, 2011 17:46:25
- Сообщения: 882
- Зарегистрирован: Ср фев 22, 2012 01:25:21
Странно... у меня AVRST4.19 и avr-toolchain3.3.0.710 и ведет себя так как я описал...oleg110592 писал(а):WinAVR 2010 с оптимизацией Os в протеусе все нормально 0xFF11
Всё верно.
А во второй строчке *(pointer+1) - восьмибитное число, сдвинув которое 8 раз влево, Вы получаете 0. Вот и итоговое число не меняется. Результат и должен быть 0x0011.
Вот если эта строчка записывалась как-то так:, было бы другое дело.
Первая строчка - без вопросов, Data присваивается 0x11.shads писал(а):Код: Выделить всё
Data = *pointer; Data |= (*(pointer+1) << 8);
А во второй строчке *(pointer+1) - восьмибитное число, сдвинув которое 8 раз влево, Вы получаете 0. Вот и итоговое число не меняется. Результат и должен быть 0x0011.
Вот если эта строчка записывалась как-то так:
Код: Выделить всё
Data |= ((uint16_t)(*(pointer+1)) << 8);


