Stm32 + 1-wire + DMA

В очередной раз потребовалось считывать данные по 1-wire. Сначала я это делал на AVR просто дерганьем ножек. Потом прочел небезызвестный аппнот от maxim Using a UART to Implement a 1-Wire Bus Master, начал использовать USART. Когда перебрался на STM32, увидел что усартов у него чуть больше чем дофига, поэтому милое дело использовать их для этих целей. Ясное дело, все получилось. Но тут заметил, что вдобавок к USART есть такой бонус — DMA. Вот про прикручивание его к работе с 1-wire и пойдет разговор в этой статье.

Введение

Сначала чуть освежим принципы работы с 1-wire через USART.

Схема подключения — проста как три копейки. В качестве подопытного будет выступать термометр DS1820. Да, знаю что лучше было бы взять DS18b20, но что под руку попалось…



Reset выполняется так — настройки порта 9600,8,n,1, отправляем 0xf0, если приходит не 0xf0 – значит на линии кто-то сидит.

Для всех остальных действий настройки порта 115200,8,n,1
Запись 0 — отправляем 0х00. По идее и прийти должно 0x00
Запись 1 — отправляем 0хff. По идее и прийти должно 0xff
Чтение — отправляем 0xff. Если вернулось 0xff – прочиталась 1, иначе — 0.

Соответственно, чтобы записать байт на линию 1-wire, нам надо прокачать 8 байт через USART. Вручную это делать неинтересно, почитаем, что нам пишут про DMA. Как это примерно выглядит — формируем буфер для отправки, настраиваем DMA (указываем сколько, откуда, и куда заслать), даем пинка и все завертелось.

У STM32F103 есть два контроллера DMA, в сумме 12 каналов. Каждый канал закреплен за своей периферией. Ну и кроме того, любой канал может работать в режиме память-память, но нам такой режим пока не интересен.

Раскладка каналов по периферии приведена в Reference manual, в разделе про DMA. Нас интересует строка UART. Исторически сложилось, что я в примере использовал USART2, значит для него задействуем каналы DMA1_Channel6 и DMA1_Channel7




Инициализация

И первый шаг — инициализация:

void OW_Init(USART_TypeDef* USARTx) {
	GPIO_InitTypeDef GPIO_InitStruct;
	USART_InitTypeDef USART_InitStructure;

	if (USARTx == USART2) {
		RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

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

		GPIO_Init(GPIOA, &GPIO_InitStruct);

		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_3;
		GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN_FLOATING;
		GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

		GPIO_Init(GPIOA, &GPIO_InitStruct);

		RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
	}


	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_Init(USARTx, &USART_InitStructure);
	USART_Cmd(USARTx, ENABLE);

	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);

}


Как такой поток сознания написать быстро и не запутавшись? У католиков есть мнемоника, чтобы запомнить как креститься — «очки, яйца, бумажник, часы». У нас немного по-другому «часы, ноги, периферия»:

Первой командой включаем тактирование порта GPIOA. Почему A? Потому что там находятся ноги USART2. Смотреть распиновку в даташите.

Потом настраиваем ноги. Про это надо читать в разделе General-purpose and alternate-function I/Os (GPIOs and AFIOs). Там есть таблички на все случаи жизни, в том числе и USART. Ногу TX ставим в альтернативный пуш-пул, ногу RX — оставляем висеть.



И дальше включаем периферию. В нашем случае USART и DMA1.

Сброс шины 1-wire

Едем дальше — Reset.

uint8_t OW_Reset(USART_TypeDef* USARTx) {
	uint8_t ow_presence;
	USART_InitTypeDef USART_InitStructure;

	USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);

	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(USARTx, &USART_InitStructure);

	USART_ClearFlag(USARTx, USART_FLAG_TC);

	USART_SendData(USARTx, 0xf0);
	while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
	ow_presence = USART_ReceiveData(USARTx);

	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(USARTx, &USART_InitStructure);

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

	return 0;
}


Тут вроде все должно быть понятно — устанавливаем 9600, шлем байт, ждем отправки, читаем что на шине и устанавливаем скорость обратно 115200.

Можно было бы задействовать прерывание, но я буду использовать freeRTOS, поэтому мне проще будет отдать тик системе, чтобы она провернула другую задачу, чем возиться с прерываниями. В чем прелесть работы с 1-wire через USART, это то, что все тайминги внутри слота чтения/записи выдерживает USART аппаратно, а задержки между битами никого не волнуют, хоть на год растянется. Поэтому если мы и пропустим пару микросекунд, ничего нам за это не будет.
Ну и флаг анализирую USART_FLAG_TC – Transfer Complete. Этот флаг означает что все, данные уехали в шину полностью. Казалось бы, есть еще флаг USART_FLAG_TXE, но он означает, что всего лишь освободился регистр данных, а сами данные еще перемалываются в дебрях USART. Как банкомат, который карточку уже сожрал, а денег еще не дал. А нам кроме того, что отправить данные, надо еще и прочитать, что же в итоге наших манипуляций получилось. Поскольку выход TX и вход RX жестко связаны по схеме, то в момент окончания отправки чудесным образом у нас закончится прием байта. И его можно будет считать командой USART_ReceiveData().

