Страница 1 из 1

Помогите решить проблему с DS18b20

Добавлено: 28 фев 2019, 09:08
Skipper
Здравствуйте. Сам я далек от программирования, но возникшая проблема вынуждает обратиться к вам за помощью.
Имеется: линия с 8 DS18B20 - cхемка на двух транзисторах(внизу) - адаптер RS232-USB "Z-Tek" - компьютер - программа TempKeeper. Система отлично работала несколько дней и вдруг:
1 - На одном датчике стала плавать(произвольно меняться в процессе измерения) битность с 9 до 12. В свойствах датчика битность - 12
2 - На другом датчике стала плавать(произвольно меняться в процессе измерения) битность с 9 до 11. В свойствах битность - 11
3 - На остальных битность 9, в свойствах - пробел. Программой задана на все датч битность 12
Первым делом отключил линию, подключил новый DS прямо на плату, результ - см выше п.1 . Пробовал поменять комп и ставил другие программы Т-мониторинга - все то же самое. Еще пробовал время изм 750мс менять.
Для меня важна не столько точность, сколь высокое разрешение.
Очень надеюсь на вашу помощь.
aaa.gif
aaa.gif (7.51 КБ) 15919 просмотров

Re: Помогите решить проблему с DS18b20

Добавлено: 06 май 2020, 23:50
nike
Здравствуйте. Запустил в протеусе термометр по этой статье https://radioparty.ru/programming/avr/c ... n2-ds18b20 На Atmega 8, всё работает. Хотел переделать под Atmega328p, заменил в настройках таймера регистры TIMSK и TCCR2 на TIMSK2 и TCCR2B, всё остральное не трогал. В итоге экран показывает одни прочерки (. Подскажите пожалуйста, может я забыл ещё что-то изменить ? Вот на всякий случай код

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

// Подключение цифровых датчиков температуры DS18B20 к AVR
#define F_CPU 8000000UL // Устанавливаем рабочую частоту контроллера
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

// Массив значениий для семисегментного индикатора
char SEGMENTE[] =
{
	0x3F, // 0
	0x06, // 1
	0x5B, // 2
	0x4F, // 3
	0x66, // 4
	0x6D, // 5
	0x7D, // 6
	0x07, // 7
	0x7F, // 8
	0x6F, // 9
	0x40, // "минус"
	0x00  // "пусто"
};
unsigned char segcounter = 0;
volatile unsigned char display_1, display_2, display_3, display_4;

// Прерывание по переполнению T2, динамическая индикация
ISR (TIMER2_OVF_vect)
{
	PORTD = 0xFF;
	PORTB = (1 << segcounter);
	
	switch (segcounter)
	{
		case 0:
		PORTD = ~(SEGMENTE[display_1]);
		break;
		case 1:
		PORTD = ~(SEGMENTE[display_2]);
		break;
		case 2:
		PORTD = ~((SEGMENTE[display_3])|0x80); // добавляем точку
		break;
		case 3:
		PORTD = ~(SEGMENTE[display_4]);
		break;
	}
	if ((segcounter++) > 2) segcounter = 0;
}

unsigned char Temp_H, Temp_L, OK_Flag, temp_flag;

// Инициализация DS18B20
unsigned char DS18B20_init(void)
{
	DDRC |= (1 << PC0); // PC0 - выход
	PORTC &= ~(1 << PC0); // Устанавливаем низкий уровень
	_delay_us(490);
	DDRC &= ~(1 << PC0); // PC0 - вход
	_delay_us(68);
	OK_Flag = (PINC & (1 << PC0)); // Ловим импульс присутствия датчика
	// если OK_Flag = 0 датчик подключен, OK_Flag = 1 датчик не подключен
	_delay_us(422);
	return OK_Flag;
}

// Функция чтения байта из DS18B20
unsigned char read_18b20(void)
{
	unsigned char i, data = 0;
	for(i = 0; i < 8; i++)
	{
		DDRC |= (1 << PC0); // PC0 - выход
		_delay_us(2);
		DDRC &= ~(1 << PC0); // PC0 - вход
		_delay_us(4);
		data = data >> 1; // Следующий бит
		if(PINC & (1 << PC0)) data |= 0x80;
		_delay_us(62);
	}
	return data;
}

// Функция записи байта в DS18B20
void write_18b20(unsigned char data)
{
	unsigned char i;
	for(i = 0; i < 8; i++)
	{
		DDRC |= (1 << PC0); // PC0 - выход
		_delay_us(2);
		if(data & 0x01) DDRC &= ~(1 << PC0);
		else DDRC |= (1 << PC0);
		data = data >> 1; // Следующий бит
		_delay_us(62);
		DDRC &= ~(1 << PC0); // PC0 - вход
		_delay_us(2);
	}
}

