Вопросы по С/С++ (СИ)
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Zhuk72, то есть получается так:
ISR (TIMER0_OVF_vect) заменяю на ISR (TIMER2_OVF_vect)
Обработчик прерывания по переполнению таймера вставляю перед главной программой int main (void)
ISR (TIMER2_OVF_vect)
{
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B); // Гасим все разряды
}
Настройки таймера такие
TCCR2 |= (1 << WGM21)|(1 << WGM20)|(1 << CS21); // Режим FASTPWM. Предделитель на 8
TIMSK |= (1 << TOIE2)|(1 << OCIE2); // Разрешение прерываний по таймеру 2
OCR2 = 50; // Начальное значение OCR2
ISR (TIMER0_OVF_vect) заменяю на ISR (TIMER2_OVF_vect)
Обработчик прерывания по переполнению таймера вставляю перед главной программой int main (void)
ISR (TIMER2_OVF_vect)
{
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B); // Гасим все разряды
}
Настройки таймера такие
TCCR2 |= (1 << WGM21)|(1 << WGM20)|(1 << CS21); // Режим FASTPWM. Предделитель на 8
TIMSK |= (1 << TOIE2)|(1 << OCIE2); // Разрешение прерываний по таймеру 2
OCR2 = 50; // Начальное значение OCR2
- Реклама
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Пробуйте.
Но для сохранении идеологии вашего исходника сделайте такую поправку:
И для стройности вставьте после основного прерывания от таймера.
По поводу настроек таймера ничего не скажу. Это вы сами сравните с ДШ на МК.
Но для сохранении идеологии вашего исходника сделайте такую поправку:
Код: Выделить всё
ISR (TIMER2_OVF_vect)
{
///////////////////////////////////
// Индикатор с общим анодом (ОА)
///////////////////////////////////
#ifndef LEDS_OK
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
///////////////////////////////////
// Индикатор с общим катодом (ОК)
///////////////////////////////////
#else
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
#endif
}
По поводу настроек таймера ничего не скажу. Это вы сами сравните с ДШ на МК.
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Zhuk72, компилятор сыпет ошибками что не знает такого таймера. Полез в даташит, оказывается действительно у ATTiny261A нет такого таймера. Это получается что яркость семисегментного индикатора уменьшить программно не получиться на этом микроконтроллере?
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Так с этого и надо было начинать, с чтения ДШ. Да и тип МК вы держали в секрете.
Если есть 2 таймера, то можно легко сделать. Да и с одним тоже с чуть большими движениями.
Если есть 2 таймера, то можно легко сделать. Да и с одним тоже с чуть большими движениями.
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Zhuk72, да я сам об этом как то сразу и не подумал. Оказалось зря.
А с теми таймерами которые есть у ATTiny261A не подскажите конструкцию?
А с теми таймерами которые есть у ATTiny261A не подскажите конструкцию?
- Реклама
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Я атмелами не занимаюсь, поэтому надо дш смотреть.
С двумя таймерами принцип такой: в конце прерывания первого таймера заряжаете и запускаете второй таймер, а уже в прерывании второго отключаете индикатор и останавливаете таймер. Период второго таймера должен быть меньше, чем у первого. Чем он будет меньше, тем ниже яркость свечения индикатора.
С двумя таймерами принцип такой: в конце прерывания первого таймера заряжаете и запускаете второй таймер, а уже в прерывании второго отключаете индикатор и останавливаете таймер. Период второго таймера должен быть меньше, чем у первого. Чем он будет меньше, тем ниже яркость свечения индикатора.
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
вы не учитываете, что у этой тиньки развитая система цифровых компараторов для таймеров. чтобы регулировать яркость при динамической индикации достаточно одного таймера, общий принцип я описывал здесь: http://arv.radioliga.com/content/view/101/49/
Добавлено after 2 minutes 58 seconds:
Добавлено after 2 minutes 58 seconds:
блин, такое ощущение, что статья была написана после прочтения моейЭлектpониk писал(а):Реализация изменения скважности импульсов показана тут http://radioparty.ru/prog-avr/program-c ... egment-avr
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Потому и сказал, что не занимаюсь АтмеламиARV писал(а):вы не учитываете, что у этой тиньки развитая система цифровых компараторов для таймеров.
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Похоже что нужно юзать Timer1 у него есть Fast PWM Mode.
The fast Pulse Width Modulation or fast PWM mode (PWM1A/PWM1B = 1 and WGM1[1:0] = 00)
provides a high frequency PWM waveform generation option. The fast PWM differs from the
other PWM option by its single-slope operation. The counter counts from BOTTOM to TOP
(defined as OCR1C) then restarts from BOTTOM. In non-inverting Compare Output mode the
Waveform Output (OCW1x) is cleared on the Compare Match between TCNT1 and OCR1x and
set at BOTTOM. In inverting Compare Output mode, the Waveform Output is set on Compare
Match and cleared at BOTTOM. In complementary Compare Output mode the Waveform Output
is cleared on the Compare Match and set at BOTTOM.
Re: Вопросы по С/С++ (СИ)
Электpониk, принцип прост как бублик и состоит в следующем
берете 8 разрядный таймер и настраиваете его на режим Fast PWM Mode
в прерывании по переполнению зажигаете нужный анод, нужного разряда и выводите цифру, а в сравнении весь этот зоопарк тушим
изменяя значение для OCR2 мы тем самым изменяем яркость определенного разряда
код для ATmega8
берете 8 разрядный таймер и настраиваете его на режим Fast PWM Mode
в прерывании по переполнению зажигаете нужный анод, нужного разряда и выводите цифру, а в сравнении весь этот зоопарк тушим
Код: Выделить всё
//-----------------------------------------------
// Timer/Counter 2 initialization
// Clock source: System Clock
TCCR2 = 1 << WGM21 | 1 << WGM20 | // FastPWM
1 << CS22; // предделитель на 64 (16MHz/64/256/6 = 163Hz)
// 163 -частота мигания одной лампы
// 6 -количество ламп
// 256 - 8-ми разрядний таймер 2^8=256
// 64 - предделитель таймера
// 16 - частота МК
OCR2=250;
//--------------------------------------------------
TIMSK = 1 << OCIE2 | // Timer/Counter2 Output Compare Match Interrupt Enable
1 << TOIE2; // Timer/Counter2 Overflow Interrupt Enable
//-------------------------------------------------
ISR (TIMER2_OVF_vect) {
PORTB = Screen[var]; // выодим нужную цифру
switch (var) {
case 0: ANOD_RAZRYDA_0(); break; // анод един. секунд
case 1: ANOD_RAZRYDA_1(); break; // анод дес. секунд
case 2: ANOD_RAZRYDA_2(); break; // анод един. минут
case 3: ANOD_RAZRYDA_3(); break; // анод дес. минут
case 4: ANOD_RAZRYDA_4(); break; // анод един. часов
case 5: ANOD_RAZRYDA_5(); break; // анод дес. часов
default: break;
}
}
if (++var >= 5) var = 0;
OCR2=br_razryda[var];
}
ISR (TIMER2_COMP_vect) {
TURN_OFF_INDICATORS_AND_DOT(); // выключаем анодные драйвера (гасим индикаторы )
}
код для ATmega8
Tell Me The Truth
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Принцип я понимаю. Вот только проблема в том, что у ATTINY261A нет Timer2. Но есть Timer1 с режимом FastPWM. Можно его задействовать. Правда, сложность в том, что у него несколько компараторов и куча разнообразных режимов и регистров. Ну не беда, после изучения даташита, стали понятны назначения регистров Timer1, и как их настраивать.
Переделал программу на Timer1, но проблема в том, что не срабатывает прерывание по сравнению вообще. Подскажите в чём моя ошибка. Может что-то упустил.
ISR (TIMER1_OVF_vect) // Прерывание по переполнению таймера 1
{
Отображение цифр на сегментах
}
ISR (TIMER1_COMPA_vect) //Прерывание по сравнению таймера 1
{
Гасим все разряды
}
// Главная программа
int main (void)
{
// Настраиваю таймер 1 для ШИМ
TCCR1A |= (0 << COM1A0)|(0 << COM1A1)|(1 << PWM1A); // Ножки микроконтроллера отключены от компаратора. Режим FASTPWM.
TCCR1B |= (1 << CS13)|(0 << CS12)|(1 << CS11)|(1 << CS10); //Предделитель на 1024, частота индикатора 2,6 кГц.
TCCR1D |= (0 << WGM10)|(0 << WGM11); //Режим FASTPWM
TIMSK |= (1 << TOIE1)|(1 << OCIE1A); // Разрешение прерываний таймера 1 по переполнению и сравнению
OCR1A = 50; // Начальное значение OCR1A. Яркость индикатора.
asm volatile ("sei"); // Глобально разрешаю прерывания
...остальная часть программы. Считывание температуры и вывод на индикатор.
}
Полный код программы под спойлером.
#define LEDS_OK // Раскомментировать, если используется индикатор с общим катодом
// Подключаю стандартные библиотеки
#include <avr/io.h> // Ножки ввода-вывода
#include <util/delay.h> // Задержки
#include <avr/interrupt.h> // Прерывания
// Сегменты, должны быть в пределах одного порта МК
#define LED_SEG_A 2
#define LED_SEG_B 0
#define LED_SEG_C 4
#define LED_SEG_D 6
#define LED_SEG_E 5
#define LED_SEG_F 1
#define LED_SEG_G 3
#define LED_SEG_DP 7
#define LED_SEG_PORT PORTB
#define LED_SEG_DDR DDRB
// Знакоместа, должны быть в пределах одного порта МК
#define LED_DIG_1A 2
#define LED_DIG_1B 3
#define LED_DIG_2A 1
#define LED_DIG_2B 4
#define LED_DIG_3A 0
#define LED_DIG_3B 5
#define LED_DIG_PORT PORTA
#define LED_DIG_DDR DDRA
// Датчик DS18B20 - любая свободная ножка МК
#define DS18B20 7
#define DS18B20_PORT PORTA
#define DS18B20_PIN PINA
#define DS18B20_DDR DDRA
// Массив для перекодировки цифры в набор сегментов для семисегментного индикатора
const uint8_t codes[16]=
{
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F), // цифра 0
(1<<LED_SEG_B)|(1<<LED_SEG_C), // цифра 1
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // цифра 2
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_G), // цифра 3
(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 4
(1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 5
(1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 6
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F), // цифра 7
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 8
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 9
0b00000000, // пробел (код 10)
(1<<LED_SEG_G), // прочерк (код 11)
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // символ градуса (код 12)
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G)|(1<<LED_SEG_DP), // зажечь все сегменты (код 13)
(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // буква "c" для вывода слова "crc" (код 14)
(1<<LED_SEG_E)|(1<<LED_SEG_G) // буква "r" для вывода слова "crc" (код 15)
};
#define SEG_BLANK 10 // пробел
#define SEG_MINUS 11 // прочерк
#define SEG_DEGREE 12 // символ градуса
#define SEG_ALL 13 // зажечь все сегменты
#define SEG_C 14 // буква "c" для вывода слова "crc"
#define SEG_R 15 // буква "r" для вывода слова "crc"
volatile uint8_t digit = 0; // Номер текущего знакоместа динамической индикации
volatile uint8_t digit1 = 0; // Цифра или символ, выводимые в 1 знакоместо
volatile uint8_t digit2 = 0; // Цифра или символ, выводимые во 2 знакоместо
volatile uint8_t digit3 = 0; // Цифра или символ, выводимые в 3 знакоместо
uint8_t DS_scratchpad[9] = {0,0,0,0,0,0,0,0,0}; // 9 байт, считанных с DS18B20, или так называемый "блокнот"
uint8_t Presense_errors = 0; // Счётчик ошибок - инициализация DS18B20
uint8_t Short_circuit_errors = 0; // Счётчик ошибок - КЗ линии данных DS18B20
int8_t Temperature = 0; // Температура преобразованная (целая часть градусов)
// Прерывание по переполнению таймера 1 (динамическая индикация)
ISR (TIMER1_OVF_vect)
{
///////////////////////////////////
// Индикатор с общим анодом (ОА)
///////////////////////////////////
// Выключаю все сегменты
#ifndef LEDS_OK
LED_SEG_PORT = ~(0b00000000);
// Деактивирую все знакоместа
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
// Отображаю цифру в одном из знакомест
switch (digit)
{
case 0:
{
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B); // Активирую 1 знакоместо
LED_SEG_PORT = ~(codes[digit1]); // На сегментах отображаю цифру
} break;
case 1:
{
LED_DIG_PORT |= (1<<LED_DIG_2A)|(1<<LED_DIG_2B); // Активирую 2 знакоместо
LED_SEG_PORT = ~(codes[digit2]); // На сегментах отображаю цифру
} break;
case 2:
{
LED_DIG_PORT |= (1<<LED_DIG_3A)|(1<<LED_DIG_3B); // Активирую 3 знакоместо
LED_SEG_PORT = ~(codes[digit3]); // На сегментах отображаю цифру
} break;
};
///////////////////////////////////
// Индикатор с общим катодом (ОК)
///////////////////////////////////
// Выключаю все сегменты
#else
LED_SEG_PORT = 0b00000000;
// Деактивирую все знакоместа
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
// Отображаю цифру в одном из знакомест
switch (digit)
{
case 0:
{
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)); // Активирую 1 знакоместо
LED_SEG_PORT = codes[digit1]; // На сегментах отображаю цифру
} break;
case 1:
{
LED_DIG_PORT &= ~((1<<LED_DIG_2A)|(1<<LED_DIG_2B)); // Активирую 2 знакоместо
LED_SEG_PORT = codes[digit2]; // На сегментах отображаю цифру
} break;
case 2:
{
LED_DIG_PORT &= ~((1<<LED_DIG_3A)|(1<<LED_DIG_3B)); // Активирую 3 знакоместо
LED_SEG_PORT = codes[digit3]; // На сегментах отображаю цифру
} break;
};
#endif
// Готовлюсь к отображению следующего знакоместа
if (digit >= 2) digit = 0; else digit++;
}
// Инициализирую DS18B20
void DS18B20_init (void)
{
if ((DS18B20_PIN & (1 << DS18B20)) == 0) Short_circuit_errors++; // Проверяю КЗ линии данных
DS18B20_PORT &= ~(1 << DS18B20); // Устанавливаю низкий уровень
DS18B20_DDR |= (1 << DS18B20);
_delay_us(490);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(68);
if ((DS18B20_PIN & (1 << DS18B20)) > 0) Presense_errors++; // Ловлю импульс присутствия датчика
// Если датчик не подключен, Presense_errors увеличиваю на 1
_delay_us(422);
}
// Функция чтения байта из DS18B20
uint8_t DS18B20_read (void)
{
uint8_t dat = 0;
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(4);
dat = dat >> 1;
if (DS18B20_PIN & (1 << DS18B20))
{
dat |= 0x80;
}
_delay_us(62);
}
return dat;
}
// Функция чтения "блокнота" из DS18B20
void DS18B20_read_scratchpad (void)
{
for (uint8_t i=0; i<9; i++) // Считываю 9 байт данных, или так называемый "блокнот"
{
DS_scratchpad = DS18B20_read();
}
}
// Функция записи байта в DS18B20
void DS18B20_write (uint8_t dat)
{
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
if (dat & 0x01)
{
DS18B20_DDR &= ~(1 << DS18B20);
}
else
{
DS18B20_DDR |= (1 << DS18B20);
}
dat = dat >> 1;
_delay_us(62);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(2);
}
}
// Алгоритм для вычисления CRC-8 для DALLAS.
// Для первого байта CRC = 0, для остальных - то, что получилось от предыдущего.
// В расчёт CRC входят первые 8 байт DS18B20.
// 1. Нахождение логического исключающего ИЛИ между младшим битом CRC и младшим битом данных.
// 2. Если результат равен 0, то:
// - Сдвиг вправо CRC.
// 3. Если результат равен 1, то:
// - Поиск нового значения CRC путем вычисления логического исключающего ИЛИ между CRC и полиномом CRC.
// - Сдвиг вправо CRC.
// - Установка старшего бита CRC в 1.
// - Сдвиг вправо данных.
// - Повтор данной последовательности 8 раз на 1 байт данных.
uint8_t DS18B20_crc (uint16_t adress)
{
uint8_t crc = 0; // Переменная для накопления CRC
for (uint8_t i=0; i<8; i++) // Считаю CRC 8-ми байт, 9-й байт это CRC
{
// Расчитываю CRC одного байта
crc = crc ^ (*(uint16_t*)(adress+i));
for (uint8_t j=0; j<8; j++)
{
if (crc & 0x01) crc = (crc >> 1) ^ 0x8C;
else crc >>= 1;
}
}
return crc; // Возвращаю CRC
}
//Прерывание по сравнению таймера 1 гасим все разряды
ISR (TIMER1_COMPA_vect)
{
///////////////////////////////////
// Индикатор с общим анодом (ОА)
///////////////////////////////////
#ifndef LEDS_OK
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
///////////////////////////////////
// Индикатор с общим катодом (ОК)
///////////////////////////////////
#else
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
#endif
}
// Главная программа
int main (void)
{
// Настраиваю ножки МК для сегментов
LED_SEG_DDR |= 0xFF;
LED_SEG_PORT |= 0x00;
// Настраиваю ножки МК для знакомест
LED_DIG_DDR |= (1 << LED_DIG_1A)|(1 << LED_DIG_1B)|(1 << LED_DIG_2A)|(1 << LED_DIG_2B)|(1 << LED_DIG_3A)|(1 << LED_DIG_3B);
LED_DIG_PORT |= 0x00;
// Настраиваю таймер 1 для ШИМ
TCCR1A |= (0 << COM1A0)|(0 << COM1A1)|(1 << PWM1A); // Ножки микроконтроллера отключены от компаратора. Режим FASTPWM.
TCCR1B |= (1 << CS13)|(0 << CS12)|(1 << CS11)|(1 << CS10); //предделитель на 1024, частота индикатора 2,6 кГц.
TCCR1D |= (0 << WGM10)|(0 << WGM11); //Режим FASTPWM
TIMSK |= (1 << TOIE1)|(1 << OCIE1A); // Разрешение прерываний таймера 1 по переполнению и сравнению
OCR1A = 50; // Начальное значение OCR1A. Яркость индикатора.
asm volatile ("sei"); // Глобально разрешаю прерывания
// При старте термометра делаю тест всех сегментов 0.5 секунды
digit1 = SEG_ALL;
digit2 = SEG_ALL;
digit3 = SEG_ALL;
while(1)
{
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0x44); // Запускаю температурное преобразование
_delay_ms(1000); // Жду окончания температурного преобразования
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0xBE); // Команда на чтение содержимого ОЗУ
DS18B20_read_scratchpad(); // Считываю "блокнот"
if (Presense_errors | Short_circuit_errors) // Если датчик не отвечает на Presense-импульс, либо КЗ линии данных
{
// Cтавлю "---" во всех разрядах семисегментного индикатора
digit1 = SEG_MINUS;
digit2 = SEG_MINUS;
digit3 = SEG_MINUS;
}
else
{
if (DS_scratchpad[8] == DS18B20_crc(&DS_scratchpad[0])) // Если принятая CRC совпала с расчётной CRC
{
Temperature = (int8_t)((DS_scratchpad[1] << 4)|(DS_scratchpad[0] >> 4)); // Совмещаю младший и старший байты, отбрасываю дробную часть, получаю температуру в градусах.
if (Temperature < 0)
// Отрицательная температура
{
Temperature =-Temperature; // Перевожу отрицательное число в положительное
digit1 = SEG_MINUS; // Символ "-"
if (Temperature < 10)
{
// -9*...-1*
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
else
{
// -55...-10
digit2 = Temperature % 100 / 10; // Десятки градусов
digit3 = Temperature % 10; // Единицы градусов
}
}
else
// Положительная температура
{
if (Temperature > 99)
{
// 100...125
digit1 = Temperature % 1000 / 100; // Сотни градусов
digit2 = Temperature % 100 / 10; // Десятки градусов
digit3 = Temperature % 10; // Единицы градусов
}
else
{
if (Temperature > 9)
{
// 10*...99*
digit1 = Temperature % 100 / 10; // Десятки градусов
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
else
{
// 0*...9*
digit1 = SEG_BLANK; // Пустой символ
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
}
}
}
else // Если принятая CRC не совпала с расчётной, выводим надпись "crc" на семисегментный индикатор
{
digit1 = SEG_C; // "c"
digit2 = SEG_R; // "r"
digit3 = SEG_C; // "c"
}
}
Presense_errors=Short_circuit_errors=0; // Сбрасываю счётчик ошибок инициализации DS18B20, сбрасываю флаг КЗ
}
}
Переделал программу на Timer1, но проблема в том, что не срабатывает прерывание по сравнению вообще. Подскажите в чём моя ошибка. Может что-то упустил.
ISR (TIMER1_OVF_vect) // Прерывание по переполнению таймера 1
{
Отображение цифр на сегментах
}
ISR (TIMER1_COMPA_vect) //Прерывание по сравнению таймера 1
{
Гасим все разряды
}
// Главная программа
int main (void)
{
// Настраиваю таймер 1 для ШИМ
TCCR1A |= (0 << COM1A0)|(0 << COM1A1)|(1 << PWM1A); // Ножки микроконтроллера отключены от компаратора. Режим FASTPWM.
TCCR1B |= (1 << CS13)|(0 << CS12)|(1 << CS11)|(1 << CS10); //Предделитель на 1024, частота индикатора 2,6 кГц.
TCCR1D |= (0 << WGM10)|(0 << WGM11); //Режим FASTPWM
TIMSK |= (1 << TOIE1)|(1 << OCIE1A); // Разрешение прерываний таймера 1 по переполнению и сравнению
OCR1A = 50; // Начальное значение OCR1A. Яркость индикатора.
asm volatile ("sei"); // Глобально разрешаю прерывания
...остальная часть программы. Считывание температуры и вывод на индикатор.
}
Полный код программы под спойлером.
Спойлер
#define F_CPU 8000000UL // Тактовая частота микроконтроллера 8 МГц#define LEDS_OK // Раскомментировать, если используется индикатор с общим катодом
// Подключаю стандартные библиотеки
#include <avr/io.h> // Ножки ввода-вывода
#include <util/delay.h> // Задержки
#include <avr/interrupt.h> // Прерывания
// Сегменты, должны быть в пределах одного порта МК
#define LED_SEG_A 2
#define LED_SEG_B 0
#define LED_SEG_C 4
#define LED_SEG_D 6
#define LED_SEG_E 5
#define LED_SEG_F 1
#define LED_SEG_G 3
#define LED_SEG_DP 7
#define LED_SEG_PORT PORTB
#define LED_SEG_DDR DDRB
// Знакоместа, должны быть в пределах одного порта МК
#define LED_DIG_1A 2
#define LED_DIG_1B 3
#define LED_DIG_2A 1
#define LED_DIG_2B 4
#define LED_DIG_3A 0
#define LED_DIG_3B 5
#define LED_DIG_PORT PORTA
#define LED_DIG_DDR DDRA
// Датчик DS18B20 - любая свободная ножка МК
#define DS18B20 7
#define DS18B20_PORT PORTA
#define DS18B20_PIN PINA
#define DS18B20_DDR DDRA
// Массив для перекодировки цифры в набор сегментов для семисегментного индикатора
const uint8_t codes[16]=
{
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F), // цифра 0
(1<<LED_SEG_B)|(1<<LED_SEG_C), // цифра 1
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // цифра 2
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_G), // цифра 3
(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 4
(1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 5
(1<<LED_SEG_A)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 6
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_F), // цифра 7
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 8
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // цифра 9
0b00000000, // пробел (код 10)
(1<<LED_SEG_G), // прочерк (код 11)
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_F)|(1<<LED_SEG_G), // символ градуса (код 12)
(1<<LED_SEG_A)|(1<<LED_SEG_B)|(1<<LED_SEG_C)|(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_F)|(1<<LED_SEG_G)|(1<<LED_SEG_DP), // зажечь все сегменты (код 13)
(1<<LED_SEG_D)|(1<<LED_SEG_E)|(1<<LED_SEG_G), // буква "c" для вывода слова "crc" (код 14)
(1<<LED_SEG_E)|(1<<LED_SEG_G) // буква "r" для вывода слова "crc" (код 15)
};
#define SEG_BLANK 10 // пробел
#define SEG_MINUS 11 // прочерк
#define SEG_DEGREE 12 // символ градуса
#define SEG_ALL 13 // зажечь все сегменты
#define SEG_C 14 // буква "c" для вывода слова "crc"
#define SEG_R 15 // буква "r" для вывода слова "crc"
volatile uint8_t digit = 0; // Номер текущего знакоместа динамической индикации
volatile uint8_t digit1 = 0; // Цифра или символ, выводимые в 1 знакоместо
volatile uint8_t digit2 = 0; // Цифра или символ, выводимые во 2 знакоместо
volatile uint8_t digit3 = 0; // Цифра или символ, выводимые в 3 знакоместо
uint8_t DS_scratchpad[9] = {0,0,0,0,0,0,0,0,0}; // 9 байт, считанных с DS18B20, или так называемый "блокнот"
uint8_t Presense_errors = 0; // Счётчик ошибок - инициализация DS18B20
uint8_t Short_circuit_errors = 0; // Счётчик ошибок - КЗ линии данных DS18B20
int8_t Temperature = 0; // Температура преобразованная (целая часть градусов)
// Прерывание по переполнению таймера 1 (динамическая индикация)
ISR (TIMER1_OVF_vect)
{
///////////////////////////////////
// Индикатор с общим анодом (ОА)
///////////////////////////////////
// Выключаю все сегменты
#ifndef LEDS_OK
LED_SEG_PORT = ~(0b00000000);
// Деактивирую все знакоместа
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
// Отображаю цифру в одном из знакомест
switch (digit)
{
case 0:
{
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B); // Активирую 1 знакоместо
LED_SEG_PORT = ~(codes[digit1]); // На сегментах отображаю цифру
} break;
case 1:
{
LED_DIG_PORT |= (1<<LED_DIG_2A)|(1<<LED_DIG_2B); // Активирую 2 знакоместо
LED_SEG_PORT = ~(codes[digit2]); // На сегментах отображаю цифру
} break;
case 2:
{
LED_DIG_PORT |= (1<<LED_DIG_3A)|(1<<LED_DIG_3B); // Активирую 3 знакоместо
LED_SEG_PORT = ~(codes[digit3]); // На сегментах отображаю цифру
} break;
};
///////////////////////////////////
// Индикатор с общим катодом (ОК)
///////////////////////////////////
// Выключаю все сегменты
#else
LED_SEG_PORT = 0b00000000;
// Деактивирую все знакоместа
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
// Отображаю цифру в одном из знакомест
switch (digit)
{
case 0:
{
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)); // Активирую 1 знакоместо
LED_SEG_PORT = codes[digit1]; // На сегментах отображаю цифру
} break;
case 1:
{
LED_DIG_PORT &= ~((1<<LED_DIG_2A)|(1<<LED_DIG_2B)); // Активирую 2 знакоместо
LED_SEG_PORT = codes[digit2]; // На сегментах отображаю цифру
} break;
case 2:
{
LED_DIG_PORT &= ~((1<<LED_DIG_3A)|(1<<LED_DIG_3B)); // Активирую 3 знакоместо
LED_SEG_PORT = codes[digit3]; // На сегментах отображаю цифру
} break;
};
#endif
// Готовлюсь к отображению следующего знакоместа
if (digit >= 2) digit = 0; else digit++;
}
// Инициализирую DS18B20
void DS18B20_init (void)
{
if ((DS18B20_PIN & (1 << DS18B20)) == 0) Short_circuit_errors++; // Проверяю КЗ линии данных
DS18B20_PORT &= ~(1 << DS18B20); // Устанавливаю низкий уровень
DS18B20_DDR |= (1 << DS18B20);
_delay_us(490);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(68);
if ((DS18B20_PIN & (1 << DS18B20)) > 0) Presense_errors++; // Ловлю импульс присутствия датчика
// Если датчик не подключен, Presense_errors увеличиваю на 1
_delay_us(422);
}
// Функция чтения байта из DS18B20
uint8_t DS18B20_read (void)
{
uint8_t dat = 0;
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(4);
dat = dat >> 1;
if (DS18B20_PIN & (1 << DS18B20))
{
dat |= 0x80;
}
_delay_us(62);
}
return dat;
}
// Функция чтения "блокнота" из DS18B20
void DS18B20_read_scratchpad (void)
{
for (uint8_t i=0; i<9; i++) // Считываю 9 байт данных, или так называемый "блокнот"
{
DS_scratchpad = DS18B20_read();
}
}
// Функция записи байта в DS18B20
void DS18B20_write (uint8_t dat)
{
for (uint8_t i=0; i<8; i++)
{
DS18B20_DDR |= (1 << DS18B20);
_delay_us(2);
if (dat & 0x01)
{
DS18B20_DDR &= ~(1 << DS18B20);
}
else
{
DS18B20_DDR |= (1 << DS18B20);
}
dat = dat >> 1;
_delay_us(62);
DS18B20_DDR &= ~(1 << DS18B20);
_delay_us(2);
}
}
// Алгоритм для вычисления CRC-8 для DALLAS.
// Для первого байта CRC = 0, для остальных - то, что получилось от предыдущего.
// В расчёт CRC входят первые 8 байт DS18B20.
// 1. Нахождение логического исключающего ИЛИ между младшим битом CRC и младшим битом данных.
// 2. Если результат равен 0, то:
// - Сдвиг вправо CRC.
// 3. Если результат равен 1, то:
// - Поиск нового значения CRC путем вычисления логического исключающего ИЛИ между CRC и полиномом CRC.
// - Сдвиг вправо CRC.
// - Установка старшего бита CRC в 1.
// - Сдвиг вправо данных.
// - Повтор данной последовательности 8 раз на 1 байт данных.
uint8_t DS18B20_crc (uint16_t adress)
{
uint8_t crc = 0; // Переменная для накопления CRC
for (uint8_t i=0; i<8; i++) // Считаю CRC 8-ми байт, 9-й байт это CRC
{
// Расчитываю CRC одного байта
crc = crc ^ (*(uint16_t*)(adress+i));
for (uint8_t j=0; j<8; j++)
{
if (crc & 0x01) crc = (crc >> 1) ^ 0x8C;
else crc >>= 1;
}
}
return crc; // Возвращаю CRC
}
//Прерывание по сравнению таймера 1 гасим все разряды
ISR (TIMER1_COMPA_vect)
{
///////////////////////////////////
// Индикатор с общим анодом (ОА)
///////////////////////////////////
#ifndef LEDS_OK
LED_DIG_PORT &= ~((1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B));
///////////////////////////////////
// Индикатор с общим катодом (ОК)
///////////////////////////////////
#else
LED_DIG_PORT |= (1<<LED_DIG_1A)|(1<<LED_DIG_1B)|(1<<LED_DIG_2A)|(1<<LED_DIG_2B)|(1<<LED_DIG_3A)|(1<<LED_DIG_3B);
#endif
}
// Главная программа
int main (void)
{
// Настраиваю ножки МК для сегментов
LED_SEG_DDR |= 0xFF;
LED_SEG_PORT |= 0x00;
// Настраиваю ножки МК для знакомест
LED_DIG_DDR |= (1 << LED_DIG_1A)|(1 << LED_DIG_1B)|(1 << LED_DIG_2A)|(1 << LED_DIG_2B)|(1 << LED_DIG_3A)|(1 << LED_DIG_3B);
LED_DIG_PORT |= 0x00;
// Настраиваю таймер 1 для ШИМ
TCCR1A |= (0 << COM1A0)|(0 << COM1A1)|(1 << PWM1A); // Ножки микроконтроллера отключены от компаратора. Режим FASTPWM.
TCCR1B |= (1 << CS13)|(0 << CS12)|(1 << CS11)|(1 << CS10); //предделитель на 1024, частота индикатора 2,6 кГц.
TCCR1D |= (0 << WGM10)|(0 << WGM11); //Режим FASTPWM
TIMSK |= (1 << TOIE1)|(1 << OCIE1A); // Разрешение прерываний таймера 1 по переполнению и сравнению
OCR1A = 50; // Начальное значение OCR1A. Яркость индикатора.
asm volatile ("sei"); // Глобально разрешаю прерывания
// При старте термометра делаю тест всех сегментов 0.5 секунды
digit1 = SEG_ALL;
digit2 = SEG_ALL;
digit3 = SEG_ALL;
while(1)
{
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0x44); // Запускаю температурное преобразование
_delay_ms(1000); // Жду окончания температурного преобразования
DS18B20_init(); // Инициализирую DS18B20
DS18B20_write(0xCC); // Пропускаю проверку серийного номера DS18B20
DS18B20_write(0xBE); // Команда на чтение содержимого ОЗУ
DS18B20_read_scratchpad(); // Считываю "блокнот"
if (Presense_errors | Short_circuit_errors) // Если датчик не отвечает на Presense-импульс, либо КЗ линии данных
{
// Cтавлю "---" во всех разрядах семисегментного индикатора
digit1 = SEG_MINUS;
digit2 = SEG_MINUS;
digit3 = SEG_MINUS;
}
else
{
if (DS_scratchpad[8] == DS18B20_crc(&DS_scratchpad[0])) // Если принятая CRC совпала с расчётной CRC
{
Temperature = (int8_t)((DS_scratchpad[1] << 4)|(DS_scratchpad[0] >> 4)); // Совмещаю младший и старший байты, отбрасываю дробную часть, получаю температуру в градусах.
if (Temperature < 0)
// Отрицательная температура
{
Temperature =-Temperature; // Перевожу отрицательное число в положительное
digit1 = SEG_MINUS; // Символ "-"
if (Temperature < 10)
{
// -9*...-1*
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
else
{
// -55...-10
digit2 = Temperature % 100 / 10; // Десятки градусов
digit3 = Temperature % 10; // Единицы градусов
}
}
else
// Положительная температура
{
if (Temperature > 99)
{
// 100...125
digit1 = Temperature % 1000 / 100; // Сотни градусов
digit2 = Temperature % 100 / 10; // Десятки градусов
digit3 = Temperature % 10; // Единицы градусов
}
else
{
if (Temperature > 9)
{
// 10*...99*
digit1 = Temperature % 100 / 10; // Десятки градусов
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
else
{
// 0*...9*
digit1 = SEG_BLANK; // Пустой символ
digit2 = Temperature % 10; // Единицы градусов
digit3 = SEG_DEGREE; // Символ градуса
}
}
}
}
else // Если принятая CRC не совпала с расчётной, выводим надпись "crc" на семисегментный индикатор
{
digit1 = SEG_C; // "c"
digit2 = SEG_R; // "r"
digit3 = SEG_C; // "c"
}
}
Presense_errors=Short_circuit_errors=0; // Сбрасываю счётчик ошибок инициализации DS18B20, сбрасываю флаг КЗ
}
}
- Электpониk
- Прорезались зубы
- Сообщения: 247
- Зарегистрирован: Чт янв 08, 2015 22:31:15
Re: Вопросы по С/С++ (СИ)
Разобрался. Я моделировал в Proteus, а в нём почему то ШИМ не работает, возможно это связано с тем, что семисегментные индикаторы в нём не умеют менять яркость. Хотя на осциллографе должна изменяться скважность импульсов подаваемых на катоды/аноды, но почему то и этого не происходит. В общем Proteus для моделирования таких задач не подходит.
На реальном железе всё работает, как нельзя лучше. Яркость изменяется в зависимости от значения регистра OCR1A. Чем оно выше, тем выше яркость.
На реальном железе всё работает, как нельзя лучше. Яркость изменяется в зависимости от значения регистра OCR1A. Чем оно выше, тем выше яркость.
Re: Вопросы по С/С++ (СИ)
Добрый день, на вход функции надо подать число в формате Q15, это число с фиксированной точкой где 1бит отводится под целую часть и 15 под дробную часть. У меня же данные, которые хотелось бы подать хранятся в uint16_t.
Нужно ли как то преобразовывать uint16_t или можно подать так?
Мне думается, что можно подать без каких-либо преобразований uint16_t?
Подскажите пожалуйста как правильно?
Нужно ли как то преобразовывать uint16_t или можно подать так?
Мне думается, что можно подать без каких-либо преобразований uint16_t?
Подскажите пожалуйста как правильно?
- ARV
- Ум, честь и совесть. И скромность.
- Сообщения: 18544
- Зарегистрирован: Чт дек 28, 2006 08:19:56
- Откуда: Новочеркасск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
если сами биты в вашем числе расположены в соответствии с требованиями функции, то можно подать. для исключения предупреждения компилятора при подаче рекомендую принудительно привести число к требуемому типу.baghear писал(а):Подскажите пожалуйста как правильно?
как-то так: my_func((Q15)my_int16_var);
если рассматривать человека снизу, покажется, что мозг у него глубоко в жопе
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
при взгляде на многих сверху ничего не меняется...
Мой уютный бложик... заходите!
Re: Вопросы по С/С++ (СИ)
Спасибо!!!
Ещё вопрос входной и выходной формат функции отличается, как показано в таблице.
Что указывается в последнем столбце.
Находил упоминание о том, что число в последнем столбце показывает на сколько надо сдвинуть влево получившийся результат, но так и не понял почему.
Ещё вопрос входной и выходной формат функции отличается, как показано в таблице.
Что указывается в последнем столбце.
Находил упоминание о том, что число в последнем столбце показывает на сколько надо сдвинуть влево получившийся результат, но так и не понял почему.
- Вложения
-
- Screenshot_1.jpg
- (37.72 КБ) 554 скачивания
- ptr128
- Вымогатель припоя
- Сообщения: 606
- Зарегистрирован: Чт окт 06, 2016 21:12:07
- Откуда: Южное Бутово
Re: Вопросы по С/С++ (СИ)
Не уверен, что это так, но очень похоже на формат двоичного числа с фиксированной точкой, где в таблице указываетя количество бит до десятичной точки и количество бит после нее.
То есть, в последней колонке указано, на сколько бит вправо смещена десятичная точка, относительно формата во второй колонке.
То есть, в последней колонке указано, на сколько бит вправо смещена десятичная точка, относительно формата во второй колонке.
Не ошибается только то, кто ничего не делает.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Тот, кто признает свои ошибки, на них учится.
Глупец же, упорствуя в своих заблуждениях, остается глупцом.
Re: Вопросы по С/С++ (СИ)
Спасибо, похоже Вы правы.
- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Други-знатоки, помогите, если не трудно, разобраться в указателях
По определению указатель есть переменная, которая содержит в себе адрес другой переменной. Определение в общем понятно.
Непонятно следующее: если он (указатель) содержит адрес, который обычно не занимает меньше 16 бит, то почему его всегда ориентируют на размерность переменной, на которую он указывает?
Если, скажем, имеется массив char array[10], то почему указатель на него *ptr тоже должен быть типа char? Ведь адрес, по которому размещается массив, скорее всего не менее 16 бит?
По определению указатель есть переменная, которая содержит в себе адрес другой переменной. Определение в общем понятно.
Непонятно следующее: если он (указатель) содержит адрес, который обычно не занимает меньше 16 бит, то почему его всегда ориентируют на размерность переменной, на которую он указывает?
Если, скажем, имеется массив char array[10], то почему указатель на него *ptr тоже должен быть типа char? Ведь адрес, по которому размещается массив, скорее всего не менее 16 бит?
Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
- WiseLord
- Друг Кота
- Сообщения: 4905
- Зарегистрирован: Чт апр 11, 2013 11:19:59
- Откуда: Минск
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Ничего подобного, Вы немного запутались. Все указатели, на любые типы, имеют один и тот же размер.Zhuk72 писал(а):если он (указатель) содержит адрес, который обычно не занимает меньше 16 бит, то почему его всегда ориентируют на размерность переменной, на которую он указывает?
Не так. Правильно не "указатель *ptr типа char", а "указатель ptr типа char*".Если, скажем, имеется массив char array[10], то почему указатель на него *ptr тоже должен быть типа char?
В данном случае, например, если вы пишете что-то вроде
Код: Выделить всё
char array[10];
char *ptr = array;- Zhuk72
- Сверлит текстолит когтями
- Сообщения: 1231
- Зарегистрирован: Ср янв 29, 2014 08:41:31
- Откуда: Баку
- Контактная информация:
Re: Вопросы по С/С++ (СИ)
Спасибо за разъяснение!
Т.е. запись char *ptr означает, что содержимое ячейки, на которую указывает ptr имеет тип char. Верно?
Соответственно равносильно
Я правильно понимаю?
Т.е. запись char *ptr означает, что содержимое ячейки, на которую указывает ptr имеет тип char. Верно?
Соответственно
Код: Выделить всё
char array[10];
char *ptr = array;Код: Выделить всё
char array[10];
char *ptr;
ptr = array;Каждый имеет право на свое личное ошибочное мнение.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.
У меня было тяжелое детство - я до 14 лет смотрел черно-белый телевизор.