Функция OW_Reset() в итоге возвращает 0 — если никаких устройств на шине не откликнулось и дальнейший обмен бесперспективен, или 1 — в противном случае.

Посылка команд


Теперь самое интересное — посылка пакета команд.
Как, например, выглядит работа с термометром? Посылаем ему сначала команду выбора «эй, ты!», ну или «эй вы все, слушать сюда». Потом посылаем собственно команду «температуру измеряй!». Для примера я не буду задействовать идентификатор устройства, а буду кричать всем.
Нам надо отправить два байта 0xcc (SKIP ROM) и 0x44 (CONVERT T). При этом через USART надо будет прокачать 16 байт. Создадим соответствующий массив:

#define OW_0	0x00
#define OW_1	0xff
#define OW_R	0xff


const uint8_t convert_T[] = {
		OW_0, OW_0, OW_1, OW_1, OW_0, OW_0, OW_1, OW_1, // 0xcc SKIP ROM
		OW_0, OW_0, OW_1, OW_0, OW_0, OW_0, OW_1, OW_0  // 0x44 CONVERT
};


В 1-wire биты передаются начиная с младшего, поэтому записываем их наоборот.

Дальше вызываем функцию:

void OW_SendCommand(USART_TypeDef* USARTx, const uint8_t *command, uint16_t len) {
	DMA_InitTypeDef DMA_InitStructure;

	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = len;
	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);

	USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);
	DMA_Cmd(DMA1_Channel7, ENABLE);
}


Настройку DMA разберем подробнее:

В качестве адреса периферии устанавливаем адрес регистра данных USART2
DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);


В качестве адреса памяти берем переданный в параметрах массив — его мы составляли ранее.
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;


Направление передачи — из памяти в периферию
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;


Длина передаваемого блока данных. Не может превышать 65536 байт.
DMA_InitStructure.DMA_BufferSize = len;


Надо ли увеличивать адрес порта после каждой передачи? Нет не надо — все льем в один порт
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;


Вот эта команда говорит — USART2, еси тебе нечего передавать, дергай DMA, он тебе еще отсыплет. Канал DMA не указывается, он и так понятен какой — DMA1_Channel7.
USART_DMACmd(USART2, USART_DMAReq_Tx, ENABLE);


Ну и запуск DMA.
DMA_Cmd(DMA1_Channel7, ENABLE);


После того, как запустили DMA, он первым делом закинет первый байт, а дальше уже USART будет его дергать. Поэтому порядок инициализации именно такой — сначала USART_DMACmd, а только потом — DMA ENABLE.

В даташите сказано — как только закончите пользоваться, сразу сделайте
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, DISABLE);


Ну а поскольку мы никакой активности в порту USART не ожидаем, да и следующая команда будет гарантированно RESET, то засунем эту команду в начало функции OW_Reset().

Чтение данных


Это если нам не надо ничего читать из устройств 1-wire. А что делать, если они нам будут слать что-то? Надо подключить второй канал DMA, ну и вдобавок определить буфер, куда мы будем все считывать.

const uint8_t read_scratch[] = {
		OW_0, OW_0, OW_1, OW_1, OW_0, OW_0, OW_1, OW_1, // 0xcc SKIP ROM
		OW_0, OW_1, OW_1, OW_1, OW_1, OW_1, OW_0, OW_1, // 0xbe READ SCRATCH
		OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R,
		OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R, OW_R
};

uint8_t scratch[sizeof(read_scratch)];

void OW_ReadData(USART_TypeDef* USARTx, const uint8_t *command, uint8_t *buf, uint16_t len) {
	DMA_InitTypeDef DMA_InitStructure;

	DMA_DeInit(DMA1_Channel6);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) buf;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;
	DMA_InitStructure.DMA_BufferSize = len;
	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);

	DMA_DeInit(DMA1_Channel7);
	DMA_InitStructure.DMA_PeripheralBaseAddr = (uint32_t) &(USART2->DR);
	DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) command;
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = len;
	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);

	USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);
	DMA_Cmd(DMA1_Channel6, ENABLE);
	DMA_Cmd(DMA1_Channel7, ENABLE);

	while (DMA_GetFlagStatus(DMA1_FLAG_TC6) == RESET);
}


Тут инициализируется канал 6 первого контроллера. Из отличий:

В качестве адреса памяти используется выделенный буфер
DMA_InitStructure.DMA_MemoryBaseAddr = (uint32_t) buf;

