Перейти к содержанию

Помогите разобраться с кодом на Atmega16


Cegrei Ulanov

Рекомендуемые сообщения

Добрый день. Хочу к микроконтроллеру Atmega16 подключить датчик температуры DS18B20. Для этого я пошел в гугл и нашёл код, только он был написан на Atmega8. Я его немного изменил, только вот функции с обнаружением датчика не трогал. На выходе я получил скомпилированную программу которая успешно работает в протеусе, а вот в железе микроконтроллер, всё иначе. Он не может обнаружить датчик DS18B20. И поэтому срабатывает условие

	if(OK_Flag == 1) // если датчик не ответил
		{
			// ставим прочерки во всех разрядах
			display1 = 11; display2 = 11;
			display3 = 11; display4 = 11;
		}

Я думал может DS18B20 не рабочий, но как выяснилось, он рабочий. На arduino проверял.

Весь код моей программы:

 

/*** Практическое применение термодатчиков DS18B20. Простой термометр ***/
//#define F_CPU 10000000
#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

void presend(){
	////DDRA = 0xFF; //0b1111111 	порт работает на выход.
	///PORTA = 0x00; // Порт отключен.
	
}
//#define F_CPU 8000000UL // устанавливаем рабочую частоту контроллера
//------------------0-----1-----2-----3-----4-----5-----6-----7-----8------9----dp---minus-blank
#define SEG_A  (1<<0) // назначение сегментов индикатора
#define SEG_B  (1<<1) // соответствующим битам порта LED
#define SEG_C  (1<<2) //      A
#define SEG_D  (1<<3) //   F     B
#define SEG_E  (1<<4) //      G
#define SEG_F  (1<<5) //   E     C
#define SEG_G  (1<<6) //      D     H
#define SEG_H  (1<<7) //

const unsigned char SEGMENTE [15] = {
	(SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F), //           ; zero
	(SEG_B + SEG_C)                                , //           ; one
	(SEG_A + SEG_B + SEG_D + SEG_E + SEG_G ),        //           ; two
	(SEG_A + SEG_B + SEG_C + SEG_D + SEG_G),         //           ; three
	(SEG_B + SEG_C + SEG_F + SEG_G),                 //           ; four
	(SEG_A + SEG_C + SEG_D + SEG_F + SEG_G),         //           ; five
	(SEG_A + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G), //           ; six
	(SEG_A + SEG_B + SEG_C),                         //           ; seven
	(SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G),//    ; eight
	(SEG_A + SEG_B + SEG_C + SEG_D + SEG_F + SEG_G), //           ; nine
	~(SEG_A + SEG_B + SEG_C + SEG_D + SEG_E + SEG_F + SEG_G),//    ; пусто
	(SEG_A + SEG_F + SEG_E),                         //           ; R
	(SEG_A + SEG_D + SEG_E + SEG_F + SEG_G),                 //     ; E
	( SEG_B + SEG_C + SEG_D + SEG_E + SEG_F),    //           ; U
	(SEG_A + SEG_B + SEG_C + SEG_E + SEG_F + SEG_G) //           ; A
};

volatile unsigned char segcounter = 0;
volatile int display1 = 0, display2 = 0, display3 = 0, display4 = 0;

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

unsigned char Temp_H = 0,Temp_L = 0,OK_Flag = 0,temp_flag;

/*** Инициализация DS18B20 ***/
unsigned char DS18B20_init(void)
{
	PORTC &= ~(1 << PC0); // устанавливаем низкий уровень
	DDRC |= (1 << PC0);
	_delay_us(490);
	DDRC &= ~(1 << 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;
	unsigned char dat = 0;
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		DDRC &= ~(1 << PC0);
		_delay_us(4);
		dat = dat >> 1;
		if(PINC & (1 << PC0))
		{
			dat |= 0x80;
		}
		_delay_us(62);
	}
	return dat;
}

/*** функция записи байта в DS18B20 ***/
void write_18b20(unsigned char dat)
{
	unsigned char i;
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		if(dat & 0x01)
		{
			DDRC &= ~(1 << PC0);
		}
		else
		{
			DDRC |= (1 << PC0);
		}
		dat = dat >> 1;
		_delay_us(62);
		DDRC &= ~(1 << PC0);
		_delay_us(2);
	}
}

