SHT10 и ATmega8

Обсуждаем контроллеры компании Atmel.
Ответить
Вымогатель припоя
Сообщения: 580
Зарегистрирован: Пт ноя 08, 2013 01:01:18

Сообщение melandr »

Доброй ночи, уважаемые коты! Подскажите с такой проблемой, а то уже мозг сломал себе. Делаю на МК ATmega8 и SHT10 датчик влажности. Нашел на просторах интернета готовый проект работы с датчиком SHT15. Но в библиотеке есть одна трабла. Запуск измерения , ожидание и само чтение данных из датчика SHT10 сделано одной функцией. А так как я использую динамическую индикацию, то задержка в 350 мс совсем не вариант. При разделении функции измерения на две функции, датчик начинает передавать ерунду. Первая - запуск преобразования, потом задержка и вторая функция - чтение данных из SHT10.
Вот исходная функция:
Спойлер

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

int ShtMeasure(unsigned char mode)
{
	unsigned int 	temp = 0xFFFF;
	unsigned char	checksum;
	unsigned char 	c;

	// Signal start of communications
	transstart();

	// Request measurement
	write_byte(mode);

	// Sensor lowers the data line when measurement
	// is complete. Wait up to 2 seconds for this.
	for (c=0; c<20; c++)
	{
		if (! bit_is_set(SHT_PIN, SHT_DATA))
			break;
		DELAY(1000000/10);
	}

	// Read the measurement
	if (! bit_is_set(SHT_PIN, SHT_DATA))
	{
		temp = read_byte();
		temp = temp << 8;
		temp += read_byte();
		checksum = read_byte();
	}

	return temp;
}

а вот я разбил ее на две:
void ShtMeasure(unsigned char mode)
{
	unsigned char 	c;
	// Signal start of communications
	transstart();

	// Request measurement
	write_byte(mode);

	DELAY(350000);

}

int ShtReadData(void)
{
	unsigned int 	temp = 0xFFFF;
	unsigned char	checksum;

	temp = read_byte();
	temp = temp << 8;
	temp += read_byte();
	checksum = read_byte();

	return temp;
}
Заранее благодарен за помощь.
Вложения
sht15_test_m8.rar
Проект AVRStudio и Proteus
(100.37 КБ) 255 скачиваний
Реклама
afz
Опытный кот
Аватара пользователя
Сообщения: 744
Зарегистрирован: Сб дек 22, 2012 08:17:42
Откуда: Караганда, Казахстан

Сообщение afz »

А сделать индикацию в прерываниях, по таймеру? Программа пусть выкладывает считанные из датчика и обработанные результаты куда-то в отдельную область памяти, а в прерывании по таймеру эти данные обновляются на индикаторе.

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

Сообщение uk8amk »

И как вы узнаете что датчик уже готов к общению?

На мой взгляд желательно переписать ShtReadData(void) так, чтобы она возвращала 2 поля: статус датчика(ready, busy, error) и результат.
Когда готов - читаем значение, если занят - занимаемся какими-то иными делами, через некоторое время повторяем вызов ShtReadData. А вот если ошибка - можно начать со сброса датчика.
Плюсом будет то, что никаких лишних delay не требуется.
Друг Кота
Аватара пользователя
Сообщения: 7016
Зарегистрирован: Вс июл 12, 2009 19:15:29
Откуда: Ижевск

Сообщение pyzhman »

Влажность не такой параметр, который требует работы в реальном режиме времени. Считывайте данные раз в десять минут.
Docendo discimus
Контактная информация:
Реклама
Эиком - электронные компоненты и радиодетали
Вымогатель припоя
Сообщения: 580
Зарегистрирован: Пт ноя 08, 2013 01:01:18

Сообщение melandr »

Блин проблема в том, что когда я в одной функции даю команду считать температуру, потом задержку 350 мс и потом читаю два байта данных и один байт контрольной суммы, то данные получаю правильные. А когда я эту функцию разделяю на две. Одна дает команду на измерение температуры, а во второй делаю задержку на 350 мс и потом опрос датчика, такой же как и в первой функции. Данные уже получаю неправильные. Вот и пытаюсь понять, в чем может быть проблема.

Добавлено after 3 hours 15 minutes 6 seconds:
afz писал(а):А сделать индикацию в прерываниях, по таймеру? Программа пусть выкладывает считанные из датчика и обработанные результаты куда-то в отдельную область памяти, а в прерывании по таймеру эти данные обновляются на индикаторе.
Индикация и так сделана в прерываниях. Проблема состоит в том, что я хочу убрать задержку в 350 мс из функции, разбив ее на две функции и вызываю по таймеру
Реклама
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

В первом случае, Вы проверяете бит SHT_DATA и по нему выходите из цикла. Во втором случае, этого нет, а просто стоит задержка.
В остальном, разницы нет между двумя вариантами.
Контактная информация:
Реклама
Вымогатель припоя
Сообщения: 576
Зарегистрирован: Пт май 19, 2006 05:39:11

