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

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

Добавлено: Вт ноя 29, 2016 14:27:36
Электpониk
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

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

Добавлено: Вт ноя 29, 2016 15:03:25
Zhuk72
Пробуйте.

Но для сохранении идеологии вашего исходника сделайте такую поправку:

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

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
}
И для стройности вставьте после основного прерывания от таймера.

По поводу настроек таймера ничего не скажу. Это вы сами сравните с ДШ на МК.

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

Добавлено: Вт ноя 29, 2016 20:03:55
Электpониk
Zhuk72, компилятор сыпет ошибками что не знает такого таймера. Полез в даташит, оказывается действительно у ATTiny261A нет такого таймера. Это получается что яркость семисегментного индикатора уменьшить программно не получиться на этом микроконтроллере?

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

Добавлено: Вт ноя 29, 2016 20:19:14
Zhuk72
Так с этого и надо было начинать, с чтения ДШ. Да и тип МК вы держали в секрете.
Если есть 2 таймера, то можно легко сделать. Да и с одним тоже с чуть большими движениями.

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

Добавлено: Вт ноя 29, 2016 20:31:13
Электpониk
Zhuk72, да я сам об этом как то сразу и не подумал. Оказалось зря.
А с теми таймерами которые есть у ATTiny261A не подскажите конструкцию?

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

Добавлено: Вт ноя 29, 2016 20:47:42
Zhuk72
Я атмелами не занимаюсь, поэтому надо дш смотреть.
С двумя таймерами принцип такой: в конце прерывания первого таймера заряжаете и запускаете второй таймер, а уже в прерывании второго отключаете индикатор и останавливаете таймер. Период второго таймера должен быть меньше, чем у первого. Чем он будет меньше, тем ниже яркость свечения индикатора.

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

Добавлено: Вт ноя 29, 2016 20:59:16
ARV
вы не учитываете, что у этой тиньки развитая система цифровых компараторов для таймеров. чтобы регулировать яркость при динамической индикации достаточно одного таймера, общий принцип я описывал здесь: http://arv.radioliga.com/content/view/101/49/

Добавлено after 2 minutes 58 seconds:
Электpониk писал(а):Реализация изменения скважности импульсов показана тут http://radioparty.ru/prog-avr/program-c ... egment-avr
блин, такое ощущение, что статья была написана после прочтения моей :)

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

Добавлено: Вт ноя 29, 2016 21:37:45
Zhuk72
ARV писал(а):вы не учитываете, что у этой тиньки развитая система цифровых компараторов для таймеров.
Потому и сказал, что не занимаюсь Атмелами :) Я описал общий случай, не привязанный к конкретному железу. Если можно обойтись одним таймером с компаратором - тем лучше.

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

Добавлено: Ср ноя 30, 2016 11:31:00
Электpониk
Похоже что нужно юзать 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: Вопросы по С/С++ (СИ)

Добавлено: Ср ноя 30, 2016 21:42:28
FreshMan
Электpониk, принцип прост как бублик и состоит в следующем
берете 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();  // выключаем анодные драйвера (гасим индикаторы )
}


изменяя значение для OCR2 мы тем самым изменяем яркость определенного разряда
код для ATmega8

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

Добавлено: Пт дек 02, 2016 20:19:55
Электpониk
Принцип я понимаю. Вот только проблема в том, что у 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 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, сбрасываю флаг КЗ
}
}

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

Добавлено: Вс дек 04, 2016 11:54:04
Электpониk
Разобрался. Я моделировал в Proteus, а в нём почему то ШИМ не работает, возможно это связано с тем, что семисегментные индикаторы в нём не умеют менять яркость. Хотя на осциллографе должна изменяться скважность импульсов подаваемых на катоды/аноды, но почему то и этого не происходит. В общем Proteus для моделирования таких задач не подходит.
На реальном железе всё работает, как нельзя лучше. Яркость изменяется в зависимости от значения регистра OCR1A. Чем оно выше, тем выше яркость.

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

Добавлено: Чт дек 15, 2016 14:11:21
baghear
Добрый день, на вход функции надо подать число в формате Q15, это число с фиксированной точкой где 1бит отводится под целую часть и 15 под дробную часть. У меня же данные, которые хотелось бы подать хранятся в uint16_t.
Нужно ли как то преобразовывать uint16_t или можно подать так?
Мне думается, что можно подать без каких-либо преобразований uint16_t?
Подскажите пожалуйста как правильно?

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

Добавлено: Чт дек 15, 2016 14:17:38
ARV
baghear писал(а):Подскажите пожалуйста как правильно?
если сами биты в вашем числе расположены в соответствии с требованиями функции, то можно подать. для исключения предупреждения компилятора при подаче рекомендую принудительно привести число к требуемому типу.

как-то так: my_func((Q15)my_int16_var);

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

Добавлено: Чт дек 15, 2016 14:26:19
baghear
Спасибо!!!
Ещё вопрос входной и выходной формат функции отличается, как показано в таблице.
Что указывается в последнем столбце.

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

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

Добавлено: Чт дек 15, 2016 15:46:42
ptr128
Не уверен, что это так, но очень похоже на формат двоичного числа с фиксированной точкой, где в таблице указываетя количество бит до десятичной точки и количество бит после нее.
То есть, в последней колонке указано, на сколько бит вправо смещена десятичная точка, относительно формата во второй колонке.

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

Добавлено: Чт дек 15, 2016 18:29:44
baghear
Спасибо, похоже Вы правы.

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

Добавлено: Ср дек 21, 2016 08:58:53
Zhuk72
Други-знатоки, помогите, если не трудно, разобраться в указателях :?

По определению указатель есть переменная, которая содержит в себе адрес другой переменной. Определение в общем понятно.
Непонятно следующее: если он (указатель) содержит адрес, который обычно не занимает меньше 16 бит, то почему его всегда ориентируют на размерность переменной, на которую он указывает?
Если, скажем, имеется массив char array[10], то почему указатель на него *ptr тоже должен быть типа char? Ведь адрес, по которому размещается массив, скорее всего не менее 16 бит?

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

Добавлено: Ср дек 21, 2016 09:22:28
WiseLord
Zhuk72 писал(а):если он (указатель) содержит адрес, который обычно не занимает меньше 16 бит, то почему его всегда ориентируют на размерность переменной, на которую он указывает?
Ничего подобного, Вы немного запутались. Все указатели, на любые типы, имеют один и тот же размер.
Если, скажем, имеется массив char array[10], то почему указатель на него *ptr тоже должен быть типа char?
Не так. Правильно не "указатель *ptr типа char", а "указатель ptr типа char*".

В данном случае, например, если вы пишете что-то вроде

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

char array[10];
char *ptr = array;
То указатель - это ptr. Не *ptr (это, вообще-то, разыменование указателя - т.е., содержимое ячейки, куда он указывает), а именно ptr. И тип у него - char* (указывающий на char).

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

Добавлено: Ср дек 21, 2016 10:18:40
Zhuk72
Спасибо за разъяснение!
Т.е. запись char *ptr означает, что содержимое ячейки, на которую указывает ptr имеет тип char. Верно?
Соответственно

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

char array[10];
char *ptr = array;
равносильно

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

char array[10];
char *ptr;

ptr = array;
Я правильно понимаю?