И направление немного другое — из периферии в память
DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralSRC;


Соответственно команда USART'у будет такой:
USART_DMACmd(USARTx, USART_DMAReq_Tx | USART_DMAReq_Rx, ENABLE);

Типа отправляй как в прошлом примере, но если чего-то принял, то тоже дергай DMA.

Тут я просто ожидаю окончания работы с DMA. Опять же, можно использовать прерывание, благо их много есть у нас — и по исчерпанию половины буфера, и по полному завершению передачи. Но, повторюсь, я лучше тик отдам системе.
while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET);


main.c


Как теперь этим пользоваться?

OW_Init(OW_USART);

	OW_Reset(OW_USART);
	OW_SendCommand(OW_USART, convert_T, sizeof(convert_T));

	for (i=0; i<1000000; i++);

	OW_Reset(OW_USART);
	OW_ReadData(OW_USART, read_scratch, scratch,  sizeof(read_scratch));

	uint16_t tt=0;

	for (i=16;i<32; i++) {
		if (scratch[i] == 0xff) {
			tt = (tt>>1) | 0x8000;
		} else {
			tt = tt>>1;
		}

	}


Задержка после команды Convert T – это время на измерение температуры. Читать в даташите на датчик.
По результатам действия в переменной tt будет значение первых двух байт из scratch-памяти термометра. Это и есть температура.

Выводы


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

Поиск устройств особо не распараллелишь, он интерактивный на каждом шаге. Придется делать как в OW_Reset – кинули байтик, ждем.

Минус один — требуется буфер, достаточно большой.
Но можно минус слегка нивелировать — в этом буфере составлять команду и в него же читать передаваемые данные. Посмотрим.

UPD. Вот ссылка на пост с оформленной библиотекой:
http://we.easyelectronics.ru/STM32/stm32-1-wire-dma-prodolzhenie.html

  • +6
  • 11 февраля 2012, 00:57
  • steel_ne

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

RSS свернуть / развернуть
А где ты отдаешь управление системе? Или у тебя вытесняйка?
0
Это просто пример работы с 1-wire, пнуть без rtos. Отдавать буду так

while (DMA_GetFlagStatus(DMA1_FLAG_TC7) == RESET) {
    taskYIELD();
}
0
Оно даже в вытесняйке полезно.
Вообще я для себя сделал вывод — вытесняющая многозадачность полезна только когда у тебя крутится чужая тяжелая библиотека. Если задачи свои, то всегда видно, где можно отдать тик, а где лучше критическую секцию поставить.
0
Гм. Я бы спихнул формирование массивов из OW_x на библиотеку. Тогда будет функция вида uint8_t OW_SendByte(uint8_t Data), использующая 16 байт под внутренние буферы (8 на передачу, 8 на прием), и принимающая/выдающая данные сразу удобоваримым байтиком.
А вообще, буфер можно один использовать. Все равно, когда пришел на RX очередной байтик — это значит, что из буфера передачи он уже забран и больше не нужен. Так что можно оба канала натравить на один буфер.
0
  • avatar
  • Vga
  • 11 февраля 2012, 03:30
Хотелось сначала сформировать всю посылку, а потом ее выплюнуть. По большому счету часть команд — это константы. Например, начало измерения температуры, запись в скретч (конфигурация датчика). В другой части команд будет использоваться восьмибайтный айди датчика, вот как там соберется команда — не знаю.
А про оба канала на один буфер — это реально.
0
Ну, во первых, константы таких посылок неудобно записывать.
Во вторых, на них тратится в 8 раз больше памяти. Зачем?
Формировать вполне достаточно побайтно посылки, это потребует всего 8 байт ОЗУ под буфер.
0
О, как удачненько! Как раз нужно реализовать 1-wire. А тут всё подробно расписано, да ещё и с блекджеком. Буду использовать, разве что, наверно, заюзаю прерывания вместо ртос.
Спасибо!
0
  • avatar
  • ACE
  • 11 февраля 2012, 15:10
подскажите, пожалуйста, а multidrop по такой схеме будет работать?
0
Подразумевается когда несколько устройств 1-wire на шине? Будет конечно. С точки зрения 1-wire ничего не поменялось.
0
На лифлабсовском форуме как раз всплыла аналогичная тема, запостил линк на статью туда. Кстати, нет желания/возможности перевести статью на английский? Думаю, желающих почитать ее в таком виде найдется немало.

P.S. вот бы тоже самое, но на libmaple…
0
  • avatar
  • evsi
  • 15 февраля 2012, 14:53
Та как-то не тусовался на зарубежных форумах. А лифлабс нормальный по контингенту?

А что такое вообще libmaple? :)
0
Да, вполне. Только активность там не очень высокая.