Сообщение DimAlt »

melandr я использовал этот датчик с динамической индикацией, в этом проекте, есть исходник. Я там опрос разбивал по состояниям
Спойлер

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

	switch(StateSHT10){                     
		case (0):
			//if (--Time1ms==0) StateSHT10=1;
			StateSHT10++;
			break;
		case (21):
			sht_sart();
			error=sht_wr_byte(MEASURE_TEMP); 
			Time1ms=0;
			StateSHT10=22;
			break;
		case (22): 
			if ( (ACTIVE(SDA))==0 ) StateSHT10=23;
			if (++Time1ms==1000) error=0xFF;
			break;
		case (23): 
			TempSht.Byte[1]=sht_rx_byte(1);
			TempSht.Byte[0]=sht_rx_byte(0);//stop connect (no ask)
			StateSHT10=24;
			break;	
		case (24):
			sht_sart();
			error=sht_wr_byte(MEASURE_HUMI); 
			Time1ms=0;
			StateSHT10=25;
			break;
и так далее..
Только вот с контрольной суммой не получилось.. В протеусе работало, в железе crc не совпадает, так и не разобрался.
Контактная информация:
Вымогатель припоя
Сообщения: 580
Зарегистрирован: Пт ноя 08, 2013 01:01:18

Сообщение melandr »

Спасибо, это похожее, что я искал. Правда пока перебил под свой код саму функция измерения, что-то не пошло. Попробую использовать полностью Вашу библиотеку.
Вымогатель припоя
Сообщения: 576
Зарегистрирован: Пт май 19, 2006 05:39:11

Сообщение DimAlt »

Вот в виде библиотеки из другого проекта.
Вложения
sht10.zip
(4.25 КБ) 232 скачивания
Контактная информация:
Вымогатель припоя
Сообщения: 580
Зарегистрирован: Пт ноя 08, 2013 01:01:18

Сообщение melandr »

Что-то не могу понять. У Вас есть переменная extern uint8_t StateSHT10; Вначале ее значение равно 0xFF. При заходе в switch попадаем в секцию default, обнуляем эту переменную. При следующем вызове measure_sht10() заходим в секцию case(0) увеличиваем StateSHT10 на 1. При следующем вызове measure_sht10() опять попадаем в секцию default и обнуляем значение StateSHT10. А в остальные секции switch мы не попадаем. И где-то в функции измерения температуры Вы принудительно присваиваете StateSHT10 = 21, чтобы начать измерение влажности. Непонятно, для чего это присвоение засовывать в какую-то функцию, не относящуюся к измерению влажности. И не подскажете, как правильно и когда нужно сделать присвоение StateSHT10, чтобы запустить измерение?
Для чего тогда
case (0):
//if (--Time1ms==0) StateSHT10=1;
StateSHT10++;
break;
Не подскажете. Для чего мы присваиваем StateSHT10 значение 0xFF. Если потом мы его обнуляем, и присваиваем 1, а дальше опять завтык пока не присвоим значение 21?
Прогнал в протеусе код, функция uint8_t sht_wr_byte(uint8_t Byte) возвращает 1. Вкладываю архив с проектом AVRStudio и проектом Протеуса, может подскажете почему не работает. DimAlt рабочий проект дал и библиотеку. Еще вопрос, почему функция void sht10_init(void) за комментирована? Инициализация не требуется?
ЗЫ: Вот я СТепан, в хидере не изменил порт и пины, на котором сидит датчик :)
ЗЫ2Ж Тут по ходу пьесы возникло пару вопросов. Первый, то что вычисление температуры и влажности происходят с плавающей. По температуре погрешность меньше запятой, насколько это критично для загрузки микроконтроллера. И второй вопрос, в протеусе выставляю влажность 40% , а получаю от датчика преобразованную влажность 41,45% По температуре погрешность меньше устанавливаю на датчике10.0 град.Ц , а с датчика получаю 10,32 град.Ц. Ну и походу при изменении температуры изменяется влажность
Вложения
Humidity_2.rar
(109.93 КБ) 213 скачиваний
Вымогатель припоя
Сообщения: 576
Зарегистрирован: Пт май 19, 2006 05:39:11

Сообщение DimAlt »

Спойлер

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

enum ST_SHT10 {SHT10_START_DELAY,
SHT10_MEAS_T, SHT10_WAIT_T, SHT10_READ_T, 
SHT10_MEAS_H, SHT10_WAIT_H, SHT10_READ_H, 
SHT10_DATA_1, SHT10_DATA_2, SHT10_END_CONV};
#define SHT10_START_CONV	SHT10_MEAS_T

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

