Еще раз о STM32 и DS18B20 (подправлено)

Решил подцепить DS18B20 к STM32 по двухпроводной шине. Задача несложная, благо и 1-wire уже не раз ковырял (первый раз лет 15 назад, еще на PIC, цеплял и ключи-идентификаторы и термометр), да и на STM32 тема сейчас избитая, примеров навалом. Прицепил термометр к известной плате STM32 Mini, и, хоть и не люблю копипастить, но все же взял готовую библиотеку от steel_ne из его статьи «Stm32 + 1-wire + DMA» и ее продолжения — мне понравилось это решение. Подправил чуть-чуть на свободный у меня USART3 и, после устранения ВСЕХ моих ошибок )), все заработало, за что автору большое спасибо.
К чему это я? А вот — главной моей ошибкой было то, что цеплял я термометр по двухпроводной схеме. И температура не измерялась, +85 градусов, хоть удавись… У меня термометры уже работают по двухпроводной схеме на AT91SAM7SE512 и раньше на PIC16F84 работали, поэтому вопрос для меня о схеме подключения особо не стоял, в даташиты я на эту тему давно не смотрел и схему автора вышеупомянутой статьи тоже глянул одним глазом. Посмотрел повнимательнее на схему в статье, а там термометр подключен по трем проводам. Подключил и я питание – работает. Проверил на Атмеле – но там несколько тех же DS18B20 на двух проводах стоят и подцеплены резистором 4,7 К к питанию, но правда там к 5 В. Ага, понятно, надо разбираться, ведь работает же оно на 5 вольтах… Вот тут-то и пригодилось свойство альтернативности выводов в STM32.

Полез осциллографом туда и сюда, вижу — разница налицо. На 5-вольтовой шине во время измерения есть просад напряжения шины, но небольшой, где-то до 4,5 В, не менее, измерения идут нормально:

А на шине 3,3 В во время измерения, после выдачи команды Convert T ( 0х44) напряжение на шине просаживается до 1,6 — 1,7 Вольта, видимо на меньших напряжениях ток потребляемый побольше, напряжение на шине становится недостаточным и ничего уже не измеряется, читаются показания +85 С:

Собственно, для вас это наверняка не откровенность, посмотрел по форумам – вопрос с подключением обсосан не раз. Решения предлагается два – включить по трехпроводной схеме, с питанием, или по двухпроводной схеме, подключая питание к шине на время измерения с помощью ключа. Вот предложенная в даташитах схема:
Также ставят полевые транзисторы еще и на выход порта.Например как это описано здeсь на форуме:

А ведь токи на 1-wire маленькие, тут любой выход потянет.
Вот тут-то и есть мой ответ на вопрос, зачем написал все это. Проблема подключения термометров по двухпроводной схеме, а для меня это очень актуально, ибо я подключаю их несколько (да и не только их, поэтому хотелось бы тянуть двух, а не трехпроводную линию), решается очень просто. Достаточно:
1. Убрать диод из цепи передатчика UART, а для этого нужно выход передатчика программировать как альтернативный open-drain.
(кстати — здесь и далее на некоторых рисунках перепутаны ножки 1 и 3, по даташиту 1 = GND, 3 = Vdd)

2. На время измерения переводить этот пин в режим GPIO push-pull c подачей на него высокого уровня.
Вот что увидим:

В кодах это не очень напряжно, просто добавить несколько строк — например в вышеупомянутые коды (если автор не против):
В библиотечном файле onewire.c изменить строки инициализации ножек передатчика USARTов c:
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
на
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;

Ну и, соответственно, можно добавить несколько строк для переназначения ножки на время измерения, куда хотите, можно например в вышеупомянутую библиотеку (если автор опять же не против), что-то типа того (не пинайте — я по образованию старый железячник) — в файл onewire.h:
void OW_out_set_as_Power_pin(void);
void OW_out_set_as_TX_pin(void);
И в onewire.c (не забывая установить на выходе единицу для подачи питания на шину!)
void OW_out_set_as_TX_pin(void){
        GPIO_InitTypeDef GPIO_InitStruct;  
	if (OW_USART == USART1) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
		// USART TX
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStruct);
	}
	if (OW_USART == USART2) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

		GPIO_Init(GPIOA, &GPIO_InitStruct);
	}        
	if (OW_USART == USART3) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStruct);
	}  
}

void OW_out_set_as_Power_pin(void){
        GPIO_InitTypeDef GPIO_InitStruct;  
	if (OW_USART == USART1) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
		// GPIO
                GPIO_SetBits(GPIOA, GPIO_Pin_9);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStruct);                
	}
	if (OW_USART == USART2) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);
                GPIO_SetBits(GPIOA , GPIO_Pin_2);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOA, &GPIO_InitStruct);
	}        
	if (OW_USART == USART3) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB | RCC_APB2Periph_AFIO, ENABLE);
		GPIO_SetBits(GPIOB , GPIO_Pin_10);
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_Init(GPIOB, &GPIO_InitStruct);
	}  
}

В рабочем коде надо просто после подачи команды на измерение добавить назначение выхода, как питающего шину, а по истечении времени измерения вернуть выход в исходное состояние – как передатчик UART:

    OW_Init();
    OW_Send(OW_SEND_RESET, "\xcc\x44", 2, NULL, NULL, OW_NO_READ);
    
    // назначаем функцию двухтактного выхода - подаем "питание" на шину
    OW_out_set_as_Power_pin();
    
    // выдерживаем время измерения (например 750 мс для 12-битного измерения)
    for (i=0; i<1000000; i++);

    // восстанавливаем функцию передатчика UART
    OW_out_set_as_TX_pin();

    uint8_t buf[2];
    OW_Send(OW_SEND_RESET, "\xcc\xbe\xff\xff", 4, buf,2, 2);

Вот и все, надеюсь, сильно не запинают. Хотя за что — просто поделился своим опытом, авось кому-нить и пригодится. (Табличку из моего первого опыта с публикацией, хоть и потоптали, но всеж кто-то скачал, а значит не зря публиковал.) Особо не претендую ни на что, возможно это давно решено таким же способом — я глубоко не копал, просто посмотрел немножко на форумах, в том числе и здесь, не нашел. Кстати, это решение достаточно универсально и, если не использовать UART, а только GPIO, формируя сигналы интерфейса 1-wire программно, все можно сделать на одном выводе. Как — достаточно понятно, думаю — назначая вывод то входом, то выходом с открытым стоком, то двухтактным выходом. Такой подход может и еще где-нибудь пригодиться, если пользоваться «дерущейся за выводы» периферией не одновременно, а последовательно.
Еще раз спасибо steel_ne.
PS немножко подправил по тексту, вчера спать хотелось, пару строк пропустил.

PPS. Сегодня наконец опять добрался до термометров. Не буду рассусоливать, естественно наш коллега Gaaaaaad был абсолютно точен и прав, хватит копипастить избыточное решение с использованием двух ножек процессора для нашего случая.
Можно просто объявить полудуплексный режим для USART и для работы с 1-Wire вполне хватит одного вывода USART_TX, работающего в режиме Alternate_Open_Drain во время приема-передачи и в режиме GPIO_Out_Push_Pull во время проведения измерения или перезаписи. Таким образом схема становится минимальной и для связи с устройствами 1-wire используются всего два провода, к чему и стремились:


Итожим все написанное:
В библиотеке из вышеупомянутой статьи steel_ne нужно лишь немножко подправить код в OW_Init(), вот так:

1. Изменить строки инициализации ножек передатчика USARTов c:
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_PP;
на
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;

2. Везде убрать инициализацию USART_RX:

 		// USART RX
//		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;
//		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
//		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

//		GPIO_Init(GPIOA, &GPIO_InitStruct);

3. В конце, перед выходом из OW_Init(), добавить одну-единственную строку:

	USART_Init(OW_USART, &USART_InitStructure);
	USART_Cmd(OW_USART, ENABLE);
        
        // Здесь вставим разрешение работы USART в полудуплексном режиме 
        USART_HalfDuplexCmd(OW_USART, ENABLE);
	
        return OW_OK;

Необходимо также добавить в библиотеку вышеописанные функции OW_out_set_as_TX_pin() и OW_out_set_as_Power_pin().

