Некорректный ответ от SHT21

Обсуждаем контроллеры компании Atmel.
Ответить
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

Всем доброго здоровья.
Столкнулся с проблемой и не вижу где же я ошибся. Прошу помочь подсказать кто может:)
Суть в следующем, есть МК Атемега32(по сути не важно какая) и датчик влажности/температуры SHT21. Пытаюсь подружить их по шине I2C. проверяю аботу в протеусе 8 версии. и вот тут получаю ошибки в чтении с датчика.
Ниже участок кода для работы с I2C
Спойлер

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


//Функция СТАРТ TWI (I2C)
void I2C_StartCondition(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
	while(!(TWCR&(1<<TWINT)));//подождем пока установится TWIN
}
//-----------------------------------------------------

//Функция СТОП TWI (I2C)
void I2C_StopCondition(void)
{
	TWCR = (1<<TWINT)|(1<<TWSTO)|(1<<TWEN);
}
//-----------------------------------------------------

//Функция для передачи байта в шину TWI (I2C)
void I2C_SendByte(unsigned char c)
{
	TWDR = c;//запишем байт в регистр данных
	TWCR = (1<<TWINT)|(1<<TWEN);//включим передачу байта
	while (!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
}
//----------------------------------------------------

//Функция чтения с шины TWI (I2C)
unsigned char I2C_Read(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);//включим прием данных
	while(!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
	return TWDR;
}
//------------------------------------------------------


//Функция чтения с шины TWI (I2C) ПОСЛЕДНЕГО БАЙТА
unsigned char I2C_ReadLastByte(void)
{
	TWCR = (1<<TWINT)|(1<<TWEN);//включим прием данных
	while(!(TWCR&(1<<TWINT)));//подождем пока установится TWIN
	return TWDR;
}
//--------------------------------------------------------


//*********************************************************
//Основной код
int main(void)
{
    port_ini(); //Инициализируем порты
	
	I2C_Init(); //Инициализируем шину TWI (I2C)
		
	
	while (1) 
    {
				
		I2C_StartCondition(); //Отправим условие START
		I2C_SendByte(0b10000000); //Кидаем на линию адрес устройства
		I2C_SendByte(0b11100101); //выбор измерения RH в нормальном режиме
		//_delay_ms(1000);
		I2C_StartCondition();
		I2C_SendByte(0b10000001); //чтение  с датчика
		I2C_Read() ;
		I2C_ReadLastByte();
		I2C_StopCondition(); //Отправим условие STOP
		//data = data1+data2;
	}
}
Запускаю в протеусе и смотрю в I2C дебаггер, от него получаю такую картину:
см вложение.

Как видно из скрина, то ответы от датчика идут через один.
ответ 95 и 12 - корректный
следом за этим идут данные 12 и 12 - и это уже бред. и так по кругу.
Где то есть ошибка, вопрос где? прошу помочь

Добавлено after 2 hours 27 minutes 7 seconds:
Опытным путем, пришел к выводу что проблема где то тут
Спойлер

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

//Функция чтения с шины TWI (I2C)
unsigned char I2C_Read(void)
{
   TWCR = (1<<TWINT)|(1<<TWEN)|(1<<TWEA);//включим прием данных
   while(!(TWCR & (1<<TWINT)));//подождем пока установится TWIN
   return TWDR;
}
//_______
Вложения
Безымянный.jpg
(124.53 КБ) 291 скачивание
Я все еще учусь, и ох как тяжело это дается
Реклама
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

Ну а если задержку на 1 с раскомментировать - работает как надо?
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

Попробуйте так

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

//Функция чтения с шины TWI (I2C) ПОСЛЕДНЕГО БАЙТА
unsigned char I2C_ReadLastByte(void)
{
   TWCR &= (~(1<<(TWEA)));
   TWCR |= (1<<TWINT)|(1<<TWEN);//включим прием данных
   while(!(TWCR&(1<<TWINT)));//подождем пока установится TWIN
   return TWDR;
}
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

[uquote="NStorm",url="/forum/viewtopic.php?p=3728898#p3728898"]Ну а если задержку на 1 с раскомментировать - работает как надо?[/uquote]
Нет, в протеусе она ни на что не влияет. в железе 100 оставлю.

Добавлено after 38 seconds:
[uquote="Dimon456",url="/forum/viewtopic.php?p=3728933#p3728933"]Попробуйте так

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

//Функция чтения с шины TWI (I2C) ПОСЛЕДНЕГО БАЙТА
unsigned char I2C_ReadLastByte(void)
{
   TWCR &= (~(1<<(TWEA)));
   TWCR |= (1<<TWINT)|(1<<TWEN);//включим прием данных
   while(!(TWCR&(1<<TWINT)));//подождем пока установится TWIN
   return TWDR;
}
[/uquote]
Попробовал. Результата нет

Мне почему то кажется что проблема в unsigned char I2C_Read(void), так как если его закоментировать, то в дебагере отображается получение первыйх восьми бит, и все корректно.
Если же закоментировать unsigned char I2C_ReadLastByte(void, то так же пишутся первые 8 бит, но каждый второй запрос с некорректным ответом

Во втором запросе, второй байт почему то попадает на первое место.
Я все еще учусь, и ох как тяжело это дается
Реклама
Эиком - электронные компоненты и радиодетали
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

А что у вас в I2C_Init(); ?

Добавлено after 26 minutes 57 seconds:
Проблема в Hold Master. Уж не знаю реализован ли в меге clock stretching, читать ДШ некогда уже. Но если будете без hold master отправлять запрос на измерение (I2C_SendByte(0b11110101);), то всё заработает.
А может это и глюк протеуса, т.к. проверял тоже в нём.

Добавлено after 8 minutes 8 seconds:
В ДШ написано, что в no hold master, сенсор должен прислать NACK в ответ на чтение, если данные не готовы. А в протеусе в этом режиме первая передача возвращает ACK, но данные с 0. Модель короче в протеусе походу кривая. Зато дальше так начинает работать. Проверяйте лучше в железе.
Реклама
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

NStorm, в I2C_Init(); у меня следующее:
Спойлер

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

void I2C_Init(void)
{
	TWBR=0x2; //скорость передачи (при 8 мГц получается 100 кГц)
}
//--------------------------------


Сделал, как вы посоветовали, без hold master, и все заработало корректно. проверю позже еще в железе, с hold master, а пока пусть так. Спасибо огромное!

Добавлено after 4 hours 55 minutes 54 seconds:
Так появился новый вопрос по этой же теме.
после того как получили данные от датчика температуры и склеили два байта для получения 16 битного значения, (sht21 отдает значение температуры в 14 битном значении). Согласно даташита нужно произвести вычисления по формуле temp=1*((data*175.72/65536)-46.85)
И вот тут моих знаний не хватает.
Спойлер

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

                I2C_StartCondition();
		I2C_SendByte(0b10000001); //чтение температуры с датчика
		data1=I2C_Read();
		data2=I2C_ReadLastByte();
		I2C_StopCondition(); //Отправим условие STOP
		
		unsigned int data=(data1 << 8) | data2;
		unsigned int temp=1*((data*175.72/65536)-46.85);
							
		sprintf (buffer, "%d", temp); 
		setpos(0,0);
		str_lcd (buffer); //Функция str_lcd выводит содержимое на экран по позиции setpos
При такой записи, на экран выводится только целое значение температуры, без дробей. Логично предположить что нужно изменить тип переменной "temp",на float но в этом случае на экран выводится вообще что попало.
Решения пока не нашел (.
Я все еще учусь, и ох как тяжело это дается
Реклама
Мудрый кот
Сообщения: 1849
Зарегистрирован: Вс дек 25, 2016 08:34:54

Сообщение Dimon456 »

densir писал(а):При такой записи, на экран выводится только целое значение температуры, без дробей. Логично предположить что нужно изменить тип переменной "temp",на float но в этом случае на экран выводится вообще что попало.
Тут надо sprintf сказать что бы float выводил, что увеличит размер кода и sprintf (buffer, "%f", temp);.
Гораздо проще сделать

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

	float temp=1*((data*175.72/65536)-46.85);	
	int integer = (int)temp;
	int fractional = (int)(temp*100)%100;// 100 - 2 знака после запятой
	sprintf (buffer, "%1d.%02d", integer, fractional);
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

Dimon456,
Огромное спасибо. Помогло. Добавил еще одну строку

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

fractional=fabs(fractional);
Без нее при отрицательных значених температуры получалась запись типа "-13,-10" вместо "-13,10". Сейчас все отлично! огромное спасибо!
Я все еще учусь, и ох как тяжело это дается
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

Дабы не плодить темы спрошу здесь, все равно эти вопросы по тому же устройству :)

В устройстве имеется многоуровневое меню, с подменю в пунктах. управление будет осуществляться китайским энкодером с кнопкой. Защита от дребезга контактов - программная(имеется счетчик, значение которого инкрементиуются/декрементируется и при достижении некого значения считается что кнопка нажата). так вот при нажатии кнопки возникает такая ситуация, что МК отрабатывает нажатие, переходит в подменю и видя что кнопка все еще нажата проваливается глубже. можно конечно увеличить значение счетчика при котором кнопка дожна срабатывать, но будет складываться впечатление что система тормозит. как можно обойти это? пока в голову ничего не приходит.
Я все еще учусь, и ох как тяжело это дается
Поставщик валерьянки для Кота
Сообщения: 2222
Зарегистрирован: Вт ноя 27, 2007 11:32:06
Откуда: Tashkent

Сообщение uk8amk »

densir писал(а):как можно обойти это?
Фиксируйте в программе момент перехода от ненажатого к нажатому состоянию кнопки. К примеру смену уровня H->L после прохождения программной фильтрации. Таким образом вы не будете зависеть от каких-либо задержек кроме минимальной задержки подавления дребезга контактов(20-50мс).
Поставщик валерьянки для Кота
Сообщения: 1978
Зарегистрирован: Ср июл 17, 2013 13:55:57

Сообщение NStorm »

densir, ждите "отжатия" кнопки и только потом снова начинайте фиксировать нажатие, с учетом антидребезга аналогично.
Нашел транзистор. Понюхал.
Сообщения: 185
Зарегистрирован: Ср фев 03, 2010 20:12:15
Откуда: Барнаул

Сообщение densir »

NStorm,
Как же я сам не сообразил!?
Все гениальное просто. Дописал. Спасибо в очередной раз
Я все еще учусь, и ох как тяжело это дается
Ответить

Вернуться в «AVR»