/*** Главная функция ***/
int main(void)
{
	DDRA = 0xFF;
	DDRB |= (1 << PB0)|(1 << PB1)|(1 << PB2)|(1 << PB3);
	PORTA = 0x00;
	PORTB = 0x00;

	TIMSK |= (1 << TOIE2); // разрешение прерывания по таймеру2
	TCCR2 |= (1 << CS21);  // предделитель на 8
	
	_delay_ms(50);
	
	unsigned int tempint = 0,tempint1,tempint2,tempint3; // переменные для целого значения температуры
	unsigned int temppoint = 0,temppoint1; // переменные для дробного значения температуры

	sei(); //глобально разрешаем прерывания
	
	while(1)
	{
		if(OK_Flag == 1) // если датчик не ответил
		{
			// ставим прочерки во всех разрядах
			display1 = 11; display2 = 11;
			display3 = 11; display4 = 11;
		}

		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 tmp;
			temp_flag = 0;      // флаг знака равен 0(минус)
			tmp = (Temp_H << 8) | Temp_L;
			tmp = -tmp;
			Temp_L = tmp;
			Temp_H = tmp >> 8;
		}

		tempint = ((Temp_H << 4) & 0x70)|(Temp_L >> 4); // вычисляем целое значение температуры
		tempint1 = tempint % 1000 / 100;
		tempint2 = tempint % 100 / 10;
		tempint3 = tempint % 10;
		temppoint = Temp_L & 0x0F; // вычисляем дробное значение температуры
		temppoint = temppoint * 625;       // точность температуры
		temppoint1 = temppoint / 1000;
		
		if(temp_flag == 0) // если флаг знака температуры равен 0, в первом разряде ставим минус
		tempint1 = 11;

		if(tempint1 < 1) // если первая цифра значения температуры меньше 1, то гасим 1 разряд индикатора
		tempint1 = 12;

		if(tempint1 == 12 && tempint2 < 1) // если первая цифра погашена и вторая цифра значения температуры меньше 1, то гасим 2 разряд индикатора
		tempint2 = 12;

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

		// выводим значения на дисплей
		display1 = tempint1;
		display2 = tempint2;
		display3 = tempint3;
		display4 = temppoint1;
	}
}

Результат протеуса, в качестве картинки:

 

Screenshot_104.jpg

Ссылка на комментарий
Поделиться на другие сайты

Реклама: ООО ТД Промэлектроника, ИНН: 6659197470, Тел: 8 (800) 1000-321

20% скидка на весь каталог электронных компонентов в ТМ Электроникс!

Акция "Лето ближе - цены ниже", успей сделать выгодные покупки!

Плюс весь апрель действует скидка 10% по промокоду APREL24 + 15% кэшбэк и бесплатная доставка!

Перейти на страницу акции

Реклама: ООО ТМ ЭЛЕКТРОНИКС, ИНН: 7806548420, info@tmelectronics.ru, +7(812)4094849

Я вижу в коде один, но серьёзный с моей точки зрения, недостаток: в функциях обмена по 1-wire нет запрета прерываний, в то время как для динамической индикации они необходимы. Это с большой долей вероятности приведет к тому, что задержки, которые должны выдерживаться с высокой точностью для протокола обмена, будут случайным образом искажаться, что сделает обмен невозможным. 

Я делал не один вариант "библиотек" для работы с 1-wire, и могу утверждать с полной уверенностью, что без запрета прерываний на время, пока в начале тайм-слота не отработает процедура опроса линии или необходимой минимальной выдержки низкого уровня в линии, ничего хорошего не получится.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

Выбираем схему BMS для корректной работы литий-железофосфатных (LiFePO4) аккумуляторов

 Обязательным условием долгой и стабильной работы Li-FePO4-аккумуляторов, в том числе и производства EVE Energy, является применение специализированных BMS-микросхем. Литий-железофосфатные АКБ отличаются такими характеристиками, как высокая многократность циклов заряда-разряда, безопасность, возможность быстрой зарядки, устойчивость к буферному режиму работы и приемлемая стоимость. Но для этих АКБ, также как и для других, очень важен контроль процесса заряда и разряда, а специализированных микросхем для этого вида аккумуляторов не так много. Инженеры КОМПЭЛ подготовили список имеющихся микросхем и возможных решений от разных производителей. Подробнее>>

Реклама: АО КОМПЭЛ, ИНН: 7713005406, ОГРН: 1027700032161

1 час назад, ARV сказал:

Я вижу в коде один, но серьёзный с моей точки зрения, недостаток: в функциях обмена по 1-wire нет запрета прерываний, в то время как для динамической индикации они необходимы. Это с большой долей вероятности приведет к тому, что задержки, которые должны выдерживаться с высокой точностью для протокола обмена, будут случайным образом искажаться, что сделает обмен невозможным. 

Я делал не один вариант "библиотек" для работы с 1-wire, и могу утверждать с полной уверенностью, что без запрета прерываний на время, пока в начале тайм-слота не отработает процедура опроса линии или необходимой минимальной выдержки низкого уровня в линии, ничего хорошего не получится.

