Вопросы по С/С++ (СИ)
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Вопросы по С/С++ (СИ)
Можно использовать указатель.
- Реклама
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18647
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
для MCS51 характерно "сопоставлять" переменные с определенными адресами в ОЗУ. по-моему, в кейле для этого есть расширение в виде "оператора" at или @ - точно не знаю, но вы можете посмотреть в любом хидере на периферию конкретного МК как там определены SFR-регистры, они точно привязаны к адресам...greenled писал(а):Доброго всем дня! Пишу тут прогу для МК с архитектурой 8051 на Си в Keil, увы, уровень владения языком невысок, но интересует такой вопрос: как ассоциировать с переменной какую-либо ячейку памяти данных? Делать ассемблерную вставку или можно как-то стандартными средствами кейловского си обойтись?
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
Gudd-Head, нужно чтобы МК изредка принимал коэффициенты для ацп и хранил у себя во флеше
ARV, адреса SFR регистров есть, но как организовать к ним обращение? постоянно ссылаться на адрес или можно как-то организовать указатель на него?
ARV, адреса SFR регистров есть, но как организовать к ним обращение? постоянно ссылаться на адрес или можно как-то организовать указатель на него?
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18647
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
вы не поняли: вам надо посмотреть в хидере, как определены переменные-SFR, и аналогично определить свои переменные. тогда никаких указателей не потребуется, и кейл сумеет использовать архитектурные особенности ассемблера для работы с вашими переменными, если таковые вдруг будут.
в хидере будет что-то типа такого:
unsigned char PCON at 0xF0;
вот и вам вашу переменную надо будет определить аналогично, например, если ее адрес 0x1A:
unsigned char my_var at 0x1A;
только имейте ввиду, что адрес PCON я просто от фонаря написал - не помню я настоящий.
в конце-концов хелп у вас в кейле есть или нет?! прочтите его...
в хидере будет что-то типа такого:
unsigned char PCON at 0xF0;
вот и вам вашу переменную надо будет определить аналогично, например, если ее адрес 0x1A:
unsigned char my_var at 0x1A;
только имейте ввиду, что адрес PCON я просто от фонаря написал - не помню я настоящий.
в конце-концов хелп у вас в кейле есть или нет?! прочтите его...
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Gudd-Head
- Друг Кота
- Сообщения: 20092
- Зарегистрирован: Чт сен 18, 2008 12:27:21
- Откуда: Столица Мира Санкт-Петербург
Re: Вопросы по С/С++ (СИ)
О как. Была память данных, стала память программ.greenled писал(а):как ассоциировать с переменной какую-либо ячейку памяти данных?
...
МК изредка принимал коэффициенты для ацп и хранил у себя во флеше
[ Всё дело не столько в вашей глупости, сколько в моей гениальности ] [ Правильно заданный вопрос содержит в себе половину ответа ]
- Реклама
Re: Вопросы по С/С++ (СИ)
ARV, ок, большущее Спасибо)
Gudd-Head, нет, речь все еще о памяти данных) В даташите она фигурирует как Flash/EE, просто примелькалось
Gudd-Head, нет, речь все еще о памяти данных) В даташите она фигурирует как Flash/EE, просто примелькалось
- COKPOWEHEU
- Говорящий с текстолитом
- Сообщения: 1525
- Зарегистрирован: Чт июн 10, 2010 20:11:19
Re: Вопросы по С/С++ (СИ)
На уровне языка Си можно так
В С++ вроде есть штатный способ расположения переменной по определенному адресу
Код: Выделить всё
TYPE *b=0x????; // TYPE заменить на желаемый тип данных
#define A (*b) // обращение будет именно через А
#define B (*(TYPE*)0x????) // или так, если нет желания отъедать память лишней переменнойRe: Вопросы по С/С++ (СИ)
COKPOWEHEU, премного благодарен) заработало)
Re: Вопросы по С/С++ (СИ)
Друзья, я столкнулся с таким вопросом. Написал програму на с++ для атмеги88, после запуска как и положено попадаю в 0x0000, но вот вся трудность заключается в том, что там находится далеко не функция main(), как я понимаю нужно всего лишь определить прерывание ресет, но вот найти как на с++ определить вектор этого прерывания мне найти не удалось. :\
Re: Вопросы по С/С++ (СИ)
Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали.
Если, конечно, вы сами ничего не навыкрутасничали.
Когда уже ничего не помогает - прочтите, наконец, инструкцию.
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
Лучший оптимизатор находится у вас между ушей. (Майкл Абраш, программист Quake и QuakeII)
Избыток информации ведёт к оскудению души - Леонтьев А. (сказано в 1965 г.)
-
uk8amk
- Поставщик валерьянки для Кота
- Сообщения: 2222
- Зарегистрирован: Вт ноя 27, 2007 11:32:06
- Откуда: Tashkent
Re: Вопросы по С/С++ (СИ)
Эта "кухня" происходит в стартап коде, который пишется на асме. Из него и происходит вызов main().Ехан писал(а):как на с++ определить вектор этого прерывания мне найти не удалось. :\
Обычно нужный стартап подключается компилятором автоматически.
Кстати, если программа весьма примитивна(вроде помигать светодиодом), не использует стек и прерываний, то вполне возможно для AVR расположить main() по адресу 0x0000.
Re: Вопросы по С/С++ (СИ)
Не навыкрутасничил, не знаю как. А стек боюсь использовать, как бы не послал куда не надоKavka писал(а):Да, там находиться не main. Там стоит rjmp на процедуру инициализации стека и RAM, а потом управление передаётся на main.
Если, конечно, вы сами ничего не навыкрутасничали.
А есть чем дизассемблировать и прогнать на эмуляторе? Интересно посмотреть процедуры инициализации.
Re: Вопросы по С/С++ (СИ)
Ехан, 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
Re: Вопросы по С/С++ (СИ)
Подскажите как правильнее оптимизировать деление на 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;Re: Вопросы по С/С++ (СИ)
Деление на 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 г.)
Re: Вопросы по С/С++ (СИ)
Процессор 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х байт из адреса первого параметра во второй.
-
uk8amk
- Поставщик валерьянки для Кота
- Сообщения: 2222
- Зарегистрирован: Вт ноя 27, 2007 11:32:06
- Откуда: Tashkent
Re: Вопросы по С/С++ (СИ)
Код: Выделить всё
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
- Ум, честь и совесть. И скромность.
- Сообщения: 18647
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
если компилятор поддерживает безымянные структуры, то можно так
если не поддерживает, тодобавится имя поля структуры в юнионе...
Код: Выделить всё
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: Вопросы по С/С++ (СИ)
#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
"Я не даю готовых решений, я заставляю думать!"(С)
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Переделал програмку для термометра 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 КБ) 130 скачиваний