//--------------------------------------------------------------
void measure_sht10(void){
static uint16_t Time1ms;
uint8_t error=0;

	switch(StateSHT10){                     
		case (SHT10_START_DELAY):
			if (++Time1ms==TIME_WAIT_ERROR_SHT10*2) 
				StateSHT10=SHT10_MEAS_T;//StateSHT10=SHT10_CMD_STATUS_R;//
			DRIVER(SCK,OUT);//инициализация на выход, что бы все ножки настраивались внутри модуля без выноса в основную прогу
			break;
		case (SHT10_MEAS_T):
			error=sht_sart();
			error=sht_wr_byte(MEASURE_TEMP); 
			Time1ms=0;
			StateSHT10=SHT10_WAIT_T;
			break;
		case (SHT10_WAIT_T): 
			if ( (ACTIVE(SDA))==0 ) StateSHT10=SHT10_READ_T;
			if (++Time1ms==TIME_WAIT_ERROR_SHT10) error=0xFF;
			break;
		case (SHT10_READ_T): 
			TempSht.Byte[1]=sht_rx_byte(1);//msb
			TempSht.Byte[0]=sht_rx_byte(0);//lsb 0 stop connect (no ask)
			StateSHT10=SHT10_MEAS_H;
			break;				
		case (SHT10_MEAS_H):
			error=sht_sart();
			error=sht_wr_byte(MEASURE_HUMI); 
			Time1ms=0;
			StateSHT10=SHT10_WAIT_H;
			break;
		case (SHT10_WAIT_H): 
			if ( (ACTIVE(SDA))==0 ) StateSHT10=SHT10_READ_H;
			if (++Time1ms==TIME_WAIT_ERROR_SHT10) error=0xFF;
			break;
		case (SHT10_READ_H): 
			HumiSht.Byte[1]=sht_rx_byte(1);//msb
			HumiSht.Byte[0]=sht_rx_byte(0);//lsb 0 stop connect (no ask)	
			StateSHT10=SHT10_DATA_1;	
			break;
		case (SHT10_DATA_1): 
			TempSht.f=(float)TempSht.i;
			HumiSht.f=(float)HumiSht.i;
			StateSHT10=SHT10_DATA_2;
			break;

		case (SHT10_DATA_2): 
			calc_sth11(&HumiSht.f,&TempSht.f);
			XhtHumi=(int)(HumiSht.f);
			XhtTemper=(int)((TempSht.f)*10);
			if ( (XhtHumi!=0) || (XhtTemper!=0) )
				Flag_Xht=XHT_OK;
				else
				error=1;
			StateSHT10=SHT10_END_CONV;
			break;
		case (SHT10_END_CONV): 
			//StateSHT10=1;
			//return 1;
			break;
		
		default : 
			s_softreset();
			StateSHT10=SHT10_START_DELAY;
			Time1ms=0;
			break;	 
		}
	if (error){
		StateSHT10=0xFF;
		Flag_Xht=XHT_ERROR;
		//return 0xFF;
		}
	
	//return 0;
}
Сначала попадаем в состояние SHT10_START_DELAY, делал для того чтобы после ошибки датчика не сразу его опрашивать, а через какое то время. У меня функция measure_sht10 вызывается раз в 1мС. Старт после ошибки через время (++Time1ms==TIME_WAIT_ERROR_SHT10*2).

Как работает у меня.
В коде есть это:
#define SHT10_START_CONV SHT10_MEAS_T
Старт преобразования выполняется в основном коде программы
StateSHT10=SHT10_START_CONV
Затем можно ждать окончание преобразования StateSHT10==SHT10_END_CONV (можно не дождаться, нужно мониторить XHT_ERROR).
У меня, в рабочем проекте, это состояние опрашивается через 1сек после StateSHT10=SHT10_START_CONV, поэтому я не смотрю это условие, а проверяю if (Flag_Xht==XHT_OK){действия}
Затем запускаем по новому. Что бы крутилось автоматом, то можно сделать так:

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

case (SHT10_END_CONV): 
			StateSHT10=SHT10_START_CONV;
			break;
Непонятно, для чего это присвоение засовывать в какую-то функцию, не относящуюся к измерению влажности.
У меня, для синхронизации задач в главном цикле программы. Старт измерения влажности во время простоя при опросе других датчиков.
Тут по ходу пьесы возникло пару вопросов. Первый, то что вычисление температуры и влажности происходят с плавающей. По температуре погрешность меньше запятой, насколько это критично для загрузки микроконтроллера.
Вычисления вынесены в отдельное состояние, занимают относительно мало времени.
И второй вопрос, в протеусе выставляю влажность 40% , а получаю от датчика преобразованную влажность 41,45% По температуре погрешность меньше устанавливаю на датчике10.0 град.Ц , а с датчика получаю 10,32 град.Ц. Ну и походу при изменении температуры изменяется влажность
У меня было также, не знаю почему. Код функции вычисления данных от производителя.
Контактная информация:
Вымогатель припоя
Сообщения: 580
Зарегистрирован: Пт ноя 08, 2013 01:01:18

Сообщение melandr »

DimAlt спасибо. Запустил датчик влажности, все нормально работает.
Ответить

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