// Главная функция
int main(void)
{
	// Настройка портов ввода/вывода
	DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3); // Разряды
	PORTB = 0x00;
	DDRD = 0xFF; // Сегменты
	PORTD = 0x00;
	// Настройка Т2
	TIMSK2 |= (1 << TOIE2); // Разрешение прерывания по Т2
	TCCR2B |= (1 << CS21);  // Предделитель на 8
	
	unsigned int buffer;
	unsigned int temp_int_1,temp_int_2,temp_int_3; // Переменные для целого значения температуры
	unsigned int temp_point; // Переменная для дробного значения температуры

	sei(); // Глобально разрешаем прерывания
	
	while(1)
	{
		// Если датчик не ответил выводим "минус" во всех разрядах
		if(OK_Flag) display_1 = display_2 = display_3 = display_4 = 10;

		DS18B20_init();        // Инициализация DS18B20
		write_18b20(0xCC);     // Проверка кода датчика
		write_18b20(0x44);     // Запуск температурного преобразования
		_delay_ms(1000);       // Задержка на опрос датчика
		DS18B20_init();        // Инициализация DS18B20
		write_18b20(0xCC);     // Проверка кода датчика
		write_18b20(0xBE);     // Считываем содержимое ОЗУ
		Temp_L = read_18b20(); // Читаем первые 2 байта блокнота
		Temp_H = read_18b20();
		temp_flag = 1;         // Флаг знака температуры равен 1(плюс)

		// Вычисляем отрицательную температуру
		if(Temp_H &(1 << 3))   // Проверяем бит знака температуры на равенство единице
		{
			signed int temp;
			temp_flag = 0;      // Флаг знака равен 0(минус)
			temp = (Temp_H << 8)|Temp_L;
			temp = -temp; // Переводим дополнительный код в прямой
			Temp_L = temp;
			Temp_H = temp >> 8;
		}

		// Вычисляем целое значение температуры
		buffer = ((Temp_H << 4) & 0x70)|(Temp_L >> 4);
		temp_int_1 = buffer % 1000 / 100;
		temp_int_2 = buffer % 100 / 10;
		temp_int_3 = buffer % 10;

		// Вычисляем дробное значение температуры
		if(temp_flag == 0) buffer = (Temp_L & 0x0F) + 1;
		else buffer = (Temp_L & 0x0F);
		temp_point = buffer * 625 / 1000; // Точность темпер.преобразования(0.0625)

		// Если флаг знака температуры равен 0, в первом разряде ставим минус
		if(temp_flag == 0) temp_int_1 = 10; // "минус"
		// Если первая цифра значения температуры меньше 1, то гасим 1-й разряд индикатора
		if(temp_int_1 < 1) temp_int_1 = 11; // "пусто"
		// Если первая цифра погашена и вторая цифра значения температуры меньше 1, то гасим 2-й разряд индикатора
		if(temp_int_1 == 11 && temp_int_2 < 1) temp_int_2 = 11; // "пусто"
		// Если вторая цифра значения температуры меньше 1 и знак равен "минус", то гасим 2-й разряд индикатора
		if(temp_int_2 < 1 && temp_flag == 0) temp_int_2 = 11; // "пусто"

		// Выводим значения на дисплей
		display_1 = temp_int_1;
		display_2 = temp_int_2;
		display_3 = temp_int_3;
		display_4 = temp_point;

	}
}

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 10:15
AntonChip
Здравствуйте. Возможно неправильно установлена частота микроконтроллера, установлен бит CLKDIV8

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 10:20
microsystems
прочерки - значит датчик не читается, так вроде бы?

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 11:37
nike
А atmel studio и протеусе стоит 8 Мгц
CLKDIV8
А где его проверить ?

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 11:46
nike
Нашёл, в протеусе поставил CLKDIV8 в (1) Unprogrammed, было (0) Programmed и всё заработало. А как в железе нормально будет работать ?

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 12:15
AntonChip
В железе работает, проверено

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 13:01
nike
AntonChip писал(а): 07 май 2020, 12:15 В железе работает, проверено
У меня не получилось( Правда у меня другой дисплей (SSD1306). Пробую выводить на него переменные temp_int_1,temp_int_2,temp_int_3.
Вместо них экран показывает :;01 При нагревании датчика нечего не меняется. Может при прошивке в avrdude попробывать убрать галочку с фьюза CKDIV8 ?

Re: Помогите решить проблему с DS18b20

Добавлено: 07 май 2020, 13:29
nike
Ура заработало. Пришлось убрать галочку CKDIV8 в avrdude. Спасибо за помощь.