P.S. www.leaflabs.com и дальше по ссылкам, там и форум, и Maple, и libmaple. Еще стоит глянуть github.com/gbulmer/openstm32sw и github.com/gbulmer/openstm32hw.
0
По поводу перевода: я могу помочь, если есть необходимость.

P.S. как минимум еще двое людей из местного сообщества периодически тусуются на лифлабсе.
P.P.S. любопытно, будет ли DIHALT против постов на других языках или, например, комбинированных постов, где текст присутствует более чем на одном языке…
0
Если в личном блоге, то нет. В общественном ещё не известно. В правилах вроде не сказано что посты должны быть только на русском.
0
Я заметил, что если этот термометр опросить сразу после включения и продолжать опрашивать ~раз в секунду, то через 5-10 секунд он показывает на 0,5-1 градуса больше, чем сразу после включения. Нагревается что-ли сам от себя. С таким раскладом точности в 1/16 градуса доверять нельзя (( По хорошему, 1/2 градуса — это максимум, на что он способен. А не знает ли кто-то более точного термометра?
0
Не знаю насчет этого, а вот в даташите на SHT21 прямо сказано — при скважности работы более 10% (т.е. опрос чаще 1 Гц при максимальной точности преобразования — оно при этом занимает 100мс) микросхема разогревается.
Кроме того, не надо забывать про детали рядом с термометром. Этому Sensirion даже отдельный документ посвятили. Не зря датчик на демоплатах отгорожен от прочей платы прорезью в текстолите.
0
Поправьте меня если я ошибаюсь.
Если сконфигурировать выход USART_TX как open drain, то можно исключиь диод из схемы.
В даташите как раз указанно, что USART_TX может быть как PushPull так и OpenDrain.
0
  • avatar
  • shein
  • 29 августа 2012, 15:06
Проглядел даташит, не нашел такого. Я писал для серии STM32F103. Может на STM8, например, и допустима такая гибкость.
0
Как раз для STM32F103
The USART_TX pin can also be configured as alternate function open drain.
Страница 162 Reference Manual Rev 14
Кстати, у меня валяется ещё этот документ 11 ревизии, так там действительно нет этой сноски :)

Вчера попробовал сконфигурировать USART_TX как OpenDrain и убрал диод, всё работает замечательно.
ЗЫ: Вообще статья отличная, она мне очень помогла, спасибо.
0
Спасибо, буду знать. Скорее всего я сам и напоролся на классику — читай последний даташит, а не тот, который есть ))
0
вопрос по количеству ног… типа 1-wire, так 1-wire

ткните носом, может я чего-то не понял во всей химии, но внутреннее соединение TX c RX и OpenDrain в одном флаконе:

RM0008 Doc ID 13902 Rev 14 стр 779
27.3.10 Single-wire half-duplex communication
The single-wire half-duplex mode is selected by setting the HDSEL bit in the USART_CR3
register. In this mode, the following bits must be kept cleared:
● LINEN and CLKEN bits in the USART_CR2 register,
● SCEN and IREN bits in the USART_CR3 register.
The USART can be configured to follow a single-wire half-duplex protocol. In single-wire
half-duplex mode, the TX and RX pins are connected internally. The selection between halfand
full-duplex communication is made with a control bit ‘HALF DUPLEX SEL’ (HDSEL in
USART_CR3).
As soon as HDSEL is written to 1:
● RX is no longer used,
● TX is always released when no data is transmitted. Thus, it acts as a standard IO in idle
or in reception. It means that the IO must be configured so that TX is configured as
floating input (or output high open-drain) when not driven by the USART.
Apart from this, the communications are similar to what is done in normal USART mode.

The conflicts on the line must be managed by the software (by the use of a centralized
arbiter, for instance). In particular, the transmission is never blocked by hardware and
continue to occur as soon as a data is written in the data register while the TE bit is set.

Платы нет, железки нет — типа готовлюсь теоретизирую…
Наткнулся играясь с MicroXplorer 2.1
0
Господа! Вопрос такой. Меня смущает вот это: "
It means that the IO must be configured so that TX is configured as floating input (or output high open-drain) when not driven by the USART
". А когда управляется UART-ом, значицца, совсем не обязательно open drain?

Точно не погорит, например, через полгодика-годик работы, если без диода?

Может у кого-нибудь есть схема готовая, чтобы быстро попробовать слать в UART в half duplex? А подтягивающий к питанию резистор заменить на подтягивающий к земле — сразу будет видно, open drain или нет.
0
while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);


Вот эта конструкция может повлечь беду. Если датчик отвалится, то здесь бесконечный цикл получится. Отдавай тик, не отдавай, а текущая задача заблокирована.
0
Датчик не влияет на работу передатчика USART, после того как передатчик передаст последний бит он выставит флаг TC.
0
Хорошая статья. Тоже прочитал аппнот «Using a UART to Implement a 1-Wire Bus Master», буду реализовывать, только без Standart Peripheral Library
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.