Будем пользоваться библиотекой также, как и приводилось выше. Вот рабочий пример для измерения температуры тремя термометрами DS18B20, проверен на STM32 Mini. Здесь используются заранее определенные ID термометров, соответственно {0x28, 0xF8, 0xFB, 0xE1, 0x01, 0x00, 0x00, 0x76}, {0x28, 0x3C, 0xED, 0xDF, 0x01, 0x00, 0x00, 0x88} и {0x28, 0xCA, 0xED, 0xE1, 0x01, 0x00, 0x00, 0x15}:

    OW_Init();
    // Заставляем ВСЕ термометры одновременно провести измерение температуры	
    OW_Send(OW_SEND_RESET, "\xcc\x44", 2, NULL, NULL, OW_NO_READ);
    
    // назначаем функцию двухтактного выхода - подаем "питание" на шину
    OW_out_set_as_Power_pin();
    
    // выдерживаем время измерения (например 750 мс для 12-битного измерения)
    for (i=0; i<1000000; i++);

    // восстанавливаем функцию передатчика UART
    OW_out_set_as_TX_pin();

    uint8_t buf[2];

    // читаем показания первого термометра	
    OW_Send(OW_SEND_RESET, "\x55\28\xF8\xFB\xE1\x01\x00\x00\x76\xbe\xff\xff", 12, buf, 2, 10);

    // используем их по Вашему разумению, например выводим на экран
    Out_buf_as_Temperature_on_TFT (buf, xy_1);

    // второго термометра	
    OW_Send(OW_SEND_RESET, "\x55\x28\x3C\xED\xDF\x01\x00\x00\x88\xbe\xff\xff", 12, buf, 2, 10);
    Out_buf_as_Temperature_on_TFT (buf, xy_2);

    //и третьего термометра	
    OW_Send(OW_SEND_RESET, "\x55\x28\xCA\xED\xE1\x01\x00\x00\x15\xbe\xff\xff", 12, buf, 2, 10);
    Out_buf_as_Temperature_on_TFT (buf, xy_3);


Еще раз спасибо steel_ne и Gaaaaaad. Библиотеку я не прилагаю, если steel_ne захочет – можно внести соответствующие коррективы в приложении к его статье, я буду только рад.
  • +5
  • 25 октября 2013, 02:44
  • dadigor

Комментарии (100)

RSS свернуть / развернуть
Спасибо за ваш опыт, а я целый транзистор для этого ставил, хотя знал, что без него можно обойтись, но че то думать тогда не хотелось)
0
Да не за что… Мне как раз вчера транзистор ставить не захотелось, вот и подумал. Токи на 1-wire пустяшные, чего там нужно, пара-тройка миллиампер в пиковый момент, да и то навряд ли.
0
гм… интересно сколько еще раз будут «копипастить» железячное соединение двух выводов TX+RX, вместо использования на одном выводе…

RM0008 Doc ID 13902 Rev 14 стр 779
27.3.10 Single-wire half-duplex communication

Если что — я и комент писал год назад к той статье (железа не было), и железячно проверил и на форуме другой человек работоспособность подтверждал… А так да — вредничаю :)
0
Вообще-то идея не в том, что просто объединить выводы для образования полудуплекса, это достаточно очевидно и это только первый пункт на пути к решению поставленной задачи — без него в показанной схеме было никак не обойтись. Идея в том, чтобы переключать режим выхода — в пушпул GPIO для питания DS18B20 на время преобразования — и в альтернативный режим открытый сток USART в остальное время, пользуясь замечательной возможностью процессора на ходу менять режим из альтернативного в основной и обратно, при этом третий провод (питание для DS18B20) становится абсолютно лишним.

Жаль, что это не понятно из статьи, значит очень плохо я написал. В даташите RM0008 в указанном месте об этом ни слова. О проблемах питания DS18B20 во время измерения писалось много, но такого решения я не видел даже в комментах. Конечно я все статьи не проверял и оно возможно давно описано где-нить, думаю, почти наверняка, оно тоже достаточно очевидно. Я честно написал об этом в конце статьи. Мне понадобилось решение, быстро не нашел, как подумалось, так и сделал, да и проверил. Ну и написал, чтоб в другим в комментах не искать, благо проблема достаточно наболевшая.

Если это все же копипаст, я могу удалить статью, хоть и времени потраченного на писанину конечно жаль. Напишите. Кстати, дайте ссылку на коммент, где говорится, как обойтись без подачи питания на DS18B20 (обычно или ставят дополнительный ключ на шину и еще один порт или цепляют третью ножку термометра на питание) в случае подтяжки шины 1-wire резистором 4,7 КОм к источнику +3,3 В, мне так и не попалось.
0
копипастом названо использование соединения — как плохое решение при использовании STM32, а не переключение режимов…

Если Вы не поняли, значит очень плохо я написал.
0
Просто статья как бы не совсем об этом была, я на полудуплексный режим и не отвлекался,… поэтому я чего-то заволновался )) Кстати счас попробую доделать на полудуплекс, хотя скорее всего окончательно буду делать просто на одном GPIO и прерываниях.
В общем, если чего не так я — мой реверанс.
0
я так и понял, без обид. Я ничуть не имел в виду что статью надо удалять.

Для очистки своей совести полез проверил — в режиме Single-wire half-duplex communication — у меня вывод для нормальной работы с 1wire изначально был настроен в GPIO_Mode_AF_OD

=====
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO,
				ENABLE);

		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

		GPIO_Init(GPIOA, &GPIO_InitStruct);

	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl =
			USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

	USART_Init(OW_USART, &USART_InitStructure);
	USART_Cmd(OW_USART, ENABLE);
	USART_HalfDuplexCmd(OW_USART, ENABLE);



ссылка на форум forum.easyelectronics.ru/viewtopic.php?p=248557#p248557
еще раз подчеркну мои комментарии никогда не стоит воспринимать как предложение удалять статью… == любая статья это большой труд и я его всегда ценю… а комментарии это только повод пинка мысли, иногда даже не в верном направлении…
0
Ага, без них, и на меня тоже. Я просто сгоряча не совсем въехал в Ваш коммент, но сразу ушел в защиту…

Кстати, все же с полудуплексом мне казалось все понятным, а сейчас стал разбираться поплотнее и мне стало не совсем ясно по поводу чтения бита. Ведь на чтение одного бита 1-wire тратится одна 8-битная посылка USART. То есть передатчик гонит 8 бит 0xFF (по сути только START — как запускающий импульс 1-wire), а в это же время приемник должен принимать реакцию шины. Он не блокируется на время передачи? Лет 7 назад, на Атмеловских SAM7SE я работал в полудуплексе для организации RS-485, там приемник в этом случае (но опять же по памяти, вроде бы, давно было...) блокировался — от эхо-сигнала. А у STM как? Поискал немножко на их форумах, похоже народ наоборот, жалуется на наличие эха, что есть гут для нашего случая. Проверить сегодня уже не смогу, упадаю...))
0
для меня программирующего железо «раз в год по обещанию, и то если вспомню» == эхо как раз было плюсом тк содержало и отправленное мной и принятое от слейва.
И это как раз ИХМО правильное решение, тк все функции приемника и передатчика независимы друг от друга:
по сути приемник это просто высокоомный вход никак не влияющий на ногу, а передатчик может быть организован любым способом как пп, од и тд…
плюсом является то что они синхронны по общим настройкам UART — скорость четность и тд.
0
Спасибо! Сегодня ночью дошли руки, попробовал работать только с ножкой TX, все замечательно работает, что и следовало ожидать. Так что я ступил в комментах, надо было сразу это сделать, а я сгоряча «ушел в оборону». Вы были абсолютно правы, надо пресечь «копипаст» железячного соединения двух выводов TX+RX при использовании USART для работы с 1-wire.
Завтра (или послезавтра, как получится) поправлю статью.
0
Кому надо, записал лог общения с DS18B20

yadi.sk/d/OZmTF_cXGQ358
0
0
Приобрел плату stm32vldiscovery с контроллером STM32F100RBT6B. Попробовал подключить описываемым способом ds18b20, не получается. До осциллографа пока не добрался. Стал смотреть документацию, и нашел в Errata sheet пункт «2.7.8 USARTx_TX pin usage limitation». Повлияет это как-тона работу по шине 1-wire?
0
Вроде бы не должно влиять. А что не получается? В чем отлаживаете? Где затык?
0
Уважаемые dadigor, Gaaaaaad и steel_ne! Хочу сделать замечание по поводу резистора 4,7К в цепи питания датчика. В даташите на датчик сказано, что во время преобразования потребляемый ток составляет порядка 1мА, что и определяет номинал резистора при питании от 5В. Соответственно, при питании STM32 от 3,3В номинал резистора должен быть другим. У меня с резистором 3,3К преобразование идёт без проблем.
0
Вы конечно правы, снижение номинала резистора спасает ситуацию, я тоже это делал — и с тем же результатом. С точки зрения перегрузки устройства при снижении номинала резистора — в ситуации, когда устройство отвечает нулевым потенциалом (отправка сигнала Present или логический ноль в отдаваемых данных) — при номинале 3,3 к и питании от 3,3 В выходной ток не превышает его значение при номинале 4,7 к и питании от 5 В. Я правда не испытывал вариант с несколькими устройствами на шине, да еще и одновременно выполняющими преобразование. Может быть Вы проверите такой вариант? Это интересно. Будет ли это работать во всех случаях — на мой взгляд это вполне возможно.

Но такое решение, к сожалению, не соответствует рекомендациям производителя, который не предложил такой вариант, во всяком случае я его не видел. А подключение шины при помощи ключа к питанию на время преобразования вполне соответствует рекомендациям, да и на мой взгляд, ключ, позволяющий увеличить ток на шине, возможно улучшает питание устройств, одновременно выполняющих преобразование (после подачи команды SKIP ROM, затем CONVERT T), а также одновременно обеспечивает дозарядку/неразрядку питающих емкостей в остальных устройствах на шине, особенно когда их достаточно много (в моем варианте 15-40 устройств, из них термометров 3-7). А крошечное дополнение программного кода для меня не существенно. ))