Добрый день, спасибо за ответ. Если это не будет затруднительно, вы можете в коде указать прерывания? Или где его нужно поставить ? Наверное здесь

		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 час назад, Cegrei Ulanov сказал:

16 МГц.

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

 

Ссылка на комментарий
Поделиться на другие сайты

запрет прерываний

/*** Функция чтения байта из DS18B20 ***/
unsigned char read_18b20(void)
{
	unsigned char i;
	unsigned char dat = 0;
    cli();                                //прерывание откл
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		DDRC &= ~(1 << PC0);
		_delay_us(4);
		dat = dat >> 1;
		if(PINC & (1 << PC0))
		{
			dat |= 0x80;
		}
		_delay_us(62);
	}
      sei();                                  //прерывание вкл
	return dat;
}

/*** функция записи байта в DS18B20 ***/
void write_18b20(unsigned char dat)
{
	unsigned char i;
      cli();                             //прерывание откл
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		if(dat & 0x01)
		{
			DDRC &= ~(1 << PC0);
		}
		else
		{
			DDRC |= (1 << PC0);
		}
		dat = dat >> 1;
		_delay_us(62);
		DDRC &= ~(1 << PC0);
		_delay_us(2);
	}
      sei();                                  //прерывание вкл
}

выстави одинаковую тактовую частоту

1. при компилированиии

2. при программировании

3. в протеусе

Ссылка на комментарий
Поделиться на другие сайты

2 часа назад, skripach сказал:

запрет прерываний

Нет, это ИЗБЫТОЧНО.

Не надо запрещать прерывания на целый цикл передачи 8-и таймслотов. Рекомендую переделать процедуру общения, выделив в отдельные static-функции чтение бита и запись бита, и внутри записи бита или чтения бита запрещать прерывания только на начало таймслота, как я и писал.

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

40 минут назад, ARV сказал:

Нет, это ИЗБЫТОЧНО.

Не надо запрещать прерывания на целый цикл передачи 8-и таймслотов. Рекомендую переделать процедуру общения, выделив в отдельные static-функции чтение бита и запись бита, и внутри записи бита или чтения бита запрещать прерывания только на начало таймслота, как я и писал.

Я всё равно вашу идею не смогу воплотить, я плохо знаю язык C. И даже с прерываниями, при подключения датчика к ножки моментально выдаешь ошибку, о том, что датчик не найден.  

3 часа назад, skripach сказал:

запрет прерываний


/*** Функция чтения байта из DS18B20 ***/
unsigned char read_18b20(void)
{
	unsigned char i;
	unsigned char dat = 0;
    cli();                                //прерывание откл
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		DDRC &= ~(1 << PC0);
		_delay_us(4);
		dat = dat >> 1;
		if(PINC & (1 << PC0))
		{
			dat |= 0x80;
		}
		_delay_us(62);
	}
      sei();                                  //прерывание вкл
	return dat;
}

/*** функция записи байта в DS18B20 ***/
void write_18b20(unsigned char dat)
{
	unsigned char i;
      cli();                             //прерывание откл
	for(i = 0;i < 8;i++)
	{
		DDRC |= (1 << PC0);
		_delay_us(2);
		if(dat & 0x01)
		{
			DDRC &= ~(1 << PC0);
		}
		else
		{
			DDRC |= (1 << PC0);
		}
		dat = dat >> 1;
		_delay_us(62);
		DDRC &= ~(1 << PC0);
		_delay_us(2);
	}
      sei();                                  //прерывание вкл
}

выстави одинаковую тактовую частоту

1. при компилированиии

2. при программировании

3. в протеусе

В протеусе все работает отлично, когда я выставляю частоту 1 МHz, а когда больше, выдает ошибку подключения датчика. А в коде #define F_CPU 1600000. Может из-за этого. Чуть позже проверю.

Screenshot_105.jpg

Изменено пользователем Cegrei Ulanov
Ссылка на комментарий
Поделиться на другие сайты

24 минуты назад, Cegrei Ulanov сказал:

Я всё равно вашу идею не смогу воплотить, я плохо знаю язык C

А чего  тогда вы хотите?

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

1 час назад, ARV сказал:

А чего  тогда вы хотите?

Я хочу чтобы микроконтроллер смог считывать информацию с датчика температуры. Но как вы уже поняли, не получается. Я уже не первую неделю вожусь с этим датчиком. Наверно будет проще поискать другой код в интернете.

Ссылка на комментарий
Поделиться на другие сайты

1 hour ago, Cegrei Ulanov said:

