Stm32F0 и 1-wire

Сегодня решил попробовать работу связки STM32F030 и DS18B20 как описал steel_ne здесь. Не получилось определить наличие датчика на OWI по сбросу так, как мне хотелось. Код steel_ne полностью рабочий, за исключением возврата значения функцией OW_Reset при закороченной линии данных. Проблемное место нашел и исправил.

Я пытался в процедуре сброса определить три состояния:
1. Есть датчик OWI
2. Нет датчика
3. КЗ ни линии.

Сделать это пытался по анализу ответа на сброс.
В статье есть раздел «Сброс шины 1-wire», и сделано так (незначимая часть — опущена)

uint8_t OW_Reset(USART_TypeDef* USARTx) {
uint8_t ow_presence;
...........................
        USART_ClearFlag(USARTx, USART_FLAG_TC);

        USART_SendData(USARTx, 0xf0);
        while (USART_GetFlagStatus(USARTx, USART_FLAG_TC) == RESET);
        ow_presence = USART_ReceiveData(USARTx);
...........................
        if (ow_presence != 0xf0) {
                return 1;
        }

        return 0;


Пока к шине никто не подключен ow_presence = USART_ReceiveData(USARTx); возвращает правильное значение 0xF0. Как только подключили датчик картина меняется кардинально — USART_ReceiveData(USARTx) возвращает строго — НОЛЬ.

Видимо импульс «неправильной» длительности сносит башню приемнику. На картинке отмечено место где должны быть переходы у «нормальной» последовательности 9600.



Может быть, промежуток времени между отпусканием линии контроллером и началом ответа датчиком воспринимается приемником как повторный старт.
В отладчике видно, что к моменту окончания передачи приемник еще не решил, принял он что-то или нет. Если поставить точку останова после строки
ow_presence = USART_ReceiveData(USARTx);
то USART_FLAG_RXNE оказывается взведен, а в регистре RDR лежат правильные данные (0хE0)
Т.е. приемник принимает решение о приеме байта позже из-за дерготни в непонятные для него моменты времени.

Лечение — элементарно. Ждем флага готовности приема.

#define OWI_USART   USART1
..........................
    OWI_USART->TDR = 0x0F;
    while ((OWI_USART->ISR & USART_FLAG_TC) == RESET);

    while ((OWI_USART->ISR & USART_FLAG_RXNE) == RESET);
    ow_presence = OWI_USART->RDR;


Теперь посылаем 0x0F а принимаем 0x07. Ответ на импульс сброса — виден.

Но задачу этим я не решил. :)
Поскольку при КЗ ответа не будет никогда, т.к. на входе приемника (RxD) не будет стартового перепада, при ожидании ответа необходимо завести тайм-аут по приему. И вот этот тайм-аут покажет, что на линии КЗ.
Как организовать паузу — каждый решает самостоятельно. :)

У меня USART_CR2_MSBFIRST установлен, поэтому данные передаются старшим битом вперед. Мне так показалось нагляднее. :)

Более простое решение подсказал dadigor в комментах. Перед тем как вообще что-то делать с OWI нужно посмотреть входной пин и если там 0, то КЗ и завершаем с ошибкой.

12.11.2017 Прикрепил исходники.
  • +1
  • 31 октября 2015, 19:59
  • SeregaB
  • 1
Файлы в топике: SRC.ZIP

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

RSS свернуть / развернуть
У steel_ne есть развитие темы здесь. Там все коды рабочие, проверено.
0
Где нибудь, в моей заметке написано что код steel_ne нерабочий?
Я пытался в процедуре сброса определить три состояния:
1. Есть датчик OWI
2. Нет датчика
3. КЗ ни линии.

Не получилось по п.3 потому, что ответ, записанный в переменной ow_presence при наличии датчика всегда нулевой. Мне показалось это странным, решил понять в чем дело. Разобрался, кратенько описал.
У steel_ne и в указанной тобой библиотеке и по ссылке которую дал я очень тонко обойден этот момент. Ответ сравнивается с исходной посылкой.
if (ow_presence != 0xf0) {
		return OW_OK;
	}


Т.о., получив 0х00, при сравнении с 0xF0 все работает.

Я понимаю, после того как дописал кусок кода дальше, что я не могу получить в ответе 0х00 при КЗ в линни, поскольку не будет стартового бита. И выходить при КЗ пришлось по тайм-ауту приема. Но мне необходимо знать до начала штатной работы есть КЗ или нет (подавать умощненное питание на время преобразования или не стОит, поскольку датчики включены с фантомным питанием).
0
Что-то я не очень наверное въехал, башка сегодня ни к черту… Никак не соображу, но вроде бы КЗ можно проверить сразу, ничего вообще не передавая — USART выдает в стоповом состоянии 1, просто посмотри что на приемном входе, если 0, значит КЗ и не начинай обмен вообще.
+1
Сейчас именно так и сделал. :) Спасибо за простое решение.
С тайм-аут выкинул за ненадобностью. Перед переинициализацией на 9600 переключаю TxD в GPIO-вход и смотрю уровень. При низком — функция OWI_Reset сразу возвращает код ошибки КЗ.
А у меня утром сегодня башка плохо варила и я пытался по приему байта 0х00 определить КЗ. :)
0
Ну значит мир и порядок! Я сам часто зацикливаюсь на одном решении, тычок со стороны выводит из ступора… )) А как питаешь линию? Я тут описывал решение, кстати оно КЗ не должно бояться — выходы вроде бы защищены от КЗ.
+1
Можно реализацию для F0? Утараканился я с ним F1 работает, F0 показывает количество куриц в Усть-Жопинске. Чую где-то мелочь пропускаю а поймать — никак. Заранее спасибо!
0
Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.