Кстати, я не без греха, нарушаю рекомендации производителя на одном из термометров — при измерении температуры в парной, когда там температура 110 градусов: «The use of parasite power is not recommended for temperatures above +100°C since the DS18B20 may not be able to sustain communications due to the higher leakage currents that can exist at these temperatures. For applications in which such temperatures are likely, it is strongly recommended that the DS18B20 be powered by an external power supply». Пока он работает по двум проводам. ))
0
Уважаемый dadigor, я просто исходил из одной-единственной рекомендации: обеспечить рекомендованный даташитом ток на время преобразования. А величина этого тока, ограниченная резистором, и будет примерно одинакова что через 3,3К при 3,3В, что через 4,7К при 5В. И при преобразовании, и при отправке нуля или сигнала Presence через открытый ключ. Так что, я думаю, опасения здесь напрасны. Тем более, что производитель сам предложил двухпроводную схему включения.
А несколько датчиков на линии я обязательно проверю, мне и самому это надо. Только сначала выйду из ступора — второй день тупо смотрю в код и не могу понять, где собака зарыта. ))) Вроде всё нормально, USART2 в режиме half-duplex прилежно шлёт для чтения байты 0xFF, датчик стабильно отвечает байтами 0xFC, но приёмник ни за что не хочет их принимать! В симуляторе при ручном вводе всё работает как надо. Мистика! )))
0
Верно, но не совсем… Внимательно просмотрите осциллограммы, приведенные в статье. Во время ответа устройства это действительно верно, а вот во время преобразования напряжение на шине не просаживается до нуля, а ДОЛЖНО оставаться и остается на приличном уровне, кстати можете посмотреть на каком в разных вариантах, если есть осциллограф/ Я для всех случаев просто не помню, а под рукой работающей системы нет. Причем при питании от 5 В это будет одно падение напряжения, а при питании от 3,3 В другое. На резисторе 4,7К при питании от 3,3 В этот просад может стать критичным, на резисторе 3,3К ситуация несколько улучшается, но когда ставишь несколько термометров и заставляешь их делать преобразование ОДНОВРЕМЕННО, помогает уже только резистор 1К. Просад напряжения на шине может стать ниже некоего критического, когда устройства вообще перестанут преобразовывать температуру. Поэтому ключ кардинально решает проблему.
Кстати, опять же насколько я помню, мощность потребления (U*I) во время преобразования даже чуть возрастает при понижении питающего напряжения ниже какого-то уровня.
Впрочем хорошо бы, если Вы повторили мои эксперименты для разных вариантов питания, я их проводил года три назад и не протоколировал.
Datasheet описывает ток потребления во время преобразования равным 1-1,5 мА при питании от 5 В, что не совсем (или совсем не) соответствует реальному положению вещей. В этом случае при питании от 5 В напряжение на шине упало бы до нуля при резисторе 4,7К, чего реально естественно никогда не происходит. Так что будем считать этот ток предельным, при питании напрямую от источника. В любом случае резистор не спасет при преобразовании температуры в нескольких устройствах одновременно, так как снижать его значение до 1К все же было бы неправильно с токи зрения перегрузки выходных каскадов устройств.
Покажите коды, не стесняясь, или свяжитесь со мной в Скайпе, я там под своим ником, мож помогу чем-нить.
0
Уважаемы dadigor!
Гляньте, пожалуйста, свежим взглядом

u8 OW_Buffer[16];
u8 convert_T[]={0x00,0x00,0xff,0x00,0x00,0x00,0xff,0x00}; //0x44
u8 skip_ROM[]={0x00,0x00,0xff,0xff,0x00,0x00,0xff,0xff}; //0xcc
u8 read_scratchpad[]={0x00,0xff,0xff,0xff,0xff,0xff,0x00,0xff};//0xbe
u16 received_data;
//------ Buses configuring —
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA| //GPIOA clock RCC_APB2Periph_USART1| //USART1 clock RCC_APB2Periph_AFIO,ENABLE); //AFIO enable
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE); //USART2 clock
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE); //DMA1 clock
//------ Port configuring —
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_2;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_AF_OD;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStructure); //USART2_TX-OW interface
//------ Interrupt configuring — NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure); //USART2_TX interrupt
//------ USART2 (1-wire port) configuring — USART_InitStructure.USART_BaudRate=115200;
USART_InitStructure.USART_WordLength=USART_WordLength_8b;
USART_InitStructure.USART_StopBits=USART_StopBits_1;
USART_InitStructure.USART_Parity=USART_Parity_No;
USART_InitStructure.USART_HardwareFlowControl=USART_HardwareFlowControl_None;
USART_InitStructure.USART_Mode=USART_Mode_Rx|USART_Mode_Tx;
USART_Init(OW_port,&USART_InitStructure); //USART2 configuring
USART_Cmd(OW_port,ENABLE); //USART2 enable
USART_HalfDuplexCmd(OW_port,ENABLE); //halfduplex enable
USART_DMACmd(OW_port,USART_DMAReq_Tx|USART_DMAReq_Rx,ENABLE);//OW port DMA enable
//------ USART2 (1-wire port) transmitter DMA configuring — DMA_DeInit(DMA1_Channel7);
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&OW_Buffer[0];
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralDST;
DMA_InitStructure.DMA_BufferSize=sizeof(OW_Buffer);
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
DMA_Init(DMA1_Channel7,&DMA_InitStructure); //DMA1_channel7 initialization
DMA_ITConfig(DMA1_Channel7,DMA_IT_TC,ENABLE); //DMA1_channel7 interrupt enable
//------ USART2 (1-wire port) receiver DMA configuring — DMA_DeInit(DMA1_Channel6);
DMA_InitStructure.DMA_PeripheralBaseAddr=(u32)&(USART2->DR);
DMA_InitStructure.DMA_MemoryBaseAddr=(u32)&OW_Buffer[0];
DMA_InitStructure.DMA_DIR=DMA_DIR_PeripheralSRC;
DMA_InitStructure.DMA_BufferSize=sizeof(OW_Buffer);
DMA_InitStructure.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
DMA_InitStructure.DMA_MemoryInc=DMA_MemoryInc_Enable;
DMA_InitStructure.DMA_PeripheralDataSize=DMA_PeripheralDataSize_Byte;
DMA_InitStructure.DMA_MemoryDataSize=DMA_MemoryDataSize_Byte;
DMA_InitStructure.DMA_Mode=DMA_Mode_Normal;
DMA_InitStructure.DMA_Priority=DMA_Priority_Low;
DMA_InitStructure.DMA_M2M=DMA_M2M_Disable;
DMA_Init(DMA1_Channel6,&DMA_InitStructure); //DMA1_channel6 initialization
DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE); //DMA1_channel6 interrupt enable
//------ end initialization — DMA1_Channel7->CNDTR=(uint32_t)0x00;
DMA1_Channel6->CNDTR=(uint32_t)0x00;

void Measuring(void)
{
u32 ticks;
u8 i;
OW_Reset(OW_port); //reset OW line
SendOWCommand(skip_ROM,sizeof(skip_ROM)); //send 0xcc
SendOWCommand(convert_T,sizeof(convert_T)); //send 0x44
ticks=os_time_get(); //get current time
while((os_time_get()-ticks)<750); //delay 750ms
OW_Reset(OW_port); //reset OW line
SendOWCommand(skip_ROM,sizeof(skip_ROM)); //send 0xcc
SendOWCommand(read_scratchpad,sizeof(read_scratchpad)); //send 0xbe
ReadData(16); //send 0xffff and read 16 byte
while(!(DMA1->ISR&DMA_ISR_TCIF6));
DMA1->IFCR|=DMA_IFCR_CTCIF6;
DMA1_Channel6->CCR&=~DMA_CCR6_EN;
received_data=0x0000;
for(i=0;i<16;i++)
{
if(OW_Buffer[i]==0xff)
{
received_data|=(1<<i);
}
}
}

u8 OW_Reset(USART_TypeDef* port)
{
while(!(port->SR&USART_FLAG_TC)); //wait, while port is not ready
port->BRR=0x0EA6; //baudrate 9600
port->DR=(uint8_t)0xf0; //send 'reset' pulse
while(!(port->SR&USART_FLAG_TC));
port->BRR=0x0138; //baudrate 115200
if(port->DR!=(uint8_t)0xf0) //if sensor connected
{
return 1;
}
return 0;
}

void SendOWCommand(u8* command,u8 count)
{
u8 i;
while(DMA1_Channel7->CNDTR);
for(i=0;i<count;i++)
{
OW_Buffer[i]=*command++;
}
DMA1_Channel7->CCR&=~DMA_CCR7_EN;
DMA1_Channel7->CNDTR=count;
DMA1_Channel7->CCR|=DMA_CCR7_EN; //send command start
}