#define F_CPU 1600000.

Это в форуме скопировано с программы или написано? 1.6МГц?

А С придется учить поглубже. На copy - paste вы много не напишете

Настоящему коту и в декабре март!

Ссылка на комментарий
Поделиться на другие сайты

43 минуты назад, Cegrei Ulanov сказал:

Наверно будет проще поискать другой код в интернете

Проще? - возможно. Правильнее? - нет. Правильнее вам следовало бы Си подучить и скорректировать этот код.

Изменено пользователем ARV

Если забанить всех, кто набрался смелости думать независимо, здорово будет на форуме - как на кладбище: тишина, птички поют...

Ссылка на комментарий
Поделиться на другие сайты

56 минут назад, KomSoft сказал:

А С придется учить поглубже. На copy - paste вы много не напишете

Да вы правы, нужно учить. Но лучше всего учить язык во время практики. Лично это я для себя открыл. Код заработал. Спасибо что вы меня поправили в #define F_CPU 1600000. - мне нужно было еще один ноль написать. Но это не точно, я еще прерывания расставил, как мне подсказали выше.  

Ссылка на комментарий
Поделиться на другие сайты

Вообще код немного странный (плохой пример для изучения).
1) почему вы решили что "импульс присутствия" датчика должен попадать только на момент выполнения кода функции DS18B20_init(), а если попадёт на строку _delay_ms(1000), что тогда? Вы импульс пропустите
2) зачем после выполнения функции DS18B20_init() вы выполняете другие функции по работе с датчиком если датчик не ответил. Уберите проверку на обнаружение датчика по "импульсу присутствия". Работайте с датчиком как будто он всегда есть, т.е. наличие датчика определяется по CRC. Если вы всё же хотите использовать "импульс присутствия", то надо использовать прерывания (INT0 например).
3) лучше данный код писать на ассемблере, на Си можно если вы отключите оптимизацию и будете знать, сколько времени выполняется тот или иной участок кода
4) лучший вариант, взять datasheet на DS18B20 и начать по диаграммам писать свой код, конечно анализируя сторонние примеры.
5) код подобный этому "DDRC |= (1 << PC0);"уже говорит о том, что пример не очень хороший. Надо как минимум использовать макросы.

Ссылка на комментарий
Поделиться на другие сайты

4 минуты назад, dm37 сказал:

Вообще код немного странный (плохой пример для изучения).
1) почему вы решили что "импульс присутствия" датчика должен попадать только на момент выполнения кода функции DS18B20_init(), а если попадёт на строку _delay_ms(1000), что тогда? Вы импульс пропустите
2) зачем после выполнения функции DS18B20_init() вы выполняете другие функции по работе с датчиком если датчик не ответил. Уберите проверку на обнаружение датчика по "импульсу присутствия". Работайте с датчиком как будто он всегда есть, т.е. наличие датчика определяется по CRC. Если вы всё же хотите использовать "импульс присутствия", то надо использовать прерывания (INT0 например).
3) лучше данный код писать на ассемблере, на Си можно если вы отключите оптимизацию и будете знать, сколько времени выполняется тот или иной участок кода
4) лучший вариант, взять datasheet на DS18B20 и начать по диаграммам писать свой код, конечно анализируя сторонние примеры.
5) код подобный этому "DDRC |= (1 << PC0);"уже говорит о том, что пример не очень хороший. Надо как минимум использовать макросы.

Спасибо за столь развернутый ответ. Мне этот код понравился из-за простоты, видел и другие примеры с использованием больше кода, а этот такой простой для начинающих) Я вернусь к вашим рекомендациям позже, и попытаюсь код улучшить.   

Ссылка на комментарий
Поделиться на другие сайты

5 минут назад, dm37 сказал:

вот так и рождается плохой код

Я мучался с этим кодом две недели, не так как с кодом, а как с железом. Думал датчик не работает, заказал пару, а он оказался рабочим. И этому результату на самом деле рад, теперь могу продолжать реализовывать задуманное.

Изменено пользователем Cegrei Ulanov
Ссылка на комментарий
Поделиться на другие сайты

уверяю, результат вас разочарует. Потратьте время на вылизывание кода работы с датчиком, без этого ваш проект может не заработать как вы задумывали

Ссылка на комментарий
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.
Примечание: Ваш пост будет проверен модератором, прежде чем станет видимым.

Гость
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Ответить в этой теме...

×   Вставлено с форматированием.   Восстановить форматирование

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

Загрузка...
  • Последние посетители   0 пользователей онлайн

    • Ни одного зарегистрированного пользователя не просматривает данную страницу
×
×
  • Создать...