void ReadData(u8 datalenght)
{
u8 i;
while(DMA1_Channel6->CNDTR);
DMA1_Channel6->CCR&=~DMA_CCR6_EN;
DMA1_Channel6->CNDTR=datalenght;
DMA1_Channel6->CCR|=DMA_CCR6_EN; //OW-port Rx start
while(DMA1_Channel7->CNDTR);
for(i=0;i<datalenght;i++)
{
OW_Buffer[i]=0xff;
}
DMA1_Channel7->CCR&=~DMA_CCR7_EN;
DMA1_Channel7->CNDTR=datalenght;
DMA1_Channel7->CCR|=DMA_CCR7_EN; //OW-port Tx start
}

код стопорится в процедуре Measuring на строчке while(!(DMA1->ISR&DMA_ISR_TCIF6));
на реализацию задержек не обращайте внимания, это тупо отладочный код, крутится поверх RTX
0
а не пробовали закомментаривать эту строчку?
0
Нет, это я сгоряча ((
0
Вы инициализировали прерывание от канала передачи
//------ Interrupt configuring — NVIC_InitStructure.NVIC_IRQChannel=DMA1_Channel7_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0;
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
NVIC_Init(&NVIC_InitStructure); //USART2_TX interrupt
а ждете от канала приема
while(!(DMA1->ISR&DMA_ISR_TCIF6));
или я чего-то просмотрел
0
Всё правильно
В указанном Вами фрагменте я инициализирую контроллер прерываний передатчика, чтобы возникали прерывания, которые я потом обрабатываю.
А прерывания приёмника я не обрабатываю, соответственно, необходимости в инициализации нет.
Я проверяю флаг, а за его управление отвечает строчка DMA_ITConfig(DMA1_Channel6,DMA_IT_TC,ENABLE);
Кстати, включение в код приведённого Вами фрагмента применительно к каналу 6 эффекта не даёт.
0
Просадка напряжения на 1-wire при конвертировании вызвана не только повышенным потреблением, но и тем, что при трёхпроводной схеме DS18x20 во время конвертирования формируют на 1-wire низкий уровень, чтобы сигнализировать мастеру о происходящем процессе (нет смысла читать скрэтчпэд, пока на шине низкий уровень). Вероятно, когда схема двухпроводная, этот механизм всё равно работает (хотя и написано, что он не применим) и просаживает питание, в результате чего сенсор сбрасывается (85 градусов — это его power-on default).

У меня вот другая проблема. Схема трёхпроводная. Без всяких UART'ов, чистый GPIO в полудуплексе. Все коммуникации с сенсором работают отлично. После подачи CONVERT T (0x44) напряжение на 1-wire скачкообразно проседает на 172ms, потом так же скачкообразно поднимается. Всё вроде бы по даташиту. Но в результате из скрэтчпэда читается значение 0x00FF (все остальные байты — как полагается, CRC совпадает), что соответствует 127.5 градусам для DS18S20.

Что я делаю не так, кто подскажет?

Пока вижу лишь одно отличие от даташита. Подтяжка у меня 2к, а не 4.7к, как там написано. Но не понятно, как это может влиять на измерение при 3-проводной схеме. На Vdd при измерении уровень не проседает ни на милливольт. Да и всё остальное общение с сенсором происходит отлично.

Есть у кого-нибудь идеи?
0
Вероятно, когда схема двухпроводная, этот механизм всё равно работает (хотя и написано, что он не применим) и просаживает питание, в результате чего сенсор сбрасывается (85 градусов — это его power-on default).
Не очень понял идею — «когда схема двухпроводная» Даллас просаживает питание, как бы выдавая такой же сигнал, как для трехпроводной схемы, что приводит к его же сбросу?? Т.е. по двухпроводной схеме нельзя вообще измерять?? Или что?? Нет уж, дело не в этом. При проведении измерения просто резко возрастает ток потребления, емкости внутреннего питающего конденсатора не хватает на то, чтобы не просаживалось напряжение шины. Для двухпроводной схемы подключения может быть критичным, если номинал резистора больше необходимого или если заставить измерять даже несколько термометров одновременно. Опыт это подтверждает — уменьшая номинал резистора можно добиться устойчивой работы нескольких термометров на шине. Однако уменьшение номинала не соответствует требованию даташитов и увеличивает ток нагрузки выходных каскадов подключенных микросхем, что тоже наверняка не есть хорошо.
Поэтому игру с номиналом резистора я лично не рассматриваю даже как вариант, гораздо разумнее питать шину по предложенной схеме, полностью соответствующей требованиям. Питаю шину от 3,3 В, резистор 4К7 (наверное все же можно и 3К3, хотя даташит об этом молчит). Подключаю щепотку Далласов, заставляю измерять всех одновременно, но на время измерения подаю питание на шину (кстати, его нужно успеть подать не позднее, чем через 10 мксек после передачи команды Convert T) и по окончании времени измерения читаю их поочередно. Все работает.
А вот непонятно, зачем у Вас подтяжка 2К ?? А вдруг Вы перегрузили выходной каскад Далласа, не пробовали все же поставить номинал побольше, вдруг поможет? Кстати, у Вас чтение нормально работает, уникальный номер микросхемы пробовали читать? Я бы попробовал прочитать для начала номер, чтобы проверить чтение. Напоминаю, первый байт обязан прочитаться как 0x28.
0
Честно говоря, я сильно сомневаюсь, что выходной каскад у них настолько хилый, чтобы не справиться с парой миллиампер. А вот если вдруг почему-то какое-то из устройств на шине надумает передавать при поданном на нее напрямую питании — вот тогда точно будет дым.
0
Насчет хилости выхода — я не проверял, да особо и не хочется, так что это гипотетически. Микруха старой разработки, вряд ли ее сильно усовершенствовали. Осциллограф показал бы, что там у него на шине творится.
А насчет надумает чего-нить передать во время запитывания — наверняка гикнется, но ведь это тоже надуманный вариант, с чего бы это ему, если мы приказали измерять, после чего на вход дали мощную единицу.
По сути я больше грешу на нечеткость при выполнении чтения у Spirit.
0
Ну, по идее, устройства на шине не должны передавать без запроса с хоста. Но если хост сглючит и не снимет питание, или пробьется транзистор подачи питания — будет ахтунг. Плюс если у DS18B20 есть функция прижатия шины к нулю на время преобразования, то ее активация по ошибке тоже приведет к выгоранию.
А вот подтяжка меньшего номинала врядли приведет к перегрузке выхода.
0
Я подаю питание на шину выдачей единицы на соответствующий выход STM, переопределенный на это время как пушпульный, если почитать внимательно статью.
1. Если хост сглючит и не снимет питание, то он и не даст команду чтения, или я чего-то не понимаю… И что значит сглючит, ошибется именно в этом месте, а дальше заработает как надо?
2. Пробьется транзистор на выходе микрухи хоста? Тогда уж ахтунг и хосту по сути… Ибо больше он работать правильно не сможет.
3. Активация функции, не допустимой при двухвыводном подключении? Тоже непонятно с чего, типа Даллас заглючит.
Короче, я даже не спорю — ситуации можно еще придумать, а по жизни вполне можно еще удар молнии в шину получить, ахтунг всему, а мож и оператору… ))
А вот резистор снижать до 2К ни с того ни с сего я бы не стал. У него же трехвыводное подключение. Зачем снижать? Даже куча термометров нормально работают на 4К7, проверял это еще лет пятнадцать тому назад. Не понимаю. Хотя очень может быть, что дело совсем и не в этом, я уже выше говорил. Но все равно зачем?
В общем я подключаю по двухпроводной схеме и пользуюсь уже второй год. Зимой два термометра (дома и за окном), летом на даче 4-6 штук (за окном минимум три, один всегда в глухой тени). Иногда цеплял и больше, старый холодильник проверял, до парника доводил.
0
Кстати, припомнил, понижал я резистор в свое время до 1К или даже меньше. Уровень нуля на выходе Далласа повышался прилично. Мож попробую на днях ее раз — отпишусь. Как Вы думаете — это перегрузка выхода или как это называть?
0
Логично что повышался — там MOSFET со вполне определенным сопротивлением, чем больше ток — тем больше падение напруги на нем. А перегрузка ли это — надо по даташиту смотреть, там наверняка указан максимальный ток выхода.
0
Если хост сглючит и не снимет питание, то он и не даст команду чтения, или я чего-то не понимаю…
Это сильно зависит от программы, во время отладки можно и налажать.
Пробьется транзистор на выходе микрухи хоста?
А это уже зависит от схемотехники — например, ключ может быть и внешний. Хотя, кстати, многие МК успешно работают с частично выбитыми портами.
Алсо можно добавить туда защитный резистор на 100-300 ом.
0
Я говорю о том, что написал в статье. Ключ внутренний, в этом вся соль статьи. Если он пробьется, то проц без перепрошивки (переназначения ножки на другую — если есть такая возможность, соответственно перепайки схемы) уже успешно на этой задаче работать не будет… Да и у меня плохая привычка выкидывать нафиг процы с битой ногой, ибо веры им нет, а проводить тестирование камня нет желания.
Резистор добавить в такой схеме нежелательно, ибо уровень нуля при выдаче команды с хоста будет уже не очень…
0
Вот у меня сейчас 3 провода. Vdd = 3.3V. Подтяжка 4.7. Один единственный DS18S20 на шине. После подачи команды 0x44 (Convert T) он теперь на целых 8 секунд (!) просаживает линию 1-wire до 1.47В и в результате потом всё равно выдаёт 127.5 градусов.
Когда была подтяжка 2к, он на 172мс задумывался, но всё равно выдавал 127.5 градусов.

И да, все остальные коммуникации с ним работают идеально. Серийник читается, контрольная сумма у этих 127.5 градусов — правильная, и т.д. Ну и если ему Convert T не говорить после включения, то читаются паспортные 85 градусов, как полагается.
0
При трехпроводной схеме подключения это не «просадка» напряжения на шине, а вполне реальный сигнал «temperature conversion is in progress» от термометра, который не вырабатывается при двухпроводной схеме. Вот что написано в даташите:
If the DS18B20 is powered by an external supply, the master can issue “read time slots” (see the 1-Wire Bus System section) after the Convert T command and the DS18B20 will respond by transmitting 0 while the temperature conversion is in progress and 1 when the conversion is done. If the DS18B20 is powered with parasite power, this notification technique cannot be used since the bus must be pulled high by a strong pullup during the entire temperature conversion. The bus requirements for parasite power are explained in detail in the Powering the DS18B20 section."
0
Вы, простите, первый абзац моего сообщения читали? ;-)

Цитирую:
«при трёхпроводной схеме DS18x20 во время конвертирования формируют на 1-wire низкий уровень, чтобы сигнализировать мастеру о происходящем процессе»

То есть я, как бы, в курсе. :)

Далее я тоже пишу:
«После подачи CONVERT T (0x44) напряжение на 1-wire скачкообразно проседает на 172ms, потом так же скачкообразно поднимается. Всё вроде бы по даташиту

А если Вам не понравилось слово «проседает» в этом предложении, то извините. Я программист, а не схемотехник. Как правильно было это явление называть? «Датчик формирует низкий уровень»? Так то-то и оно, что ничерта там не низкий уровень, а какая-то «логическая половинка» — 1.5В. И почему, — я не знаю. Поэтому и пишу «проседает».
0
Извините и Вы меня, я не придираюсь, а просто пытаюсь понять и помочь. Информации маловато.
1. Кстати, а Вы после измерения перед чтением все команды по шине даете? (RESET/PRESENCE, затем SKIP_ROM, ну или MATCH_ROM + CODE, и только потом READ_SCRATCHPAD). Спрашиваю, потому что не знаю, как там у Вас сделано.
2. Проседание на шине как раз и неправильное, тем более что Вы в курсе, что по даташиту там должен быть логический ноль (and the DS18B20 will respond by transmitting 0). С этим и надо начать бороться — найти причину ненулевого сигнала.
3. И что такое у Вас чистый GPIO в полудуплексе? просто уточните, как это сделано, может быть здесь «собака порылась» )).
0
Рассказываю всё как есть:
1. Подаю все команды. Сначала Reset, потом чтение presence, потом match rom с кодом (или skip, результат тот же).
2. Там и другие чудеса есть. Например, будучи подключенным по 3 проводам, датчик считает, что запитан паразитно. То есть на ноге 3 у него +5В сейчас (а было 3.3, результат тот же), а он по команде Reset+Match+Read_Power(0xB4)+Read bit выдаёт нолик. Причём хороший такой нолик, аж до самой GND.
3. Это значит, что ножка GPIOE8 у STM32F101VBT6 подключена на среднюю ножку датчика DS18S20, а сверху припаяна подтяжка 4.7k. При необходимости выставить ноль, ножка программируется в GPIO_OUT_OD | GPIO_Speed_50MHz, а при небходимости выставить 1 или прочитать шину — в GPIO_Mode_IN_FLOATING.
0
Хорошо, тогда другой вопрос. Куда сейчас припаяна подтяжка — к 3,3 В (питание STM) или к 5 В?
0
Спасибо за помощь и прошу прощения за беспокойство. Разобрался.
Наши схемотехники впихнули датчик DS18S20-PAR, у которого нога 3 — это не Vdd, а NC.
И он всегда питается только паразитно. Соответственно, ему на время конверсии нужна сильная подтяжка.

Будем менять датчики на нормальные 18S20.
0
А зачем же менять-то? Включайте GPIO на время преобразования в режим пушпул с выдачей «1» и все дела. Да, и не забудьте переподключить резистор к 3,3 В, если он сейчас подключен к 5.
0
Спасибо! Push-pull помог!
Резистор подключен к 3.3, конечно же.

Но всё-таки с нормальным трёхпроводным датчиком удобнее. Понятно, когда он закончил конверсию.
А с этим надо ждать все 750мс всегда. Правда, в моём случае это не критично.
0
Прелесть этого варианта в том, что можно одновременно заставить измерять несколько датчиков, дав команду SKIP_ROM перед CONVERT_T, затем выждать время, необходимое для одного измерения на двухпроводном подключении, а затем прочитать поочередно все 10 термометров, это лучше, чем ловить конец измерения от каждого по-очереди… Так что насчет удобства я бы поспорил, если речь идет о нескольких термометрах конечно. А когда их несколько, то и сама двухпроводность тоже облегчает задачу.
Я как-то невнятно это обозначил в статье и народ пассивно отнесся, вроде бы никто и не использует этот вариант. Ну а я по-другому уже с DS18B20 и не работаю ))
0
Ну, если они по 3 проводам подключены, то их тоже можно все параллельно запустить на конверсию и ловить конец измерений последнего.

Мало того, есть ещё прекрасная функция SEARCH ALARM, которая позволяет не опрашивать датчики вовсе, если нужно ловить только превышение температуры. Причём весь алгоритм исполнять нет никакого смысла. Достаточно подать ALARM SEARCH и прочитать первые два бита. Если есть тревога хоть на одном датчике, то или первый или второй бит будет 0.
0
Правда, на конверсию их всё равно запускать надо. Потому что без этого тревога не выставится.
0
А не прикидывали, сколько датчиков можно повесить на одну ногу STM32 при паразитном питании, если включать их на конверсию широковещательным запросом (SKIP ROM + Convert T)?

У нас в схеме стоит последовательно резистор 47ом. Я так понимаю, что как раз для ограничения тока. Но вот из каких соображений выбран именно такой номинал — не знаю. Схемотехники, которые это делали, как я уже писал ранее, уволились.
0
Это не паразитное питание, а вполне полноценное. Что до количества — ножки STM32 рассчитаны, ЕМНИП, на 25мА, датчик жрет 1мА — получаем до 25 датчиков на ногу. У STM8 чуть хилее, там для прокорма 25 датчиков нужно использовать HS ножку.
0
Спасибо.
И тем не менее, в даташите на датчик схема питания через 1-wire называется паразитным питанием.
0
Тут прикол в том, что на время измерения питание с паразитного переключается на полноценное.
0
Это вопрос терминологии, но я бы предпочёл всё же придерживаться терминов Maxim Integrated в этом вопросе. Любое питание по 1-wire — паразитное:

«Derives power from data line (“parasite power”) — does not need a local power supply»

И при паразитном питании датчика на время измерения необходимо в эту линию (по прежнему паразитного питания) вкачивать больше мощности. Но паразитным оно от этого быть не перестаёт, в отличие от раздельного, когда ножка Vdd подключена у датчика. И не зря датчик с неиспользуемой третьей ногой называется DS18S20-PAR. :)
0
Реально я вешал 8 штук, больше не было необходимости. По идее потребление одного термометра в режиме измерения температуры порядка 1,5 мА, так что десяток или чуть больше вполне можно. Только 47 Ом в этом случае уже будут лишними — «слишком много на себя возьмут».
0
Упс, опоздал… Не очень у нас с комментами, нет предупреждения о появившемся новом, когда отправляешь свой. Помнится где-то на форумах я встречал такой сервис.
Когда-то я замерял ток потребления в момент измерения при питании от 3.3 В, доходило до 1,5 мА. Если типичный ток 1 мА, значит 25 штюк.
Это немало, но и не очень много. В принципе лет 15 назад я организовывал сеть в 60 а может и 70 датчиков, не помню точно, но тогда я подпитывал измерение через внешний ключ. Там еще было две такие ветки на сети, всего под 130 Далласов (тогда пятивольтовых), веселое было времечко )) Были небольшие проблемы с наводками, но решились.
0
А вот зачем у меня там была подтяжка 2к — сам не знаю. Наши чудо-схемотехники так насхемотехничали. И уволились.
0
Запилил, вашу библиотечку для работы с STM32F4 в режиме half-duplex и Alternate_Open_Drain
Из ньюансов:
// enable DMA
		USART_ClearFlag(USART6, USART_FLAG_RXNE);
		USART_ClearFlag(USART6, USART_FLAG_TC);
		//USART_ClearFlag(USART6, USART_FLAG_TXE);

Пришлось закоментить Очистку флага TXE, поскольку в этом месте все висло.
Собственно вопрос — почему?
Его надо сбрасывать чтением?

Под freeRTOS думаю имеет смысл следующая конструкция

// выдерживаем время измерения (например 750 мс для 12-битного измерения)
#ifdef OW_GIVE_TICK_RTOS <br />
    vTaskDelay(750 / portTICK_PERIOD_MS);
#else
    for (i=0; i<1_MICROSECOND*750; i++);
#endif



Все великолепно работает, спасибо большое!!!
C разрешения авторов статьи могу «расшарить» для нужд страждущих
0
Мой первый коммент, что-то туплю, как отредактировать уже опубликованное.
0
как отредактировать уже опубликованное
Никак
0
Попробовал читать 2 термометра одновременно, все получилось, единственное, автор «на автомате» допустил ошибку:

    // читаем показания первого термометра      
    OW_Send(OW_SEND_RESET, "\x55\28\xF8\xFB\xE1\x01\x00\x00\x76\xbe\xff\xff", 4, buf,2, 2);

Хотя само-собой разумеется, что он имел в виду:

    OW_Transceive(  OW_SEND_RESET,                                      // reset / no reset
                    "\x55\x28\x93\x00\x7d\x02\x00\x00\x8C\xbe\xff\xff", // 0x55 -> ROMcode -> 0xBE
		    12,                                                 // bytes to TX length
		    buf,                                                // ref to read buff
		    2,                                                  // RX buff length
		    10);                                                // 1st read symbol number

Прошу простить мое занудство :), спасибо за внимание!
0
Да, опечаточка вышла, живые коды были несколько более корявые, поэтому после причесывания для статьи не проверил, моя вина. Естественно 12 байт на передачу, чтение с 10-го (учитывая нумерацию с нуля).
Спасибо, поправлю в статье.
Насчет библиотеки — я абсолютно не против, может быть кому-нибудь еще пригодятся, я буду только рад. Но исходные коды все же не мои, а из упомянутой статьи steel_ne, я их только слегка изменил.
0
Здравствуйте уважаемые! Не могли бы вы помочь мне с этим проектом для stm32f407vg???

#ifdef OW_USART1

#undef OW_USART2
#undef OW_USART3
#undef OW_USART4

#define OW_USART 		USART1
#define OW_DMA_CH_RX 	DMA2_Stream5
#define OW_DMA_CH_TX 	DMA2_Stream7
#define OW_DMA_FLAG_RX		DMA_IT_TCIF5
#define OW_DMA_FLAG_TX		DMA_IT_TCIF7

#endif


#ifdef OW_USART2

#undef OW_USART1
#undef OW_USART3
#undef OW_USART4

#define OW_USART 		USART2
#define OW_DMA_CH_RX 	DMA1_Channel6
#define OW_DMA_CH_TX 	DMA1_Channel7
#define OW_DMA_FLAG		DMA1_FLAG_TC6

#endif


// Буфер для приема/передачи по 1-wire
uint8_t ow_buf[8];

#define OW_0	0x00
#define OW_1	0xff
#define OW_R_1	0xff

//-----------------------------------------------------------------------------
// функция преобразует один байт в восемь, для передачи через USART
// ow_byte - байт, который надо преобразовать
// ow_bits - ссылка на буфер, размером не менее 8 байт
//-----------------------------------------------------------------------------
void OW_toBits(uint8_t ow_byte, uint8_t *ow_bits) {
	uint8_t i;
	for (i = 0; i < 8; i++) {
		if (ow_byte & 0x01) {
			*ow_bits = OW_1;
		} else {
			*ow_bits = OW_0;
		}
		ow_bits++;
		ow_byte = ow_byte >> 1;
	}
}

//-----------------------------------------------------------------------------
// обратное преобразование - из того, что получено через USART опять собирается байт
// ow_bits - ссылка на буфер, размером не менее 8 байт
//-----------------------------------------------------------------------------
uint8_t OW_toByte(uint8_t *ow_bits) {
	uint8_t ow_byte, i;
	ow_byte = 0;
	for (i = 0; i < 8; i++) {
		ow_byte = ow_byte >> 1;
		if (*ow_bits == OW_R_1) {
			ow_byte |= 0x80;
		}
		ow_bits++;
	}

	return ow_byte;
}

//-----------------------------------------------------------------------------
// инициализирует USART и DMA
//-----------------------------------------------------------------------------
uint8_t OW_Init() {
	GPIO_InitTypeDef GPIO_InitStruct;
	USART_InitTypeDef USART_InitStructure;

	if (OW_USART == USART1) {
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
		RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2,ENABLE);
		GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);

		// USART TX
		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
		GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
		GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
		GPIO_Init(GPIOA, &GPIO_InitStruct);
	}

	if (OW_USART == USART2) {

	}

	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;

	USART_Init(OW_USART, &USART_InitStructure);
	USART_Cmd(OW_USART, ENABLE);
	USART_HalfDuplexCmd(OW_USART, ENABLE);
	return OW_OK;
}

void OW_out_set_as_TX_pin(void){
        GPIO_InitTypeDef GPIO_InitStruct;
        if (OW_USART == USART1) {
        	   RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        	   GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
                // USART TX
                GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
                GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF;
                GPIO_InitStruct.GPIO_OType = GPIO_OType_OD;
                GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_UP;
                GPIO_Init(GPIOA, &GPIO_InitStruct);
        }
}

void OW_out_set_as_Power_pin(void){
        GPIO_InitTypeDef GPIO_InitStruct;
        if (OW_USART == USART1) {
        	    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
        	    GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
                // GPIO
                GPIO_SetBits(GPIOA, GPIO_Pin_9);
                GPIO_InitStruct.GPIO_Pin = GPIO_Pin_9;
                GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
                GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
                GPIO_InitStruct.GPIO_OType = GPIO_OType_PP;
                GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_NOPULL;
                GPIO_Init(GPIOA, &GPIO_InitStruct);
        }
}

//-----------------------------------------------------------------------------
// осуществляет сброс и проверку на наличие устройств на шине
//-----------------------------------------------------------------------------
uint8_t OW_Reset() {
	uint8_t ow_presence;
	USART_InitTypeDef USART_InitStructure;

	USART_InitStructure.USART_BaudRate = 9600;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_Init(OW_USART, &USART_InitStructure);

	// отправляем 0xf0 на скорости 9600
	USART_ClearFlag(OW_USART, USART_FLAG_TC);
	USART_SendData(OW_USART, 0xf0);
	while (USART_GetFlagStatus(OW_USART, USART_FLAG_TC) == RESET) {
#ifdef OW_GIVE_TICK_RTOS
		taskYIELD();
#endif
	}

	ow_presence = USART_ReceiveData(OW_USART);

	USART_InitStructure.USART_BaudRate = 115200;
	USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	USART_InitStructure.USART_StopBits = USART_StopBits_1;
	USART_InitStructure.USART_Parity = USART_Parity_No;
	USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	USART_Init(OW_USART, &USART_InitStructure);

	if (ow_presence != 0xf0) {
		return OW_OK;
	}

	return OW_NO_DEVICE;
}


//-----------------------------------------------------------------------------
// процедура общения с шиной 1-wire
// sendReset - посылать RESET в начале общения.
// 		OW_SEND_RESET или OW_NO_RESET
// command - массив байт, отсылаемых в шину. Если нужно чтение - отправляем OW_READ_SLOTH
// cLen - длина буфера команд, столько байт отошлется в шину
// data - если требуется чтение, то ссылка на буфер для чтения
// dLen - длина буфера для чтения. Прочитается не более этой длины
// readStart - с какого символа передачи начинать чтение (нумеруются с 0)
//		можно указать OW_NO_READ, тогда можно не задавать data и dLen
//-----------------------------------------------------------------------------
uint8_t OW_Send(uint8_t sendReset, char *command, uint8_t cLen,
		uint8_t *data, uint8_t dLen, uint8_t readStart) {

	// если требуется сброс - сбрасываем и проверяем на наличие устройств
	if (sendReset == OW_SEND_RESET) {
		if (OW_Reset() == OW_NO_DEVICE) {
			return OW_NO_DEVICE;
		}
	}
	GPIO_SetBits(LED_GREEN);
	while (cLen > 0) {

		OW_toBits(*command, ow_buf);
		command++;
		cLen--;

		DMA_InitTypeDef DMA_InitStructure;

		// DMA на чтение
		DMA_DeInit(OW_DMA_CH_RX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
		DMA_InitStructure.DMA_BufferSize = 8;
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_Init(OW_DMA_CH_RX, &DMA_InitStructure);

		// DMA на запись
		DMA_DeInit(OW_DMA_CH_TX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t) ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
		DMA_InitStructure.DMA_BufferSize = 8;
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_Init(OW_DMA_CH_TX, &DMA_InitStructure);

		// старт цикла отправки
		USART_ClearFlag(OW_USART, USART_FLAG_RXNE | USART_FLAG_TC);
		USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
		DMA_Cmd(OW_DMA_CH_RX, ENABLE);
		DMA_Cmd(OW_DMA_CH_TX, ENABLE);

		// Ждем, пока не примем 8 байт
		while (DMA_GetFlagStatus(OW_DMA_CH_RX, OW_DMA_FLAG_RX) == RESET || DMA_GetFlagStatus(OW_DMA_CH_TX, OW_DMA_FLAG_TX) == RESET){
#ifdef OW_GIVE_TICK_RTOS
			taskYIELD();
#endif
			GPIO_SetBits(LED_GREEN);
		}

		// отключаем DMA
		DMA_Cmd(OW_DMA_CH_TX, DISABLE);
		DMA_Cmd(OW_DMA_CH_RX, DISABLE);
		USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);

		// если прочитанные данные кому-то нужны - выкинем их в буфер
		if (readStart == 0 && dLen > 0) {
			*data = OW_toByte(ow_buf);
			data++;
			dLen--;
		} else {
			if (readStart != OW_NO_READ) {
				readStart--;
			}
		}
	}

	return OW_OK;
}

Зависает в функции OW_Reset В ожидании флага USART_FLAG_TC.
Заранее благодарен!!!
0
с этим разобрался! Теперь виснет на ожидании флагов DMA.
В этой строчке: while (DMA_GetFlagStatus(OW_DMA_CH_RX, OW_DMA_FLAG_RX) == RESET || DMA_GetFlagStatus(OW_DMA_CH_TX, OW_DMA_FLAG_TX) == RESET)
0
В первом случае Вы наверное забыли включить USART…
А тут видимо что-то с инициализацией DMA не так. Мне сейчас трудно смотреть — вне дома, с маленького экрана, посмотрите внимательно библиотечную инициализацию для STM32F407, она может отличаться от приведенной выше.
0
Буду пробовать! Но вы пожалуйста гляньте как свободная минутка будет! Заранее спасибо!
0
Ну а с USART так оно и было?
0
Да! Забыл затактировать!!! А вот с DMA все ни как! инициализацию проверил! Вроде все так!
0
Посмотрите внимательнее названия флагов и прочее, компилятор предупреждения на инициализации какие-нибудь пишет?
0
Не ошибок и варнингов нету! Stream5 и Stream7 это потоки RX И TX и их ли надо указывать при проверке флагов DMA?
0
Попробуйте указать каналы
0
Пробовал! Тогда пишет варнинг что указали long а надо DMA_Stream_TypeDef* DMAy_Streamx вот сижу и бьюсь головой что не так!)
0
а у Вас и на прием и на передачу DMA_Channel_4 вроде бы указан
0
По даташиту там указано: Chanel 4 -> USART1_RX -> Stream 5, Chanel 4 -> USART1_TX -> Stream 7. то-есть разные потоки но один канал!
0
Я не запускал DMA на 400-х камнях, завтра посмотрю. А Вы в примерах библиотечных не смотрели?
0
Кстати, поправьте комментарии
// инициализирует USART и DMA
там только USART приисутствует
0
Смотрел! Вроде все так!!! Но виснет всеравно!( Ладненько я тоже спать пойду! До завтра!!!
0
Спночи!
0
Посмотрел в даташиты на 407. Инициализация DMA тут будет не совсем такая, а немного посложнее, для лучшего понимания посмотрите статью «DMA в STM32F4. Описание», тут неплохо описана структура DMA в STM32F4. При выборе каналов обратите внимание на таблицы «Table 2. DMA1 request mapping» и «Table 3. DMA2 request mapping» в документе AN4031 от STM.
А для самой инициализации посмотрите отличный Простой пример использования АЦП+ПДП (ADC+DMA) для STM32F4-Discovery. Мне кажется, у Вас все получится, если да — поделитесь, а если нет — посмотрим вместе, достану свою еще нетронутую Discovery F4, заодно и пощупаю.
0
Я, кстати, в каком-то из проектов делал проще — на гпиошках, для нескольких датчиков.
В фоне крутится процесс, основная нагрузка у которого импульсная — задержка без прерываний на пару десятков микросекунд на опрос или запись одного битика, перерывы произвольные для всего остального. Из плюсов — можно параллельно опрашивать сколько угодно датчиков (каждый на своей ножке), из минусов — если есть какие-то сверхкритичные прерывания или высокочастотное прерывание по таймеру или какому суперскоростному уарту, то не покатит. Хотя можно использовать один таймер и работать без программных задержек. Будет чуть сложнее, но без блокировок.

Вывод почти всегда находится в состоянии выхода, питания там достаточно, переключается на вход с подтяжкой только на время чтения (это несколько десятков мкс).
0
В этом варианте изюм как раз в том, что работают в основном встроенные автоматы контроллера, не мучая процессор. Для тех, кому это важно.
0
Спасибо! Буду Разбираться!!! Сделаю обязательно выложу, а то в интернете много описания на STM32F1 а на F4 нету такой реализации я не нашел! а вообще у меня связка freeRTOS-StEmWin-RTC-HC_SR-04 — bluetooth-wifi-TEA5767-ds18b20. Все прикручено и работает, а вот с ds18b20 что то не вяжется!!! Программно я его запускал!!! А вот аппаратно не в какую не хочет!!! А не может быть из-за скорости USART не работать???
0
Вряд ли дело в USART, думаю, что там все нормально. А Вы на каком железе и в какой среде отлаживаетесь? Можете остановить и посмотреть состояние регистров? По идее USART в нашем случае работает как конечный автомат и принимает любую белиберду. А осциллограф есть?
0
Осциллограф есть старенький С1-150 15МГц. Нормальную работу usart на нем не проверить! Единственное что можно увидеть это что что дергается!!! Синхронизировать не получается! А вот на счет просмотра регистра это можно!!! А если я на дисплей выведу состояние регистров до проверки флагов статуса!? Пользуюсь Coocox. В принципе можно же и в отладке посмотреть регистры!
0
При вызове OW_Reset USART Отправляет данные, а вот принимает 0! Даже осцилл не дергается на приеме!!! Вот первая посылка: OW_Send(OW_SEND_RESET, "\xCC\x44", 2, 0, 0, OW_NO_READ);
0
Если не работает DMA, то интерфейс 1-Wire по сути не отрабатывается, только стартовый «0»от команды или в нашем случае это просто импульс RESET…
Кстати, у Вас выход и вход USART замкнуты? Что значит «Даже осцилл не дергается на приеме!!»
0
А зачем в USART замыкать RX И TX??? Там же в инициализации указано что полудуплекс! Значит используется только одна ножка TX!!! Или не так????
0
Ну конечно так. Просто меня смутила фраза «Даже осцилл не дергается на приеме!!». Не понял, где это, вроде бы прием и передача на одном проводе должны быть. ))
Байт 1-Wire передается с помощью передачи 8-ми байт по USART. А несколько байт смогут уйти только когда мы отладим DMA.
0
так то оно так! а в функции OW_Send идет одна инициализация dma затем следам другая инициализация dma. не получается ли так что настроили на передачу, а затем сразу на прием! без сброса всяких флагов!
0
А Вы переделали инициализацию DMA под STM32F4?
0
Конечно да!!!
// DMA на чтение
		DMA_DeInit(OW_DMA_CH_RX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
		DMA_InitStructure.DMA_BufferSize = sizeof(ow_buf);
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
		DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
		DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
		DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

		DMA_Init(OW_DMA_CH_RX, &DMA_InitStructure);

		// DMA на запись
		DMA_DeInit(OW_DMA_CH_TX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
		DMA_InitStructure.DMA_BufferSize = sizeof(ow_buf);
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
		DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
		DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
		DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
		DMA_Init(OW_DMA_CH_TX, &DMA_InitStructure);
0
OW_DMA_CH_RX -> DMA2_Channel6
OW_DMA_CH_TX -> DMA2_Channel7
0
две последних строки не понял
0
в коде у меня есть #define OW_DMA_CH_RX DMA2_Stream5
#define OW_DMA_CH_TX DMA2_Stream7
0
Как ни странно но я оказался прав!!! вот что я сделал:
uint8_t OW_Send(uint8_t sendReset, char *command, uint8_t cLen,
		uint8_t *data, uint8_t dLen, uint8_t readStart) {

	// если требуется сброс - сбрасываем и проверяем на наличие устройств
	if (sendReset == OW_SEND_RESET) {
		if (OW_Reset() == OW_NO_DEVICE) {
			return OW_NO_DEVICE;
		}
	}

	while (cLen > 0) {

		OW_toBits(*command, ow_buf);
		command++;
		cLen--;

		DMA_InitTypeDef DMA_InitStructure;

		// DMA на запись
		DMA_DeInit(OW_DMA_CH_TX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral;
		DMA_InitStructure.DMA_BufferSize = 8;
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
		DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
		DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
		DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
		DMA_Init(OW_DMA_CH_TX, &DMA_InitStructure);
		USART_ClearFlag(OW_USART, USART_FLAG_TC | USART_FLAG_TXE);
		USART_DMACmd(OW_USART, USART_DMAReq_Tx, ENABLE);
		DMA_Cmd(OW_DMA_CH_TX, ENABLE);

		while (DMA_GetFlagStatus(OW_DMA_CH_TX, OW_DMA_FLAG_TX) == RESET){
			GPIO_SetBits(LED_GREEN);
		}
		GPIO_SetBits(LED_ORANGE);

		// DMA на чтение
		DMA_DeInit(OW_DMA_CH_RX);
		DMA_InitStructure.DMA_Channel = DMA_Channel_4;
		DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART1->DR);
		DMA_InitStructure.DMA_Memory0BaseAddr = (uint32_t)ow_buf;
		DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory;
		DMA_InitStructure.DMA_BufferSize = 8;
		DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
		DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
		DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
		DMA_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
		DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;
		DMA_InitStructure.DMA_Priority = DMA_Priority_Low;
		DMA_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Disable;
		DMA_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_1QuarterFull;
		DMA_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
		DMA_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

		DMA_Init(OW_DMA_CH_RX, &DMA_InitStructure);

		// старт цикла отправки
		USART_ClearFlag(OW_USART, USART_FLAG_RXNE | USART_FLAG_TC | USART_FLAG_TXE);
		USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
		DMA_Cmd(OW_DMA_CH_RX, ENABLE);
		DMA_Cmd(OW_DMA_CH_TX, ENABLE);

		// Ждем, пока не примем 8 байт
		while ((DMA_GetFlagStatus(OW_DMA_CH_RX, OW_DMA_FLAG_RX) == RESET) || (DMA_GetFlagStatus(OW_DMA_CH_TX, OW_DMA_FLAG_TX) == RESET)){
#ifdef OW_GIVE_TICK_RTOS
			taskYIELD();
#endif

		}
		GPIO_SetBits(LED_GREEN);
		// отключаем DMA
		DMA_Cmd(OW_DMA_CH_TX, DISABLE);
		DMA_Cmd(OW_DMA_CH_RX, DISABLE);
		USART_DMACmd(OW_USART, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);

		// если прочитанные данные кому-то нужны - выкинем их в буфер
		if (readStart == 0 && dLen > 0) {
			*data = OW_toByte(ow_buf);
			data++;
			dLen--;
		} else {
			if (readStart != OW_NO_READ) {
				readStart--;
			}
		}
	}

	return OW_OK;
}


между dma tx и dma rx я вставил цикл на проверку сброса флагов! И о чудо все отправилось!!! Сейчас переделаю на прием и отпишусь!
0
у Вас дважды разрешается передача
DMA_Cmd(OW_DMA_CH_TX, ENABLE);
Второй раз наверное лишний
0
или наверное надо запретить ее после проверки флага
0
Мда, судя по паузе пошло дело, некогда написать что и как )) Но
DMA_Cmd(OW_DMA_CH_TX, DISABLE);
до или после строки
GPIO_SetBits(LED_ORANGE);
все же нужно вставить, я так думаю.
0
Да воюю все! ( Виснет на проверке флага приема и все тут!( Я уже замучился!!!
0
Весь код перебрал и переделал!!! Сейчас хоть после DMA_Cmd(DMA_TX_STREAM, ENABLE); USART Делает отправку!!! А вот только доходит до while(DMA_GetFlagStatus(DMA_RX_STREAM, DMA_FLAG_TCIF5) == RESET); Сразу виснет тут!(
0
ВОТ переделанная функция

uint8_t OW_Send(uint8_t sendReset,
		        uint8_t *command,
		        uint8_t cLen,
		        uint8_t *data,
		        uint8_t dLen,
		        uint8_t readStart){

	// если требуется сброс - сбрасываем и проверяем на наличие устройств
	if (sendReset == OW_SEND_RESET) {
		if (OW_Reset() == OW_NO_DEVICE) {
			return OW_NO_DEVICE;
		}
	}

	while (cLen > 0) {

		OW_toBits(*command, OneWireBuffer);
		command++;
		cLen--;

		DMA_DeInit(DMA_TX_STREAM);
		DMA_DeInit(DMA_RX_STREAM);
		InitStucture.DMA_TX_InitStructure.DMA_BufferSize = 8;
		InitStucture.DMA_RX_InitStructure.DMA_BufferSize = 8;
		DMA_Init(DMA_TX_STREAM, &InitStucture.DMA_TX_InitStructure);
		DMA_Init(DMA_RX_STREAM, &InitStucture.DMA_RX_InitStructure);

		USART_ClearFlag(USART_X, USART_FLAG_RXNE | USART_FLAG_TC | USART_FLAG_TXE);
		USART_DMACmd(USART_X, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);

		DMA_Cmd(DMA_RX_STREAM, ENABLE);
		DMA_Cmd(DMA_TX_STREAM, ENABLE);

		while(DMA_GetFlagStatus(DMA_TX_STREAM, DMA_FLAG_TCIF7) == RESET);
        while(DMA_GetFlagStatus(DMA_RX_STREAM, DMA_FLAG_TCIF5) == RESET);

		USART_DMACmd(USART_X, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);

		// если прочитанные данные кому-то нужны - выкинем их в буфер
		if (readStart == 0 && dLen > 0) {
			*data = OW_toByte(OneWireBuffer);
			data++;
			dLen--;
		} else {
			if (readStart != OW_NO_READ) {
				readStart--;
			}
		}
	}

	return OW_OK;
}


а вот и инициализация
void Init_OneWire(void){
	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE);
	 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_DMA2, ENABLE);
	 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);

	 InitStucture.GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
	 InitStucture.GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 InitStucture.GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	 InitStucture.GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;
	 InitStucture.GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;
	 GPIO_Init(GPIOA, &InitStucture.GPIO_InitStructure);

	 InitStucture.GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
	 InitStucture.GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	 InitStucture.GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;
	 InitStucture.GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
	 InitStucture.GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
	 GPIO_Init(GPIOA, &InitStucture.GPIO_InitStructure);

	 GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
	 GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);

	 InitStucture.USART_InitStructure.USART_BaudRate = 115200;
	 InitStucture.USART_InitStructure.USART_WordLength = USART_WordLength_8b;
	 InitStucture.USART_InitStructure.USART_StopBits = USART_StopBits_1;
	 InitStucture.USART_InitStructure.USART_Parity = USART_Parity_No;
	 InitStucture.USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	 InitStucture.USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx;
	 USART_Init(USART_X, &InitStucture.USART_InitStructure);
	 //USART_HalfDuplexCmd(USART_X, ENABLE);
	 USART_Cmd(USART_X, ENABLE);

	 DMA_DeInit(DMA_TX_STREAM);
	 InitStucture.DMA_TX_InitStructure.DMA_Channel = DMA_CHANNEL;
	 InitStucture.DMA_TX_InitStructure.DMA_DIR = DMA_DIR_MemoryToPeripheral; // Transmit
	 InitStucture.DMA_TX_InitStructure.DMA_Memory0BaseAddr = (uint32_t)OneWireBuffer;
	 InitStucture.DMA_TX_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART_X->DR);
	 InitStucture.DMA_TX_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	 InitStucture.DMA_TX_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	 InitStucture.DMA_TX_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	 InitStucture.DMA_TX_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	 InitStucture.DMA_TX_InitStructure.DMA_Mode = DMA_Mode_Normal;
	 InitStucture.DMA_TX_InitStructure.DMA_Priority = DMA_Priority_High;
	 InitStucture.DMA_TX_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
	 InitStucture.DMA_TX_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	 InitStucture.DMA_TX_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	 InitStucture.DMA_TX_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;

	 DMA_DeInit(DMA_RX_STREAM);
	 InitStucture.DMA_RX_InitStructure.DMA_Channel = DMA_CHANNEL;
	 InitStucture.DMA_RX_InitStructure.DMA_DIR = DMA_DIR_PeripheralToMemory; // Receive
	 InitStucture.DMA_RX_InitStructure.DMA_Memory0BaseAddr = (uint32_t)OneWireBuffer;
	 InitStucture.DMA_RX_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART_X->DR);
	 InitStucture.DMA_RX_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	 InitStucture.DMA_RX_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	 InitStucture.DMA_RX_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	 InitStucture.DMA_RX_InitStructure.DMA_MemoryDataSize = DMA_MemoryDataSize_Byte;
	 InitStucture.DMA_RX_InitStructure.DMA_Mode = DMA_Mode_Normal;
	 InitStucture.DMA_RX_InitStructure.DMA_Priority = DMA_Priority_High;
	 InitStucture.DMA_RX_InitStructure.DMA_FIFOMode = DMA_FIFOMode_Enable;
	 InitStucture.DMA_RX_InitStructure.DMA_FIFOThreshold = DMA_FIFOThreshold_Full;
	 InitStucture.DMA_RX_InitStructure.DMA_MemoryBurst = DMA_MemoryBurst_Single;
	 InitStucture.DMA_RX_InitStructure.DMA_PeripheralBurst = DMA_PeripheralBurst_Single;
}
0
Даже уже пытаюсь по трем проводам запустить!!! и все ни как!(
0
Слишком много всяких вопросов-ответов возникает, посмотри в личку — пообщаемся, потом выложим здесь результат.
0
Я нашел вас в скайпе и добавил в контакты!
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.